package net.minecraft.world.gen;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.init.Blocks;
import net.minecraft.util.IProgressUpdate;
import net.minecraft.world.ChunkPosition;
import net.minecraft.world.World;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraft.world.gen.feature.WorldGenDungeons;
import net.minecraft.world.gen.feature.WorldGenLakes;
import net.minecraft.world.gen.structure.MapGenMineshaft;
import net.minecraft.world.gen.structure.MapGenScatteredFeature;
import net.minecraft.world.gen.structure.MapGenStronghold;
import net.minecraft.world.gen.structure.MapGenStructure;
import net.minecraft.world.gen.structure.MapGenVillage;

public class ChunkProviderFlat implements IChunkProvider
{
	private World worldObj;
	private Random random;
	private final Block[] cachedBlockIDs = new Block[256];
	private final byte[] cachedBlockMetadata = new byte[256];
	private final FlatGeneratorInfo flatWorldGenInfo;
	private final List structureGenerators = new ArrayList();
	private final boolean hasDecoration;
	private final boolean hasDungeons;
	private WorldGenLakes waterLakeGenerator;
	private WorldGenLakes lavaLakeGenerator;
	private static final String __OBFID = "CL_00000391";

	public ChunkProviderFlat(World par1World, long par2, boolean par4, String par5Str)
	{
		this.worldObj = par1World;
		this.random = new Random(par2);
		this.flatWorldGenInfo = FlatGeneratorInfo.createFlatGeneratorFromString(par5Str);

		if (par4)
		{
			Map map = this.flatWorldGenInfo.getWorldFeatures();

			if (map.containsKey("village"))
			{
				Map map1 = (Map)map.get("village");

				if (!map1.containsKey("size"))
				{
					map1.put("size", "1");
				}

				this.structureGenerators.add(new MapGenVillage(map1));
			}

			if (map.containsKey("biome_1"))
			{
				this.structureGenerators.add(new MapGenScatteredFeature((Map)map.get("biome_1")));
			}

			if (map.containsKey("mineshaft"))
			{
				this.structureGenerators.add(new MapGenMineshaft((Map)map.get("mineshaft")));
			}

			if (map.containsKey("stronghold"))
			{
				this.structureGenerators.add(new MapGenStronghold((Map)map.get("stronghold")));
			}
		}

		this.hasDecoration = this.flatWorldGenInfo.getWorldFeatures().containsKey("decoration");

		if (this.flatWorldGenInfo.getWorldFeatures().containsKey("lake"))
		{
			this.waterLakeGenerator = new WorldGenLakes(Blocks.water);
		}

		if (this.flatWorldGenInfo.getWorldFeatures().containsKey("lava_lake"))
		{
			this.lavaLakeGenerator = new WorldGenLakes(Blocks.lava);
		}

		this.hasDungeons = this.flatWorldGenInfo.getWorldFeatures().containsKey("dungeon");
		Iterator iterator = this.flatWorldGenInfo.getFlatLayers().iterator();

		while (iterator.hasNext())
		{
			FlatLayerInfo flatlayerinfo = (FlatLayerInfo)iterator.next();

			for (int j = flatlayerinfo.getMinY(); j < flatlayerinfo.getMinY() + flatlayerinfo.getLayerCount(); ++j)
			{
				this.cachedBlockIDs[j] = flatlayerinfo.func_151536_b();
				this.cachedBlockMetadata[j] = (byte)flatlayerinfo.getFillBlockMeta();
			}
		}
	}

	public Chunk loadChunk(int par1, int par2)
	{
		return this.provideChunk(par1, par2);
	}

	public Chunk provideChunk(int par1, int par2)
	{
		Chunk chunk = new Chunk(this.worldObj, par1, par2);
		int l;

		for (int k = 0; k < this.cachedBlockIDs.length; ++k)
		{
			Block block = this.cachedBlockIDs[k];

			if (block != null)
			{
				l = k >> 4;
				ExtendedBlockStorage extendedblockstorage = chunk.getBlockStorageArray()[l];

				if (extendedblockstorage == null)
				{
					extendedblockstorage = new ExtendedBlockStorage(k, !this.worldObj.provider.hasNoSky);
					chunk.getBlockStorageArray()[l] = extendedblockstorage;
				}

				for (int i1 = 0; i1 < 16; ++i1)
				{
					for (int j1 = 0; j1 < 16; ++j1)
					{
						extendedblockstorage.func_150818_a(i1, k & 15, j1, block);
						extendedblockstorage.setExtBlockMetadata(i1, k & 15, j1, this.cachedBlockMetadata[k]);
					}
				}
			}
		}

		chunk.generateSkylightMap();
		BiomeGenBase[] abiomegenbase = this.worldObj.getWorldChunkManager().loadBlockGeneratorData((BiomeGenBase[])null, par1 * 16, par2 * 16, 16, 16);
		byte[] abyte = chunk.getBiomeArray();

		for (l = 0; l < abyte.length; ++l)
		{
			abyte[l] = (byte)abiomegenbase[l].biomeID;
		}

		Iterator iterator = this.structureGenerators.iterator();

		while (iterator.hasNext())
		{
			MapGenStructure mapgenstructure = (MapGenStructure)iterator.next();
			mapgenstructure.func_151539_a(this, this.worldObj, par1, par2, (Block[])null);
		}

		chunk.generateSkylightMap();
		return chunk;
	}

