package electroblob.wizardry.inventory;

import electroblob.wizardry.tileentity.TileEntityBookshelf;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;

/**
 * A {@code VirtualSlot} represents a slot in an inventory other than the one that is currently open. Like regular slots,
 * they hold a single {@link net.minecraft.item.ItemStack}, but unlike regular slots, they are not drawn to the screen
 * and cannot be interacted with directly. A virtual slot is effectively a reference to a specific slot in some other
 * inventory that allows the details of that inventory to be abstracted away from the current container.
 * <p></p>
 * <i>N.B. For normal slots, {@code slotIndex == slotNumber} (index is for the inventory, number is for the container).
 * Importantly, for virtual slots this is <b>not the case</b>, since the {@code Container} they belong to is not the
 * one associated with the virtual slot's {@code IInventory}.</i>
 */
public class VirtualSlot extends Slot {

	private final TileEntity tileEntity;
	/** Allows the virtual slot to remember what was last stored in it, so items can be put back in the same place. */
	private ItemStack prevStack; // For now this doesn't persist over GUI close

	public VirtualSlot(IInventory inventory, int index){
		super(inventory, index, -999, -999);
		if(!(inventory instanceof TileEntity)) throw new IllegalArgumentException("Inventory must be a tile entity!");
		this.tileEntity = (TileEntity)inventory;
		this.prevStack = getStack().copy(); // We MUST copy the stack or it will get changed from elsewhere later!
	}

	@Override
	public boolean isEnabled(){
		return false; // Virtual slots are never displayed
	}

	// We don't really want to be updating the bookshelves every single tick (let alone every frame!), so we're going
	// to have to do some 'assuming things stay the same until told otherwise'. This means it's possible that virtual
	// slots will remain even when their containers are gone, so we need a failsafe for when that happens.

	/** Returns true if this slot is valid, i.e. the tile entity still exists. */
	public boolean isValid(){
		return !tileEntity.isInvalid();
	}

	// Normally the container decides if a stack is valid, but that's not going to work here
	@Override
	public boolean isItemValid(ItemStack stack){
		// getSlotIndex() is required here, NOT slotNumber (which is only populated when the slot is added to a
		// container - the javadoc is wrong, it has nothing to do with inventories)
		return isValid() && inventory.isItemValidForSlot(getSlotIndex(), stack);
	}

	@Override
	public boolean canTakeStack(EntityPlayer playerIn){
		return isValid() && super.canTakeStack(playerIn);
	}

	@Override
	public ItemStack onTake(EntityPlayer player, ItemStack stack){
		return isValid() ? super.onTake(player, stack) : ItemStack.EMPTY;
	}

	@Override
	public void onSlotChanged(){
		super.onSlotChanged();
		if(this.getHasStack()) this.prevStack = this.getStack().copy(); // Ignore stack removal (insertion of empty stacks)
	}

	@Override
	public ItemStack getStack(){
		return isValid() ? super.getStack() : ItemStack.EMPTY;
	}

	/** Returns the stack that was last in this slot. */
	public ItemStack getPrevStack(){
		return prevStack;
	}

	@Override
	public void putStack(ItemStack stack){
		if(isValid()){
			if(inventory instanceof TileEntityBookshelf) ((TileEntityBookshelf)inventory).sync();
			super.putStack(stack);
		}
	}

	@Override
	public ItemStack decrStackSize(int amount){
		if(isValid() && inventory instanceof TileEntityBookshelf) ((TileEntityBookshelf)inventory).sync();
		return isValid() ? super.decrStackSize(amount) : ItemStack.EMPTY;
	}

}
