package org.ultramine.mods.hawkeye.entry;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.ultramine.mods.hawkeye.DataType;
import org.ultramine.mods.hawkeye.util.HawkInventoryUtil;
import org.ultramine.server.util.InventoryUtil;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTSizeTracker;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.IChatComponent;
import net.minecraft.world.World;

/**
 * Represents a container transaction as created in {@MonitorInventoryListener
 * 
 * }
 * 
 * @author oliverw92
 */
public class ContainerEntry extends DataEntry
{
	private static final Logger log = LogManager.getLogger();
	
	public ContainerEntry()
	{
	}

	public ContainerEntry(EntityPlayer player, World world, double x, double y, double z, String diff)
	{
		data = diff;
		setInfo(player, DataType.CONTAINER_TRANSACTION, world, x, y, z);
	}

	public ContainerEntry(String player, World world, double x, double y, double z, String diff)
	{
		data = diff;
		setInfo(player, DataType.CONTAINER_TRANSACTION, world, x, y, z);
	}

	@Override
	public IChatComponent getStringData()
	{
		return data.length() <= 1 ? new ChatComponentText("invisible changes") : HawkInventoryUtil.createChangeComponent(HawkInventoryUtil.interpretDifferenceString(data));
	}

	@Override
	public boolean rollback(World world)
	{
		TileEntity te = world.getTileEntity((int) getX(), (int) getY(), (int) getZ());
		if(!(te instanceof IInventory))
			return false;
		IInventory inv = (IInventory) te;
		
		byte[] subdata = getSubData();
		if(subdata != null)
		{
			try
			{
				NBTTagCompound all = CompressedStreamTools.func_152457_a(subdata, NBTSizeTracker.field_152451_a);
				NBTTagList add = all.getTagList("add", 10);
				for(int i = 0; i < add.tagCount(); i++)
					InventoryUtil.removeItem(HawkInventoryUtil.getInvContents(inv), HawkInventoryUtil.loadFromNBT(add.getCompoundTagAt(i)));
				NBTTagList sub = all.getTagList("sub", 10);
				for(int i = 0; i < sub.tagCount(); i++)
					InventoryUtil.addItem(HawkInventoryUtil.getInvContents(inv), HawkInventoryUtil.loadFromNBT(sub.getCompoundTagAt(i)), false, true);
			}
			catch(IOException e)
			{
				log.error("Failed to load stored inventory NBT", e);
			}
		}
		else
		{
			List<HashMap<String, Integer>> ops = HawkInventoryUtil.interpretDifferenceString(data);
			//Handle the additions
			if(ops.size() > 0)
			{
				for(ItemStack stack : HawkInventoryUtil.uncompressInventory(ops.get(0)))
					HawkInventoryUtil.removeItem(HawkInventoryUtil.getInvContents(inv), stack);
			}
			//Handle subtractions
			if(ops.size() > 1)
			{
				for(ItemStack stack : HawkInventoryUtil.uncompressInventory(ops.get(1)))
					HawkInventoryUtil.addItem(HawkInventoryUtil.getInvContents(inv), stack);
			}
		}
		return true;
	}

	@Override
	public boolean rebuild(World world)
	{
		TileEntity te = world.getTileEntity((int) getX(), (int) getY(), (int) getZ());
		if(!(te instanceof IInventory))
			return false;
		IInventory inv = (IInventory) te;
		byte[] subdata = getSubData();
		if(subdata != null)
		{
			try
			{
				NBTTagCompound all = CompressedStreamTools.func_152457_a(subdata, NBTSizeTracker.field_152451_a);
				NBTTagList add = all.getTagList("add", 10);
				for(int i = 0; i < add.tagCount(); i++)
					InventoryUtil.addItem(HawkInventoryUtil.getInvContents(inv), HawkInventoryUtil.loadFromNBT(add.getCompoundTagAt(i)));
				NBTTagList sub = all.getTagList("sub", 10);
				for(int i = 0; i < sub.tagCount(); i++)
					InventoryUtil.removeItem(HawkInventoryUtil.getInvContents(inv), HawkInventoryUtil.loadFromNBT(sub.getCompoundTagAt(i)));
			}
			catch(IOException e)
			{
				log.error("Failed to load stored inventory NBT", e);
			}
		}
		else
		{
			List<HashMap<String, Integer>> ops = HawkInventoryUtil.interpretDifferenceString(data);
			//Handle the additions
			if(ops.size() > 0)
			{
				for(ItemStack stack : HawkInventoryUtil.uncompressInventory(ops.get(0)))
					HawkInventoryUtil.addItem(HawkInventoryUtil.getInvContents(inv), stack);
			}
			//Handle subtractions
			if(ops.size() > 1)
			{
				for(ItemStack stack : HawkInventoryUtil.uncompressInventory(ops.get(1)))
					HawkInventoryUtil.removeItem(HawkInventoryUtil.getInvContents(inv), stack);
			}
		}
		return true;
	}
}
