package floor

import (
	"fmt"

	"gitlab.univ-nantes.fr/jezequel-l/quadtree/configuration"
	"gitlab.univ-nantes.fr/jezequel-l/quadtree/quadtree"
)

/// EXTENSION 5 : bloc bloquant (note : marche en FloorKind 1 et 2) ///

// BlockingAndWater reprend la méthode Blocking, en rajoutant comme cases bloquantes celles d'eau (valeur 4)
func (f *Floor) BlockingAndWater(characterXPos, characterYPos, camXPos, camYPos int) (waterBlocking [4]bool) {

	relativeXPos := characterXPos - camXPos + configuration.Global.ScreenCenterTileX
	relativeYPos := characterYPos - camYPos + configuration.Global.ScreenCenterTileY

	waterBlocking[0] = relativeYPos <= 0 || f.content[relativeYPos-1][relativeXPos] == -1 || f.content[relativeYPos-1][relativeXPos] == 4
	waterBlocking[1] = relativeXPos >= configuration.Global.NumTileX-1 || f.content[relativeYPos][relativeXPos+1] == -1 || f.content[relativeYPos][relativeXPos+1] == 4
	waterBlocking[2] = relativeYPos >= configuration.Global.NumTileY-1 || f.content[relativeYPos+1][relativeXPos] == -1 || f.content[relativeYPos+1][relativeXPos] == 4
	waterBlocking[3] = relativeXPos <= 0 || f.content[relativeYPos][relativeXPos-1] == -1 || f.content[relativeYPos][relativeXPos-1] == 4
	return waterBlocking
}

// SpawnOnWater déplace le personnage sur une case viable à proximité du point d'apparition,
// si ce dernier est un bloc d'eau. Dans le cas où le terrain complet n'est qu'un océan,
// un simple radeau de fortune est accordé au personnage pour éviter qu'il se noie
// (traduction : le point d'apparition devient un bloc de bois, de valeur 3)
func (f *Floor) SpawnOnWater(spawnX, spawnY int) (neoSpawnX, neoSpawnY int) {

	if configuration.Global.FloorKind == 1 {

		ocean := f.WaterWorld()
		if ocean {
			f.fullContent[spawnY][spawnX] = 3
			fmt.Println("C'était ça ou le laisser se noyer dans l'océan ; le pauvre ne sait pas nager.")
		} else {

			if f.fullContent[spawnY][spawnX] != 4 && f.fullContent[spawnY][spawnX] != -1 {
				return spawnX, spawnY
			} else {

				if spawnY-1 >= 0 {
					foundX, foundY := f.SpawnOnWater(spawnX, spawnY-1)
					if foundX != -1 && foundY != -1 {
						return f.SpawnOnWater(spawnX, spawnY-1)
					}
				}
				if spawnY+1 < f.GetHeight() {
					foundX, foundY := f.SpawnOnWater(spawnX, spawnY+1)
					if foundX != -1 && foundY != -1 {
						return f.SpawnOnWater(spawnX, spawnY+1)
					}
				}
				if spawnX-1 >= 0 {
					foundX, foundY := f.SpawnOnWater(spawnX-1, spawnY)
					if foundX != -1 && foundY != -1 {
						return f.SpawnOnWater(spawnX-1, spawnY)
					}
				}
				if spawnX+1 < f.GetWidth() {
					foundX, foundY := f.SpawnOnWater(spawnX+1, spawnY)
					if foundX != -1 && foundY != -1 {
						return f.SpawnOnWater(spawnX+1, spawnY)
					}
				}
			}
		}
	}

	if configuration.Global.FloorKind == 2 {

		contentHolder := make([][]int, f.QuadtreeContent.GetHeight())
		for y := range contentHolder {
			contentHolder[y] = make([]int, f.QuadtreeContent.GetWidth())
		}
		f.QuadtreeContent.GetContent(0, 0, contentHolder)

		ocean := f.WaterWorld()
		if ocean {
			contentHolder[spawnY][spawnX] = 3
			f.QuadtreeContent = quadtree.MakeFromArray(contentHolder)
			fmt.Println("C'était ça ou le laisser se noyer dans l'océan ; le pauvre ne sait pas nager.")
		} else {

			if contentHolder[spawnY][spawnX] != 4 && contentHolder[spawnY][spawnX] != -1 {
				return spawnX, spawnY
			} else {
				if spawnY-1 >= 0 {
					foundX, foundY := f.SpawnOnWater(spawnX, spawnY-1)
					if foundX != -1 && foundY != -1 {
						return f.SpawnOnWater(spawnX, spawnY-1)
					}
				}
				if spawnY+1 < f.QuadtreeContent.GetHeight() {
					foundX, foundY := f.SpawnOnWater(spawnX, spawnY+1)
					if foundX != -1 && foundY != -1 {
						return f.SpawnOnWater(spawnX, spawnY+1)
					}
				}
				if spawnX-1 >= 0 {
					foundX, foundY := f.SpawnOnWater(spawnX-1, spawnY)
					if foundX != -1 && foundY != -1 {
						return f.SpawnOnWater(spawnX-1, spawnY)
					}
				}
				if spawnX+1 < f.QuadtreeContent.GetWidth() {
					foundX, foundY := f.SpawnOnWater(spawnX+1, spawnY)
					if foundX != -1 && foundY != -1 {
						return f.SpawnOnWater(spawnX+1, spawnY)
					}
				}
			}
		}
	}
	return -1, -1
}

// Fonction intermédiaire : WaterWorld vérifie que le terrain n'est pas qu'un vaste océan,
// dans quel cas chercher une case viable aux alentours serait vain
func (f *Floor) WaterWorld() bool {

	if configuration.Global.FloorKind == 1 {
		for i := 0; i < f.GetHeight(); i++ {
			for j := 0; j < f.GetWidth(); j++ {
				if f.fullContent[i][j] != 4 {
					return false
				}
			}
		}
		return true
	}

	if configuration.Global.FloorKind == 2 {
		if f.QuadtreeContent.ValueIfUnique() != 4 {
			return false
		}
	}
	return true
}
