package main

import (
	"image/color"
	"sync"

	gg "github.com/faiface/pixel-examples/community/amidakuji/glossary"

	"github.com/faiface/pixel"
	"github.com/faiface/pixel/imdraw"
	"golang.org/x/image/colornames"
)

// Scalpel is a surgical knife for dissection and surgery. And for debugging purposes sometimes.
type Scalpel struct {
	imd   *imdraw.IMDraw // shared variable
	mutex sync.Mutex     // synchronize
}

// Draw guarantees the thread safety, though it's not a necessary condition.
// It is quite dangerous to access this struct's member (imdraw) directly from outside these methods.
func (s *Scalpel) Draw(t pixel.Target) {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	if s.imd == nil { // isInvisible set to true.
		return // An empty image is drawn.
	}

	s.imd.Draw(t)
}

// Update dissects a ladder. The anatomy of a ladder is drawn on an imdraw.
// A non-ptr Ladder as a read only argument passes lock by value within itself but that seems totally fine.
func (s *Scalpel) Update(l Ladder) {
	ptsEnd := l.PtsAtLevelOfPrizes()

	// lock shared imdraw access
	s.mutex.Lock()
	defer s.mutex.Unlock()

	// imdraw (a state machine)
	if s.imd == nil { // lazy creation
		s.imd = imdraw.New(nil)
	}
	imd := s.imd
	imd.Clear()

	// draw bounds
	imd.Color = colornames.Black
	imd.EndShape = imdraw.NoEndShape
	imd.Push(gg.VerticesOfRect(l.bound)...)
	imd.Polygon(4)

	// draw end points
	imd.Color = colornames.Blueviolet
	imd.Push(ptsEnd...)
	imd.Circle(10, 0)

	// draw grid
	imd.Color = colornames.Red
	for nrow, row := range l.grid {
		for ncol := range row {
			imd.Push(l.grid[nrow][ncol])
		}
	}
	imd.Circle(5, 0)
}

// -------------------------------------------------------------------------

// UpdateDrawProjekt has nothing to do with scalpel.
func UpdateDrawProjekt(t pixel.Target, rekt pixel.Rect, color color.Color, matrix pixel.Matrix) {
	imd := imdraw.New(nil)

	imd.Color = color
	imd.EndShape = imdraw.NoEndShape
	vertices := gg.VerticesOfRect(rekt)
	for i, v := range vertices {
		vertices[i] = matrix.Project(v)
	}
	imd.Push(vertices...)
	imd.Polygon(10)

	imd.Draw(t)
}

// UpdateDrawUnprojekt has nothing to do with scalpel.
func UpdateDrawUnprojekt(t pixel.Target, rekt pixel.Rect, color color.Color, matrix pixel.Matrix) {
	imd := imdraw.New(nil)

	imd.Color = color
	imd.EndShape = imdraw.NoEndShape
	vertices := gg.VerticesOfRect(rekt)
	for i, v := range vertices {
		vertices[i] = matrix.Unproject(v)
	}
	imd.Push(vertices...)
	imd.Polygon(10)

	imd.Draw(t)
}

// UpdateDrawUnprojekt2 has nothing to do with scalpel.
func UpdateDrawUnprojekt2(t pixel.Target, rekt pixel.Rect, color color.Color, camera gg.Camera) {
	imd := imdraw.New(nil)

	imd.Color = color
	imd.EndShape = imdraw.NoEndShape
	vertices := gg.VerticesOfRect(rekt)
	for i, v := range vertices {
		vertices[i] = camera.Unproject(v)
	}
	imd.Push(vertices...)
	imd.Polygon(10)

	imd.Draw(t)
}
