package org.terasology.logic.world.generator.core;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import org.terasology.logic.world.WorldBiomeProvider;
import org.terasology.logic.world.chunks.Chunk;
import org.terasology.logic.world.generator.ChunkGenerator;
import org.terasology.model.blocks.Block;
import org.terasology.model.blocks.management.BlockManager;

/**
 * Create a flat world with a specified height. It use the WorldBiomeProvider
 * but not the seed.
 * 
 * @author Mathias Kalb
 */
public class FlatTerrainGenerator implements ChunkGenerator {

    // TODO FlatTerrainGenerator: What is a good value for MAX_Y?
    public static final int MAX_HEIGHT = Chunk.SIZE_Y - 100;
    public static final int MIN_HEIGHT = 0;
    public static final int DEFAULT_HEIGHT = 50;

    private final Logger logger = Logger.getLogger(getClass().getName());

    private WorldBiomeProvider biomeProvider;
    private int height;

    private final Block air;

    public FlatTerrainGenerator() {
        air = BlockManager.getInstance().getAir();
        height = FlatTerrainGenerator.DEFAULT_HEIGHT;
    }

    public FlatTerrainGenerator(final int height) {
        this();
        setHeight(height);
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(final int height) {
        if (height < FlatTerrainGenerator.MIN_HEIGHT) {
            this.height = FlatTerrainGenerator.MIN_HEIGHT;
        } else if (height > FlatTerrainGenerator.MAX_HEIGHT) {
            this.height = FlatTerrainGenerator.MAX_HEIGHT;
        } else {
            this.height = height;
        }
    }

    public boolean isValidHeight(final int height) {
        return height >= FlatTerrainGenerator.MIN_HEIGHT && height <= FlatTerrainGenerator.MAX_HEIGHT;
    }

    /**
     * Seed is not used at the moment.
     */
    @Override
    public void setWorldSeed(final String seed) {
    }

    @Override
    public void setWorldBiomeProvider(final WorldBiomeProvider biomeProvider) {
        this.biomeProvider = biomeProvider;
    }

    @Override
    public Map<String, String> getInitParameters() {
        final Map<String, String> initParameters = new HashMap<String, String>();
        initParameters.put("height", String.valueOf(height));
        return initParameters;
    }

    @Override
    public void setInitParameters(final Map<String, String> initParameters) {
        if (initParameters != null) {
            final String heightStr = initParameters.get("height");
            if (heightStr != null) {
                try {
                    setHeight(Integer.parseInt(heightStr));
                } catch (final NumberFormatException e) {
                    logger.severe("Cannot set initParameters! " + initParameters);
                    // TODO Improved exception handling
                }
            }
        }
    }

    @Override
    public void generateChunk(final Chunk chunk) {
        for (int x = 0; x < Chunk.SIZE_X; x++) {
            for (int z = 0; z < Chunk.SIZE_Z; z++) {
                final WorldBiomeProvider.Biome type = biomeProvider.getBiomeAt(chunk.getBlockWorldPosX(x), chunk.getBlockWorldPosZ(z));

                for (int y = Chunk.SIZE_Y; y >= 0; y--) {
                    if (y == 0) {
                        // bedrock/mantle
                        chunk.setBlock(x, y, z, BlockManager.getInstance().getBlock("MantleStone"));
                    } else if (y < height) {
                        // underground
                        switch (type) {
                        case FOREST:
                            chunk.setBlock(x, y, z, BlockManager.getInstance().getBlock("Dirt"));
                            break;
                        case PLAINS:
                            chunk.setBlock(x, y, z, BlockManager.getInstance().getBlock("Dirt"));
                            break;
                        case MOUNTAINS:
                            chunk.setBlock(x, y, z, BlockManager.getInstance().getBlock("Stone"));
                            break;
                        case SNOW:
                            chunk.setBlock(x, y, z, BlockManager.getInstance().getBlock("Snow"));
                            break;
                        case DESERT:
                            chunk.setBlock(x, y, z, BlockManager.getInstance().getBlock("Sand"));
                            break;
                        }
                    } else if (y == height) {
                        // surface
                        switch (type) {
                        case FOREST:
                            chunk.setBlock(x, y, z, BlockManager.getInstance().getBlock("Dirt"));
                            break;
                        case PLAINS:
                            chunk.setBlock(x, y, z, BlockManager.getInstance().getBlock("Grass"));
                            break;
                        case MOUNTAINS:
                            chunk.setBlock(x, y, z, BlockManager.getInstance().getBlock("Stone"));
                            break;
                        case SNOW:
                            chunk.setBlock(x, y, z, BlockManager.getInstance().getBlock("Snow"));
                            break;
                        case DESERT:
                            chunk.setBlock(x, y, z, BlockManager.getInstance().getBlock("Sand"));
                            break;
                        }
                    } else {
                        // air
                        chunk.setBlock(x, y, z, air);
                    }
                }
            }
        }
    }

}

@@ -590,16 +590,82 @@
 ator %7B%0A%0A
+    private static final String INIT_PARAMETER_HEIGHT = %22height%22;%0A
     // T
@@ -2323,24 +2323,58 @@
 ers.put(
-%22height%22
+FlatTerrainGenerator.INIT_PARAMETER_HEIGHT
 , String
@@ -2616,24 +2616,58 @@
 ers.get(
-%22height%22
+FlatTerrainGenerator.INIT_PARAMETER_HEIGHT
 );%0A     

Constant INIT_PARAMETER_HEIGHT