package client.gui.element;

import client.gui.Font;
import client.renderer.Drawing;
import client.renderer.Drawing.Offset;
import client.renderer.Drawing.Vec2i;
import common.util.CharValidator;
import common.util.ExtMath;
import common.util.Util;

public class Area extends Textbox {
	private int textHeight;
	private int scrollPos;
	private int cursorX;
	private int cursorY;

	private Area(int x, int y, int w, int h, int cap, boolean editable, CharValidator validator, String text) {
		super(x, y, w, h, cap, editable, null, validator);
		this.setText(text);
	}
	
	public Area(int x, int y, int w, int h, int cap, CharValidator validator, String text) {
		this(x, y, w, h, cap, true, validator, text);
	}

	public Area(int x, int y, int w, int h, int cap, String text) {
		this(x, y, w, h, cap, true, null, text);
	}

	public Area(int x, int y, int w, int h, String text) {
		this(x, y, w, h, Integer.MAX_VALUE, false, null, text);
	}
	
	public void updateText() {
		this.textHeight = Drawing.txt_size(this.pos_x + this.margin_x1, this.pos_y + this.margin_y1, 
				this.pos_x + this.margin_x1, this.pos_y + this.margin_y1, 
				this.pos_x + (this.size_x - (this.margin_x1 + this.margin_x2)), Integer.MAX_VALUE, this.text).ypos;
	}
	
	public void scroll(int scr_x, int scr_y, int x, int y, boolean ctrl, boolean shift) {
		if(scr_y != 0) {
			int limit = Font.HEIGHT + this.textHeight - (this.size_y - (this.margin_y1 + this.margin_y2));
			limit = ExtMath.clampi(limit, 0, 0x7fffffff);
			int prev = this.text_y;
			this.text_y += (scr_y < 0 ? -1 : 1) * (ctrl ? 1 : Font.HEIGHT) * this.gm.scrollLines * (shift ? 10 : 1);
			this.text_y = ExtMath.clampi(this.text_y, -limit, 0);
			if(this.sel_start >= 0)
				this.cursorY += (this.text_y - prev);
		}
	}
	
	public void mouserel() {
		this.scrollPos = 0;
	}
	
	public void onReturn(boolean shift) {
		insertText("\n");
	}
	
	public void onSelection(boolean up) {
		if(!up && this.sel_start != this.sel_end) {
			this.sel_start = this.sel_drag = this.sel_end;
		}
		else if(up && this.sel_start != this.sel_end) {
			this.sel_end = this.sel_drag = this.sel_start;
		}
		if(!up && this.sel_start >= 0) {
			if(this.sel_end < this.text.length()) {
				int nl = this.text.indexOf('\n', this.sel_end);
				this.sel_end = nl >= 0 ? nl + 1 : this.text.length();
				this.sel_start = this.sel_drag = this.sel_end;
			}
			else {
				this.sel_end = this.sel_drag = this.sel_start;
			}
			gui_text_update_cur(this.sel_end, true);
		}
		else if(up && this.sel_start >= 0) {
			if(this.sel_start > 0) {
				int nl = this.text.lastIndexOf('\n', this.sel_start);
				this.sel_start = nl >= 0 ? nl : 0;
			}
			this.sel_end = this.sel_drag = this.sel_start;
			gui_text_update_cur(this.sel_end, true);
		}
	}
	
	public void update() {
		if(this.scrollPos != 0) {
			int n = this.updateScroll(this.scrollPos);
			this.text_y += n;
			if(n != 0)
				gui_text_clamp_scroll();
		}
	}
	
	public void shift(int shift_x, int shift_y) {
		super.shift(shift_x, shift_y);
		this.cursorX += shift_x;
		this.cursorY += shift_y;
	}
	
	protected void gui_text_clamp_scroll() {
		int limit = Font.HEIGHT + this.textHeight - (this.size_y - (this.margin_y1 + this.margin_y2));
		limit = ExtMath.clampi(limit, 0, 0x7fffffff);
		this.text_y = ExtMath.clampi(this.text_y, -limit, 0);
	}
	
	protected void updateCursor(int offset, boolean shift, int x1, int y1, int x2, int y2) {
		Vec2i coord = Drawing.txt_coord(offset, x1, y1 + this.text_y, 
			x1 + this.text_x, y1 + this.text_y, this.pos_x + x2, 0x7fffffff, this.text);
		this.cursorX = coord.xpos;
		this.cursorY = coord.ypos;
		if(shift) {
			if(this.cursorY < y1)
				this.text_y += y1 - this.cursorY;
			else if((this.cursorY + Font.HEIGHT) >= (y1 + y2))
				this.text_y -= (this.cursorY + Font.HEIGHT) - (y1 + y2);
			gui_text_update_cur(offset, false);
		}
	}
	
	protected int onCursorOffset(int x, int y, int x1, int y1, int x2, int y2) {
		Offset off = Drawing.txt_offset(x, y, x1, y1 + this.text_y, 
			x1 + this.text_x, y1 + this.text_y, this.pos_x + x2, 0x7fffffff, this.text);
		if(off != null) {
			this.cursorX = off.xpos;
			this.cursorY = off.ypos;
		}
		int offset = off == null ? 0 : off.offset;
		if(y < y1)
			this.scrollPos = y1 - y;
		else if(y >= (y1 + y2))
			this.scrollPos = -(y - (y1 + y2));
		return offset;
	}
	
	protected void drawForeground(int x1, int y1, int x2, int y2) {
		Drawing.txt_draw(x1, y1 + this.text_y, 
				x1 + this.text_x, y1 + this.text_y, 
				this.pos_x + x2, Integer.MAX_VALUE, this.enabled ? this.gm.style.text_field : Util.mulColor(this.gm.style.text_field, 0.5f), this.text);
		if(this.sel_start >= 0 && this.sel_end != this.sel_start)
			Drawing.txt_overlay(this.sel_start, this.sel_end, x1, y1 + this.text_y, 
				x1 + this.text_x, y1 + this.text_y, 
				this.pos_x + x2, Integer.MAX_VALUE, this.enabled ? 0x808080ff : 0x80404040, this.text);
	}
	
	protected char getNewline() {
		return '\n';
	}

	protected int getCursorX(int x1, int x2) {
		return this.cursorX;
	}

	protected int getCursorY(int y1, int y2) {
		return this.cursorY;
	}
}
