package crazypants.enderio.machine.crafter;

import java.util.ArrayList;
import java.util.List;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.nbt.NBTTagCompound;
import crazypants.enderio.Config;
import crazypants.enderio.ModObject;
import crazypants.enderio.machine.AbstractMachineEntity;
import crazypants.enderio.machine.SlotDefinition;
import crazypants.enderio.power.Capacitors;

public class TileCrafter extends AbstractMachineEntity {

  DummyCraftingGrid craftingGrid = new DummyCraftingGrid();
  
  private List<ItemStack> containerItems;
  
  public TileCrafter() {
    super(new SlotDefinition(9, 1));
    
    containerItems = new ArrayList<ItemStack>();
  }

  @Override
  public String getMachineName() {
    return ModObject.blockCrafter.unlocalisedName;
  }

  @Override
  protected boolean isMachineItemValidForSlot(int slot, ItemStack itemstack) {
    if(!slotDefinition.isInputSlot(slot)) {
      return false;
    }
    return craftingGrid.inv[slot] != null && craftingGrid.inv[slot].isItemEqual(itemstack);
  }

  @Override
  public boolean isActive() {
    return false;
  }

  @Override
  public float getProgress() {
    return 0.5f;
  }

  @Override
  protected boolean processTasks(boolean redstoneCheckPassed) {  
    if(!redstoneCheckPassed || !craftingGrid.hasValidRecipe() || !canMergeOutput() || !hasPower()) {      
      return false;
    }
    if(capacitorType == Capacitors.BASIC_CAPACITOR && worldObj.getTotalWorldTime() % 20 != 0) {
      return false;
    } else if(capacitorType == Capacitors.ACTIVATED_CAPACITOR && worldObj.getTotalWorldTime() % 10 != 0) {
      return false;
    } else if(worldObj.getTotalWorldTime() % 2 != 0) {
      return false;
    }
    
    // process buffered container items
    if(!containerItems.isEmpty()) {
      for(int i = 0; i < containerItems.size(); i++) {
	ItemStack stack = containerItems.get(i);
	if(inventory[9] == null) {
	  inventory[9] = stack;
	  containerItems.remove(i);
	} else if(ItemStack.areItemStacksEqual(inventory[9], stack) && inventory[9].stackSize + stack.stackSize <= inventory[9].getMaxStackSize()) {
	  inventory[9].stackSize += stack.stackSize;
	  containerItems.remove(i);
	}
      }
      return false;
    }
    
    List<ItemStack> required = new ArrayList<ItemStack>();
    craftingGrid.copyRequiredInputs(required);
    if(hasRequiredInput(required)) {      
      craftRecipe();
      double used = Math.min(powerHandler.getEnergyStored(), Config.crafterMjPerCraft);    
      powerHandler.setEnergy(powerHandler.getEnergyStored() - used);
    }     
    return false;
  }

  private void craftRecipe() {    
    List<ItemStack> required = new ArrayList<ItemStack>();
    craftingGrid.copyRequiredInputs(required);
    for(ItemStack req : required) {
      for(int i=0;i<9 && req.stackSize > 0; i++) {
        ItemStack avail = inventory[i];
        if(avail != null && avail.stackSize > 0 && avail.isItemEqual(req)) {
          req.stackSize--;
          avail = avail.copy();
          avail.stackSize--;
          if(avail.stackSize <= 0) {
            avail = avail.getItem().getContainerItem(avail);
            if (avail != null) {
              containerItems.add(avail.copy());
              avail = null;
            }
          }
          setInventorySlotContents(i, avail);          
        }
      }
    }
    ItemStack output = craftingGrid.getOutput().copy();
    if(inventory[9] == null) {      
      setInventorySlotContents(9, output);
    } else {
      ItemStack cur = inventory[9].copy();
      cur.stackSize += output.stackSize;
      setInventorySlotContents(9, cur);
    }    
  }

  private boolean canMergeOutput() {
    if(inventory[9] == null) {
      return true;
    }
    ItemStack output = craftingGrid.getOutput();
    if(!inventory[9].isItemEqual(output)) {      
      return false;
    }        
    return output.getMaxStackSize() >= (inventory[9].stackSize + output.stackSize);
  }

  private boolean hasRequiredInput(List<ItemStack> required) {
    List<ItemStack> available = new ArrayList<ItemStack>();
    for(int i=0;i<9;i++) {
      ItemStack is = inventory[i];
      if(is != null) {
        available.add(is.copy());
      }      
    }    
    for(ItemStack req : required) {
      boolean foundReq = false;
      for(ItemStack avail : available) {
        if(req.isItemEqual(avail) && avail.stackSize > 0) {
          avail.stackSize--;
          foundReq = true;
          break;
        }
      }
      if(!foundReq) {
        return false;
      }
    }    
    return true;
  }

  @Override
  public void readCommon(NBTTagCompound nbtRoot) {
    super.readCommon(nbtRoot);
    NBTTagCompound craftRoot = nbtRoot.getCompoundTag("craftingGrid");
    craftingGrid.readFromNBT(craftRoot);
  }

  @Override
  public void writeCommon(NBTTagCompound nbtRoot) {
    super.writeCommon(nbtRoot);    
    NBTTagCompound craftingRoot = new NBTTagCompound();
    craftingGrid.writeToNBT(craftingRoot);
    nbtRoot.setTag("craftingGrid", craftingRoot);
  }

  public void updateCraftingOutput() {
    InventoryCrafting inv = new InventoryCrafting(new Container() {
      
      @Override
      public boolean canInteractWith(EntityPlayer var1) {        
        return false;
      }
    }, 3, 3);
    
    for(int i=0;i<9;i++) {
      inv.setInventorySlotContents(i, craftingGrid.getStackInSlot(i));
    }
    ItemStack matches = CraftingManager.getInstance().findMatchingRecipe(inv, worldObj);
    craftingGrid.setInventorySlotContents(9, matches);
    markDirty();
    
  }
  
  

}

@@ -66,16 +66,43 @@
 ayList;%0A
+import java.util.Iterator;%0A
 import j
@@ -2015,53 +2015,89 @@
     
-for(int i = 0; i %3C containerItems.size(); i++
+Iterator%3CItemStack%3E iter = containerItems.iterator();%0A      while (iter.hasNext()
 ) %7B%0A
@@ -2119,28 +2119,18 @@
 k = 
-containerItems.ge
+iter.nex
 t(
-i
 );%0A%09
@@ -2184,38 +2184,28 @@
 ack;%0A%09  
-containerItems
+iter
 .remove(
 i);%0A%09%7D e
@@ -2192,25 +2192,24 @@
 iter.remove(
-i
 );%0A%09%7D else i
@@ -2394,30 +2394,20 @@
 %0A%09  
-containerItems
+iter
 .remove(
 i);%0A
@@ -2402,17 +2402,16 @@
 .remove(
-i
 );%0A%09%7D%0A  

Switch to iterator in Crafter to make MatthiasM2 happy