package pl.shockah.ts.menu;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.lwjgl.input.Keyboard;
import pl.shockah.FieldObj;
import pl.shockah.Math2;
import pl.shockah.glib.geom.Rectangle;
import pl.shockah.glib.geom.vector.Vector2d;
import pl.shockah.glib.geom.vector.Vector2i;
import pl.shockah.glib.gl.Graphics;
import pl.shockah.glib.gl.color.Color;
import pl.shockah.glib.gl.font.ETextAlign;
import pl.shockah.glib.gl.font.Font;
import pl.shockah.glib.gl.font.TextHelper;
import pl.shockah.glib.gl.tex.Atlas;
import pl.shockah.glib.input.KInput;
import pl.shockah.glib.input.MInput;
import pl.shockah.glib.state.State;
import pl.shockah.ts.Assets;

public class MenuElChoose<T> extends MenuElement {
	public static final Atlas atlas = Assets.aFrameText;
	
	protected final ToString<T> tostring;
	protected List<T> options = new LinkedList<>();
	protected String text = "";
	protected FieldObj field = null;
	protected float selectedAlpha = 0f, openAlpha = 0f;
	protected boolean open = false;
	protected int selected = 0;
	
	public MenuElChoose() {
		this(null);
	}
	public MenuElChoose(ToString<T> tostring) {
		this.tostring = tostring;
	}
	
	public MenuElChoose<T> setText(String text) {
		this.text = text;
		return this;
	}
	public MenuElChoose<T> setAction(FieldObj field) {
		this.field = field;
		return this;
	}
	
	@SuppressWarnings("unchecked") public MenuElChoose<T> addOptions(T... options) {
		this.options.addAll(Arrays.asList(options));
		return this;
	}
	
	protected void create(MenuSet menu, boolean selected) {
		selectedAlpha = selected ? 1f : 0f;
	}
	
	protected boolean update(MenuSet menu, Rectangle rect, Font font, boolean selected) {
		font = Assets.font16;
		selectedAlpha = Math2.limit(selectedAlpha+.1f*(selected ? 1 : -1),0,1);
		openAlpha = Math2.limit(openAlpha+.1f*(selected && open ? 1 : -1),0,1);
		
		if (open) {
			if (KInput.isPressed(Keyboard.KEY_UP)) this.selected = Math.max(this.selected-1,0);
			if (KInput.isPressed(Keyboard.KEY_DOWN)) this.selected = Math.min(this.selected+1,options.size()-1);
			
			if (selected && KInput.isPressed(Keyboard.KEY_RETURN)) {
				open = false;
				setValue();
			}
			
			Vector2d size2 = new Vector2d();
			for (T t : options) {
				double w = font.getWidth(toString(t));
				if (w > size2.x) size2.x = w;
				size2.y += font.getHeight();
			}
			Rectangle rect2 = new Rectangle(State.get().getDisplaySize().toDouble().div(2).sub(size2.Div(2)),size2);
			
			for (int i = 0; i < options.size(); i++) {
				Rectangle rect3 = new Rectangle(rect2.pos.Add(0,rect2.size.y/options.size()*i),new Vector2d(rect2.size.x,rect2.size.y/options.size()));
				if (MInput.inRectangle(new Rectangle(0,rect3.pos.y,State.get().getDisplaySize().x,rect3.size.y))) {
					if (!MInput.getDeltaPos().equals(new Vector2i())) this.selected = i;
					if (selected && MInput.isPressed(MInput.LEFT)) {
						open = false;
						setValue();
					}
					return !MInput.getDeltaPos().equals(new Vector2i());
				}
			}
		} else {
			if (selected && KInput.isPressed(Keyboard.KEY_RETURN)) {
				if (options.size() == 2) this.selected = this.selected == 0 ? 1 : 0; else open = true;
			}
			if (MInput.inRectangle(new Rectangle(0,rect.pos.y,State.get().getDisplaySize().x,rect.size.y))) {
				if (selected && MInput.isPressed(MInput.LEFT)) {
					if (options.size() == 2) this.selected = this.selected == 0 ? 1 : 0; else open = true;
				}
				return !MInput.getDeltaPos().equals(new Vector2i());
			}
		}
		return false;
	}
	protected boolean lockedSelection() {
		return open;
	}
	protected void setValue() {
		try {
			if (field != null) field.set(options.get(this.selected));
		} catch (Exception e) {e.printStackTrace();}
	}
	
	protected void render(MenuSet menu, Graphics g, Rectangle rect, Font font, boolean selected) {
		g.setColor(Color.Black.alpha(.5f));
		g.draw(new Rectangle(0,rect.pos.y,State.get().getDisplaySize().x,rect.size.y));
		g.setColor(Color.Black.alpha(.5f*selectedAlpha));
		g.draw(new Rectangle(0,rect.pos.y,State.get().getDisplaySize().x,rect.size.y));
		
		g.setColor(Color.Black);
		for (int yy = -1; yy <= 1; yy += 2) for (int xx = -1; xx <= 1; xx += 2) {
			TextHelper.draw(g,font,rect.pos.Add(xx,yy).add(rect.size.x/2-24,rect.size.y/2),text,ETextAlign.MiddleRight);
			TextHelper.draw(g,font,rect.pos.Add(xx,yy).add(rect.size.x/2+24,rect.size.y/2),toStringOption(),ETextAlign.MiddleLeft);
		}
		g.setColor(Color.White);
		TextHelper.draw(g,font,rect.pos.Add(rect.size.x/2-24,rect.size.y/2),text,ETextAlign.MiddleRight);
		TextHelper.draw(g,font,rect.pos.Add(rect.size.x/2+24,rect.size.y/2),toStringOption(),ETextAlign.MiddleLeft);
	}
	protected void render2(MenuSet menu, Graphics g, Rectangle rect, Font font, boolean selected) {
		font = Assets.font16;
		if (!selected || openAlpha <= 0f) return;
		
		Vector2d size2 = new Vector2d();
		for (T t : options) {
			double w = font.getWidth(toString(t));
			if (w > size2.x) size2.x = w;
			size2.y += font.getHeight();
		}
		Rectangle rect2 = new Rectangle(State.get().getDisplaySize().toDouble().div(2).sub(size2.Div(2)),size2.Add(8,8));
		
		g.setColor(Color.Black.alpha(.75f*openAlpha));
		g.draw(new Rectangle(0,rect2.pos.y,State.get().getDisplaySize().x,rect2.size.y));
		
		int i = 0;
		for (T t : options) {
			g.setColor(Color.Black.alpha(openAlpha*(this.selected == i ? 1f : .5f)));
			for (int yy = -1; yy <= 1; yy += 2) for (int xx = -1; xx <= 1; xx += 2) TextHelper.draw(g,font,rect2.pos.Add(xx,yy+font.getHeight()*(i+.5f)).add(rect2.size.x/2,6),toString(t),ETextAlign.MiddleCenter);
			g.setColor(Color.White.alpha(openAlpha*(this.selected == i ? 1f : .5f)));
			TextHelper.draw(g,font,rect2.pos.Add(rect2.size.x/2,6).add(0,font.getHeight()*(i+.5f)),toString(t),ETextAlign.MiddleCenter);
			i++;
		}
	}
	
	protected String toStringOption() {
		return options.isEmpty() ? "" : toString(options.get(selected));
	}
	protected String toString(T t) {
		return tostring == null ? t.toString() : tostring.toString(t);
	}
	
	public static abstract class ToString<T> {
		public abstract String toString(T t);
	}
}