package ui

import (
	"image"

	"github.com/hajimehoshi/ebiten"
)

type region struct {
	offset image.Point
	image  *ebiten.Image
}

func oneRegion(offset image.Point, image *ebiten.Image) []region {
	return []region{{offset: offset, image: image}}
}

type idable interface {
	id() string
}

// Clickable can be clicked by the left button of a mouse. Specify code to run
// with OnClick().
type clickable interface {
	idable

	bounds() image.Rectangle
	onClick(f func())

	// These are used to drive the state of the item
	mouseDownState() bool
	setMouseDownState(bool)
	registerMouseClick()
}

// This implements the clickable interface except id(), bounds(), and registerMouseClick()
type clickImpl struct {
	f         func()
	mouseDown bool
}

func (c *clickImpl) onClick(f func()) {
	c.f = f
}

func (c *clickImpl) mouseDownState() bool {
	return c.mouseDown
}

func (c *clickImpl) setMouseDownState(down bool) {
	c.mouseDown = down
}

func (c *clickImpl) registerMouseClick() {
	if c.f != nil {
		c.f()
	}
}

// Freezable represents a widget that can be enabled or disabled
type freezable interface {
	idable

	isFrozen() bool
	setFreezeState(bool)
}

// This implements the freezable interface except id()
type freezeImpl struct {
	frozen bool
}

func (f *freezeImpl) isFrozen() bool {
	return f.frozen
}

func (f *freezeImpl) setFreezeState(frozen bool) {
	f.frozen = frozen
}

// Hoverable can be hovered over by the mouse cursor.
//
// If something can be hovered, it can have a tooltip, so that is implemented
// here too.
type hoverable interface {
	bounds() image.Rectangle
	tooltip() string

	// These are used to drive the state of the item
	hoverState() bool
	setHoverState(bool)
}

// Implements the hoverable interface with the exception of bounds()
type hoverImpl struct {
	hovering bool
	text     string
}

func (h *hoverImpl) tooltip() string {
	return h.text
}

func (h *hoverImpl) hoverState() bool {
	return h.hovering
}

func (h *hoverImpl) setHoverState(hovering bool) {
	h.hovering = hovering
}

// Mouseables are told where on the (original) screen the mouse cursor is
type mouseable interface {
	registerMousePosition(image.Point)
}

type mouseImpl struct {
	pos image.Point
}

func (m *mouseImpl) registerMousePosition(pt image.Point) {
	m.pos = pt
}

// Paintable encapsulates one or more regions to be painted to the screen
type paintable interface {
	regions(tick int) []region
}

// Valueable encapsulates the idea of an element with a value. Only strings are
// supported - #dealwithit for bools, ints, etc
type valueable interface {
	idable

	value() string
	setValue(string)
}

type valueImpl struct {
	str string
}

func (v *valueImpl) value() string {
	return v.str
}

func (v *valueImpl) setValue(value string) {
	v.str = value
}
