package mcjty.deepresonance.blocks.tank;
import com.google.common.collect.Maps;
import elec332.core.main.ElecCore;
import elec332.core.multiblock.dynamic.IDynamicMultiBlockTile;
import elec332.core.world.WorldHelper;
import mcjty.deepresonance.DeepResonance;
import mcjty.deepresonance.api.fluid.IDeepResonanceFluidAcceptor;
import mcjty.deepresonance.api.fluid.IDeepResonanceFluidProvider;
import mcjty.deepresonance.blocks.base.ElecTileBase;
import mcjty.deepresonance.grid.tank.DRTankMultiBlock;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.IStringSerializable;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fluids.*;
import java.util.Map;
/**
* Created by Elec332 on 9-8-2015.
*/
public class TileTank extends ElecTileBase implements IDynamicMultiBlockTile<DRTankMultiBlock>, IFluidHandler, IDeepResonanceFluidAcceptor, IDeepResonanceFluidProvider {
public TileTank(){
super();
this.settings = Maps.newHashMap();
for (EnumFacing direction : EnumFacing.VALUES){
settings.put(direction, Mode.SETTING_NONE);
}
this.multiBlockSaveData = new NBTTagCompound();
this.tankHooks = Maps.newHashMap();
}
private Fluid clientRenderFluid;
// Client only
private float renderHeight; //Value from 0.0f to 1.0f
private NBTTagCompound multiBlockSaveData;
protected Map<EnumFacing, Mode> settings;
private Map<EnumFacing, ITankHook> tankHooks;
public static enum Mode implements IStringSerializable {
SETTING_NONE("none"),
SETTING_ACCEPT("accept"), // Blue
SETTING_PROVIDE("provide"); // Yellow
private final String name;
Mode(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
@Override
public void onTileLoaded() {
super.onTileLoaded();
if (!worldObj.isRemote) {
DeepResonance.worldGridRegistry.getTankRegistry().get(worldObj).addTile(this);
//MinecraftForge.EVENT_BUS.post(new FluidTileEvent.Load(this));
initHooks();
}
}
@Override
public void onTileUnloaded() {
super.onTileUnloaded();
if (!worldObj.isRemote) {
DeepResonance.worldGridRegistry.getTankRegistry().get(worldObj).removeTile(this);
//MinecraftForge.EVENT_BUS.post(new FluidTileEvent.Unload(this));
for (Map.Entry<EnumFacing, ITankHook> entry : getConnectedHooks().entrySet()){
entry.getValue().unHook(this, entry.getKey().getOpposite());
}
getConnectedHooks().clear();
}
}
public void onNeighborChange(){
Map<EnumFacing, ITankHook> hookMap = getConnectedHooks();
for (EnumFacing facing : EnumFacing.VALUES){
ITankHook tankHook = hookMap.get(facing);
BlockPos pos = getPos().offset(facing);
TileEntity tile = WorldHelper.chunkLoaded(worldObj, pos) ? WorldHelper.getTileAt(worldObj, pos) : null;
if ((tile == null && tankHook != null) || (tile != null && tankHook == null) || (tile != tankHook)){
hookMap.remove(facing);
if (tile instanceof ITankHook){
((ITankHook) tile).hook(this, facing.getOpposite());
hookMap.put(facing, (ITankHook) tile);
}
} else if (tankHook != null){
tankHook.onContentChanged(this, facing.getOpposite());
}
}
}
private void initHooks(){
tankHooks.clear();
for (EnumFacing facing : EnumFacing.VALUES){
BlockPos pos = getPos().offset(facing);
TileEntity tile = WorldHelper.chunkLoaded(worldObj, pos) ? WorldHelper.getTileAt(worldObj, pos) : null;
if (tile instanceof ITankHook){
tankHooks.put(facing, (ITankHook) tile);
((ITankHook) tile).hook(this, facing.getOpposite());
}
}
}
private DRTankMultiBlock multiBlock;
public FluidStack myTank;
public Fluid lastSeenFluid;
public Map<EnumFacing, Mode> getSettings() {
return settings;
}
@Override
public void readFromNBT(NBTTagCompound tagCompound) {
super.readFromNBT(tagCompound);
NBTTagList tagList = tagCompound.getTagList("settings", Constants.NBT.TAG_COMPOUND);
if (tagList != null){
for (int i = 0; i < tagList.tagCount(); i++) {
NBTTagCompound tag = tagList.getCompoundTagAt(i);
EnumFacing side = EnumFacing.values()[tag.getInteger("dir")];
Mode mode = Mode.values()[tag.getInteger("n")];
settings.put(side, mode);
}
}
}
@Override
public void writeToNBT(NBTTagCompound tagCompound) {
super.writeToNBT(tagCompound);
NBTTagList tagList = new NBTTagList();
for (Map.Entry<EnumFacing, Mode> entry : settings.entrySet()){
NBTTagCompound tag = new NBTTagCompound();
tag.setInteger("dir", entry.getKey().ordinal());
tag.setInteger("n", entry.getValue().ordinal());
tagList.appendTag(tag);
}
tagCompound.setTag("settings", tagList);
}
@Override
public void readRestorableFromNBT(NBTTagCompound tagCompound) {
super.readRestorableFromNBT(tagCompound);
this.myTank = getFluidStackFromNBT(tagCompound);
multiBlockSaveData = tagCompound.getCompoundTag("multiBlockData");
if (tagCompound.hasKey("lastSeenFluid")) { /* legacy compat */
this.lastSeenFluid = FluidRegistry.getFluid(tagCompound.getString("lastSeenFluid"));
} else if (multiBlockSaveData.hasKey("lastSeenFluid")){
this.lastSeenFluid = FluidRegistry.getFluid(multiBlockSaveData.getString("lastSeenFluid"));
}
}
public static FluidStack getFluidStackFromNBT(NBTTagCompound tagCompound) {
NBTTagCompound mbTag = tagCompound.getCompoundTag("multiBlockData");
FluidStack s;
if (tagCompound.hasKey("fluid")) { /* legacy compat */
s = FluidStack.loadFluidStackFromNBT(tagCompound.getCompoundTag("fluid"));
} else if (mbTag.hasKey("fluid")){
s = FluidStack.loadFluidStackFromNBT(mbTag.getCompoundTag("fluid"));
} else {
s = null;
}
return s;
}
@Override
public void writeRestorableToNBT(NBTTagCompound tagCompound) {
super.writeRestorableToNBT(tagCompound);
if (multiBlock != null) {
getMultiBlock().setDataToTile(this);
}
ElecCore.systemPrintDebug("Writing restorable NBT @ " + pos);
tagCompound.setTag("multiBlockData", multiBlockSaveData);
}
@Override
public void setMultiBlock(DRTankMultiBlock multiBlock) {
this.multiBlock = multiBlock;
}
@Override
public DRTankMultiBlock getMultiBlock() {
return multiBlock;
}
@Override
public void setSaveData(NBTTagCompound nbtTagCompound) {
ElecCore.systemPrintDebug("Setting MB save data @ " + pos);
this.multiBlockSaveData = nbtTagCompound;
}
@Override
public NBTTagCompound getSaveData() {
return this.multiBlockSaveData;
}
@Override
public int fill(EnumFacing from, FluidStack resource, boolean doFill) {
if (!isInput(from))
return 0;
notifyChanges(doFill);
return multiBlock == null ? 0 : multiBlock.fill(from, resource, doFill);
}
@Override
public FluidStack drain(EnumFacing from, FluidStack resource, boolean doDrain) {
if (!isOutput(from))
return null;
notifyChanges(doDrain);
return multiBlock == null ? null : multiBlock.drain(from, resource, doDrain);
}
@Override
public FluidStack drain(EnumFacing from, int maxDrain, boolean doDrain) {
if (!isOutput(from))
return null;
notifyChanges(doDrain);
return multiBlock == null ? null : multiBlock.drain(from, maxDrain, doDrain);
}
@Override
public boolean canFill(EnumFacing from, Fluid fluid) {
return isInput(from) && multiBlock != null && multiBlock.canFill(from, fluid);
}
@Override
public boolean canDrain(EnumFacing from, Fluid fluid) {
return isOutput(from) && multiBlock != null && multiBlock.canDrain(from, fluid);
}
@Override
public FluidTankInfo[] getTankInfo(EnumFacing from) {
return multiBlock == null ? new FluidTankInfo[0] : multiBlock.getTankInfo(from);
}
@Override
public boolean canAcceptFrom(EnumFacing direction) {
return isInput(direction);
}
@Override
public boolean canProvideTo(EnumFacing direction) {
return isOutput(direction);
}
@Override
public FluidStack getProvidedFluid(int maxProvided, EnumFacing from) {
if (!isOutput(from))
return null;
return getMultiBlock() == null ? null : getMultiBlock().drain(maxProvided, true);
}
@Override
public int getRequestedAmount(EnumFacing from) {
if (!isInput(from))
return 0;
return multiBlock == null ? 0 : Math.min(multiBlock.getFreeSpace(), 1000);
}
@Override
public FluidStack acceptFluid(FluidStack fluidStack, EnumFacing from) {
if (!isInput(from)) {
fill(from, fluidStack, true);
notifyChanges(true);
return null;
} else {
return fluidStack;
}
}
public Fluid getClientRenderFluid() {
return clientRenderFluid;
}
// Client only
public float getRenderHeight() {
return renderHeight;
}
public FluidStack getFluid() {
return multiBlock == null ? null : multiBlock.getFluid();
}
public NBTTagCompound getFluidTag() {
return getFluid() == null ? null : getFluid().tag;
}
public int getFluidAmount() {
return multiBlock == null ? 0 : multiBlock.getFluidAmount();
}
public int getCapacity() {
return multiBlock == null ? 0 : multiBlock.getCapacity();
}
private void notifyChanges(boolean b){
if (multiBlock != null && b){
for (Map.Entry<EnumFacing, ITankHook> entry : getConnectedHooks().entrySet()){
entry.getValue().onContentChanged(this, entry.getKey().getOpposite());
}
}
}
private Map<EnumFacing, ITankHook> getConnectedHooks(){
/*Map<ITankHook, EnumFacing> ret = Maps.newHashMap();
for (EnumFacing direction : EnumFacing.VALUES){
try {
TileEntity tile = WorldHelper.getTileAt(worldObj, getPos().offset(direction));
if (tile instanceof ITankHook)
ret.put((ITankHook) tile, direction.getOpposite());
} catch (Exception e){
e.printStackTrace();
}
}
return ret;*/
return tankHooks;
}
public boolean isInput(EnumFacing direction){
return direction == null || settings.get(direction) == Mode.SETTING_ACCEPT;
}
public boolean isOutput(EnumFacing direction){
return direction == null || settings.get(direction) == Mode.SETTING_PROVIDE;
}
@Override
public void onDataPacket(int id, NBTTagCompound tag) {
switch (id){
case 1:
this.clientRenderFluid = FluidRegistry.getFluid(tag.getString("fluid"));
return;
case 2:
return;
case 3:
this.renderHeight = tag.getFloat("render");
}
}
}