#include "CtrlLib.h"

namespace Upp {

void SuggestCtrl::CancelMode()
{
	Cancel();
}

int SuggestCtrl::IsDelimiter(int c)
{
	if(delimiter_filter || delimiter_char) {
		if(delimiter_filter)
			c = (*delimiter_filter)(c);
		if(delimiter_char && delimiter_char != c)
			c = 0;
		return c;
	}
	return 0;
}

WString SuggestCtrl::CF(const WString& src)
{
	return compare_filter ? UPP::Filter(src, compare_filter) : src;
}

WString SuggestCtrl::ReadLast(int& h)
{
	int l;
	GetSelection(l, h);
	if(l != h)
		return Null;
	WString text = GetText();
	WString x;
	while(--l >= 0 && !IsDelimiter(text[l])) {
		h = l;
		x.Insert(0, text[l]);
	}
	return Upp::TrimLeft(x);
}

void SuggestCtrl::Select()
{
	if(list.IsCursor()) {
		int h;
		WString x = ReadLast(h);
		int q;
		if(GetSelection(q, q))
			return;
		Remove(h, q - h);
		x = list.GetKey();
		Insert(h, x);
		h += x.GetCount();
		SetSelection(h, h);
		Cancel();
		Action();
	}
}

bool SuggestCtrl::Key(dword key, int count)
{
	if(list.IsOpen()) {
		if(key == K_UP || key == K_PAGEUP || key == K_CTRL_PAGEDOWN) {
			if(list.IsCursor())
				return list.Key(key, count);
			else {
				list.GoEnd();
				return true;
			}
		}
		if(key == K_DOWN || key == K_PAGEDOWN || key == K_CTRL_PAGEUP) {
			if(list.IsCursor())
				return list.Key(key, count);
			else {
				list.GoBegin();
				return true;
			}
		}
	}
	if(key == K_ENTER && list.IsOpen() && list.IsCursor()) {
		Select();
		return true;
	}
	if(key == K_ESCAPE && list.IsOpen()) {
		Close();
		return true;
	}
	int cc = IsDelimiter(key);
	if(cc)
		key = cc;
	if(EditString::Key(key, count)) {
		if(key >= 32 && key < 65536 || key == K_BACKSPACE || key == K_CTRL_SPACE) {
			int h;
			WString x = CF(ReadLast(h));
			list.Clear();
			for(int i = 0; i < data.GetCount(); i++) {
				WString h = CF(data[i]);
				if(just_start ? h.StartsWith(x) : h.Find(x) >= 0)
					list.Add(data[i]);
			}
			if(list.GetCount() == 0) {
				Cancel();
				return true;
			}
			Rect cr = GetCaretRect(h) + GetScreenView().TopLeft();
			Rect wr = GetWorkArea();
			int c = droplines * Draw::GetStdFontCy();
			Rect r(cr.BottomLeft(), Size(c, c));
			r.SetSize(c, c);
			if(r.bottom > wr.bottom) {
				r.top = cr.top - c;
				r.bottom = r.top + c;
			}
			if(r.right > wr.right) {
				r.left = cr.left - c;
				r.right = r.left + c;
			}
			list.SetRect(r);
			if(!list.IsOpen()) 
				list.Ctrl::PopUp(GetParent(), false, false, true);
		}
		else
			Cancel();
		return true;
	}
	return false;
}

void SuggestCtrl::Cancel()
{
	if(list.IsOpen())
		list.Close();
}

void SuggestCtrl::LostFocus()
{
	EditField::LostFocus();
	Cancel();	
}

void SuggestCtrl::GotFocus()
{
	EditField::GotFocus();
	Move(GetLength());
}

SuggestCtrl::SuggestCtrl()
{
	list.AddColumn();
	list.NoHeader().NoGrid();
	list.SetFrame(BlackFrame());
	list.MouseMoveCursor();
	list.WhenLeftClick = THISBACK(Select);
	list.NoWantFocus();
	delimiter_char = 0;
	delimiter_filter = NULL;
	droplines = 16;
	compare_filter = NULL;
	just_start = false;
}

}
