/*
   ui/inputbox.cc
   This file is part of the Osirion project and is distributed under
   the terms of the GNU General Public License version 2
*/

#include "ui/inputbox.h"
#include "ui/paint.h"
#include "auxiliary/functions.h"
#include "math/functions.h"
#include "core/application.h"

namespace ui
{

InputBox::InputBox(Widget *parent) : Widget(parent)
{
	input_text.clear();
	input_pos = 0;
	input_max = 512;
	
	set_label("input");
	set_background(false);
	set_border(false);
}

InputBox::~InputBox()
{
}

void InputBox::clear()
{
	input_text.clear();
	input_pos = 0;
}
void InputBox::set_text(std::string const &text)
{
	input_text.assign(text);
	input_pos = input_text.size();
}

void InputBox::set_text(const char *text)
{
	if (text)
		input_text.assign(text);
	else
		input_text.clear();
	input_pos = input_text.size();
}

void InputBox::set_prompt(const std::string &prompt)
{
	input_prompt.assign(prompt);
}

void InputBox::set_prompt(const char *prompt)
{
	if (!prompt)
		input_prompt.clear();
	else
		input_prompt.assign(prompt);
}

void InputBox::set_max(const size_t max)
{
	input_max = max;
}

void InputBox::draw()
{
	size_t text_width = (size_t) floorf(width() / font()->width());
	size_t prompt_width = aux::text_length(input_prompt);
	math::Vector2f v(global_location());
	paint::color(palette()->text());
	
	// draw the prompt
	if (prompt_width) {
		paint::text(v, size(), font(), input_prompt);
		v.x +=  prompt_width * font()->width();
	}
	paint::color(palette()->text());

	// draw the part before the cursor
	std::string firstpart(input_text.substr(0, input_pos));
	size_t draw_width = 0;
	const char *c = firstpart.c_str();
	
	while (*c) {
		if (aux::is_color_code(c)) {
			c++;
		} else {
			draw_width++;
		}
		c++;
	}
	
	c = firstpart.c_str();
	while (*c && draw_width > text_width - prompt_width - 1) {
		if (aux::is_color_code(c)) {
			c++;
			paint::color_code(*c);
		} else {
			draw_width--;
		}
		c++;
	}
	
	if (*c) {
		paint::text(v, size(), font(), std::string(c));
	}
	
	// draw the part behind the cursor
	v.x += draw_width * font()->width();
	if (input_pos < input_text.size()) {
		if (input_pos > 1 && aux::is_color_code(input_text.c_str() + input_pos -1)) {
			paint::color_code(input_text[input_pos]);
		}
		// limit to width
		std::string secondpart;
		c = &input_text.c_str()[input_pos];
		while (*c && (draw_width <= (text_width - prompt_width - 1))) {
			if (aux::is_color_code(c)) {
				c++;
			} else {
				draw_width++;
				secondpart += *c;
			}
			c++;
		}

		paint::text(v, size(), font(), secondpart);
	}
	
	// draw the cursor
	if (has_input_focus() && (core::application()->time() - ::floorf(core::application()->time())) < 0.5f) {
		std::string cursor("^B");
		cursor += (char) 11;
		paint::text(v, size(), font(), cursor);
	}

	// reset color
	paint::color(palette()->foreground());
}

bool InputBox::on_keypress(const int key, const unsigned int modifier)
{
	switch (key) {
		case SDLK_TAB:
			// FIXME should not be here
			core::CommandBuffer::complete(input_text, input_pos);
			return true;
			break;
			
		case SDLK_HOME:
			input_pos = 0;
			return true;
			break;
			
		case SDLK_END:
			input_pos = input_text.size();
			return true;
			break;
			
		case SDLK_LEFT:
			if (input_pos > 0)
				input_pos--;
			return true;
			break;
			
		case SDLK_RIGHT:
			if (input_pos < input_text.size())
				input_pos++;
			return true;
			break;
			
		case SDLK_DELETE:
			if (input_text.size() && input_pos < input_text.size()) {
				input_text.erase(input_pos, 1);
			}
			return true;
			break;
			
		case SDLK_BACKSPACE:
			if (input_text.size() && input_pos) {
				input_text.erase(input_pos-1, 1);
				input_pos--;
			}
			return true;
			break;
			
		default:
			if ((key >= 32) && (key <175)) {
				if (input_text.size() < input_max) {
					// TODO bell sound
					if (input_pos == input_text.size())
						input_text += (char)key;
					else
						input_text.insert(input_pos, 1, (char)key);
					input_pos++;
				}
				return true;
			}
			break;
	}
	
	return false;
}
bool InputBox::on_keyrelease(const int key, const unsigned int modifier)
{
	return false;
}

}