/////////////////////////////////////////////////////////////////////
// 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.
/////////////////////////////////////////////////////////////////////
/* VSS $Header: /Viper/VPCmdIF/VPCmdIF/VPtracei.h 11    6/01/20 3:54p Suzanne $
*/
#pragma once
#include <time.h>
#include <thread>
#include "PTTypeDefs.h"
#include "VPcmdif.h"
#include "VPcmdDefsi.h"
#include "VPtrace.h"
#include <string.h>

#define trTracefHP3 trTracefHP
/////////////////////////////////////////////////////////////////////
#ifndef CODETRACE
	#ifndef NDEBUG
		#define CODETRACE trTracefHP("%s : %s : %d\r\n", __FILE__, __FUNCTION__, __LINE__)
		#define CODETRACEEX trTracefHP("\t >>>>leaving %s : %s : %d\r\n", __FILE__, __FUNCTION__, __LINE__ )
		#define CODETRACE7 trTracefHP7("%s : %s : %d\r\n", __FILE__, __FUNCTION__, __LINE__)
		#define CODETRACEEX7 trTracefHP7("\t >>>>leaving %s : %s : %d\r\n", __FILE__, __FUNCTION__, __LINE__ )
	#else
		#define CODETRACE   // trTracefHP("%s : %s : %d\r\n", __FILE__, __FUNCTION__, __LINE__)
		#define CODETRACEEX  //trTracefHP("\t >>>>leaving %s : %s : %d\r\n", __FILE__, __FUNCTION__, __LINE__ )
		#define CODETRACE7   //trTracefHP7("%s : %s : %d\r\n", __FILE__, __FUNCTION__, __LINE__)
		#define CODETRACEEX7 //trTracefHP7("\t >>>>leaving %s : %s : %d\r\n", __FILE__, __FUNCTION__, __LINE__ )
	#endif
#endif

#define _TR_CRLF "\r\n";
#define _TR_SP   " ";

#define _INVALID_CONDITION(lv, msg, ctx) {lv = E_CTXERR_INVALID_CONDITION; trTraceErr(ctx, E_CTXERR_INVALID_CONDITION, msg, __FUNCTION__, __LINE__);}

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

extern eVPcmdTraceLevel g_eVPTraceLev;
extern void trTraceEnable(bool bTrace, int32_t iLev=2);
extern void trLogEnable(bool bLog, TCHAR * fp);
extern void trTraceRxII(void* pCtx, uint8_t * pBuf, int32_t iCount, const char * szFunc, int32_t iLine, bool bMicroTrace = false, int32_t iLev = 1);
extern void trTraceTxII(void* pCtx, uint8_t * pBuf, int32_t iCount, const char * szFunc, int32_t iLine, bool bMicroTrace = false, int32_t iLev = 1);
extern void trTraceRxII0(void* pCtx, uint8_t * pBuf, int32_t iCount, const char * szFunc, int32_t iLine, bool bMicroTrace = false);
extern void trTraceTxII0(void* pCtx, uint8_t * pBuf, int32_t iCount, const char * szFunc, int32_t iLine, bool bMicroTrace = false);
POLHEMUS_API void trTraceSysErr(void* pCtx, int32_t err, const char *msg, const char *szFunc, int32_t iLine);
extern void trTraceSysErr3 (void* pCtx, int32_t err, const char *msg, const char *szFunc, int32_t iLine);
extern void trTraceSysErrHub(int32_t hid, const char * ascid, int32_t err, const char * msg, const char *szFunc, int32_t iLine);
extern void trTraceSysErrHub3(int32_t hid, const char * ascid, int32_t err, const char * msg, const char *szFunc, int32_t iLine); // DOUT3
extern void trTraceErr(void* pCtx, int32_t err, const char *msg, const char *szFunc, int32_t iLine, int32_t minlev=0);

// trace frame buf
extern void trTraceFBuf   (void * pBuf,    int32_t iCount, bool bCR = true, const char *szPre = 0, int32_t minlev=2);
extern void trTraceFBufcmd(void* pBuf, int32_t iCount, bool bCR = true, const char* szPre = 0, int32_t minlev = 2);
extern void trTraceFBufpno(void* pBuf, int32_t iCount, bool bCR = true, const char* szPre = 0, int32_t minlev = 2);
extern void trTraceHexBuf5(uint8_t * pBuf, int32_t iCount, bool bCR = true, const char *szPre = 0);

extern void trTraceHexBufFLC(uint8_t * pBuf, int32_t iCount, bool bCR = true, const char *szFunc=0, int32_t iLine=0);
extern void trTraceHexBuf5FLC(uint8_t * pBuf, int32_t iCount, bool bCR = true, const char *szFunc=0, int32_t iLine=0);


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

#include <string>

//extern uint32_t trTraceThID();  //for vc140 build
extern std::thread::id trTraceThID(); //for vc142 build

///@todo make portable _TOSTRING, sprintf_s
#ifndef _TOSTRING
#define _TOSTRING(buf, fmt, val)	\
	sprintf_s(buf, sizeof (buf), fmt, val)
#endif

