package com.austinv11.peripheralsplusplus.lua;
import com.austinv11.collectiveframework.minecraft.utils.Location;
import com.austinv11.peripheralsplusplus.reference.Config;
import com.austinv11.peripheralsplusplus.tiles.TileEntityPlayerInterface;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaObject;
import dan200.computercraft.api.lua.LuaException;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.util.ForgeDirection;
import java.util.ArrayList;
import java.util.HashMap;
public class LuaObjectPlayerInv implements ILuaObject {
private InventoryPlayer inv;
private TileEntityPlayerInterface playerInterface;
private ItemStack permCard;
public LuaObjectPlayerInv(EntityPlayer player, TileEntityPlayerInterface playerInterface, ItemStack permCard) {
this.inv = player.inventory;
this.playerInterface = playerInterface;
this.permCard = permCard;
}
@Override
public Object[] callMethod(ILuaContext context, int method, Object[] arguments) throws LuaException, InterruptedException {
ItemStack origStack;
ItemStack newStack;
switch (method) {
case 0:
if (arguments.length != 1) {
throw new LuaException("Wrong number of arguments. 1 expected.");
}
if (!(arguments[0] instanceof Double)) {
throw new LuaException("Bad argument #1 (expected number)");
}
if (hasGetStacksPermission()) {
return new Object[] {getObjectFromStack(inv.getStackInSlot(((Double) arguments[0]).intValue()))};
}
break;
case 1:
if (arguments.length != 2) {
throw new LuaException("Wrong number of arguments. 2 expected.");
}
if (!(arguments[0] instanceof Double)) {
throw new LuaException("Bad argument #1 (expected number)");
}
if (!(arguments[1] instanceof Double)) {
throw new LuaException("Bad argument #2 (expected number)");
}
if (getOutputInventory() == null) {
throw new LuaException("No output side set.");
}
if (hasWithdrawPermission()) {
origStack = inv.getStackInSlot(((Double) arguments[0]).intValue());
if (origStack == null) {
return new Object[0];
}
newStack = inv.decrStackSize(((Double) arguments[0]).intValue(), ((Double) arguments[1]).intValue());
if (!addStackToInv(getOutputInventory(), newStack, -1)) {
inv.addItemStackToInventory(newStack);
return new Object[]{false};
}
return new Object[]{true};
}
break;
case 2:
if (arguments.length != 3) {
throw new LuaException("Wrong number of arguments. 3 expected.");
}
if (!(arguments[0] instanceof Double)) {
throw new LuaException("Bad argument #1 (expected number)");
}
if (!(arguments[1] instanceof Double)) {
throw new LuaException("Bad argument #2 (expected number)");
}
if (!(arguments[2] instanceof Double)) {
throw new LuaException("Bad argument #3 (expected number)");
}
if (hasDepositPermission()) {
origStack = getInputInventory().getStackInSlot(((Double) arguments[1]).intValue());
newStack = getInputInventory().decrStackSize(((Double) arguments[1]).intValue(), ((Double) arguments[2]).intValue());
if (newStack == null) {
return new Object[0];
}
if (addStackToInv(inv, newStack, 0)) {
return new Object[]{true};
} else {
getInputInventory().setInventorySlotContents(((Double) arguments[1]).intValue(), origStack);
return new Object[]{false};
}
}
break;
case 3:
if (arguments.length != 2) {
throw new LuaException("Wrong number of arguments. 2 expected.");
}
if (!(arguments[0] instanceof Double)) {
throw new LuaException("Bad argument #1 (expected number)");
}
if (!(arguments[1] instanceof Double)) {
throw new LuaException("Bad argument #2 (expected number)");
}
if (hasDepositPermission()) {
origStack = getInputInventory().getStackInSlot(((Double) arguments[0]).intValue());
newStack = getInputInventory().decrStackSize(((Double) arguments[0]).intValue(), ((Double) arguments[1]).intValue());
if (newStack == null) {
return new Object[0];
}
if (addStackToInv(inv, newStack, -1)) {
return new Object[]{true};
} else {
getInputInventory().setInventorySlotContents(((Double) arguments[0]).intValue(), origStack);
return new Object[]{false};
}
}
break;
case 4:
if (hasGetStacksPermission())
{
return new Object[]{inv.getSizeInventory()};
}
break;
}
inv.markDirty();
return new Object[0];
}
@Override
public String[] getMethodNames() {
return new String[]{"getStackInSlot", "retrieveFromSlot", "pushToSlot", "push", "getSize"};
}
private Object getObjectFromStack(ItemStack stack) {
HashMap<String, Object> map = new HashMap<String, Object>();
if (stack == null)
{
return null;
}
String itemName = Item.itemRegistry.getNameForObject(stack.getItem());
int meta = stack.getItemDamage();
long amount = stack.stackSize;
String displayName = stack.getDisplayName();
map.put("name", itemName);
map.put("meta", meta);
map.put("amount", amount);
map.put("displayName", displayName);
return map;
}
private IInventory getOutputInventory() throws LuaException {
ForgeDirection outDir = playerInterface.outputSide;
if (outDir == null) {
throw new LuaException("Output Side has not yet been set.");
}
Location blockLoc = new Location(playerInterface.xCoord + outDir.offsetX, playerInterface.yCoord + outDir.offsetY, playerInterface.zCoord + outDir.offsetZ, playerInterface.getWorldObj());
Block block = playerInterface.getWorldObj().getBlock(blockLoc.getRoundedX(), blockLoc.getRoundedY(), blockLoc.getRoundedZ());
if (block instanceof BlockContainer) {
return (IInventory) playerInterface.getWorldObj().getTileEntity(blockLoc.getRoundedX(), blockLoc.getRoundedY(), blockLoc.getRoundedZ());
} else {
throw new LuaException("Invalid Output Inventory.");
}
}
private IInventory getInputInventory() throws LuaException {
ForgeDirection inDir = playerInterface.inputSide;
if (inDir == null) {
throw new LuaException("Input Side has not yet been set.");
}
Location blockLoc = new Location(playerInterface.xCoord + inDir.offsetX, playerInterface.yCoord + inDir.offsetY, playerInterface.zCoord + inDir.offsetZ, playerInterface.getWorldObj());
Block block = playerInterface.getWorldObj().getBlock(blockLoc.getRoundedX(), blockLoc.getRoundedY(), blockLoc.getRoundedZ());
if (block instanceof BlockContainer) {
return (IInventory) playerInterface.getWorldObj().getTileEntity(blockLoc.getRoundedX(), blockLoc.getRoundedY(), blockLoc.getRoundedZ());
} else {
throw new LuaException("Invalid Input Inventory.");
}
}
/**
* Don't look at me, I'm hideous! D:
* Attempts to add the passed ItemStack to the passed IInventory.
* Specify a slot ID if the stack must be placed in that slot. Pass -1 if they are all valid.
*
* @return Success at depositing any items in the stack.
*/
private boolean addStackToInv(IInventory inv, ItemStack addStack, int slot) {
for (Integer slotNum : getValidSlotsForStack(inv, addStack, slot)) {
ItemStack currentStack = inv.getStackInSlot(slotNum);
if (inv.getStackInSlot(slotNum) == null) {
inv.setInventorySlotContents(slotNum, addStack);
return true;
} else {
int add = currentStack.getMaxStackSize() - currentStack.stackSize;
if (addStack.stackSize <= add) {
currentStack.stackSize += addStack.stackSize;
return true;
} else {
// Was unable to add all of the stack to one slot and must add what it can to this slot and move on to the next.
currentStack.stackSize += add;
addStack.stackSize -= add;
// We should only move onto the next slot if the user specified that this is ok (slot == -1)
if (slot != -1) {
return false;
}
}
if (addStack.stackSize == 0) {
return true;
}
}
}
return false;
}
/**
* Returns an ArrayList of the valid slot IDs for the passed ItemStack in the passed IInventory.
* Valid meaning the slot is either empty or contains the correct item and is not full.
* The passed slot takes priority over other found slots and will be placed first.
* Passing -1 in its place indicates that no slot should take priority.
*/
private ArrayList<Integer> getValidSlotsForStack(IInventory inv, ItemStack stack, int slot) {
ArrayList<Integer> slots = new ArrayList<Integer>();
if (slot != -1) {
slots.add(slot);
}
for (int i = 0; i < inv.getSizeInventory(); i++) {
if ((inv.getStackInSlot(i) == null || (inv.getStackInSlot(i).getItem().equals(stack.getItem()) &&
inv.getStackInSlot(i).stackSize != inv.getStackInSlot(i).getMaxStackSize() &&
inv.getStackInSlot(i).getItemDamage() == stack.getItemDamage())) && i != slot) {
slots.add(i);
}
}
return slots;
}
private boolean hasDepositPermission() {
return !Config.enableInterfacePermissions || permCard.getTagCompound().getBoolean("deposit");
}
private boolean hasWithdrawPermission() {
return !Config.enableInterfacePermissions || permCard.getTagCompound().getBoolean("withdraw");
}
private boolean hasGetStacksPermission() {
return !Config.enableInterfacePermissions || permCard.getTagCompound().getBoolean("getStacks");
}
}