package common.biome;

import java.util.List;
import java.util.Map;

import common.collect.Lists;
import common.collect.Maps;
import common.color.Colorizer;
import common.log.Log;
import common.rng.PerlinGen;
import common.rng.Random;
import common.util.BlockPos;
import common.util.ExtMath;

public enum Biome {
	NONE(0, "none", "<Keins>", 0x000000),
	PLAINS(1, "plains", "Ebene", 0x8db360, 12.0f, 40.0f),
	DESERT(2, "desert", "Wüste", 0xfa9418, 60.0f, 0.0f),
	EXTREMEHILLS(3, "extremeHills", "Extremes Bergland", 0x606060, -12.0f, 30.0f),
	FOREST(4, "forest", "Wald", 0x056621, 8.0f, 80.0f),
	TAIGA(5, "taiga", "Taiga", 0x0b6659, -10.0f, 80.0f),
	SWAMPLAND(6, "swampland", "Sumpf", 0x07f9b2, 12.0f, 90.0f, 0xe0ffae, 0xffffffff, 6975545),
	RIVER(7, "river", "Fluss", 0x0000ff),
	EXTERMINATED(8, "exterminated", "Ausgelöscht", 0x000000, 150.0f, 0.0f, 0x202020, 0x303030, 0x303030, 0x101010, 0x303030, 0x000000),
	SPACE(9, "space", "Leere des Weltraums", 0x000000, 0.0f, 0.0f),
	FROZENSEA(10, "frozenSea", "Vereister See", 0x9090a0, -20.0f),
	FROZENRIVER(11, "frozenRiver", "Vereister Fluss", 0xa0a0ff, -20.0f),
	ICEPLAINS(12, "icePlains", "Eisebene", 0xffffff, -20.0f),
	ICEMOUNTAINS(13, "iceMountains", "Vereistes Bergland", 0xa0a0a0, -20.0f),
	MUSHROOMPLAINS(14, "mushroomPlains", "Pilzland", 0xff00ff, 16.0f, 100.0f),
	BLACKENED(15, "blackened", "Schwarz", 0x000000, 0.0f, 0.0f, 0x000000, 0x303030, 0x303030),
	BEACH(16, "beach", "Strand", 0xfade55, 12.0f, 40.0f),
	DESERTHILLS(17, "desertHills", "Wüsten-Bergland", 0xd25f12, 60.0f, 0.0f),
	FORESTHILLS(18, "forestHills", "Wald-Bergland", 0x22551c, 8.0f, 80.0f),
	TAIGAHILLS(19, "taigaHills", "Taiga-Bergland", 0x163933, -10.0f, 80.0f),
	EXTREMEHILLSEDGE(20, "extremeHillsEdge", "Extremes Bergland Gr.", 0x72789a, -12.0f, 30.0f),
	JUNGLE(21, "jungle", "Urwald", 0x537b09, 18.0f, 90.0f),
	JUNGLEHILLS(22, "jungleHills", "Urwald-Bergland", 0x2c4205, 18.0f, 90.0f),
	JUNGLEEDGE(23, "jungleEdge", "Urwald Gr.", 0x628b17, 18.0f, 80.0f),
	SEA(24, "sea", "See", 0x000070),
	STONEBEACH(25, "stoneBeach", "Steinstrand", 0xa2a284, -12.0f, 30.0f),
	COLDBEACH(26, "coldBeach", "Vereister Strand", 0xfaf0c0, -18.0f, 30.0f),
	BIRCHFOREST(27, "birchForest", "Birkenwald", 0x307444, 4.0f, 60.0f),
	BIRCHFORESTHILLS(28, "birchForestHills", "Birkenwald-Bergland", 0x1f5f32, 4.0f, 60.0f),
	ROOFEDFOREST(29, "roofedForest", "Dichter Wald", 0x40511a, 8.0f, 80.0f),
	COLDTAIGA(30, "coldTaiga", "Vereiste Taiga", 0x31554a, -40.0f, 40.0f),
	COLDTAIGAHILLS(31, "coldTaigaHills", "Vereistes Taiga-Bergland", 0x243f36, -40.0f, 40.0f),
	MEGATAIGA(32, "megaTaiga", "Hohe Taiga", 0x596651, -8.0f, 80.0f),
	MEGATAIGAHILLS(33, "megaTaigaHills", "Hohes Taiga-Bergland", 0x454f3e, -8.0f, 80.0f),
	EXTREMEHILLSPLUS(34, "extremeHillsPlus", "Extremes Bergland +", 0x507050, -12.0f, 30.0f),
	SAVANNA(35, "savanna", "Savanne", 0xbdb25f, 28.0f, 0.0f),
	SAVANNAPLATEAU(36, "savannaPlateau", "Savannen-Plateau", 0xa79d64, 20.0f, 0.0f),
	MESA(37, "mesa", "Mesa", 0xd94515, 0.0f, 0.0f, 0xffffff, 9470285, 10387789),
	MESAPLATEAUF(38, "mesaPlateauF", "Mesa-Waldplateau", 0xb09765, 0.0f, 0.0f, 0xffffff, 9470285, 10387789),
	MESAPLATEAU(39, "mesaPlateau", "Mesa-Plateau", 0xca8c65, 0.0f, 0.0f, 0xffffff, 9470285, 10387789),
	SNOWLAND(40, "snowLand", "Eisland", 0xffffff, 0.0f, 100.0f),
	TIAN(41, "tian", "Tian", 0x808080, 0.0f, 80.0f),
	ELVENFOREST(42, "elvenForest", "Elbenwald", 0x059821, 8.0f, 90.0f),
	UPPERHELL(43, "upperHell", "Übergang in die Hölle", 0xff0000, 0.0f, 0.0f, 0x000000, 0x000000, 0x000000),
	LOWERHELL(44, "lowerHell", "Abgrund der Hölle", 0xff0000, 0.0f, 0.0f, 0x000000, 0x000000, 0x000000),
	HELLHILLS(45, "hellHills", "Bergland der Hölle", 0xff0000, 0.0f, 0.0f, 0x000000, 0x000000, 0x000000),
	SOULPLAINS(46, "soulPlains", "Seelenland", 0xff0000, 0.0f, 0.0f, 0x000000, 0x000000, 0x000000),
	ASHLAND(47, "ashLand", "Verbrannt", 0xff0000, 0.0f, 0.0f, 0x000000, 0x000000, 0x000000),
	MOON(48, "moon", "Mondoberfläche", 0xa0a0a0, 0.0f, 0.0f),
	CHAOS(49, "chaos", "Chaos", 0xff00ff),
	
