public class AccessDeniedScreen extends MSCScreen {
	
	private Container container;
	private Label title, message;
	private Button close;

	public AccessDeniedScreen() {
		super(null);
	}
	
	@Override
	protected void createGui() {
		title = new Label("Mob Spawn Controls", new Tooltip("by Davidee"));
		message = new Label("You do not have permission to use MSC", new Tooltip("Try contacting a Server OP"));
		close = new ButtonVanilla("Close",new CloseHandler());

		container = new Container();
		container.addWidgets(title,message,close);
		containers.add(container);
	}

	@Override
	protected void revalidateGui() {
		title.setPosition(width/2, height/4-30);
		close.setPosition(width/2-100, height/4 + 132);
		message.setPosition(width/2,height/4+45);
		
		container.revalidate(0, 0, width, height);
	}


} public class DebugScreen extends MSCScreen{
	
	private DebugPacket packet;
	
	private Container container, logContainer;
	private Scrollbar scrollbar;
	private Button close;
	private Label title;

	public DebugScreen(DebugPacket packet, GuiScreen parent) {
		super(parent);
		
		this.packet = packet;
	}

	@Override
	protected void revalidateGui() {
		title.setPosition(width/2, height/4-40);
		close.setPosition(width/2-75, height/4+132);
		
		scrollbar.setPosition(width - 20, height/4 - 20);
		List<FocusableWidget> groups = logContainer.getFocusableWidgets();
		for (int i = 0; i < groups.size(); ++i)
			groups.get(i).setPosition(width/2, height/4 - 18 + i*14);
		
		logContainer.revalidate(20, height/4 - 20, width - 20, 142);
		container.revalidate(0,0,width,height);
	}
	
	@Override
	public void drawBackground() {
		super.drawBackground();
		drawRect(logContainer.left(), logContainer.top(), logContainer.right() - 20, logContainer.bottom(), 0x44444444);
	}

	@Override
	protected void createGui() {
		close = new ButtonVanilla(150,20,"Back",new CloseHandler());
		title = new Label("MSC Debug", new Tooltip(MobSpawnControls.VERSION));
		
		container = new Container();
		container.addWidgets(close,title);
		
		scrollbar = new ScrollbarVanilla(20);
		logContainer = new FocusedContainer(scrollbar, 14, 4);
		
		FocusableLabel[] labels = new FocusableLabel[packet.log.length];
		for (int i = 0; i < labels.length; ++i)
			labels[i] = new FocusableLabel(packet.log[i]);
		
		logContainer.addWidgets(labels);
		
		containers.add(logContainer);
		containers.add(container);
		
		selectedContainer = logContainer;
	}

} public class MainMenu extends MSCScreen{

	private Container container;

	private Button close, mods, settings, debug;
	private Label title;

	public MainMenu() {
		super(null);
	}

	public void createGui() {
		close = new ButtonVanilla(150,20,"Close",new CloseHandler());
		mods = new ButtonVanilla(100,20,"Configs", this);
		settings = new ButtonVanilla(100,20,"Settings",this);
		debug = new ButtonVanilla(100,20,"Debug",this);

		title = new Label("Mob Spawn Controls",new Tooltip(MobSpawnControls.VERSION));

		container = new Container();
		container.addWidgets(close, mods, settings, debug, title);
		containers.add(container);
		
		selectedContainer = container;
	}

	@Override
	public void buttonClicked(Button button){
		if (button == mods)
			MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getRequestPacket(PacketType.MOD_LIST));
		if (button == settings)
			MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getRequestPacket(PacketType.SETTINGS));
		if (button == debug)
			MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getRequestPacket(PacketType.DEBUG));
		setEnabled(false,mods,settings,debug);
	}
	
	@Override
	protected void reopenedGui(){
		setEnabled(true, mods, settings, debug);
	}
	
	@Override
	protected void revalidateGui(){
		title.setPosition(width/2, height/4-30);
		close.setPosition(width/2-75, height/4 + 107);
		
		mods.setPosition(width/2-50, height/4+8);
		settings.setPosition(width/2-50, height/4+33);
		debug.setPosition(width/2-50, height/4+58);
		
		container.revalidate(0,0,width,height);
	}

} public class MobTypesMenu extends MSCScreen{
	
	private String mod;
	
	private Container container;
	private Button close, monster, creature, ambient, water, none;
	private Label title;
	

	public MobTypesMenu(String mod, GuiScreen parent) {
		super(parent);

		this.mod = mod;
	}

	@Override
	protected void revalidateGui() {
		title.setPosition(width/2,height/4-30);
		close.setPosition(width/2-75,height/4+107);
		
		monster.setPosition(width/2-102,height/4+8);
		creature.setPosition(width/2+2,height/4+8);
		ambient.setPosition(width/2-102,height/4+33);
		water.setPosition(width/2+2,height/4+33);
		none.setPosition(width/2-50,height/4+58);
		
		container.revalidate(0,0,width,height);
	}
	
	@Override
	public void buttonClicked(Button b) {
		MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getRequestPacket(PacketType.CREATURE_TYPE, mod + ":" + ((ButtonVanilla)b).getText()));
		setEnabled(false, monster, creature, ambient, water, none);
	}
	
	protected void reopenedGui(){
		setEnabled(true, monster, creature, ambient, water, none);
	}

	@Override
	protected void createGui() {
		close = new ButtonVanilla(150,20,"Back",new CloseHandler());
		
		monster = new ButtonVanilla(100, 20, "Monster", this);
		creature = new ButtonVanilla(100, 20, "Creature", this);
		ambient = new ButtonVanilla(100, 20, "Ambient", this);
		water = new ButtonVanilla(100, 20, "WaterCreature", this);
		none = new ButtonVanilla(100, 20, "None/Unknown", this);

		title = new Label(mod + " Mob Types", new Tooltip("Select a Mob Type"));

		container = new Container();
		container.addWidgets(close, monster, creature, ambient, water, none, title);
		containers.add(container);
	}

} public class SpawnControlMenu extends MSCScreen{
	
	private Container container;
	private Button close, master, biomes, entities, eval;
	private Label title;
	
	private String mod;

	public SpawnControlMenu(String mod, GuiScreen parent) {
		super(parent);
		
		this.mod = mod;
	}

	@Override
	protected void reopenedGui(){
		setEnabled(true, master, biomes, entities, eval);
	}
	

	@Override
	public void buttonClicked(Button button){
		if (button == master)
			MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getRequestPacket(PacketType.BIOME_SETTING, mod + ":Master"));
		if (button == biomes)
			MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getRequestPacket(PacketType.BIOME_LIST, "0" + mod));
		if (button == entities)
			MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getRequestPacket(PacketType.ENTITY_LIST, mod));
		if (button == eval)
			MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getRequestPacket(PacketType.BIOME_LIST, "1" + mod));
		
		setEnabled(false, master, biomes, entities, eval);
	}
	
	@Override
	protected void revalidateGui(){
		title.setPosition(width/2, height/4-30);
		close.setPosition(width/2-75, height/4 + 107);
		
		master.setPosition(width/2-50, height/4-5);
		biomes.setPosition(width/2-50,  height/4+20);
		entities.setPosition(width/2-50,height/4+45);
		eval.setPosition(width/2-50, height/4+70);
		
		container.revalidate(0,0,width,height);
	}

	@Override
	protected void createGui() {
		close = new ButtonVanilla(150,20,"Back",new CloseHandler());
		master = new ButtonVanilla(100, 20, "Master Settings", this);
		biomes = new ButtonVanilla(100,20,"By Biome", this);
		entities = new ButtonVanilla(100,20,"By Entity",this);
		eval = new ButtonVanilla(100,20,"Evaluated",this);

		title = new Label(mod + " Spawn Controls");

		container = new Container();
		container.addWidgets(close, master, biomes, entities, eval, title);
		containers.add(container);
	}

} public class EditBiomeScreen extends MSCScreen {

	private Label title, subTitle;
	private Button save, close, monster, creature, ambient, water;
	private Scrollbar scrollbar;
	private Checkbox enabled;
	private IntSlider weight, min, max;

	private Container masterContainer, labelContainer;
	private FocusableWidget lastFocused;

	private BiomeSettingPacket packet;

	private EntityEntry[][] entries;
	private int creatureType;

	public EditBiomeScreen(BiomeSettingPacket packet, GuiScreen parent) {
		super(parent);

		this.packet = packet;
		entries = packet.getOrderedEntries();
	}

	@Override
	public void drawBackground() {
		super.drawBackground();
		drawRect(labelContainer.left(),labelContainer.top(),labelContainer.right()-10,labelContainer.bottom(),0x44444444);
	}

	@Override
	public void updateScreen() {
		if (labelContainer.hasFocusedWidget()) {
			if (lastFocused == labelContainer.getFocusedWidget())
				updateEntrySettings();
			else
				updateGuiSettings();
		}
		else {
			lastFocused = null;
		}
		super.updateScreen();
	}
	
	@Override
	protected void unhandledKeyTyped(char c, int code) { 
		if (code == Keyboard.KEY_RETURN) {
			if (labelContainer.hasFocusedWidget() && labelContainer.getFocusedWidget() == lastFocused) {
				enabled.setChecked(!enabled.isChecked());
				updateEntrySettings();
			}
		}
		super.unhandledKeyTyped(c, code);
	}

	private void updateGuiSettings() {
		lastFocused = labelContainer.getFocusedWidget();
		FocusableLabel label = (FocusableLabel)lastFocused;
		EntityEntry e = (EntityEntry)label.getUserData();
		enabled.setChecked(e.weight > 0);
		weight.setIntValue(enabled.isChecked() ? e.weight : 4);
		min.setIntValue(e.min);
		max.setIntValue(e.max);
	}

	private void updateEntrySettings() {
		FocusableLabel label = (FocusableLabel)labelContainer.getFocusedWidget();
		EntityEntry e = (EntityEntry) label.getUserData();
		if (enabled.isChecked()) {
			e.weight = weight.getIntValue();
			e.min = min.getIntValue();
			e.max = max.getIntValue();
			label.setColor(ENABLED_COLOR);
			label.setHoverColor(ENABLED_HOVER);
			label.setFocusColor(ENABLED_FOCUS);
		}
		else {
			e.weight = 0;
			e.min = min.getIntValue();
			e.max = max.getIntValue();
			label.setColor(DIS_COLOR);
			label.setHoverColor(DIS_HOVER);
			label.setFocusColor(DIS_FOCUS);
		}
	}

	@Override
	protected void revalidateGui() {
		close.setPosition(width/2+6,height/4+135);
		save.setPosition(width/2-57, height/4+135);
		title.setPosition(width/2,height/4-48);
		subTitle.setPosition(width/2,height/4-32);

		enabled.setPosition(width/2 + 70, height/4+15);

		weight.setPosition(width/2 + 50, height/4 + 30);
		min.setPosition(width/2 + 50, height/4 + 55);
		max.setPosition(width/2 + 50, height/4 + 80);
		
		monster.setPosition(width/2-190, height/4+10);
		creature.setPosition(width/2-190, height/4+35);
		ambient.setPosition(width/2-190, height/4+60);
		water.setPosition(width/2-190, height/4+85);

		List<FocusableWidget> groups = labelContainer.getFocusableWidgets();
		for (int i = 0; i < groups.size(); ++i)
			groups.get(i).setPosition(width/2-50,height/4-11+i*14);

		scrollbar.setPosition(width/2+20,height/4-13);
		labelContainer.revalidate(width/2-120,height/4-13,150,143);
		masterContainer.revalidate(0, 0, width, height);
	}

	@Override
	protected void createGui() {
		masterContainer = new Container();
		title = new Label(packet.mod + " Controls");
		subTitle = new Label(packet.biome);
		close = new ButtonVanilla(50, 20, "Cancel", new CloseHandler());
		save = new ButtonVanilla(50, 20, "Save", this);
		enabled = new CheckboxVanilla("Enabled", true);

		weight = new IntSlider(100, 20, "Weight %d", 1, 1, 100);
		min = new IntSlider(100, 20, "Min %d", 1, 1, 10);
		max = new IntSlider(100, 20, "Max %d", 1, 1, 15);
		
		monster = new ButtonVanilla(60, 20, "Monster", this);
		creature = new ButtonVanilla(60, 20, "Creature", this);
		ambient = new ButtonVanilla(60, 20, "Ambient", this);
		water = new ButtonVanilla(60, 20, "Water", this);

		masterContainer.addWidgets(title, subTitle, enabled, weight, min, max, monster, creature, ambient, water, save, close);

		scrollbar = new ScrollbarVanilla(10);
		labelContainer = new FocusedContainer(scrollbar, 14, 4);

		creatureType = 0;
		EntityEntry[] monsterEntries = entries[creatureType];
		FocusableLabel[] labels = new FocusableLabel[monsterEntries.length];
		for (int i = 0; i < labels.length; ++i) {
			EntityEntry e = monsterEntries[i];
			if (e.weight != 0) //enabled
				labels[i] = new FocusableLabel(e.entity, ENABLED_COLOR, ENABLED_HOVER, ENABLED_FOCUS);
			else //disabled
				labels[i] = new FocusableLabel(e.entity, DIS_COLOR, DIS_HOVER, DIS_FOCUS);
			labels[i].setUserData(e);
		}

		labelContainer.addWidgets(labels);

		containers.add(labelContainer);
		containers.add(masterContainer);
		
		if (labelContainer.hasFocusedWidget())
			updateGuiSettings();

		selectedContainer = labelContainer;
	}


	@Override
	public void buttonClicked(Button button) {
		if (button == save) {
			save();
			close();
		}
		else {
			String type = button.getText().replace("Water", "WaterCreature");
			int index = MobHelper.typeOf(type).ordinal();
			if (index != creatureType) {
				EntityEntry[] curEntries = entries[index];
				FocusableLabel[] labels = new FocusableLabel[curEntries.length];
				labelContainer.removeFocusableWidgets();
				
				for (int i = 0; i < labels.length; ++i) {
					EntityEntry e = curEntries[i];
					if (e.weight != 0) //enabled
						labels[i] = new FocusableLabel(e.entity, ENABLED_COLOR, ENABLED_HOVER, ENABLED_FOCUS);
					else //disabled
						labels[i] = new FocusableLabel(e.entity, DIS_COLOR, DIS_HOVER, DIS_FOCUS);
					labels[i].setUserData(e);
					labels[i].setPosition(width/2 - 50, height/4 - 11 + i*14);
				}

				labelContainer.addWidgets(labels);
				creatureType = index;
				
				if (labelContainer.hasFocusedWidget())
					updateGuiSettings();
			}
		}
	}

	private void save() {
		EntityEntry[][] newEntries = new EntityEntry[4][];
		String[][] empty = new String[4][0];
		
		for (int index = 0; index < 4; ++index) {
			List<EntityEntry> entryList = new ArrayList<EntityEntry>();
			
			for (EntityEntry entry : entries[index])
				if (entry.weight > 0) {
					if (entry.min > entry.max) {
						int tmp = entry.min;
						entry.min = entry.max;
						entry.max = tmp;
					}
					entryList.add(entry);
				}
			
			newEntries[index] = entryList.toArray(new EntityEntry[0]);
		}
		
		MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getPacket(PacketType.BIOME_SETTING, packet.mod, packet.biome, newEntries, empty));
	}


} public class EditCreatureTypeScreen extends MSCScreen{

	private CreatureTypePacket packet;
	
	private Label title, arrow;
	private Button close, save, move;
	private Scrollbar scrollbar;
	
	private Container labelContainer, masterContainer, creatureContainer;
	
	private List<String> modifications;
	
	private boolean sent;
	
	public EditCreatureTypeScreen(CreatureTypePacket packet, GuiScreen parent) {
		super(parent);
		
		this.packet = packet;
		modifications = new ArrayList<String>();
	}
	
	@Override
	public void drawBackground() {
		super.drawBackground();
		drawRect(labelContainer.left(),labelContainer.top(),labelContainer.right()-15,labelContainer.bottom(),0x44444444);
		drawRect(creatureContainer.left(),creatureContainer.top(),creatureContainer.right(),creatureContainer.bottom(),0x44444444);
	}
	
	@Override
	public void updateScreen() {
		move.setEnabled(!sent && labelContainer.hasFocusedWidget());
		super.updateScreen();
	}
	
	@Override
	protected void revalidateGui() {
		scrollbar.setPosition(width/2+30,height/4-25);
		arrow.setPosition(width/2+58,height/4+47);
		title.setPosition(width/2-30,height/4-45);
		close.setPosition(width/2+5,height/4+130);
		save.setPosition(width/2-55,height/4+130);
		move.setPosition(width/2+120-25, height/4);
		
		List<FocusableWidget> entities = labelContainer.getFocusableWidgets();
		for (int i = 0; i < entities.size(); ++i) 
			entities.get(i).setPosition(width/2-30,height/4-23+i*14);
		
		List<FocusableWidget> types = creatureContainer.getFocusableWidgets();
		for (int i =0; i < types.size(); ++i)
			types.get(i).setPosition(width/2+120,height/4+27+i*14);
		
		creatureContainer.revalidate(width/2+80,height/4+25,80,58);
		labelContainer.revalidate(width/2-90,height/4-25,135,142);
		masterContainer.revalidate(0, 0, width, height);
	}

	@Override
	protected void createGui() {
		arrow = new Label("-->");
		title = new Label(packet.mod + " " + packet.creatureType +"s");
		save = new ButtonVanilla(50,20,"Save",new ButtonHandler(){
			public void buttonClicked(Button button) {
				setEnabled(false,save,move);
				sent = true;
				MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getPacket(PacketType.CREATURE_TYPE, 
						packet.mod, packet.creatureType, modifications.toArray(new String[0])));
				close();
			}
		});
		save.setEnabled(false);
		move = new ButtonVanilla(50, 20, "Move To", new ButtonHandler(){
			public void buttonClicked(Button button) {
				String s = ((FocusableLabel)labelContainer.deleteFocused()).getText() + ":" +
						((FocusableLabel)creatureContainer.getFocusedWidget()).getText();
				modifications.add(s);
				button.setEnabled(labelContainer.hasFocusedWidget());
				save.setEnabled(true);
			}
		});
		move.setEnabled(packet.mobs.length > 0);
		close = new ButtonVanilla(50,20,"Cancel",new CloseHandler());
		
		masterContainer = new Container();
		masterContainer.addWidgets(title, arrow, move, save, close);
		
		FocusableLabel[] labels = new FocusableLabel[packet.mobs.length];
		for (int i = 0; i < labels.length; ++i)
			labels[i] = new FocusableLabel(packet.mobs[i]);
		
		scrollbar = new ScrollbarVanilla(15);
		labelContainer = new FocusedContainer(scrollbar, 14, 4);
		labelContainer.addWidgets(labels);
		
		
		List<String> creatures = Utils.asList("Monster","Creature","Ambient","WaterCreature","None/Unknown");
		creatures.remove(packet.creatureType);
		String[] creatureNames = creatures.toArray(new String[0]);
		FocusableLabel[] creatureLabels = new FocusableLabel[creatureNames.length];
		for (int i = 0; i < creatureLabels.length; ++i)
			creatureLabels[i] = new FocusableLabel(creatureNames[i]);
		
		creatureContainer = new FocusedContainer();
		creatureContainer.addWidgets(creatureLabels);
		
		containers.add(labelContainer);
		containers.add(creatureContainer);
		containers.add(masterContainer);
		selectedContainer = labelContainer;
	}

} public class EditEntityScreen extends MSCScreen{
	
	public static final int ENABLED_COLOR = 0x49EC65, ENABLED_HOVER = 0x3CD5BC, ENABLED_FOCUS = 0xFF00;
	public static final int DIS_COLOR = 0xFA3333, DIS_HOVER = 0xEB489F, DIS_FOCUS = 0xFF0000;
	
	private Label title, subTitle;
	private Button save, close;
	private Scrollbar scrollbar;
	private Checkbox enabled;
	private IntSlider weight, min, max;
	
	private Container masterContainer, labelContainer;
	private FocusableWidget lastFocused;
	
	private EntitySettingPacket packet;
	
	public EditEntityScreen (EntitySettingPacket packet, GuiScreen parent) {
		super(parent);
		
		this.packet = packet;
	}
	
	@Override
	public void drawBackground() {
		super.drawBackground();
		drawRect(labelContainer.left(),labelContainer.top(),labelContainer.right()-10,labelContainer.bottom(),0x44444444);
	}
	
	@Override
	public void updateScreen() {
		if (lastFocused == labelContainer.getFocusedWidget())
			updateEntrySettings();
		else
			updateGuiSettings();
		super.updateScreen();
	}
	
	@Override
	protected void unhandledKeyTyped(char c, int code) { 
		if (code == Keyboard.KEY_RETURN) {
			if (labelContainer.getFocusedWidget() == lastFocused) {
				enabled.setChecked(!enabled.isChecked());
				updateEntrySettings();
			}
		}
		super.unhandledKeyTyped(c, code);
	}
	
	private void updateGuiSettings() {
		lastFocused = labelContainer.getFocusedWidget();
		FocusableLabel label = (FocusableLabel)lastFocused;
		BiomeEntry e = (BiomeEntry) label.getUserData();
		enabled.setChecked(e.weight > 0);
		weight.setIntValue(enabled.isChecked() ? e.weight : 4);
		min.setIntValue(e.min);
		max.setIntValue(e.max);
	}
	
	private void updateEntrySettings() {
		FocusableLabel label = (FocusableLabel)labelContainer.getFocusedWidget();
		BiomeEntry e = (BiomeEntry) label.getUserData();
		if (enabled.isChecked()) {
			e.weight = weight.getIntValue();
			e.min = min.getIntValue();
			e.max = max.getIntValue();
			label.setColor(ENABLED_COLOR);
			label.setHoverColor(ENABLED_HOVER);
			label.setFocusColor(ENABLED_FOCUS);
		}
		else {
			e.weight = 0;
			e.min = min.getIntValue();
			e.max = max.getIntValue();
			label.setColor(DIS_COLOR);
			label.setHoverColor(DIS_HOVER);
			label.setFocusColor(DIS_FOCUS);
		}
	}

	@Override
	protected void revalidateGui() {
		close.setPosition(width/2+6,height/4+135);
		save.setPosition(width/2-57, height/4+135);
		title.setPosition(width/2,height/4-48);
		subTitle.setPosition(width/2,height/4-32);
		
		enabled.setPosition(width/2 + 70, height/4+15);
		
		weight.setPosition(width/2 + 50, height/4 + 30);
		min.setPosition(width/2 + 50, height/4 + 55);
		max.setPosition(width/2 + 50, height/4 + 80);
		
		List<FocusableWidget> groups = labelContainer.getFocusableWidgets();
		for (int i = 0; i < groups.size(); ++i)
			groups.get(i).setPosition(width/2-50,height/4-11+i*14);
		
		scrollbar.setPosition(width/2+20,height/4-13);
		labelContainer.revalidate(width/2-120,height/4-13,150,143);
		masterContainer.revalidate(0, 0, width, height);
	}

	@Override
	protected void createGui() {
		BiomeEntry[] arr = packet.getOrderedEntries();
		
		masterContainer = new Container();
		title = new Label(packet.mod + " Controls");
		subTitle = new Label(packet.entity);
		close = new ButtonVanilla(50, 20, "Cancel", new CloseHandler());
		save = new ButtonVanilla(50, 20, "Save", this);
		
		enabled = new CheckboxVanilla("Enabled", true);
		
		weight = new IntSlider(100, 20, "Weight %d", 1, 1, 100);
		min = new IntSlider(100, 20, "Min %d", 1, 1, 10);
		max = new IntSlider(100, 20, "Max %d", 1, 1, 15);
		
		masterContainer.addWidgets(title, subTitle, enabled, weight, min, max, save, close);
		
		scrollbar = new ScrollbarVanilla(10);
		labelContainer = new FocusedContainer(scrollbar,14,4);
		
		FocusableLabel[] labels = new FocusableLabel[arr.length];
		for (int i = 0; i < labels.length; ++i) {
			BiomeEntry e = arr[i];
			if (e.weight != 0) //enabled
				labels[i] = new FocusableLabel(e.biome, ENABLED_COLOR, ENABLED_HOVER, ENABLED_FOCUS);
			else //disabled
				labels[i] = new FocusableLabel(e.biome, DIS_COLOR, DIS_HOVER, DIS_FOCUS);
			labels[i].setUserData(e);
		}
		
		labelContainer.addWidgets(labels);
		updateGuiSettings();

		containers.add(labelContainer);
		containers.add(masterContainer);
		
		selectedContainer = labelContainer;
	}
	
	@Override
	public void buttonClicked(Button b) {
		if (b == save) {
			save();
			close();
		}
	}
	
	private void save() {
		List<BiomeEntry> entries = new ArrayList<BiomeEntry>();
		List<String> empty = new ArrayList<String>();
		
		for (FocusableWidget w : labelContainer.getFocusableWidgets()) {
			BiomeEntry e = (BiomeEntry) ((FocusableLabel)w).getUserData();
			if (e.weight > 0) {
				if (e.min > e.max) {
					int tmp = e.min;
					e.min = e.max;
					e.max = tmp;
				}
				entries.add(e); 
			}
			else
				empty.add(e.biome);
		}
		MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getPacket( PacketType.ENTITY_SETTING, packet.mod, packet.entity, 
				entries.toArray(new BiomeEntry[0]), empty.toArray(new String[0])));
	}
} public class GroupsMenu extends MSCScreen{


	private Container masterContainer, labelContainer;
	private Scrollbar scrollbar;
	private Button save, close;
	private Button add, remove, rename, edit;
	private Label title;

	private GroupsPacket packet;

	private Map<String,String> groupMap;
	private List<String> groups, log;

	public GroupsMenu(GroupsPacket packet, GuiScreen parent) {
		super(parent);

		this.packet = packet;
		groupMap = new HashMap<String,String>();
		groups = new ArrayList<String>();
		log = new ArrayList<String>();
	}

	@Override
	public void updateScreen() {
		setEnabled(labelContainer.hasFocusedWidget(), remove, rename, edit);
		super.updateScreen();
	}

	@Override
	public void drawBackground() {
		super.drawBackground();
		drawRect(labelContainer.left(),labelContainer.top(),labelContainer.right()-10,labelContainer.bottom(),0x44444444);
	}

	@Override
	protected void revalidateGui() {
		scrollbar.setPosition(width/2+70,height/4-7);
		title.setPosition(width/2,height/4-30);
		save.setPosition(width/2-55,height/4+135);
		close.setPosition(width/2+5,height/4+135);
		add.setPosition(width/2-150,height/4);
		remove.setPosition(width/2-150,height/4+25);
		rename.setPosition(width/2+100,height/4);
		edit.setPosition(width/2+100,height/4+25);

		List<FocusableWidget> groups = labelContainer.getFocusableWidgets();
		for (int i = 0; i < groups.size(); ++i)
			groups.get(i).setPosition(width/2,height/4-5+i*14);


		labelContainer.revalidate(width/2-70,height/4-7,150,128);
		masterContainer.revalidate(0, 0, width, height);
	}

	@Override
	protected void createGui() {
		title = new Label(packet.mod + " Biome Groups");
		save = new ButtonVanilla(50,20,"Save",  new ButtonHandler(){
			public void buttonClicked(Button button) {
				String[] arr = new String[groups.size()];
				for (int i = 0; i < arr.length; ++i){
					String gName = groups.get(i);
					arr[i] = gName + '=' + groupMap.get(gName);
				}
				MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getPacket(PacketType.GROUPS, packet.mod, arr, log.toArray(new String[0])));
				close();
			}
		});
		close = new ButtonVanilla(50,20,"Cancel",new CloseHandler());
		add = new ButtonVanilla(50,20,"Add", this);
		remove = new ButtonVanilla(50,20,"Remove", this);
		rename = new ButtonVanilla(50,20,"Rename", this);
		edit = new ButtonVanilla(50,20,"Edit", this);
		save.setEnabled(false);
		setEnabled(packet.groups.length > 0, remove, rename, edit);

		scrollbar = new ScrollbarVanilla(10);
		labelContainer = new FocusedContainer(scrollbar,14,4);

		FocusableLabel[] labels = new FocusableLabel[packet.groups.length];
		for (int i = 0; i < labels.length; ++i){
			String group = packet.groups[i];
			int index = group.indexOf('=');
			String groupName = group.substring(0,index), groupDef = group.substring(index+1);
			groups.add(groupName);
			groupMap.put(groupName, groupDef);
			labels[i] = new FocusableLabel(width/2,height/4-5+i*14,groupName);
		}
		labelContainer.addWidgets(labels);

		masterContainer = new Container();
		masterContainer.addWidgets(title, add, remove, rename, edit, save, close);
		containers.add(labelContainer);
		containers.add(masterContainer);
		selectedContainer = labelContainer;
	}

	@Override
	public void buttonClicked(Button button) {
		if (button == add)
			mc.displayGuiScreen(new GroupPopup(this,groupMap.keySet()));
		if (button == remove){
			String group = ((FocusableLabel)labelContainer.getFocusedWidget()).getText();
			mc.displayGuiScreen(new PopupYesNo(this,"Yes","Cancel",new YesNoHandler(){
				public void handleExit(boolean yes) {
					if (yes){
						String s= ((FocusableLabel)labelContainer.deleteFocused()).getText();
						//LOG IT
						log.add("del," + s);
						removeReferences(s);
						setEnabled(labelContainer.hasFocusedWidget(), remove, rename, edit);
						save.setEnabled(true);
					}
				}
			},"",group,"","Are you sure you want to remove this group?","","Deleting a group is permanent!"));
		}
		if (button == rename)
			mc.displayGuiScreen(new GroupPopup(this,((FocusableLabel)labelContainer.getFocusedWidget()).getText(),
					groupMap.keySet()));
		if (button == edit){
			String group = ((FocusableLabel)labelContainer.getFocusedWidget()).getText();
			mc.displayGuiScreen(new EditGroupScreen(this, group, groupMap.get(group), getUnused(group)));
		}

	}

	private List<String> getUnused(String group) {
		List<String> list = new ArrayList<String>();
		//Add groups that come before this one
		for (int i = 0; i < groups.indexOf(group); ++i)
			list.add(groups.get(i));
		//Add all biomes
		for (String s : packet.biomeNames)
			list.add(s);
		//Now remove all groups/biomes in the definition
		String defString = groupMap.get(group);
		if (!defString.isEmpty()) {
			String[] def = defString.split(",");
			for (String s : def) 
				if (s.charAt(0) != '*')
					list.remove(s.substring(1));
		}

		return list;
	}

	private void removeReferences(String group) {
		groups.remove(group);
		groupMap.remove(group);

		for (Entry<String,String> entry : groupMap.entrySet()) { 
			String[] ops = entry.getValue().split(",");
			boolean hasPrev = false;
			StringBuilder sb = new StringBuilder();
			for (String s : ops) {
				if (!s.isEmpty()) { 
					char c = s.charAt(0);
					if (c != '*') {
						String gb = s.substring(1);
						if (!gb.equalsIgnoreCase(group)) {
							if(hasPrev)
								sb.append(',');
							sb.append(c + gb);
							hasPrev = true;
						}
					}
					else {
						hasPrev = true;
						sb.append('*');
					}
				}
			}
			entry.setValue(sb.toString());
		}
	}

	public void addGroup(String group) {
		//LOG IT
		log.add("add," + group);
		groups.add(group);
		groupMap.put(group, "");
		int i = labelContainer.getFocusableWidgets().size();
		labelContainer.addWidgets(new FocusableLabel(width/2,height/4-5+i*14,group));
		save.setEnabled(true);
	}
	
	public void updateDefinition(String group, String definition) {
		groupMap.put(group, definition);
		save.setEnabled(true);
	}

	public void renameGroup(String group, String newName) {
		//LOG IT
		log.add("ren," + group + "," + newName);
		//Remove map entry
		String def = groupMap.remove(group);

		//Update References
		for (Entry<String,String> entry : groupMap.entrySet()) { 
			String[] ops = entry.getValue().split(",");
			boolean hasPrev = false;
			StringBuilder sb = new StringBuilder();
			for (String s : ops) {
				if (!s.isEmpty()) {  // For each string
					char c = s.charAt(0);
					if (c != '*') {
						String gb = s.substring(1);
						if (gb.equalsIgnoreCase(group))
							gb = newName;
						if(hasPrev)
							sb.append(',');
						sb.append(c + gb);
						hasPrev = true;
					}
					else {
						hasPrev = true;
						sb.append('*');
					}
				}
			}
			entry.setValue(sb.toString());
		}
		//Update GUI Label
		for (FocusableWidget w : labelContainer.getFocusableWidgets()){
			FocusableLabel l = ((FocusableLabel)w);
			if (l.getText().equalsIgnoreCase(group)){
				l.setText(newName);
				break;
			}
		}
		//Add new group
		groups.set(groups.indexOf(group), newName);
		groupMap.put(newName, def);

		save.setEnabled(true);
	}

} public class SettingsScreen extends MSCScreen {
	
	private Container container;
	private Button close, save;
	private Label title, cap, freqLabel;
	private IntSlider mon, cre, amb, wat;
	private Checkbox readOnly, masterEnabled;
	private TextField creatureFreq;
	
	private final SettingsPacket packet;
	
	public SettingsScreen(SettingsPacket packet, GuiScreen parent) {
		super(parent);
		
		this.packet = packet;
	}

	@Override
	protected void revalidateGui() {
		save.setPosition(width/2-55,height/4+132);
		close.setPosition(width/2+5, height/4+132);
		title.setPosition(width/2, height/4-40);
		readOnly.setPosition(width/2+19, height/4+50);
		masterEnabled.setPosition(width/2+19, height/4+65);
		freqLabel.setPosition(width/2+50, height/4-10);
		creatureFreq.setPosition(width/2+35, height/4+5);
		
		cap.setPosition(width/2-55, height/4-10);
		mon.setPosition(width/2-105,height/4+10);
		cre.setPosition(width/2-105,height/4+35);
		amb.setPosition(width/2-105,height/4+60);
		wat.setPosition(width/2-105,height/4+85);
		
		container.revalidate(0,0,width,height);
	}

	@Override
	protected void createGui() {
		save = new ButtonVanilla(50,20,"Save",new ButtonHandler(){
			@Override
			public void buttonClicked(Button button) {
				button.setEnabled(false);
				save();
				close();
			}
		});
		close = new ButtonVanilla(50,20,"Cancel",new CloseHandler());
		title = new Label("MSC Settings");
		readOnly = new CheckboxVanilla("Read Only", packet.readOnly);
		masterEnabled = new CheckboxVanilla("Master Enabled", packet.masterEnabled);
		freqLabel = new Label("Creature Freq", new Tooltip("Gap between creature spawns"));
		creatureFreq = new TextFieldVanilla(30, 20, new NumberFilter());
		creatureFreq.setMaxLength(3);
		creatureFreq.setText("" + packet.creatureFreq);
		
		cap = new Label("Spawn Caps");
		mon = new IntSlider(100,20,"Monster %d",packet.caps[0],1,200);
		cre = new IntSlider(100,20,"Creature %d",packet.caps[1],1,200);
		amb = new IntSlider(100,20,"Ambient %d",packet.caps[2],1,200);
		wat = new IntSlider(100,20,"Water %d",packet.caps[3],1,200);
		
		container = new Container();
		container.addWidgets(close, save, mon, cre, amb, wat, readOnly, masterEnabled, creatureFreq, freqLabel, title, cap);
		containers.add(container);
		selectedContainer = container;
	}

	private void save() {
		int[] caps = new int[] { mon.getIntValue(), cre.getIntValue(), amb.getIntValue(), wat.getIntValue() };
		int cFreq = Utils.parseIntDMinMax(creatureFreq.getText(), packet.creatureFreq, 1, 400);
		MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getPacket(PacketType.SETTINGS, readOnly.isChecked(), masterEnabled.isChecked(), caps, cFreq));
	}
} public class BiomeListScreen extends MSCScreen{

	private Label title, subTitle;
	private Button select, close, biomes, groups;
	private Scrollbar scrollbar;
	private Container masterContainer, labelContainer;

	private BiomeListPacket packet;

	public BiomeListScreen(BiomeListPacket packet, GuiScreen parent) {
		super(parent);

		this.packet = packet;
	}

	@Override
	public void drawBackground() {
		super.drawBackground();
		drawRect(labelContainer.left(),labelContainer.top(),labelContainer.right()-10,labelContainer.bottom(),0x44444444);
	}

	@Override
	protected void reopenedGui(){
		select.setEnabled(true);
	}

	@Override
	protected void revalidateGui() {
		groups.setPosition(width/2+10, height/4-33);
		biomes.setPosition(width/2-60, height/4-33);
		
		close.setPosition(width/2+6,height/4+136);
		select.setPosition(width/2-57, height/4+136);
		
		title.setPosition(width/2,height/4-58);
		subTitle.setPosition(width/2,height/4-46);

		scrollbar.setPosition(width/2+70,height/4-10);

		List<FocusableWidget> groups = labelContainer.getFocusableWidgets();
		for (int i = 0; i < groups.size(); ++i)
			groups.get(i).setPosition(width/2,height/4-8+i*14);

		labelContainer.revalidate(width/2-70,height/4-10,150,143);
		masterContainer.revalidate(0, 0, width, height);
	}

	@Override
	protected void createGui() {
		masterContainer = new Container();
		title = new Label(packet.mod + " Controls");
		subTitle = new Label((packet.evalRequest ? "Evaluated Biomes" : "By Biome"));
		
		groups = new ButtonVanilla(50, 20, "Groups", this);
		groups.setEnabled(packet.groups.length > 0);
		biomes = new ButtonVanilla(50, 20, "Biomes", this);
		
		
		close = new ButtonVanilla(50, 20, "Back", new CloseHandler());
		select = new ButtonVanilla(50, 20, (packet.evalRequest ? "View" : "Edit"), this);

		masterContainer.addWidgets(title, subTitle, biomes, groups, select, close);

		scrollbar = new ScrollbarVanilla(10);
		labelContainer = new FocusedContainer(scrollbar, 14, 4);
		FocusableLabel[] labels = new FocusableLabel[packet.biomes.length];
		for (int i = 0; i < labels.length; ++i)
			labels[i] = new FocusableLabel(packet.biomes[i]);
		labelContainer.addWidgets(labels);

		containers.add(labelContainer);
		containers.add(masterContainer);

		selectedContainer = labelContainer;
	}

	public void buttonClicked(Button button) {
		if (button == groups) {
			labelContainer.removeFocusableWidgets();
			FocusableLabel[] labels = new FocusableLabel[packet.groups.length];
			for (int i = 0; i < labels.length; ++i)
				labels[i] = new FocusableLabel(width/2,height/4-8+i*14,packet.groups[i]);
			labelContainer.addWidgets(labels);
			subTitle.setText((packet.evalRequest ? "Evaluated Groups" : "By Group"));
		}
		if (button == biomes) {
			labelContainer.removeFocusableWidgets();
			FocusableLabel[] labels = new FocusableLabel[packet.biomes.length];
			for (int i = 0; i < labels.length; ++i)
				labels[i] = new FocusableLabel(width/2,height/4-8+i*14,packet.biomes[i]);
			labelContainer.addWidgets(labels);
			subTitle.setText((packet.evalRequest ? "Evaluated Biomes" : "By Biome"));
		}
		if (button == select) {
			button.setEnabled(false);
			String selected = ((FocusableLabel)labelContainer.getFocusedWidget()).getText();
			
			if (packet.evalRequest) {
				if (selected.contains(".")) //Biome
					MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getRequestPacket(PacketType.EVALUATED_BIOME, packet.mod + ':' + selected));
				else  //Group
					MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getRequestPacket(PacketType.EVALUATED_GROUP, packet.mod + ':' + selected));
			}
			else
				MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getRequestPacket(PacketType.BIOME_SETTING, packet.mod + ':' + selected));
		}
	}

} public class EntityListScreen extends MSCScreen{

	private Label title, subTitle;
	private Button select, close, monster, creature, ambient, water;
	private Scrollbar scrollbar;
	private Container masterContainer, labelContainer;
	
	private EntityListPacket packet;
	private String curType;
	private boolean sent;
	
	public EntityListScreen(EntityListPacket packet, GuiScreen parent) {
		super(parent);
		
		this.packet = packet;
	}
	
	@Override
	public void drawBackground() {
		super.drawBackground();
		drawRect(labelContainer.left(),labelContainer.top(),labelContainer.right()-10,labelContainer.bottom(),0x44444444);
	}
	
	@Override
	public void updateScreen() {
		select.setEnabled(!sent && labelContainer.hasFocusedWidget());
		super.updateScreen();
	}
	
	@Override
	protected void reopenedGui(){
		sent = false;
	}
	
	@Override
	protected void revalidateGui() {
		close.setPosition(width/2+6,height/4+135);
		select.setPosition(width/2-57, height/4+135);
		title.setPosition(width/2,height/4-45);
		subTitle.setPosition(width/2,height/4-30);
		
		monster.setPosition(width/2-130, height/4-10);
		creature.setPosition(width/2-65, height/4-10);
		ambient.setPosition(width/2, height/4-10);
		water.setPosition(width/2+65, height/4-10);
		
		scrollbar.setPosition(width/2+70,height/4+15);
		
		List<FocusableWidget> groups = labelContainer.getFocusableWidgets();
		for (int i = 0; i < groups.size(); ++i)
			groups.get(i).setPosition(width/2,height/4+17+i*14);
		
		labelContainer.revalidate(width/2-70,height/4+15,150,115);
		masterContainer.revalidate(0, 0, width, height);
	}

	@Override
	protected void createGui() {
		masterContainer = new Container();
		title = new Label(packet.mod + " Controls");
		subTitle = new Label("By Entity");
		close = new ButtonVanilla(50, 20, "Back", new CloseHandler());
		select = new ButtonVanilla(50, 20, "Edit", this);
		select.setEnabled(false);
		
		monster = new ButtonVanilla(60, 20, "Monster", this);
		creature = new ButtonVanilla(60, 20, "Creature", this);
		ambient = new ButtonVanilla(60, 20, "Ambient", this);
		water = new ButtonVanilla(60, 20, "Water", this);
		
		masterContainer.addWidgets(monster, creature, ambient, water, title, subTitle, select, close);
		
		scrollbar = new ScrollbarVanilla(10);
		labelContainer = new Container(scrollbar,14,4);
		
		containers.add(labelContainer);
		containers.add(masterContainer);
	}
	
	@Override
	public void buttonClicked(Button button) {
		if (button == select) {
			sent = true;
			String selectedObj = ((FocusableLabel)labelContainer.getFocusedWidget()).getText();
			MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getRequestPacket(PacketType.ENTITY_SETTING, packet.mod + ':' + selectedObj));
		}
		else { //CreatureType button
			String type = button.getText().replace("Water", "WaterCreature");
			if (!type.equalsIgnoreCase(curType)) {
				int index = MobHelper.typeOf(type).ordinal();
				String[] entities = packet.entities[index];
				FocusableLabel[] labels = new FocusableLabel[entities.length];
				labelContainer.removeFocusableWidgets();
				for (int i = 0; i < entities.length; ++i)
					labels[i] = new FocusableLabel(width/2,height/4+17+i*14, entities[i]);

				labelContainer.addWidgets(labels);
				curType = type;
			}
		}
	}

} public class EvaluatedBiomeScreen extends MSCScreen {

	private Label title, subTitle;
	private Button close, monster, creature, ambient, water;
	private Scrollbar scrollbar;
	private Container masterContainer, labelContainer;

	private EvaluatedBiomePacket packet;
	
	private String curType;

	public EvaluatedBiomeScreen(EvaluatedBiomePacket packet, GuiScreen parent) {
		super(parent);

		this.packet = packet;
	}

	@Override
	public void drawBackground() {
		super.drawBackground();
		drawRect(labelContainer.left(),labelContainer.top(),labelContainer.right()-10,labelContainer.bottom(),0x44444444);
	}

	@Override
	protected void revalidateGui() {
		close.setPosition(width/2-50,height/4+135);
		title.setPosition(width/2,height/4-45);
		subTitle.setPosition(width/2,height/4-30);

		monster.setPosition(width/2-130, height/4-10);
		creature.setPosition(width/2-65, height/4-10);
		ambient.setPosition(width/2, height/4-10);
		water.setPosition(width/2+65, height/4-10);

		scrollbar.setPosition(width/2+70,height/4+15);

		List<FocusableWidget> groups = labelContainer.getFocusableWidgets();
		for (int i = 0; i < groups.size(); ++i)
			groups.get(i).setPosition(width/2,height/4+17+i*14);

		labelContainer.revalidate(width/2-70,height/4+15,150,115);
		masterContainer.revalidate(0, 0, width, height);
	}

	@Override
	protected void createGui() {
		masterContainer = new Container();
		title = new Label(packet.mod + " Controls");
		subTitle = new Label("Evaluated Biome \"" + packet.biome + "\"");
		close = new ButtonVanilla(100, 20, "Back", new CloseHandler());

		monster = new ButtonVanilla(60, 20, "Monster", this);
		creature = new ButtonVanilla(60, 20, "Creature", this);
		ambient = new ButtonVanilla(60, 20, "Ambient", this);
		water = new ButtonVanilla(60, 20, "Water", this);

		masterContainer.addWidgets(monster, creature, ambient, water, title, subTitle, close);

		scrollbar = new ScrollbarVanilla(10);
		labelContainer = new Container(scrollbar, 14, 4);

		containers.add(labelContainer);
		containers.add(masterContainer);
	}

	@Override
	public void buttonClicked(Button button) {
		//CreatureType button
		String type = button.getText().replace("Water", "WaterCreature");
		if (!type.equalsIgnoreCase(curType)) {
			int index = MobHelper.typeOf(type).ordinal();
			String[] entities = packet.entities[index];
			FocusableLabel[] labels = new FocusableLabel[entities.length];
			labelContainer.removeFocusableWidgets();
			for (int i = 0; i < entities.length; ++i)
				labels[i] = new FocusableLabel(width/2,height/4+17+i*14, entities[i]);

			labelContainer.addWidgets(labels);
			curType = type;
		}

	}

} public class EvaluatedGroupsScreen extends MSCScreen {
	
	private Label title, subTitle;
	private Button close;
	private Scrollbar scrollbar;
	private Container masterContainer, labelContainer;
	
	
	private EvaluatedGroupPacket packet;

	public EvaluatedGroupsScreen(EvaluatedGroupPacket packet, GuiScreen parent) {
		super(parent);
		
		this.packet = packet;
	}
	
	@Override
	public void drawBackground() {
		super.drawBackground();
		drawRect(labelContainer.left(), labelContainer.top(), labelContainer.right()-10, labelContainer.bottom(), 0x44444444);
	}

	@Override
	protected void revalidateGui() {
		title.setPosition(width/2,height/4-50);
		subTitle.setPosition(width/2,height/4-30);
		close.setPosition(width/2-50,height/4+136);
		
		scrollbar.setPosition(width/2+70,height/4-14);

		List<FocusableWidget> groups = labelContainer.getFocusableWidgets();
		for (int i = 0; i < groups.size(); ++i)
			groups.get(i).setPosition(width/2,height/4-12 + i*14);

		labelContainer.revalidate(width/2-70, height/4-14, 150, 143);
		masterContainer.revalidate(0, 0, width, height);
	}

	@Override
	protected void createGui() {
		masterContainer = new Container();
		title = new Label(packet.mod + " Controls");
		subTitle = new Label("Evaluated Group \"" + packet.group + "\"");
		close = new ButtonVanilla(100, 20, "Back", new CloseHandler());
		
		masterContainer.addWidgets(title, subTitle, close);
		
		scrollbar = new ScrollbarVanilla(10);
		labelContainer = new FocusedContainer(scrollbar, 14, 4);
		FocusableLabel[] labels = new FocusableLabel[packet.biomes.length];
		for (int i = 0; i < labels.length; ++i)
			labels[i] = new FocusableLabel(packet.biomes[i]);
		labelContainer.addWidgets(labels);
		
		containers.add(labelContainer);
		containers.add(masterContainer);

		selectedContainer = labelContainer;
	}

} public class ModListScreen extends MSCScreen{

	private ModListPacket packet;

	private Label title;
	private FocusableLabel[] labels;
	private Button close, controls, types, groups;
	private Scrollbar scrollbar;
	private Container labelContainer, masterContainer;
	
	
	public ModListScreen(ModListPacket packet, GuiScreen parent) {
		super(parent);

		this.packet = packet;
	}

	@Override
	protected void revalidateGui() {
		scrollbar.setPosition(width/2+50,height/4-7);
		controls.setPosition(width/2-50,height/4+106);
		groups.setPosition(width/2-155,height/4+106);
		types.setPosition(width/2+55,height/4+106);
		close.setPosition(width/2-50,height/4+132);
		title.setPosition(width/2,height/4-30);
		
		for (int i = 0; i < labels.length; ++i)
			labels[i].setPosition(width/2,height/4-5+i*14);
		
		labelContainer.revalidate(width/2-50,height/4-7,110,100);
		masterContainer.revalidate(0, 0, width, height);
	}
	
	@Override
	public void drawBackground() {
		super.drawBackground();
		drawRect(labelContainer.left(),labelContainer.top(),labelContainer.right()-10,labelContainer.bottom(),0x44444444);
	}


	@Override
	protected void createGui() {
		title = new Label("Mod Select");
		controls = new ButtonVanilla(100,20,"Spawn Controls", this);
		groups = new ButtonVanilla(100,20,"Biome Groups", this);
		types = new ButtonVanilla(100,20,"Mob Types", this);
		
		close = new ButtonVanilla(100,20,"Back",new CloseHandler());
		
		labels = new FocusableLabel[packet.mods.length];
		for (int i = 0; i < labels.length; ++i)
			labels[i] = new FocusableLabel(packet.mods[i]);

		scrollbar = new ScrollbarVanilla(10);
		labelContainer = new FocusedContainer(scrollbar, 14, 4);
		masterContainer = new Container();
		masterContainer.addWidgets(title, controls, groups, types, close);
		labelContainer.addWidgets(labels);
		containers.add(labelContainer);
		containers.add(masterContainer);
		selectedContainer = labelContainer;
	}
	
	@Override
	protected void reopenedGui(){
		setEnabled(true, controls, groups, types);
	}
	
	@Override
	public void buttonClicked(Button button) {
		setEnabled(false, controls, groups, types);
		String mod = ((FocusableLabel)labelContainer.getFocusedWidget()).getText();
		if (button == types)
			mc.displayGuiScreen(new MobTypesMenu(mod, this));
		if (button == controls)
			mc.displayGuiScreen(new SpawnControlMenu(mod, this));
		if (button == groups)
			MobSpawnControls.DISPATCHER.sendToServer(MSCPacket.getRequestPacket(PacketType.GROUPS, mod));
	}
	
} public class BiomeListPacket extends MSCPacket{
	
	public boolean evalRequest;
	public String mod;
	public String[] groups, biomes;

	@Override
	public MSCPacket readData(Object... data) {
		evalRequest = (Boolean) data[0];
		mod = (String) data[1];
		groups = (String[]) data[2];
		biomes = (String[]) data[3];
		return this;
	}
	
	@Override
	public void encodeInto(ChannelHandlerContext ctx, ByteBuf to) throws IOException { 
		to.writeBoolean(evalRequest);
		writeString(mod, to);
		writeStringArray(groups, to);
		writeStringArray(biomes, to);
	}

	@Override
	public void decodeFrom(ChannelHandlerContext ctx, ByteBuf from) throws IOException {
		evalRequest = from.readBoolean();
		mod = readString(from);
		groups = readStringArray(from);
		biomes = readStringArray(from);
	}

	@Override
	public void execute(MSCPacketHandler handler, EntityPlayer player) {
		handler.handleBiomeList(this, player);
	}

} public class CreatureTypePacket extends MSCPacket {

	public String mod;
	public String creatureType;
	public String[] mobs;

	@Override
	public MSCPacket readData(Object... data) {
		mod = (String) data[0];
		creatureType = (String) data[1];
		mobs = (String[]) data[2];
		return this;
	}
	
	@Override
	public void encodeInto(ChannelHandlerContext ctx, ByteBuf to) throws IOException { 
		writeString(mod, to);
		writeString(creatureType, to);
		writeStringArray(mobs, to);
	}

	@Override
	public void decodeFrom(ChannelHandlerContext ctx, ByteBuf from) throws IOException {
		mod = readString(from);
		creatureType = readString(from);
		mobs = readStringArray(from);
	}

	@Override
	public void execute(MSCPacketHandler handler, EntityPlayer player) {
		handler.handleCreatureType(this, player);
	}

} public class DebugPacket extends MSCPacket {

	public String[] log;
	
	@Override
	public MSCPacket readData(Object... data) {
		log = (String[]) data[0];
		return this;
	}
	
	@Override
	public void encodeInto(ChannelHandlerContext ctx, ByteBuf to) throws IOException { 
		writeStringArray(log, to);
	}

	@Override
	public void decodeFrom(ChannelHandlerContext ctx, ByteBuf from) throws IOException {
		log = readStringArray(from);
	}

	@Override
	public void execute(MSCPacketHandler handler, EntityPlayer player) {
		handler.handleDebug(this, player);
	}

} public class EntityListPacket extends MSCPacket{

	public String mod;
	public String[][] entities;

	@Override
	public MSCPacket readData(Object... data) {
		mod = (String) data[0];
		entities = (String[][]) data[1];
		return this;
	}
	
	@Override
	public void encodeInto(ChannelHandlerContext ctx, ByteBuf to) throws IOException { 
		writeString(mod, to);
		for (int i = 0; i < 4; ++i)
			writeStringArray(entities[i], to);
	}

	@Override
	public void decodeFrom(ChannelHandlerContext ctx, ByteBuf from) throws IOException {
		mod = readString(from);
		entities = new String[4][];
		for (int i = 0; i < 4; ++i)
			entities[i] = readStringArray(from);
	}

	@Override
	public void execute(MSCPacketHandler handler, EntityPlayer player) {
		handler.handleEntityList(this, player);
	}

} public class GroupsPacket extends MSCPacket {

	public String mod;
	public String[] groups;
	public String[] biomeNames;

	@Override
	public MSCPacket readData(Object... data) {
		mod = (String) data[0];
		groups = (String[]) data[1];
		biomeNames = (String[]) data[2];
		return this;
	}
	
	@Override
	public void encodeInto(ChannelHandlerContext ctx, ByteBuf to) throws IOException { 
		writeString(mod, to);
		writeStringArray(groups, to);
		writeStringArray(biomeNames, to);
	}

	@Override
	public void decodeFrom(ChannelHandlerContext ctx, ByteBuf from) throws IOException {
		mod = readString(from);
		groups = readStringArray(from);
		biomeNames = readStringArray(from);
	}

	@Override
	public void execute(MSCPacketHandler handler, EntityPlayer player) {
		handler.handleGroups(this, player);
	}

} public enum PacketType{

	HANDSHAKE(HSPacket.class),
	ACCESS_DENIED(ADPacket.class),
	REQUEST(RequestPacket.class),
	MOD_LIST(ModListPacket.class),
	GROUPS(GroupsPacket.class),
	CREATURE_TYPE(CreatureTypePacket.class),
	BIOME_LIST(BiomeListPacket.class),
	BIOME_SETTING(BiomeSettingPacket.class),
	ENTITY_LIST(EntityListPacket.class),
	ENTITY_SETTING(EntitySettingPacket.class),
	SETTINGS(SettingsPacket.class),
	EVALUATED_BIOME(EvaluatedBiomePacket.class),
	EVALUATED_GROUP(EvaluatedGroupPacket.class),
	DEBUG(DebugPacket.class);

	private Class<? extends MSCPacket> packetType;

	private PacketType(Class<? extends MSCPacket> cls) {
		this.packetType = cls;
	}

	private MSCPacket make() {
		try {
			return packetType.newInstance();
		} catch (Exception e) {
			MobSpawnControls.getLogger().severe("Error during packet creation");
			throw new RuntimeException(e);
		}
	}
		
	public static int ordinalForClass(Class<? extends MSCPacket> cls) throws IllegalArgumentException {
		PacketType[] values = PacketType.values();
		for (int i = 0; i < values.length; ++i)
			if (values[i].packetType == cls)
				return i;
		throw new IllegalArgumentException("Unknown class " + cls);
	}
} public class ModListPacket extends MSCPacket {

	public String[] mods;

	@Override
	public MSCPacket readData(Object... data) {
		mods = (String[]) data[0];
		return this;
	}
	
	@Override
	public void encodeInto(ChannelHandlerContext ctx, ByteBuf to) throws IOException { 
		writeStringArray(mods, to);
	}

	@Override
	public void decodeFrom(ChannelHandlerContext ctx, ByteBuf from) throws IOException {
		mods = readStringArray(from);
	}

	@Override
	public void execute(MSCPacketHandler handler, EntityPlayer player) {
		handler.handleModList(this, player);
	}

} public class BiomeSettingPacket extends MSCPacket {

	public String mod;
	public String biome;
	public EntityEntry[][] entries;
	public String[][] disabled;

	@Override
	public MSCPacket readData(Object... data) {
		mod = (String) data[0];
		biome = (String) data[1];
		entries = (EntityEntry[][]) data[2];
		disabled = (String[][]) data[3];
		return this;
	}
	
	@Override
	public void encodeInto(ChannelHandlerContext ctx, ByteBuf to) throws IOException {
		writeString(mod, to);
		writeString(biome, to);
		for (int i = 0; i < 4; ++i) {
			EntityEntry[] entities = entries[i];
			to.writeInt(entities.length);
			
			for (EntityEntry e : entities) {
				writeString(e.entity, to);
				to.writeInt(e.weight);
				to.writeInt(e.min);
				to.writeInt(e.max);
			}
		}
		for (int i = 0; i < 4; ++i)
			writeStringArray(disabled[i], to);
	}

	@Override
	public void decodeFrom(ChannelHandlerContext ctx, ByteBuf from) throws IOException { 
		mod = readString(from);
		biome = readString(from);
		entries = new EntityEntry[4][];
		for (int i = 0; i < 4; ++i) {
			entries[i] = new EntityEntry[from.readInt()];
			for (int j = 0; j < entries[i].length; ++j)
				entries[i][j] = new EntityEntry(readString(from), from.readInt(), from.readInt(), from.readInt());
		}
		disabled = new String[4][];
		for (int i = 0; i < 4; ++i)
			disabled[i] = readStringArray(from);
	}

	public EntityEntry[][] getOrderedEntries() {
		EntityEntry[][] allEntries = new EntityEntry[4][];
		for (int index = 0; index < 4; ++index) {
			EntityEntry[] curEntries = new EntityEntry[entries[index].length + disabled[index].length];
			
			for (int i = 0; i < entries[index].length; ++i)
				curEntries[i] = entries[index][i];
			for (int i = 0; i < disabled[index].length; ++i)
				curEntries[entries[index].length + i] = new EntityEntry(disabled[index][i]);
			Arrays.sort(curEntries, new Comparator<EntityEntry>() {
				public int compare(EntityEntry a, EntityEntry b) {
					return a.entity.compareTo(b.entity);
				}
			});
			allEntries[index] = curEntries;
		}
		return allEntries;
	}

	@Override
	public void execute(MSCPacketHandler handler, EntityPlayer player) {
		handler.handleBiomeSetting(this, player);
	}

	public static class EntityEntry {

		public String entity;
		public int weight;
		public int min;
		public int max;

		public EntityEntry(String entity) {
			this.entity = entity;
			min = 4;
			max = 4;
		}

		public EntityEntry(String entity, int w, int min, int max) {
			this.entity = entity;
			this.weight = w;
			this.min = min;
			this.max = max;
		}

	}

} public class EntitySettingPacket extends MSCPacket {

	public String mod;
	public String entity;
	public BiomeEntry[] entries;
	public String[] disabled;
	
	@Override
	public MSCPacket readData(Object... data) {
		mod = (String) data[0];
		entity = (String) data[1];
		entries = (BiomeEntry[]) data[2];
		disabled = (String[]) data[3];
		return this;
	}
	
	@Override
	public void encodeInto(ChannelHandlerContext ctx, ByteBuf to) throws IOException { 
		writeString(mod, to);
		writeString(entity, to);
		
		to.writeInt(entries.length);
		for (BiomeEntry e : entries) {
			writeString(e.biome, to);
			to.writeInt(e.weight);
			to.writeInt(e.min);
			to.writeInt(e.max);
		}
		writeStringArray(disabled, to);
	}

	@Override
	public void decodeFrom(ChannelHandlerContext ctx, ByteBuf from) throws IOException { 
		mod = readString(from);
		entity = readString(from);
		
		entries = new BiomeEntry[from.readInt()];
		for (int i = 0; i < entries.length; ++i)
			entries[i] = new BiomeEntry(readString(from), from.readInt(), from.readInt(), from.readInt());
		disabled = readStringArray(from);
	}
	
	public BiomeEntry[] getOrderedEntries() {
		BiomeEntry[] allEntries = new BiomeEntry[entries.length + disabled.length];
		for (int i = 0; i < entries.length; ++i)
			allEntries[i] = entries[i];
		for (int i = 0; i < disabled.length; ++i)
			allEntries[entries.length + i] = new BiomeEntry(disabled[i]);
		Arrays.sort(allEntries, new Comparator<BiomeEntry>() {
			public int compare(BiomeEntry a, BiomeEntry b) {
				return a.biome.compareTo(b.biome);
			}
		});
		return allEntries;
	}

	@Override
	public void execute(MSCPacketHandler handler, EntityPlayer player) {
		handler.handleEntitySetting(this, player);
	}

	public static class BiomeEntry {
		public String biome;
		public int weight;
		public int min;
		public int max;
		
		public BiomeEntry (String biome) {
			this.biome = biome;
			min = 4;
			max = 4;
		}
		
		public BiomeEntry(String biome, int w, int min, int max) {
			this.biome = biome;
			this.weight = w;
			this.min = min;
			this.max = max;
		}
		
	}
} public class EvaluatedBiomePacket extends MSCPacket {
	
	public String mod;
	public String biome;
	public String[][] entities;

	@Override
	public MSCPacket readData(Object... data) {
		mod = (String) data[0];
		biome = (String) data[1];
		entities = (String[][]) data[2];
		return this;
	}
	
	@Override
	public void encodeInto(ChannelHandlerContext ctx, ByteBuf to) throws IOException { 
		writeString(mod, to);
		writeString(biome, to);
		for (int i = 0; i < 4; ++i)
			writeStringArray(entities[i], to);
	}

	@Override
	public void decodeFrom(ChannelHandlerContext ctx, ByteBuf from) throws IOException { 
		mod = readString(from);
		biome = readString(from);
		entities = new String[4][];
		for (int i = 0; i < 4; ++i)
			entities[i] = readStringArray(from);
	}
	
	@Override
	public void execute(MSCPacketHandler handler, EntityPlayer player) {
		handler.handleEvaluatedBiome(this, player);
	}

} public class EvaluatedGroupPacket extends MSCPacket {
	
	public String mod;
	public String group;
	public String[] biomes;
	
	@Override
	public MSCPacket readData(Object... data) {
		mod = (String) data[0];
		group = (String) data[1];
		biomes = (String[]) data[2];
		return this;
	}
	
	@Override
	public void encodeInto(ChannelHandlerContext ctx, ByteBuf to) throws IOException {
		writeString(mod, to);
		writeString(group, to);
		writeStringArray(biomes, to);
	}

	@Override
	public void decodeFrom(ChannelHandlerContext ctx, ByteBuf from) throws IOException { 
		mod = readString(from);
		group = readString(from);
		biomes = readStringArray(from);
	}
	
	@Override
	public void execute(MSCPacketHandler handler, EntityPlayer player) {
		handler.handleEvaluatedGroup(this, player);
	}
	
} public class SettingsPacket extends MSCPacket {

	public boolean readOnly;
	public boolean masterEnabled;
	public int[] caps;
	public int creatureFreq;

	@Override
	public MSCPacket readData(Object... data) {
		readOnly = (Boolean) data[0];
		masterEnabled = (Boolean) data[1];
		caps = (int[]) data[2];
		creatureFreq = (Integer) data[3];
		return this;
	}
	
	@Override
	public void encodeInto(ChannelHandlerContext ctx, ByteBuf to) throws IOException { 
		to.writeBoolean(readOnly);
		to.writeBoolean(masterEnabled);
		for (int i = 0; i < caps.length; ++i)
			to.writeInt(caps[i]);
		to.writeInt(creatureFreq);
	}

	@Override
	public void decodeFrom(ChannelHandlerContext ctx, ByteBuf from) throws IOException { 
		readOnly = from.readBoolean();
		masterEnabled = from.readBoolean();
		caps = new int[4];
		for (int i = 0; i < caps.length; ++i)
			caps[i] = from.readInt();
		creatureFreq = from.readInt();
	}

	@Override
	public void execute(MSCPacketHandler handler, EntityPlayer player) {
		handler.handleSettings(this, player);
	}

}
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import com.mcf.davidee.msc.gui.AccessDeniedScreen;
import com.mcf.davidee.msc.gui.DebugScreen;
import com.mcf.davidee.msc.gui.MainMenu;
import com.mcf.davidee.msc.gui.MobTypesMenu;
import com.mcf.davidee.msc.gui.SpawnControlMenu;
import com.mcf.davidee.msc.gui.edit.EditBiomeScreen;
import com.mcf.davidee.msc.gui.edit.EditCreatureTypeScreen;
import com.mcf.davidee.msc.gui.edit.EditEntityScreen;
import com.mcf.davidee.msc.gui.edit.GroupsMenu;
import com.mcf.davidee.msc.gui.edit.SettingsScreen;
import com.mcf.davidee.msc.gui.list.BiomeListScreen;
import com.mcf.davidee.msc.gui.list.EntityListScreen;
import com.mcf.davidee.msc.gui.list.EvaluatedBiomeScreen;
import com.mcf.davidee.msc.gui.list.EvaluatedGroupsScreen;
import com.mcf.davidee.msc.gui.list.ModListScreen;
import com.mcf.davidee.msc.packet.BiomeListPacket;
import com.mcf.davidee.msc.packet.CreatureTypePacket;
import com.mcf.davidee.msc.packet.DebugPacket;
import com.mcf.davidee.msc.packet.EntityListPacket;
import com.mcf.davidee.msc.packet.GroupsPacket;
import com.mcf.davidee.msc.packet.MSCPacket.PacketType;
import com.mcf.davidee.msc.packet.ModListPacket;
import com.mcf.davidee.msc.packet.settings.BiomeSettingPacket;
import com.mcf.davidee.msc.packet.settings.EntitySettingPacket;
import com.mcf.davidee.msc.packet.settings.EvaluatedBiomePacket;
import com.mcf.davidee.msc.packet.settings.EvaluatedGroupPacket;
import com.mcf.davidee.msc.packet.settings.SettingsPacket;
package com.mcf.davidee.msc.network;



public class ClientPacketHandler extends MSCPacketHandler {

	
	//TODO Verify that the GUIs are open for the correct mod?
	
	private Minecraft mc;
	
	public ClientPacketHandler() {
		this.mc = Minecraft.getMinecraft();
	}

	@Override
	protected boolean hasPermission(EntityPlayer player) {
		return true;
	}

	@Override
	public void handleSettings(SettingsPacket pkt, EntityPlayer player) {
		if(mc.currentScreen instanceof MainMenu)
			mc.displayGuiScreen(new SettingsScreen(pkt,mc.currentScreen));
	}

	@Override
	public void handleAccessDenied(EntityPlayer player) {
		if(mc.currentScreen == null)
			mc.displayGuiScreen(new AccessDeniedScreen());
	}

	@Override
	public void handleRequest(PacketType type, String mod, EntityPlayer player) { }

	@Override
	public void handleHandShake(EntityPlayer player) {
		if (mc.currentScreen == null)
			mc.displayGuiScreen(new MainMenu());
	}

	@Override
	public void handleModList(ModListPacket packet, EntityPlayer player) {