package door

import (
	"fmt"
	"strings"
)

// TODO:  Break out the progress bar characters into stuctures.
// Write tests to verify that CP437 matches Unicode.
// See box_test.  ;)

type BarStyle int8

const (
	SOLID BarStyle = iota
	HALF_STEP
	GRADIENT
)

type Percent_Style int8

const (
	PERCENT_NONE Percent_Style = iota
	PERCENT
	PERCENT_SPACE
)

type BarRange struct {
	Percent int64
	Color   string
}

type BarLine struct {
	Width        int
	Style        BarStyle
	Percent      int64 // percentage * 100
	PercentStyle Percent_Style
	ColorRange   []BarRange
	UpdateP      func() int64
	Line
}

type BarCharacters struct {
	Solid    string
	Half     [2]string
	Gradient [4]string
}

var BARS BarCharacters

var BARS_CP437 = BarCharacters{
	"\xdb",
	[2]string{"\xdb", "\xdd"},
	[4]string{"\xdb", "\xb0", "\xb1", "\xb2"},
}

var BARS_UNICODE = BarCharacters{
	"\u2588",
	[2]string{"\u2588", "\u258c"},
	[4]string{"\u2588", "\u2591", "\u2592", "\u2593"},
}

func (bl *BarLine) CheckRange() {
	if len(bl.ColorRange) != 0 {
		// Ok, there is a color range.  Get checking

		for _, br := range bl.ColorRange {
			if bl.Percent <= br.Percent {
				bl.DefaultColor = br.Color
				break
			}
		}
	}
}

func (bl *BarLine) Output() string {
	var output string
	var step_width int64

	if bl.UpdateP != nil {
		bl.Percent = bl.UpdateP()
	}

	bl.CheckRange()

	switch bl.Style {
	case SOLID:
		step_width = int64(100 * 100 / bl.Width)
		var steps int = int(bl.Percent / step_width)

		output += strings.Repeat(BARS.Solid, steps)
		// This will work, because we aren't trying to len(output) with unicode.
		output += strings.Repeat(" ", int(bl.Width-steps))

	case HALF_STEP:
		step_width = int64(100 * 100 / bl.Width)
		var steps int = int(bl.Percent * 2 / step_width)

		output += strings.Repeat(BARS.Half[0], steps/2)
		if steps%2 == 1 {
			output += BARS.Half[1]
			steps++
		}
		output += strings.Repeat(" ", bl.Width-(steps/2))

	case GRADIENT:
		step_width = int64(100 * 100 / bl.Width)
		var steps int = int(bl.Percent * 4 / step_width)

		output += strings.Repeat(BARS.Gradient[0], steps/4)
		if steps%4 != 0 {
			switch steps % 4 {
			case 1, 2, 3:
				output += BARS.Gradient[steps%4]
			}
			for steps%4 != 0 {
				steps++
			}
		}
		output += strings.Repeat(" ", bl.Width-(steps/4))
	}

	if bl.PercentStyle != PERCENT_NONE {
		percent := fmt.Sprintf("%d", bl.Percent/100)

		var pos int = bl.Width/2 - 1
		if percent != "100" {
			percent += "%"
			if len(percent) < 3 {
				percent = " " + percent
			}
		}

		if bl.PercentStyle == PERCENT_SPACE {
			percent = " " + percent + " "
			pos--
		}

		// to process/slice the string (with unicode) do this:
		// convert to []rune, slice that, convert back to string
		//
		// sliceable := []rune(output)
		// newString := string(sliceable[:5]) + " new content " + (sliceable[10:])
		// fmt.Printf("%d %d [%s] %d [%s]\n", bl.Width, pos, percent, len(output), output)

		if Unicode {
			runes := []rune(output)
			output = string(runes[:pos]) + percent + string(runes[pos+len(percent):])
		} else {
			output = output[:pos] + percent + output[pos+len(percent):]
		}
	}

	return bl.DefaultColor + output
}