public interface SubGui {
	public void onClose();
	public void onOpen();
	public void renderBackground();
	public void renderForeground();
	public void actionPerformed (GuiButton button);
} public class ChannelButton extends GuiButton {
	public enum TYPES {INACTIVE, ON, OFF, EDIT};
	private boolean output;
	private TYPES type;
	private int idx;
	
	public ChannelButton(int par1, int par2, int par3, TYPES type, int idx, boolean output) {
		super(par1, par2, par3,8,8, null);
		this.type = type;
		this.idx = idx;
		this.output = output;
		this.width = 5;
		this.height = 3;
	}
	
	
	
	@Override
	public void drawButton(Minecraft par1Minecraft, int par2, int par3)
    {
        if (this.drawButton)
        {
            FontRenderer var4 = par1Minecraft.fontRenderer;
            GL11.glBindTexture(GL11.GL_TEXTURE_2D, par1Minecraft.renderEngine.getTexture("/ressources/art/gui/extender.png"));
            GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
            this.field_82253_i = par2 >= this.xPosition && par3 >= this.yPosition && par2 < this.xPosition + this.width && par3 < this.yPosition + this.height;
            int var5 = this.getHoverState(this.field_82253_i);
            
            int textureposx = 176;
            int textureposy = 4;
            
            if (idx % 5 == 0)
            	textureposy = 2;
            
            if (idx % 10 == 0)
            	textureposy = 0;
            
            
            textureposx += type.ordinal()*4;
            if (output)
            	textureposx += 16;
            
            this.drawTexturedModalRect(this.xPosition, this.yPosition,  textureposx,textureposy, 4, 2);
            this.mouseDragged(par1Minecraft, par2, par3);
           
        }
    }



	public TYPES getType() {
		return type;
	}



	public void setType(TYPES type) {
		this.type = type;
	}



	public int getIdx() {
		return idx;
	}



	public void setIdx(int idx) {
		this.idx = idx;
	}



	public boolean isOutput() {
		return output;
	}



	
} public class TextButton extends GuiButton {
	private String text;
	private boolean active;
	private int data = -1;
	public TextButton(int par1, int x, int y, String text, boolean active) {
		super(par1, x, y, 6*text.length(), 10, null);
		this.text = text;
		this.active = active;
		
	}
	public TextButton(int par1, int x, int y, String text, int data, boolean active) {
		super(par1, x, y, 6*text.length(), 10, null);
		this.text = text;
		this.active = active;
		this.data = data;
		
	}
	
	
	@Override
	public void drawButton(Minecraft par1Minecraft, int par2, int par3)
    {
        if (this.drawButton)
        {
            FontRenderer var4 = par1Minecraft.fontRenderer;
            
            
            
           this.mouseDragged(par1Minecraft, par2, par3);
            int var6 = 0xFF0000;

            if (!active)
            {
            	var6 = 0x000000;
               // var6 = -6250336;
            }
            else if (this.field_82253_i)
            {
            	var6 = 0xFF00FF;
                //var6 = 16777120;
            }

            //this.drawCenteredString(var4, this.text, this.xPosition + this.width / 2, this.yPosition + (this.height - 8) / 2, var6);
           var4.drawString(text,  this.xPosition,  this.yPosition, var6);
          
        }
    }



	public String getText() {
		return text;
	}



	public void setText(String text) {
		this.text = text;
	}



	public boolean isActive() {
		return active;
	}



	public void setActive(boolean active) {
		this.active = active;
	}
	public int getData() {
		return data;
	}
	public void setData(int data) {
		this.data = data;
	}
	
	
} public class TouchButton extends GuiButton {
	public enum TYPES {UP, DOWN, LEFT, RIGHT, TRIGGER};
	private TYPES type;
	private int triggerID = 0;
	private boolean active = false;
	
	public TouchButton(int par1, int par2, int par3, TYPES type) {
		super(par1, par2, par3,8,8, null);
		this.type = type;
		
	}
	
	public TouchButton(int par1, int par2, int par3, TYPES type, int triggerID) {
		super(par1, par2, par3,16,16, null);
		
		this.type = type;
		this.triggerID = triggerID;
	}
	
	
	@Override
	public void drawButton(Minecraft par1Minecraft, int par2, int par3)
    {
        if (this.drawButton)
        {
            FontRenderer var4 = par1Minecraft.fontRenderer;
            GL11.glBindTexture(GL11.GL_TEXTURE_2D, par1Minecraft.renderEngine.getTexture("/ressources/art/gui/touch.png"));
            GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
            this.field_82253_i = par2 >= this.xPosition && par3 >= this.yPosition && par2 < this.xPosition + this.width && par3 < this.yPosition + this.height;
            int var5 = this.getHoverState(this.field_82253_i);
            int textureposx = 0;
            int textureposy = 0;
            
            if (type == TYPES.UP)
            	textureposx = 0;
            if (type == TYPES.DOWN)
            	textureposx = 8;
            if (type == TYPES.LEFT)
            	textureposx = 16;
            if (type == TYPES.RIGHT)
            	textureposx = 24;
            if (type == TYPES.TRIGGER) {
            	textureposx = 0 + triggerID*16;
            	textureposy = 32;
            	if (active)
            		textureposy += 16;
            }
            
            
            this.drawTexturedModalRect(this.xPosition, this.yPosition,  textureposx,textureposy, this.width, this.height);
            //this.drawTexturedModalRect(this.xPosition + this.width / 2, this.yPosition, 200 - this.width / 2, 46 + var5 * 20, this.width / 2, this.height);
            this.mouseDragged(par1Minecraft, par2, par3);
            int var6 = 14737632;

            if (!this.enabled)
            {
                var6 = -6250336;
            }
            else if (this.field_82253_i)
            {
                var6 = 16777120;
            }

            //this.drawCenteredString(var4, this.displayString, this.xPosition + this.width / 2, this.yPosition + (this.height - 8) / 2, var6);
        }
    }

	public TYPES getType() {
		return type;
	}

	public int getTriggerID() {
		return triggerID;
	}

	public boolean isActive() {
		return active;
	}

	public void setActive(boolean active) {
		this.active = active;
	}
	
	
} public class ContainerExtender extends Container {

    private TileExtender extender;
    
    public ContainerExtender(InventoryPlayer inventoryPlayer, TileExtender extender) {
    	this.extender = extender;
    	 
        this.addSlotToContainer(new SlotInterface(extender, 0,6, 74));
        //this.addSlotToContainer(new Slot(extender, 1, 56, 62));
        for (int inventoryRowIndex = 0; inventoryRowIndex < 3; ++inventoryRowIndex) {
            for (int inventoryColumnIndex = 0; inventoryColumnIndex < 9; ++inventoryColumnIndex) {
                this.addSlotToContainer(new Slot(inventoryPlayer, inventoryColumnIndex + inventoryRowIndex * 9 + 9, 8 + inventoryColumnIndex * 18, 94 + inventoryRowIndex * 18));
            }
        }
        // Add the player's action bar slots to the container
        for (int actionBarSlotIndex = 0; actionBarSlotIndex < 9; ++actionBarSlotIndex) {
            this.addSlotToContainer(new Slot(inventoryPlayer, actionBarSlotIndex, 8 + actionBarSlotIndex * 18, 152));
        }
    }

	@Override
	public boolean canInteractWith(EntityPlayer var1) {
		return true;
		
	}

	 @Override
     public ItemStack transferStackInSlot(EntityPlayer player, int slot) {
             ItemStack stack = null;
             Slot slotObject = (Slot) inventorySlots.get(slot);
             if (slotObject != null && slotObject.getHasStack()) {
                     ItemStack stackInSlot = slotObject.getStack();
                     stack = stackInSlot.copy();
                     if (stack != null && !(stack.getItem() instanceof ItemMulti)) 
                    	 return null;
                     if ((stack.getItemName() != null || stack.getItemName().startsWith("item.plcItem.Interface")))
                    	 return null;
                     //merges the item into player inventory since its in the tileEntity
                     //this assumes only 1 slot, for inventories with > 1 slots, check out the Chest Container.
                     if (slot == 0) {
                             if (!mergeItemStack(stackInSlot, 1,
                                             inventorySlots.size(), true)) {
                                     return null;
                             }
                     //places it into the tileEntity is possible since its in the player inventory
                     } else if (!mergeItemStack(stackInSlot, 0, 1, false)) {
                             return null;
                     }

                     if (stackInSlot.stackSize == 0) {
                             slotObject.putStack(null);
                     } else {
                             slotObject.onSlotChanged();
                     }
             }
             extender.onSlotChange();
             return stack;
     }
} public enum Signal {
	ON, OFF, PULSE, NEGATIVEPULSE;

	public Signal getHigherSignal(Signal signal) {
		if (signal == null)
			return OFF;
		if (this.equals(signal))
			return this;
		if (signal.equals(ON) || this.equals(ON))
			return ON;
		if (this.equals(OFF))
			return signal;
		if (signal.equals(OFF))
			return this;
		if (this.equals(PULSE) && signal.equals(NEGATIVEPULSE))
			return ON;
		if (this.equals(NEGATIVEPULSE) && signal.equals(PULSE))
			return ON;
		return OFF;
	}

	public Signal getLowerSignal(Signal signal) {
		if (signal == null)
			return OFF;
		if (this.equals(OFF) || signal.equals(OFF))
			return OFF;
		if (this.equals(ON) && signal.equals(ON))
			return Signal.ON;
		if (this.equals(ON))
			return signal;
		if (signal.equals(ON))
			return this;
		if (this.equals(PULSE) && signal.equals(NEGATIVEPULSE))
			return OFF;
		if (this.equals(NEGATIVEPULSE) && signal.equals(PULSE))
			return OFF;
		return OFF;
	}

	public Signal invert() {
		if (this.equals(ON))
			return OFF;
		if (this.equals(OFF))
			return ON;
		if (this.equals(PULSE))
			return NEGATIVEPULSE;
		if (this.equals(NEGATIVEPULSE))
			return PULSE;
		return OFF;
	}

	public static Signal fromOrdinal(int ordinal) {
		switch (ordinal) {
		case 0:
			return ON;
		case 1:
			return OFF;
		case 2:
			return PULSE;
		case 3:
			return NEGATIVEPULSE;
		}
		return null;
	}

} public class ExtenderChannel {
	public static enum TYPES {
		INPUT, OUTPUT
	}

	private TYPES type;
	private int number;
	private TileExtender extender;

	
	private String functionData = "";
	private String triggerData = "";
	private Object functionLocalData = "";
	private Object triggerLocalData = "";
	
	private long sheduledOn = -1;
	

	private ExtenderFunction function = ExtenderFunction.disabledFunction;
	private int side = 6;

	private Signal signal = Signal.OFF;
	private ExtenderTrigger trigger;

	
	
	
	public ExtenderChannel(TileExtender extender, TYPES type, int number) {
		this.number = number;
		this.type = type;
		this.extender = extender;
		this.function = ExtenderFunction.disabledFunction;
	}
	
	public void setSignalWithReset(Signal signal, int timer) {
		
	}



	public TYPES getType() {
		return type;
	}

	public void setType(TYPES type) {
		this.type = type;
	}

	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}

	public String getName() {
		if (type == TYPES.INPUT)
			return ("INPUT " + number);
		else
			return ("OUTPUT " + number);
	}

	public ExtenderFunction getFunction() {
		return function;
	}

	public void setFunction(int functionid) {
		if (function != null && function.getId() == functionid)
			return;
		if (function != null) {
			function.onDestroy(this);
		}
		function = ExtenderFunction.getFunction(this,functionid);
		if (function != null)
			function.onCreate(this);
		
	}

	public TileExtender getExtender() {
		return extender;
	}

	public Signal getSignal() {
		return signal;
	}

	public void setSignal(Signal signal) {
		this.signal = signal;
	}

	public void saveTo(DataOutputStream data) throws IOException {
		data.writeChar(number);
	
		data.writeChar(type.ordinal());
		data.writeChar(side);
		
		data.writeChar(function.getId());
		if (trigger != null)
			data.writeChar(trigger.getTriggerId());
		else data.writeChar(255);
		data.writeUTF(functionData);
		data.writeUTF(triggerData);
		
	}

	public int getSide() {
		return side;
	}

	public void setSide(int side) {
		boolean update = this.side != side;
		this.side = side;
		if (update)
			extender.sheduleNeighbourUpdate();
	}

	public static ExtenderChannelNetworkData readFrom(DataInputStream data)
			throws IOException {

		char number = data.readChar();
		char type = data.readChar();
		char side = data.readChar();
		char functiontype = data.readChar();
		char triggerid = data.readChar();
		String functionData = data.readUTF();
		String triggervalue = data.readUTF();
		return new ExtenderChannelNetworkData(number, type, side, functiontype, triggerid, functionData,triggervalue);

	}

	public void inject(ExtenderChannelNetworkData dt) {
		if (this.type.ordinal() != dt.getType()) {
			LogHelper.error("Trying to Update Channel of wrong type! "
					+ this.getType().ordinal() + " != " + dt.getType());
			return;
		}
		
		
		setSide(dt.getSide());
		
		setFunction(dt.getFunctionType());
		
		if (dt.getTriggerType() < 255 && function != null && function.getTriggers() != null) {
			for (ExtenderTrigger trg : function.getTriggers()) 
				if (trg.getTriggerId() == dt.getTriggerType()) 
					setTrigger(trg);
				
		} else trigger = null;
			
		functionData = dt.getFunctionData();
		triggerData = dt.getTriggerData();

	}

	public void onSignal(Signal signal) {
		
		if (type.equals(TYPES.INPUT)) {
			if (function != null)
				function.onSignal(this,signal);
			this.signal = signal;

		} else if (type.equals(TYPES.OUTPUT)) {
			if (function != null && !(function instanceof DisabledFunction))
				function.onSignal(this,signal);
		}
	}
	
	public void onRedstoneChanged(boolean isRedstonePowered, boolean b) {
		if (function instanceof RedstoneFunction)
			((RedstoneFunction) function).onRedstoneChanged(this,isRedstonePowered,b);
	}

	public void enableShedule(long inticks) {
		setSheduledOn(extender.getWorldObj().getTotalWorldTime()+inticks);
		extender.addChannelToShedule(this);
	}
	
	
	public ExtenderTrigger getTrigger() {
		return trigger;
	}
	public void setTrigger(ExtenderTrigger trigger) {
		this.trigger = trigger;
	}


	public String getFunctionData() {
		return functionData;
	}


	public void setFunctionData(String functionData) {
		this.functionData = functionData;
	}


	public String getTriggerData() {
		return triggerData;
	}


	public void setTriggerData(String triggerData) {
		this.triggerData = triggerData;
	}


	public Object getFunctionLocalData() {
		return functionLocalData;
	}


	public void setFunctionLocalData(Object functionLocalData) {
		this.functionLocalData = functionLocalData;
	}


	public Object getTriggerLocalData() {
		return triggerLocalData;
	}


	public void setTriggerLocalData(Object triggerLocalData) {
		this.triggerLocalData = triggerLocalData;
	}

	public long getSheduledOn() {
		return sheduledOn;
	}

	public void setSheduledOn(long sheduledOn) {
		this.sheduledOn = sheduledOn;
	}
	

} public class LogHelper {

	private static Logger plcLoggerServer = null;
	private static Logger plcLoggerClient = null;

	public static void init() {
		plcLoggerClient = Logger.getLogger("plcClient");
		plcLoggerClient.setParent(FMLLog.getLogger());
		plcLoggerServer = Logger.getLogger("plcServer");
		plcLoggerServer.setParent(FMLLog.getLogger());

	}

	public static void log(Level logLevel, String message) {
		Side side = FMLCommonHandler.instance().getEffectiveSide();
		if (side == Side.CLIENT)
			plcLoggerClient.log(logLevel, message);
		else
			plcLoggerServer.log(logLevel, message);

	}

	public static void info(String message) {
		log(Level.INFO, message);
	}

	public static void warn(String message) {
		log(Level.WARNING, message);
	}

	public static void error(String message) {
		log(Level.SEVERE, message);
	}

} public class PacketExtenderData extends PLCPacket {

	public int x, y, z;
	public int dimId;
	
	private UUID cUUID = null;
	private String cName = null;
	private Boolean cConnected = null;
	private List<ExtenderChannelNetworkData> channelsIn = null;
	private List<ExtenderChannelNetworkData> channelsOut = null;
	
	private TileExtender extender;
	
	
	
	public PacketExtenderData() {
		super(PacketTypeHandler.EXTENDERDATA, true);
	}

	public void setCoords(int x, int y, int z) {
		this.x = x;
		this.y = y;
		this.z = z;
	}
	
	public void setExtender (TileExtender extender) {
		this.extender = extender;
	}


	// int x,y,z
	// String id
	//
	// bool state
	// state...
	// bool elements 
	// bool elementsAll
	// elements....
	// bool objects
	// objects...
	// bool poweredState
	// poweredMap...
	// bool more
	//
	
	@Override
	public void writeData(DataOutputStream data) throws IOException {
		data.writeInt(extender.getWorldObj().getWorldInfo().getDimension());
		data.writeInt(extender.xCoord);
		data.writeInt(extender.yCoord);
		data.writeInt(extender.zCoord);
		if (extender.getConnectedController()!= null) {
			data.writeBoolean(true);
			data.writeUTF(extender.getConnectedController().toString());
			data.writeUTF(extender.getConnectedControllerName());
		} else  {
			data.writeBoolean(false);
		}
		
		data.writeChar(extender.getChannelsIn().size());
		for (ExtenderChannel channel : extender.getChannelsIn()) {
			channel.saveTo(data);
		}
		data.writeChar(extender.getChannelsOut().size());
		for (ExtenderChannel channel : extender.getChannelsOut()) {
			channel.saveTo(data);
		}
		data.writeBoolean(false);
	}

	public void readData(DataInputStream data) throws IOException {
		this.dimId = data.readInt();
		this.x = data.readInt();
		this.y = data.readInt();
		this.z = data.readInt();
		this.cConnected = data.readBoolean();
		if (cConnected) {
			cUUID = UUID.fromString(data.readUTF());
			cName = data.readUTF();
		} 
		int dsize = data.readChar();
		channelsIn = new ArrayList<ExtenderChannelNetworkData>();
		for (int i = 0; i < dsize; i++) {
			channelsIn.add(ExtenderChannel.readFrom(data));
		}
		
		dsize = data.readChar();
		channelsOut = new ArrayList<ExtenderChannelNetworkData>();
		for (int i = 0; i < dsize; i++) {
			channelsOut.add(ExtenderChannel.readFrom(data));
		}
		
		
	}

	public void execute(INetworkManager manager, Player player) {
		Side side = FMLCommonHandler.instance().getEffectiveSide();
		World worldObj = null;
		if (side == Side.CLIENT) {
			if (player instanceof EntityClientPlayerMP)
				worldObj = ((EntityClientPlayerMP) player).worldObj;
		} else if (side == Side.SERVER) {
			
			if (player instanceof EntityPlayerMP)
				worldObj = ((EntityPlayerMP) player).worldObj;
		}

		if (worldObj != null) {
			TileEntity tile = worldObj.getBlockTileEntity(x, y, z);
			if (tile != null && tile instanceof TileExtender) {
				TileExtender tileE = (TileExtender) tile;
				
				if (cConnected) {
					if (tileE.getConnectedController() != null 
							&& !tileE.getConnectedController().equals(cUUID))
						tileE.unlink();
					tileE.linkFromPackage(cUUID, cName);
				} else {
					tileE.unlink();
				}
				for (ExtenderChannelNetworkData dt : channelsIn) {
					tileE.injectChannel(ExtenderChannel.TYPES.INPUT,dt);
				}
				for (ExtenderChannelNetworkData dt : channelsOut) {
					tileE.injectChannel(ExtenderChannel.TYPES.OUTPUT,dt);
				}
				tileE.sheduleNeighbourUpdate();
				tileE.sheduleRemoteUpdate();
				
			}
			
		}
		LogHelper.info("Extender Data executed");
	}

	
	public static void sendElements(TileExtender tile,
			 EntityPlayer player) {
		PacketExtenderData pkg = new PacketExtenderData();
		pkg.setExtender(tile);
		pkg.setCoords(tile.xCoord, tile.yCoord, tile.zCoord);
		Packet packet = PacketTypeHandler.populatePacket(pkg);
		Side side = FMLCommonHandler.instance().getEffectiveSide();
		if (side == Side.SERVER) {
			// Server
			EntityPlayerMP playermp = (EntityPlayerMP) player;
			PacketDispatcher.sendPacketToPlayer(packet, (Player) playermp);
		
		} else if (side == Side.CLIENT) {
			// Client
			//PacketDispatcher.sendPacketToServer(packet);
			EntityClientPlayerMP playerclient = (EntityClientPlayerMP)player;
			playerclient.sendQueue.addToSendQueue(packet);
		}

	}
	private static void updateArround(TileExtender tile, int i) {
		PacketExtenderData pkg = new PacketExtenderData();
		pkg.setExtender(tile);
		pkg.setCoords(tile.xCoord, tile.yCoord, tile.zCoord);
		Packet packet = PacketTypeHandler.populatePacket(pkg);
		PacketDispatcher.sendPacketToAllAround(tile.xCoord, tile.yCoord, tile.zCoord, i,tile.getWorldObj().getWorldInfo().getDimension() , packet);	
	}
	
	
} public class TileController extends TilePLC {
	public enum STATES {
		STOP, RUN, EDIT, ERROR
	};

	private STATES state = STATES.STOP;

	private Circuit circuit = null;

	private String controllerName = "unknown";

	private int range = 32;

	public TileController() {
		super(PLCEvent.TARGETTYPE.CONTROLLER);
		circuit = new BasicCircuit(this);
	}

	@Override
	public void updateEntity() {
		super.updateEntity();
		if (circuit != null && circuit.getSimulator() != null)
			circuit.getSimulator().onTick(worldObj.getTotalWorldTime());
	}

	@Override
	protected void initialize() {
		super.initialize();

	}

	public void onEvent(PLCEvent event) {
		if (isInvalid()) {
			PLC.instance.getNetworkBroker().removeEventListener(this);
			return;
		}
		if (event instanceof SignalEvent) {
			SignalEvent events = (SignalEvent) event;
			CircuitObject obj = circuit.getByType(LogicInput.class,
					events.getChannel());
			if (obj instanceof LogicInput) {
				LogicInput inp = (LogicInput) obj;
				inp.onSignal(events.getSignal());
			}
		} else if (event instanceof ControllerDataEvent) {
			sendUpdatesToExtenders(true);
		} else if (event instanceof SearchEvent) {
			if (event.getSource().getWorldObj() == getWorldObj()) {

				int dx = xCoord - event.getSource().xCoord;
				int dy = yCoord - event.getSource().yCoord;
				int dz = zCoord - event.getSource().zCoord;
				int dist = (int) Math.floor(Math.sqrt(dx * dx + dy * dy + dz
						* dz));
				if (StaticData.range < 0 || StaticData.range >= dist) {
					SearchResponseEvent resp = new SearchResponseEvent(this,
							event.getSource().getUuid(), dist, uuid,
							controllerName, circuit.getByType(LogicInput.class)
									.size(), circuit.getByType(
									LogicOutput.class).size());
					PLC.instance.getNetworkBroker().fireEvent(resp);
				}
			}
		}

	}

	@Override
	public void onChunkUnload() {
		circuit.onDestroy();
		super.onChunkUnload();
	}

	public void onDestroy() {
		circuit.onDestroy();
		super.onDestroy();
	}

	public void readFromNBT(NBTTagCompound nbtTagCompound) {
		super.readFromNBT(nbtTagCompound);

		if (nbtTagCompound.hasKey("name"))
			controllerName = nbtTagCompound.getString("name");
		try {

			InputStream is = new ByteArrayInputStream(
					nbtTagCompound.getByteArray("elements"));
			DataInputStream dis = new DataInputStream(is);
			List<CircuitElementNetworkData> nd = circuit.loadElementsFrom(dis,
					true);
			circuit.injectElements(nd, true);
		} catch (IOException ex) {
			LogHelper.error("exception durring reading elements data!");
		}
		try {

			InputStream is = new ByteArrayInputStream(
					nbtTagCompound.getByteArray("objects"));
			DataInputStream dis = new DataInputStream(is);
			List<CircuitObjectNetworkData> nd = circuit.loadObjectsFrom(dis,
					true);
			circuit.injectObjects(nd, true);
		} catch (IOException ex) {
			LogHelper.error("exception durring reading objects data!");
		}

	}

	public void writeToNBT(NBTTagCompound nbtTagCompound) {
		super.writeToNBT(nbtTagCompound);
		

		nbtTagCompound.setString("name", controllerName);
		try {
			{
				ByteArrayOutputStream baos = new ByteArrayOutputStream();
				DataOutputStream w = new DataOutputStream(baos);
				circuit.saveElementsTo(w, true);
				w.flush();
				byte[] result = baos.toByteArray();
				nbtTagCompound.setByteArray("elements", result);
			}
			{
				ByteArrayOutputStream baos = new ByteArrayOutputStream();
				DataOutputStream w = new DataOutputStream(baos);
				circuit.saveObjectsTo(w, true);
				w.flush();
				byte[] result = baos.toByteArray();
				nbtTagCompound.setByteArray("objects", result);
			}

		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	public Circuit getCircuit() {
		return circuit;
	}

	public void setCircuit(Circuit circuit) {
		this.circuit = circuit;
	}

	public TileController.STATES getState() {
		return this.state;
	}

	public void setState(TileController.STATES state) {
		this.state = state;
	}

	public String getControllerName() {
		return controllerName;
	}

	public void setControllerName(String controllerName) {
		this.controllerName = controllerName;
	}

	public int getRange() {
		return range;
	}

	public void setRange(int range) {
		this.range = range;
	}

	public void sendUpdatesToExtenders(boolean updateAll) {
		List<ControllerDataPayload> tosend = new ArrayList<ControllerDataPayload>();
		for (CircuitObject out : circuit.getByType(LogicOutput.class)) {
			LogicOutput lo = (LogicOutput) out;
			if (lo.isChanged() || updateAll) {
				//LogHelper.info("sending "+lo.getLinkNumber()+" "+lo.getSignal());
				tosend.add(new ControllerDataPayload(lo.getLinkNumber(), lo
						.getSignal()));
				lo.setChanged(false);
			}
		}
		if (tosend.size() > 0)
			PLC.instance.getNetworkBroker().fireEvent(
					new ControllerDataEvent(circuit.getController(), circuit
							.getController().getUuid(), tosend));
	}

} public class TileExtender extends TilePLC implements IInventory {
	public enum TYPE {
		BASIC
	};

	private ItemStack[] extenderCards = new ItemStack[2];

	private TYPE type = null;

	private int range = StaticData.ExtenderBaseRange;

	// SOFT link
	private UUID connectedController = null;
	private String connectedControllerName = null;

	private List<SearchResponseEvent> controllersInRange = null;

	private List<ExtenderChannel> channelsIn = null;
	private List<ExtenderChannel> channelsOut = null;

	private List<ExtenderChannel> sheduledChannelUpdates;

	private List<ExtenderChannel> tickListener = new ArrayList<ExtenderChannel>();

	private boolean isRedstonePowered;

	private boolean remoteUpdate = false;
	private boolean neighbourUpdate = false;

	private boolean channelsConfigChangedForGui = false;
	
	// load shit
	private boolean needsLoad = false;
	private List<ExtenderChannelNetworkData> loadChannelDataIn = null;
	private List<ExtenderChannelNetworkData> loadChannelDataOut = null;

	// status
	private char[] instatus = new char[0];
	private char[] outstatus = new char[0];

	public TileExtender() {
		super(PLCEvent.TARGETTYPE.EXTENDER);
		channelsIn = new ArrayList<ExtenderChannel>();
		channelsOut = new ArrayList<ExtenderChannel>();
		sheduledChannelUpdates = new LinkedList<ExtenderChannel>();

		Side side = FMLCommonHandler.instance().getEffectiveSide();
		if (side.equals(Side.CLIENT))
			needsLoad = true;

	}

	public void updateStatus(char[] ins, char[] outs) {
		instatus = ins;
		outstatus = outs;
	}

	public char[] getInputs() {
		return instatus;
	}

	public char[] getOutputs() {
		return outstatus;
	}

	/**
	 * bc3 support integration
	 * 
	 * @return
	 */
	public static TileExtender createInstance() {
		try {
			Class bc3Extender = PLC.class.getClassLoader().loadClass(
					"de.squig.plc.bc3.compat.TileExtenderBC3");
			Constructor constructor = bc3Extender.getConstructor(null);
			TileExtender res = (TileExtender) constructor.newInstance(null);
			return res;
		} catch (Exception ex) {
			return new TileExtender();
		}
	}

	public boolean isSidePowered(ForgeDirection side) {
		return getSideSignal(side).equals(Signal.ON);
	}

	public Signal getSideSignal(ForgeDirection side) {
		Signal ret = Signal.OFF;
		for (int i = 0; i < channelsOut.size(); i++) {
			ExtenderChannel chn = channelsOut.get(i);
			if (chn.getFunction() instanceof RedstoneFunction
					&& (chn.getSide() == 6 || chn.getSide() == side.ordinal()))
				ret = ret.getHigherSignal(chn.getSignal());

		}
		return ret;
	}

	public void sheduleNeighbourUpdate() {
		neighbourUpdate = true;
	}

	public void sheduleRemoteUpdate() {
		remoteUpdate = true;
	}

	@Override
	public void onDestroy() {
		if (connectedController != null)
			PLC.instance.getNetworkBroker().removeMulticastListener(
					connectedController, this);
		super.onDestroy();
	}

	@Override
	public void onChunkUnload() {
		if (connectedController != null)
			PLC.instance.getNetworkBroker().removeMulticastListener(
					connectedController, this);
		super.onChunkUnload();
	}

	@Override
	protected void initialize() {
		super.initialize();

	}

	@Override
	public void validate() {
		super.validate();
	};

	@Override
	public boolean canUpdate() {
		return true;
	};

	public void addChannelToShedule(ExtenderChannel chn) {
		Side side = FMLCommonHandler.instance().getEffectiveSide();
		if (side.equals(Side.CLIENT))
			return;
		if (!sheduledChannelUpdates.contains(chn))
			sheduledChannelUpdates.add(chn);

	}

	@Override
	public void updateEntity() {
		super.updateEntity();
		if (needsLoad) {
			loadData();
		}
		Side side = FMLCommonHandler.instance().getEffectiveSide();
		if (side.equals(Side.CLIENT))
			return;
		long now = worldObj.getTotalWorldTime();
		if (sheduledChannelUpdates.size() > 0) {
			List<ExtenderChannel> tr = new LinkedList<ExtenderChannel>();
			for (ExtenderChannel chn : sheduledChannelUpdates) {
				if (now >= chn.getSheduledOn() && chn.getFunction() != null) {
					chn.getFunction().onUpdate(chn, now);
					chn.setSheduledOn(-1);
					tr.add(chn);
				}
			}
			sheduledChannelUpdates.removeAll(tr);
		}
		if (remoteUpdate) {
			PacketExtenderLiteData.sendUpdateToClients(this);
			remoteUpdate = false;
		}
		if (neighbourUpdate) {
			worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord,
					StaticData.BlockExtender);
			neighbourUpdate = false;
		}
	};

	private void loadData() {
		needsLoad = false;
		Side side = FMLCommonHandler.instance().getEffectiveSide();
		if (side.equals(Side.CLIENT)) {
			PacketExtenderLiteData.requestUpdateFromServer(this);
			return;
		}

		for (ExtenderChannelNetworkData dt : loadChannelDataIn) {
			injectChannel(ExtenderChannel.TYPES.INPUT, dt);
		}
		for (ExtenderChannelNetworkData dt : loadChannelDataOut) {
			injectChannel(ExtenderChannel.TYPES.OUTPUT, dt);
		}

		if (connectedController != null) {
			PLC.instance.getNetworkBroker().addMulticastListener(
					connectedController, this);
			requestUpdateFromController();
		}

		loadChannelDataIn = null;
		loadChannelDataOut = null;

	}

	public void readFromNBT(NBTTagCompound nbtTagCompound) {
		super.readFromNBT(nbtTagCompound);
		needsLoad = true;

		if (nbtTagCompound.hasKey("cuuid")) {
			connectedController = UUID.fromString(nbtTagCompound
					.getString("cuuid"));
			connectedControllerName = nbtTagCompound.getString("cname");
		}

		NBTTagList tagList = nbtTagCompound.getTagList("Items");
		this.extenderCards = new ItemStack[this.getSizeInventory()];
		for (int i = 0; i < tagList.tagCount(); ++i) {
			NBTTagCompound tagCompound = (NBTTagCompound) tagList.tagAt(i);
			byte slot = tagCompound.getByte("Slot");
			if (slot >= 0 && slot < this.extenderCards.length) {
				this.extenderCards[slot] = ItemStack
						.loadItemStackFromNBT(tagCompound);
			}
		}

		loadChannelDataIn = new ArrayList<ExtenderChannelNetworkData>();
		for (int i = 0; i < 64; i++) {
			if (nbtTagCompound.hasKey("I-" + i)) {
				try {
					InputStream is = new ByteArrayInputStream(
							nbtTagCompound.getByteArray("I-" + i));
					DataInputStream dis = new DataInputStream(is);
					loadChannelDataIn.add(ExtenderChannel.readFrom(dis));
				} catch (IOException ex) {
					LogHelper.error("exception durring reading data!");
				}
			}
		}
		loadChannelDataOut = new ArrayList<ExtenderChannelNetworkData>();
		for (int i = 0; i < 32; i++) {
			if (nbtTagCompound.hasKey("O-" + i)) {
				try {
					InputStream is = new ByteArrayInputStream(
							nbtTagCompound.getByteArray("O-" + i));
					DataInputStream dis = new DataInputStream(is);
					loadChannelDataOut.add(ExtenderChannel.readFrom(dis));
				} catch (IOException ex) {
					LogHelper.error("exception durring reading data!");
				}
			}
		}

	}

	public void writeToNBT(NBTTagCompound nbtTagCompound) {
		super.writeToNBT(nbtTagCompound);

		if (connectedController != null) {
			nbtTagCompound.setString("cuuid", connectedController.toString());
			nbtTagCompound.setString("cname", connectedControllerName);
		} else {
			nbtTagCompound.removeTag("cuuid");
			nbtTagCompound.removeTag("cname");
		}

		NBTTagList tagList = new NBTTagList();
		for (int currentIndex = 0; currentIndex < this.extenderCards.length; ++currentIndex) {
			if (this.extenderCards[currentIndex] != null) {
				NBTTagCompound tagCompound = new NBTTagCompound();
				tagCompound.setByte("Slot", (byte) currentIndex);
				this.extenderCards[currentIndex].writeToNBT(tagCompound);
				tagList.appendTag(tagCompound);
			}
		}
		nbtTagCompound.setTag("Items", tagList);

		for (int i = 0; i < 64; i++) {
			if (i < channelsIn.size()) {
				try {
					ByteArrayOutputStream baos = new ByteArrayOutputStream();
					DataOutputStream w = new DataOutputStream(baos);

					ExtenderChannel chan = channelsIn.get(i);
					chan.saveTo(w);
					w.flush();

					byte[] result = baos.toByteArray();
					nbtTagCompound.setByteArray("I-" + i, result);

				} catch (IOException ex) {
					LogHelper.error("exception durring writing data!");
				}
			} else {
				if (nbtTagCompound.hasKey("I-" + i))
					nbtTagCompound.removeTag("I-" + i);
			}
		}
		for (int i = 0; i < 32; i++) {
			if (i < channelsOut.size()) {
				try {
					ByteArrayOutputStream baos = new ByteArrayOutputStream();
					DataOutputStream w = new DataOutputStream(baos);

					ExtenderChannel chan = channelsOut.get(i);
					chan.saveTo(w);
					w.flush();

					byte[] result = baos.toByteArray();
					nbtTagCompound.setByteArray("O-" + i, result);

				} catch (IOException ex) {
					LogHelper.error("exception durring writing data!");
				}
			} else {
				if (nbtTagCompound.hasKey("O-" + i))
					nbtTagCompound.removeTag("O-" + i);
			}
		}

	}

	public void sendBroadcastSearch() {
		controllersInRange = new ArrayList<SearchResponseEvent>();
		SearchEvent event = new SearchEvent(this,
				PLCEvent.TARGETTYPE.CONTROLLER, null);
		PLC.instance.getNetworkBroker().fireEvent(event);
	}

	public List<SearchResponseEvent> getControllerInRange() {
		return controllersInRange;
	}

	private void createChannels(SearchResponseEvent linkto) {
		channelsIn.clear();
		channelsOut.clear();
		tickListener.clear();
		char[] ins = new char[linkto.getInChannels()];
		char[] outs = new char[linkto.getOutChannels()];

		for (int i = 0; i < linkto.getInChannels(); i++) {
			ExtenderChannel channel = new ExtenderChannel(this,
					ExtenderChannel.TYPES.INPUT, i);

			channelsIn.add(channel);
			ins[i] = 0;

		}
		for (int i = 0; i < linkto.getOutChannels(); i++) {
			ExtenderChannel channel = new ExtenderChannel(this,
					ExtenderChannel.TYPES.OUTPUT, i);

			channelsOut.add(channel);
			outs[i] = 0;
		}
		updateStatus(ins, outs);
	}

	public void checkRedstonePower() {
		boolean isRedstonePowered = worldObj.isBlockIndirectlyGettingPowered(
				xCoord, yCoord, zCoord);

		for (ExtenderChannel channel : channelsIn) {
			if (channel.getFunction() instanceof RedstoneFunction)
				channel.onRedstoneChanged(isRedstonePowered, false);
		}

	}

	public void injectChannel(TYPES input, ExtenderChannelNetworkData dt) {
		ExtenderChannel chnn = null;
		List<ExtenderChannel> chns = channelsIn;
		if (input.equals(ExtenderChannel.TYPES.OUTPUT))
			chns = channelsOut;

		for (ExtenderChannel chn : chns)
			if (chn.getType().ordinal() == dt.getType())
				if (chn.getNumber() == dt.getNumber()) {
					chnn = chn;
					break;
				}
		if (chnn == null) {
			chnn = new ExtenderChannel(this,
					ExtenderChannel.TYPES.values()[dt.getType()],
					dt.getNumber());
			chns.add(chnn);
		}
		chnn.inject(dt);
	}

	public void onEvent(PLCEvent event) {
		if (event instanceof ControllerDataEvent) {
			ControllerDataEvent eventd = (ControllerDataEvent) event;
			for (ControllerDataPayload load : eventd.getPayload()) {
				if (load.channel < channelsOut.size()) {
					ExtenderChannel chn = channelsOut.get(load.channel);
					chn.onSignal(load.signal);
				}
			}

		} else if (event instanceof SignalEvent) {
			SignalEvent events = (SignalEvent) event;
			int chn = events.getChannel();

			ExtenderChannel channel;
			if (chn < channelsOut.size()
					&& (channel = channelsOut.get(chn)) != null)
				channel.onSignal(events.getSignal());
			else
				LogHelper.warn("cound not route event to channel "
						+ events.getChannel());
		} else if (event instanceof SearchResponseEvent) {
			if (controllersInRange == null)
				controllersInRange = new ArrayList<SearchResponseEvent>();
			controllersInRange.add((SearchResponseEvent) event);
			return;
		}

	}

	public void link(SearchResponseEvent linkto) {
		connectedController = linkto.getUuid();
		connectedControllerName = linkto.getName();
		createChannels(linkto);

	}

	public void linkFromPackage(UUID controller, String controllerName) {
		if (connectedController != null)
			PLC.instance.getNetworkBroker().removeMulticastListener(
					connectedController, this);
		boolean requestUpdate = (this.connectedController == null || !this.connectedController
				.equals(controller));
		connectedController = controller;
		connectedControllerName = controllerName;
		if (connectedController != null)
			PLC.instance.getNetworkBroker().addMulticastListener(
					connectedController, this);

		if (requestUpdate)
			requestUpdateFromController();

	}

	public void unlink() {
		if (connectedController != null)
			PLC.instance.getNetworkBroker().removeMulticastListener(
					connectedController, this);
		connectedController = null;
		connectedControllerName = null;
		channelsIn.clear();
		channelsOut.clear();
		tickListener.clear();
		sheduleNeighbourUpdate();
		sheduleRemoteUpdate();
	}

	public void requestUpdateFromController() {
		PLC.instance.getNetworkBroker().fireEvent(
				new ControllerDataEvent(this, connectedController, null));
	}

	public UUID getConnectedController() {
		return connectedController;
	}

	public String getConnectedControllerName() {
		return connectedControllerName;
	}

	public List<ExtenderChannel> getChannelsIn() {
		return channelsIn;
	}

	public List<ExtenderChannel> getChannelsOut() {
		return channelsOut;
	}

	/**
	 * Returns the number of slots in the inventory.
	 */
	public int getSizeInventory() {
		return this.extenderCards.length;
	}

	@Override
	public void setInventorySlotContents(int slot, ItemStack stack) {
		extenderCards[slot] = stack;
		if (stack != null && stack.stackSize > getInventoryStackLimit()) {
			stack.stackSize = getInventoryStackLimit();
		}
		checkInterfaces();
		onSlotChange();
	}

	@Override
	public ItemStack getStackInSlot(int slot) {
		return extenderCards[slot];
	}

	@Override
	public ItemStack getStackInSlotOnClosing(int slot) {
		ItemStack stack = getStackInSlot(slot);
		if (stack != null) {
			setInventorySlotContents(slot, null);
		}
		return stack;
	}

	public String getInvName() {
		return "container.extender";
	}

	public int getInvCheckSum() {
		int sum = 0;
		if (extenderCards[0] != null)
			sum += extenderCards[0].stackSize;
		return sum;
	}
	
	
	public int getInventoryStackLimit() {
		return 64;
	}

	private void checkInterfaces() {
		
		// redstone...
		Class chk = RedstoneFunction.class;
		boolean update = false;
		int space = 0;
		if (extenderCards[0] != null)
			space = extenderCards[0].stackSize;

		for (ExtenderChannel chn : channelsIn) {
			if (chn.getFunction() instanceof RedstoneFunction) {
				if (space > 0)
					space--;
				else {
					chn.setFunction(0);
					update = true;
				}
			}
		}
		for (ExtenderChannel chn : channelsOut) {
			if (chn.getFunction() instanceof RedstoneFunction) {
				if (space > 0)
					space--;
				else {
					chn.setFunction(0);
					update = true;
				}
			}
		}
		if (update) {
			channelsConfigChangedForGui = true;
		}
	}
	
	public void onSlotChange () {
		channelsConfigChangedForGui = true;
	}

	private int countFunction(Class funct) {
		int count = 0;
		for (ExtenderChannel chn : channelsIn) {
			if (chn.getFunction() instanceof RedstoneFunction)
				count++;
		}
		for (ExtenderChannel chn : channelsOut) {
			if (chn.getFunction() instanceof RedstoneFunction)
				count++;
		}
		return count;
	}

	public boolean hasInterfaceFor(Class funct) {
		if (funct.equals(RedstoneFunction.class)) {
			if (extenderCards[0] == null)
				return false;
			int count = extenderCards[0].stackSize;
			int fnct = countFunction(RedstoneFunction.class);
			LogHelper.info("space: "+count+" has:"+fnct);
			if (count <= fnct)
				return false;
		}
		return true;
	}

	public void openChest() {

	}

	public void closeChest() {

	}

	@Override
	public ItemStack decrStackSize(int slot, int amt) {
		ItemStack stack = getStackInSlot(slot);
		if (stack != null) {
			if (stack.stackSize <= amt) {
				setInventorySlotContents(slot, null);
			} else {
				stack = stack.splitStack(amt);
				if (stack.stackSize == 0) {
					setInventorySlotContents(slot, null);
				}
			}
		}
		checkInterfaces();
		onSlotChange();
		return stack;
	}

	public boolean isChannelsConfigChangedForGui() {
		if (channelsConfigChangedForGui) {
			channelsConfigChangedForGui = false;
			return true;
		} else return false;
	}

}
import java.util.ArrayList;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.InventoryPlayer;
import org.lwjgl.opengl.GL11;
import de.squig.plc.client.gui.SubGui;
import de.squig.plc.client.gui.controlls.ChannelButton;
import de.squig.plc.client.gui.controlls.TextButton;
import de.squig.plc.client.gui.controlls.TouchButton;
import de.squig.plc.container.ContainerExtender;
import de.squig.plc.logic.Signal;
import de.squig.plc.logic.extender.ExtenderChannel;
import de.squig.plc.logic.helper.LogHelper;
import de.squig.plc.network.PacketExtenderData;
import de.squig.plc.tile.TileController;
import de.squig.plc.tile.TileExtender;
package de.squig.plc.client.gui.extender;





public class GuiExtender extends GuiContainer {

	private TileController controller;
	protected TileExtender extender;

	public int screenX = 28;
	public int screenY = 7;

	// private static int selectedChannel = -1;

	private int invCheck = 0;

	private SubGui subGui = null;
	private SubGui nextSubGui = null;

	private ExtenderChannel.TYPES myChannelType;

	private ExtenderChannel edit = null;

	ArrayList<GuiButton> btnsChannelsIn = new ArrayList<GuiButton>();
	ArrayList<GuiButton> btnsChannelsOut = new ArrayList<GuiButton>();

	protected InventoryPlayer iplayer;

	public GuiExtender(InventoryPlayer inventoryPlayer, TileExtender extender) {
		super(new ContainerExtender(inventoryPlayer, extender));
		this.extender = extender;
		this.iplayer = inventoryPlayer;
		invCheck = extender.getInvCheckSum();
	}

	public void initGui() {
		super.initGui();
		// selectedChannel = 0;

		extender.sendBroadcastSearch();

		controlList.clear();
		refreshChannelButtons();
		setSubGui(new SubGuiFront(this));

	}

	public void guiBack() {
		setSubGui(new SubGuiFront(this));
	}

	protected void refreshChannelButtons() {
		controlList.removeAll(btnsChannelsIn);
		controlList.removeAll(btnsChannelsOut);
		btnsChannelsIn.clear();
		btnsChannelsOut.clear();

		int in = 0, out = 0;

		for (ExtenderChannel chn : extender.getChannelsIn()) {
			GuiButton btn = null;
			ChannelButton.TYPES typ = ChannelButton.TYPES.INACTIVE;
			if (chn.getFunction().getId() > 0)
				typ = ChannelButton.TYPES.OFF;
			if (chn.getSignal().equals(Signal.ON))
				typ = ChannelButton.TYPES.ON;
			if (chn == edit)
				typ = ChannelButton.TYPES.EDIT;
			btn = new ChannelButton(1, guiLeft + screenX, guiTop + screenY + 10
					+ in * 3, typ, chn.getNumber(), false);
			btnsChannelsIn.add(btn);
			controlList.add(btn);
			in++;
		}
		for (ExtenderChannel chn : extender.getChannelsOut()) {
			GuiButton btn = null;
			ChannelButton.TYPES typ = ChannelButton.TYPES.INACTIVE;
			if (chn.getFunction().getId() > 0)
				typ = ChannelButton.TYPES.OFF;
			if (chn.getSignal().equals(Signal.ON))
				typ = ChannelButton.TYPES.ON;
			if (chn == edit)
				typ = ChannelButton.TYPES.EDIT;
			btn = new ChannelButton(1, guiLeft + screenX + 136, guiTop
					+ screenY + 10 + out * 3, typ, chn.getNumber(), true);

			btnsChannelsOut.add(btn);
			controlList.add(btn);
			out++;
		}
	}

	protected void subDrawText(String text, int x, int y, int color) {
		fontRenderer.drawString(text, screenX + x, screenY + y, color);
	}

	protected TextButton subTextButton(int p1, int x, int y, String text,
			boolean active) {
		return new TextButton(p1, guiLeft + screenX + x, guiTop + screenY + y,
				text, active);
	}

	protected TextButton subTextButton(int p1, int x, int y, String text,
			int data, boolean active) {
		return new TextButton(p1, guiLeft + screenX + x, guiTop + screenY + y,
				text, data, active);
	}

	protected TouchButton subTouchButton(int p1, int x, int y,
			TouchButton.TYPES type) {
		return new TouchButton(p1, guiLeft + screenX + x, guiTop + screenY + y,
				type);
	}

	protected TouchButton subTouchButton(int p1, int x, int y,
			TouchButton.TYPES type, int triggerId) {
		return new TouchButton(p1, guiLeft + screenX + x, guiTop + screenY + y,
				type, triggerId);
	}

	public void addControl(GuiButton button) {
		controlList.add(button);
	}

	public void removeControl(GuiButton button) {
		controlList.remove(button);
	}

	@Override
	protected void drawGuiContainerBackgroundLayer(float par1, int par2,
			int par3) {
		if (extender.isChannelsConfigChangedForGui()
				|| invCheck != extender.getInvCheckSum()) {
			refreshChannelButtons();
			invCheck = extender.getInvCheckSum();
			if (subGui instanceof SubGuiChannel) {
				if (subGui != null)
					subGui.onClose();
				if (edit != null)
					nextSubGui = new SubGuiChannel(edit, this);
			}
			PacketExtenderData.sendElements(extender, iplayer.player);