package mekanism.common.tile;
import java.util.ArrayList;
import mekanism.api.Coord4D;
import mekanism.api.IConfigurable;
import mekanism.api.Range4D;
import mekanism.api.StackUtils;
import mekanism.common.IActiveState;
import mekanism.common.ILogisticalTransporter;
import mekanism.common.Mekanism;
import mekanism.common.PacketHandler;
import mekanism.common.item.ItemBlockBasic;
import mekanism.common.network.PacketTileEntity.TileEntityMessage;
import mekanism.common.transporter.TransporterManager;
import mekanism.common.util.InventoryUtils;
import mekanism.common.util.MekanismUtils;
import mekanism.common.util.TransporterUtils;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.ForgeDirection;
import cpw.mods.fml.common.Optional.Interface;
import io.netty.buffer.ByteBuf;
import powercrystals.minefactoryreloaded.api.IDeepStorageUnit;
@Interface(iface = "powercrystals.minefactoryreloaded.api.IDeepStorageUnit", modid = "MineFactoryReloaded")
public class TileEntityBin extends TileEntityBasicBlock implements ISidedInventory, IActiveState, IDeepStorageUnit, IConfigurable
{
public boolean isActive;
public boolean clientActive;
public final int MAX_DELAY = 10;
public int addTicks = 0;
public int delayTicks;
public int cacheCount;
public final int MAX_STORAGE = 4096;
public ItemStack itemType;
public ItemStack topStack;
public ItemStack bottomStack;
public int prevCount;
public int clientAmount;
public void sortStacks()
{
if(getItemCount() == 0 || itemType == null)
{
itemType = null;
topStack = null;
bottomStack = null;
cacheCount = 0;
return;
}
int count = getItemCount();
int remain = MAX_STORAGE-count;
if(remain >= itemType.getMaxStackSize())
{
topStack = null;
}
else {
topStack = itemType.copy();
topStack.stackSize = itemType.getMaxStackSize()-remain;
}
count -= StackUtils.getSize(topStack);
bottomStack = itemType.copy();
bottomStack.stackSize = Math.min(itemType.getMaxStackSize(), count);
count -= StackUtils.getSize(bottomStack);
cacheCount = count;
}
public boolean isValid(ItemStack stack)
{
if(stack == null || stack.stackSize <= 0)
{
return false;
}
if(stack.getItem() instanceof ItemBlockBasic && stack.getItemDamage() == 6)
{
return false;
}
if(itemType == null)
{
return true;
}
if(!stack.isItemEqual(itemType) || !ItemStack.areItemStackTagsEqual(stack, itemType))
{
return false;
}
return true;
}
public ItemStack add(ItemStack stack)
{
if(isValid(stack) && getItemCount() != MAX_STORAGE)
{
if(itemType == null)
{
setItemType(stack);
}
if(getItemCount() + stack.stackSize <= MAX_STORAGE)
{
setItemCount(getItemCount() + stack.stackSize);
return null;
}
else {
ItemStack rejects = itemType.copy();
rejects.stackSize = (getItemCount()+stack.stackSize) - MAX_STORAGE;
setItemCount(MAX_STORAGE);
return rejects;
}
}
return stack;
}
public ItemStack removeStack()
{
if(getItemCount() == 0)
{
return null;
}
return remove(bottomStack.stackSize);
}
public ItemStack remove(int amount)
{
if(getItemCount() == 0)
{
return null;
}
ItemStack ret = itemType.copy();
ret.stackSize = Math.min(Math.min(amount, itemType.getMaxStackSize()), getItemCount());
setItemCount(getItemCount() - ret.stackSize);
return ret;
}
public int getItemCount()
{
return StackUtils.getSize(bottomStack) + cacheCount + StackUtils.getSize(topStack);
}
@Override
public void onUpdate()
{
if(!worldObj.isRemote)
{
addTicks = Math.max(0, addTicks-1);
delayTicks = Math.max(0, delayTicks-1);
sortStacks();
if(getItemCount() != prevCount)
{
markDirty();
MekanismUtils.saveChunk(this);
}
if(delayTicks == 0)
{
if(bottomStack != null && isActive)
{
TileEntity tile = Coord4D.get(this).getFromSide(ForgeDirection.getOrientation(0)).getTileEntity(worldObj);
if(tile instanceof ILogisticalTransporter)
{
ILogisticalTransporter transporter = (ILogisticalTransporter)tile;
ItemStack rejects = TransporterUtils.insert(this, transporter, bottomStack, null, true, 0);
if(TransporterManager.didEmit(bottomStack, rejects))
{
setInventorySlotContents(0, rejects);
}
}
else if(tile instanceof IInventory)
{
setInventorySlotContents(0, InventoryUtils.putStackInInventory((IInventory)tile, bottomStack, 0, false));
}
delayTicks = 10;
}
}
else {
delayTicks--;
}
}
}
@Override
public void writeToNBT(NBTTagCompound nbtTags)
{
super.writeToNBT(nbtTags);
nbtTags.setBoolean("isActive", isActive);
nbtTags.setInteger("itemCount", cacheCount);
if(bottomStack != null)
{
nbtTags.setTag("bottomStack", bottomStack.writeToNBT(new NBTTagCompound()));
}
if(topStack != null)
{
nbtTags.setTag("topStack", topStack.writeToNBT(new NBTTagCompound()));
}
if(getItemCount() > 0)
{
nbtTags.setTag("itemType", itemType.writeToNBT(new NBTTagCompound()));
}
}
@Override
public void readFromNBT(NBTTagCompound nbtTags)
{
super.readFromNBT(nbtTags);
isActive = nbtTags.getBoolean("isActive");
cacheCount = nbtTags.getInteger("itemCount");
bottomStack = ItemStack.loadItemStackFromNBT(nbtTags.getCompoundTag("bottomStack"));
topStack = ItemStack.loadItemStackFromNBT(nbtTags.getCompoundTag("topStack"));
if(getItemCount() > 0)
{
itemType = ItemStack.loadItemStackFromNBT(nbtTags.getCompoundTag("itemType"));
}
}
@Override
public ArrayList getNetworkedData(ArrayList data)
{
super.getNetworkedData(data);
data.add(isActive);
data.add(getItemCount());
if(getItemCount() > 0)
{
data.add(itemType);
}
return data;
}
@Override
public void handlePacketData(ByteBuf dataStream)
{
super.handlePacketData(dataStream);
isActive = dataStream.readBoolean();
clientAmount = dataStream.readInt();
if(clientAmount > 0)
{
itemType = PacketHandler.readStack(dataStream);
}
else {
itemType = null;
}
MekanismUtils.updateBlock(worldObj, xCoord, yCoord, zCoord);
}
@Override
public ItemStack getStackInSlot(int slotID)
{
if(slotID == 1)
{
return topStack;
}
else {
return bottomStack;
}
}
@Override
public ItemStack decrStackSize(int slotID, int amount)
{
if(slotID == 1)
{
return null;
}
else if(slotID == 0)
{
int toRemove = Math.min(getItemCount(), amount);
if(toRemove > 0)
{
ItemStack ret = itemType.copy();
ret.stackSize = toRemove;
setItemCount(getItemCount()-toRemove);
return ret;
}
}
return null;
}
@Override
public ItemStack getStackInSlotOnClosing(int slotID)
{
return getStackInSlot(slotID);
}
@Override
public int getSizeInventory()
{
return 2;
}
@Override
public void setInventorySlotContents(int i, ItemStack itemstack)
{
if(i == 0)
{
if(getItemCount() == 0)
{
return;
}
if(itemstack == null)
{
setItemCount(getItemCount() - bottomStack.stackSize);
}
else {
setItemCount(getItemCount() - (bottomStack.stackSize-itemstack.stackSize));
}
}
else if(i == 1)
{
if(isValid(itemstack))
{
add(itemstack);
}
}
}
@Override
public void markDirty()
{
super.markDirty();
if(!worldObj.isRemote)
{
MekanismUtils.saveChunk(this);
Mekanism.packetHandler.sendToReceivers(new TileEntityMessage(Coord4D.get(this), getNetworkedData(new ArrayList())), new Range4D(Coord4D.get(this)));
prevCount = getItemCount();
sortStacks();
}
}
public void setItemType(ItemStack stack)
{
if(stack == null)
{
itemType = null;
cacheCount = 0;
topStack = null;
bottomStack = null;
return;
}
ItemStack ret = stack.copy();
ret.stackSize = 1;
itemType = ret;
}
public void setItemCount(int count)
{
cacheCount = Math.max(0, count);
topStack = null;
bottomStack = null;
if(count == 0)
{
setItemType(null);
}
markDirty();
}
@Override
public String getInventoryName()
{
return MekanismUtils.localize("tile.BasicBlock.Bin.name");
}
@Override
public boolean hasCustomInventoryName()
{
return true;
}
@Override
public int getInventoryStackLimit()
{
return 64;
}
@Override
public boolean isUseableByPlayer(EntityPlayer entityplayer)
{
return true;
}
@Override
public void openInventory() {}
@Override
public void closeInventory() {}
@Override
public boolean isItemValidForSlot(int i, ItemStack itemstack)
{
return i == 1 ? isValid(itemstack) : false;
}
@Override
public int[] getAccessibleSlotsFromSide(int side)
{
if(side == 1)
{
return new int[] {1};
}
else if(side == 0)
{
return new int[] {0};
}
return InventoryUtils.EMPTY;
}
@Override
public boolean canInsertItem(int i, ItemStack itemstack, int j)
{
return isItemValidForSlot(i, itemstack);
}
@Override
public boolean canExtractItem(int i, ItemStack itemstack, int j)
{
return i == 0 ? isValid(itemstack) : false;
}
@Override
public boolean canSetFacing(int facing)
{
return facing != 0 && facing != 1;
}
@Override
public void setActive(boolean active)
{
isActive = active;
if(clientActive != active)
{
Mekanism.packetHandler.sendToReceivers(new TileEntityMessage(Coord4D.get(this), getNetworkedData(new ArrayList())), new Range4D(Coord4D.get(this)));
clientActive = active;
}
}
@Override
public boolean getActive()
{
return isActive;
}
@Override
public boolean renderUpdate()
{
return true;
}
@Override
public boolean lightUpdate()
{
return true;
}
@Override
public ItemStack getStoredItemType()
{
if(itemType == null)
{
return null;
}
return MekanismUtils.size(itemType, getItemCount());
}
@Override
public void setStoredItemCount(int amount)
{
if(amount == 0)
{
setStoredItemType(null, 0);
}
setItemCount(amount);
}
@Override
public void setStoredItemType(ItemStack type, int amount)
{
itemType = type;
cacheCount = amount;
topStack = null;
bottomStack = null;
markDirty();
}
@Override
public int getMaxStoredCount()
{
return MAX_STORAGE;
}
@Override
public boolean onSneakRightClick(EntityPlayer player, int side)
{
setActive(!getActive());
worldObj.playSoundEffect(xCoord, yCoord, zCoord, "random.click", 0.3F, 1);
return true;
}
@Override
public boolean onRightClick(EntityPlayer player, int side)
{
return false;
}
}