// ★コメント未記入
// FinderDefault.cpp: CFinderDefault クラスのインプリメンテーション
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ShitarabianView.h"
#include "ShitarabianDoc.h"
#include "FinderDefault.h"
#include "Selection.h"
#include "CommandCaret.h"
#include "TokenReader.h"
#include "ExeCommon.h"

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

//////////////////////////////////////////////////////////////////////
// 構築/消滅
//////////////////////////////////////////////////////////////////////

CFinderDefault::CFinderDefault()
{

}

CFinderDefault::~CFinderDefault()
{

}





// 行から文字列を検索
BOOL CFinderDefault::FindAtLine(
	CString&			strTarget,
	long				idxStartColumn,
	long				idxEndColumn,
	CString&			strSubStringSrc,
	long*				pidxFoundCaretColumn,
	long*				pnCaretColumn,
	BOOL				bCaseCare,
	BOOL				bToken
)
{

	return(
		FindAtString(
			strTarget,
			idxStartColumn,
			idxEndColumn,
			strSubStringSrc,
			pidxFoundCaretColumn,
			pnCaretColumn,
			bCaseCare,
			bToken
		)
	);
}


BOOL CFinderDefault::FindAtString(
	CString&			strSrc,
	long				idxStartColumn,
	long				idxEndColumn,
	CString&			strSubStringSrc,
	long*				pidxFoundCaretColumn,
	long*				pnCaretColumn,
	BOOL				bCaseCare,
	BOOL				bToken
)
{
	// 大文字小文字を区別しない場合、SubStringを前もって大文字変換する。
	CString	strSubString( strSubStringSrc );
	if ( !bCaseCare )
	{
		_tcsupr( strSubString.GetBuffer( strSubString.GetLength() ) );
	}

	if ( idxStartColumn <= idxEndColumn )
	{
		int idxStartByte = ::CaretColumnToByteColumn( (LPCTSTR)strSrc, idxStartColumn );
		int idxEndByte = ::CaretColumnToByteColumn( (LPCTSTR)strSrc, idxEndColumn );

		// 検索対象だけにぶった切る
		CString		strSubLine(
			(LPCTSTR)strSrc + idxStartByte,
			idxEndByte - idxStartByte
		);

		// 大文字小文字を区別しない場合、前もって大文字変換する。
		if( !bCaseCare )
		{
			_tcsupr( strSubLine.GetBuffer( strSubLine.GetLength() ) );
			_tcsupr( strSubString.GetBuffer( strSubString.GetLength() ) );
		}

		// 「単語単位」用トークン情報作成
// please! ここでつくると遅くなるかな？
		CArray< TToken, TToken& >	aTokenz;
		if ( bToken )
		{
			CTokenReader::StringToCharTypez(
				strSrc,
				&aTokenz
			);
		}

		int		idxOffset = 0;
		BOOL	bFound = TRUE;
		while( bFound )
		{
			// 文字列の検索
			bFound = FALSE;
			int		idxFoundByte = 0;
			{
				char*	pFound;
				pFound = _tcsstr(
					( (LPCTSTR)(strSubLine)+idxOffset ),
					strSubString
				);
				if ( pFound != NULL )
				{
					bFound = TRUE;
					idxFoundByte = (int)pFound - (int)( (LPCTSTR)(strSubLine)+idxOffset );
				}
			}
			if ( !bFound )
			{
				break;
			}

			BOOL	bValid = TRUE;

			int	idxFoundCaretColumn = ::ByteColumnToCaretColumn(
										(LPCTSTR)strSrc,
										idxStartByte+idxFoundByte+idxOffset
										);
			int nCaretColumn = ::StringToColumn( strSubString );

			// 単語単位検査
			if ( bToken )
			{
				// 選択単語先頭がトークンの先頭？
				BOOL	bTokenHead = FALSE;
				{
					int		idxToken = CTokenReader::TokenIndex(
						aTokenz,
						idxFoundCaretColumn
					);
					if ( idxToken != InvalidTokenIndex )
					if ( aTokenz[ idxToken ].idxStartColumn == idxFoundCaretColumn )
					{
						bTokenHead = TRUE;
					}
				}

				// 選択単語末尾がトークンの末尾？
				BOOL	bTokenLast = FALSE;
				{
					int		idxToken = CTokenReader::TokenIndex(
						aTokenz,
						idxFoundCaretColumn + nCaretColumn -1
					);
					if ( idxToken != InvalidTokenIndex )
					{
						int idxLastColumn = aTokenz[ idxToken ].idxStartColumn + aTokenz[ idxToken ].nColumn -1;
						if ( idxLastColumn == idxFoundCaretColumn + nCaretColumn -1 )
						{
							bTokenLast = TRUE;
						}
					}
				}

				bValid = bTokenHead && bTokenLast;
			}

			// 見つかれば完了
			if( bValid )
			{
				*pidxFoundCaretColumn = idxFoundCaretColumn;
				*pnCaretColumn = nCaretColumn;
				return( TRUE );
			}

			idxOffset += idxFoundByte +1;
		}
	}

	return( FALSE );
}


long CFinderDefault::GetMatchz(
	CString&					strSrc,
	CString&					strSubString,
	CArray<TMatch, TMatch& >*	paMatchz,
	BOOL						bCaseCare,
	BOOL						bToken,
	BOOL						bNeedSubMatch
)
{
// ▼ (ワーニング回避) BGN 2003.12.29 (moralog) warning C4100
	// warning C4100 回避
	bNeedSubMatch;
// ▲ (ワーニング回避) END

	BOOL	bFound = FALSE;

	long	idxStartColumn = 0;
	long	idxEndColumn = INT_MAX;

	while( TRUE )
	{
		long	idxFoundCaretColumn;
		long	nCaretColumn;

		bFound = FindAtString(
			strSrc,
			idxStartColumn,
			idxEndColumn,
			strSubString,
			&idxFoundCaretColumn,
			&nCaretColumn,
			bCaseCare,
			bToken
		);

		if ( bFound )
		{
			// マッチ情報
			TMatch	match;
			match.idxStartColumn = idxFoundCaretColumn;
			match.nColumn = nCaretColumn;
			paMatchz->Add( match );

			idxStartColumn += nCaretColumn;
		}
		else
		{
			break;
		}
	}
	return( paMatchz->GetSize() ); 
}


/*-----------------------------------------------------------------------------
[名称]	文字列検索
[機能]	対照文字列から任意の文字列をひとつ検索する。
[戻値]	BOOL	検索結果 [-] (TRUE:マッチ、FALSE:マッチしない)
[備考]	複数行強調表示色の終端文字列の検索に使用する。
-----------------------------------------------------------------------------*/
BOOL CFinderDefault::QuickMatch(
	LPCTSTR			strSrc,			// I  :検索対象文字列 [-] (-) :-
	CString&		strSubString,	// I  :検索文字列 [普通の文字列] (-) :-
	TMatch*			pMatch,			//   O:マッチ情報 [-] (-) :-
	BOOL			bCaseCare,		// I  :大文字小文字区別 [-] (TRUE:する、FALSE:しない) :-
	BOOL			bToken			// I  :単語単位 [-] (TRUE:する、FALSE:しない) :-
)
{
	BOOL	bFound = FALSE;
	CString	strTarget( strSrc );
	bFound = FindAtString(
		strTarget,
		0,
		INT_MAX,
		strSubString,
		&pMatch->idxStartColumn,
		&pMatch->nColumn,
		bCaseCare,
		bToken
	);

	return( bFound ); 
}
