#include "StdAfx.h"
#include ".\texttools.h"
#include <comutil.h>

#pragma comment(lib,"comsuppw.lib")

CString CTextTools::GetFormat(LPCTSTR lpszFormat, ...)
{
	va_list argList;
	CString	str;
	va_start(argList, lpszFormat);
	str.FormatV(lpszFormat,argList);
	va_end(argList);

	return str;
}


__int64 CTextTools::strtoi64(CString str,int base)
{
	char	*err;
	return _strtoi64(str,&err,base);
}



//////////////////////////////////////////////////////////////////////
// ライン切り出し
//////////////////////////////////////////////////////////////////////
int CTextTools::GetLine(CString &str, CString &line)
{
	int index = str.Find("\r\n");

	if(index == -1)
	{
		if(str.IsEmpty())
			return(0);

		line = str;
		str.Empty();
		return(1);
	}
	
	//	切り出し
	line = str.Left(index);

	//	削除
	str = str.Mid(index + 2);
	return(1);
}

//////////////////////////////////////////////////////////////////////
// トークン切り出し
//////////////////////////////////////////////////////////////////////
int CTextTools::GetToken(CString &str, CString &token, CString div, int trim)
{
	//	空っぽ？
	if(str.IsEmpty())
		return(0);

	//	divの長さ
	int tlen = div.GetLength();

	//	トークンを検出
	int index = str.Find(div);
	if(index == -1)
	{
		token = str;
		if(trim)
			token.Trim();
		str.Empty();
		return(1);
	}
	
	//	切り出し
	token = str.Left(index);
	if(trim)
		token.Trim();

	//	削除
	str = str.Mid(index + tlen);
	return(1);
}


/*!
	トークン全て切り出し
*/
void CTextTools::GetAllToken(CString str, CStringArray &tokens, CString div, int trim)
{
	tokens.RemoveAll();

	CString token;
	while(GetToken(str, token, div, trim))
		tokens.Add(token);
}

/*!
	トークンの切り出し(ダブルコーテーションによる文字列に対応)
*/
int CTextTools::GetTokenDoubleQuotation(CString &str, CString &token, CString div, int trim)
{
	//	空っぽ？
	if(str.IsEmpty())
		return(0);

	//	divの長さ
	int tlen = div.GetLength();

	//	トークンを検出
	int	curPos = 0;
	while(1)
	{
		int divIndex = str.Find(div, curPos);
		if(divIndex == -1)
		{
			//	全てがトークン
			token = str;

			//	トリム
			if(trim)
				token.Trim();

			//	残りを削除
			str.Empty();
			return(1);	
		}

		//	ダブルコーテーションを検索
		int dqIndex = str.Find(_T("\""), curPos);
		if(dqIndex != -1 && dqIndex < divIndex)	//	divよりダブルコーテーションが手前にある
		{
			//	閉じる方を検索
			dqIndex = str.Find(_T("\""), dqIndex + 1);
			if(dqIndex == -1)
			{
				//	全てがトークン
				token = str;

				//	トリム
				if(trim)
					token.Trim();

				//	残りを削除
				str.Empty();
				return(1);	
			}
			curPos = dqIndex + 1;
		}
		else
		{
			//	切り出し
			token = str.Left(divIndex);
			if(trim)
				token.Trim();

			//	削除
			str = str.Mid(divIndex + tlen);
			return(1);
		}
	}
}

/*!
	トークン全て切り出し(ダブルコーテーションによる文字列に対応)
*/
void CTextTools::GetAllTokenDoubleQuotation(CString str, CStringArray &tokens, CString div, int trim)
{
	tokens.RemoveAll();

	CString token;
	while(GetTokenDoubleQuotation(str, token, div, trim))
		tokens.Add(token);
}

/*!
	文字列前後のダブルコーテーションを処理
*/
CString CTextTools::RemoveDoubleQuotation(CString str)
{
	//	短い？
	if(str.GetLength() < 2)
		return(str);

	//	ダブルコーテーションを処理
	if(str.Left(1) == _T("\"") && str.Right(1) == _T("\""))
		str = str.Mid(1, str.GetLength() - 2);
	return(str);
}

//////////////////////////////////////////////////////////////
//	ワイルドカード比較
//////////////////////////////////////////////////////////////
/*!
	ワイルドカードで比較

	\return TRUE->一致
*/
int CTextTools::WildCompare(CString wild, CString str)
{
	//	前処理
	wild.MakeLower();
	str.MakeLower();

	return(StrMatch(wild, str));
}

/*!
	下請け
*/
int CTextTools::StrMatch( const char *Ptn, const char *Str )
{
	switch( *Ptn )
	{
		case '\0':
			return (*Str=='\0');
		case '*':
			return StrMatch( Ptn+1, Str ) || (*Str!='\0') && StrMatch( Ptn, Str+1 );
		case '?':
			return (*Str!='\0') && StrMatch( Ptn+1, Str+1 );
		default:
			return ((unsigned char)*Ptn==(unsigned char)*Str) && StrMatch( Ptn+1, Str+1 );
	}
}


//////////////////////////////////////////////////////////////
//	文字列配列処理
//////////////////////////////////////////////////////////////
/*!
	配列から文字列を検索
*/
int CTextTools::FindStrIndex(CStringArray &list, CString find, int noCase)
{
	for(int i=0;i<list.GetSize();i++)
	{
		if(noCase)
		{
			if(list[i].CompareNoCase(find) == 0)
				return(i);
		}
		else
		{
			if(list[i] == find)
				return(i);
		}
	}

	return(-1);
}

