package blusunrize.immersiveengineering.common.blocks.metal;
import blusunrize.immersiveengineering.api.Lib;
import blusunrize.immersiveengineering.api.TargetingInfo;
import blusunrize.immersiveengineering.api.energy.wires.IImmersiveConnectable;
import blusunrize.immersiveengineering.api.energy.wires.ImmersiveNetHandler;
import blusunrize.immersiveengineering.api.energy.wires.ImmersiveNetHandler.Connection;
import blusunrize.immersiveengineering.api.energy.wires.TileEntityImmersiveConnectable;
import blusunrize.immersiveengineering.api.energy.wires.WireType;
import blusunrize.immersiveengineering.api.energy.wires.redstone.IRedstoneConnector;
import blusunrize.immersiveengineering.api.energy.wires.redstone.RedstoneWireNetwork;
import blusunrize.immersiveengineering.client.models.IOBJModelCallback;
import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.*;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumDyeColor;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ITickable;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class TileEntityConnectorRedstone extends TileEntityImmersiveConnectable implements ITickable, IDirectionalTile, IRedstoneOutput, IHammerInteraction, IBlockBounds, IBlockOverlayText, IOBJModelCallback<IBlockState>, IRedstoneConnector
{
public EnumFacing facing = EnumFacing.DOWN;
public int ioMode = 0; // 0 - input, 1 -output
public int redstoneChannel = 0;
public boolean rsDirty = false;
private RedstoneWireNetwork wireNetwork = new RedstoneWireNetwork().add(this);
private boolean loaded = false;
@Override
public void update()
{
if(hasWorldObj() && !worldObj.isRemote && !loaded)
{
loaded = true;
wireNetwork.removeFromNetwork(null);
}
if (hasWorldObj() && !worldObj.isRemote && rsDirty)
wireNetwork.updateValues();
}
@Override
public int getStrongRSOutput(IBlockState state, EnumFacing side)
{
if(!isRSOutput() || side != this.facing.getOpposite())
return 0;
return wireNetwork != null ? wireNetwork.getPowerOutput(redstoneChannel) : 0;
}
@Override
public int getWeakRSOutput(IBlockState state, EnumFacing side)
{
if(!isRSOutput())
return 0;
return wireNetwork != null ? wireNetwork.getPowerOutput(redstoneChannel) : 0;
}
@Override
public boolean canConnectRedstone(IBlockState state, EnumFacing side)
{
return false;
}
@Override
public void setNetwork(RedstoneWireNetwork net)
{
wireNetwork = net;
}
@Override
public RedstoneWireNetwork getNetwork()
{
return wireNetwork;
}
@Override
public void onChange()
{
if (!isInvalid() && isRSOutput())
{
markContainingBlockForUpdate(null);
markBlockForUpdate(pos.offset(facing), null);
}
}
@Override
public World getConnectorWorld()
{
return getWorld();
}
public boolean isRSInput()
{
return ioMode == 0;
}
@Override
public void updateInput(byte[] signals)
{
if (isRSInput())
{
int val = worldObj.isBlockIndirectlyGettingPowered(pos);
signals[redstoneChannel] = (byte) Math.max(val, signals[redstoneChannel]);
}
rsDirty = false;
}
public boolean isRSOutput()
{
return ioMode == 1;
}
@Override
public boolean hammerUseSide(EnumFacing side, EntityPlayer player, float hitX, float hitY, float hitZ)
{
//Sneaking iterates through colours, normal hammerign toggles in and out
if(player.isSneaking())
redstoneChannel = (redstoneChannel + 1) % 16;
else
ioMode = ioMode == 0 ? 1 : 0;
markDirty();
wireNetwork.updateValues();
onChange();
worldObj.addBlockEvent(getPos(), this.getBlockType(), 254, 0);
return true;
}
@Override
public boolean canConnectCable(WireType cableType, TargetingInfo target)
{
if(cableType != WireType.REDSTONE)
return false;
return limitType == null || limitType == cableType;
}
@Override
public void connectCable(WireType cableType, TargetingInfo target, IImmersiveConnectable other)
{
super.connectCable(cableType, target, other);
if(other instanceof IRedstoneConnector)
if(((IRedstoneConnector) other).getNetwork() != wireNetwork)
wireNetwork.mergeNetwork(((IRedstoneConnector) other).getNetwork());
}
@Override
public void removeCable(ImmersiveNetHandler.Connection connection)
{
super.removeCable(connection);
wireNetwork.removeFromNetwork(this);
}
@Override
public EnumFacing getFacing()
{
return this.facing;
}
@Override
public void setFacing(EnumFacing facing)
{
this.facing = facing;
}
@Override
public int getFacingLimitation()
{
return 0;
}
@Override
public boolean mirrorFacingOnPlacement(EntityLivingBase placer)
{
return true;
}
@Override
public boolean canHammerRotate(EnumFacing side, float hitX, float hitY, float hitZ, EntityLivingBase entity)
{
return false;
}
@Override
public boolean canRotate(EnumFacing axis)
{
return false;
}
@Override
public void writeCustomNBT(NBTTagCompound nbt, boolean descPacket)
{
super.writeCustomNBT(nbt, descPacket);
nbt.setInteger("facing", facing.ordinal());
nbt.setInteger("ioMode", ioMode);
nbt.setInteger("redstoneChannel", redstoneChannel);
}
@Override
public void readCustomNBT(NBTTagCompound nbt, boolean descPacket)
{
super.readCustomNBT(nbt, descPacket);
facing = EnumFacing.getFront(nbt.getInteger("facing"));
ioMode = nbt.getInteger("ioMode");
redstoneChannel = nbt.getInteger("redstoneChannel");
}
@Override
public Vec3d getRaytraceOffset(IImmersiveConnectable link)
{
EnumFacing side = facing.getOpposite();
return new Vec3d(.5 + side.getFrontOffsetX() * .0625, .5 + side.getFrontOffsetY() * .0625, .5 + side.getFrontOffsetZ() * .0625);
}
@Override
public Vec3d getConnectionOffset(Connection con)
{
EnumFacing side = facing.getOpposite();
double conRadius = con.cableType.getRenderDiameter() / 2;
return new Vec3d(.5 - conRadius * side.getFrontOffsetX(), .5 - conRadius * side.getFrontOffsetY(), .5 - conRadius * side.getFrontOffsetZ());
}
@SideOnly(Side.CLIENT)
private AxisAlignedBB renderAABB;
@SideOnly(Side.CLIENT)
@Override
public AxisAlignedBB getRenderBoundingBox()
{
int inc = getRenderRadiusIncrease();
return new AxisAlignedBB(this.pos.getX() - inc, this.pos.getY() - inc, this.pos.getZ() - inc, this.pos.getX() + inc + 1, this.pos.getY() + inc + 1, this.pos.getZ() + inc + 1);
}
int getRenderRadiusIncrease()
{
return WireType.REDSTONE.getMaxLength();
}
@Override
public float[] getBlockBounds()
{
float length = .625f;
float wMin = .3125f;
float wMax = .6875f;
switch(facing.getOpposite())
{
case UP:
return new float[]{wMin, 0, wMin, wMax, length, wMax};
case DOWN:
return new float[]{wMin, 1 - length, wMin, wMax, 1, wMax};
case SOUTH:
return new float[]{wMin, wMin, 0, wMax, wMax, length};
case NORTH:
return new float[]{wMin, wMin, 1 - length, wMax, wMax, 1};
case EAST:
return new float[]{0, wMin, wMin, length, wMax, wMax};
case WEST:
return new float[]{1 - length, wMin, wMin, 1, wMax, wMax};
}
return new float[]{0, 0, 0, 1, 1, 1};
}
@SideOnly(Side.CLIENT)
@Override
public TextureAtlasSprite getTextureReplacement(IBlockState object, String material)
{
return null;
}
@SideOnly(Side.CLIENT)
@Override
public boolean shouldRenderGroup(IBlockState object, String group)
{
if("io_out".equals(group))
return this.ioMode == 1;
else if("io_in".equals(group))
return this.ioMode == 0;
return true;
}
@SideOnly(Side.CLIENT)
@Override
public int getRenderColour(IBlockState object, String group)
{
if("coloured".equals(group))
return 0xff000000|EnumDyeColor.byMetadata(this.redstoneChannel).getMapColor().colorValue;
return 0xffffffff;
}
@Override
public String getCacheKey(IBlockState object)
{
return redstoneChannel+";"+ioMode;
}
@Override
public String[] getOverlayText(EntityPlayer player, RayTraceResult mop, boolean hammer)
{
if(!hammer)
return null;
return new String[]{
I18n.format(Lib.DESC_INFO + "redstoneChannel", I18n.format("item.fireworksCharge." + EnumDyeColor.byMetadata(redstoneChannel).getUnlocalizedName())),
I18n.format(Lib.DESC_INFO + "blockSide.io." + this.ioMode)
};
}
@Override
public boolean useNixieFont(EntityPlayer player, RayTraceResult mop)
{
return false;
}
}