package com.raoulvdberge.refinedstorage.tile;

import com.raoulvdberge.refinedstorage.RS;
import com.raoulvdberge.refinedstorage.RSUtils;
import com.raoulvdberge.refinedstorage.api.util.IComparer;
import com.raoulvdberge.refinedstorage.inventory.ItemHandlerBasic;
import com.raoulvdberge.refinedstorage.inventory.ItemHandlerUpgrade;
import com.raoulvdberge.refinedstorage.item.ItemUpgrade;
import com.raoulvdberge.refinedstorage.tile.config.IComparable;
import com.raoulvdberge.refinedstorage.tile.data.TileDataParameter;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.wrapper.CombinedInvWrapper;

public class TileInterface extends TileNode implements IComparable {
    public static final TileDataParameter<Integer> COMPARE = IComparable.createParameter();

    private static final String NBT_COMPARE = "Compare";

    private ItemHandlerBasic importItems = new ItemHandlerBasic(9, this) {
        @Override
        public ItemStack extractItem(int slot, int amount, boolean simulate) {
            return null;
        }
    };

    private ItemHandlerBasic exportSpecimenItems = new ItemHandlerBasic(9, this);
    private ItemHandlerBasic exportItems = new ItemHandlerBasic(9, this) {
        @Override
        public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
            return stack;
        }
    };

    private ItemHandlerUpgrade upgrades = new ItemHandlerUpgrade(4, this, ItemUpgrade.TYPE_SPEED, ItemUpgrade.TYPE_STACK, ItemUpgrade.TYPE_CRAFTING);

    private int compare = IComparer.COMPARE_NBT | IComparer.COMPARE_DAMAGE;

    private int currentSlot = 0;

    public TileInterface() {
        dataManager.addWatchedParameter(COMPARE);
    }

    @Override
    public int getEnergyUsage() {
        return RS.INSTANCE.config.interfaceUsage + upgrades.getEnergyUsage();
    }

    @Override
    public void updateNode() {
        if (currentSlot >= importItems.getSlots()) {
            currentSlot = 0;
        }

        ItemStack slot = importItems.getStackInSlot(currentSlot);

        if (slot == null) {
            currentSlot++;
        } else if (ticks % upgrades.getSpeed() == 0) {
            ItemStack remainder = network.insertItem(slot, upgrades.getInteractStackSize(), false);

            if (remainder == null) {
                importItems.extractItemInternal(currentSlot, upgrades.getInteractStackSize(), false);
            } else {
                importItems.extractItemInternal(currentSlot, upgrades.getInteractStackSize() - remainder.stackSize, false);
                currentSlot++;
            }
        }

        for (int i = 0; i < 9; ++i) {
            ItemStack wanted = exportSpecimenItems.getStackInSlot(i);
            ItemStack got = exportItems.getStackInSlot(i);

            if (wanted == null) {
                if (got != null) {
                    exportItems.setStackInSlot(i, network.insertItem(got, got.stackSize, false));
                }
            } else {
                int delta = got == null ? wanted.stackSize : (wanted.stackSize - got.stackSize);

                if (delta > 0) {
                    ItemStack result = network.extractItem(wanted, delta, compare);

                    if (result != null) {
                        if (got == null) {
                            exportItems.setStackInSlot(i, result);
                        } else {
                            exportItems.getStackInSlot(i).stackSize += result.stackSize;
                        }
                    } else {
                        network.scheduleCraftingTaskIfUnscheduled(wanted, delta, compare);
                    }
                } else if (delta < 0) {
                    ItemStack remainder = network.insertItem(got, Math.abs(delta), false);

                    if (remainder == null) {
                        exportItems.extractItem(i, Math.abs(delta), false);
                    } else {
                        exportItems.extractItem(i, Math.abs(delta) - remainder.stackSize, false);
                    }
                }
            }
        }
    }

    @Override
    public int getCompare() {
        return compare;
    }

    @Override
    public void setCompare(int compare) {
        this.compare = compare;

        markDirty();
    }

    @Override
    public void read(NBTTagCompound tag) {
        super.read(tag);

        RSUtils.readItems(importItems, 0, tag);
        RSUtils.readItems(exportSpecimenItems, 1, tag);
        RSUtils.readItems(exportItems, 2, tag);
        RSUtils.readItems(upgrades, 3, tag);

        if (tag.hasKey(NBT_COMPARE)) {
            compare = tag.getInteger(NBT_COMPARE);
        }
    }

    @Override
    public NBTTagCompound write(NBTTagCompound tag) {
        super.write(tag);

        RSUtils.writeItems(importItems, 0, tag);
        RSUtils.writeItems(exportSpecimenItems, 1, tag);
        RSUtils.writeItems(exportItems, 2, tag);
        RSUtils.writeItems(upgrades, 3, tag);

        tag.setInteger(NBT_COMPARE, compare);

        return tag;
    }

    public IItemHandler getImportItems() {
        return importItems;
    }

    public IItemHandler getExportSpecimenItems() {
        return exportSpecimenItems;
    }

    public IItemHandler getExportItems() {
        return exportItems;
    }

    public IItemHandler getUpgrades() {
        return upgrades;
    }

    @Override
    public IItemHandler getDrops() {
        return new CombinedInvWrapper(importItems, exportItems, upgrades);
    }

    @Override
    public boolean hasConnectivityState() {
        return true;
    }

    @Override
    public <T> T getCapability(Capability<T> capability, EnumFacing facing) {
        if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
            return facing == EnumFacing.DOWN ? (T) exportItems : (T) importItems;
        }

        return super.getCapability(capability, facing);
    }

    @Override
    public boolean hasCapability(Capability<?> capability, EnumFacing facing) {
        return capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY || super.hasCapability(capability, facing);
    }
}

@@ -1147,148 +1147,8 @@
 his)
- %7B%0A        @Override%0A        public ItemStack extractItem(int slot, int amount, boolean simulate) %7B%0A            return null;%0A        %7D%0A    %7D
 ;%0A%0A 
@@ -2240,24 +2240,107 @@
 d() == 0) %7B%0A
+            int size = Math.min(slot.stackSize, upgrades.getInteractStackSize());%0A%0A
             
@@ -2390,39 +2390,12 @@
 ot, 
-upgrades.getInteractStackS
+s
 ize
-()
 , fa
@@ -2503,39 +2503,12 @@
 ot, 
-upgrades.getInteractStackS
+s
 ize
-()
 , fa
@@ -2599,39 +2599,12 @@
 ot, 
-upgrades.getInteractStackS
+s
 ize
-()
  - r

Fix item dupe bug in interface