package advancedsystemsmanager.tileentities;
import advancedsystemsmanager.AdvancedSystemsManager;
import advancedsystemsmanager.helpers.BlockHelper;
import advancedsystemsmanager.helpers.SavableData;
import advancedsystemsmanager.network.ASMPacket;
import advancedsystemsmanager.network.PacketHandler;
import advancedsystemsmanager.reference.Reference;
import advancedsystemsmanager.util.SystemCoord;
import gnu.trove.map.hash.TIntObjectHashMap;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.Packet;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraft.world.WorldSavedData;
import net.minecraftforge.common.DimensionManager;
public class TileEntityQuantumCable extends TileEntityElementBase
{
public static final String NBT_QUANTUM_KEY = "quantumKey";
public static final String NBT_QUANTUM_RANGE = "quantumRange";
private static final QuantumSave NEXT_QUANTUM_KEY;
private static TIntObjectHashMap<TileEntityQuantumCable> quantumRegistry = new TIntObjectHashMap<TileEntityQuantumCable>();
private int quantumKey;
private int quantumRange;
private TileEntityQuantumCable pair;
static
{
AdvancedSystemsManager.worldSave.save(NEXT_QUANTUM_KEY = new QuantumSave());
}
public static int getNextQuantumKey()
{
return NEXT_QUANTUM_KEY.getNextID();
}
public static int peekNextQuantumKey()
{
return NEXT_QUANTUM_KEY.peekNextID();
}
@Override
public void writeItemNBT(NBTTagCompound tag)
{
super.writeItemNBT(tag);
tag.setInteger(NBT_QUANTUM_KEY, quantumKey);
tag.setInteger(NBT_QUANTUM_RANGE, quantumRange);
}
@Override
public void readItemNBT(NBTTagCompound tag)
{
super.readItemNBT(tag);
quantumRange = tag.getInteger(NBT_QUANTUM_RANGE);
setQuantumKey(tag.getInteger(NBT_QUANTUM_KEY));
setMessageType(1);
}
private boolean isInRange(TileEntityQuantumCable paired)
{
return (isInterDimensional() && paired.hasWorldObj() && paired.getWorldObj().provider.dimensionId != getWorldObj().provider.dimensionId) ||
(getRange(quantumRange) * getRange(quantumRange) >= getDistanceFrom(paired.xCoord + 0.5d, paired.yCoord + 0.5d, paired.zCoord + 0.5d));
}
public int getQuantumRange()
{
return getRange(quantumRange);
}
public static int getRange(int quantumRange)
{
return quantumRange * quantumRange + 5;
}
public boolean isInterDimensional()
{
return quantumRange == 9;
}
public static TileEntityQuantumCable getPairedCable(TileEntityQuantumCable cable)
{
TileEntityQuantumCable paired = cable.pair;
if (paired != null && !paired.isInvalid() && paired.hasWorldObj() && paired.getWorldObj().blockExists(paired.xCoord, paired.yCoord, paired.zCoord) && paired.isInRange(cable))
{
return paired;
}
return null;
}
public void pairWith(TileEntityQuantumCable pair)
{
if (pair != this && this.pair != pair)
{
this.pair = pair;
pair.pair = this;
if (!worldObj.isRemote)
{
BlockHelper.updateInventories(new SystemCoord(xCoord, yCoord, zCoord, worldObj));
quantumRegistry.remove(getQuantumKey());
setMessageType(2);
pair.setMessageType(2);
}
}
}
public static void addCable(TileEntityQuantumCable cable)
{
if (quantumRegistry.containsKey(cable.getQuantumKey()))
{
quantumRegistry.get(cable.getQuantumKey()).pairWith(cable);
} else
{
quantumRegistry.put(cable.getQuantumKey(), cable);
}
}
public void setQuantumKey(int key)
{
quantumKey = key;
addCable(this);
}
@Override
public void validate()
{
super.validate();
}
@Override
public void invalidate()
{
unloadPairing();
super.invalidate();
}
@Override
public void onChunkUnload()
{
unloadPairing();
super.onChunkUnload();
}
public void unloadPairing()
{
if (!worldObj.isRemote)
{
if (pair != null && !pair.isInvalid())
{
pair.pair = null;
addCable(pair);
pair.setMessageType(2);
BlockHelper.updateInventories(new SystemCoord(pair.xCoord, pair.yCoord, pair.zCoord, pair.worldObj));
}else
{
quantumRegistry.remove(getQuantumKey());
}
}
}
@Override
public boolean equals(Object obj)
{
if (obj instanceof TileEntityQuantumCable)
{
TileEntityQuantumCable other = (TileEntityQuantumCable) obj;
return other.xCoord == xCoord && other.yCoord == yCoord && other.zCoord == zCoord && other.quantumKey == quantumKey;
}
return false;
}
public int getQuantumKey()
{
return quantumKey;
}
private static final char[] SPIN = "UDSCTB".toCharArray();
public String getSpinString()
{
return getSpinString(quantumKey);
}
public static String getSpinString(int key)
{
String result = "";
while (key != 0)
{
result = SPIN[key % SPIN.length] + result;
key /= SPIN.length;
}
return result;
}
public static void clearRegistry()
{
quantumRegistry.clear();
}
@Override
public void readClientSyncData(ASMPacket packet)
{
super.readClientSyncData(packet);
quantumRange = packet.readByte();
quantumKey = packet.readVarIntFromBuffer();
if (packet.readBoolean())
{
World world = DimensionManager.getWorld(packet.readShort());
TileEntity te = world.getTileEntity(packet.readInt(), packet.readUnsignedByte(), packet.readInt());
if (te instanceof TileEntityQuantumCable)
{
pair = (TileEntityQuantumCable)te;
((TileEntityQuantumCable) te).pair = this;
}
} else
{
pair = null;
}
}
@Override
public void writeClientSyncData(ASMPacket packet)
{
super.writeClientSyncData(packet);
packet.writeByte(quantumRange);
packet.writeVarIntToBuffer(quantumKey);
if (pair != null && pair.worldObj != null)
{
packet.writeBoolean(true);
packet.writeShort(pair.worldObj.provider.dimensionId);
packet.writeInt(pair.xCoord);
packet.writeByte(pair.yCoord);
packet.writeInt(pair.zCoord);
} else
{
packet.writeBoolean(false);
}
}
public static class QuantumSave extends SavableData
{
private static final String KEY = "quantumSave";
private int ID = 0;
public QuantumSave(String key)
{
super(key);
}
@Override
protected SavableData getNew()
{
return new QuantumSave();
}
public QuantumSave()
{
this(Reference.NETWORK_ID + "." + KEY);
}
@Override
public boolean copyFrom(WorldSavedData worldSavedData)
{
if (worldSavedData instanceof QuantumSave)
{
ID = ((QuantumSave) worldSavedData).ID;
return true;
}
return false;
}
@Override
public void readFromNBT(NBTTagCompound tag)
{
ID = tag.getInteger(KEY);
}
@Override
public void writeToNBT(NBTTagCompound tag)
{
tag.setInteger(KEY, ID);
}
public int getNextID()
{
markDirty();
return ++ID;
}
public int peekNextID()
{
return ID+1;
}
}
}