package mekanism.common.tile;
import io.netty.buffer.ByteBuf;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import mekanism.api.Coord4D;
import mekanism.api.IHeatTransfer;
import mekanism.api.Range4D;
import mekanism.common.Mekanism;
import mekanism.common.PacketHandler;
import mekanism.common.capabilities.Capabilities;
import mekanism.common.content.boiler.BoilerCache;
import mekanism.common.content.boiler.BoilerUpdateProtocol;
import mekanism.common.content.boiler.SynchronizedBoilerData;
import mekanism.common.content.tank.SynchronizedTankData.ValveData;
import mekanism.common.multiblock.MultiblockManager;
import mekanism.common.network.PacketTileEntity.TileEntityMessage;
import mekanism.common.util.LangUtils;
import mekanism.common.util.MekanismUtils;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fml.common.FMLCommonHandler;
public class TileEntityBoilerCasing extends TileEntityMultiblock<SynchronizedBoilerData> implements IHeatTransfer
{
/** A client-sided set of valves on this tank's structure that are currently active, used on the client for rendering fluids. */
public Set<ValveData> valveViewing = new HashSet<ValveData>();
/** The capacity this tank has on the client-side. */
public int clientWaterCapacity;
public int clientSteamCapacity;
public float prevWaterScale;
public TileEntityBoilerCasing()
{
this("BoilerCasing");
}
public TileEntityBoilerCasing(String name)
{
super(name);
inventory = new ItemStack[2];
}
@Override
public void onUpdate()
{
super.onUpdate();
if(worldObj.isRemote)
{
if(structure != null && clientHasStructure && isRendering)
{
float targetScale = (float)(structure.waterStored != null ? structure.waterStored.amount : 0)/clientWaterCapacity;
if(Math.abs(prevWaterScale - targetScale) > 0.01)
{
prevWaterScale = (9*prevWaterScale + targetScale)/10;
}
}
if(!clientHasStructure || !isRendering)
{
for(ValveData data : valveViewing)
{
TileEntityBoilerCasing tileEntity = (TileEntityBoilerCasing)data.location.getTileEntity(worldObj);
if(tileEntity != null)
{
tileEntity.clientHasStructure = false;
}
}
valveViewing.clear();
}
}
if(!worldObj.isRemote)
{
if(structure != null)
{
if(structure.waterStored != null && structure.waterStored.amount <= 0)
{
structure.waterStored = null;
markDirty();
}
if(structure.steamStored != null && structure.steamStored.amount <= 0)
{
structure.steamStored = null;
markDirty();
}
if(isRendering)
{
boolean needsValveUpdate = false;
for(ValveData data : structure.valves)
{
if(data.activeTicks > 0)
{
data.activeTicks--;
}
if(data.activeTicks > 0 != data.prevActive)
{
needsValveUpdate = true;
}
data.prevActive = data.activeTicks > 0;
}
boolean needsHotUpdate = false;
boolean newHot = structure.temperature >= SynchronizedBoilerData.BASE_BOIL_TEMP-0.01F;
if(newHot != structure.clientHot)
{
needsHotUpdate = true;
structure.clientHot = newHot;
}
double[] d = structure.simulateHeat();
structure.applyTemperatureChange();
structure.lastEnvironmentLoss = d[1];
if(structure.temperature >= SynchronizedBoilerData.BASE_BOIL_TEMP && structure.waterStored != null)
{
int steamAmount = structure.steamStored != null ? structure.steamStored.amount : 0;
double heatAvailable = structure.getHeatAvailable();
structure.lastMaxBoil = (int)Math.floor(heatAvailable / SynchronizedBoilerData.getHeatEnthalpy());
int amountToBoil = Math.min(structure.lastMaxBoil, structure.waterStored.amount);
amountToBoil = Math.min(amountToBoil, (structure.steamVolume*BoilerUpdateProtocol.STEAM_PER_TANK)-steamAmount);
structure.waterStored.amount -= amountToBoil;
if(structure.steamStored == null)
{
structure.steamStored = new FluidStack(FluidRegistry.getFluid("steam"), amountToBoil);
}
else {
structure.steamStored.amount += amountToBoil;
}
structure.temperature -= (amountToBoil*SynchronizedBoilerData.getHeatEnthalpy())/structure.locations.size();
structure.lastBoilRate = amountToBoil;
}
else {
structure.lastBoilRate = 0;
structure.lastMaxBoil = 0;
}
if(needsValveUpdate || structure.needsRenderUpdate() || needsHotUpdate)
{
sendPacketToRenderer();
}
structure.prevWater = structure.waterStored != null ? structure.waterStored.copy() : null;
structure.prevSteam = structure.steamStored != null ? structure.steamStored.copy() : null;
MekanismUtils.saveChunk(this);
}
}
}
}
@Override
public boolean onActivate(EntityPlayer player, EnumHand hand, ItemStack stack)
{
if(!player.isSneaking() && structure != null)
{
Mekanism.packetHandler.sendToReceivers(new TileEntityMessage(Coord4D.get(this), getNetworkedData(new ArrayList())), new Range4D(Coord4D.get(this)));
player.openGui(Mekanism.instance, 54, worldObj, getPos().getX(), getPos().getY(), getPos().getZ());
return true;
}
return false;
}
@Override
protected SynchronizedBoilerData getNewStructure()
{
return new SynchronizedBoilerData();
}
@Override
public BoilerCache getNewCache()
{
return new BoilerCache();
}
@Override
protected BoilerUpdateProtocol getProtocol()
{
return new BoilerUpdateProtocol(this);
}
@Override
public MultiblockManager<SynchronizedBoilerData> getManager()
{
return Mekanism.boilerManager;
}
@Override
public ArrayList<Object> getNetworkedData(ArrayList<Object> data)
{
super.getNetworkedData(data);
if(structure != null)
{
data.add(structure.waterVolume*BoilerUpdateProtocol.WATER_PER_TANK);
data.add(structure.steamVolume*BoilerUpdateProtocol.STEAM_PER_TANK);
data.add(structure.lastEnvironmentLoss);
data.add(structure.lastBoilRate);
data.add(structure.superheatingElements);
data.add(structure.temperature);
data.add(structure.lastMaxBoil);
if(structure.waterStored != null)
{
data.add(1);
data.add(FluidRegistry.getFluidName(structure.waterStored));
data.add(structure.waterStored.amount);
}
else {
data.add(0);
}
if(structure.steamStored != null)
{
data.add(1);
data.add(FluidRegistry.getFluidName(structure.steamStored));
data.add(structure.steamStored.amount);
}
else {
data.add(0);
}
structure.upperRenderLocation.write(data);
if(isRendering)
{
data.add(structure.clientHot);
Set<ValveData> toSend = new HashSet<ValveData>();
for(ValveData valveData : structure.valves)
{
if(valveData.activeTicks > 0)
{
toSend.add(valveData);
}
}
data.add(toSend.size());
for(ValveData valveData : toSend)
{
valveData.location.write(data);
data.add(valveData.side.ordinal());
}
}
}
return data;
}
public int getScaledWaterLevel(int i)
{
if(clientWaterCapacity == 0 || structure.waterStored == null)
{
return 0;
}
return structure.waterStored.amount*i / clientWaterCapacity;
}
public int getScaledSteamLevel(int i)
{
if(clientSteamCapacity == 0 || structure.steamStored == null)
{
return 0;
}
return structure.steamStored.amount*i / clientSteamCapacity;
}
@Override
public void handlePacketData(ByteBuf dataStream)
{
super.handlePacketData(dataStream);
if(FMLCommonHandler.instance().getEffectiveSide().isClient())
{
if(clientHasStructure)
{
clientWaterCapacity = dataStream.readInt();
clientSteamCapacity = dataStream.readInt();
structure.lastEnvironmentLoss = dataStream.readDouble();
structure.lastBoilRate = dataStream.readInt();
structure.superheatingElements = dataStream.readInt();
structure.temperature = dataStream.readDouble();
structure.lastMaxBoil = dataStream.readInt();
if(dataStream.readInt() == 1)
{
structure.waterStored = new FluidStack(FluidRegistry.getFluid(PacketHandler.readString(dataStream)), dataStream.readInt());
}
else {
structure.waterStored = null;
}
if(dataStream.readInt() == 1)
{
structure.steamStored = new FluidStack(FluidRegistry.getFluid(PacketHandler.readString(dataStream)), dataStream.readInt());
}
else {
structure.steamStored = null;
}
structure.upperRenderLocation = Coord4D.read(dataStream);
if(isRendering)
{
structure.clientHot = dataStream.readBoolean();
SynchronizedBoilerData.clientHotMap.put(structure.inventoryID, structure.clientHot);
int size = dataStream.readInt();
valveViewing.clear();
for(int i = 0; i < size; i++)
{
ValveData data = new ValveData();
data.location = Coord4D.read(dataStream);
data.side = EnumFacing.getFront(dataStream.readInt());
valveViewing.add(data);
TileEntityBoilerCasing tileEntity = (TileEntityBoilerCasing)data.location.getTileEntity(worldObj);
if(tileEntity != null)
{
tileEntity.clientHasStructure = true;
}
}
}
}
}
}
@Override
public double getTemp()
{
return 0;
}
@Override
public double getInverseConductionCoefficient()
{
return SynchronizedBoilerData.CASING_INVERSE_CONDUCTION_COEFFICIENT;
}
@Override
public double getInsulationCoefficient(EnumFacing side)
{
return SynchronizedBoilerData.CASING_INSULATION_COEFFICIENT;
}
@Override
public void transferHeatTo(double heat)
{
if(structure != null)
{
structure.heatToAbsorb += heat;
}
}
@Override
public double[] simulateHeat()
{
return new double[] {0, 0};
}
@Override
public double applyTemperatureChange()
{
return 0;
}
@Override
public boolean canConnectHeat(EnumFacing side)
{
return structure != null;
}
@Override
public IHeatTransfer getAdjacent(EnumFacing side)
{
return null;
}
@Override
public boolean hasCapability(Capability<?> capability, EnumFacing side)
{
return capability == Capabilities.HEAT_TRANSFER_CAPABILITY || super.hasCapability(capability, side);
}
@Override
public <T> T getCapability(Capability<T> capability, EnumFacing side)
{
if(capability == Capabilities.HEAT_TRANSFER_CAPABILITY)
{
return (T)this;
}
return super.getCapability(capability, side);
}
@Override
public String getName()
{
return LangUtils.localize("gui.thermoelectricBoiler");
}
}