#include "sgl.h"
#include <stdio.h>

#pragma warn(disable: 2118 2216)	/* disable some warnings					*/
				/* 2118: Parameter {parameter_name} is not referenced.			*/
				/* 2216: The return value from {function_name} is never used.	*/

static HWND mainPanel, rightPanel, table;

													/* TABLE DATA				*/
													/*--------------------------*/

static SGL_TABLE_COLUMN_T columns[] =				/* table columns			*/
{
	{ -10,	0,	0,	0xAAAAFF } ,
	{ -5,	1,	0,	0xFFBBBB } ,						/* header merge			*/
	{ -6,	0,	0,	0xFFBBBB } ,
	{ -5,	0,	0,	0xAAFFAA } ,
	{ -2,	0,	1,	0XCCCCCC } ,						/* no right separator	*/
	{ -8,	0,	0,	0XCCCCCC } ,
	{ 0 }
};

static char *headers[] =								/* column headers		*/
{ 
	"Item name",
	"", "Delivery", 
	"Discount", 
	"", 
	"Selected items" 
};

#define ROW_NB 32000								/* rows						*/
static char itemName[ROW_NB][32];						/* string				*/
static int allChecked, checked[ROW_NB];					/* boolean 0|1			*/
static int discount[ROW_NB];							/* percent				*/
static int delivery[ROW_NB];							/* delivery index		*/
static SYSTEMTIME date[ROW_NB] ;


static SGL_POPUPMENU_OPTIONS_T deliveryOpt[] =		/* delivery options			*/
{
	{0, "Slow"},
	{0, "Fast"},
	{0, "Damn fast"},
	{0, NULL}
};

/*------------------------------------------------------------- DATE FUNCTION --*/

void dateAdd(SYSTEMTIME *dt, int days)
{
	if (dt)
	{
		unsigned long long ft = 0 ;
		SystemTimeToFileTime(dt, (FILETIME*) &ft) ;
		ft += 10000000ULL * 86400 * days ;
		FileTimeToSystemTime((FILETIME*) &ft, dt) ;
	}
}

/*------------------------------------------------------------------- DIMMING --*/

int dimCB(HWND hwnd, UINT event, WPARAM wParam, LPARAM lParam)
{
	static char *label[2] = { "TABLE ON" , "TABLE OFF" };
	static int color[2] = { RGB(0,255,0), RGB(255,0,0) };

	if (event == WM_USER)						/* button value has changed		*/
	{
		int dimmed = SGL_ButtonValueGet(hwnd) ? 0 : 1;	/* get its value		*/
		SGL_ButtonValueSet(hwnd, dimmed);				/* set the new value	*/

		SGL_TitleSet(hwnd, label[dimmed]);				/* set the new aspect	*/
		SGL_BGcolorSet(hwnd, color[dimmed]);
		SGL_Redraw(hwnd);

		SGL_DimmedSet(table, dimmed);					/* table process		*/
		SGL_Redraw(table);
	}
	return 0;
}


/*------------------------------------------- RADIO BUTTONS - TABLE SELECTION --*/

#define RADIOBTNNB 4
static HWND rbtn[RADIOBTNNB];
static char *rLabel[RADIOBTNNB] = { "None", "Cell", "Line", "Lines" };

static int radioBtnCB(HWND hwnd, UINT event, WPARAM wParam, LPARAM lParam)
{
	if (event == WM_USER)					/* one button has changed value		*/
	{
		for (int b = 0; b < RADIOBTNNB; b++)	 		/* which one?			*/
		{
			if (hwnd == rbtn[b])					 		/* this one ..		*/
			{
				SGL_ButtonValueSet(rbtn[b], 1);
				SGL_TableSelectionModeSet(table, b);
			}
			else
				SGL_ButtonValueSet(rbtn[b], 0);  		/* reset other buttons	*/
		}
		SGL_Redraw(table);					/* update the display				*/
		PostMessage(table, WM_SETFOCUS, 0, 0);
	}
	return 0;
}

static void radioBtnInstall(HWND parent, int c, int r, int init)
{
	SGL_New(parent, SGL_CTRL_BUTTON, 0, "Select mode", 0, 2);	/* text button	*/
	for (int b = 0 ; b < RADIOBTNNB ; b++)
	{
		rbtn[b] = SGL_New(parent, SGL_CTRL_RADIOBUTTON, DT_LEFT,
							 rLabel[b], c, r + b);
		SGL_CallbackFunctionSet(rbtn[b], radioBtnCB);
		SGL_ButtonValueSet(rbtn[b], (b == init));
	}

	SGL_TableSelectionModeSet(table, init);
}

/*----------------------------------------------------------- NUMERIC EDITING --*/

