package basic

import (
	"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
	"lab.zaar.be/thefish/alchemyst-go/engine/types"
	"math"
)

//fixme store separate FovMap, add method IsInMap to it

type FieldOfVision struct {
	cosTable    map[int]float64
	sinTable    map[int]float64
	torchRadius int
}

func (f *FieldOfVision) Initialize() {

	f.cosTable = make(map[int]float64)
	f.sinTable = make(map[int]float64)

	for i := 0; i < 360; i++ {
		ax := math.Sin(float64(i) / (float64(180) / math.Pi))
		ay := math.Cos(float64(i) / (float64(180) / math.Pi))

		f.sinTable[i] = ax
		f.cosTable[i] = ay
	}
}

func (f *FieldOfVision) SetTorchRadius(radius int) {
	if radius > 1 {
		f.torchRadius = radius
	}
}

func (f *FieldOfVision) SetAllInvisible(level *gamemap.Level) {
	for x := 0; x < level.W; x++ {
		for y := 0; y < level.H; y++ {
			level.GetTileByXY(x,y).Visible = false
		}
	}
}

func (f *FieldOfVision) RayCast(playerCoords types.Coords, level *gamemap.Level) {
	// Cast out rays each degree in a 360 circle from the player. If a ray passes over a floor (does not block sight)
	// tile, keep going, up to the maximum torch radius (view radius) of the player. If the ray intersects a wall
	// (blocks sight), stop, as the player will not be able to see past that. Every visible tile will get the Visible
	// and Explored properties set to true.

	for i := 0; i < 360; i++ {

		ax := f.sinTable[i]
		ay := f.cosTable[i]

		x := float64(playerCoords.X)
		y := float64(playerCoords.Y)

		// Mark the players current position as explored
		tile := level.GetTile(playerCoords) //[playerCoords.X][playerCoords.Y]
		tile.Explored = true
		tile.Visible = true

		for j := 0; j < f.torchRadius; j++ {
			x -= ax
			y -= ay

			roundedX := int(Round(x))
			roundedY := int(Round(y))

			if x < 0 || x > float64(level.W -1) || y < 0 || y > float64(level.H -1) {
				// If the ray is cast outside of the gamemap, stop
				break
			}

			tile := level.GetTileByXY(roundedX, roundedY)

			tile.Explored = true
			tile.Visible = true

			if level.GetTileByXY(roundedX, roundedY).BlocksSight == true {
				// The ray hit a wall, go no further
				break
			}
		}
	}
}

func Round(f float64) float64 {
	return math.Floor(f + .5)
}