#include "lgi/common/Lgi.h"
#include "lgi/common/Edit.h"
#include "lgi/common/Button.h"
#include "lgi/common/DisplayString.h"
#include "lgi/common/TextLabel.h"
#include "lgi/common/Css.h"
#include "lgi/common/DbTable.h"
#include "lgi/common/XmlTree.h"
#include "lgi/common/TabView.h"
#include "lgi/common/TextLog.h"
#include "lgi/common/DropFiles.h"
#include "lgi/common/TableLayout.h"

const char *AppName = "Lgi Test App";

enum Ctrls
{
	IDC_EDIT1 = 100,
	IDC_EDIT2,
	IDC_BLT_TEST,
	IDC_TXT,
};

void GStringTest()
{
	LString a("This<TD>is<TD>a<TD>test");
	a.RFind("<TD>");
	LString f = a(8,10);
	LString end = a(-5, -1);
	
	LString sep(", ");
	LString::Array parts = LString("This is a test").Split(" ");
	LString joined = sep.Join(parts);
	
	LString src("  asdwer   ");
	LString left = src.LStrip();
	LString right = src.RStrip();
	LString both = src.Strip();
	
}

LColourSpace RgbColourSpaces[] =
{
	/*
	CsIndex1,
	CsIndex4,
	CsIndex8,
	CsAlpha8,
	*/
	CsRgb15,
	CsBgr15,
	CsRgb16,
	CsBgr16,
	CsRgb24,
	CsBgr24,
	CsRgbx32,
	CsBgrx32,
	CsXrgb32,
	CsXbgr32,
	CsRgba32,
	CsBgra32,
	CsArgb32,
	CsAbgr32,
	CsBgr48,
	CsRgb48,
	CsBgra64,
	CsRgba64,
	CsAbgr64,
	CsArgb64,
	/*
	CsHls32,
	CsCmyk32,
	*/
	CsNone,
};

class BltTest : public LWindow
{
	struct Test
	{
		LColourSpace Src, Dst;
		LMemDC Result;
		
		void Create()
		{
			if (!Result.Create(16, 16, Dst))
				return;
			for (int y=0; y<Result.Y(); y++)
			{
				Result.Colour(Rgb24(y * 16, 0, 0), 24);
				for (int x=0; x<Result.X(); x++)
				{
					Result.Set(x, y);
				}
			}
			
			LMemDC SrcDC;
			if (!SrcDC.Create(16, 16, Src))
				return;
			
			// Result.Blt(0, 0, &SrcDC);
		}
	};
	
	LArray<Test*> a;

public:
	BltTest()
	{
		Name("BltTest");
		LRect r(0, 0, 1200, 1000);
		SetPos(r);
		MoveToCenter();
		
		if (Attach(0))
		{
			Visible(true);
			
			for (int Si=0; RgbColourSpaces[Si]; Si++)
			{
				for (int Di=0; RgbColourSpaces[Di]; Di++)
				{
					Test *t = new Test;
					t->Src = RgbColourSpaces[Si];
					t->Dst = RgbColourSpaces[Di];
					t->Create();
					a.Add(t);
				}
			}
		}
	}
	
	void OnPaint(LSurface *pDC)
	{
		pDC->Colour(L_WORKSPACE);
		pDC->Rectangle();
		
		int x = 10;
		int y = 10;
		for (unsigned i=0; i<a.Length(); i++)
		{
			char s[256];
			Test *t = a[i];
			sprintf_s(s, sizeof(s), "%s->%s", LColourSpaceToString(t->Src), LColourSpaceToString(t->Dst));
			LDisplayString ds(LSysFont, s);
			ds.Draw(pDC, x, y);
			y += ds.Y();
			if (t->Result.Y())
			{
				pDC->Blt(x, y, &t->Result);
				y += t->Result.Y();
			}
			y += 10;
			if (Y() - y < 100)
			{
				y = 10;
				x += 150;
			}
		}
	}
};

class DnDtarget : public LTextLog
{
public:
	DnDtarget() : LTextLog(10)
	{
	}

	int WillAccept(LDragFormats &Formats, LPoint Pt, int KeyState)
	{
		return DROPEFFECT_COPY;
	}

