package micdoodle8.mods.galacticraft.core.inventory;
import java.util.LinkedList;
import java.util.List;
import com.google.common.collect.Lists;
import micdoodle8.mods.galacticraft.core.tile.TileEntityCrafting;
import micdoodle8.mods.galacticraft.core.util.GCLog;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryCraftResult;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class ContainerCrafting extends Container
{
public TileEntityCrafting tileEntity;
public PersistantInventoryCrafting craftMatrix;
public IInventory craftResult = new InventoryCraftResult();
private ItemStack[] memory = new ItemStack[9];
public ContainerCrafting(InventoryPlayer playerInventory, IInventory tile)
{
this.tileEntity = (TileEntityCrafting) tile;
this.craftMatrix = tileEntity.craftMatrix;
this.craftMatrix.eventHandler = this;
this.addSlotToContainer(new SlotCraftingMemory(playerInventory.player, this.craftMatrix, this.craftResult, 0, 124, 35, this.tileEntity));
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
this.addSlotToContainer(new Slot(this.craftMatrix, j + i * 3, 30 + j * 18, 17 + i * 18));
}
}
for (int k = 0; k < 3; ++k)
{
for (int i1 = 0; i1 < 9; ++i1)
{
this.addSlotToContainer(new Slot(playerInventory, i1 + k * 9 + 9, 8 + i1 * 18, 84 + k * 18));
}
}
for (int l = 0; l < 9; ++l)
{
this.addSlotToContainer(new Slot(playerInventory, l, 8 + l * 18, 142));
}
this.onCraftMatrixChanged(this.craftMatrix);
}
@Override
public List<ItemStack> getInventory()
{
List<ItemStack> list = Lists.<ItemStack>newArrayList();
for (int i = 0; i < this.inventorySlots.size(); ++i)
{
list.add(((Slot)this.inventorySlots.get(i)).getStack());
}
//Override this method to trick vanilla networking into carrying our memory at end of its packets
for (int i = 0; i < 9; i++)
list.add(this.tileEntity.memory[i]);
return list;
}
@Override
@SideOnly(Side.CLIENT)
public void putStacksInSlots(ItemStack[] stacks)
{
for (int i = 0; i < stacks.length; ++i)
{
if (i < 46)
this.getSlot(i).putStack(stacks[i]);
else if (i < 55)
//Read memory clientside from the end of the vanilla packet, see getInventory()
this.tileEntity.memory[i - 46] = stacks[i];
}
}
/**
* Callback for when the crafting matrix is changed.
*/
@Override
public void onCraftMatrixChanged(IInventory inventoryIn)
{
this.craftResult.setInventorySlotContents(0, CraftingManager.getInstance().findMatchingRecipe(this.craftMatrix, this.tileEntity.getWorld()));
}
/**
* Called when the container is closed.
*/
@Override
public void onContainerClosed(EntityPlayer playerIn)
{
super.onContainerClosed(playerIn);
craftMatrix.eventHandler = null;
}
@Override
public boolean canInteractWith(EntityPlayer playerIn)
{
return this.tileEntity.isUseableByPlayer(playerIn);
}
/**
* Take a stack from the specified inventory slot.
*/
@Override
public ItemStack transferStackInSlot(EntityPlayer playerIn, int index)
{
ItemStack itemstack = null;
Slot slot = (Slot)this.inventorySlots.get(index);
if (slot != null && slot.getHasStack() && slot.getStack().stackSize > 0)
{
ItemStack itemstack1 = slot.getStack();
itemstack = itemstack1.copy();
if (index == 0)
{
if (!this.mergeItemStack(itemstack1, 10, 46, true))
{
return null;
}
slot.onSlotChange(itemstack1, itemstack);
}
else if (index < 10)
{
if (!this.mergeItemStack(itemstack1, 10, 46, false))
{
return null;
}
}
else if (this.matchesCrafting(itemstack1))
{
if (!this.mergeToCrafting(itemstack1, false))
{
return null;
}
}
else if (index >= 10 && index < 37)
{
if (!this.mergeItemStack(itemstack1, 37, 46, false))
{
return null;
}
}
else if (index >= 37 && index < 46)
{
if (!this.mergeItemStack(itemstack1, 10, 37, false))
{
return null;
}
}
if (itemstack1.stackSize == 0)
{
slot.putStack((ItemStack)null);
}
else
{
slot.onSlotChanged();
}
if (itemstack1.stackSize == itemstack.stackSize)
{
return null;
}
slot.onPickupFromSlot(playerIn, itemstack1);
}
return itemstack;
}
private boolean mergeToCrafting(ItemStack stack, boolean b)
{
List<Slot> acceptSlots = new LinkedList();
List<Integer> acceptQuantity = new LinkedList();
int minQuantity = 64;
int acceptTotal = 0;
for (int i = 1; i < 10; i++)
{
Slot slot = (Slot)this.inventorySlots.get(i);
if (slot != null)
{
ItemStack target = slot.getStack();
ItemStack target2 = this.memory[i - 1];
if (target2 == null) continue;
if (target == null)
{
target = target2;
}
if (matchingStacks(stack, target))
{
acceptSlots.add(slot);
int availSpace = target.getMaxStackSize() - target.stackSize;
acceptQuantity.add(availSpace);
acceptTotal += availSpace;
if (availSpace < minQuantity) minQuantity = availSpace;
}
}
}
//The stack more than exceeds what the crafting inventory requires
if (stack.stackSize >= acceptTotal)
{
if (acceptTotal == 0)
return false;
for (Slot slot : acceptSlots)
{
ItemStack target = slot.getStack();
if (target == null)
{
ItemStack target2 = this.memory[slot.slotNumber - 1];
if (target2 == null) continue;
target = target2.copy();
this.craftMatrix.setInventorySlotContents(slot.slotNumber - 1, target);
}
stack.stackSize -= target.getMaxStackSize() - target.stackSize;
target.stackSize = target.getMaxStackSize();
slot.onSlotChanged();
}
return true;
}
int uneven = 0;
for (int q : acceptQuantity)
{
uneven += q - minQuantity;
}
//Use the whole stack to try to even up the neediest slots
if (stack.stackSize < uneven)
{
do
{
Slot neediest = null;
int smallestStack = 64;
for (Slot slot : acceptSlots)
{
ItemStack target = slot.getStack();
if (target == null)
{
ItemStack target2 = this.memory[slot.slotNumber - 1];
if (target2 == null) continue;
target = target2.copy();
this.craftMatrix.setInventorySlotContents(slot.slotNumber - 1, target);
}
if (target.stackSize < smallestStack)
{
smallestStack = target.stackSize;
neediest = slot;
}
}
neediest.getStack().stackSize++;
}
while (--stack.stackSize > 0);
for (Slot slot : acceptSlots)
{
slot.onSlotChanged();
}
return true;
}
//Use some of the stack to even things up
if (uneven > 0)
{
int targetSize = stack.getMaxStackSize() - minQuantity;
for (Slot slot : acceptSlots)
{
ItemStack target = slot.getStack();
if (target == null)
{
ItemStack target2 = this.memory[slot.slotNumber - 1];
if (target2 == null) continue;
target = target2.copy();
this.craftMatrix.setInventorySlotContents(slot.slotNumber - 1, target);
}
stack.stackSize -= targetSize - target.stackSize;
acceptTotal -= targetSize - target.stackSize;
target.stackSize = targetSize;
slot.onSlotChanged();
}
}
//Spread the remaining stack over all slots evenly
int average = stack.stackSize / acceptSlots.size();
int modulus = stack.stackSize - average * acceptSlots.size();
for (Slot slot : acceptSlots)
{
if (slot != null)
{
ItemStack target = slot.getStack();
ItemStack target2 = this.memory[slot.slotNumber - 1];
if (target2 == null) continue;
if (target == null)
{
target = target2.copy();
this.craftMatrix.setInventorySlotContents(slot.slotNumber - 1, target);
}
int transfer = average;
if (modulus > 0)
{
transfer++;
modulus--;
}
stack.stackSize -= transfer;
target.stackSize += transfer;
if (target.stackSize > target.getMaxStackSize())
{
GCLog.info("Shift clicking - slot " + slot.slotNumber + " wanted more than it could accept:" + target.stackSize);
stack.stackSize += target.stackSize - target.getMaxStackSize();
target.stackSize = target.getMaxStackSize();
}
if (stack.stackSize < 0)
{
target.stackSize += stack.stackSize;
stack.stackSize = 0;
}
slot.onSlotChanged();
if (stack.stackSize == 0)
break;
}
}
return true;
}
private boolean matchesCrafting(ItemStack itemstack1)
{
if (this.tileEntity.overrideMemory(itemstack1, this.memory))
return true;
for (int i = 0; i < 9; i++)
{
if (matchingStacks(itemstack1, this.tileEntity.getMemory(i)) && (this.craftMatrix.getStackInSlot(i) == null || this.craftMatrix.getStackInSlot(i).stackSize < itemstack1.getMaxStackSize()))
{
for (int j = 0; j < 9; j++)
{
this.memory[j] = this.tileEntity.getMemory(j);
}
return true;
}
}
return false;
}
private boolean matchingStacks(ItemStack stack, ItemStack target)
{
return target != null && target.getItem() == stack.getItem() && (!stack.getHasSubtypes() || stack.getMetadata() == target.getMetadata()) && ItemStack.areItemStackTagsEqual(stack, target) && target.isStackable() && target.stackSize < target.getMaxStackSize();
}
/**
* Called to determine if the current slot is valid for the stack merging (double-click) code. The stack passed in
* is null for the initial slot that was double-clicked.
*/
@Override
public boolean canMergeSlot(ItemStack stack, Slot p_94530_2_)
{
return p_94530_2_.inventory != this.craftResult && super.canMergeSlot(stack, p_94530_2_);
}
}