package net.mcft.copy.betterstorage.inventory;

import java.util.List;

import net.mcft.copy.betterstorage.BetterStorage;
import net.mcft.copy.betterstorage.api.ICrateWatcher;
import net.mcft.copy.betterstorage.config.GlobalConfig;
import net.mcft.copy.betterstorage.misc.Constants;
import net.mcft.copy.betterstorage.tile.crate.CratePileData;
import net.mcft.copy.betterstorage.utils.StackUtils;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;

/** An inventory interface built for machines accessing crate piles. */
public class InventoryCrateBlockView extends InventoryBetterStorage implements ICrateWatcher {
	
	private static final int numStacksStored = 4;
	
	private final CratePileData data;
	
	private final ItemStack[] originalStacks = new ItemStack[numStacksStored];
	private final ItemStack[] exposedStacks = new ItemStack[numStacksStored];
	
	/** If the crate contents were changed outside of this block view. */
	private boolean changed = true;
	/** If the block view is currently modifying items, so changed will not be set. */
	private boolean isModifying = false;
	
	/** If the crate was accessed by something. Resets every update. */
	private boolean accessed = false;
	
	public InventoryCrateBlockView(CratePileData data) {
		super(Constants.containerCrate);
		this.data = data;
		data.addWatcher(this);
	}
	
	@Override
	public int getSizeInventory() { return (numStacksStored + 1); }
	
	@Override
	public boolean isItemValidForSlot(int slot, ItemStack stack) {
		return ((slot > 0) || (data.spaceForItem(stack) >= stack.stackSize));
	}
	
	@Override
	public ItemStack getStackInSlot(int slot) {
		access();
		if ((slot <= 0) || (slot >= getSizeInventory())) return null;
		return exposedStacks[slot - 1];
	}
	
	@Override
	public void setInventorySlotContents(int slot, ItemStack stack) {
		access();
		if ((slot < 0) || (slot >= getSizeInventory())) return;
		ItemStack oldStack = null;
		if (slot > 0) {
			oldStack = originalStacks[slot - 1];
			exposedStacks[slot - 1] = stack;
			originalStacks[slot - 1] = ItemStack.copyItemStack(stack);
		}
		isModifying = true;
		if (oldStack != null) {
			// If the two stacks match, just add/remove the difference.
			if (StackUtils.matches(oldStack, stack)) {
				int count = stack.stackSize - oldStack.stackSize;
				if (count > 0) data.addItems(StackUtils.copyStack(stack, count));
				else if (count < 0) data.removeItems(StackUtils.copyStack(stack, -count));
				isModifying = false;
				return;
			}
			data.removeItems(oldStack);
		}
		data.addItems(stack);
		isModifying = false;
	}
	
	@Override
	public ItemStack decrStackSize(int slot, int amount) {
		ItemStack stack = getStackInSlot(slot);
		if (stack == null) return null;
		amount = Math.min(amount, stack.stackSize);
		originalStacks[slot - 1].stackSize = exposedStacks[slot - 1].stackSize -= amount;
		isModifying = true;
		ItemStack result = data.removeItems(stack, amount);
		isModifying = false;
		return result;
	}
	
	@Override
	public void markDirty() {
		for (int i = 0; i < numStacksStored; i++)
			if (!ItemStack.areItemStacksEqual(originalStacks[i], exposedStacks[i]))
				setInventorySlotContents(i + 1, exposedStacks[i]);
	}
	
	@Override
	public boolean isUseableByPlayer(EntityPlayer player) { return true; }
	
	@Override
	public void openInventory() { }
	@Override
	public void closeInventory() { }
	
	
	public void onUpdate() {
		
		if (!GlobalConfig.enableCrateInventoryInterfaceSetting.getValue() || !accessed) return;
		accessed = false;
		
		// Check for modifications done to the inventory without markDirty() being called.
		for (int i = 0; i < numStacksStored; i++)
			if (!ItemStack.areItemStacksEqual(originalStacks[i], exposedStacks[i])) {
				BetterStorage.log.warn("A crate inventory was modified without markDirty() being called afterwards.");
				BetterStorage.log.warn("The crate inventory interface will be disabled until the next restart, to minimize chances of issues.");
				BetterStorage.log.warn(String.format("You can find the crate pile at [%s,%s,%s] in dimension %s.",
				                                     data.getCenterX(), data.getCenterY(), data.getCenterZ(), data.collection.dimension));
				GlobalConfig.enableCrateInventoryInterfaceSetting.setSyncedValue(false);
				markDirty();
				return;
			}
		
		// Cause new stacks to be picked the
		// next time something is accessed.
		changed = true;
		
	}
	
	private void access() {
		accessed = true;
		
		if (changed) {
			// Pick a new set of random stacks from the crate.
			List<ItemStack> picked = data.pickItemStacks(numStacksStored);
			for (int i = 0; i < numStacksStored; i++) {
				exposedStacks[i] = ((i < picked.size()) ? picked.get(i) : null);
				originalStacks[i] = ItemStack.copyItemStack(exposedStacks[i]);
			}
			changed = false;
		}
	}
	
	@Override
	public void onCrateItemsModified(ItemStack stack) {
		if (!isModifying) changed = true;
	}
	
}

@@ -3400,19 +3400,16 @@
 ate() %7B%0A
-%09%09%0A
 %09%09if (!G
@@ -3514,801 +3514,8 @@
 se;%0A
-%09%09%0A%09%09// Check for modifications done to the inventory without markDirty() being called.%0A%09%09for (int i = 0; i %3C numStacksStored; i++)%0A%09%09%09if (!ItemStack.areItemStacksEqual(originalStacks%5Bi%5D, exposedStacks%5Bi%5D)) %7B%0A%09%09%09%09BetterStorage.log.warn(%22A crate inventory was modified without markDirty() being called afterwards.%22);%0A%09%09%09%09BetterStorage.log.warn(%22The crate inventory interface will be disabled until the next restart, to minimize chances of issues.%22);%0A%09%09%09%09BetterStorage.log.warn(String.format(%22You can find the crate pile at %5B%25s,%25s,%25s%5D in dimension %25s.%22,%0A%09%09%09%09                                     data.getCenterX(), data.getCenterY(), data.getCenterZ(), data.collection.dimension));%0A%09%09%09%09GlobalConfig.enableCrateInventoryInterfaceSetting.setSyncedValue(false);%0A%09%09%09%09markDirty();%0A%09%09%09%09return;%0A%09%09%09%7D%0A%09%09%0A
 %09%09//
@@ -3605,19 +3605,16 @@
 = true;%0A
-%09%09%0A
 %09%7D%0A%09%0A%09pr

Remove direct stackSize modification check