// LUADBG.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "LUADBG.h"
#include "_TinyRegistry.h"
#include "_TinyFileEnum.h"
#include "_TinyBrowseFolder.h"
#include "AboutWnd.h"

_TINY_DECLARE_APP();

CLUADbg::CLUADbg()
{

}

CLUADbg::~CLUADbg()
{
	_TinyRegistry cTReg;
	_TinyVerify(cTReg.WriteNumber("Software\\Tiny\\LuaDebugger\\", "MainHorzSplitter", m_wndMainHorzSplitter.GetSplitterPos()));
	_TinyVerify(cTReg.WriteNumber("Software\\Tiny\\LuaDebugger\\", "SrcEditSplitter", m_wndSrcEditSplitter.GetSplitterPos()));
	_TinyVerify(cTReg.WriteNumber("Software\\Tiny\\LuaDebugger\\", "WatchSplitter", m_wndWatchSplitter.GetSplitterPos()));
	_TinyVerify(cTReg.WriteNumber("Software\\Tiny\\LuaDebugger\\", "WatchCallstackSplitter", m_wndWatchCallstackSplitter.GetSplitterPos()));
}

TBBUTTON tbButtonsAdd [] = 
{
	{ 0, ID_DEBUG_RUN, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0L, 0 },
	{ 1, ID_DEBUG_BREAK, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0L, 0 },
	{ 2, ID_DEBUG_STOP, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0L, 0 },

	{ 0, 0, TBSTATE_ENABLED, BTNS_SEP, { 0 }, 0L, 0 },
	
	{ 3, ID_DEBUG_STEPINTO, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0L, 0 },
	{ 4, ID_DEBUG_STEP_OVER, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0L, 0 },
	{ 5, ID_DEBUG_TOGGLEBREAKPOINT, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0L, 0 },

	{ 0, 0, TBSTATE_ENABLED, BTNS_SEP, { 0 }, 0L, 0 },

	{ 7, IDM_ABOUT, TBSTATE_ENABLED, BTNS_BUTTON, { 0 }, 0L, 0 },
}; 

