// my handy debugging stuff
//
// 10 March 97 : Modified to optionally use OutputDebugString


#include "standard.h"
#include "global.h"
#include "template.h"
#include "debug.h"
#include "utils.h"
#ifdef DBLOG

#define USE_ODS						// send log messages to OutputDebugString, not DBLog
#define HARD_LOG						// ensure log is always committed to disk file
//#define VERBOSE_WINDOWS_MESSAGES		// list windows messages in nauseating detail (crashes after CreatePalette if !USE_ODS ???)
#ifdef GAMEDEBUG
//#define LOCKS_ARE_OK
#endif

#define DB_MaxLineLength 256
#define DB_StoreSize 4096
#define DB_LOG_EXEC_TIMEOUT 5000

/*** globals ***/

/*** locals ***/
local HWND LhLogWnd;
local char LsLogWindowName[]="DBLog";
local char LsLogAppName[]="dblog";
local char LacLogStore[DB_StoreSize];
local char* LpStoreNext;
local bool LatLogTypeEnabled[]=
	{
	true,	// LT_Default
	true,	// LT_Enter
	false,	// LT_Exit
	true,	// LT_Release
	true,	// LT_Info
//#ifdef VERBOSE_WINDOWS_MESSAGES
	true,	// LT_WindowMessage
//#else
//	false,	// LT_WindowMessage
//#endif
	true,	// LT_DXTry
	true,	// LT_Error
	true,	// LT_Warning
	true,	// LT_Version
	true,	// LT_Texture
	false,	// LT_Sound
	};

/*** code ***/
void DB_FlushLogStore()
	{
#ifdef LOCKS_ARE_OK
	GnDirectDrawLocks=0;
#endif
	if (GnDirectDrawLocks || !(LacLogStore<LpStoreNext))
		return;
#ifndef USE_ODS
	if (!LhLogWnd || !IsWindow(LhLogWnd))
		return;
	COPYDATASTRUCT cds;
#endif
	char* pItem=LacLogStore;
	do
		{
#ifdef USE_ODS
		if (((DWORD*)pItem)[0]==LOG_OUTPUT)
			OutputDebugString(pItem+2*sizeof(DWORD));
		pItem+=(2*sizeof(DWORD)+((DWORD*)pItem)[1]);
#else
		cds.dwData=((DWORD*)pItem)[0];
		cds.cbData=((DWORD*)pItem)[1];
		pItem+=2*sizeof(DWORD);
		cds.lpData=pItem;
		pItem+=cds.cbData;
		SendMessage(LhLogWnd,WM_COPYDATA,(WPARAM)0,(LPARAM)&cds);
#endif
		}
	while (pItem<LpStoreNext);
	LpStoreNext=LacLogStore;
	}

void DB_SendLogMessage(DWORD dwType,PVOID pData,DWORD dwLen)
	{
#ifndef USE_ODS
	if (!LhLogWnd)
		return;
#endif
	if (dwLen==LOG_DO_STRLEN)
		dwLen=strlen((char*)pData)+1;
	if (GnDirectDrawLocks)
		{
		if ((LpStoreNext+2*sizeof(DWORD)+dwLen)>EndOfArray(LacLogStore))
			return;		// oops... must throw stuff away
		((DWORD*)LpStoreNext)[0]=dwType;
		((DWORD*)LpStoreNext)[1]=dwLen;
		LpStoreNext+=2*sizeof(DWORD);
		memcpy(LpStoreNext,pData,dwLen);
		LpStoreNext+=dwLen;
		return;
		}
#ifdef USE_ODS
	DB_FlushLogStore();
	if (dwType==LOG_OUTPUT)
		OutputDebugString((char*)pData);
#else
	if (!IsWindow(LhLogWnd))
		{
		LhLogWnd=NULL;
		return;
		}
	DB_FlushLogStore();
	COPYDATASTRUCT cds;
	cds.dwData=dwType;
	cds.cbData=dwLen;
	cds.lpData=pData;
	SendMessage(LhLogWnd,WM_COPYDATA,0,(LPARAM)&cds);
#endif
	}

extern "C" void __cdecl DB_Log(char* format,...)
	{
#ifndef USE_ODS
	if (!LhLogWnd)
		return;
#endif
	char buffer[DB_MaxLineLength];
	va_list args;
	va_start(args,format);
	if (int(format)<ArraySize(LatLogTypeEnabled))
		{
		if (!LatLogTypeEnabled[int(format)])
			return;
		format=va_arg(args,char*);
		}
	int nLen=_vsnprintf(buffer,sizeof buffer,format,args)+1;
	if (nLen<0)
		{
		nLen=(sizeof buffer)-1;
		buffer[nLen]=0;
		}
	va_end(args);
#ifdef USE_ODS
	buffer[nLen-1]='\n';
	buffer[nLen++]=0;
#endif
	DB_SendLogMessage(LOG_OUTPUT,buffer,nLen);
#ifdef HARD_LOG
	FILE* f=fopen("hardlog.txt","a+tc");
#ifdef USE_ODS
	fwrite(buffer,nLen-1,1,f);
#else
	buffer[nLen-1]='\n';
	fwrite(buffer,nLen,1,f);
#endif
	fflush(f);
	fclose(f);
#endif
	}

void DB_InitLog(char* sLogName)
	{
	GnDirectDrawLocks=0;	// should this be here?
	LpStoreNext=LacLogStore;
#ifdef USE_ODS
	DB_Log("%s: Log started",sLogName);
#else
	LhLogWnd=FindWindow(NULL,LsLogWindowName);
	if (!LhLogWnd)
		{
		if (!UT_ExecAndWait(LsLogAppName,DB_LOG_EXEC_TIMEOUT))
			return;
		LhLogWnd=FindWindow(NULL,LsLogWindowName);
		if (!LhLogWnd)
			return;		// give up!
		}
	DB_SendLogMessage(LOG_RESET,sLogName,LOG_DO_STRLEN);
#endif
	}

