package projectzombie.world.layer.layergen;

import java.util.Random;

import gl_engine.MathHelpers;
import gl_engine.vec.Vec2d;
import gl_engine.vec.Vec2i;
import gl_engine.vec.Vec3d;
import projectzombie.Main;
import projectzombie.entity.Entity;
import projectzombie.entity.EntityZombieArmored;
import projectzombie.init.Tiles;
import projectzombie.util.ColorRange;
import projectzombie.util.TileState;
import projectzombie.util.math.random.NoiseGenerator;
import projectzombie.util.math.random.NoiseGeneratorSimplex;
import projectzombie.util.math.random.RandomHelpers;
import projectzombie.world.chunk.Chunk;
import projectzombie.world.layer.Layer;

public class LayerGenLavaCaves extends LayerGen
{
	@Override
	public void init(Layer layer) {
		super.init(layer);
		
		Random rand = new Random(layer.lseed);
		
		layer.noise_gens = new NoiseGenerator[] {
				new NoiseGeneratorSimplex(rand),
				new NoiseGeneratorSimplex(rand),
		};
	}

	@Override
	public void generateChunk(Chunk chunk, Layer layer, Random rand, Vec2i pos)
	{
		// Make sure the random generated is the same
		if(PortalSpawnrates.WorldCavePortal(rand)) {
			rand.nextDouble();
			rand.nextDouble();
		}
		
		boolean hasLadder = PortalSpawnrates.CaveLavaCavePortal(rand);
		Vec2i ladder_pos = null;
		if(hasLadder) {
			ladder_pos = new Vec2i(
					RandomHelpers.randrange(rand, 16),
					RandomHelpers.randrange(rand, 16));
		}
		
		boolean hasBossPortal = PortalSpawnrates.LavaCaveBossArenaPortal(rand);
		Vec2i boss_portal_pos = null;
		if(hasBossPortal) {
			boss_portal_pos = new Vec2i(
					RandomHelpers.randrange(rand, 16),
					RandomHelpers.randrange(rand, 16));
		}
		
		// Loop over the chunk
		for(int x=0;x<Chunk.CHUNK_SIZE.mx;x++) {
			for(int y=0;y<Chunk.CHUNK_SIZE.my;y++)
			{
				// Get the x and y in the world
				int cx = x + pos.x * Chunk.CHUNK_SIZE.mx;
				int cy = y + pos.y * Chunk.CHUNK_SIZE.my;
				
				// Get the noise value and the position vector
				double noise_n = (layer.noise_gens[0].eval(cx/128.0, cy/128.0) + 1) * 50;
				double noise_c = (layer.noise_gens[1].eval(cx/16.0, cy/16.0) + 1) * 50;
				Vec2i tpos = new Vec2i(x, y);
				
				chunk.setTemperature(tpos, 0.8);
				chunk.setHumidity(tpos, 0);
				
				if(noise_n > 60 || noise_n < 20) {
					chunk.setBackTile(Tiles.STONE.getDefaultState(), tpos);
				}
				
				else
				{
					if(noise_c > 40 && noise_c < 60) {
						chunk.setBackTile(Tiles.STONE.getDefaultState(), tpos);
					}
					
					else {
						chunk.setBackTile(Tiles.WALL.getDefaultState(), tpos);
					}
				}
				
				if(noise_n > 58 && noise_n < 60 && noise_c > 40 && noise_c < 60) {
					chunk.setFrontTile(Tiles.LAVA_FLOW.getDefaultState(), tpos);
				}
				
				else if(noise_n > 60) {
					chunk.setFrontTile(Tiles.LAVA.getDefaultState(), tpos);
				}
			}
		}
		
		if(hasLadder) {
			chunk.setFrontTile(new TileState(Tiles.LADDER_UP, (short)1), ladder_pos);
		}
		
		if(
				hasBossPortal && 
				chunk.getBackTile(boss_portal_pos).tile == Tiles.STONE &&
				chunk.getFrontTile(boss_portal_pos).tile == Tiles.VOID) {
			chunk.setFrontTile(Tiles.BOSS_PORTAL.getDefaultState(), boss_portal_pos);
		}
		
		Vec2i chest_pos = new Vec2i(
				RandomHelpers.randrange(rand, Chunk.CHUNK_SIZE.mx),
				RandomHelpers.randrange(rand, Chunk.CHUNK_SIZE.my));
		Vec2i lava_flow_pos = new Vec2i(
				RandomHelpers.randrange(rand, Chunk.CHUNK_SIZE.mx),
				RandomHelpers.randrange(rand, Chunk.CHUNK_SIZE.my));
		
		// Only place a chest here if the tile is clear
		if(
				chunk.getBackTile(chest_pos).tile == Tiles.STONE &&
				chunk.getFrontTile(chest_pos).tile == Tiles.VOID) {
			chunk.setFrontTile(new TileState(Tiles.CHEST, 2), chest_pos);
		}
		if(
				chunk.getBackTile(lava_flow_pos).tile == Tiles.STONE &&
				chunk.getFrontTile(lava_flow_pos).tile == Tiles.VOID) {
			chunk.setFrontTile(Tiles.LAVA_FLOW.getDefaultState(), lava_flow_pos);
		}
	}

	@Override
	public void spawnEntities(Layer layer, Random rand)
	{
		if(rand.nextDouble() > 0.9)
		{
			Vec3d ppos = Main.player.getPos();
			
			Entity zombie = new EntityZombieArmored(new Vec3d(
					RandomHelpers.randrange(rand, (int)ppos.x - 128, (int)ppos.x + 128), 0,
					RandomHelpers.randrange(rand, (int)ppos.z - 128, (int)ppos.z + 128)),
					new Vec3d(0, 0, 0));
			
			Vec3d zpos = zombie.getPos();
			boolean exists = false;
			
			for(Entity e : layer.getChunk(zpos.xz()).entities) {
				if(e.getClass() == zombie.getClass()) {
					exists = true;
					break;
				}
			}
			
			if(!exists)
			{
				TileState tsb = layer.getBackTile(new Vec2i((int)zpos.x,
						(int)zpos.z));
				TileState tsf = layer.getFrontTile(new Vec2i((int)zpos.x,
						(int)zpos.z));
				
				if(
						tsb.tile == Tiles.STONE &&
						tsf.tile == Tiles.VOID &&
						zpos.squareDistance(ppos) > 32) {
					layer.spawnEntity(zombie);
				}
			}
		}
	}

	@Override
	public TileState getTileDestroyed(Layer layer, Vec2i pos) {
		return Tiles.STONE.getDefaultState();
	}

	@Override
	public ColorRange getLightLevel() {
		return new ColorRange(new Vec3d(0, 0, 0), new Vec3d(0, 0, 0));
	}
	
	@Override
	public double getTemperature(Layer layer, Vec2d pos) {
		return MathHelpers.map(layer.noise_gens[0].eval(pos.x / 128, pos.y / 128), -1, 1, 0.8, 1);
	}

}
