///////////////////////////////////////////////////////////////////////////
// KeywordFinder.h
// キーワードのリストの中から、キーワードの検索を行う
///////////////////////////////////////////////////////////////////////////

#if !defined( KEYWORDFINDER_H_INCLUDED_ )
#define KEYWORDFINDER_H_INCLUDED_

#include <vector>
#include <string>

// 処理系がASCIIコードを使用しているか否か
#define LANGEXT_IS_ASCII 1

namespace NLangExt {

template < typename T_Char, bool IsSensitive = true >
class CKeywordFinder
{
public:
	CKeywordFinder( const std::vector< std::wstring > *argpVec )
		: pKeywordVec( argpVec ), CharCnt( 0 )
	{
		s = 0;
		e = argpVec->size();
	};
private:
	// 文字を比較する
	int CompareChar( T_Char c1, T_Char c2 )
	{
		if ( IsSensitive )
			return c1 - c2;
		else {

#if LANGEXT_IS_ASCII
			if ( c1 >= T_Char( 'a' ) && c1 <= T_Char( 'z' ) )
				c1 &= 0xDF;
			if ( c2 >= T_Char( 'a' ) && c2 <= T_Char( 'z' ) )
				c2 &= 0xDF;
			return c1 - c2;
#else
			const char *pLC = "abcdefghijklmnopqrstuvwxyz";
			const char *pBC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
			int i;
			T_Char wc1, wc2;
			for ( i = 0; i < 26 && c1 != T_Char( pLC[i] ); i++ );
			if ( i >= 26 )
				wc1 = c1;
			else
				wc1 = T_Char( pBC[i] );
			for ( i = 0; i < 26 && c2 != T_Char( pLC[i] ); i++ );
			if ( i >= 26 )
				wc2 = c2;
			else
				wc2 = T_Char( pBC[i] );
			return wc1 == wc2;
#endif
		}
	}

	// 文字の追加による、キーワードの限定（探索)
	int AddChar_Search( T_Char c )
	{
		int L = s;
		int H = e;
		int M;
		while ( L < H ){
			M = ( L + H ) / 2;
			int r = CompareChar( (*pKeywordVec)[M][CharCnt], c );
			if ( r == 0 ) return M;
			if ( r > 0 )
				H = M;
			else
				L = M + 1;
		}
		return -1;
	}

	// 文字の追加による、キーワードの範囲の限定（始点）
	int AddChar_LowerBound( T_Char c )
	{
		int r = AddChar_Search( c );
		if ( r < 0 ) return -1;
		while ( r >= s && CompareChar( (*pKeywordVec)[r][CharCnt], c ) == 0 )
			r--;
		return r + 1;
	}

	// 文字の追加による、キーワードの範囲の限定（終点）
	int AddChar_UpperBound( T_Char c )
	{
		int r = AddChar_Search( c );
		if ( r < 0 ) return -1;
		while ( r < e && CompareChar( (*pKeywordVec)[r][CharCnt], c ) == 0 )
			r++;
		return r;
	}
public:
	// 文字を追加し、キーワードの範囲を限定する
	void AddChar( T_Char c )
	{
		int sr, er;
		if ( s >= 0 && e >= 0 && s < e ) {
			sr = AddChar_LowerBound( c );
			er = AddChar_UpperBound( c );
			if ( sr < 0 )
				s = -1;
			else
				s = sr;
			if ( er < 0 )
				e = -2;
			else
				e = er;
		}
/*
		// 始点を進める
		for (; s < e && s < pKeywordVec->size() && !CompareChar( (*pKeywordVec)[s][CharCnt], c ); s++ );
		// 終点を進める
		for ( e-- ; e > s && e > 0 && !CompareChar( (*pKeywordVec)[e][CharCnt], c ); e-- );
		e++;
*/
		CharCnt++;
	};

	// キーワードが見つかったか否か
	bool IsFound()
	{
		if ( s >= e )
			return false;	// 該当するものはなかった
		return ( T_Char( (*pKeywordVec)[s][CharCnt] ) == T_Char( '\0' ) );
	};

	// 見つかった文字列を取得する
	const std::wstring& GetFoundStr() const
	{
		return (*pKeywordVec)[s];
	};

protected:
	const std::vector< std::wstring > *pKeywordVec;
	int CharCnt;
	int s;
	int e;
};

};

#endif // KEYWORDFINDER_H_INCLUDED_