//////////////////////////////////////////////////////////////
//	文字列変換
//////////////////////////////////////////////////////////////
/*!
	Unicodeから、ANSI文字列へ
*/
CStringA CTextTools::WideStrToMultiStr(const wchar_t *str)
{
	CStringA	ret;
	ret = (char *)_bstr_t(str);

	return(ret);
}

/*!
	MBから、Unicode文字列へ
*/
CStringW CTextTools::MBStrToWideStr(const char *str)
{
	CStringW	ret;
	ret = str;

	return(ret);
}

/*!
	MBからUTF8へ
*/
CStringA CTextTools::MBStrToUTF8Str(const char *str)
{
	//	UTF16へ変換
	CStringW			utf16(str);

	//	UTF8へ変換
	int mbLen = WideCharToMultiByte(CP_UTF8, 0, utf16.GetBuffer(0), utf16.GetLength(), NULL, 0, NULL, NULL);
	CStringA	utf8;
	WideCharToMultiByte(CP_UTF8, 0, utf16.GetBuffer(0), utf16.GetLength(), utf8.GetBuffer(mbLen + 1), mbLen, NULL, NULL);
	utf8.ReleaseBufferSetLength(mbLen);

	return(utf8);
}

/*!
	UTF8からMBへ
*/
CStringA CTextTools::UTF8ToMBStr(const char *str)
{
	//	変換
	CStringW	utf16;
	int wbLen = MultiByteToWideChar(CP_UTF8, 0, str, (int)strlen(str), NULL, 0);
	MultiByteToWideChar(CP_UTF8, 0, str, (int)strlen(str), utf16.GetBuffer(wbLen), wbLen);
	utf16.ReleaseBufferSetLength(wbLen);

	return(CStringA(utf16));
}

/*!
	UnicodeからUTF8へ
*/
CStringA CTextTools::WideStrToUTF8Str(const wchar_t *str)
{
	//	UTF16
	CStringW			utf16(str);

	//	UTF8へ変換
	int mbLen = WideCharToMultiByte(CP_UTF8, 0, utf16.GetBuffer(0), utf16.GetLength(), NULL, 0, NULL, NULL);
	CStringA	utf8;
	WideCharToMultiByte(CP_UTF8, 0, utf16.GetBuffer(0), utf16.GetLength(), utf8.GetBuffer(mbLen + 1), mbLen, NULL, NULL);
	utf8.ReleaseBufferSetLength(mbLen);

	return(utf8);
}

/*!
	文字列をUTF8へ
*/
CStringA CTextTools::StrToUTF8(CString str)
{
#ifdef _UNICODE
	return WideStrToUTF8Str(str);
#else
	return MBStrToUTF8Str(str);
#endif
}



///////////////////////////////////////////////////////////////////////////
//	文字列のエスケープ
///////////////////////////////////////////////////////////////////////////
/*!
	エスケープの実行
*/
CString CTextEscape::Escape(CString src)
{
	CString	ret;

	int	curPos = 0;
	while(1)
	{
		int	findIndex;
		int itemIndex = MultiFind(curPos, findIndex, src, m_escape);

		if(itemIndex != -1)
		{
			//	切り出し
			if(findIndex > curPos)
				ret += src.Mid(curPos, findIndex - curPos);

			//	置き換え
			ret += m_escape[itemIndex].m_escape;
			curPos = findIndex + m_escape[itemIndex].m_token.GetLength();
		}
		else
		{
			if(ret.IsEmpty())
				return(src);
			return(ret + src.Mid(curPos));
		}
	}
}

/*!
	エスケープの解除
*/
CString CTextEscape::UnEscape(CString escaped)
{
	CString	ret;

	int	curPos = 0;
	while(1)
	{
		int	findIndex;
		int itemIndex = MultiFind(curPos, findIndex, escaped, m_unescape);

		if(itemIndex != -1)
		{
			//	切り出し
			if(findIndex > curPos)
				ret += escaped.Mid(curPos, findIndex - curPos);

			//	置き換え
			ret += m_unescape[itemIndex].m_escape;
			curPos = findIndex + m_unescape[itemIndex].m_token.GetLength();
		}
		else
		{
			if(ret.IsEmpty())
				return(escaped);
			return(ret + escaped.Mid(curPos));
		}
	}
}

/*!
	追加
*/
void CTextEscape::AddEscape(CString token, CString escape)
{
	m_escape.Add(CTextEscapeItem(token, escape));
	m_unescape.Add(CTextEscapeItem(escape, token));
}

/*!
	クリア
*/
void CTextEscape::Clear()
{
	m_escape.RemoveAll();
	m_unescape.RemoveAll();
}


/*!
	一番最初に見つかったインデックスを取得
*/
int CTextEscape::MultiFind(int startIndex, int &findIndex, CString &src, CArray<CTextEscapeItem> &items)
{
	findIndex = src.GetLength() + 1;
	int	itemIndex = -1;
	for(int i=0;i<items.GetCount();i++)
	{
		int index = src.Find(items[i].m_token, startIndex);
		if(index != -1)
		{
			if(itemIndex == -1 || findIndex > index)
			{
				itemIndex = i;
				findIndex = index;
			}
		}
	}

	return(itemIndex);
}

