/********************************************************************************
*	ファイル名：Tools.cpp														*
*	用　　　途：汎用ツール														*
*	備　　　考：																*
*	履　　　歴：																*
********************************************************************************/
/****************************
*	 コンパイル環境設定		*
****************************/
/****************************
*	 プリコンパイル設定		*
****************************/
#include "stdafx.h"
/****************************
*	インクルードファイル	*
****************************/
#include "Tools.h"
/****************************
*		 マクロ定数			*
****************************/
/***** Check()戻り値 *****/
#define	RNGCHK_ERR				-999					/* 主に引数異常							*/
#define	RNGCHK_LT				-1						/* 最小値未満							*/
#define RNGCHK_EQ				0						/* 適正範囲								*/
#define	RNGCHK_GT				1						/* 最大値超								*/

/****************************
*		 構造体定義			*
****************************/
typedef union											/* データ型共用体						*/
{
	BYTE			nByte;
	BOOL			nBool;
	INT32			nInt32;
	UINT32			uUInt32;
	INT64			nInt64;
	UINT64			uUInt64;
	float			fFloat;
	double			dDouble;
	TCHAR			*szPtr;
} BASED_DATA;
/****************************
*		 クラス定義			*
****************************/
/****************************
*		 関数　宣言			*
****************************/
static int RangeCheck(CString &str, INT32 nAttr, PVOID vpMin, PVOID vpMax);
template<class T>static INT32 InRange(T v, T *pMin, T *pMax);
/****************************
*		 変数　宣言			*
****************************/
/********************************************************************************
*	関数名：StringToData														*
*	用　途：文字列からデータを設定												*
*	引き数：データアドレス、文字列、データ型									*
*	戻り値：成功でＴＲＵＥ、失敗でＦＡＬＳＥ									*
*	備　考：																	*
********************************************************************************/
BOOL StringToData(PVOID vpDst, CString &strSrc, INT32 nAttr)
{
	TCHAR *p;

	switch(nAttr)
	{
	case DATA_ATTR_BYTE:
		*(PBYTE)vpDst			= _tstoi(strSrc);
		break;
	case DATA_ATTR_BOOL:
		*(PBOOL)vpDst			= _tstoi(strSrc);
		break;
	case DATA_ATTR_INT32:
		*(PINT32)vpDst			= _tstoi(strSrc);
		break;
	case DATA_ATTR_UINT32:
		*(PUINT32)vpDst			= (UINT32)_tcstoul(strSrc, &p, 10);
		break;
	case DATA_ATTR_INT64:
		*(PINT64)vpDst			= _tcstoi64(strSrc, &p, 10);
		break;
	case DATA_ATTR_UINT64:
		*(PUINT64)vpDst			= _tcstoui64(strSrc, &p, 10);
		break;
	case DATA_ATTR_FLOAT:
		*(float *)vpDst			= (float)_tstof(strSrc);
		break;
	case DATA_ATTR_DOUBLE:
		*(double *)vpDst		= _tstof(strSrc);
		break;
	case DATA_ATTR_STRING:
		_tcscpy((TCHAR *)vpDst, strSrc);
		break;
	case DATA_ATTR_CSTRING:
		*(CString *)vpDst		= strSrc;
		break;
	default:
		return FALSE;
	}

	return TRUE;
}

/********************************************************************************
*	関数名：DataToString														*
*	用　途：文字列へデータを設定												*
*	引き数：文字列、データアドレス、データ型									*
*	戻り値：成功でＴＲＵＥ、失敗でＦＡＬＳＥ									*
*	備　考：																	*
********************************************************************************/
BOOL DataToString(CString *strDst, PVOID vpSrc, INT32 nAttr)
{
	switch(nAttr)
	{
	case DATA_ATTR_BYTE:
		strDst->Format(_T("%c"), *(PBYTE)vpSrc);
		break;
	case DATA_ATTR_BOOL:
		strDst->Format(_T("%d"), *(PBOOL)vpSrc);
		break;
	case DATA_ATTR_INT32:
		strDst->Format(_T("%d"), *(PINT32)vpSrc);
		break;
	case DATA_ATTR_UINT32:
		strDst->Format(_T("%u"), *(PUINT32)vpSrc);
		break;
	case DATA_ATTR_INT64:
		strDst->Format(_T("%lld"), *(PINT64)vpSrc);
		break;
	case DATA_ATTR_UINT64:
		strDst->Format(_T("%llu"), *(PUINT64)vpSrc);
		break;
	case DATA_ATTR_FLOAT:
		strDst->Format(_T("%f"), *(float *)vpSrc);
		break;
	case DATA_ATTR_DOUBLE:
		strDst->Format(_T("%lf"), *(double *)vpSrc);
		break;
	case DATA_ATTR_STRING:
		*strDst	= (TCHAR *)vpSrc;
		break;
	case DATA_ATTR_CSTRING:
		*strDst = *(CString *)vpSrc;
		break;
	default:
		return FALSE;
	}

	return TRUE;
}

