package client.gui.element;

import client.gui.Formatter;
import client.renderer.Drawing;
import client.window.Button;
import common.util.ExtMath;
import common.util.Util;

public class Slider extends Element {
	private static final int SLIDER_WIDTH = 8;

	private final SliderCallback func;
	private final int def;
	private final int min;
	private final int max;
	private final int precision;
	private final int handle;
	
	private int value;
	private int position;

	public Slider(int x, int y, int w, int h, int prec, int min, int max, int def, int init, SliderCallback callback, Formatter<Slider> formatter) {
		super(x, y, w, h, formatter);
		this.handle = ((this.size_y * SLIDER_WIDTH) / BASE_HEIGHT) & ~1;
		this.func = callback;
		this.precision = prec;
		this.min = min;
		this.max = max;
		this.def = def;
		this.value = init;
		this.position = gui_slider_pixel();
		this.formatText();
	}

	public Slider(int x, int y, int w, int h, int prec, int min, int max, int def, int init, SliderCallback callback, final String text) {
		this(x, y, w, h, prec, min, max, def, init, callback, new Formatter<Slider>() {
			public String use(Slider elem) {
				return String.format("%s: %d", text, elem.value);
			}
		});
	}

	public Slider(int x, int y, int w, int h, int prec, int min, int max, int def, int init, SliderCallback callback, final String text, final String unit) {
		this(x, y, w, h, prec, min, max, def, init, callback, new Formatter<Slider>() {
			private final String format = unit.isEmpty() ? "%s: %d" : "%s: %d %s";
			
			public String use(Slider elem) {
				return String.format(this.format, text, elem.value, unit);
			}
		});
	}

	public Slider(int x, int y, int w, int h, int prec, float min, float max, float def, float init, final SliderFloatCallback callback, Formatter<Slider> formatter) {
		this(x, y, w, h, prec, (int)(min * 1000.0f), (int)(max * 1000.0f), (int)(def * 1000.0f), (int)(init * 1000.0f), new SliderCallback() {
			public void use(Slider elem, int value) {
				callback.use(elem, (float)value / 1000.0f);
			}
		}, formatter);
	}

	public Slider(int x, int y, int w, int h, final int prec, float min, float max, float def, float init, SliderFloatCallback callback, final String text, final String unit) {
		this(x, y, w, h, prec < 0 ? 0 : prec, min, max, def, init, callback, new Formatter<Slider>() {
			private final String format = "%s: " + (prec <= 0 ? "%d" : ("%." + prec + "f")) + (unit.isEmpty() ? "" : " %s");
			
			public String use(Slider elem) {
				return prec <= 0 ? String.format(this.format, text, prec < 0 ? (int)((float)elem.value / 10.0f) : (elem.value / 1000), unit)
						: String.format(this.format, text, (float)elem.value / 1000.0f, unit);
			}
		});
	}
	
	public void scroll(int scr_x, int scr_y, int x, int y, boolean ctrl, boolean shift) {
		if(scr_y != 0) {
			int prev = this.value;
			this.value += (scr_y < 0 ? -1 : 1) * (ctrl ? (this.precision != 0 ? 1 : 10) : ((this.precision >= 2) ? 10 : (this.precision != 0 ? 100 : 1))) * (shift ? (this.precision != 0 ? 50 : 5) : 1);
			this.value = ExtMath.clampi(this.value, this.min, this.max);
			this.position = gui_slider_pixel();
			if(this.value != prev) {
				this.func.use(this, this.value);
				this.formatText();
			}
		}
	}
	
	public void mouse(Button btn, int x, int y, boolean ctrl, boolean shift) {
		int prev = this.value;
		if(ctrl || (btn == Button.MOUSE_MIDDLE)) {
			this.value = this.def;
			this.position = gui_slider_pixel();
			if(this.value != prev) {
				this.func.use(this, this.value);
				this.formatText();
				this.playSound();
			}
		}
		else {
			this.position = x - this.pos_x;
			this.value = gui_slider_value();
			this.position = gui_slider_pixel();
			if(this.value != prev) {
				this.func.use(this, this.value);
				this.formatText();
				this.playSound();
			}
		}
	}
	
	public void drag(int x, int y) {
		x = (x < this.pos_x) ? this.pos_x : ((x >= (this.pos_x + this.size_x)) ? (this.pos_x - 1 + this.size_x) : x);
		int prev = this.value;
		this.position = x - this.pos_x;
		this.value = gui_slider_value();
		this.value = ExtMath.clampi(this.value, this.min, this.max);
		this.position = gui_slider_pixel();
		if(this.value != prev) {
			this.func.use(this, this.value);
			this.formatText();
		}
	}
	
	public void reformat() {
		this.position = gui_slider_pixel();
//		if(this.visible)
//			this.r_dirty = true;
		super.reformat();
	}
	
	private int gui_slider_value() {
		int r = this.min + (int)(((float)(int)(this.position - (this.handle / 2))) * ((float)(int)(this.max - this.min)) / ((float)(int)(this.size_x + 1 - this.handle)));
		return ExtMath.clampi(r, this.min, this.max);
	}
	
	private int gui_slider_pixel() {
		int r = ((int)(float)(((float)(int)(this.value - this.min)) * ((float)(int)(this.size_x + 1 - this.handle)) / ((float)(int)(this.max - this.min)))) + (this.handle / 2);
		return ExtMath.clampi(r, this.handle / 2, this.size_x - (this.handle / 2));
	}
	
	public void setValue(int value) {
		this.value = ExtMath.clampi(value, this.min, this.max);
		this.position = gui_slider_pixel();
		this.formatText();
	}
	
	public void setFloatValue(float value) {
		this.setValue((int)(value * 1000.0f));
	}
	
	public int getValue() {
		return this.value;
	}
	
	public float getFloatValue() {
		return (float)this.value / 1000.0f;
	}
	
	protected void drawBackground() {
		if(this.enabled) {
			Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, this.gm.style.fill_btm, this.gm.style.fill_top, 0xff000000, this.gm.style.brdr_top, this.gm.style.brdr_btm);
			Drawing.drawGradientBorder(this.pos_x + this.position - (this.handle / 2), this.pos_y, this.handle, this.size_y, this.gm.style.fill_top, this.gm.style.fill_btm, 0xff000000, this.gm.style.brdr_top, this.gm.style.brdr_btm);
		}
		else {
			Drawing.drawGradientBorder(this.pos_x, this.pos_y, this.size_x, this.size_y, Util.mulColor(this.gm.style.fill_btm, 0.5f), Util.mulColor(this.gm.style.fill_top, 0.5f), 0xff000000, Util.mulColor(this.gm.style.brdr_top, 0.5f), Util.mulColor(this.gm.style.brdr_btm, 0.5f));
			Drawing.drawGradientBorder(this.pos_x + this.position - (this.handle / 2), this.pos_y, this.handle, this.size_y, Util.mulColor(this.gm.style.fill_top, 0.5f), Util.mulColor(this.gm.style.fill_btm, 0.5f), 0xff000000, Util.mulColor(this.gm.style.brdr_top, 0.5f), Util.mulColor(this.gm.style.brdr_btm, 0.5f));
		}
	}
}