	DESERTM(130, "desertM", "Wüste M", 0xfa9418, 60.0f, 0.0f),
	EXTREMEHILLSM(131, "extremeHillsM", "Extremes Bergland M", 0x606060, -12.0f, 30.0f),
	FLOWERFOREST(132, "flowerForest", "Blumenwald", 0x6a7425, 8.0f, 80.0f),
	TAIGAM(133, "taigaM", "Taiga M", 0x0b6659, -10.0f, 80.0f),
	SWAMPLANDM(134, "swamplandM", "Sumpf M", 0x07f9b2, 12.0f, 90.0f, 0xe0ffae, 0xffffffff, 6975545),
	ICEPLAINSSPIKES(140, "icePlainsSpikes", "Eisebene + Spitzen", 0xd2ffff, -20.0f),
	JUNGLEM(149, "jungleM", "Urwald M", 0x537b09, 18.0f, 90.0f),
	JUNGLEEDGEM(151, "jungleEdgeM", "Urwald Gr. M", 0x628b17, 18.0f, 80.0f),
	BIRCHFORESTM(155, "birchForestM", "Birkenwald M", 0x307444, 4.0f, 60.0f),
	BIRCHFORESTHILLSM(156, "birchForestHillsM", "Birkenwald-Bergland M", 0x1f5f32, 4.0f, 60.0f),
	ROOFEDFORESTM(157, "roofedForestM", "Dichter Wald M", 0x40511a, 8.0f, 80.0f),
	COLDTAIGAM(158, "coldTaigaM", "Vereiste Taiga M", 0x31554a, -40.0f, 40.0f),
	MEGASPRUCETAIGA(160, "megaSpruceTaiga", "Hohe Fichtentaiga", 0x596651, -10.0f, 80.0f),
	REDWOODTAIGAHILLSM(161, "redwoodTaigaHillsM", "Mammutbaumtaiga", 0x596651, -10.0f, 80.0f),
	EXTREMEHILLSPLUSM(162, "extremeHillsPlusM", "Extremes Bergland + M", 0x507050, -12.0f, 30.0f),
	SAVANNAM(163, "savannaM", "Savanne M", 0xbdb25f, 24.0f, 0.0f),
	SAVANNAPLATEAUM(164, "savannaPlateauM", "Savannen-Plateau M", 0xa79d64, 20.0f, 0.0f),
	MESABRYCE(165, "mesaBryce", "Mesa (Bryce)", 0xd94515, 0.0f, 0.0f, 0xffffff, 9470285, 10387789),
	MESAPLATEAUFM(166, "mesaPlateauFM", "Mesa-Waldplateau M", 0xb09765, 0.0f, 0.0f, 0xffffff, 9470285, 10387789),
	MESAPLATEAUM(167, "mesaPlateauM", "Mesa-Plateau M", 0xca8c65, 0.0f, 0.0f, 0xffffff, 9470285, 10387789);

