/*-----------------------------------------------------------------------------
[名称]	CategoryTree.cpp
[概要]	カテゴリツリーの実装
[備考]	なし
[履歴]	2003-03-18	NC		新規作成(moralog)
-----------------------------------------------------------------------------*/


//-----------------------------------------------------------------------------
// インクルード
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "hebope.h"
#include "CategoryTree.h"
#include "CategoryNode.h"
#include "ExeCommon.h"
#include "MainFrm.h"
#include <ctype.h>

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


//-----------------------------------------------------------------------------
// ファイル内関数
//-----------------------------------------------------------------------------


/*-----------------------------------------------------------------------------
[名称]	文字列一致長さ取得
[機能]	先頭から何バイト同じかを得る。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
long	CompareString(
	const char*		strA,	// I  :文字列A [-] (-)
	const char*		strB	// I  :文字列B [-] (-)
)
{
	long	lLength = 0;
	while( TRUE )
	{
		if( strA[lLength] != strB[lLength] )
		{
			break;
		}

		if( strA[lLength] == 0x00 )
		{
			break;
		}

		lLength++;
	}
	return( lLength );
}


//-----------------------------------------------------------------------------
// メンバ関数
//-----------------------------------------------------------------------------


/*-----------------------------------------------------------------------------
[名称]	コンストラクタ
[機能]	インスタンスの生成。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
CCategoryTree::CCategoryTree()
{
	m_CategoryNode.SetNodeName( (CString)"(無題)" );
}


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

}


/*-----------------------------------------------------------------------------
[名称]	自動カテゴライズ
[機能]	カテゴリわけする。
[戻値]	なし
[備考]	AA名称の先頭iNearSreshold文字を検査して同一なら同じカテゴリにする。
-----------------------------------------------------------------------------*/
void CCategoryTree::Categorize(
	CAAHanger&		AAHanger,		// <I>	AA情報 [-] (-) :-
	CCategoryNode*	pBranchNode		// <I>	対象ノード [-] (-) :-
)
{
	long	iNearSreshold = ::GetMainFrame()->GetNearPattern();
	long	iMinCategoryMember = ::GetMainFrame()->GetMinMember();

	// ツリーの初期化
//	pBranchNode->RemoveAllNode();

	// 処理済を判別するためのフラグ
	CDWordArray		adwAAz;
	{
		adwAAz.SetSize( pBranchNode->GetIndexCount() );
		for ( long idxAA=0 ; idxAA<pBranchNode->GetIndexCount() ; idxAA++ )
		{
			adwAAz[ idxAA ] = pBranchNode->GetIndex( idxAA );
		}
	}

	// とりあえずインデクスを全て削除
	pBranchNode->RemoveAllIndex();

	while( adwAAz.GetSize() > 0 )
	{
		CString	strCategoryName = AAHanger.GetName( adwAAz[ 0 ] );

		// 近似とみなすバイト数（マルチバイト判別）
		long	iNearByte = 0;
		{
			long	iNearColumn = iNearSreshold;
			while( iNearColumn > 0 )
			{
				if ( isleadbyte( ((LPCTSTR)strCategoryName)[ iNearByte ] ) )
				{
					iNearByte++;
				}
				iNearByte++;
				iNearColumn--;
			}
		}

		// 近似のAA名称を探す
		CDWordArray		adwHitz;
		long			lCategoryNameLength = strCategoryName.GetLength();
		for ( long idxYet=0 ; idxYet<adwAAz.GetSize() ; idxYet++ )
		{
			CString	strAAName = AAHanger.GetName( adwAAz[ idxYet ] );

			long lMatchLength = CompareString(
				strCategoryName,
				strAAName
			);

			BOOL	bSame = ( lMatchLength == strAAName.GetLength() );
			BOOL	bNear = ( lMatchLength >= iNearByte );

			// カテゴリにマッチした
			if ( bSame || bNear )
			{
				lCategoryNameLength = min( lCategoryNameLength, lMatchLength );
				adwHitz.Add( idxYet );
			}
		}

		if( adwHitz.GetSize() >= iMinCategoryMember )
		{
		// カテゴリを作るにたる集団を発見した
			// カテゴリ名称を作成
			{
			// please! マルチバイト文字を考慮してlCategoryNameLength バイト以内
				long	nNameByte = 0;
				while( TRUE )
				{
					int	nByte = 1;
					if ( isleadbyte( ((LPCTSTR)strCategoryName)[ nNameByte ] ) )
					{
						nByte = 2;
					}

					if( nNameByte+nByte > lCategoryNameLength )
					{
						break;
					}
					nNameByte += nByte;
				}

				CString	tmp = strCategoryName.Left( nNameByte );
				strCategoryName = tmp;
			}

			// ツリーに追加
			CCategoryNode*	pNode = pBranchNode->AddNode( strCategoryName, FALSE );
			pNode->SetNodeName( strCategoryName );
			for( long idxHit=adwHitz.GetSize()-1 ; idxHit>=0 ; idxHit-- )
			{
				pNode->AddIndex( adwAAz[ adwHitz[ idxHit ] ] );
				// ヒットした要素を処理済として削除
				adwAAz.RemoveAt( adwHitz[ idxHit ] );
			}


			// ドキュメントに変更あり！
			::NotifyModified();
		}
		else
		{
		// カテゴリを作るほどでもない要素
			// カテゴリわけせずルートに追加する
			pBranchNode->AddIndex( adwAAz[ 0 ] );
			adwAAz.RemoveAt( 0 );
		}
	}
}


/*-----------------------------------------------------------------------------
[名称]	インデクス追加
[機能]	カテゴリわけせずにルート直下にインデクスを追加する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CCategoryTree::AddIndexz(
	CAAHanger&	AAHanger		// I  :AA情報 [-] (-)
)
{
	// ツリーの初期化
	CCategoryNode*	pBranchNode;
	pBranchNode = Node();
	pBranchNode->RemoveAllNode();
	pBranchNode->RemoveAllIndex();

	// カテゴリわけせずルートに追加する
	for ( long idxAA=0 ; idxAA<AAHanger.GetCount() ; idxAA++ )
	{
		pBranchNode->AddIndex( idxAA );
	}
}


void CCategoryTree::AddAA(
	CCategoryNode*	pBranchNode,
	long			idxAA
)
{
	// ノードに追加する
	pBranchNode->AddIndex( idxAA );
}


void CCategoryTree::AddAA(
	const CString&	strNodeName,
	long			idxAA
)
{
	// ツリーのルートを取得
	CCategoryNode*	pRootNode;
	pRootNode = Node();

	// 目的のノードを取得
	CCategoryNode*	pBranchNode;
	pBranchNode = pRootNode;

	// ノードに追加する
	AddAA(
		pBranchNode,
		idxAA
	);
}