/********************************************************************************
*	関数名：DataToString														*
*	用　途：文字列へデータを設定												*
*	引き数：文字列、書式指定、データアドレス、データ型							*
*	戻り値：成功でＴＲＵＥ、失敗でＦＡＬＳＥ									*
*	備　考：書式指定を省略した場合、デフォルト書式で動作						*
********************************************************************************/
BOOL DataToString(CString *strDst, PTCHAR szFormat, PVOID vpSrc, INT32 nAttr)
{
	if (szFormat == 0)
	{
		return DataToString(strDst, vpSrc, nAttr);
	}

	switch(nAttr)
	{
	case DATA_ATTR_BYTE:
		strDst->Format(szFormat, *(PBYTE)vpSrc);
		break;
	case DATA_ATTR_BOOL:
		strDst->Format(szFormat, *(PBOOL)vpSrc);
		break;
	case DATA_ATTR_INT32:
		strDst->Format(szFormat, *(PINT32)vpSrc);
		break;
	case DATA_ATTR_UINT32:
		strDst->Format(szFormat, *(PUINT32)vpSrc);
		break;
	case DATA_ATTR_INT64:
		strDst->Format(szFormat, *(PINT64)vpSrc);
		break;
	case DATA_ATTR_UINT64:
		strDst->Format(szFormat, *(PUINT64)vpSrc);
		break;
	case DATA_ATTR_FLOAT:
		strDst->Format(szFormat, *(float *)vpSrc);
		break;
	case DATA_ATTR_DOUBLE:
		strDst->Format(szFormat, *(double *)vpSrc);
		break;
	case DATA_ATTR_STRING:
		*strDst	= (TCHAR *)vpSrc;
		break;
	case DATA_ATTR_CSTRING:
		*strDst = *(CString *)vpSrc;
		break;
	default:
		return FALSE;
	}

	return TRUE;
}

/********************************************************************************
*	関数名：DataToData															*
*	用　途：データ代入															*
*	引き数：代入先、代入元、データ型											*
*	戻り値：成功でＴＲＵＥ、失敗でＦＡＬＳＥ									*
*	備　考：																	*
********************************************************************************/
BOOL DataToData(PVOID vpDst, PVOID vpSrc, INT32 nAttr)
{
	if(vpDst == 0 || vpSrc == 0 || vpDst == vpSrc)
	{
		return FALSE;
	}

	switch(nAttr)
	{
	case DATA_ATTR_BYTE:
		*((PBYTE)vpDst) = *((PBYTE)vpSrc);
		break;
	case DATA_ATTR_BOOL:
		*((PBOOL)vpDst) = *((PBOOL)vpSrc);
		break;
	case DATA_ATTR_INT32:
		*((PINT32)vpDst) = *((PINT32)vpSrc);
		break;
	case DATA_ATTR_UINT32:
		*((PUINT32)vpDst) = *((PUINT32)vpSrc);
		break;
	case DATA_ATTR_INT64:
		*((PINT64)vpDst) = *((PINT64)vpSrc);
		break;
	case DATA_ATTR_UINT64:
		*((PUINT64)vpDst) = *((PUINT64)vpSrc);
		break;
	case DATA_ATTR_FLOAT:
		*((float*)vpDst) = *((float*)vpSrc);
		break;
	case DATA_ATTR_DOUBLE:
		*((double*)vpDst) = *((double*)vpSrc);
		break;
	case DATA_ATTR_STRING:
		_tcscpy((PTCHAR)vpDst, (PTCHAR)vpSrc);
		break;
	case DATA_ATTR_CSTRING:
		*((CString *)vpDst) = *((CString *)vpSrc);
		break;
	default:
		return FALSE;
	}

	return TRUE;
}


