package graphics

import (
	"fmt"
	"math/rand"
	"image/color"
	rl "github.com/gen2brain/raylib-go/raylib"
)

type Graphics struct {
	layout Layout 
	style Style
}

type Layout struct {
	// total monitor bounds
	Monitor Rect
	// bounds of the application window
	Window Rect
	// bounds of the ui controls area
	Controls Rect
	// bounds of the region of the app window reserved for rendering the graphics buffer
	Viewport Rect
	// bounds of the off screen graphics buffer where rendering happens
	Graphics Rect
}

type Color color.RGBA

type HSBA struct {
	H uint
	S, B float32
	A uint8
}

type Style struct {
	StrokeColor Color
	StrokeWeight float32
	FillColor Color
}

type Rect rl.Rectangle

/**
 * scale the given rect down to the target rect
 * maintaining the aspect ratio of the original rect
 */
func (r Rect) ToRL() *rl.Rectangle {
	return &rl.Rectangle { X: r.X, Y: r.Y, Width: r.Width, Height: r.Height }
}

func (r Rect) ScaleTo(tgt Rect) Rect {

	outputWidth := tgt.Width
	outputHeight := tgt.Height

	aspect := r.Width / r.Height
	tgtAspect := outputWidth / outputHeight

	if aspect < tgtAspect {
		// source is relatively taller than the target
		// so we set the output height to the target height
		// and calculate the width based on source aspect and center
		outputWidth = float32(outputHeight) * aspect
	} else {
		// source is relatively wider than the target
		// so we set the output width to the target width
		// and calculate the height based on source aspect and center
		outputHeight = float32(outputWidth) / aspect
	}

	// output width and height are correct -- center within TargetBounds
	x := tgt.X + tgt.Width / 2.0 - outputWidth / 2.0 
	y := tgt.Y + tgt.Height / 2.0 - outputHeight / 2.0 

	return Rect {
		X: x, Y: y,
		Width: outputWidth,
		Height: outputHeight,
	}
}

var (
	FlourescentHues = []float32{
		0,   // hot magenta-red
		30,  // neon orange
		60,  // acid yellow
		120, // laser green
		180, // cyan
		210, // electric blue
		270, // ultraviolet purple
	}
	FlourescentColors = makeFlourescentColors()
)

func Clamp(c rl.Color, min uint8, max uint8) rl.Color {
	return rl.NewColor(
		uint8(rl.Clamp(float32(c.R), float32(min), float32(max))),
		uint8(rl.Clamp(float32(c.G), float32(min), float32(max))),
		uint8(rl.Clamp(float32(c.B), float32(min), float32(max))),
		uint8(rl.Clamp(float32(c.A), float32(min), float32(max))),
	)
}

func makeFlourescentColors() []rl.Color {
	fc := make([]rl.Color, len(FlourescentHues))
	for i, hue := range(FlourescentHues) {
		fc[i] = rl.ColorFromHSV(hue, 1.0, 1.0)
	}
	fmt.Printf("flourescent colors --> %v\n", fc)

	return fc
}

type ColorCycle interface {
	Next() rl.Color
}

type ArrayBackedColorCycle struct {
	colors []rl.Color
	index int
}

func NewFixedColorCycle(colors []rl.Color) *ArrayBackedColorCycle {
	return &ArrayBackedColorCycle {
		colors: colors,
		index: 0,
	}
}

func (c ArrayBackedColorCycle) Shuffle(seed int64) *ArrayBackedColorCycle {
	r := rand.New(rand.NewSource(seed))
	cprime := &ArrayBackedColorCycle {
		colors: make([]rl.Color, len(c.colors)),
		index: 0,
	}
	copy(cprime.colors, c.colors)
	r.Shuffle(len(c.colors), func(i, j int) {
		cprime.colors[i], cprime.colors[j] = cprime.colors[j], cprime.colors[i]
	})
	fmt.Printf("shuffled colors --> %v\n", cprime.colors)
	return cprime
}

func (c *ArrayBackedColorCycle) Next() rl.Color {
	color := c.colors[c.index]
	c.index = (c.index + 1) % len(c.colors)
	return color
}