	int OnDrop(LArray<LDragData> &Data, LPoint Pt, int KeyState)
	{
		LString Keys;
		if (KeyState & LGI_EF_CTRL)
			Keys += "LGI_EF_CTRL ";
		if (KeyState & LGI_EF_ALT)
			Keys += "LGI_EF_ALT ";
		if (KeyState & LGI_EF_SHIFT)
			Keys += "LGI_EF_SHIFT ";

		Print("OnDrop(Data, ms={%i,%i}, keys={%s})\n", Pt.x, Pt.y, Keys?Keys.Get():"");
		for (unsigned i=0; i<Data.Length(); i++)
		{
			auto &d = Data[i];
			Print("\t[%i] fmt='%s'\n", i, d.Format.Get());
			for (unsigned n=0; n<d.Data.Length(); n++)
			{
				auto &v = d.Data[n];
				if (d.IsFileDrop())
				{
					LDropFiles df(d);
					Print("\t\t%i files:\n", (int)df.Length());
					for (unsigned f=0; f<df.Length(); f++)
					{
						Print("\t\t[%i]='%s'\n", f, df[f]);
					}
				}
				else
				{
					Print("\t\t[%i]=%s\n", n, v.ToString().Get());
				}
			}
		}

		return DROPEFFECT_COPY;
	}
};

class App : public LWindow
{
	LOptionsFile Opts;
	LEdit *e;
	LEdit *e2;
	LTextLabel *Txt;
	LTableLayout *Tbl;

public:
	App() : Opts(LOptionsFile::PortableMode, AppName)
	{
		e = 0;
		e2 = 0;
		Txt = 0;
		Tbl = 0;

		LRect r(0, 0, 1000, 800);
		SetPos(r);
		Name(AppName);
		MoveToCenter();
		SetQuitOnClose(true);

		Opts.SerializeFile(false);
		SerializeState(&Opts, "WndState", true);
		
		if (Attach(0))
		{
			#if 1

			LTabView *t = new LTabView(100);
			t->Attach(this);
			t->GetCss(true)->Padding("6px");

			auto *tab = t->Append("First");
			tab->GetCss(true)->FontStyle(LCss::FontStyleItalic);
			tab->Append(new DnDtarget());
			
			tab = t->Append("Second");
			tab->GetCss(true)->FontSize("14pt");
			
			tab = t->Append("Third");
			tab->GetCss(true)->Color("red");
			t->OnStyleChange();

			#elif 0

			AddView(Tbl = new LTableLayout(100));
			GLayoutCell *c = Tbl->GetCell(0, 0);

			c->Add(Txt = new LTextLabel(IDC_TXT, 0, 0, -1, -1, "This is a test string. &For like\ntesting and stuff. "
																"It has multiple\nlines to test wrapping."));
			Txt->SetWrap(true);
			//Txt->GetCss(true)->Color(LCss::ColorDef(LColour::Red));
			// Txt->GetCss(true)->FontWeight(LCss::FontWeightBold);
			// Txt->GetCss(true)->FontStyle(LCss::FontStyleItalic);
			Txt->GetCss(true)->FontSize(LCss::Len("22pt"));
			Txt->OnStyleChange();

			c = Tbl->GetCell(1, 0);
			c->Add(new LEdit(IDC_EDIT1, 0, 0, -1, -1));

			#elif 0

			AddView(e = new LEdit(IDC_EDIT1, 10, 10, 200, 22));
			AddView(e2 = new LEdit(IDC_EDIT1, 10, 50, 200, 22));
			AddView(new LButton(IDC_BLT_TEST, 10, 200, -1, -1, "Blt Test"));
			// e->Focus(true);
			e->Password(true);
			e->SetEmptyText("(this is a test)");

			#endif
			
			AttachChildren();
			// Debug();
			Visible(true);
		}
	}

	~App()
	{
		SerializeState(&Opts, "WndState", false);
		Opts.SerializeFile(true);
	}

	void OnPaint(LSurface *pDC)
	{
		auto c = GetClient();
		
		pDC->Colour(L_MED);
		pDC->Rectangle();
		
		#if 0
		pDC->Colour(LColour::Red);
		pDC->Line(0, 0, c.X()-1, c.Y()-1);
		#endif
	}
	
	int OnNotify(LViewI *Ctrl, LNotification n)
	{
		switch (Ctrl->GetId())
		{
			case IDC_BLT_TEST:
				new BltTest();
				break;
		}
		
		return 0;
	}
};

enum EmailFields
{
	M_UID = 100,
	M_FLAGS,
	M_DATE,
	M_LABEL,
	M_COLOUR,
	M_SIZE,
	M_FILENAME,
};

