package erogenousbeef.bigreactors.utils;

import net.minecraft.init.Blocks;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import buildcraft.api.transport.IPipeTile;
import cofh.api.transport.IItemDuct;
import erogenousbeef.bigreactors.utils.intermod.ModHelperBase;

/**
 * Wraps a given direction's inventory exposure. Listen for block/tile changes and set
 * whatever tile entity you find in that direction as this object's
 * tracked tile entity.
 * 
 * You can then use distribute() to safely try to distribute items.
 * @author Erogenous Beef
 */
public class AdjacentInventoryHelper {

	private ForgeDirection dir;
	private TileEntity entity;
	private IItemDuct duct;
	private IPipeTile pipe;
	private InventoryHelper inv;

	/**
	 * @param dir The direction away from the current tile entity which this wrapper represents.
	 */
	public AdjacentInventoryHelper(ForgeDirection dir) {
		this.dir = dir;
		entity = null;
		duct = null;
		pipe = null;
		inv = null;
	}

	/**
	 * Attempt to distribute an item to a cached inventory connection
	 * which is wrapped by this object.
	 * @param itemToDistribute An itemstack to distribute.
	 * @return An itemstack containing the remaining items, or null if all items were distributed.
	 */
	public ItemStack distribute(ItemStack itemToDistribute) {
		if(entity == null || itemToDistribute == null) {
			return itemToDistribute;
		}
		
		if(!hasConnection()) {
			return itemToDistribute;
		}

		if(ModHelperBase.useCofh && duct != null) {
			itemToDistribute = duct.insertItem(dir.getOpposite(), itemToDistribute);
		}
		else if(ModHelperBase.useBuildcraftTransport && pipe != null) {
			if(pipe.isPipeConnected(dir.getOpposite())) {
				itemToDistribute.stackSize -= pipe.injectItem(itemToDistribute.copy(), true, dir.getOpposite());
				
				if(itemToDistribute.stackSize <= 0) {
					itemToDistribute = null;
				}
			}

		}
		else if(inv != null) {
			itemToDistribute = inv.addItem(itemToDistribute);
		}

		return itemToDistribute;
	}
	
	public boolean hasConnection() {
		return inv != null || pipe != null || duct != null;
	}
	
	/**
	 * @param te The new tile entity for this helper to cache.
	 * @return True if this helper's wrapped inventory changed, false otherwise.
	 */
	public boolean set(TileEntity te) {
		if(entity == te) { return false; }
		
		if(te == null) {
			duct = null;
			pipe = null;
			inv = null;
		}
		else if(ModHelperBase.useCofh && te instanceof IItemDuct) {
			setDuct((IItemDuct)te);
		}
		else if(ModHelperBase.useBuildcraftTransport && te instanceof IPipeTile) {
			setPipe((IPipeTile)te);
		}
		else if(te instanceof IInventory) {
			setInv(te);
		}
		
		entity = te;
		return true;
	}
	
	private void setDuct(IItemDuct duct) {
		this.duct = duct;
		this.pipe = null;
		this.inv = null;
	}
	
	private void setPipe(IPipeTile pipe) {
		this.pipe = pipe;
		this.duct = null;
		this.inv = null;
	}
	
	private void setInv(TileEntity te) {
		this.pipe = null;
		this.duct = null;
		this.inv = null;

		if(te instanceof ISidedInventory) {
			this.inv = new SidedInventoryHelper((ISidedInventory)te, dir.getOpposite());
		}
		else {
			IInventory inv = (IInventory)te;
			World world = te.getWorldObj();
			if(world.getBlock(te.xCoord, te.yCoord, te.zCoord) == Blocks.chest) {
				inv = StaticUtils.Inventory.checkForDoubleChest(world, inv, te.xCoord, te.yCoord, te.zCoord);
			}
			this.inv = new InventoryHelper(inv);
		}
	}
}
