package ca.recrown.islandsurvivalcraft.world.generation.biomes;

import ca.recrown.islandsurvivalcraft.utilities.GeneralUtilities;
import ca.recrown.islandsurvivalcraft.utilities.biomes.BiomeInfo;
import ca.recrown.islandsurvivalcraft.utilities.caching.Cache;
import ca.recrown.islandsurvivalcraft.utilities.datatypes.Point2;
import ca.recrown.islandsurvivalcraft.utilities.datatypes.Reference;
import ca.recrown.islandsurvivalcraft.utilities.floodfill.Floodable;
import ca.recrown.islandsurvivalcraft.utilities.floodfill.Flooder;
import ca.recrown.islandsurvivalcraft.utilities.pathfinding.CoordinateTargetValidatable;
import ca.recrown.islandsurvivalcraft.world.BiomeMap;
import ca.recrown.islandsurvivalcraft.world.IslandWorldMap;
import ca.recrown.islandsurvivalcraft.world.TemperatureMap;

public class UniqueBiomeGenerator implements BiomeGenerator {

    @Override
    public void generateBiomeColumn(BiomeInfo[][] localBiomeInfo, int chunkX, int chunkZ, int localX, int localZ,
            IslandWorldMap islandMap, BiomeMap biomeSelector, TemperatureMap tempGenerator,
            Cache<Point2, BiomeInfo> biomeCache) {
                int worldX = 16 * chunkX + localX;
                int worldZ = 16 * chunkZ + localZ;
                Point2 worldCoords = new Point2(worldX, worldZ);

                localBiomeInfo[localX][localZ] = biomeCache.get(worldCoords);
                if (localBiomeInfo[localX][localZ] != null) return;

                float temperature = tempGenerator.getTemperature(worldX, worldZ);
                if (!islandMap.isIsland(worldX, worldZ)) {
                    BiomeInfo oceanInfo = biomeSelector.getOceanBiome(temperature);
                    localBiomeInfo[localX][localZ] = oceanInfo;
                    biomeCache.set(worldCoords, oceanInfo);
                    return;
                }

                Reference<BiomeInfo> currentIslandInfo = new Reference<>();
                Point2 islandOrigin = islandMap.findIslandOrigin(worldX, worldZ, new CoordinateTargetValidatable() {
                    @Override
                    public boolean isCoordinateTarget(int x, int y) {
                        Point2 coord = new Point2(x, y);
                        BiomeInfo info = biomeCache.get(coord);
                        if (info == null) return false;
                        currentIslandInfo.value = info;
                        return true;
                    }
                });
                if (currentIslandInfo.value == null) {
                    currentIslandInfo.value = biomeSelector.getLandBiomeInfo(temperature, islandOrigin.x, islandOrigin.y);
                }
                Flooder flooder = new Flooder(worldCoords, new Floodable() {
                    @Override
                    public boolean flood(Point2 point) {
                        Point2 chunkCoords = GeneralUtilities.worldToChunkCoordinates(point);
                        if (chunkCoords.x != chunkX || chunkCoords.y != chunkZ || !islandMap.isIsland(point.x, point.y)) return false;
                        biomeCache.set(point, currentIslandInfo.value);
                        Point2 localCoords = GeneralUtilities.worldToLocalChunkCoordinates(point);
                        localBiomeInfo[localCoords.x][localCoords.y] = currentIslandInfo.value;
                        return true;
                    }
                });
                flooder.start();
    }

}