package org.ultramine.mods.hawkeye;

import gnu.trove.map.TIntObjectMap;

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

import org.ultramine.mods.hawkeye.database.DataManager;
import org.ultramine.mods.hawkeye.entry.ContainerEntry;
import org.ultramine.mods.hawkeye.util.HawkInventoryUtil;

import com.mojang.authlib.GameProfile;

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.NBTTagCompound;
import net.minecraft.world.World;

/**
 * Contains methods for managing container access
 * 
 * @author oliverw92
 */
public class ContainerAccessManager
{
	private final Map<GameProfile, ContainerAccess> accessList = new HashMap<GameProfile, ContainerAccess>();

	/**
	 * Checks whether the player's inventory was open and should now trigger a
	 * container transaction
	 * 
	 * @param player
	 *            player to check
	 */
	public void checkInventoryClose(EntityPlayer player)
	{
		//Get access from list
		ContainerAccess access = accessList.remove(player.getGameProfile());

		//If no access, return
		if(access == null)
			return;

		//Get current inventory, create diff string and add the database
		TIntObjectMap<List<ItemStack>> after = HawkInventoryUtil.compressInventory(access.container);
		boolean subdata = HawkEye.instance.config.general.logBlocksSubData;
		NBTTagCompound diff = !subdata ? null : HawkInventoryUtil.createDifferenceNBT(access.beforeInv, after);
		if(diff != null || !subdata)
		{
			String diffStr = HawkInventoryUtil.createDifferenceString(access.beforeInv, after);
			if(diffStr.length() > 1 || subdata)
			{
				ContainerEntry ent = new ContainerEntry(player, access.world, access.x, access.y, access.z, diffStr);
				if(subdata)
				{
					try
					{
						ent.setSubData(CompressedStreamTools.compress(diff));
					} catch(IOException ignored){}
				}
				DataManager.addEntry(ent);
			}
		}
	}

	/**
	 * 'Sets' the player inventory to be open and stores the current contents of
	 * the container
	 * 
	 * @param player
	 *            player to check
	 * @param block
	 *            container to store
	 */
	public void checkInventoryOpen(EntityPlayer player, IInventory container, World world, double x, double y, double z)
	{
		accessList.put(player.getGameProfile(), new ContainerAccess(container, player, HawkInventoryUtil.compressInventory(container),
				world, x, y, z));
	}

	/**
	 * Class representing a container access
	 * 
	 * @author oliverw92
	 */
	public class ContainerAccess
	{
		public IInventory container;
		public EntityPlayer player;
		public TIntObjectMap<List<ItemStack>> beforeInv;
		public World world;
		public double x, y, z;

		public ContainerAccess(IInventory container, EntityPlayer player, TIntObjectMap<List<ItemStack>> beforeInv, World world, double x, double y, double z)
		{
			this.container = container;
			this.player = player;
			this.beforeInv = beforeInv;
			this.world = world;
			this.x = x;
			this.y = y;
			this.z = z;
		}
	}

}