/********************************************************************************
*	関数名：IsInteger															*
*	用　途：整数を示す文字列かを検査する										*
*	引き数：評価文字列、負号許可フラグ											*
*	戻り値：整数であればＴＲＵＥ、そうでなければＦＡＬＳＥ						*
*	備　考：有効な文字列は下記に従う											*
*			wswns																*
*			w : いくらかのスペース												*
*			s : 符号[+|-] ※負号許可フラグがＴＲＵＥの場合のみ有効				*
*			n : いくらかの数字													*
********************************************************************************/
BOOL IsInteger(CString &str, BOOL bSigned)
{
	INT32	i;				/* ループカウンタ		*/
	INT32	nLen;			/* 評価する文字列の長さ	*/
	INT32	nNumStrLen;		/* 数字部分の文字列長	*/
	TCHAR	c;				/* テンポラリバッファ	*/

	nLen = str.GetLength();

	/***** いくらかのスペースを読み飛ばす *****/
	for (i = 0; i < nLen; i++)
	{
		if ( str[i] != _T(' ') ) break;
	}

	if ( i >= nLen )
	{
		return FALSE;	/* ダラ */
	}

	c = (TCHAR)str[i];

	/***** 符号の取得 *****/
	if ( c == _T('+') || c == _T('-') )
	{
		if ( c == _T('-') && !bSigned ) return FALSE;
		i++;
	}

	/***** いくらかのスペースを読み飛ばす *****/
	for (; i < nLen; i++)
	{
		if ( str[i] != _T(' ') ) break;
	}

	nNumStrLen	= 0;

	while(i < nLen)
	{
		c = (TCHAR)str[i];
		switch(c)
		{
		case _T('0'):	case _T('1'):	case _T('2'):
		case _T('3'):	case _T('4'):	case _T('5'):
		case _T('6'):	case _T('7'):	case _T('8'):
		case _T('9'):
			nNumStrLen++;
			i++;
			break;
		default:
			for (; i < nLen; i++)
			{
				if ( str[i] != _T(' ') ) return FALSE;
			}
			break;
		}
	}

	return (nNumStrLen > 0);
}

/********************************************************************************
*	関数名：IsFloat																*
*	用　途：実数を示す文字列かを検査する										*
*	引き数：評価文字列, 負号許可フラグ											*
*	戻り値：実数である場合はＴＲＵＥ、そうでない場合はＦＡＬＳＥ				*
*	備　考：有効な文字列は下記に従う											*
*			wsw[n|p]nw															*
*			w : いくらかのスペース												*
*			s : 符号[+|-] ※負号許可フラグがＴＲＵＥの場合のみ有効				*
*			n : いくらかの数字													*
*			p : 小数点															*
********************************************************************************/
BOOL IsFloat(CString &str, BOOL bSigned)
{
	INT32	i;				/* ループカウンタ		*/
	INT32	nLen;			/* 評価する文字列の長さ	*/
	INT32	nNumStrLen;		/* 数字部分の文字列長	*/
	BOOL	bPoint;			/* 小数点フラグ			*/
	TCHAR	c;				/* テンポラリバッファ	*/

	nLen = str.GetLength();

	/***** いくらかのスペースを読み飛ばす *****/
	for (i = 0; i < nLen; i++)
	{
		if ( str[i] != _T(' ') ) break;
	}

	if ( i >= nLen ) return FALSE;	/* ダラ */

	c = (TCHAR)str[i];

	/***** 符号の取得 *****/
	if ( c == _T('+') || c == _T('-') )
	{
		if ( c == _T('-') && !bSigned ) return FALSE;
		i++;
	}

	/***** いくらかのスペースを読み飛ばす *****/
	for (; i < nLen; i++)
	{
		if ( str[i] != _T(' ') ) break;
	}

	nNumStrLen	= 0;
	bPoint		= FALSE;

	while(i < nLen)
	{
		c = (TCHAR)str[i];
		switch(c)
		{
		case _T('.'):
			/***** 小数点は１つだけ *****/
			if ( bPoint ) return FALSE;
			bPoint = TRUE;
			i++;
			break;
		case _T('0'):	case _T('1'):	case _T('2'):
		case _T('3'):	case _T('4'):	case _T('5'):
		case _T('6'):	case _T('7'):	case _T('8'):
		case _T('9'):
			nNumStrLen++;
			i++;
			break;
		default:
			for (; i < nLen; i++)
			{
				if ( str[i] != _T(' ') ) return FALSE;
			}
			break;
		}
	}

	return (nNumStrLen > 0);
}

