package main

import (
	"image/color"
	"math"

	"tinygo.org/x/drivers"
	"tinygo.org/x/drivers/touch"
)

type touchPaintDisplay interface {
	drivers.Displayer
	FillRectangle(x, y, width, height int16, c color.RGBA) error
	DrawRectangle(x, y, w, h int16, c color.RGBA) error
}

var (
	white   = color.RGBA{255, 255, 255, 255}
	black   = color.RGBA{0, 0, 0, 255}
	red     = color.RGBA{255, 0, 0, 255}
	green   = color.RGBA{0, 255, 0, 255}
	blue    = color.RGBA{0, 0, 255, 255}
	magenta = color.RGBA{255, 0, 255, 255}
	yellow  = color.RGBA{255, 255, 0, 255}
	cyan    = color.RGBA{0, 255, 255, 255}

	oldColor     color.RGBA
	currentColor color.RGBA
)

const (
	penRadius = 3
	boxSize   = 30

	Xmin = 0
	Xmax = 0xFFFF
	Ymin = 0
	Ymax = 0xFFFF
)

func main() {
	display, resistiveTouch, _ := initDevices()

	// fill the background and activate the backlight
	width, height := display.Size()
	display.FillRectangle(0, 0, width, height, black)

	// make color selection boxes
	display.FillRectangle(0, 0, boxSize, boxSize, red)
	display.FillRectangle(boxSize, 0, boxSize, boxSize, yellow)
	display.FillRectangle(boxSize*2, 0, boxSize, boxSize, green)
	display.FillRectangle(boxSize*3, 0, boxSize, boxSize, cyan)
	display.FillRectangle(boxSize*4, 0, boxSize, boxSize, blue)
	display.FillRectangle(boxSize*5, 0, boxSize, boxSize, magenta)
	display.FillRectangle(boxSize*6, 0, boxSize, boxSize, black)
	display.FillRectangle(boxSize*7, 0, boxSize, boxSize, white)

	// set the initial color to red and draw a box to highlight it
	oldColor = red
	currentColor = red
	display.DrawRectangle(0, 0, boxSize, boxSize, white)

	last := touch.Point{}

	// loop and poll for touches, including performing debouncing
	debounce := 0
	for {

		point := resistiveTouch.ReadTouchPoint()
		touch := touch.Point{}
		if point.Z>>6 > 100 {
			rawX := mapval(point.X, Xmin, Xmax, 0, int(width))
			rawY := mapval(point.Y, Ymin, Ymax, 0, int(height))
			touch.X = rawX
			touch.Y = rawY
			touch.Z = 1
		} else {
			touch.X = 0
			touch.Y = 0
			touch.Z = 0
		}

		if last.Z != touch.Z {
			debounce = 0
			last = touch
		} else if math.Abs(float64(touch.X-last.X)) > 4 ||
			math.Abs(float64(touch.Y-last.Y)) > 4 {
			debounce = 0
			last = touch
		} else if debounce > 1 {
			debounce = 0
			HandleTouch(display, last)
		} else if touch.Z > 0 {
			debounce++
		} else {
			last = touch
			debounce = 0
		}

	}
}

// based on Arduino's "map" function
func mapval(x int, inMin int, inMax int, outMin int, outMax int) int {
	return (x-inMin)*(outMax-outMin)/(inMax-inMin) + outMin
}

func HandleTouch(display touchPaintDisplay, touch touch.Point) {

	if int16(touch.Y) < boxSize {
		oldColor = currentColor
		x := int16(touch.X)
		switch {
		case x < boxSize:
			currentColor = red
		case x < boxSize*2:
			currentColor = yellow
		case x < boxSize*3:
			currentColor = green
		case x < boxSize*4:
			currentColor = cyan
		case x < boxSize*5:
			currentColor = blue
		case x < boxSize*6:
			currentColor = magenta
		case x < boxSize*7:
			currentColor = black
		case x < boxSize*8:
			currentColor = white
		}

		if oldColor == currentColor {
			return
		}

		display.DrawRectangle((x/boxSize)*boxSize, 0, boxSize, boxSize, white)
		switch oldColor {
		case red:
			x = 0
		case yellow:
			x = boxSize
		case green:
			x = boxSize * 2
		case cyan:
			x = boxSize * 3
		case blue:
			x = boxSize * 4
		case magenta:
			x = boxSize * 5
		case black:
			x = boxSize * 6
		case white:
			x = boxSize * 7
		}
		display.FillRectangle(int16(x), 0, boxSize, boxSize, oldColor)

	}

	if (int16(touch.Y) - penRadius) > boxSize {
		display.FillRectangle(
			int16(touch.X), int16(touch.Y), penRadius*2, penRadius*2, currentColor)
	}
}