static int discountEditCB(WPARAM virtKey, char* s, int len, int caret, void *cbd)
{
	int value, entry;
	int result = 0;
	entry = strtol(s, NULL, 10);

	switch (virtKey)
	{
		case VK_UP :							/* up/down/scroll edit			*/
		case VK_DOWN :
		{
			int inc = SGL_KEY_SHIFT ? 10 : 1;
			entry += (virtKey == VK_UP) ? inc : - inc;
			result = 1;							/* edit box must be updated		*/
			break;
		}
	}

	value = max(0, min(entry, 90));
	if (value != entry)							/* entry was out of limits		*/
	{
		MessageBeep(MB_ICONHAND);
		result = 1;								/* edit box must be updated		*/
	}

	if (result)									/* update the edited string		*/
		sprintf(s, "%02d", value);
	*((int*) cbd) = value;						/* update the discount array	*/

	return result;
}

/*--------------------------------------------- TABLE CALLBACK - CELL EDITING --*/

static int tableCB(HWND hwnd, UINT event, WPARAM wParam, LPARAM lParam)
{
	if (event == WM_RBUTTONUP)					/* some column may be edited	*/
	{
		int r, c;											/* clicked cell		*/
		if (SGL_TableCellCoordinatesGet(hwnd, &r, &c))
			return 0;

		RECT rect;										/* cell rectangle used	*/
		SGL_TableCellRectangleGet(hwnd, r, c, &rect);	/* to locate a popup	*/

		if (r >= 0 && c == 0)						/* edit the name			*/
			SGL_PopupEdit(hwnd, &rect, ES_LEFT,
						 	itemName[r], sizeof(itemName[0]), NULL, NULL);

		if (r >= 0 && c == 1)						/* edit the delivery speed	*/
		{
			COLORREF savedBG = columns[c].cellBGcolor;
			columns[c].cellBGcolor = SGL_WHITE;			/* temporary cell color	*/
			SGL_TableUpdate(hwnd, r, 1, c);
			int e = SGL_PopupMenu(hwnd, deliveryOpt, &rect, SGL_CENTER);
			if (e >= 0)
				delivery[r] = e;
			columns[c].cellBGcolor = savedBG;			/* restore cell color	*/
			SGL_TableUpdate(hwnd, r, 1, c);
		}

		if (r >= 0 && c == 2)						/* edit the delivery date	*/
		{
			int dateStyle = SGL_DATE | SGL_DT_CALENDAR | SGL_DT_NONE ;
	        SGL_PopupDatetime(hwnd, &rect, dateStyle, NULL, &(date[r]), NULL, NULL) ;
		}

		if (r >= 0 && c == 3)						/* edit the discount		*/
		{
			static char s[12]; sprintf(s, "%02d", discount[r]);
			SGL_PopupEdit(hwnd, &rect, ES_CENTER | ES_NUMBER, 
							s, 8, discountEditCB, &(discount[r]));
		}

		if (c == 4)									/* edit the check			*/
		{
			if (r < 0)								/* if clicked in the header	*/
			{
				allChecked = allChecked ? 0 : 1;				/* change all	*/
				for (size_t i = 0 ; i < ROW_NB ; i++)
					checked[i] = allChecked;
				SGL_Redraw(hwnd);
			}
			else									/* if clicked in a cell		*/
			{
				checked[r] = checked[r] ? 0 : 1;				/* change it	*/
				SGL_TableUpdate(hwnd, r, 1, c);
			}
		}
	}
	return 0;
}

/*------------------------------------------------------------- TABLE FILLING --*/

static void tableFill(HWND hwnd, HDC hdc, int row, int col, RECT *rect)
{
	UINT styleCenter = DT_SINGLELINE | DT_VCENTER | DT_CENTER;	/* text style	*/
	UINT styleLeft   = DT_SINGLELINE | DT_VCENTER | DT_LEFT;

	static wchar_t s[2] = {0xea53, 0xea52};					/* check symbols	*/

	static char l[32];										/* cell text		*/
	snprintf(l, 32, " %d/%d ", row, col);					/* default text		*/

	if (row < 0 && col >= 0)
	{
		if (col == 4)										/* draw check box	*/
		{
			HFONT newFont = SGL_FontHandleGet(hwnd, -1, SGL_FONT_EXTRA);
			HFONT previous = SelectObject(hdc, newFont);
			SetBkMode(hdc, TRANSPARENT);
			DrawTextW(hdc, s, 1, rect, styleCenter);
			SelectObject(hdc, previous);
		}
		else												/* other headers	*/
			DrawText(hdc, headers[col], -1, rect, styleCenter);
	}
	else switch (col)
	{
		case -1 :										/* notification			*/
			break;

		case 0 :										/* name column			*/
			rect->left += SGL_DefPaddingGet();			/* default padding left	*/
			DrawText(hdc, itemName[row], -1, rect, styleLeft);
			break;

		case 1 :										/* delivery speed		*/
			DrawText(hdc, deliveryOpt[delivery[row]].text, -1, rect, styleCenter);
			break;

		case 2 :										/* delivery date		*/
			SGL_DateTimeStringGet(&(date[row]), SGL_DATE, NULL, l, sizeof(l));
			DrawText(hdc, l, -1, rect, styleCenter);
			break ;

		case 3 :										/* discount column		*/
			sprintf(l, "%02d %c", discount[row], '%');
			DrawText(hdc, l, -1, rect, styleCenter);
			break;

		case 4 :										/* check column			*/
		{
			HFONT newFont = SGL_FontHandleGet(hwnd, -1, SGL_FONT_EXTRA);
			HFONT previous = SelectObject(hdc, newFont);
			DrawTextW(hdc, s + checked[row], 1, rect, styleCenter);
			SelectObject(hdc, previous);
			break;
		}

		default :										/* other columns		*/
			DrawText(hdc, l, -1, rect, styleCenter);
			break;
	}
}

