package org.ultramine.mods.hawkeye.entry;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import org.ultramine.mods.hawkeye.DataType;
import org.ultramine.mods.hawkeye.HawkEye;
import org.ultramine.mods.hawkeye.util.HawkBlockUtil;

import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTSizeTracker;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.play.server.S23PacketBlockChange;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IChatComponent;
import net.minecraft.world.World;

/**
 * Represents a block-type entry in the database Rollbacks will set the block to
 * the data value
 * 
 * @author oliverw92
 */
public class BlockBreakEntry extends DataEntry
{
	private static final Set<Class<?>> disabledTEs = new HashSet<Class<?>>();
	
	public BlockBreakEntry()
	{
	}

	public BlockBreakEntry(String player, DataType type, World world, double x, double y, double z, Block id, int metadata)
	{
		setInfo(player, type, world, x, y, z);
		loadBlock(world, (int) x, (int) y, (int) z, id, metadata);
	}

	public BlockBreakEntry(EntityPlayer player, DataType type, World world, double x, double y, double z, Block id, int metadata)
	{
		setInfo(player, type, world, x, y, z);
		loadBlock(world, (int) x, (int) y, (int) z, id, metadata);
	}

	private void loadBlock(World world, int x, int y, int z, Block id, int metadata)
	{
		data = Integer.toString(Block.getIdFromBlock(id));
		if(metadata != 0)
			data = data.concat(":").concat(Integer.toString(metadata));

		TileEntity te = world.getTileEntity(x, y, z);
		Class<?> cls;
		if(te != null && HawkEye.instance.config.general.logBlocksSubData && !disabledTEs.contains(cls = te.getClass()))
		{
			try
			{
				NBTTagCompound nbt = new NBTTagCompound();
				te.writeToNBT(nbt);
				nbt.removeTag("id");
				nbt.removeTag("x");
				nbt.removeTag("y");
				nbt.removeTag("z");
				try {
					subdata = CompressedStreamTools.compress(nbt);
				} catch(IOException e){}
			}
			catch (Throwable t)
			{
				t.printStackTrace();
				disabledTEs.add(cls);
			}
		}
	}

	@Override
	public IChatComponent getStringData()
	{
		IChatComponent comp = HawkBlockUtil.getBlockComponent(data);
		comp.getChatStyle().setColor(EnumChatFormatting.RED);
		return comp;
	}

	@Override
	public boolean rollback(World world)
	{
		HawkBlockUtil.setBlockString(world, (int) getX(), (int) getY(), (int) getZ(), data);
		if(subdata != null)
		{
			TileEntity te = world.getTileEntity((int) getX(), (int) getY(), (int) getZ());
			if(te != null)
			{
				NBTTagCompound nbt = null;
				try
				{
					nbt = CompressedStreamTools.func_152457_a(subdata, NBTSizeTracker.field_152451_a);
				}
				catch(IOException e1)
				{
				}

				if(nbt != null)
				{
					nbt.setInteger("x", (int) getX());
					nbt.setInteger("y", (int) getY());
					nbt.setInteger("z", (int) getZ());

					te.readFromNBT(nbt);
				}
			}
		}
		return true;
	}

	@Override
	public boolean rollbackPlayer(World world, EntityPlayerMP player)
	{
		S23PacketBlockChange p = new S23PacketBlockChange((int) getX(), (int) getY(), (int) getZ(), world);
		Block block = Block.getBlockById(HawkBlockUtil.getIdFromString(data));
		if(block != null)
		{
			p.field_148883_d = block;
			p.field_148884_e = HawkBlockUtil.getDataFromString(data);
			player.playerNetServerHandler.sendPacket(p);
			return true;
		}

		return false;
	}

	@Override
	public boolean rebuild(World world)
	{
		if(data == null)
			return false;
		else
			world.setBlockSilently((int) getX(), (int) getY(), (int) getZ(), Blocks.air, 0, 3);
		return true;
	}
}
