package mcjty.rftools.blocks.storagemonitor;
import mcjty.lib.entity.GenericEnergyReceiverTileEntity;
import mcjty.lib.entity.SyncedCoordinate;
import mcjty.lib.entity.SyncedValue;
import mcjty.lib.entity.SyncedValueList;
import mcjty.lib.network.Argument;
import mcjty.lib.varia.Coordinate;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.ForgeDirection;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
public class StorageScannerTileEntity extends GenericEnergyReceiverTileEntity {
public static final String CMD_SETRADIUS = "setRadius";
public static final String CMD_STARTSCAN = "startScan";
public static final String CMD_STARTSEARCH = "startSearch";
public static final String CLIENTCMD_SEARCHREADY = "searchReady";
// For client side: the items of the inventory we're currently looking at.
private List<ItemStack> showingItems = new ArrayList<ItemStack> ();
private SyncedValue<Integer> radius = new SyncedValue<Integer>(1);
private SyncedValue<Boolean> scanning = new SyncedValue<Boolean>(false);
private SyncedCoordinate c1 = new SyncedCoordinate(Coordinate.INVALID);
private SyncedCoordinate c2 = new SyncedCoordinate(Coordinate.INVALID);
private SyncedCoordinate cur = new SyncedCoordinate(Coordinate.INVALID);
private SyncedValueList<InvBlockInfo> inventories = new SyncedValueList<InvBlockInfo>() {
@Override
public InvBlockInfo readElementFromNBT(NBTTagCompound tagCompound) {
return InvBlockInfo.readFromNBT(tagCompound);
}
@Override
public NBTTagCompound writeElementToNBT(InvBlockInfo element) {
return element.writeToNBT();
}
};
public StorageScannerTileEntity() {
super(StorageScannerConfiguration.MAXENERGY, StorageScannerConfiguration.RECEIVEPERTICK);
registerSyncedObject(scanning);
registerSyncedObject(c1);
registerSyncedObject(c2);
registerSyncedObject(cur);
registerSyncedObject(inventories);
}
public List<Coordinate> startSearch(String search) {
search = search.toLowerCase();
List<Coordinate> output = new ArrayList<Coordinate>();
for (InvBlockInfo invBlockInfo : inventories) {
Coordinate c = invBlockInfo.getCoordinate();
TileEntity tileEntity = worldObj.getTileEntity(c.getX(), c.getY(), c.getZ());
if (tileEntity instanceof IInventory) {
IInventory inventory = (IInventory) tileEntity;
for (int i = 0 ; i < inventory.getSizeInventory() ; i++) {
ItemStack itemStack = inventory.getStackInSlot(i);
if (itemStack != null) {
String readableName = itemStack.getDisplayName();
if (readableName.toLowerCase().contains(search)) {
output.add(c);
break;
}
}
}
}
}
return output;
}
public void startScan(boolean start) {
if (!worldObj.isRemote) {
if (!start) {
scanning.setValue(false);
notifyBlockUpdate();
return;
}
int r = radius.getValue();
// Only on server
int y1 = yCoord-r;
if (y1 < 0) {
y1 = 0;
}
c1.setCoordinate(new Coordinate(xCoord-r, y1, zCoord-r));
int y2 = yCoord+r;
if (y2 >= worldObj.getHeight()) {
y2 = worldObj.getHeight()-1;
}
c2.setCoordinate(new Coordinate(xCoord+r, y2, zCoord+r));
scanning.setValue(true);
cur.setCoordinate(c1.getCoordinate());
inventories.clear();
notifyBlockUpdate();
}
}
public int getRadius() {
return radius.getValue();
}
public void setRadius(int v) {
radius.setValue(v);
notifyBlockUpdate();
}
public boolean isScanning() {
return scanning.getValue();
}
public int getProgress() {
int z1 = c1.getCoordinate().getZ();
int z2 = c2.getCoordinate().getZ();
int z = cur.getCoordinate().getZ();
return (z-z1) * 100 / (z2-z1);
}
@Override
protected void checkStateServer() {
super.checkStateServer();
if (scanning.getValue()) {
int rf = StorageScannerConfiguration.rfPerOperation;
rf = (int) (rf * (2.0f - getInfusedFactor()) / 2.0f);
if (getEnergyStored(ForgeDirection.DOWN) < rf) {
return;
}
consumeEnergy(rf);
int scans = StorageScannerConfiguration.scansPerOperation;
scans = scans * (int) (getInfusedFactor() + 1.01f);
for (int i = 0 ; i < scans; i++) {
Coordinate c = cur.getCoordinate();
checkInventoryStatus(c.getX(), c.getY(), c.getZ());
if (!advanceCurrent()) {
return;
}
}
}
}
public void storeItemsForClient(List<ItemStack> items) {
showingItems = new ArrayList<ItemStack>(items);
}
public List<ItemStack> getShowingItems() {
return showingItems;
}
public void clearShowingItems() {
showingItems.clear();
}
public List<ItemStack> getInventoryForBlock(int cx, int cy, int cz) {
showingItems = new ArrayList<ItemStack>();
if (getEnergyStored(ForgeDirection.DOWN) < StorageScannerConfiguration.rfPerOperation) {
return showingItems;
}
consumeEnergy(StorageScannerConfiguration.rfPerOperation);
TileEntity tileEntity = worldObj.getTileEntity(cx, cy, cz);
if (tileEntity instanceof IInventory) {
IInventory inventory = (IInventory) tileEntity;
for (int i = 0 ; i < inventory.getSizeInventory() ; i++) {
ItemStack itemStack = inventory.getStackInSlot(i);
if (itemStack != null) {
showingItems.add(itemStack);
}
}
}
return showingItems;
}
private void checkInventoryStatus(int cx, int cy, int cz) {
TileEntity tileEntity = worldObj.getTileEntity(cx, cy, cz);
if (tileEntity instanceof IInventory) {
IInventory inventory = (IInventory) tileEntity;
if (inventory.getSizeInventory() > 0) {
inventories.add(new InvBlockInfo(new Coordinate(cx, cy, cz), inventory.getSizeInventory()));
notifyBlockUpdate(); }
}
}
// Advance the 'cur' index to the next block. Return false when done.
// When done 'scanning' will be set to false as well.
private boolean advanceCurrent() {
Coordinate c = cur.getCoordinate();
int cx = c.getX();
int cy = c.getY();
int cz = c.getZ();
cx++;
Coordinate lo = c1.getCoordinate();
Coordinate up = c2.getCoordinate();
if (cx > up.getX()) {
cx = lo.getX();
cy++;
if (cy > up.getY()) {
cy = lo.getY();
cz++;
if (cz > up.getZ()) {
scanning.setValue(false);
notifyBlockUpdate();
return false;
}
}
}
cur.setCoordinate(new Coordinate(cx, cy, cz));
notifyBlockUpdate();
return true;
}
public SyncedValueList<InvBlockInfo> getInventories() {
return inventories;
}
@Override
public void readFromNBT(NBTTagCompound tagCompound) {
super.readFromNBT(tagCompound);
scanning.setValue(tagCompound.getBoolean("scanning"));
c1.readFromNBT(tagCompound, "c1");
c2.readFromNBT(tagCompound, "c2");
cur.readFromNBT(tagCompound, "cur");
inventories.readFromNBT(tagCompound, "inv");
}
@Override
public void readRestorableFromNBT(NBTTagCompound tagCompound) {
super.readRestorableFromNBT(tagCompound);
radius.setValue(tagCompound.getInteger("radius"));
}
@Override
public void writeToNBT(NBTTagCompound tagCompound) {
super.writeToNBT(tagCompound);
tagCompound.setBoolean("scanning", scanning.getValue());
c1.writeToNBT(tagCompound, "c1");
c2.writeToNBT(tagCompound, "c2");
cur.writeToNBT(tagCompound, "cur");
inventories.writeToNBT(tagCompound, "inv");
}
@Override
public void writeRestorableToNBT(NBTTagCompound tagCompound) {
super.writeRestorableToNBT(tagCompound);
tagCompound.setInteger("radius", radius.getValue());
}
@Override
public boolean execute(EntityPlayerMP playerMP, String command, Map<String, Argument> args) {
boolean rc = super.execute(playerMP, command, args);
if (rc) {
return true;
}
if (CMD_SETRADIUS.equals(command)) {
setRadius(args.get("r").getInteger());
return true;
} else if (CMD_STARTSCAN.equals(command)) {
startScan(args.get("start").getBoolean());
return true;
}
return false;
}
@Override
public List executeWithResultList(String command, Map<String, Argument> args) {
List rc = super.executeWithResultList(command, args);
if (rc != null) {
return rc;
}
if (CMD_STARTSEARCH.equals(command)) {
return startSearch(args.get("search").getString());
}
return null;
}
@Override
public boolean execute(String command, List list) {
boolean rc = super.execute(command, list);
if (rc) {
return true;
}
if (CLIENTCMD_SEARCHREADY.equals(command)) {
GuiStorageScanner.fromServer_coordinates = new HashSet<Coordinate>(list);
return true;
}
return false;
}
}