/*==============================================================================*/

HWND mainBuild(HWND parent, int c, int r)			/* build the top window		*/
{
	HWND panel = SGL_New(parent, SGL_PANEL, 0, "Main frame", c, r);
	table = SGL_New(panel, SGL_CTRL_TABLE, WS_VSCROLL, "Table", 0, 0);

							/* table minimum height = height of the right panel	*/
	SGL_AlignmentSet(table, SGL_TOP | SGL_BOTTOM);

	SGL_TableColumnsSet(table, columns);
	SGL_TableHeaderBorderThicknessSet(table, -40);
	SGL_TableFillFunctionSet(table, tableFill);
	SGL_CallbackFunctionSet(table, &tableCB);
	SGL_BGcolorSet(table, 0xF0F080);
	SGL_TableGridColorSet(table, 0x4444a0);
	SGL_TableAltRowSet(table, 2);

	SGL_TableRowNbSet(table, ROW_NB);
	for (int i = 0 ; i < ROW_NB ; i++)	/* initial values	*/
	{
		sprintf(itemName[i], "%c%c%c", ((i / 676) % 26) + 'A', 
										((i / 26) % 26) + 'a', 
											   (i % 26) + 'a'); 
		discount[i] = rand() % 90;
		checked[i] =	rand() % 2;
		delivery[i] = rand() % 3;

		if ((double) rand() / RAND_MAX < 0.5)
			SGL_DATETIME_NONE_SET(date[i]) ;
		else
		{
			dateAdd(&date[i], 7 + rand() % 28) ;
			SYSTEMTIME now = SGL_DateTimeNow() ;
			unsigned long long ft = 0 ;
			SystemTimeToFileTime(&now, (FILETIME*) &ft) ;
			ft += 10000000ULL * 86400 * (7 + rand() % 28) ;
			FileTimeToSystemTime((FILETIME*) &ft, &date[i]) ;
		}
	}
													/* create the right panel	*/
	rightPanel = SGL_New(panel, SGL_HIDDENFRAME, 0, "Btn frame", 1, 0);
	SGL_AlignmentSet(rightPanel, SGL_CENTER);

	HWND f = SGL_New(rightPanel, SGL_CTRL_PUSHBUTTON, 0, "Dim", 0, 0);
	SGL_CallbackFunctionSet(f, dimCB);
	dimCB(f, WM_USER, 0, 0);									/* initialize	*/

	f = SGL_New(rightPanel, SGL_CTRL_EDIT, ES_LEFT | ES_MULTILINE, 
							"What to do", 0, 1);
	SGL_SizeSet(f, SGL_WIDTH, -1);					/* set same width as button	*/
	SGL_AlignmentSet(f, SGL_LEFT | SGL_RIGHT);
	SGL_SizeSet(f, SGL_HEIGHT, -5);					/* set height (lines)		*/
	SGL_EditTextSet(f, "Press the right button of the mouse to change"
							  " the value in the 5 first columns.");

	radioBtnInstall(rightPanel, 0, 3, 0);					/* radio buttons	*/
	return panel;
}

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
					PSTR szCmdLine, int iCmdShow)
{
	AllocConsole();								/* for console messages			*/
	SGL_DebugSet(NULL, 2);
	SGL_Init(hInstance, "#8001");
	SGL_Log(STD, "==== SGL DEMO ====\n");

	SGL_FontLoad(":MYFONT:#8002");
//	SGL_FontLoad("sample_data\\IcoMoon-Free.ttf");
	SGL_FontFaceSet(SGL_FONT_EXTRA, "IcoMoon-Free");

	mainPanel = SGL_New(0, SGL_PANEL, WS_MINIMIZEBOX, "Main Panel", -1, -1);
	SGL_BGcolorSet(mainPanel, 0xb0e0b0);

	mainBuild(mainPanel, 0, 0);					/* build the main frame			*/
	SGL_ResizeInstall(table, 0, 1, NULL) ;		/* resize height only			*/
	SGL_Layout(mainPanel);

	SGL_VisibleSet(mainPanel, 1);
	SGL_Run();

	SGL_Exit();
	return 0;
}