void DB_EndLog()
	{
#ifdef USE_ODS
	DB_Log("Log Closed");
#else
	DB_SendLogMessage(LOG_END,0,0);
#endif
	}

local inline char* BoolStr(bool bValue)
	{
	return bValue?"true":"false";
	}

#define simple_case(msg) case msg:Log(LT_WindowMessage,#msg);break
#define case_value(val) case val:pStr=#val;break

#ifdef VERBOSE_WINDOWS_MESSAGES
void DB_LogWindowsMessage(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
	{
	char* pStr="Invalid";
	POINTS pts;
	int nWPLo=LOWORD(wParam);
	int nWPHi=HIWORD(wParam);
	int nLPLo=LOWORD(lParam);
	int nLPHi=HIWORD(lParam);

	switch (msg)
		{
		case WM_ACTIVATE:
			switch (nWPLo)
				{
				case_value(WA_ACTIVE);
				case_value(WA_CLICKACTIVE);
				case_value(WA_INACTIVE);
				}
			Log(LT_WindowMessage,"WM_ACTIVATE; fActive=%s,fMinimized=%s,hwndPrevious=%x",pStr,BoolStr(bool(nWPHi)),(DWORD)(lParam));
			break;

		case WM_ACTIVATEAPP:
			Log(LT_WindowMessage,"WM_ACTIVATEAPP; fActive=%s",BoolStr(bool(wParam)));
			break;

		simple_case(WM_CLOSE);
		simple_case(WM_CREATE);

		case WM_DISPLAYCHANGE:
			Log(LT_WindowMessage,"WM_DISPLAYCHANGE; cBitsPerPixel=%d,cxScreen=%d,cyScreen=%d",int(wParam),nLPLo,nLPHi);
			break;

		simple_case(WM_GETDLGCODE);
		simple_case(WM_GETMINMAXINFO);
		simple_case(WM_GETTEXT);

		case WM_KILLFOCUS:
			Log(LT_WindowMessage,"WM_KILLFOCUS; hwndGetFocus=%x",(DWORD)(wParam));
			break;

		case WM_MOUSEMOVE:
			Log(LT_WindowMessage,"WM_MOUSEMOVE; fwKeys=%x,xPos=%d,yPos=%d",(DWORD)(wParam),nLPLo,nLPHi);
			break;

		case WM_NCACTIVATE:
			Log(LT_WindowMessage,"WM_NCACTIVATE; fActive=%s",BoolStr(bool(wParam)));
			break;

		simple_case(WM_NCCREATE);

		case WM_NCCALCSIZE:
			Log(LT_WindowMessage,"WM_NCCALCSIZE; fCalcValidRects=%s",BoolStr(bool(wParam)));
			break;

		simple_case(WM_NCDESTROY);

		case WM_NCHITTEST:
			Log(LT_WindowMessage,"WM_NCHITTEST; xPos=%d; yPos=%d",nLPLo,nLPHi);
			break;

		case WM_NCMOUSEMOVE:
			pts=MAKEPOINTS(lParam);
			Log(LT_WindowMessage,"WM_NCMOUSEMOVE; nHitTest=%d,xPos=%d,yPos=%d",int(wParam),pts.x,pts.y);
			break;

		case WM_NOTIFY:
			{
			NMHDR* pNMHdr=(NMHDR*)lParam;
			Log(LT_WindowMessage,"WM_NOTIFY; idCtrl=%d; hwndFrom=%x; idFrom=%x; code=%x",int(wParam),(DWORD)(pNMHdr->hwndFrom),int(pNMHdr->idFrom),int(pNMHdr->code));
			}
			break;

		case WM_PALETTECHANGED:
			Log(LT_WindowMessage,"WM_PALETTECHANGED; hWnd=%x",(DWORD)(wParam));
			break;			

		case WM_SETFOCUS:
			Log(LT_WindowMessage,"WM_SETFOCUS; hwndLoseFocus=%x",(DWORD)(wParam));
			break;

		case WM_SHOWWINDOW:
			switch (int(lParam))
				{
				case 0:
					pStr="0 (ShowWindow)";
					break;
				case_value(SW_OTHERUNZOOM);
				case_value(SW_OTHERZOOM);
				case_value(SW_PARENTCLOSING);
				case_value(SW_PARENTOPENING);
				}
			Log(LT_WindowMessage,"WM_SHOWWINDOW; fShow=%s,fnStatus=%s",BoolStr(bool(wParam)),pStr);
			break;

		case WM_TIMER:
			Log(LT_WindowMessage,"WM_TIMER; wTimerID=%x",(DWORD)(wParam));
			break;

		simple_case(WM_WINDOWPOSCHANGING);
		simple_case(WM_WINDOWPOSCHANGED);
			
		default:
			Log(LT_WindowMessage,"hWnd=%x: msg=%x, wParam=%x, lParam=%x",(DWORD)(hWnd),
																			(DWORD)(msg),
																			(DWORD)(wParam),
																			(DWORD)(lParam));
			break;
		}
	}
#else
void DB_LogWindowsMessage(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
	{
	hWnd; msg; wParam; lParam;
	}
#endif

#endif

TempString ERR_Describe_RC(char *szResource)
	{
	if (((DWORD)szResource)&0xffff0000)
		return TempString(szResource);
	TempString str;
	sprintf(str,"0x%02x",((DWORD)szResource)&0xffff);
	return str;
	}
