/////////////////////////////////////////////////////////////////////
// This open-source software sample is offered free of charge and without guarantee.
// Polhemus accepts no responsibility or liability for any use of this code.
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// Polhemus Inc., www.polhemus.com
// © 2002 Polhemus Inc., All Rights Reserved
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
//
//  Filename:           $Workfile: PDebug.h $
//
//  Project Name:       Polhemus Tracker Command Interface API 
//
//  Original Author:    S. Gagnon
//
//  Description:        DOUT defs - replacement for OutputDebugString calls
//
//  VSS $Header: /Viper/VPCmdIF/VPCmdIF/PDebug.h 5     11/26/19 5:16p Suzanne $  
//
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
///@cond
#ifndef _PDEBUG_H_
#define _PDEBUG_H_

/////////////////////////////////////////////////////////////////////
#ifndef VPCMD_STATIC
#if defined (PDEBUG_EXPORT)
#define PDEBUG_API __declspec(dllexport)
#else
#define PDEBUG_API __declspec(dllimport)
#endif
#else
#define PDEBUG_API
#endif
/////////////////////////////////////////////////////////////////////
#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
#include <windows.h>
/*#if defined(interface)
#undef interface
#endif
*/
#if !defined(__CYGWIN__)
#include <winsock.h>
#endif
#endif
/////////////////////////////////////////////////////////////////////

#include "PTTypeDefs.h"
#include "LogFile.h"
#include <stdint.h>
#include <stdarg.h>

/////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////
#define PI_DEBUG_BUFFER_SIZE 0x0800
#define DOUT  PiDebug::PIDOUT
#define DOUT0 PiDebug::PIDOUT0
#define DOUT1 PiDebug::PIDOUT1
#define DOUT3 PiDebug::PIDOUT3
#define DOUT5 PiDebug::PIDOUT5
#define DOUT7 PiDebug::PIDOUT7
#define DOUTL PiDebug::PIDebugOut
#define PI_DEBUGOUT( lev, str ) PiDebug::PIDebugOut( lev, str )
#define	DOUTHEXBUF	PiDebug::PIDOUTHEXBUF
#define	DOUTHEXBUF1	PiDebug::PIDOUTHEXBUF1
#define	DOUTASCBUF	PiDebug::PIDOUTASCBUF
#define DOUTLEV     PiDebug::PIDlev()
#define DOUT_LEV(a) (DOUTLEV >= a)
#define DOUT_LEV_LT(a)  (DOUTLEV < a)

#define DOUT_ERR PiDebug::PIDOUT_ERR0
#define DOUT_ERR1 PiDebug::PIDOUT_ERR1
#define DOUT_ERR3 PiDebug::PIDOUT_ERR3
#define DOUT_ERR5 PiDebug::PIDOUT_ERR5
#define DOUT_ERR7 PiDebug::PIDOUT_ERR7

#define PID_COMPACT PiDebug::Compact()

#define PID_COMPACT_LEVEL 2

//#define LOGOUT		PiDebug::LogOut//PiDebug::m_LogFile.Write
//#define LOGOUT_NFL	PiDebug::PIDOUT_ERR0//PiDebug::m_LogFile.WriteNoFlush
//#define LOGHEXBUF	PiDebug::PILOGHEXBUF

#ifndef CODETRACE
	#ifndef NDEBUG
		#define CODETRACE 	DOUT3("%s : %s : %d\r\n", __FILE__, __FUNCTION__, __LINE__)
		#define CODETRACEEX DOUT3( "\t >>>>leaving %s : %s : %d\r\n", __FILE__, __FUNCTION__, __LINE__ )
	#else
		#define CODETRACE 	DOUT3("%s : %s : %d\r\n", __FILE__, __FUNCTION__, __LINE__)
		#define CODETRACEEX DOUT3( "\t >>>>leaving %s : %s : %d\r\n", __FILE__, __FUNCTION__, __LINE__ )
	#endif
#endif

// Trace Levels used in Code
// DOUT         = trace that cannot be filtered out by trace level 
// DOUT0        = minimal trace + error  : user has set trace level to 1
// DOUT1        = minimal trace + error + normal I/O : user has set trace level to 2
// DOUT3        = minimal trace + error + normal I/O + code trace : user has set level to 5
// DOUT5        = minimal trace + error + normal I/O + code trace + other : user has set level to 7 (verbose)
// DOUT7        = verbose plus.  User has set level to 8 or higher.  Undocumented.


/////////////////////////////////////////////////////////////////////
// CLASS PiDebug
/////////////////////////////////////////////////////////////////////
class PDEBUG_API PiDebug
{
public:

	static void PIDSetLevel(int32_t level)
	{
		m_usDebugLevel = level;
		m_bDebugCompact = (level == PID_COMPACT_LEVEL);
	}

	static void PIDSetCompact(bool b)
	{
		m_bDebugCompact = b;
	}
	//static void PIDLogASCII	( bool b ) { g_bLogAscii = b; }
	//static void PIDFlushIO	( bool b ) { g_bFlushIO = b; }
	//static bool PIDFlushIO	() { return g_bFlushIO; }

