package client.vars;

import java.lang.reflect.Field;

import client.gui.element.Dropdown;
import client.gui.element.DropdownCallback;
import client.gui.element.Element;
import client.gui.element.Switch;
import client.gui.element.SwitchCallback;
import common.util.Identifyable;
import common.util.Color;
import common.util.Util;

public class EnumVar<T extends Enum> extends BaseVar {
	public static interface EnumFunction<T extends Enum> extends VarFunction {
		void apply(EnumVar cv, T value);
	}

	private final EnumFunction func;
	private final String values;
	private final T def;
	private final boolean useSwitch;
	
	public EnumVar(String name, String display, Field field, Object object, CVarCategory category, EnumFunction<T> func, boolean useSwitch) {
		super(name, display, field, object, category);
		this.func = func;
		this.useSwitch = useSwitch;
		StringBuilder sb = new StringBuilder();
		for(T value : (T[])field.getType().getEnumConstants()) {
			if(sb.length() > 0)
				sb.append(',');
			sb.append(value instanceof Identifyable ? ((Identifyable)value).getName() : value.toString());
		}
		this.values = sb.toString();
		try {
			this.def = (T)field.get(object);
		}
		catch(IllegalArgumentException | IllegalAccessException e) {
			throw new RuntimeException(e);
		}
	}

	public String getType() {
		return Color.CYAN + "enum";
	}
	
	public boolean parse(String str) {
		T value = (T)Util.parseEnum((Class<T>)this.field.getType(), str);
		if(value == null)
			return false;
		try {
			this.field.set(this.object, value);
		}
		catch(IllegalArgumentException | IllegalAccessException e) {
			throw new RuntimeException(e);
		}
		if(this.func != null)
			this.func.apply(this, value);
		return true;
	}
	
	public String format() {
		try {
			T value = (T)this.field.get(this.object);
			return value instanceof Identifyable ? ((Identifyable)value).getName() : value.toString();
		}
		catch(IllegalArgumentException | IllegalAccessException e) {
			throw new RuntimeException(e);
		}
	}
	
	public String getDefault() {
		return this.def instanceof Identifyable ? ((Identifyable)this.def).getName() : this.def.toString();
	}
	
	public String getValues() {
		return this.values;
	}
	
	public Element selector(int x, int y, int w, int h) {
		if(this.useSwitch)
			return this.switcher(x, y, w, h);
		try {
			return new Dropdown<T>(x, y, w, h < 0 ? -h : h, h < 0, (T[])this.field.getType().getEnumConstants(), this.def, (T)this.field.get(this.object), new DropdownCallback<T>() {
				public void use(Dropdown<T> elem, T value) {
					EnumVar.this.parse(value instanceof Identifyable ? ((Identifyable)value).getName() : value.toString());
				}
			}, this.display);
		}
		catch(IllegalArgumentException | IllegalAccessException e) {
			throw new RuntimeException(e);
		}
	}
	
	public Switch switcher(int x, int y, int w, int h) {
		try {
			return new Switch<T>(x, y, w, h, (T[])this.field.getType().getEnumConstants(), this.def, (T)this.field.get(this.object), new SwitchCallback<T>() {
				public void use(Switch<T> elem, T value) {
					EnumVar.this.parse(value instanceof Identifyable ? ((Identifyable)value).getName() : value.toString());
				}
			}, this.display);
		}
		catch(IllegalArgumentException | IllegalAccessException e) {
			throw new RuntimeException(e);
		}
	}
}