/********************************************************************************
*	関数名：Check																*
*	用　途：文字列が指定型に沿っているかチェックする							*
*	引き数：検査対象文字列、データ属性、最小値、最大値							*
*	戻り値：適正であればＴＲＵＥ、不正であればＦＡＬＳＥ						*
*	備　考：																	*
********************************************************************************/
int Check(CString &str, INT32 nAttr, PVOID vpMin, PVOID vpMax)
{
	switch(nAttr)
	{
	case DATA_ATTR_INT32:
	case DATA_ATTR_INT64:
		if ( !IsInteger(str, TRUE) ) return FALSE;
		
		break;
	case DATA_ATTR_BYTE:
	case DATA_ATTR_BOOL:
	case DATA_ATTR_UINT32:
	case DATA_ATTR_UINT64:
		if ( !IsInteger(str, FALSE) ) return FALSE;
		break;
	case DATA_ATTR_FLOAT:
	case DATA_ATTR_DOUBLE:
		if ( !IsFloat(str, TRUE) ) return FALSE;
		break;
	case DATA_ATTR_STRING:
	case DATA_ATTR_CSTRING:
		break;
	default:
		return FALSE;
	}

	return (RangeCheck(str, nAttr, vpMin, vpMax) == RNGCHK_EQ);
}

/********************************************************************************
*	関数名：RangeCheck															*
*	用　途：データが指定された範囲にあるかをチェックする						*
*	引き数：検査文字列、データ属性、最小値、最大値								*
*	戻り値：検査結果															*
*	備　考：文字列が指定型に沿っているかはチェックしない。						*
*			文字列型のデータの場合は最小値、最大値は文字列長(int)を指定すること	*
********************************************************************************/
static INT32 RangeCheck(CString &str, INT32 nAttr, PVOID vpMin, PVOID vpMax)
{
	BASED_DATA	b;

	switch(nAttr)
	{
	case DATA_ATTR_INT32:
		StringToData(&b.nInt32, str, nAttr);
		return InRange(b.nInt32, (PINT32)vpMin, (PINT32)vpMax);

	case DATA_ATTR_INT64:
		StringToData(&b.nInt64, str, nAttr);
		return InRange(b.nInt64, (PINT64)vpMin, (PINT64)vpMax);

	case DATA_ATTR_BYTE:
		StringToData(&b.nByte, str, nAttr);
		return InRange(b.nByte, (PBYTE)vpMin, (PBYTE)vpMax);

	case DATA_ATTR_BOOL:
		StringToData(&b.nBool, str, nAttr);
		return InRange(b.nBool, (PBOOL)vpMin, (PBOOL)vpMax);

	case DATA_ATTR_UINT32:
		StringToData(&b.uUInt32, str, nAttr);
		return InRange(b.uUInt32, (PUINT32)vpMin, (PUINT32)vpMax);

	case DATA_ATTR_UINT64:
		StringToData(&b.uUInt64, str, nAttr);
		return InRange(b.uUInt64, (PUINT64)vpMin, (PUINT64)vpMax);

	case DATA_ATTR_FLOAT:
		StringToData(&b.fFloat, str, nAttr);
		return InRange(b.fFloat, (float *)vpMin, (float *)vpMax);

	case DATA_ATTR_DOUBLE:
		StringToData(&b.dDouble, str, nAttr);
		return InRange(b.dDouble, (double *)vpMin, (double *)vpMax);

	case DATA_ATTR_STRING:
	case DATA_ATTR_CSTRING:
		b.nInt32 = str.GetLength();
		return InRange(b.nInt32, (PINT32)vpMin, (PINT32)vpMax);
	}

	return RNGCHK_ERR;
}


/********************************************************************************
*	関数名：InRange																*
*	用　途：値が範囲に入っているかを検査する									*
*	引き数：検査する値、最小値、最大値											*
*	戻り値：検査結果															*
*	備　考：																	*
********************************************************************************/
template<class T>
static INT32 InRange(T v, T *pMin, T *pMax)
{
	if ( pMin )
	{
		if ( v < *pMin ) return RNGCHK_LT;
	}
	if ( pMax )
	{
		if ( v > *pMax ) return RNGCHK_GT;
	}

	return RNGCHK_EQ;
}


/********************************************************************************
*	関数名：CompColor															*
*	用　途：補色の取得															*
*	引き数：色値																*
*	戻り値：補色																*
*	備　考：																	*
********************************************************************************/
COLORREF CompColor(COLORREF src)
{
	COLORREF r,g, b;

	r = src & 0x0000ffL;
	g = (src & 0x00ff00L) >> 8;
	b = (src & 0xff0000L) >> 16;

	r = ~r;
	g = ~g;
	b = ~b;

	return RGB(r, g, b);
}

