package org.darkstorm.darkbot.minecraftbot.world.block;

import java.util.*;

import org.darkstorm.darkbot.minecraftbot.events.EventManager;
import org.darkstorm.darkbot.minecraftbot.events.world.BlockChangeEvent;
import org.darkstorm.darkbot.minecraftbot.world.*;

public final class Chunk {
	private final World world;
	private final ChunkLocation location;
	private final byte[] blocks, metadata, light, skylight;// add, biomes;
	private final Map<BlockLocation, TileEntity> tileEntities;

	public Chunk(World world, ChunkLocation location, byte[] blocks,
			byte[] metadata, byte[] light, byte[] skylight) {
		this.world = world;
		this.location = location;
		this.blocks = blocks;
		this.metadata = metadata;
		this.light = light;
		this.skylight = skylight;
		tileEntities = new HashMap<BlockLocation, TileEntity>();
	}

	public World getWorld() {
		return world;
	}

	public ChunkLocation getLocation() {
		return location;
	}

	public TileEntity getTileEntityAt(int x, int y, int z) {
		return getTileEntityAt(new BlockLocation(x, y, z));
	}

	public TileEntity getTileEntityAt(BlockLocation location) {
		synchronized(tileEntities) {
			return tileEntities.get(location);
		}
	}

	public int getBlockIdAt(BlockLocation location) {
		return getBlockIdAt(location.getX(), location.getY(), location.getZ());
	}

	public int getBlockIdAt(int x, int y, int z) {
		int index = y << 8 | z << 4 | x;
		if(index < 0 || index > blocks.length)
			return 0;
		return blocks[index];
	}

	public void setBlockIdAt(int id, BlockLocation location) {
		setBlockIdAt(id, location.getX(), location.getY(), location.getZ());
	}

	public void setBlockIdAt(int id, int x, int y, int z) {
		int index = y << 8 | z << 4 | x;
		if(index < 0 || index > blocks.length)
			return;
		BlockLocation location = new BlockLocation((this.location.getX() * 16)
				+ x, (this.location.getY() * 16) + y,
				(this.location.getZ() * 16) + z);
		Block oldBlock = blocks[index] != 0 ? new Block(world, this, location,
				blocks[index], metadata[index]) : null;
		blocks[index] = (byte) id;
		Block newBlock = id != 0 ? new Block(world, this, location, id,
				metadata[index]) : null;
		EventManager eventManager = world.getBot().getEventManager();
		eventManager.sendEvent(new BlockChangeEvent(world, location, oldBlock,
				newBlock));
	}

	public int getBlockMetadataAt(BlockLocation location) {
		return getBlockMetadataAt(location.getX(), location.getY(),
				location.getZ());
	}

	public int getBlockMetadataAt(int x, int y, int z) {
		int index = (x << 8) + (y << 4) + z;
		if(index < 0 || index > metadata.length)
			return 0;
		return metadata[index];
	}

	public void setBlockMetadataAt(int metadata, BlockLocation location) {
		setBlockMetadataAt(metadata, location.getX(), location.getY(),
				location.getZ());
	}

	public void setBlockMetadataAt(int metadata, int x, int y, int z) {
		int index = (x << 8) + (y << 4) + z;
		if(index < 0 || index > this.metadata.length)
			return;
		BlockLocation location = new BlockLocation((this.location.getX() * 16)
				+ x, (this.location.getY() * 16) + y,
				(this.location.getZ() * 16) + z);
		Block oldBlock = new Block(world, this, location, blocks[index],
				this.metadata[index]);
		this.metadata[index] = (byte) metadata;
		Block newBlock = new Block(world, this, location, blocks[index],
				metadata);
		EventManager eventManager = world.getBot().getEventManager();
		eventManager.sendEvent(new BlockChangeEvent(world, location, oldBlock,
				newBlock));
	}

	public int getBlockLightAt(BlockLocation location) {
		return getBlockLightAt(location.getX(), location.getY(),
				location.getZ());
	}

	public int getBlockLightAt(int x, int y, int z) {
		int index = (x << 8) + (y << 4) + z;
		if(index < 0 || index > light.length)
			return 0;
		return light[index];
	}

	public int getBlockSkylightAt(BlockLocation location) {
		return getBlockSkylightAt(location.getX(), location.getY(),
				location.getZ());
	}

	public int getBlockSkylightAt(int x, int y, int z) {
		int index = (x << 8) + (y << 4) + z;
		if(index < 0 || index > skylight.length)
			return 0;
		return skylight[index];
	}
}

@@ -255,17 +255,21 @@
 t.world.
-*
+World
 ;%0A%0Apubli
@@ -1470,24 +1470,31 @@
 locks%5Bindex%5D
+ & 0xFF
 ;%0A%09%7D%0A%0A%09publi
@@ -2631,24 +2631,31 @@
 adata%5Bindex%5D
+ & 0xFF
 ;%0A%09%7D%0A%0A%09publi
@@ -3805,24 +3805,31 @@
 light%5Bindex%5D
+ & 0xFF
 ;%0A%09%7D%0A%0A%09publi
@@ -4108,32 +4108,32 @@
 h)%0A%09%09%09return 0;%0A
-
 %09%09return skyligh
@@ -4140,15 +4140,22 @@
 t%5Bindex%5D
+ & 0xFF
 ;%0A%09%7D%0A%7D%0A

Convert byte block IDs to unsigned to fix block IDs over 127.