package crazypants.enderio.conduit.me;
import java.util.EnumSet;
import java.util.List;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.IIcon;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import appeng.api.AEApi;
import appeng.api.networking.IGridConnection;
import appeng.api.networking.IGridHost;
import appeng.api.networking.IGridNode;
import appeng.api.parts.IPart;
import appeng.api.parts.IPartHost;
import com.enderio.core.client.render.IconUtil;
import com.enderio.core.common.util.BlockCoord;
import cpw.mods.fml.common.Optional.Method;
import crazypants.enderio.EnderIO;
import crazypants.enderio.conduit.AbstractConduit;
import crazypants.enderio.conduit.AbstractConduitNetwork;
import crazypants.enderio.conduit.ConduitUtil;
import crazypants.enderio.conduit.ConnectionMode;
import crazypants.enderio.conduit.IConduit;
import crazypants.enderio.conduit.IConduitBundle;
import crazypants.enderio.conduit.RaytraceResult;
import crazypants.enderio.conduit.TileConduitBundle;
import crazypants.enderio.conduit.geom.CollidableComponent;
import crazypants.enderio.tool.ToolUtil;
public class MEConduit extends AbstractConduit implements IMEConduit {
protected MEConduitNetwork network;
protected MEConduitGrid grid;
public static IIcon[] coreTextures;
public static IIcon[] longTextures;
private boolean isDense;
private int playerID = -1;
public MEConduit() {
this(0);
}
public MEConduit(int itemDamage) {
isDense = itemDamage == 1;
}
public static void initIcons() {
IconUtil.addIconProvider(new IconUtil.IIconProvider() {
@Override
public void registerIcons(IIconRegister register) {
coreTextures = new IIcon[2];
longTextures = new IIcon[2];
coreTextures[0] = register.registerIcon(EnderIO.DOMAIN + ":meConduitCore");
coreTextures[1] = register.registerIcon(EnderIO.DOMAIN + ":meConduitCoreDense");
longTextures[0] = register.registerIcon(EnderIO.DOMAIN + ":meConduit");
longTextures[1] = register.registerIcon(EnderIO.DOMAIN + ":meConduitDense");
}
@Override
public int getTextureType() {
return 0;
}
});
}
public static int getDamageForState(boolean isDense) {
return isDense ? 1 : 0;
}
@Override
public Class<? extends IConduit> getBaseConduitType() {
return IMEConduit.class;
}
@Override
public ItemStack createItem() {
return new ItemStack(EnderIO.itemMEConduit, 1, getDamageForState(isDense));
}
@Override
public AbstractConduitNetwork<?, ?> getNetwork() {
return network;
}
@Override
public boolean setNetwork(AbstractConduitNetwork<?, ?> network) {
this.network = (MEConduitNetwork) network;
return true;
}
@Override
public void writeToNBT(NBTTagCompound nbtRoot) {
super.writeToNBT(nbtRoot);
nbtRoot.setBoolean("isDense", isDense);
nbtRoot.setInteger("playerID", playerID);
}
@Override
public void readFromNBT(NBTTagCompound nbtRoot, short nbtVersion) {
super.readFromNBT(nbtRoot, nbtVersion);
isDense = nbtRoot.getBoolean("isDense");
if(nbtRoot.hasKey("playerID")) {
playerID = nbtRoot.getInteger("playerID");
} else {
playerID = -1;
}
}
public void setPlayerID(int playerID) {
this.playerID = playerID;
}
@Override
public int getChannelsInUse() {
int channelsInUse = 0;
IGridNode node = getNode();
if(node != null) {
for (IGridConnection gc : node.getConnections()) {
channelsInUse = Math.max(channelsInUse, gc.getUsedChannels());
}
}
return channelsInUse;
}
@Override
@Method(modid = "appliedenergistics2")
public boolean canConnectToExternal(ForgeDirection dir, boolean ignoreDisabled) {
World world = getBundle().getWorld();
BlockCoord pos = getLocation();
TileEntity te = world.getTileEntity(pos.x + dir.offsetX, pos.y + dir.offsetY, pos.z + dir.offsetZ);
if(te instanceof TileConduitBundle) {
return false;
}
// because the AE2 API doesn't allow an easy query like "which side can connect to an ME cable" it needs this mess
if(te instanceof IPartHost) {
IPart part = ((IPartHost) te).getPart(dir.getOpposite());
if(part == null) {
part = ((IPartHost) te).getPart(ForgeDirection.UNKNOWN);
return part != null;
}
if(part.getExternalFacingNode() != null) {
return true;
}
String name = part.getClass().getSimpleName();
return "PartP2PTunnelME".equals(name) || "PartQuartzFiber".endsWith(name) ||
"PartToggleBus".equals(name) || "PartInvertedToggleBus".equals(name);
} else if(te instanceof IGridHost) {
IGridNode node = ((IGridHost) te).getGridNode(dir.getOpposite());
if(node == null) {
node = ((IGridHost) te).getGridNode(ForgeDirection.UNKNOWN);
}
if(node != null) {
return node.getGridBlock().getConnectableSides().contains(dir.getOpposite());
}
}
return false;
}
@Override
public IIcon getTextureForState(CollidableComponent component) {
int state = getDamageForState(isDense);
if(component.dir == ForgeDirection.UNKNOWN) {
return coreTextures[state];
} else {
return longTextures[state];
}
}
@Override
public IIcon getTransmitionTextureForState(CollidableComponent component) {
return null;
}
@Override
@Method(modid = "appliedenergistics2")
public void updateEntity(World worldObj) {
if(grid == null) {
grid = new MEConduitGrid(this);
}
if(getNode() == null && !worldObj.isRemote) {
IGridNode node = AEApi.instance().createGridNode(grid);
if(node != null) {
node.setPlayerID(playerID);
getBundle().setGridNode(node);
getNode().updateState();
}
}
super.updateEntity(worldObj);
}
@Override
public ConnectionMode getNextConnectionMode(ForgeDirection dir) {
ConnectionMode mode = getConnectionMode(dir);
mode = mode == ConnectionMode.IN_OUT ? ConnectionMode.DISABLED : ConnectionMode.IN_OUT;
return mode;
}
@Override
public ConnectionMode getPreviousConnectionMode(ForgeDirection dir) {
return getNextConnectionMode(dir);
}
@Override
public boolean canConnectToConduit(ForgeDirection direction, IConduit conduit) {
if(!super.canConnectToConduit(direction, conduit)) {
return false;
}
return conduit instanceof IMEConduit;
}
@Override
@Method(modid = "appliedenergistics2")
public void connectionsChanged() {
super.connectionsChanged();
BlockCoord loc = getLocation();
if(loc != null) {
onNodeChanged(loc);
IGridNode node = getNode();
if(node != null) {
node.updateState();
node.getWorld().markBlockForUpdate(loc.x, loc.y, loc.z);
}
}
}
@Override
public boolean onBlockActivated(EntityPlayer player, RaytraceResult res, List<RaytraceResult> all) {
if(ToolUtil.isToolEquipped(player)) {
if(!getBundle().getEntity().getWorldObj().isRemote) {
if(res != null && res.component != null) {
ForgeDirection connDir = res.component.dir;
ForgeDirection faceHit = ForgeDirection.getOrientation(res.movingObjectPosition.sideHit);
if(connDir == ForgeDirection.UNKNOWN || connDir == faceHit) {
if(getConnectionMode(faceHit) == ConnectionMode.DISABLED) {
setConnectionMode(faceHit, ConnectionMode.IN_OUT);
return true;
}
return ConduitUtil.joinConduits(this, faceHit);
} else if(externalConnections.contains(connDir)) {
setConnectionMode(connDir, getNextConnectionMode(connDir));
return true;
} else if(containsConduitConnection(connDir)) {
ConduitUtil.disconectConduits(this, connDir);
return true;
}
}
}
}
return false;
}
@Method(modid = "appliedenergistics2")
private void onNodeChanged(BlockCoord location) {
World world = getBundle().getWorld();
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
TileEntity te = location.getLocation(dir).getTileEntity(world);
if(te != null && te instanceof IGridHost && !(te instanceof IConduitBundle)) {
IGridNode node = ((IGridHost) te).getGridNode(ForgeDirection.UNKNOWN);
if(node == null) {
node = ((IGridHost) te).getGridNode(dir.getOpposite());
}
if(node != null) {
node.updateState();
}
}
}
}
@Override
public void onAddedToBundle() {
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
TileEntity te = getLocation().getLocation(dir).getTileEntity(getBundle().getWorld());
if(te instanceof TileConduitBundle) {
IMEConduit cond = ((TileConduitBundle) te).getConduit(IMEConduit.class);
if(cond != null) {
cond.setConnectionMode(dir.getOpposite(), ConnectionMode.IN_OUT);
ConduitUtil.joinConduits(cond, dir.getOpposite());
}
}
}
}
@Override
@Method(modid = "appliedenergistics2")
public void onRemovedFromBundle() {
super.onRemovedFromBundle();
getNode().destroy();
getBundle().setGridNode(null);
}
@Override
@Method(modid = "appliedenergistics2")
public void onChunkUnload(World worldObj) {
super.onChunkUnload(worldObj);
if(getNode() != null) {
getNode().destroy();
getBundle().setGridNode(null);
}
}
@Override
public MEConduitGrid getGrid() {
return grid;
}
@Method(modid = "appliedenergistics2")
private IGridNode getNode() {
return getBundle().getGridNode(null);
}
@Override
public EnumSet<ForgeDirection> getConnections() {
EnumSet<ForgeDirection> cons = EnumSet.noneOf(ForgeDirection.class);
cons.addAll(getConduitConnections());
for(ForgeDirection dir : getExternalConnections()) {
if(getConnectionMode(dir) != ConnectionMode.DISABLED) {
cons.add(dir);
}
}
return cons;
}
@Override
public boolean isDense() {
return isDense;
}
}