LRESULT CLUADbg::OnCreate(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	_TinyRect erect;
	_TinyRect lrect;
	_TinyRect wrect;
	_TinyRegistry cTReg;

	SetWindowPos(0, 0, 800, 700, SWP_NOZORDER | SWP_NOMOVE);
	CenterOnScreen();
	GetClientRect(&wrect);

	erect=wrect;
	erect.top=0;
	erect.bottom=32;
	m_wToolbar.Create((ULONG) GetMenu(m_hWnd), WS_CHILD | WS_VISIBLE | TBSTYLE_TOOLTIPS, 0, &erect, this);
	m_wToolbar.AddButtons(IDC_LUADBG, tbButtonsAdd, 9);
	
	m_wndStatus.Create(0, NULL, this);

	// Client area window
	_TinyVerify(m_wndClient.Create(NULL, _T(""), WS_CHILD | WS_VISIBLE, 0, &wrect, this));

	// Splitter dividing source/file and watch windows
	m_wndMainHorzSplitter.Create(&m_wndClient, NULL, NULL, true);

	// Divides source and file view
	m_wndSrcEditSplitter.Create(&m_wndMainHorzSplitter);

	// Divides two watch windows
	m_wndWatchSplitter.Create(&m_wndMainHorzSplitter);

	// Divides the watch window and the cllstack
	m_wndWatchCallstackSplitter.Create(&m_wndWatchSplitter);
	
	// Add all scripts to the file tree
	m_wFilesTree.Create(erect, &m_wndSrcEditSplitter, IDC_FILES);
	char szRootPath[] = "C:\\MasterCD\\SCRIPTS\\";
	m_wFilesTree.ScanFiles(szRootPath);

	_TinyVerify(m_wScriptWindow.Create(WS_VISIBLE | WS_CHILD | ES_WANTRETURN | WS_HSCROLL | WS_VSCROLL | 
		ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE, 0, &erect, &m_wndSrcEditSplitter));
	m_wScriptWindow.SendMessage(EM_SETEVENTMASK,0,ENM_SCROLL);

	m_wndFileViewCaption.Create("Scripts", &m_wFilesTree, &m_wndSrcEditSplitter);
	m_wndSourceCaption.Create("Source", &m_wScriptWindow, &m_wndSrcEditSplitter);
	m_wndSrcEditSplitter.SetFirstPan(&m_wndFileViewCaption);
	m_wndSrcEditSplitter.SetSecondPan(&m_wndSourceCaption);

	m_wLocals.Create(IDC_LOCALS,WS_CHILD|TVS_HASLINES|TVS_HASBUTTONS|TVS_LINESATROOT|WS_VISIBLE,WS_EX_CLIENTEDGE,&erect, &m_wndWatchSplitter);
	m_wWatch.Create(IDC_WATCH,WS_CHILD|WS_VISIBLE,WS_EX_CLIENTEDGE,&erect, &m_wndWatchSplitter);
	m_wCallstack.Create(0,WS_CHILD|TVS_HASLINES|TVS_HASBUTTONS|TVS_LINESATROOT|WS_VISIBLE,WS_EX_CLIENTEDGE,&erect, &m_wndWatchSplitter);

	m_wndLocalsCaption.Create("Locals", &m_wLocals, &m_wndWatchSplitter);
	m_wndWatchCaption.Create("Watch", &m_wWatch, &m_wndWatchCallstackSplitter);
	m_wndCallstackCaption.Create("Callstack", &m_wCallstack, &m_wndWatchCallstackSplitter);

	m_wndWatchSplitter.SetFirstPan(&m_wndWatchCallstackSplitter);

	m_wndWatchCallstackSplitter.SetFirstPan(&m_wndWatchCaption);
	m_wndWatchCallstackSplitter.SetSecondPan(&m_wndCallstackCaption);

	m_wndWatchSplitter.SetSecondPan(&m_wndLocalsCaption);

	m_wndMainHorzSplitter.SetFirstPan(&m_wndSrcEditSplitter);
	m_wndMainHorzSplitter.SetSecondPan(&m_wndWatchSplitter);

	HTREEITEM hTI=m_wLocals.AddItemToTree("asdasd");
	hTI=m_wLocals.AddItemToTree("eeee");
	m_wLocals.AddItemToTree("asasd = 100",NULL,hTI);
	m_wLocals.AddItemToTree("asasd = 100",NULL,hTI);
	m_wLocals.AddItemToTree("asasd = 100",NULL,hTI);
	m_wLocals.AddItemToTree("asasd = 100",NULL,hTI);
	m_wLocals.AddItemToTree("asasd = 100",NULL,hTI);
	m_wLocals.AddItemToTree("asasd = 100",NULL,hTI);
	m_wLocals.AddItemToTree("asasd = 100",NULL,hTI);
	m_wLocals.AddItemToTree("asasd = 100",NULL,hTI);
	m_wLocals.AddItemToTree("asasd = 100",NULL,hTI);
	m_wLocals.AddItemToTree("asasd = 100",NULL,hTI);
	m_wLocals.AddItemToTree("asasd = 100",NULL,hTI);
	m_wLocals.AddItemToTree("asasd = 100",NULL,hTI);
	m_wLocals.AddItemToTree("asasd = 100",NULL,hTI);
	m_wLocals.AddItemToTree("asasd = 100",NULL,hTI);
	m_wLocals.AddItemToTree("asasd = 100",NULL,hTI);
	m_wLocals.AddItemToTree("asasd = 100",NULL,hTI);
	hTI=m_wLocals.AddItemToTree("asasd = 100",NULL,hTI);
	hTI=m_wLocals.AddItemToTree("uuuuuu",NULL,hTI);

 	Reshape(wrect.right-wrect.left,wrect.bottom-wrect.top);

	// Read splitter window locations from registry
	DWORD dwVal;
	cTReg.ReadNumber("Software\\Tiny\\LuaDebugger\\", "MainHorzSplitter", dwVal, 150);
	m_wndMainHorzSplitter.SetSplitterPos(dwVal);
	m_wndMainHorzSplitter.Reshape();
	cTReg.ReadNumber("Software\\Tiny\\LuaDebugger\\", "SrcEditSplitter", dwVal, 190);
	m_wndSrcEditSplitter.SetSplitterPos(dwVal);
	m_wndSrcEditSplitter.Reshape();
	cTReg.ReadNumber("Software\\Tiny\\LuaDebugger\\", "WatchSplitter", dwVal, wrect.right / 3 * 2);
	m_wndWatchSplitter.SetSplitterPos(dwVal);
	m_wndWatchSplitter.Reshape();
	cTReg.ReadNumber("Software\\Tiny\\LuaDebugger\\", "WatchCallstackSplitter", dwVal, wrect.right / 3);
	m_wndWatchCallstackSplitter.SetSplitterPos(dwVal);
	m_wndWatchCallstackSplitter.Reshape();

	_TinyVerify(LoadFile("C:\\MASTERCD\\SCRIPTS\\Default\\Entities\\PLAYER\\BasicPlayer.lua"));
	//_TinyVerify(LoadFile("C:\\MASTERCD\\SCRIPTS\\Default\\Entities\\PLAYER\\player.lua"));

	// _TINY_CHECK_LAST_ERROR

	return 0;
}