	static uint16_t PIDlev() { return m_usDebugLevel; }

	static void PIDOUT		( LPCSTR szFormat, ... );
	static void PIDOUTL		( LPCSTR szFormat, va_list );
	
	static void PIDebugOut	( int32_t level, LPCSTR szFormat, ... );
	static void PIDebugOutL	( int32_t level, LPCSTR szFormat, va_list );
	static void PIDOUT0		( LPCSTR szFormat, ... );
	static void PIDOUT1		( LPCSTR szFormat, ... );
	static void PIDOUT3		( LPCSTR szFormat, ... );
	static void PIDOUT5		( LPCSTR szFormat, ... );
	static void PIDOUT7		( LPCSTR szFormat, ... );

	static void PIDOUT_ERR	( int32_t nLev, LPCSTR szFormat, ... );
	static void PIDOUT_ERR0	( LPCSTR szFormat, ... );
	static void PIDOUT_ERR1	( LPCSTR szFormat, ... );
	static void PIDOUT_ERR3	( LPCSTR szFormat, ... );
	static void PIDOUT_ERR5	( LPCSTR szFormat, ... );
	static void PIDOUT_ERR7	( LPCSTR szFormat, ... );

	static bool Compact(){ return m_bDebugCompact; }

	/*static void PIDOUTHEXBUF1( LPCTSTR szTitle, PBYTE pBuf, DWORD dwCount );
	static void PIDOUTHEXBUF( LPCTSTR szTitle, PBYTE pBuf, DWORD dwCount );
	static void PIDOUTASCBUF( LPCTSTR szTitle, PBYTE pBuf, DWORD dwCount );
	static void PILOGHEXBUF( LPCTSTR szTitle, PBYTE pBuf, DWORD dwCount );


	static void PILOGERR( LPCSTR szFormat, ... );*/

	static void FlushLog()//{};
								{ m_LogFile.Flush(); }

	static void StartLog(int nFlushCount = 0, bool bAppend = false, bool bTS = true)
	{
		m_LogFile.Close();
		m_LogFile.Open(nFlushCount, bAppend, bTS);
		m_bLog = true;
	}

	static void StopLog			(  )
	{
		m_LogFile.Close();
		m_bLog = false;
	}
	static LPCTSTR LogFile		(  )
	{
		return m_LogFile.Filename();
		//return _T("");
	}
	static void SetLogFile( TCHAR *fp )
	{
		m_LogFile.SetFilename(fp);
	}

	static LPCSTR	SZDebug(){ return m_szDebug; }
	static LPSTR WSToMB( LPCWSTR szStr );
	static LPWSTR MBToWS( LPCSTR szStr );


protected:
	static bool     m_bLog;
	static CLogFile m_LogFile;
	static char  	m_szDebug[PI_DEBUG_BUFFER_SIZE];
	static uint16_t	m_usDebugLevel;
	static bool     m_bDebugCompact;
	//static bool		g_bLogAscii;
	//static bool		g_bFlushIO;

};

class PDEBUG_API CPiDebugOut
{
public:
	CPiDebugOut(int32_t iLev = 5)
	{
		PiDebug::PIDSetLevel(iLev);
	}
	void CreateWin(bool bMove=false)
	{
#ifdef _WINDOWS_
		HWND hFore = ::GetForegroundWindow();
		AllocConsole();
		FILE *fp=0;
		freopen_s(&fp, "CONOUT$", "w", stdout);
		HWND hcon = ::GetConsoleWindow();
		if (hcon != NULL)
		{
			HMENU hMenu = ::GetSystemMenu(hcon, FALSE);
			if (hMenu != NULL)
				DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);

			HWND hChild = ::GetWindow(hcon, GW_CHILD);
			HWND hFirst = ::GetWindow(hcon, GW_HWNDFIRST);
			HWND hLast = ::GetWindow(hcon, GW_HWNDLAST);
			HWND hNext = ::GetWindow(hcon, GW_HWNDNEXT);
			HWND hPrev = ::GetWindow(hcon, GW_HWNDPREV);
			HWND HOwn = ::GetWindow(hcon, GW_OWNER);
			HWND hForeII = ::GetForegroundWindow();

			int i = 0;
			if (hFore != 0)
			{
				RECT rf;
				POINT pc;
				bool bCanMove = false;
				if (GetWindowRect(hFore, &rf))
				{
					pc.x = rf.left-30;     pc.y = rf.top-30;
					bCanMove = true;
				}
				//::SetForegroundWindow(hFore);

				if (bMove && bCanMove)
				{
					::SetWindowPos(hcon, hFore, pc.x, pc.y, 0, 0, SWP_NOSIZE);
				}
				else
				{
					::SetWindowPos(hcon, hFore, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
				}
			}
		}
#endif
	}
	~CPiDebugOut()
	{
#ifdef _WINDOWS_
		//FreeConsole();
#endif
	}
};

/////////////////////////////////////////////////////////////////////
// END $Workfile: PDebug.h $
/////////////////////////////////////////////////////////////////////
#endif // _PDEBUG_H_
///@endcond