package client.window;

import client.Client;
import client.gui.element.Element;
import client.vars.CVar;
import client.vars.CVarCategory;
import common.util.Identifyable;
import common.util.Color;
import common.util.Util;

public enum Bind implements Identifyable, CVar {
	FORWARD("forward", "Vorwärts", Keysym.W),
	LEFT("left", "Nach links", Keysym.A),
	BACKWARD("backward", "Rückwärts", Keysym.S),
	RIGHT("right", "Nach rechts", Keysym.D),
	UP("up", "Aufwärts, Sprung", Keysym.SPACE),
	DOWN("down", "Abwärts, Langsam", Keysym.LEFT_CONTROL),
	FAST("fast", "Schneller", Keysym.LEFT_SHIFT),
	INVENTORY("inventory", "Inventar", Keysym.E),
	PRIMARY("primary", "Primäre Aktion", Button.MOUSE_LEFT),
	SECONDARY("secondary", "Sekundäre Aktion", Button.MOUSE_RIGHT),
	TERTIARY("tertiary", "Tertiäre Aktion", Button.MOUSE_MIDDLE),
	QUARTERNARY("quarternary", "Quartäre Aktion", Keysym.R),
	THROW("throw", "Weg werfen", Keysym.Q),
	SELECT1("select1", "Auswahl #1", Keysym.N1),
	SELECT2("select2", "Auswahl #2", Keysym.N2),
	SELECT3("select3", "Auswahl #3", Keysym.N3),
	SELECT4("select4", "Auswahl #4", Keysym.N4),
	SELECT5("select5", "Auswahl #5", Keysym.N5),
	SELECT6("select6", "Auswahl #6", Keysym.N6),
	SELECT7("select7", "Auswahl #7", Keysym.N7),
	SELECT8("select8", "Auswahl #8", Keysym.N8),
	SELECT9("select9", "Auswahl #9", Keysym.N9),
	SELECT10("select10", "Auswahl #10", Keysym.N0),
	SELECT11("select11", "Auswahl #11", Keysym.SHARP_S),
	SELECT12("select12", "Auswahl #12", Keysym.ACUTE),
	CRAFT("craft", "Herstellen", Keysym.M),
	RENAME("rename", "Umbenennen", Keysym.N),
	CONSOLE("console", "Konsole", Keysym.F1),
	COMMAND("command", "Befehl / Chat", Keysym.C),
	INFO("info", "Infos einblenden", Keysym.TAB),
	PERSPECTIVE("perspective", "Perspektive", Keysym.F5),
	ZOOM("zoom", "Kamera zoomen", Keysym.Y),
	MENU("menu", "Menü", Keysym.ESCAPE),
	SCREENSHOT("screenshot", "Bildschirmfoto", Keysym.F10),
	SHOW("overlay", "Perf.-Anzeige", Keysym.F2),
	FULLSCREEN("fullscreen", "Vollbild", Keysym.F12),
	CHEAT("cheat", "Schummeln / Debug", Keysym.F3);

	private static boolean windowActive;
	private static boolean inputEnabled;
	private static boolean mouseEnabled;
	private static Bind waitingFor;
	private static Keysym keyRelease;

	private final String id;
	private final String name;
	private final Input defInput;
	
	private Input input;
	private boolean pressed;
	private boolean active;
	
	public static void updateBinds() {
		for(Bind bind : values()) {
			bind.update();
		}
		mouseEnabled = true;
		for(Wheel wheel : Wheel.values()) {
			wheel.reset();
		}
	}
	
	public static void disableMouse() {
		mouseEnabled = false;
	}
	
	public static boolean isInputEnabled() {
		return inputEnabled;
	}
	
	public static void disableInput(Bind wait) {
		inputEnabled = false;
		waitingFor = wait;
	}
	
	public static void disableInput(Keysym release) {
		inputEnabled = false;
		keyRelease = release;
	}
	
	public static Bind getWaiting() {
		return waitingFor;
	}
	
	public static void unsetWaiting() {
		waitingFor = null;
	}
	
	public static void enableInput() {
		if(waitingFor == null && (keyRelease == null || !keyRelease.read()))
			inputEnabled = true;
	}

	public static void setBind(Input input, boolean release) {
		if(waitingFor != null) {
			if(release) {
				if(input == keyRelease) {
					waitingFor.input = input;
					waitingFor = null;
					keyRelease = null;
					Client.CLIENT.setDirty();
					if(Client.CLIENT.open != null)
						Client.CLIENT.open.reformat();
				}
			}
			else if(keyRelease == null) {
				if(input instanceof Keysym) {
					keyRelease = (Keysym)input;
				}
				else {
					waitingFor.input = input;
					waitingFor = null;
					Client.CLIENT.setDirty();
					if(Client.CLIENT.open != null)
						Client.CLIENT.open.reformat();
				}
			}
		}
	}
	
	public static boolean isWindowActive() {
		return windowActive;
	}
	
	public static void setWindowActive(boolean active) {
		windowActive = active;
		for(Wheel wheel : Wheel.values()) {
			wheel.reset();
		}
	}
	
	private Bind(String id, String name, Input input) {
		this.id = id;
		this.name = name;
		this.input = this.defInput = input;
	}
	
	private void update() {
		boolean last = this.pressed;
		this.pressed = inputEnabled && windowActive && this.input != null && this.input.read();
		if(inputEnabled && this.input instanceof Button && !mouseEnabled)
			last = this.pressed;
		this.active = this.pressed && !last;
	}
	
	public void setInput(Input input) {
		this.input = input;
	}
	
	public Input getInput() {
		return this.input;
	}

	public String getName() {
		return this.id;
	}

	public String getDisplay() {
		return this.name;
	}
	
	public boolean isDown() {
		return inputEnabled && this.pressed;
	}
	
	public boolean isPressed() {
		return inputEnabled && this.active;
	}

	public String getCVarName() {
		return "key_" + this.id;
	}

	public String getType() {
		return Color.VIOLET + "key";
	}
	
	public CVarCategory getCategory() {
		return CVarCategory.INPUT;
	}
	
	public boolean parse(String str) {
		if("none".equalsIgnoreCase(str)) {
			this.input = null;
			return true;
		}
		Input input = Util.parseEnum(Input.class, str, Keysym.class, Button.class, Wheel.class);
		if(input != null)
			this.input = input;
		return input != null;
	}
	
	public String format() {
		return this.input != null ? this.input.getName() : "none";
	}
	
	public String getDefault() {
		return this.defInput != null ? this.defInput.getName() : "none";
	}
	
	public void setDefault() {
		this.input = this.defInput;
	}
	
	public Element selector(int x, int y, int w, int h) {
		throw new UnsupportedOperationException("Kann kein Element für Tastenbelegung erstellen");
	}
	
	public boolean isDefault() {
		return this.input == this.defInput;
	}

	public boolean isDupe() {
		if(this.input == null)
			return false;
		for(Bind bind : values()) {
			if(this != bind && bind.input == this.input)
				return true;
		}
		return false;
	}
}
