package projectzombie.menu.gui;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

import org.lwjgl.opengl.GL33;

import gl_engine.matrix.Matrix4;
import gl_engine.vec.Vec2d;
import gl_engine.vec.Vec3d;
import projectzombie.Main;
import projectzombie.init.Models;
import projectzombie.input.types.InputGUI;
import projectzombie.input.types.InputGUITextBox;
import projectzombie.model.ModelGui;
import projectzombie.text.Text;

public class GUITextBox implements GUIComponent, InputGUITextBox
{
	private static final ModelGui BOX = Models.UI_TEXT_BOX;
	private static final ModelGui CURSOR = Models.UI_TEXT_CURSOR;
	
	private Vec2d pos;
	private String text = "";
	private int cursor_pos = 0;
	private boolean in_focus = false;
	private double offset = 0;
	private int max;
	
	public GUITextBox(Vec2d pos, int max) {
		this.pos = pos;
		this.max = max;
	}
	
	public GUITextBox(Vec2d pos, boolean max) {
		this(pos, max ? 22 : -1);
	}
	
	public GUITextBox(Vec2d pos) {
		this(pos, -1);
	}
	
	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}
	
	@Override
	public void render(Matrix4 matrix, Vec2d mousePos, boolean canHover)
	{
		Matrix4 box_matrix = Matrix4.multiply(matrix, Matrix4.translate(pos.x, pos.y, 0));
		
		BOX.setModel(box_matrix);
		BOX.render();
		
		// Set text to black and make sure text gets clipped outside the text box
		GL33.glUniform4f(Main.window.glsl_color, 0.1f, 0.1f, 0.1f, 1);
		GL33.glUniform4f(Main.window.glsl_discard_coords,
				(float)(pos.x + BOX.getWidth() * 2 / 128.0),
				(float)(pos.y + BOX.getHeight() * 2 / 16.0),
				(float)(pos.x + BOX.getWidth() * 126 / 128.0),
				(float)(pos.y + BOX.getHeight() * 14 / 16.0));
		GL33.glUniform1i(Main.window.glsl_do_discard_coords, 1);
		
		Matrix4 text_matrix = box_matrix;
		text_matrix = Matrix4.multiply(text_matrix, Matrix4.translate((1 - offset) * 0.5, 0.5, 0));
		text_matrix = Matrix4.multiply(Matrix4.scale(new Vec3d(0.5, 0.5, 0.5)), text_matrix);
		
		Text.render(text, text_matrix);
		
		if(in_focus) {
			CURSOR.setModel(Matrix4.multiply(text_matrix, Matrix4.translate(cursor_pos * 0.5, 0, 0)));
			CURSOR.render();
		}
		
		// Reset the settings back to default
		GL33.glUniform4f(Main.window.glsl_color, 1, 1, 1, 1);
		GL33.glUniform1i(Main.window.glsl_do_discard_coords, 0);
	}

	@Override
	public void update(Vec2d mousePos) {
	}

	@Override
	public boolean checkMouseHover(Vec2d mousePos) {
		return (mousePos.x > this.pos.x && mousePos.x < this.pos.x + BOX.getWidth() &&
				mousePos.y > this.pos.y && mousePos.y < this.pos.y + BOX.getHeight());
	}
	
	@Override
	public void onMouseClick(Vec2d mousePos)
	{
		((InputGUI)Main.menu.input).getGUI().setTextBox(this);
		in_focus = true;
		
		cursor_pos = (int)((mousePos.x - pos.x + offset * 0.5 - 0.5) * 2 + 0.5);
		
		if(cursor_pos > text.length()) {
			cursor_pos = text.length();
		}
	}
	
	private void updateText()
	{
		// Update the text fields offset to
		// keep the cursor in the text field
		double o = BOX.getWidth() - 1;
		
		if(cursor_pos - o < offset) {
			offset = cursor_pos - o;
		}
		
		if(cursor_pos - o * 2 > offset) {
			offset = cursor_pos - o * 2;
		}
		
		if(offset < 0) {
			offset = 0;
		}
	}
	
	@Override
	public void onPaste()
	{
		try
		{
			String clipboard = (String)(Main.clipboard.getData(DataFlavor.stringFlavor));
			
			if(max == -1 || text.length() + clipboard.length() <= max)
			{
				text = text.substring(0, cursor_pos) + clipboard + text.substring(cursor_pos, text.length());
				cursor_pos += clipboard.length();
				
				updateText();
			}
			
			else if(text.length() < max)
			{
				clipboard = clipboard.substring(0, max - text.length());
				
				text = text.substring(0, cursor_pos) + clipboard + text.substring(cursor_pos, text.length());
				cursor_pos += clipboard.length();
				
				updateText();
			}
		}
		
		catch (UnsupportedFlavorException | IOException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void onBackspace()
	{
		if(cursor_pos == 0) {
			return;
		}
		
		text = text.substring(0, cursor_pos - 1) + text.substring(cursor_pos, text.length());
		cursor_pos -= 1;
		
		updateText();
	}
	
	@Override
	public void onDelete()
	{
		if(cursor_pos == text.length()) {
			return;
		}
		
		text = text.substring(0, cursor_pos) + text.substring(cursor_pos + 1, text.length());
		
		updateText();
	}
	
	@Override
	public void onMoveCursor(int direction)
	{
		cursor_pos += direction;
		
		if(cursor_pos < 0) {
			cursor_pos = 0;
		}
		
		if(cursor_pos > text.length()) {
			cursor_pos = text.length();
		}
		
		updateText();
	}
	
	@Override
	public void onHome() {
		cursor_pos = 0;
		updateText();
	}

	@Override
	public void onEnd() {
		cursor_pos = text.length();
		updateText();
	}

	@Override
	public void onPressed(char character)
	{
		if(max == -1 || text.length() < max)
		{
			text = text.substring(0, cursor_pos) + character + text.substring(cursor_pos, text.length());
			cursor_pos += 1;
			
			updateText();
		}
	}

	@Override
	public void setFocus(boolean focus) {
		in_focus = focus;
	}

	@Override
	public void onScroll(Vec2d mousePos, double amount) {
	}

	@Override
	public void onRightClick(Vec2d mousePos) {
	}
	
	@Override
	public void onActivate() {
	}

	@Override
	public void onBack() {
	}
}
