package ca.recrown.islandsurvivalcraft.world;

import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang.NullArgumentException;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.generator.ChunkGenerator;

import ca.recrown.islandsurvivalcraft.world.generation.GeneratorModes;
import ca.recrown.islandsurvivalcraft.world.generation.chunks.IslandWorldChunkGenerator;

public class WorldInfoManager implements Listener {
    public final ConcurrentHashMap<UUID, WorldInfo> worldInformation = new ConcurrentHashMap<>();

    /**
     * Return the world info requested for the given world.
     * Should not be null.
     * @param world The world the associated info is to be requested for.
     * @return The world info.
     */
    public WorldInfo retrieve(World world) {
        if (world == null) throw new NullArgumentException("world");
        return worldInformation.computeIfAbsent(world.getUID(), (worldInfo) -> {
            return new WorldInfo(this, world);
        });
    }

    /**
     * Resets the manager deleting all currently loaded world info from memory.
     */
    public void reset() {
        worldInformation.clear();
    }

    /**
     * Returns a chunk generator.
     * @param world The world the chunk generator is for. If it does not yet exist, it will be created.
     * @return The chunk generator associated with the given world.
     */
    public ChunkGenerator getChunkGenerator(World world, GeneratorModes mode) {
        WorldInfo worldInfo = null;
        if (world != null) {
            worldInfo = retrieve(world);
            if (!worldInfo.getGenerator().isInitialized()) {
                worldInfo.getGenerator().setGeneratorType(mode);
                worldInfo.getGenerator().initialize();
            }
            return worldInfo.getGenerator();
        } else {
            worldInfo = new WorldInfo(this, null);
            IslandWorldChunkGenerator generator = new IslandWorldChunkGenerator(worldInfo);
            generator.setGeneratorType(mode);
            return generator;
        }
    }

    @EventHandler(priority = EventPriority.MONITOR)
    public void onChunkLoaded(ChunkLoadEvent event) {
        if (event.isNewChunk()) {
            Chunk chunk = event.getChunk();
            retrieve(event.getWorld()).getGenerator().updateChunkLoadedCache(chunk.getX(), chunk.getZ());
        }
    }

    protected void register(World world, WorldInfo worldInfo) {
        worldInformation.put(world.getUID(), worldInfo);
    }
}