package com.austinv11.peripheralsplusplus.tiles;
import com.austinv11.collectiveframework.minecraft.utils.Location;
import com.austinv11.collectiveframework.minecraft.utils.WorldUtils;
import com.austinv11.peripheralsplusplus.reference.Config;
import com.austinv11.peripheralsplusplus.utils.Util;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.*;
import net.minecraft.util.MathHelper;
import net.minecraftforge.common.util.ForgeDirection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
public class TileEntityInteractiveSorter extends MountedTileEntityInventory {
public static String publicName = "interactiveSorter";
private String name = "tileEntityInteractiveSorter";
private List<IComputerAccess> computers = new ArrayList<IComputerAccess>();
public TileEntityInteractiveSorter() {
super();
}
@Override
public int getSize() {
return 1;
}
public String getName() {
return name;
}
@Override
public String getType() {
return publicName;
}
@Override
public String[] getMethodNames() {
return new String[]{"analyze", "push", "pull", "isInventoryPresent"};
}
@Override
public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws LuaException, InterruptedException {
if (!Config.enableInteractiveSorter)
throw new LuaException("Interactive Sorters have been disabled");
if (method == 0) {
return new Object[]{getItemInfo(getStackInSlot(0))};
} else if (method == 1) {
if (getStackInSlot(0) == null)
return new Object[]{false};
ForgeDirection dir;
if (arguments.length < 1)
throw new LuaException("Too few arguments");
if (!(arguments[0] instanceof String) && !(arguments[0] instanceof Double))
throw new LuaException("Bad argument #1 (expected string or number)");
if (arguments.length > 1 && !(arguments[1] instanceof Double))
throw new LuaException("Bad argument #2 (expected number)");
if (arguments[0] instanceof String)
dir = ForgeDirection.valueOf(((String) arguments[0]).toUpperCase());
else
dir = ForgeDirection.getOrientation((int) (double) (Double) arguments[0]);
int amount = arguments.length > 1 ? MathHelper.clamp_int((int) (double) (Double) arguments[1], 0, getStackInSlot(0).stackSize) : getStackInSlot(0).stackSize;
if (!isInventoryOnSide(dir)) {
WorldUtils.spawnItemInWorld(new Location(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ, worldObj),
getStackInSlot(0).splitStack(amount));
markDirty();
return new Object[]{true};
}
IInventory inventory = getInventoryForSide(dir);
int oldSize = getStackInSlot(0).stackSize;
int[] slots = inventory instanceof ISidedInventory ?
((ISidedInventory) inventory).getAccessibleSlotsFromSide(dir.getOpposite().flag) : getDefaultSlots(inventory);
int currentSlot = 0;
while (getStackInSlot(0) != null && getStackInSlot(0).stackSize > oldSize-amount && currentSlot < slots.length) {
if (inventory.getStackInSlot(slots[currentSlot]) == null) {
inventory.setInventorySlotContents(slots[currentSlot], getStackInSlot(0));
setInventorySlotContents(0, null);
} else {
if (!inventory.getStackInSlot(slots[currentSlot]).isItemEqual(getStackInSlot(0))) {
currentSlot++;
continue;
}
int transferred = MathHelper.clamp_int(inventory.getStackInSlot(slots[currentSlot]).stackSize+amount,
getStackInSlot(0).stackSize, getStackInSlot(0).getMaxStackSize());
getStackInSlot(0).stackSize -= transferred;
inventory.getStackInSlot(0).stackSize += transferred;
}
inventory.markDirty();
markDirty();
currentSlot++;
}
return new Object[]{getStackInSlot(0) == null || getStackInSlot(0).stackSize != oldSize};
} else if (method == 2) {
ForgeDirection dir;
if (arguments.length < 1)
throw new LuaException("Too few arguments");
if (!(arguments[0] instanceof String) && !(arguments[0] instanceof Double))
throw new LuaException("Bad argument #1 (expected string or number)");
if (arguments.length > 1 && !(arguments[1] instanceof Double))
throw new LuaException("Bad argument #2 (expected number)");
if (arguments.length > 2 && !(arguments[2] instanceof Double))
throw new LuaException("Bad argument #3 (expected number)");
if (arguments[0] instanceof String)
dir = ForgeDirection.valueOf(((String) arguments[0]).toUpperCase());
else
dir = ForgeDirection.getOrientation((int) (double) (Double) arguments[0]);
if (!isInventoryOnSide(dir))
throw new LuaException("Block is not a valid inventory");
IInventory inventory = getInventoryForSide(dir);
int slots[] = inventory instanceof ISidedInventory ?
((ISidedInventory) inventory).getAccessibleSlotsFromSide(dir.getOpposite().flag) : getDefaultSlots(inventory);
int slot = -1;
if (arguments.length > 2) {
slot = getNearestSlot((int)(double)(Double)arguments[2], slots);
if (inventory.getStackInSlot(slot) == null)
return new Object[]{false};
} else {
for (int slot1 : slots)
if (getStackInSlot(0) == null) {
if (inventory.getStackInSlot(slot1) != null) {
slot = slot1;
break;
}
} else {
if (inventory.getStackInSlot(slot1) != null) {
if (inventory.getStackInSlot(slot1).isItemEqual(getStackInSlot(0))) {
slot = slot1;
break;
}
}
}
}
if (slot == -1)
return new Object[]{false};
int amount = arguments.length > 1 ? MathHelper.clamp_int((int) (double) (Double) arguments[1], 0,
inventory.getStackInSlot(slot).stackSize) : inventory.getStackInSlot(slot).stackSize;
int transferred;
if (getStackInSlot(0) != null) {
transferred = MathHelper.clamp_int(getStackInSlot(0).stackSize+amount,
getStackInSlot(0).stackSize, getStackInSlot(0).getMaxStackSize());
getStackInSlot(0).stackSize += transferred;
inventory.getStackInSlot(slot).stackSize -= transferred;
} else {
transferred = amount;
setInventorySlotContents(0, inventory.getStackInSlot(slot).splitStack(transferred));
}
if (inventory.getStackInSlot(slot) != null && inventory.getStackInSlot(slot).stackSize < 1)
inventory.setInventorySlotContents(slot, null);
inventory.markDirty();
markDirty();
return new Object[]{true};
} else if (method == 3) {
ForgeDirection dir;
if (arguments.length < 1)
throw new LuaException("Too few arguments");
if (!(arguments[0] instanceof String) && !(arguments[0] instanceof Double))
throw new LuaException("Bad argument #1 (expected string or number)");
if (arguments[0] instanceof String)
dir = ForgeDirection.valueOf(((String) arguments[0]).toUpperCase());
else
dir = ForgeDirection.getOrientation((int) (double) (Double) arguments[0]);
return new Object[]{isInventoryOnSide(dir)};
}
return new Object[0];
}
private int getNearestSlot(int requested, int[] slots) {
int difference = Integer.MAX_VALUE;
int currentSlot = slots[0];
for (int slot : slots) {
if (slot == requested)
return slot;
if (Math.abs(requested-slot) < difference) {
difference = Math.abs(requested-slot);
currentSlot = slot;
}
}
return currentSlot;
}
private int[] getDefaultSlots(IInventory inventory) {
int[] array = new int[inventory.getSizeInventory()];
for (int i = 0; i < inventory.getSizeInventory(); i++)
array[i] = i;
return array;
}
private boolean isInventoryOnSide(ForgeDirection dir) {
if (!worldObj.isAirBlock(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ)) {
Block block = worldObj.getBlock(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ);
if (block instanceof BlockContainer || block instanceof IInventory)
return true;
if (block.hasTileEntity(worldObj.getBlockMetadata(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ))) {
return worldObj.getTileEntity(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ) instanceof IInventory;
}
}
return false;
}
private IInventory getInventoryForSide(ForgeDirection dir) {
if (!worldObj.isAirBlock(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ)) {
Block block = worldObj.getBlock(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ);
if (block instanceof IInventory) {
return (IInventory) block;
}
if (block instanceof BlockContainer && block.hasTileEntity(worldObj.getBlockMetadata(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ)))
return (IInventory)worldObj.getTileEntity(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ);
}
return null;
}
@Override
public boolean equals(IPeripheral other) {
return other == this;
}
@Override
public void attach(IComputerAccess computer) {
super.attach(computer);
computers.add(computer);
}
@Override
public void detach(IComputerAccess computer) {
super.detach(computer);
computers.remove(computer);
}
@Override
public void setInventorySlotContents(int slot, ItemStack stack) {
super.setInventorySlotContents(slot, stack);
if (stack != null && stack.stackSize > 0 && slot == 0)
for (IComputerAccess computer : computers)
computer.queueEvent("itemReady", null);
}
private HashMap<String, Object> getItemInfo(ItemStack stack) {
if (stack == null)
return null;
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("amount", stack.stackSize);
String id;
int numId;
if (stack.getItem() instanceof ItemBlock) {
Block block = Block.getBlockFromItem(stack.getItem());
id = Block.blockRegistry.getNameForObject(block);
numId = Block.blockRegistry.getIDForObject(block);
} else {
id = Item.itemRegistry.getNameForObject(stack.getItem());
numId = Item.itemRegistry.getIDForObject(stack.getItem());
}
map.put("stringId", id);
map.put("numericalId", numId);
map.put("oreDictionaryEntries", Util.getEntries(stack));
map.put("meta", stack.getItemDamage());
map.put("name", stack.getDisplayName());
if (stack.hasTagCompound())
map.put("nbt", convertNBTToMap(stack.getTagCompound()));
return map;
}
private HashMap<String, Object> convertNBTToMap(NBTTagCompound tag) {
HashMap<String, Object> nbtMap = new HashMap<String, Object>();
Iterator iterator = tag.func_150296_c().iterator();
while (iterator.hasNext()) {
String key = (String)iterator.next();
NBTBase nbtBase = tag.getTag(key);
nbtMap.put(key, getObjectForNBT(nbtBase.copy()));
}
return nbtMap;
}
private Object getObjectForNBT(NBTBase nbtBase) {
if (nbtBase == null)
return null;
switch (nbtBase.getId()) {
case 0: //NBTTagEnd
return null;
case 1:
NBTTagByte tagByte = (NBTTagByte)nbtBase;
return tagByte.func_150290_f();
case 2:
NBTTagShort tagShort = (NBTTagShort)nbtBase;
return tagShort.func_150289_e();
case 3:
NBTTagInt tagInt = (NBTTagInt)nbtBase;
return tagInt.func_150287_d();
case 4:
NBTTagLong tagLong = (NBTTagLong)nbtBase;
return tagLong.func_150291_c();
case 5:
NBTTagFloat tagFloat = (NBTTagFloat)nbtBase;
return tagFloat.func_150288_h();
case 6:
NBTTagDouble tagDouble = (NBTTagDouble)nbtBase;
return tagDouble.func_150286_g();
case 7:
NBTTagByteArray tagByteArray = (NBTTagByteArray)nbtBase;
return Util.arrayToMap(tagByteArray.func_150292_c());
case 8:
NBTTagString tagString = (NBTTagString)nbtBase;
return tagString.func_150285_a_();
case 9:
NBTTagList tagList = (NBTTagList)nbtBase;
Object[] tags = new Object[tagList.tagCount()];
for (int i = 0; i < tagList.tagCount(); i++)
tags[i] = getObjectForNBT(tagList.removeTag(i));
return Util.arrayToMap(tags);
case 10:
NBTTagCompound tagCompound = (NBTTagCompound)nbtBase;
return convertNBTToMap(tagCompound);
case 11:
NBTTagIntArray tagIntArray = (NBTTagIntArray)nbtBase;
return Util.arrayToMap(tagIntArray.func_150302_c());
default:
return null;
}
}
}