package joshie.harvest.core.base.tile;
import joshie.harvest.animals.packet.PacketClearNeighbours;
import joshie.harvest.api.animals.AnimalFoodType;
import joshie.harvest.core.helpers.MCServerHelper;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import javax.annotation.Nonnull;
import static net.minecraft.util.EnumFacing.*;
public abstract class TileFillableConnected<T extends TileFillableConnected> extends TileFillable {
private final int maxWidth;
private boolean facingX;
private int offsetX;
private int offsetZ;
private int size;
public TileFillableConnected(AnimalFoodType foodType, int maxFill, int fillPer, int maxWidth) {
super(foodType, maxFill, fillPer);
this.maxWidth = maxWidth;
}
@Override
protected T getTile() {
return getMaster();
}
@Override
public int getMaximumFill() {
return size * super.getMaximumFill();
}
public abstract void resetClientData();
@SuppressWarnings("unchecked")
public T getMaster() {
BlockPos connection = pos.add(offsetX, 0, offsetZ);
return isValidConnection(connection) ? (T) worldObj.getTileEntity(connection) : (T) this;
}
@SuppressWarnings("unchecked, ConstantConditions")
private boolean updateMasterInDirection(EnumFacing facing) {
BlockPos offset = pos.offset(facing);
if (isValidConnection(offset)) {
TileFillableConnected master = ((TileFillableConnected)worldObj.getTileEntity(offset)).getMaster();
if (master.getSize() < maxWidth) {
int offsetX = master.getPos().getX() - getPos().getX();
int offsetZ = master.getPos().getZ() - getPos().getZ();
if (offsetX != 0 && offsetZ != 0) return false;
if (master.size > 1) {
if (master.facingX && offsetX != 0) return false;
else if (!master.facingX && offsetZ != 0) return false;
}
if (offsetZ != 0) master.facingX = true;
if (offsetX != 0) master.facingX = false;
this.offsetX = offsetX;
this.offsetZ = offsetZ;
master.size++; //Increase the trough size
master.markDirty();
return true;
}
}
return false;
}
private void updateMaster() {
if (updateMasterInDirection(NORTH)) return;
if (updateMasterInDirection(SOUTH)) return;
if (updateMasterInDirection(EAST)) return;
if (!updateMasterInDirection(WEST)) {
//Make this block it's own master
offsetX = 0;
offsetZ = 0;
size = 1;
markDirty();
}
}
public void onPlaced() {
updateMaster();
setFilled(getFillAmount());
if (!worldObj.isRemote) {
MCServerHelper.sendTileUpdate(this, new PacketClearNeighbours(pos));
}
}
@SuppressWarnings("ConstantConditions")
private BlockPos getNewMaster() {
for (int x = -2; x <= 2; x++) {
for (int z = -2; z <= 2; z++) {
BlockPos offset = pos.add(x, 0, z);
if (isValidConnection(offset)) {
TileFillableConnected connected = ((TileFillableConnected)worldObj.getTileEntity(offset));
if (connected.getMaster() == this) {
return getPos().add(x, 0, z);
}
}
}
}
return null;
}
@SuppressWarnings("ConstantConditions")
private void setMaster(BlockPos pos) {
for (int x = -2; x <= 2; x++) {
for (int z = -2; z <= 2; z++) {
BlockPos offset = pos.add(x, 0, z);
if (isValidConnection(offset)) {
TileFillableConnected tile = ((TileFillableConnected)worldObj.getTileEntity(offset));
if (tile.getMaster() == this) {
tile.offsetX = pos.getX() - tile.getPos().getX();
tile.offsetZ = pos.getZ() - tile.getPos().getZ();
tile.updateMaster(); //Refresh the master status
tile.markDirty();
}
}
}
}
}
public void onRemoved() {
TileFillableConnected master = getMaster();
int volume = master.getFillAmount();
int size = Math.max(0, master.size - 1);
boolean facingX = master.facingX;
BlockPos newMaster = null;
if (master == this) {
newMaster = getNewMaster();
if (newMaster != null) {
setMaster(newMaster);
}
}
//Copy the contents from one tile to the next
master = newMaster != null ? (TileFillableConnected) worldObj.getTileEntity(newMaster) : master;
if (master != null) {
master.size = size;
master.facingX = facingX;
master.setFilled(volume); //Update the volume in the new master
master.markDirty();
master.resetClientData();
}
//Reset everything
if (!worldObj.isRemote) {
MCServerHelper.sendTileUpdate(this, new PacketClearNeighbours(pos));
}
}
protected abstract boolean isValidConnection(BlockPos pos);
public int getSize() {
return size;
}
@Override
public void readFromNBT(NBTTagCompound nbt) {
super.readFromNBT(nbt);
facingX = nbt.getBoolean("FacingX");
offsetX = nbt.getInteger("OffsetX");
offsetZ = nbt.getInteger("OffsetZ");
size = nbt.getByte("Size");
}
@Override
@Nonnull
public NBTTagCompound writeToNBT(NBTTagCompound nbt) {
nbt.setBoolean("FacingX", facingX);
nbt.setInteger("OffsetX", offsetX);
nbt.setInteger("OffsetZ", offsetZ);
nbt.setByte("Size", (byte) size);
return super.writeToNBT(nbt);
}
}