package crazypants.enderio.machine.invpanel.server;
import crazypants.enderio.conduit.item.ItemConduitNetwork;
import crazypants.enderio.conduit.item.NetworkedInventory;
import crazypants.enderio.config.Config;
import crazypants.enderio.machine.invpanel.InventoryDatabase;
import crazypants.enderio.machine.invpanel.PacketDatabaseReset;
import crazypants.enderio.machine.invpanel.TileInventoryPanel;
import crazypants.enderio.network.PacketHandler;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import com.enderio.core.common.network.CompressedDataInput;
import com.enderio.core.common.network.CompressedDataOutput;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
public class InventoryDatabaseServer extends InventoryDatabase<ItemEntry> {
private static final AtomicInteger nextGeneration = new AtomicInteger();
private final ItemConduitNetwork network;
private int networkChangeCount;
private AbstractInventory[] inventories;
private int currentInventory;
private ChangeLog changeLog;
private boolean sentToClient;
private int tickPause;
private float power;
public InventoryDatabaseServer(ItemConduitNetwork network) {
this.network = network;
}
public ItemConduitNetwork getNetwork() {
return network;
}
public boolean isCurrent() {
return networkChangeCount == network.getChangeCount();
}
public void addChangeLog(ChangeLog cl) {
if(changeLog == null) {
changeLog = cl;
} else if(changeLog instanceof ChangeLogList) {
((ChangeLogList)changeLog).add(cl);
} else if(changeLog != cl) {
changeLog = new ChangeLogList(changeLog, cl);
}
}
public void removeChangeLog(ChangeLog cl) {
if(changeLog == cl) {
changeLog = null;
} else if(changeLog instanceof ChangeLogList) {
changeLog = ((ChangeLogList)changeLog).remove(cl);
}
}
public List<ItemEntry> decompressMissingItems(byte[] compressed) throws IOException {
CompressedDataInput cdi = new CompressedDataInput(compressed);
try {
int pktGeneration = cdi.readVariable();
if(pktGeneration != generation) {
return Collections.emptyList();
}
int numIDs = cdi.readVariable();
ArrayList<ItemEntry> items = new ArrayList<ItemEntry>(numIDs);
for(int i = 0; i < numIDs; i++) {
int dbIndex = cdi.readVariable();
if(dbIndex < complexItems.size()) {
ItemEntry entry = complexItems.get(dbIndex);
items.add(entry);
}
}
return items;
} finally {
cdi.close();
}
}
public byte[] compressItemInfo(List<ItemEntry> items) throws IOException{
CompressedDataOutput cdo = new CompressedDataOutput();
try {
int count = items.size();
cdo.writeVariable(count);
for(ItemEntry entry : items) {
assert entry.dbID >= COMPLEX_DBINDEX_START;
int code = (entry.dbID - COMPLEX_DBINDEX_START) << 1;
if(entry.nbt != null) {
code |= 1;
}
cdo.writeVariable(code);
cdo.writeVariable(entry.itemID);
cdo.writeVariable(entry.meta);
if(entry.nbt != null) {
CompressedStreamTools.write(entry.nbt, cdo);
}
cdo.writeVariable(entry.countItems(this));
}
return cdo.getCompressed();
} finally {
cdo.close();
}
}
public byte[] compressItemList() throws IOException {
CompressedDataOutput cdo = new CompressedDataOutput();
try {
cdo.writeByte(0);
for(Map.Entry<Integer, ItemEntry> entry : simpleRegsitry.entrySet()) {
int count = entry.getValue().countItems(this);
if(count > 0) {
cdo.writeVariable(count);
cdo.writeShort(entry.getKey());
}
}
cdo.writeByte(0);
int prevID = COMPLEX_DBINDEX_START;
for(ItemEntry entry : complexItems) {
if(entry != null) {
int count = entry.countItems(this);
if(count > 0) {
cdo.writeVariable(count);
cdo.writeVariable(entry.dbID - prevID);
prevID = entry.dbID;
}
}
}
cdo.writeByte(0);
sentToClient = true;
return cdo.getCompressed();
} finally {
cdo.close();
}
}
public byte[] compressChangedItems(Collection<ItemEntry> items) throws IOException {
CompressedDataOutput cdo = new CompressedDataOutput();
try {
cdo.writeVariable(items.size());
for(ItemEntry entry : items) {
cdo.writeVariable(entry.dbID);
cdo.writeVariable(entry.countItems(this));
}
return cdo.getCompressed();
} finally {
cdo.close();
}
}
public void resetDatabase() {
simpleRegsitry.clear();
complexRegistry.clear();
complexItems.clear();
currentInventory = 0;
if(sentToClient) {
PacketHandler.INSTANCE.sendToAll(new PacketDatabaseReset(generation));
sentToClient = false;
}
}
public void updateNetworkSources() {
resetDatabase();
generation = nextGeneration.incrementAndGet();
networkChangeCount = network.getChangeCount();
List<NetworkedInventory> sources = network.getInventoryPanelSources();
if(sources == null || sources.isEmpty()) {
this.inventories = null;
} else {
this.inventories = new AbstractInventory[sources.size()];
for(int i=0; i<sources.size(); i++) {
NetworkedInventory ni = sources.get(i);
inventories[i] = InventoryFactory.createInventory(ni);
}
}
if(changeLog != null) {
changeLog.databaseReset();
}
}
public int getNumInventories() {
return (inventories == null) ? 0 : inventories.length;
}
public float getPower() {
return power;
}
public void addPower(float power) {
this.power += power;
}
public boolean isOperational() {
return power > 0 && inventories != null;
}
public int extractItems(ItemEntry entry, int count, TileInventoryPanel te) {
float availablePower = power + te.getAvailablePower();
availablePower -= Config.inventoryPanelExtractCostPerOperation;
if(availablePower <= 0) {
return 0;
}
if(Config.inventoryPanelExtractCostPerOperation > 0) {
long maxCount = Math.round(Math.floor(availablePower / Config.inventoryPanelExtractCostPerOperation));
count = (int)Math.min(maxCount, count);
}
if(count > 0) {
int extracted = entry.extractItems(this, count);
power -= Config.inventoryPanelExtractCostPerOperation + extracted * Config.inventoryPanelExtractCostPerOperation;
te.refuelPower(this);
return extracted;
}
return 0;
}
private void scanNextInventory() {
if(!isOperational()) {
tickPause = 20;
return;
}
AbstractInventory inv = inventories[currentInventory];
int slots = inv.scanInventory(this);
currentInventory = (currentInventory+1) % inventories.length;
tickPause += 1 + (slots + 8) / 9;
power -= slots * Config.inventoryPanelScanCostPerSlot;
}
public void tick() {
if(--tickPause <= 0) {
scanNextInventory();
}
}
void entryChanged(ItemEntry entry) {
if(changeLog != null) {
changeLog.entryChanged(entry);
}
}
public void sendChangeLogs() {
if(changeLog != null) {
changeLog.sendChangeLog();
}
}
@Override
protected ItemEntry createItemEntry(int dbId, int hash, int itemID, int meta, NBTTagCompound nbt) {
return new ItemEntry(dbId, hash, itemID, meta, nbt);
}
AbstractInventory getInventory(int aiIndex) {
return inventories[aiIndex];
}
}