package screen

import (
	"image"
	"image/color"
	"time"
)

const (
	charWidth     = 7
	charHeight    = 8
	text40Columns = 40
	textLines     = 24
)

func snapshotText40(vs VideoSource, isSecondPage bool, isAltText bool, light color.Color) *image.RGBA {
	text := getTextFromMemory(vs, isSecondPage, false)
	return renderText(vs, text, isAltText, nil /*colorMap*/, light)
}

func snapshotText80(vs VideoSource, isSecondPage bool, isAltText bool, light color.Color) *image.RGBA {
	text := getText80FromMemory(vs, isSecondPage)
	return renderText(vs, text, isAltText, nil /*colorMap*/, light)
}

func snapshotText40RGB(vs VideoSource, isSecondPage bool, isAltText bool) *image.RGBA {
	text := getTextFromMemory(vs, isSecondPage, false)
	colorMap := getTextFromMemory(vs, isSecondPage, true)
	return renderText(vs, text, isAltText, colorMap, nil)
}

func snapshotText40RGBColors(vs VideoSource, isSecondPage bool) *image.RGBA {
	colorMap := getTextFromMemory(vs, isSecondPage, true)
	return renderText(vs, nil /*text*/, false, colorMap, nil)
}

func getText80FromMemory(vs VideoSource, isSecondPage bool) []uint8 {
	text40Columns := getTextFromMemory(vs, isSecondPage, false)
	text40ColumnsAlt := getTextFromMemory(vs, isSecondPage, true)

	// Merge the two 40 cols to return 80 cols
	text80Columns := make([]uint8, 2*len(text40Columns))
	for i := 0; i < len(text40Columns); i++ {
		text80Columns[2*i] = text40ColumnsAlt[i]
		text80Columns[2*i+1] = text40Columns[i]
	}

	return text80Columns
}

func getTextFromMemory(vs VideoSource, isSecondPage bool, isExt bool) []uint8 {
	data := vs.GetTextMemory(isSecondPage, isExt)

	text := make([]uint8, textLines*text40Columns)
	for l := 0; l < textLines; l++ {
		for c := 0; c < text40Columns; c++ {
			char := data[getTextCharOffset(c, l)]
			text[text40Columns*l+c] = char
		}
	}
	return text
}

func getTextCharOffset(col int, line int) uint16 {
	// See "Understanding the Apple II", page 5-10
	// http://www.applelogic.org/files/UNDERSTANDINGTHEAII.pdf
	section := line / 8 // Top, middle and bottom
	eighth := line % 8
	return uint16(section*40 + eighth*0x80 + col)
}

func getRGBTextColor(pixel bool, colorKey uint8) color.Color {
	if pixel {
		colorKey >>= 4
	}
	colorKey &= 0x0f
	return ntscColorMap[colorKey]

}

func renderText(vs VideoSource, text []uint8, isAltText bool, colorMap []uint8, light color.Color) *image.RGBA {
	// Flash mode is 2Hz (host time)
	isFlashedFrame := time.Now().Nanosecond() > (1 * 1000 * 1000 * 1000 / 2)

	columns := len(text) / textLines
	if text == nil {
		columns = text40Columns
	}
	width := columns * charWidth
	height := textLines * charHeight

	size := image.Rect(0, 0, 2*hiResWidth, hiResHeight)
	img := image.NewRGBA(size)

	for x := 0; x < width; x++ {
		for y := 0; y < height; y++ {
			line := y / charHeight
			col := x / charWidth
			rowInChar := y % charHeight
			colInChar := x % charWidth
			charIndex := line*columns + col
			var char uint8
			if text != nil {
				char = text[charIndex]
			} else {
				char = 79 + 128 // Debug screen filed with O
			}

			pixel := vs.GetCharacterPixel(char, rowInChar, colInChar, isAltText, isFlashedFrame)

			var colour color.Color
			if colorMap != nil {
				colour = getRGBTextColor(pixel, colorMap[charIndex])
			} else if pixel {
				colour = light
			} else {
				colour = color.Black
			}

			if columns == text40Columns {
				img.Set(x*2, y, colour)
				img.Set(x*2+1, y, colour)
			} else {
				img.Set(x, y, colour)
			}
		}
	}

	return img
}