inline std::string to_bstring(bool b)
{
	char szbool[8];
	sprintf_s(szbool, 8, "%s", (b) ? "true" : "false");
	return std::string(szbool);
}
inline std::string trTraceDT()
{
	time_t t = time(0);
	struct tm lt;
	char sztime[100];
	localtime_s(&lt, &t);
	asctime_s(sztime, 100, &lt);
	//strncpy_s(sztime, 100, std::string(asctime(localtime(&t))).c_str(), 100);
	sztime[strlen(sztime) - 1] = 0; // remove trailing \n

	return std::string(sztime);
}
inline std::string trDTbrief()
{
	time_t t = time(0);
	struct tm lt;
	localtime_s(&lt, &t);
	char sztime[100];
	sprintf_s(sztime, 100, "%02d/%02d/%02d %02d:%02d:%02d", lt.tm_year-100, lt.tm_mon, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec);

	return std::string(sztime);
}
inline std::string to_hxstring(uint8_t _Val)
{
	char _Buf[2 * _MAX_INT_DIG];

	_CSTD _TOSTRING(_Buf, "%02x", _Val);
	return (std::string(_Buf));
}
inline std::string to_hxstring(int8_t _Val)
{
	char _Buf[2 * _MAX_INT_DIG];

	_CSTD _TOSTRING(_Buf, "%02x", _Val);
	return (std::string(_Buf));
}
inline std::string to_hxstring(int32_t _Val)
{
	char _Buf[2 * _MAX_INT_DIG];

	_CSTD _TOSTRING(_Buf, "%x", _Val);
	return (std::string(_Buf));
}
inline std::string to_hxstring(uint32_t _Val)
{
	char _Buf[2 * _MAX_INT_DIG];

	_CSTD _TOSTRING(_Buf, "%x", _Val);
	return (std::string(_Buf));
}
inline std::string to_hxstring(int64_t _Val)
{
	char _Buf[2 * _MAX_INT_DIG];

	_CSTD _TOSTRING(_Buf, "%llx", _Val);
	return (std::string(_Buf));
}
inline std::string to_hxstring(uint64_t _Val)
{
	char _Buf[2 * _MAX_INT_DIG];

	_CSTD _TOSTRING(_Buf, "%llx", _Val);
	return (std::string(_Buf));
}


inline std::string to_macstring(uint64_t _val) ///< dups trMacStr
{
	char _Buf[50];
	sprintf_s(_Buf, 50, "%02x:%02x:%02x:%02x:%02x:%02x", (unsigned char)(_val & 0xff),
		(unsigned char)((_val & 0xff00) >> 8),
		(unsigned char)((_val & 0xff0000) >> 16),
		(unsigned char)((_val & 0xff000000) >> 24),
		(unsigned char)((_val & 0xff00000000) >> 32),
		(unsigned char)((_val & 0xff0000000000) >> 40));
	return(std::string(_Buf));
}
// taken from winsock2.h
#define VP_WS2_32_WINSOCK_SWAP_LONGLONG(l)            \
            ( ( ((l) >> 56) & 0x00000000000000FFLL ) |       \
              ( ((l) >> 40) & 0x000000000000FF00LL ) |       \
              ( ((l) >> 24) & 0x0000000000FF0000LL ) |       \
              ( ((l) >>  8) & 0x00000000FF000000LL ) |       \
              ( ((l) <<  8) & 0x000000FF00000000LL ) |       \
              ( ((l) << 24) & 0x0000FF0000000000LL ) |       \
              ( ((l) << 40) & 0x00FF000000000000LL ) |       \
              ( ((l) << 56) & 0xFF00000000000000LL ) )

inline uint64_t vpNetwToHostLL(uint64_t val)
{
	uint64_t r = VP_WS2_32_WINSOCK_SWAP_LONGLONG(val);
	return r;
}
inline uint64_t string_to_mac(std::string & s) {
	uint8_t a[6];
	int last = -1;
	uint64_t ui64mac = 0;
	int rc = 0;
	rc = sscanf_s(s.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx%n",
		&a[0], &a[1], &a[2], &a[3], &a[4], &a[5],
		&last);
	//if (rc != 6 ) //|| s.size() != last)
		//throw std::runtime_error("invalid mac address format " + s);

	ui64mac = 	uint64_t(a[0]) << 40 |
		uint64_t(a[1]) << 32 |
		uint64_t(a[2]) << 24 |
		uint64_t(a[3]) << 16 |
		uint64_t(a[4]) << 8 |
		uint64_t(a[5]);
#ifndef VP_CMDLIB_BIG_ENDIAN
	// not big means LE
	return vpNetwToHostLL(ui64mac) >> 16;
#else
	return ui64mac;
#endif
}

inline std::string to_saddrstring(const sockaddr_in *pSA) ///< dups trSAStr
{
	char _Buf[100];
	sprintf_s(_Buf, 100, "%d.%d.%d.%d:%d",
		pSA->sin_addr.S_un.S_un_b.s_b1,
		pSA->sin_addr.S_un.S_un_b.s_b2,
		pSA->sin_addr.S_un.S_un_b.s_b3,
		pSA->sin_addr.S_un.S_un_b.s_b4,
		ntohs(pSA->sin_port));
	return(std::string(_Buf));
}

extern const char * trPlatform_WSAstdErrStr(int32_t iWSAerr);


extern std::string to_errstring(int32_t iErr);
/////////////////////////////////////////////////////////////////////