bool DbTesting()
{
	// LDbTable::UnitTests();

	#if 1
	const char *BaseFolder = "C:\\Users\\Matthew\\AppData\\Roaming\\Scribe\\ImapCache\\1434419972\\INBOX";
	#else
	const char *BaseFolder = "C:\\Users\\matthew\\AppData\\Roaming\\Scribe\\ImapCache\\378651814\\INBOX";
	#endif

	LFile::Path FileXml(BaseFolder, "Folder.xml");
	LFile::Path FileDb(BaseFolder, "Folder.db");
	LFile::Path FileDebug(BaseFolder, "Debug.txt");
	LFile In;
	if (!In.Open(FileXml, O_READ))
		return false;	
	
	// Read XML
	LXmlTag r;
	LXmlTree t;
	uint64 Start = LgiMicroTime();
	if (!t.Read(&r, &In))
		return false;
	uint64 XmlReadTime = LgiMicroTime() - Start;


	// Convert XML to DB
	LDbTable Tbl;
	Tbl.AddField(M_UID, GV_INT32);
	Tbl.AddField(M_FLAGS, GV_INT32);
	Tbl.AddField(M_DATE, GV_DATETIME);
	Tbl.AddField(M_LABEL, GV_STRING);
	Tbl.AddField(M_COLOUR, GV_INT32);
	Tbl.AddField(M_SIZE, GV_INT64);
	Tbl.AddField(M_FILENAME, GV_STRING);

	Start = LgiMicroTime();
	LXmlTag *Emails = r.GetChildTag("Emails");
	if (!Emails)
		return false;
	for (auto c: Emails->Children)
	{
		LDbRow *m = Tbl.NewRow();
		m->SetInt(M_UID, c->GetAsInt("Uid"));
		
		ImapMailFlags Flgs;
		Flgs.Set(c->GetAttr("Flags"));
		m->SetInt(M_FLAGS, Flgs.All);
		
		char *Date = c->GetAttr("Date");
		if (Date)
		{
			LDateTime Dt;
			if (Dt.Decode(Date))
			{
				if (!m->SetDate(M_DATE, &Dt))
				{
					LAssert(0);
				}
			}
			else
			{
				LAssert(0);
			}
		}
		else LAssert(0);
		
		m->SetStr(M_LABEL, c->GetAttr("Label"));
		m->SetInt(M_COLOUR, c->GetAsInt("Colour"));
		m->SetInt(M_SIZE, Atoi(c->GetAttr("Size")));
		m->SetStr(M_FILENAME, LString(c->GetContent()).Strip());
	}
	uint64 ConvertTime = LgiMicroTime() - Start;

	Start = LgiMicroTime();
	if (!Tbl.Serialize(FileDb, true))
		return false;
	uint64 WriteTime = LgiMicroTime() - Start;

	LDbTable Test;
	Start = LgiMicroTime();
	if (!Test.Serialize(FileDb, false))
		return false;
	uint64 ReadTime = LgiMicroTime() - Start;

	Start = LgiMicroTime();
	LAutoPtr<DbArrayIndex> Idx(Test.Sort(M_FILENAME));
	uint64 SortTime = LgiMicroTime() - Start;
	if (Idx)
	{
		LFile Out;
		if (Out.Open(FileDebug, O_WRITE))
		{
			Out.SetSize(0);
			for (unsigned i=0; i<Idx->Length(); i++)
			{
				LString s = Idx->ItemAt(i)->ToString();
				s += "\n";
				Out.Write(s);
			}
			Out.Close();
		}
	}

	LgiTrace("DbTest: %i -> %i\n"
		"\tXmlReadTime=%.3f\n"
		"\tConvertTime=%.3f\n"
		"\tWriteTime=%.3f\n"
		"\tReadTime=%.3f\n"
		"\tSortTime=%.3f\n",
		Tbl.GetRows(), Test.GetRows(),
		(double)XmlReadTime/1000.0,
		(double)ConvertTime/1000.0,
		(double)WriteTime/1000.0,
		(double)ReadTime/1000.0,
		(double)SortTime/1000.0);

	return true;
}


int LgiMain(OsAppArguments &AppArgs)
{
	LApp a(AppArgs, "Lgi Test");
	if (a.IsOk())
	{
		a.AppWnd = new App;
		a.Run();
	}
	return 0;
}
