/*-----------------------------------------------------------------------------
[名称]	TokenReader.cpp
[概要]	トークンリーダクラスの実装
[備考]	なし
[履歴]	2002-12-12	NC		コメント付加(moralog)
-----------------------------------------------------------------------------*/

//-----------------------------------------------------------------------------
// インクルード
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "TokenReader.h"
#include <mbctype.h>
#include "GeneralSetting.h"
#include "WhitespaceDefine.h"
#include "Unicoder.h"
#include "ShitarabianDoc.h"
#include "ExeCommon.h"
#include "MainFrm.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


//-----------------------------------------------------------------------------
// メモ
//-----------------------------------------------------------------------------
/*
■マルチバイトケアの文字列操作関数
	_mbsnbicmp		2つのマルチバイト文字列の最初の n バイトを、大文字小文字を区別せずに、比較する。
	_mbsnbcmp		大文字小文字を区別するバージョン
	_tcsrev			文字列の反転
	_tcstok			文字列内の次のトークンを見つけます。
	_mbslen			マルチバイト文字列中のマルチバイト文字の数を返します
	_tcsstr			部分文字列を見つけます。
	_tcsupr			文字列中の文字を大文字に変換します。
*/


/*-----------------------------------------------------------------------------
[名称]	コンストラクタ
[機能]	インスタンスの生成。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
CTokenReader::CTokenReader()
{

}

/*-----------------------------------------------------------------------------
[名称]	デストラクタ
[機能]	インスタンスの破棄。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
CTokenReader::~CTokenReader()
{

}


/*-----------------------------------------------------------------------------
[名称]	トークン分割
[機能]	文字列のカラムを文字種別ごとに分割し、アレイに格納する。
[戻値]	なし
[備考]	空白文字設定を反映する。
-----------------------------------------------------------------------------*/
int	CTokenReader::StringToCharTypez(
	CString&					strSrc,		// I: 分割元文字列 [-] (-) :-
	CArray< TToken, TToken& >*	paTokenz	// O: 分割後文字列配列 [-] (-) :-
)
{
// カラム文字種情報の組み立て
	paTokenz->RemoveAll();

	// 文字列を走査
	int		idxByte = 0;
	int		idxColumn = 0;
	int		idxTypeStartColumn = 0;
	ECharType	ePrevCharType = CharTypeFunction;
	while( idxByte < strSrc.GetLength() )
	{
		// カラムの文字種別判定
		ECharType	eCharType = CharTypeWhitespace;
		long		nColumn = 0;
		while( TRUE )	// break条件が多いのでswitch文風に記述する
		{
			unsigned char	iChar = strSrc[ idxByte ];

			// WhiteSpaceDefineに合致すれば空白文字
			{
				const char* pstrChar = ((LPCTSTR)strSrc) + idxByte;
				CWhitespaceDefine*	pWhiteSpace = CGeneralSetting::GetInstance()->GetWhitespace();
				int		nByte;
				BOOL	bWhiteSpace = pWhiteSpace->IsWhitespace(
					pstrChar,
					&nByte
				);
				if( bWhiteSpace )
				{
					eCharType = CharTypeWhitespace;
					idxByte += nByte;

					CShitarabianDoc*	pDoc;
					pDoc = ::GetDocument();
					nColumn = ::StringToColumn( CString( pstrChar, nByte ) );
					break;
				}
			}

			// ユニコード
			{
				const char* pstrChar = ((LPCTSTR)strSrc) + idxByte;

				// Unicode判定
				wchar_t		wcharUnicode;
				CUnicoder*	pUnicoder = CUnicoder::GetInstance();
				long	nByte = pUnicoder->IsUnicode(
					pstrChar,
					&wcharUnicode
				);
				if ( nByte > 0 )
				{
					eCharType = CharTypeUnicode;
					idxByte += nByte;
					nColumn = nByte;
					break;
				}
			}
	
			// リードバイトであれば全角文字
			if ( _ismbblead( iChar ) )
			{
				eCharType = CharTypeDoubleByte;
				idxByte+=2;
				nColumn = 1;
				break;
			}

			// 英数字
			{
				BOOL	bFound = FALSE;
				switch ( iChar )
				{
				case '_':
					eCharType = CharTypeAlphabet;
					bFound = TRUE;
					break;
				default:
					if( _istalnum( iChar ) )
					{
						eCharType = CharTypeAlphabet;
						bFound = TRUE;
					}
					break;
				}
				if ( bFound )
				{
					idxByte++;
					nColumn = 1;
					break;
				}
			}

			// 記号
			{
				eCharType = CharTypeFunction;
				idxByte++;
				nColumn = 1;
				break;
			}
		}

		// 種別が直前のものと異なればPrev情報からTokenを記録
		if ( eCharType != ePrevCharType )
		{
			if ( idxColumn-idxTypeStartColumn > 0 )
			{
				TToken	tToken;
				tToken.eCharType = ePrevCharType;
				tToken.idxStartColumn = idxTypeStartColumn;
				tToken.nColumn = idxColumn-idxTypeStartColumn;
				paTokenz->Add( tToken );
			}
			ePrevCharType = eCharType;
			idxTypeStartColumn = idxColumn;
		}

		idxColumn += nColumn;
	}
	// 最後尾Tokenを記録
	if ( idxColumn-idxTypeStartColumn > 0 )
	{
		TToken	tToken;
		tToken.eCharType = ePrevCharType;
		tToken.idxStartColumn = idxTypeStartColumn;
		tToken.nColumn = idxColumn-idxTypeStartColumn;
		paTokenz->Add( tToken );
	}

	return( paTokenz->GetSize() );
}


/*-----------------------------------------------------------------------------
[名称]	単語特定
[機能]	文字列のカラムを文字種別ごとに分割し、アレイに格納する。
[戻値]	long 検索対象カラムを含むトークン [インデクス] (0〜:Found、InvalidTokenIndex:NotFound)
[備考]	なし
-----------------------------------------------------------------------------*/
int	CTokenReader::TokenIndex(
	CArray< TToken, TToken& >&	aTokenz,	// I: トークンアレイ [-] (-) :-
	int							idxColumn	// I: 検索対象カラム [-] (-) :-
)
{
	// トークンアレイ要素のカラム数を、検索対象カラムに達するまで順に足しこむ
	int		idxToken;
	for( idxToken=0 ; idxToken<aTokenz.GetSize() ; idxToken++ )
	{
		if ( idxColumn >= aTokenz[idxToken].idxStartColumn )
		if ( idxColumn < aTokenz[idxToken].idxStartColumn + aTokenz[idxToken].nColumn )
		{
			// 検索対象カラムに達したので、HITトークンとみなす
			return( idxToken );
		}
	}

	// HITするトークンが不在
	return( InvalidTokenIndex );
}

