package gigaherz.enderRift.storage;

import com.google.common.base.Predicate;
import gigaherz.api.automation.IInventoryAutomation;
import gigaherz.enderRift.blocks.TileEnderRift;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.IChatComponent;
import net.minecraftforge.common.util.Constants;

import javax.annotation.Nonnull;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class RiftInventory implements IInventoryAutomation
{
    private final List<ItemStack> inventorySlots = new ArrayList<>();
    private final RiftStorageWorldData manager;

    final List<Reference<? extends TileEnderRift>> listeners = new ArrayList<>();
    final ReferenceQueue<TileEnderRift> deadListeners = new ReferenceQueue<>();

    RiftInventory(RiftStorageWorldData manager) {
        this.manager = manager;
    }

    public void addWeakListener(TileEnderRift e) {
        listeners.add(new WeakReference<>(e, deadListeners));
    }

    public int getSlotCount()
    {
        return inventorySlots.size();
    }

    public void markDirty()
    {
        for (Reference<? extends TileEnderRift>
             ref = deadListeners.poll();
             ref != null;
             ref = deadListeners.poll()) {
            listeners.remove(ref);
        }

        for (Iterator<Reference<? extends TileEnderRift>> it = listeners.iterator(); it.hasNext(); ) {
            TileEnderRift rift = it.next().get();
            if (rift == null || rift.isInvalid()) {
                it.remove();
            } else {
                rift.setDirty();
            }
        }

        manager.markDirty();
    }

    public void readFromNBT(NBTTagCompound nbtTagCompound)
    {
        NBTTagList itemList = nbtTagCompound.getTagList("Items", Constants.NBT.TAG_COMPOUND);

        inventorySlots.clear();

        for (int i = 0; i < itemList.tagCount(); ++i)
        {
            NBTTagCompound slot = itemList.getCompoundTagAt(i);
            inventorySlots.add(ItemStack.loadItemStackFromNBT(slot));
        }
    }

    public void writeToNBT(NBTTagCompound nbtTagCompound) {
        NBTTagList itemList = new NBTTagList();

        for (ItemStack stack : inventorySlots)
        {
            if (stack != null)
            {
                NBTTagCompound slot = new NBTTagCompound();
                stack.writeToNBT(slot);
                itemList.appendTag(slot);
            }
        }

        nbtTagCompound.setTag("Items", itemList);
    }

    @Override
    public IInventoryAutomation getInventoryForSide(@Nonnull EnumFacing face)
    {
        return this;
    }

    @Override
    public ItemStack pushItems(@Nonnull ItemStack stack)
    {
        ItemStack remaining = stack.copy();
        int firstEmpty = -1;

        // Try to fill existing slots first
        for(int i=0;i<inventorySlots.size();i++)
        {
            ItemStack slot = inventorySlots.get(i);
            if(slot != null)
            {
                int max = Math.min(remaining.getMaxStackSize(), 64);
                int transfer = Math.min(remaining.stackSize, max - slot.stackSize);
                if (transfer > 0 && ItemStack.areItemsEqual(slot, remaining) && ItemStack.areItemStackTagsEqual(slot, remaining))
                {
                    slot.stackSize += transfer;
                    remaining.stackSize -= transfer;
                    if(remaining.stackSize == 0)
                        break;
                }
            }
            else if(firstEmpty < 0)
            {
                firstEmpty = i;
            }
        }

        // Then place the remaining items in the first available empty slot
        inventorySlots.add(remaining);

        return null;
    }

    @Override
    public ItemStack pullItems(int limit, Predicate<ItemStack> filter)
    {
        for(int i=0;i<inventorySlots.size();i++)
        {
            ItemStack slot = inventorySlots.get(i);
            if(slot != null)
            {
                int available = Math.min(limit, slot.stackSize);
                if(filter.apply(slot) && available > 0)
                {
                    ItemStack pulled = slot.splitStack(available);
                    if(slot.stackSize <= 0)
                        inventorySlots.remove(i);
                    return pulled;
                }
            }
        }
        return null;
    }

    @Override
    public ItemStack extractItems(@Nonnull ItemStack stack, int wanted)
    {
        ItemStack extracted = stack.copy();
        extracted.stackSize = 0;

        if(stack.stackSize <= 0)
            return null;

        for(int i=0;i<inventorySlots.size();i++)
        {
            ItemStack slot = inventorySlots.get(i);
            if(slot != null)
            {
                int available = Math.min(wanted, slot.stackSize);
                if (ItemStack.areItemsEqual(slot, stack) && ItemStack.areItemStackTagsEqual(slot, stack) && available > 0)
                {
                    slot.stackSize -= available;
                    extracted.stackSize += available;
                    if(slot.stackSize <= 0)
                        inventorySlots.remove(i);

                    wanted = extracted.stackSize - stack.stackSize;
                    if(wanted <= 0)
                        break;
                }
            }
        }

        if(extracted.stackSize <= 0)
            return null;

        return extracted;
    }
}

@@ -3039,37 +3039,8 @@
 y();
-%0A        int firstEmpty = -1;
 %0A%0A  
@@ -3096,68 +3096,10 @@
  for
-(int i=0;i%3CinventorySlots.size();i++)%0A        %7B%0A           
  
+(
 Item
@@ -3101,33 +3101,33 @@
 (ItemStack slot 
-=
+:
  inventorySlots.
@@ -3121,32 +3121,35 @@
 ventorySlots
-.get(i);
+)%0A        %7B
 %0A           
@@ -3143,32 +3143,33 @@
 %7B%0A            if
+ 
 (slot != null)%0A 
@@ -3605,16 +3605,17 @@
       if
+ 
 (remaini
@@ -3627,17 +3627,17 @@
 ackSize 
-=
+%3C
 = 0)%0A   
@@ -3700,104 +3700,8 @@
   %7D%0A
-            else if(firstEmpty %3C 0)%0A            %7B%0A                firstEmpty = i;%0A            %7D%0A
     
@@ -3729,19 +3729,19 @@
 n place 
-the
+any
  remaini
@@ -3783,16 +3783,54 @@
 ty slot%0A
+        if(remaining.stackSize %3E 0)%0A  
         
@@ -3857,24 +3857,46 @@
 emaining);%0A%0A
+        markDirty();%0A%0A
         retu
@@ -4452,24 +4452,57 @@
 .remove(i);%0A
+                    markDirty();%0A
             
@@ -5615,32 +5615,53 @@
   return null;%0A%0A
+        markDirty();%0A
         return e

Fix rift storage not saving to disk.