	public boolean chunkExists(int par1, int par2)
	{
		return true;
	}

	public void populate(IChunkProvider par1IChunkProvider, int par2, int par3)
	{
		int k = par2 * 16;
		int l = par3 * 16;
		BiomeGenBase biomegenbase = this.worldObj.getBiomeGenForCoords(k + 16, l + 16);
		boolean flag = false;
		this.random.setSeed(this.worldObj.getSeed());
		long i1 = this.random.nextLong() / 2L * 2L + 1L;
		long j1 = this.random.nextLong() / 2L * 2L + 1L;
		this.random.setSeed((long)par2 * i1 + (long)par3 * j1 ^ this.worldObj.getSeed());
		Iterator iterator = this.structureGenerators.iterator();

		while (iterator.hasNext())
		{
			MapGenStructure mapgenstructure = (MapGenStructure)iterator.next();
			boolean flag1 = mapgenstructure.generateStructuresInChunk(this.worldObj, this.random, par2, par3);

			if (mapgenstructure instanceof MapGenVillage)
			{
				flag |= flag1;
			}
		}

		int l1;
		int i2;
		int j2;

		if (this.waterLakeGenerator != null && !flag && this.random.nextInt(4) == 0)
		{
			l1 = k + this.random.nextInt(16) + 8;
			i2 = this.random.nextInt(256);
			j2 = l + this.random.nextInt(16) + 8;
			this.waterLakeGenerator.generate(this.worldObj, this.random, l1, i2, j2);
		}

		if (this.lavaLakeGenerator != null && !flag && this.random.nextInt(8) == 0)
		{
			l1 = k + this.random.nextInt(16) + 8;
			i2 = this.random.nextInt(this.random.nextInt(248) + 8);
			j2 = l + this.random.nextInt(16) + 8;

			if (i2 < 63 || this.random.nextInt(10) == 0)
			{
				this.lavaLakeGenerator.generate(this.worldObj, this.random, l1, i2, j2);
			}
		}

		if (this.hasDungeons)
		{
			for (l1 = 0; l1 < 8; ++l1)
			{
				i2 = k + this.random.nextInt(16) + 8;
				j2 = this.random.nextInt(256);
				int k1 = l + this.random.nextInt(16) + 8;
				(new WorldGenDungeons()).generate(this.worldObj, this.random, i2, j2, k1);
			}
		}

		if (this.hasDecoration)
		{
			biomegenbase.decorate(this.worldObj, this.random, k, l);
		}
	}

	public boolean saveChunks(boolean par1, IProgressUpdate par2IProgressUpdate)
	{
		return true;
	}

	public void saveExtraData() {}

	public boolean unloadQueuedChunks()
	{
		return false;
	}

	public boolean canSave()
	{
		return true;
	}

	public String makeString()
	{
		return "FlatLevelSource";
	}

	public List getPossibleCreatures(EnumCreatureType par1EnumCreatureType, int par2, int par3, int par4)
	{
		BiomeGenBase biomegenbase = this.worldObj.getBiomeGenForCoords(par2, par4);
		return biomegenbase.getSpawnableList(par1EnumCreatureType);
	}

	public ChunkPosition func_147416_a(World p_147416_1_, String p_147416_2_, int p_147416_3_, int p_147416_4_, int p_147416_5_)
	{
		if ("Stronghold".equals(p_147416_2_))
		{
			Iterator iterator = this.structureGenerators.iterator();

			while (iterator.hasNext())
			{
				MapGenStructure mapgenstructure = (MapGenStructure)iterator.next();

				if (mapgenstructure instanceof MapGenStronghold)
				{
					return mapgenstructure.func_151545_a(p_147416_1_, p_147416_3_, p_147416_4_, p_147416_5_);
				}
			}
		}

		return null;
	}

	public int getLoadedChunkCount()
	{
		return 0;
	}

	public void recreateStructures(int par1, int par2)
	{
		Iterator iterator = this.structureGenerators.iterator();

		while (iterator.hasNext())
		{
			MapGenStructure mapgenstructure = (MapGenStructure)iterator.next();
			mapgenstructure.func_151539_a(this, this.worldObj, par1, par2, (Block[])null);
		}
	}
}