bool CLUADbg::LoadFile(const char *pszFile)
{
	FILE *hFile = NULL;
	char *pszScript = NULL, *pszFormattedScript = NULL;
	UINT iLength, iCmpBufPos, iSrcBufPos, iDestBufPos, iNumChars, iStrStartPos, iCurKWrd, i;
	char szCmpBuf[2048];
	bool bIsKeyWord;
	
	hFile = fopen(pszFile, "rb");

	if (!hFile)
		return false;

	// Get file size
	fseek(hFile, 0, SEEK_END);
	iLength = ftell(hFile);
	fseek(hFile, 0, SEEK_SET);

    pszScript = new char [iLength + 1];
	pszFormattedScript = new char [256 + iLength * 2];

	_TinyVerify(fread(pszScript, iLength, 1, hFile) == 1);
	pszScript[iLength] = '\0';
	_TinyAssert(strlen(pszScript) == iLength);

	// RTF text, font Courier, green comments and blue keyword
	strcpy(pszFormattedScript, "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033" \
		"{\\fonttbl{\\f0\\fmodern\\fprq1\\fcharset0 Courier(PS);}{\\f1\\fswiss\\fcharset0 Arial;}}" \
		"{\\colortbl ;\\red0\\green0\\blue255;\\red0\\green128\\blue0;\\red160\\green160\\blue160;}\\f0\\fs20");

	const char szKeywords[][32] =
	{
		"function",
		"do",
		"for",
		"end",
		"and",
		"or",
		"not",
		"while",
		"return",
		"if",
		"then",
		"else",
		"elseif",
		"self",
		"local",
		"in",
		"nil",
		"repeat",
		"until",
		"break",
	};

	// Format text with syntax coloring
	iDestBufPos = strlen(pszFormattedScript);

	iSrcBufPos = 0;
	while (pszScript[iSrcBufPos] != '\0')
	{
		// Scan next token
		iNumChars = 1;
		iStrStartPos = iSrcBufPos;
		while (pszScript[iSrcBufPos] != ' '  &&
			   pszScript[iSrcBufPos] != '\n' &&
			   pszScript[iSrcBufPos] != '\r' &&
			   pszScript[iSrcBufPos] != '\t' &&
			   pszScript[iSrcBufPos] != '\0' &&
			   pszScript[iSrcBufPos] != '('  &&
			   pszScript[iSrcBufPos] != ')'  &&
			   pszScript[iSrcBufPos] != '['  &&
			   pszScript[iSrcBufPos] != ']'  &&
			   pszScript[iSrcBufPos] != '{'  &&
			   pszScript[iSrcBufPos] != '}'  &&
			   pszScript[iSrcBufPos] != ','  &&
			   pszScript[iSrcBufPos] != '.'  &&
			   pszScript[iSrcBufPos] != ';'  &&
			   pszScript[iSrcBufPos] != ':'  &&
			   pszScript[iSrcBufPos] != '='  &&
			   pszScript[iSrcBufPos] != '==' &&
			   pszScript[iSrcBufPos] != '*'  &&
			   pszScript[iSrcBufPos] != '+'  &&
			   pszScript[iSrcBufPos] != '/'  &&
			   pszScript[iSrcBufPos] != '~'  &&
			   pszScript[iSrcBufPos] != '"')
		{
			iSrcBufPos++;	
			iNumChars++;

			// Special treatment of '-' to allow parsing of '--'
			if (pszScript[iSrcBufPos - 1] == '-' && pszScript[iSrcBufPos] != '-')
				break;
		}
		if (iNumChars == 1)
			iSrcBufPos++;
		else
			iNumChars--;

		// Copy token and add escapes
		iCmpBufPos = 0;
		for (i=iStrStartPos; i<iStrStartPos + iNumChars; i++)
		{
			_TinyAssert(i - iStrStartPos < sizeof(szCmpBuf));

			if (pszScript[i] == '{' || pszScript[i] == '}' || pszScript[i] == '\\')
			{
				// Add \ to mark it as non-escape character
				szCmpBuf[iCmpBufPos++] = '\\';
				szCmpBuf[iCmpBufPos++] = pszScript[i];
				szCmpBuf[iCmpBufPos] = '\0';
			}
			else
			{
				szCmpBuf[iCmpBufPos++] = pszScript[i];
				szCmpBuf[iCmpBufPos] = '\0';
			}
		}

		// Comment
		if (strncmp(szCmpBuf, "--", 2) == 0)
		{
			// Green
			strcat(pszFormattedScript, "\\cf2 ");
			iDestBufPos += 5;
			
			strcpy(&pszFormattedScript[iDestBufPos], szCmpBuf);
			iDestBufPos += strlen(szCmpBuf);

			// Parse until newline
			while (pszScript[iSrcBufPos] != '\n' && pszScript[iSrcBufPos] != '\0')
			{
				pszFormattedScript[iDestBufPos++] = pszScript[iSrcBufPos++];
			}
			iSrcBufPos++;
			pszFormattedScript[iDestBufPos] = '\0';

			// Add newline and restore color
			strcat(pszFormattedScript, "\\par\n");
			iDestBufPos += 5;
			strcat(pszFormattedScript, "\\cf0 ");
			iDestBufPos += 5;

			continue;
		}
		
		// String
		if (strncmp(szCmpBuf, "\"", 2) == 0)
		{
			// Gray
			strcat(pszFormattedScript, "\\cf3 ");
			iDestBufPos += 5;
			
			strcpy(&pszFormattedScript[iDestBufPos], szCmpBuf);
			iDestBufPos += strlen(szCmpBuf);

			// Parse until end string / newline
			while (pszScript[iSrcBufPos] != '\n' && pszScript[iSrcBufPos] != '\0' && pszScript[iSrcBufPos] != '"')
			{
				pszFormattedScript[iDestBufPos++] = pszScript[iSrcBufPos++];
			}
			iSrcBufPos++;
			pszFormattedScript[iDestBufPos] = '\0';

			// Add literal
			strcat(pszFormattedScript, "\"");
			iDestBufPos += 1;

			// Restore color
			strcat(pszFormattedScript, "\\cf0 ");
			iDestBufPos += 5;

			continue;
		}

		// Have we parsed a keyword ?
		bIsKeyWord = false;
		for (iCurKWrd=0; iCurKWrd<sizeof(szKeywords) / sizeof(szKeywords[0]); iCurKWrd++)
		{
			if (strcmp(szKeywords[iCurKWrd], szCmpBuf) == 0)
			{
				strcat(pszFormattedScript, "\\cf1 ");
				strcat(pszFormattedScript, szKeywords[iCurKWrd]);
				strcat(pszFormattedScript, "\\cf0 ");
				iDestBufPos += 5 + 5 + strlen(szKeywords[iCurKWrd]);
				bIsKeyWord = true;
			}
		}
		if (bIsKeyWord)
			continue;

		if (strcmp(szCmpBuf, "\n") == 0)
		{
			// Newline
			strcat(pszFormattedScript, "\\par ");
			iDestBufPos += 5;
		}
		else
		{
			// Anything else, just append
			iDestBufPos += strlen(szCmpBuf);
			strcat(pszFormattedScript, szCmpBuf);
		}
	}

	if (pszScript)
	{
		delete [] pszScript;
		pszScript = NULL;
	}

	m_wScriptWindow.SetText(pszFormattedScript);

	if (pszFormattedScript)
	{
		delete [] pszFormattedScript;
		pszFormattedScript = NULL;
	}

	if (hFile)
		fclose(hFile);

	return true;
}

