package blusunrize.immersiveengineering.common.blocks.wooden;
import blusunrize.immersiveengineering.api.Lib;
import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.IGuiTile;
import blusunrize.immersiveengineering.common.blocks.TileEntityIEBase;
import blusunrize.immersiveengineering.common.util.Utils;
import net.minecraft.entity.item.EntityItem;
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.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.oredict.OreDictionary;
import java.util.ArrayList;
public class TileEntitySorter extends TileEntityIEBase implements IGuiTile
{
public SorterInventory filter;
public int[] sideFilter = {0,0,0,0,0,0};//OreDict,nbt,fuzzy
public static final int filterSlotsPerSide = 8;
private boolean isRouting = false;
public TileEntitySorter()
{
filter = new SorterInventory(this);
}
public ItemStack routeItem(EnumFacing inputSide, ItemStack stack, boolean simulate)
{
if(!worldObj.isRemote)
{
Integer[][] validOutputs = getValidOutputs(inputSide, stack, true, false);
if(validOutputs[0].length>0)
{
int rand = worldObj.rand.nextInt(validOutputs[0].length);
stack = this.outputItemToInv(stack, EnumFacing.getFront(validOutputs[0][rand]), simulate);
if(stack!=null)
for(int i=0; i<validOutputs[0].length; i++)
if(i!=rand)
{
stack = this.outputItemToInv(stack, EnumFacing.getFront(validOutputs[0][i]), simulate);
if(stack==null)
return null;
}
}
if(stack!=null && validOutputs[1].length>0)
{
if(!simulate)
{
int rand = worldObj.rand.nextInt(validOutputs[1].length);
EnumFacing fd = EnumFacing.getFront(validOutputs[1][rand]);
EntityItem ei = new EntityItem(worldObj, getPos().getX()+.5+fd.getFrontOffsetX(), getPos().getY()+.5+fd.getFrontOffsetY(), getPos().getZ()+.5+fd.getFrontOffsetZ(), stack.copy());
ei.motionX = (0.075F * fd.getFrontOffsetX());
ei.motionY = 0.025000000372529D;
ei.motionZ = (0.075F * fd.getFrontOffsetZ());
this.worldObj.spawnEntityInWorld(ei);
}
return null;
}
if(validOutputs[2].length>0)
{
int rand = worldObj.rand.nextInt(validOutputs[2].length);
stack = this.outputItemToInv(stack, EnumFacing.getFront(validOutputs[2][rand]), simulate);
if(stack!=null)
for(int i=0; i<validOutputs[2].length; i++)
if(i!=rand)
{
stack = this.outputItemToInv(stack, EnumFacing.getFront(validOutputs[2][i]), simulate);
if(stack==null)
return null;
}
}
if(stack!=null && validOutputs[3].length>0)
{
if(!simulate)
{
int rand = worldObj.rand.nextInt(validOutputs[3].length);
EnumFacing fd = EnumFacing.getFront(validOutputs[1][rand]);
EntityItem ei = new EntityItem(worldObj, getPos().getX()+.5+fd.getFrontOffsetX(), getPos().getY()+.5+fd.getFrontOffsetY(), getPos().getZ()+.5+fd.getFrontOffsetZ(), stack.copy());
ei.motionX = (0.075F * fd.getFrontOffsetX());
ei.motionY = 0.025000000372529D;
ei.motionZ = (0.075F * fd.getFrontOffsetZ());
this.worldObj.spawnEntityInWorld(ei);
}
return null;
}
}
return stack;
}
public boolean doOredict(int side)
{
if(side>=0 && side<this.sideFilter.length)
return (this.sideFilter[side]&1)!=0;
return false;
}
public boolean doNBT(int side)
{
if(side>=0 && side<this.sideFilter.length)
return (this.sideFilter[side]&2)!=0;
return false;
}
public boolean doFuzzy(int side)
{
if(side>=0 && side<this.sideFilter.length)
return (this.sideFilter[side]&4)!=0;
return false;
}
@Override
public boolean canOpenGui()
{
return true;
}
@Override
public int getGuiID()
{
return Lib.GUIID_Sorter;
}
@Override
public TileEntity getGuiMaster()
{
return this;
}
@Override
public void receiveMessageFromClient(NBTTagCompound message)
{
if(message.hasKey("sideConfig"))
this.sideFilter = message.getIntArray("sideConfig");
}
public Integer[][] getValidOutputs(EnumFacing inputSide, ItemStack stack, boolean allowUnmapped, boolean allowThrowing)
{
if(isRouting || stack==null)
return new Integer[][]{{},{},{},{}};
this.isRouting = true;
ArrayList<Integer> validFilteredInvOuts = new ArrayList<Integer>(6);
ArrayList<Integer> validFilteredEntityOuts = new ArrayList<Integer>(6);
ArrayList<Integer> validUnfilteredInvOuts = new ArrayList<Integer>(6);
ArrayList<Integer> validUnfilteredEntityOuts = new ArrayList<Integer>(6);
for(EnumFacing side : EnumFacing.values())
if(side!=inputSide)
{
boolean unmapped = true;
boolean allowed = false;
filterIteration:
{
for(ItemStack filterStack : filter.filters[side.ordinal()])
if(filterStack!=null)
{
unmapped = false;
boolean b = OreDictionary.itemMatches(filterStack, stack, true);
if(!b && doFuzzy(side.ordinal()))
b = filterStack.getItem().equals(stack.getItem());
if(!b && doOredict(side.ordinal()))
for (String name:OreDictionary.getOreNames())
if (Utils.compareToOreName(stack, name)&&Utils.compareToOreName(filterStack, name))
{
b = true;
break;
}
if(doNBT(side.ordinal()))
b &= Utils.compareItemNBT(filterStack, stack);
if(b)
{
allowed=true;
break filterIteration;
}
}
}
if(allowed)
{
TileEntity inventory = this.worldObj.getTileEntity(getPos().offset(side));
if(Utils.canInsertStackIntoInventory(inventory, stack, side.getOpposite()))
validFilteredInvOuts.add(side.ordinal());
else if(allowThrowing)
validFilteredEntityOuts.add(side.ordinal());
}
else if(allowUnmapped&&unmapped)
{
TileEntity inventory = this.worldObj.getTileEntity(getPos().offset(side));
if(Utils.canInsertStackIntoInventory(inventory, stack, side.getOpposite()))
validUnfilteredInvOuts.add(side.ordinal());
else if(allowThrowing)
validUnfilteredEntityOuts.add(side.ordinal());
}
}
this.isRouting = false;
return new Integer[][]{
validFilteredInvOuts.toArray(new Integer[validFilteredInvOuts.size()]),
validFilteredEntityOuts.toArray(new Integer[validFilteredEntityOuts.size()]),
validUnfilteredInvOuts.toArray(new Integer[validUnfilteredInvOuts.size()]),
validUnfilteredEntityOuts.toArray(new Integer[validUnfilteredEntityOuts.size()])
};
}
// public void outputItem(ItemStack stack, EnumFacing side)
// {
// TileEntity inventory = this.worldObj.getTileEntity(getPos().offset(side));
// stack = Utils.insertStackIntoInventory(inventory, stack, side.getOpposite());
// if(stack != null)
// {
// EntityItem ei = new EntityItem(worldObj, getPos().getX()+.5+side.getFrontOffsetX(), getPos().getY()+.5+side.getFrontOffsetY(), getPos().getZ()+.5+side.getFrontOffsetZ(), stack.copy());
// ei.motionX = (0.075F * side.getFrontOffsetX());
// ei.motionY = 0.025000000372529D;
// ei.motionZ = (0.075F * side.getFrontOffsetZ());
// this.worldObj.spawnEntityInWorld(ei);
// }
// }
public ItemStack outputItemToInv(ItemStack stack, EnumFacing side, boolean simulate)
{
TileEntity inventory = this.worldObj.getTileEntity(getPos().offset(side));
return Utils.insertStackIntoInventory(inventory, stack, side.getOpposite(), simulate);
}
@Override
public void readCustomNBT(NBTTagCompound nbt, boolean descPacket)
{
sideFilter = nbt.getIntArray("sideFilter");
if(!descPacket)
{
NBTTagList filterList = nbt.getTagList("filter", 10);
filter = new SorterInventory(this);
filter.readFromNBT(filterList);
}
}
@Override
public void writeCustomNBT(NBTTagCompound nbt, boolean descPacket)
{
nbt.setIntArray("sideFilter", sideFilter);
if(!descPacket)
{
NBTTagList filterList = new NBTTagList();
filter.writeToNBT(filterList);
nbt.setTag("filter", filterList);
}
}
@Override
public boolean hasCapability(Capability<?> capability, EnumFacing facing)
{
if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
return true;
return super.hasCapability(capability, facing);
}
IItemHandler[] insertionHandlers = {
new SorterInventoryHandler(this,EnumFacing.DOWN),
new SorterInventoryHandler(this,EnumFacing.UP),
new SorterInventoryHandler(this,EnumFacing.NORTH),
new SorterInventoryHandler(this,EnumFacing.SOUTH),
new SorterInventoryHandler(this,EnumFacing.WEST),
new SorterInventoryHandler(this,EnumFacing.EAST)};
@Override
public <T> T getCapability(Capability<T> capability, EnumFacing facing)
{
if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY && facing!=null)
return (T)insertionHandlers[facing.ordinal()];
return super.getCapability(capability, facing);
}
public static class SorterInventoryHandler implements IItemHandlerModifiable
{
TileEntitySorter sorter;
EnumFacing side;
public SorterInventoryHandler(TileEntitySorter sorter, EnumFacing side)
{
this.sorter = sorter;
this.side = side;
}
@Override
public int getSlots()
{
return 1;
}
@Override
public ItemStack getStackInSlot(int slot)
{
return null;
}
@Override
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate)
{
return sorter.routeItem(this.side, stack, simulate);
}
@Override
public ItemStack extractItem(int slot, int amount, boolean simulate)
{
return null;
}
@Override
public void setStackInSlot(int slot, ItemStack stack)
{
}
}
public static class SorterInventory implements IInventory
{
public ItemStack[][] filters = new ItemStack[6][filterSlotsPerSide];
final TileEntitySorter tile;
public SorterInventory(TileEntitySorter tile)
{
this.tile = tile;
}
@Override
public int getSizeInventory()
{
return 6*filterSlotsPerSide;
}
@Override
public ItemStack getStackInSlot(int slot)
{
return filters[slot/filterSlotsPerSide][slot%filterSlotsPerSide];
}
@Override
public ItemStack decrStackSize(int slot, int amount)
{
ItemStack stack = getStackInSlot(slot);
if(stack != null)
if(stack.stackSize <= amount)
setInventorySlotContents(slot, null);
else
{
stack = stack.splitStack(amount);
if(stack.stackSize == 0)
setInventorySlotContents(slot, null);
}
return stack;
}
@Override
public ItemStack removeStackFromSlot(int slot)
{
ItemStack stack = getStackInSlot(slot);
if (stack != null)
setInventorySlotContents(slot, null);
return stack;
}
@Override
public void setInventorySlotContents(int slot, ItemStack stack)
{
filters[slot/filterSlotsPerSide][slot%filterSlotsPerSide] = stack;
if (stack != null && stack.stackSize > getInventoryStackLimit())
stack.stackSize = getInventoryStackLimit();
}
@Override
public void clear()
{
for(int i=0; i<filters.length; i++)
for(int j=0; j<filters[i].length; j++)
filters[i][j] = null;
}
@Override
public String getName()
{
return "IESorterLayout";
}
@Override
public boolean hasCustomName()
{
return false;
}
@Override
public ITextComponent getDisplayName()
{
return new TextComponentString(getName());
}
@Override
public int getInventoryStackLimit()
{
return 1;
}
@Override
public boolean isUseableByPlayer(EntityPlayer player)
{
return true;
}
@Override
public void openInventory(EntityPlayer player){}
@Override
public void closeInventory(EntityPlayer player){}
@Override
public boolean isItemValidForSlot(int slot, ItemStack stack)
{
return true;
}
@Override
public void markDirty()
{
this.tile.markDirty();
}
public void writeToNBT(NBTTagList list)
{
for(int i=0; i<this.filters.length; i++)
for(int j=0; j<this.filters[i].length; j++)
if(this.filters[i][j] != null)
{
NBTTagCompound itemTag = new NBTTagCompound();
itemTag.setByte("Slot", (byte)(i*filterSlotsPerSide+j));
this.filters[i][j].writeToNBT(itemTag);
list.appendTag(itemTag);
}
}
public void readFromNBT(NBTTagList list)
{
for (int i=0; i<list.tagCount(); i++)
{
NBTTagCompound itemTag = list.getCompoundTagAt(i);
int slot = itemTag.getByte("Slot") & 255;
if(slot>=0 && slot<getSizeInventory())
this.filters[slot/filterSlotsPerSide][slot%filterSlotsPerSide] = ItemStack.loadItemStackFromNBT(itemTag);
}
}
@Override
public int getField(int id)
{
return 0;
}
@Override
public void setField(int id, int value)
{
}
@Override
public int getFieldCount()
{
return 0;
}
}
@Override
public boolean receiveClientEvent(int id, int arg)
{
return id == 0;
}
}