    public static final Biome DEF_BIOME = FOREST;
    private static final PerlinGen TEMP_NOISE = new PerlinGen(new Random(836430928262265276L), 1);
    private static final PerlinGen COLOR_NOISE = new PerlinGen(new Random(6549321755809421L), 1);
	private static final Biome[] BIOMES = new Biome[256];
    private static final Map<String, Biome> LOOKUP = Maps.newTreeMap();
	
    public final int id;
    public final String name;
    public final String display;
    public final int color;
    public final float temperature;
    public final float humidity;
    public final int waterColor;
    public final int grassColor;
    public final int foliageColor;
    public final int skyColor;
    public final int fogColor;
    public final int cloudColor;
    
    static {
        for(Biome biome : values()) {
            BIOMES[biome.id] = biome;
            if(LOOKUP.containsKey(biome.name.toLowerCase()))
                throw new IllegalStateException("Biom \"" + biome.name + "\" ist als ID " + LOOKUP.get(biome.name.toLowerCase()).id + " und " + biome.id + " definiert");
            LOOKUP.put(biome.name.toLowerCase(), biome);
        }
    }
    
    public static Biome getBiome(int id)
    {
        if (id >= 0 && id < BIOMES.length)
        {
        	return BIOMES[id];
        }
        else
        {
        	Log.TICK.warn("Biom-ID ist nicht im Bereich: " + id + ", verwende " + DEF_BIOME.id + " (" + DEF_BIOME.name + ")");
            return DEF_BIOME;
        }
    }

    public static Biome getBiomeDef(int id)
    {
        if (id >= 0 && id < BIOMES.length)
        {
        	Biome biome = BIOMES[id];
            return biome == null ? DEF_BIOME : biome;
        }
        else
        {
        	Log.TICK.warn("Biom-ID ist nicht im Bereich: " + id + ", verwende " + DEF_BIOME.id + " (" + DEF_BIOME.name + ")");
            return DEF_BIOME;
        }
    }
    
    public static List<String> getBiomeNames() {
        return Lists.newArrayList(LOOKUP.keySet());
    }