/********************************************************************************
*	関数名：DateString															*
*	用　途：日付文字列の作成													*
*	引き数：作成文字列格納場所、格納場所サイズ、参照日付文字列、				*
*			日付区切り文字、時刻区切り文字,区切り文字追加フラグ					*
*	戻り値：作成成功でＴＲＵＥ、失敗でＦＡＬＳＥ								*
*	備　考：参照日付文字列がなければ現在日時を利用する。						*
*			格納場所サイズによって作成される文字列が変わる						*
*			※文字数にはヌル文字は含んでいない									*
*			  ６文字	：yymmdd												*
*			  ８文字	：yyyymmdd												*
*			１０文字	：yyyy/mm/dd											*
*			１２文字	：yymmddhhmmss											*
*			１４文字	：yyyymmddhhmmss										*
*			１５文字	：yyyymmdd hhmmss										*
*			１９文字以上：yyyy/mm/dd hh:mm:ss									*
********************************************************************************/
BOOL DateString(
				PTCHAR	szDst,
				INT32	nSize,
				PTCHAR	szSrc,
				TCHAR	nDateSplitter,
				TCHAR	nTimeSplitter,
				TCHAR	bSplitterFlag
				)
{
	SYSTEMTIME	tTime;

	INT32		nCnt, nLen;
	TCHAR		*szPtr;
	TCHAR		szTime[23];

	if ( szDst == 0 || nSize <= 0 ) return FALSE;

	*szDst	= _T('\0');

	nCnt	= nSize / sizeof(TCHAR);

	if(szSrc == 0)
	{
		GetLocalTime(&tTime);
		_stprintf_s(szTime,
					_countof(szTime),
					_T("%4d%02d%02d%02d%02d%02d"),
					tTime.wYear,
					tTime.wMonth,
					tTime.wDay,
					tTime.wHour,
					tTime.wMinute,
					tTime.wSecond
				   );	
		szPtr	= szTime;
	}
	else
	{
		szPtr	= szSrc;
		nLen	= (int)_tcslen(szSrc) + 1;
		if ( nLen < nCnt ) nCnt = nLen;
	}

	switch(nCnt - 1)
	{
	case 6:		/* yymmdd			*/
		_stprintf_s(szDst, nCnt, _T("%2.2s%2.2s%2.2s"), szPtr, szPtr + 2, szPtr + 4);
		break;
	case 8:		/* yyyymmdd			*/
		_stprintf_s(szDst, nCnt, _T("%4.4s%2.2s%2.2s"), szPtr, szPtr + 4, szPtr + 6);
		break;
	case 10:	/* yyyy/mm/dd		*/
		_stprintf_s(szDst, nCnt, _T("%2.2s%c%2.2s%c%2.2s"), szPtr, nDateSplitter, szPtr + 2, nDateSplitter, szPtr + 4);
		break;
	case 12:	/* yymmddhhmmss		*/
		if(bSplitterFlag == FALSE){
			_stprintf_s(szDst, nCnt, _T("%2.2s%2.2s%2.2s%2.2s%2.2s%2.2s"), szPtr, szPtr + 2, szPtr + 4, szPtr + 6, szPtr + 8, szPtr + 10);
		}
		else{
			_stprintf_s(szDst, nSize / sizeof (TCHAR), _T("%2.2s%2.2s%c%2.2s%c%2.2s %2.2s%c%2.2s"),
						szPtr, szPtr + 2, nDateSplitter, szPtr + 4, nDateSplitter, szPtr + 6, szPtr + 8, nTimeSplitter, szPtr + 10);
		}
		break;
	case 14:	/* yyyymmddhhmmss	*/
		_stprintf_s(szDst, nCnt, _T("%4.4s%2.2s%2.2s%2.2s%2.2s%2.2s"), szPtr, szPtr + 4, szPtr + 6, szPtr + 8, szPtr + 10, szPtr + 12);
		break;
	case 15:	/* yyyymmdd hhmmss	*/
		_stprintf_s(szDst, nCnt, _T("%4.4s%2.2s%2.2s %2.2s%2.2s%2.2s"), szPtr, szPtr + 4, szPtr + 6, szPtr + 8, szPtr + 10, szPtr + 12);
		break;
	default:
		if (nCnt <= 19) return FALSE;
		/* yyyy/mm/dd hh:mm:ss */
		_stprintf_s(
					szDst,
					nCnt,
					_T("%4.4s%c%2.2s%c%2.2s %2.2s%c%2.2s%c%2.2s"),
					szPtr,
					nDateSplitter,
					szPtr + 4,
					nDateSplitter,
					szPtr + 6,
					szPtr + 8,
					nTimeSplitter,
					szPtr + 10,
					nTimeSplitter,
					szPtr + 12
					);
		break;
	}

	
	return TRUE;
}