LRESULT CLUADbg::OnEraseBkGnd(HWND hWnd,UINT message, WPARAM wParam, LPARAM lParam)
{
	return 1;
}

LRESULT CLUADbg::OnClose(HWND hWnd,UINT message, WPARAM wParam, LPARAM lParam)
{
	Quit();
	return 0;
}


LRESULT CLUADbg::OnSize(HWND hWnd,UINT message, WPARAM wParam, LPARAM lParam)
{

	int w=LOWORD(lParam);
	int h=HIWORD(lParam);
	Reshape(w,h);
	
	return 0;
}

LRESULT CLUADbg::OnAbout(HWND hWnd,UINT message, WPARAM wParam, LPARAM lParam)
{
	CAboutWnd wndAbout;
	wndAbout.DoModal(this);
	return 0;
}

LRESULT CLUADbg::OnToggleBreakpoint(HWND hWnd,UINT message, WPARAM wParam, LPARAM lParam)
{
	int x = 0;
	return 0;
};

#define TOOLBAR_HEIGHT 28
#define STATUS_BAR_HEIGHT 20

bool CLUADbg::Reshape(int w,int h)
{
	/*
	int nWatchHeight=(((float)h)*WATCH_HEIGHT_MULTIPLIER);
	int nFilesWidth=(((float)h)*FILES_WIDTH_MULTIPLIER);
	m_wScriptWindow.SetWindowPos(nFilesWidth,TOOLBAR_HEIGHT,w-nFilesWidth,h-TOOLBAR_HEIGHT-nWatchHeight,SWP_DRAWFRAME);
	m_wLocals.SetWindowPos(0,h-nWatchHeight,w/2,nWatchHeight,SWP_DRAWFRAME);
	m_wFilesTree.SetWindowPos(nFilesWidth,TOOLBAR_HEIGHT,nFilesWidth,h-TOOLBAR_HEIGHT-nWatchHeight,SWP_DRAWFRAME);
	m_wWatch.SetWindowPos(w/2,h-nWatchHeight,w/2,nWatchHeight,SWP_DRAWFRAME);
	*/

	m_wndClient.Reshape(w, h - TOOLBAR_HEIGHT - STATUS_BAR_HEIGHT);
	m_wndClient.SetWindowPos(0, TOOLBAR_HEIGHT, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
	m_wndMainHorzSplitter.Reshape(w, h - TOOLBAR_HEIGHT - STATUS_BAR_HEIGHT);
	m_wToolbar.SetWindowPos(0,0,w,TOOLBAR_HEIGHT,0);
	m_wndStatus.SetWindowPos(0, h -  STATUS_BAR_HEIGHT, w, STATUS_BAR_HEIGHT, NULL);

	return true;
}


int WINAPI WinMain(HINSTANCE hInstance,
				   HINSTANCE hPrevInstance,
				   LPTSTR    lpCmdLine,
				   int       nCmdShow)
{
	CLUADbg wMain;
	HACCEL hAccelerators = NULL;

	_Tiny_InitApp(hInstance,hPrevInstance,lpCmdLine,IDI_SMALL);
	_TinyVerify(wMain.Create(NULL, _T("Lua Debugger"), WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, NULL, 
		NULL,(ULONG) LoadMenu(_Tiny_GetInstance(), MAKEINTRESOURCE(IDC_LUADBG))));

	if ((hAccelerators = LoadAccelerators(_Tiny_GetInstance(), MAKEINTRESOURCE(IDC_LUADBG))) == NULL)
	{
		_TINY_CHECK_LAST_ERROR
		return -1;
	}

	return _Tiny_MainLoop(hAccelerators, wMain.m_hWnd);
}