package crazypants.enderio.conduit.item;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.ForgeDirection;
import com.enderio.core.common.util.BlockCoord;
import crazypants.enderio.conduit.AbstractConduitNetwork;
import crazypants.enderio.conduit.item.NetworkedInventory.Target;
import crazypants.enderio.conduit.item.filter.IItemFilter;
import crazypants.enderio.machine.invpanel.server.InventoryDatabaseServer;
public class ItemConduitNetwork extends AbstractConduitNetwork<IItemConduit, IItemConduit> {
final List<NetworkedInventory> inventories = new ArrayList<NetworkedInventory>();
private final Map<BlockCoord, List<NetworkedInventory>> invMap = new HashMap<BlockCoord, List<NetworkedInventory>>();
final Map<BlockCoord, IItemConduit> conMap = new HashMap<BlockCoord, IItemConduit>();
private boolean requiresSort = true;
private boolean doingSend = false;
private int changeCount;
private InventoryDatabaseServer database;
public ItemConduitNetwork() {
super(IItemConduit.class, IItemConduit.class);
}
@Override
public void addConduit(IItemConduit con) {
super.addConduit(con);
conMap.put(con.getLocation(), con);
TileEntity te = con.getBundle().getEntity();
if(te != null) {
for (ForgeDirection direction : con.getExternalConnections()) {
IInventory extCon = con.getExternalInventory(direction);
if(extCon != null) {
inventoryAdded(con, direction, te.xCoord + direction.offsetX, te.yCoord + direction.offsetY, te.zCoord + direction.offsetZ, extCon);
}
}
}
}
public void inventoryAdded(IItemConduit itemConduit, ForgeDirection direction, int x, int y, int z, IInventory externalInventory) {
BlockCoord bc = new BlockCoord(x, y, z);
NetworkedInventory inv = new NetworkedInventory(this, externalInventory, itemConduit, direction, bc);
inventories.add(inv);
getOrCreate(bc).add(inv);
requiresSort = true;
}
public NetworkedInventory getInventory(IItemConduit conduit, ForgeDirection dir) {
for(NetworkedInventory inv : inventories) {
if(inv.con == conduit && inv.conDir == dir) {
return inv;
}
}
return null;
}
public List<NetworkedInventory> getInventoryPanelSources() {
ArrayList<NetworkedInventory> res = new ArrayList<NetworkedInventory>();
for(NetworkedInventory inv : inventories) {
if(inv.con.hasInventoryPanelUpgrade(inv.conDir)) {
res.add(inv);
}
}
return res;
}
private List<NetworkedInventory> getOrCreate(BlockCoord bc) {
List<NetworkedInventory> res = invMap.get(bc);
if(res == null) {
res = new ArrayList<NetworkedInventory>();
invMap.put(bc, res);
}
return res;
}
public void inventoryRemoved(ItemConduit itemConduit, int x, int y, int z) {
BlockCoord bc = new BlockCoord(x, y, z);
List<NetworkedInventory> invs = getOrCreate(bc);
NetworkedInventory remove = null;
for (NetworkedInventory ni : invs) {
if(ni.con.getLocation().equals(itemConduit.getLocation())) {
remove = ni;
break;
}
}
if(remove != null) {
invs.remove(remove);
inventories.remove(remove);
requiresSort = true;
}
}
public void routesChanged() {
requiresSort = true;
}
public void inventoryPanelSourcesChanged() {
changeCount++;
}
public int getChangeCount() {
return changeCount;
}
public InventoryDatabaseServer getDatabase() {
check: {
if(database == null) {
database = new InventoryDatabaseServer(this);
} else if(database.isCurrent()) {
break check;
}
database.updateNetworkSources();
}
return database;
}
@Override
public void destroyNetwork() {
super.destroyNetwork();
if(database != null) {
database.resetDatabase();
database = null;
}
}
public ItemStack sendItems(ItemConduit itemConduit, ItemStack item, ForgeDirection side) {
if(doingSend) {
return item;
}
if(item == null) {
return item;
}
try {
doingSend = true;
BlockCoord loc = itemConduit.getLocation().getLocation(side);
ItemStack result = item.copy();
List<NetworkedInventory> invs = getOrCreate(loc);
for (NetworkedInventory inv : invs) {
if(inv.con.getLocation().equals(itemConduit.getLocation())) {
int numInserted = inv.insertIntoTargets(item.copy());
if(numInserted >= item.stackSize) {
return null;
}
result.stackSize -= numInserted;
}
}
return result;
} finally {
doingSend = false;
}
}
public List<String> getTargetsForExtraction(BlockCoord extractFrom, IItemConduit con, ItemStack input) {
List<String> result = new ArrayList<String>();
List<NetworkedInventory> invs = getOrCreate(extractFrom);
for (NetworkedInventory source : invs) {
if(source.con.getLocation().equals(con.getLocation())) {
if(source.sendPriority != null) {
for (Target t : source.sendPriority) {
IItemFilter f = t.inv.con.getOutputFilter(t.inv.conDir);
if(input == null || f == null || f.doesItemPassFilter(t.inv, input)) {
String s = t.inv.getLocalizedInventoryName() + " " + t.inv.location.chatString() + " Distance [" + t.distance + "] ";
result.add(s);
}
}
}
}
}
return result;
}
public List<String> getInputSourcesFor(IItemConduit con, ForgeDirection dir, ItemStack input) {
List<String> result = new ArrayList<String>();
for (NetworkedInventory inv : inventories) {
if(inv.hasTarget(con, dir)) {
IItemFilter f = inv.con.getInputFilter(inv.conDir);
if(input == null || f == null || f.doesItemPassFilter(inv, input)) {
result.add(inv.getLocalizedInventoryName() + " " + inv.location.chatString());
}
}
}
return result;
}
@Override
public void doNetworkTick() {
for (NetworkedInventory ni : inventories) {
if(requiresSort) {
ni.updateInsertOrder();
}
ni.onTick();
}
if(requiresSort) {
requiresSort = false;
changeCount++;
}
if(database != null) {
database.tick();
}
}
static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
static int MAX_SLOT_CHECK_PER_TICK = 64;
}