    public static Biome findByName(String name) {
    	Biome biome = LOOKUP.get(name.toLowerCase().replace(" ", "").replace("_", ""));
    	if(biome == null) {
    		int z;
    		try {
    			z = Integer.parseInt(name);
    		}
    		catch(NumberFormatException e) {
    			return DEF_BIOME;
    		}
    		return z < 0 || z >= BIOMES.length || BIOMES[z] == null ? DEF_BIOME : BIOMES[z];
    	}
    	return biome;
	}

    private Biome(int id, String name, String display, int color, float temperature, float humidity, int waterColor, int grassColor, int foliageColor, int skyColor, int fogColor, int cloudColor) {
        this.id = id;
        this.name = name;
        this.display = display;
        this.temperature = temperature;
        this.humidity = humidity;
        this.color = color;
        this.waterColor = waterColor;
        this.grassColor = grassColor;
        this.foliageColor = foliageColor;
        this.skyColor = skyColor;
        this.fogColor = fogColor;
        this.cloudColor = cloudColor;
    }

    private Biome(int id, String name, String display, int color, float temperature, float humidity, int waterColor, int grassColor, int foliageColor) {
        this(id, name, display, color, temperature, humidity, waterColor, grassColor, foliageColor, 0xffffffff, 0xffffffff, 0xffffffff);
    }

    private Biome(int id, String name, String display, int color, float temperature, float humidity) {
        this(id, name, display, color, temperature, humidity, 0xffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
    }

    private Biome(int id, String name, String display, int color, float temperature) {
        this(id, name, display, color, temperature, 50.0f, 0xffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
    }

    private Biome(int id, String name, String display, int color) {
        this(id, name, display, color, 0.0f, 50.0f, 0xffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
    }

    public final float getTemperature(BlockPos pos) {
        if(pos.getY() > 64) {
            float f = (float)(TEMP_NOISE.generate((double)pos.getX() * 1.0D / 8.0D, (double)pos.getZ() * 1.0D / 8.0D) * 4.0D);
            return this.temperature - (f + (float)pos.getY() - 64.0F) / 15.0f;
        }
        return this.temperature;
    }
    
    public float getFactor() {
    	float f = this.humidity * 0.01f * ((this.temperature + 14.0f) / 40.0f + 0.15f);
    	return f > 1.0f ? 1.0f : f;
    }
    
    public boolean isHighHumidity() {
        return this.humidity > 85.0f;
    }
    
    // skycolor = ((temp + 14) / 40 + 0.15) / 3
    
    public int getGrassColorAtPos(BlockPos pos) {
    	if(this.grassColor != 0xffffffff)
    		return this.grassColor;
    	if(this == SWAMPLAND || this == SWAMPLANDM) {
            double d0 = COLOR_NOISE.generate((double)pos.getX() * 0.0225D, (double)pos.getZ() * 0.0225D);
            return d0 < -0.1D ? 5011004 : 6975545;
    	}
    	if(this == ELVENFOREST)
    		return Colorizer.getGrassColor(1.0f, this.humidity * 0.01f);
        double d0 = (double)ExtMath.clampf((this.getTemperature(pos) + 14.0f) / 40.0f + 0.15f, 0.0F, 1.0F);
        double d1 = (double)ExtMath.clampf(this.humidity * 0.01f, 0.0F, 1.0F);
        return this == ROOFEDFOREST || this == ROOFEDFORESTM ? (Colorizer.getGrassColor(d0, d1) & 16711422) + 2634762 >> 1 : Colorizer.getGrassColor(d0, d1);
    }
    
    public int getFoliageColorAtPos(BlockPos pos) {
    	if(this.foliageColor != 0xffffffff)
    		return this.foliageColor;
    	if(this == ELVENFOREST)
    		return Colorizer.getFoliageColor(1.0f, this.humidity * 0.01f);
        double d0 = (double)ExtMath.clampf((this.getTemperature(pos) + 14.0f) / 40.0f + 0.15f, 0.0F, 1.0F);
        double d1 = (double)ExtMath.clampf(this.humidity * 0.01f, 0.0F, 1.0F);
        return Colorizer.getFoliageColor(d0, d1);
    }
}
