/*
このファイルの中身は、NTT オープンソースライセンス　バージョン 1.0（「本
契約」という）の適用を受けます。
本契約を遵守しない限り、このファイルを使用してはなりません。
本契約のコピーは、次のＵＲＬから入手できます。
【配布サイトのURL】 http://www.oss.ecl.ntt.co.jp/lms/

本契約に基づき頒布されるソフトウェアは、現状のまま、明示又は黙示のあらゆ
る種類の保証なしで、頒布されます。本契約に基づく権利及び制限を律する特定
の文言については、本契約を参照してください。

「オリジナルコード」は、 NTT Cyber Space Laboratories Code です。 
「オリジナルコード」の「初期開発者」は、日本電信電話株式会社です。  
日本電信電話株式会社により創作された部分は、Copyright (C) 2004 
日本電信電話株式会社 です。
全ての権利が留保されます。 
「コントリビュータ」：_____________________________________ 


The contents of this file are subject to the NTT Opensource License
Version 1.0 (the License); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
【配布サイトのURL】 http://www.oss.ecl.ntt.co.jp/lms/

Software distributed under the License is distributed on an AS IS
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.

The Original Code is NTT Cyber Space Laboratories Code .

The Initial Developer of the Original Code is NIPPON TELEGRAPH AND 
TELEPHONE CORPORATION.
Portions created by the NIPPON TELEGRAPH AND TELEPHONE CORPORATION 
are Copyright (C) 2004 NIPPON TELEGRAPH AND TELEPHONE CORPORATION. 
All Rights Reserved.

Contributor(s) ______________________________________.
*/

//
//	2重表示チェックユーティリティクラス
//			変更履歴
//				2004.01.08	新規作成	二條智文
//
package jp.co.ntt.lms.xmo.util;

import java.util.*;
import jp.co.ntt.lms.xmo.LoRelation.LoRelationClient;
import jp.co.ntt.lms.xmo.GroupAndPeople.GroupAndPeopleClient;
import jp.co.ntt.lms.xmo.XMOException;

/**
 * 2重表示チェックユーティリティクラス。
 * @author T.Nijou
 * @version 0.0.0.1
 */
public class DuplicateFilter {

	/** エラーメッセージ */
	private static String CAST_ERR = "Vectorの中身が不正です。";

	/** パスを保持します */
	private HashMap mhtbPath = null;

	/** IDリストを保持します */
	private Vector mvecIDList = null;

	/** パス分解リストを保持します */
	private Vector mvecPasthAnalysisList = new Vector();

	/** フィルタIDリストを保持します */
	private Vector mvecFilterIDList = null;

	/** 2重防止フラグ */
	private boolean mblDuplicate = true;

	/**
	 * コンストラクタです。
	 * @param mvecIDList フィルタを行うIDリストを設定します
	 */
	public DuplicateFilter( Vector vecIDList ) {
		mvecIDList = vecIDList;
	}

	/**
	 * コンストラクタです。
	 * @param vecIDList フィルタを行うIDリストを設定します
	 * @param vecFilterIDList フィルタIDを設定します
	 */
	public DuplicateFilter( Vector vecIDList, Vector vecFilterIDList ) {
		mvecIDList = vecIDList;
		mvecFilterIDList = vecFilterIDList;
	}

	/**
	 * コンストラクタです。
	 * @param vecIDList フィルタを行うIDリストを設定します
	 * @param vecFilterIDList フィルタIDを設定します
	 * @param blDuplicate true: 2重防止を行う false: 2重防止を行わない
	 */
	public DuplicateFilter( Vector vecIDList, Vector vecFilterIDList, boolean blDuplicate ) {
		mvecIDList = vecIDList;
		mvecFilterIDList = vecFilterIDList;
		mblDuplicate = blDuplicate;
	}

	/**
	 * GroupIDの2重表示チェックメソッド<BR>
	 * 引数で渡されたGroupIDリストから2重チェックをして、２重に存在するIDを取り除きます。<BR>
	 * 2重表示防止とはたとえば以下のような場合です。<BR>
	 * <PRE>
	 *        |―GR1
	 *        |   |―GR11
	 *        |       |―GR111
	 *        |―GR2
	 *            |―GR21
	 *
	 *    上記のようなグループツリーで検索結果が、GR1, GR111, GR2となった場合、同一ツリー上で
	 *    下位の位置にあるGR111は検索結果から削除されます。
	 * </PRE>
	 * @exception XMOException XMSⅡ独自例外
	 * @exception Exception RMI通信エラー
	 */
	public void filterDuplicateGroup()
		throws XMOException, Exception
	{
		mhtbPath = new HashMap();
		// LOIDとパスの対応をHashMapに格納する
		for( int i = 0; i < mvecIDList.size(); i++ ) {
			String strID = null;
			try {
				strID = (String)mvecIDList.get(i);
			}
			catch( ClassCastException ce ) {
				throw new XMOException( CAST_ERR );
			}
			Vector vecPathList = new Vector();
			// LOIDを元にパスを取得
			GroupAndPeopleClient objGandP = new GroupAndPeopleClient();
			if( !objGandP.searchPath(strID) ) {
				throw new XMOException( objGandP.getMessage() );
			}

			while( objGandP.next() ) {
				vecPathList.add( objGandP.getPath() );
			}
			mhtbPath.put( strID, vecPathList );

		}
		// フィルタIDで抽出する
		if( mvecFilterIDList != null ) {
			filterID( mvecIDList, mvecFilterIDList, mhtbPath );
		}

		// ２重チェックでさらに抽出
		if( mblDuplicate ) {
			filterDuplicate( mvecIDList, mhtbPath );
		}
	}

	/**
	 * MemberShipIDでフィルタリングします。<BR>
	 * MemberShipIDとは親IDと子IDのペアです。<BR>
	 * MemberShipID には "親ID^子ID"という形式で親IDと子IDを'^'で区切ったものを指定してください。
	 * 上記形式以外のIDが含まれていた場合は例外を投げます。
	 * 2重表示のチェックは行いません。
	 * @exception XMOException XMSⅡ独自例外
	 * @exception Exception RMI通信エラー
	 */
	public void filterDuplicateMemberShip()
		throws XMOException, Exception
	{
		mhtbPath = new HashMap();
		// LOIDとパスの対応をHashMapに格納する
		for( int i = 0; i < mvecIDList.size(); i++ ) {
			String strMemberShipID = null;
			String strChildID = null;
			String strParentID = null;
			try {
				strMemberShipID = (String)mvecIDList.get(i);
				int intPos = strMemberShipID.indexOf( '^' );
				strParentID = strMemberShipID.substring(0, intPos);
				strChildID = strMemberShipID.substring( intPos + 1, strMemberShipID.length() );
			}
			catch( ClassCastException ce ) {
				throw new XMOException( CAST_ERR );
			}
			catch( IndexOutOfBoundsException ie ) {
				throw new XMOException( CAST_ERR );
			}


			Vector vecPathList = new Vector();
			// LOIDを元にパスを取得
			GroupAndPeopleClient objGandP = new GroupAndPeopleClient();
			if( !objGandP.searchPath(strChildID) ) {
				throw new XMOException( objGandP.getMessage() );
			}

			while( objGandP.next() ) {
				String[] strPath = objGandP.getPath();
				int intLen = strPath.length;
				// 親IDがMemberShipIDの親IDと同様のもののみVectorに格納する
				if( intLen > 1 && strPath[intLen - 2].equals( strParentID ) ) {
					vecPathList.add( objGandP.getPath() );
				}
			}
			mhtbPath.put( strMemberShipID, vecPathList );

		}
		// フィルタIDで抽出する
		if( mvecFilterIDList != null ) {
			filterID( mvecIDList, mvecFilterIDList, mhtbPath );
		}
	}

	/**
	 * LOIDの2重表示チェックメソッド<BR>
	 * 引数で渡されたLOIDリストから2重チェックをして、２重に存在するIDを取り除きます。<BR>
	 * 2重表示防止とはたとえば以下のような場合です。<BR>
	 * <PRE>
	 *        |―LO1
	 *        |   |―LO11
	 *        |       |―LO111
	 *        |―LO2
	 *            |―LO21
	 *
	 *    上記のようなグループツリーで検索結果が、LO1, LO111, LO2となった場合、同一ツリー上で
	 *    下位の位置にあるGR111は検索結果から削除されます。
	 * </PRE>
	 * @exception XMOException XMSⅡ独自例外
	 * @exception Exception RMI通信エラー
	 */
	public void filterDuplicateLo()
		throws XMOException, Exception
	{

		mhtbPath = new HashMap();
		// LOIDとパスの対応をHashMapに格納する
		for( int i = 0; i < mvecIDList.size(); i++ ) {
			String strID = null;
			try {
				strID = (String)mvecIDList.get(i);
			}
			catch( ClassCastException ce ) {
				throw new XMOException(CAST_ERR);
			}
			Vector vecPathList = new Vector();
			// LOIDを元にパスを取得
			LoRelationClient objRelation = new LoRelationClient();
			if( !objRelation.searchPath(strID) ) {
				throw new XMOException( objRelation.getMessage() );
			}

			while( objRelation.next() ) {
				vecPathList.add( objRelation.getPath() );
			}
			mhtbPath.put( strID, vecPathList );
		}

		// フィルタIDで抽出する
		if( mvecFilterIDList != null ) {
			filterID( mvecIDList, mvecFilterIDList, mhtbPath );
		}
		// ２重チェックでさらに抽出
		if( mblDuplicate ) {
			filterDuplicate( mvecIDList, mhtbPath );
		}

	}

	/**
	 * 共通２重チェック処理
	 * @param mvecIDList IDのリスト
	 * @param mhtbPath パスリス炉
	 */
	private void filterDuplicate( Vector vecIDList, HashMap htbPath ) {
		// 2重チェック
		ArrayList objDelLo = new ArrayList(); // 廃棄ArrayList
		Iterator it = htbPath.keySet().iterator();
		while(it.hasNext()) {
			String strID = (String)it.next();
			int intIDLength = vecIDList.size();
			for( int i = 0; i < intIDLength; i++ ) {
				String strTempID = (String)vecIDList.get(i);
				if( strID.equals( strTempID ) ) {
					continue;
				}
				if( objDelLo.contains( strTempID ) ) {
					// すでに廃棄LOに登録されているので何もしない
					continue;
				}
				Vector vecPathList = (Vector)htbPath.get(strTempID);
				if( isContainsPath( strID, vecPathList ) ) {
					// LoIDがパスに含まれている場合は廃棄HashMapに格納する
					objDelLo.add( strTempID );
				}
			}
		}

		// 廃棄Vectorに格納されているLoDataをvecIDListから取り除く
		vecIDList.removeAll( objDelLo );
	}

	/**
	 * フィルタIDでフィルタリングする
	 * @param vecIDList IDリスト
	 * @param vecFilterIDList フィルタIDリスト
	 * @param htbPath パスリスト
	 */
	private void filterID( Vector vecIDList, Vector vecFilterIDList, HashMap htbPath )
		throws XMOException
	{
		for( int i = vecIDList.size() -1 ; i >= 0; i-- ) {
			Vector vecPathList = (Vector)htbPath.get(vecIDList.get(i));
			boolean isContain = false;
			for( int j = 0; j < vecFilterIDList.size(); j++ ) {
				String strTargetID = "";
				try {
					strTargetID = (String)vecFilterIDList.get(j);
				}
				catch( ClassCastException ce ) {
					throw new XMOException(CAST_ERR);
				}
				if( isContainsPath( (String)vecFilterIDList.get(j), vecPathList ) ) {
					// ひとつでも含まれていたらOK
					isContain = true;
				}
			}
			if( !isContain ) {
				htbPath.remove(vecIDList.get(i));
				vecIDList.remove(i);
			}
		}
	}

	/**
	 * 内部関数<BR>
	 * パスにターゲットのIDが含まれているかどうかを判断する
	 * @param strTargetID ターゲットID
	 * @param vecPathList パスリスト（中身はString[])
	 * @return boolean true: 含まれる false: 含まれない
	 */
	private boolean isContainsPath( String strTargetID, Vector vecPathList ) {
		if( vecPathList == null ) {
			return false;
		}
		int intPathCount = vecPathList.size();
		for( int i = 0; i < intPathCount; i++ ) {
			String[] strTempPath = (String[])vecPathList.get(i);
			for( int j = 0; j < strTempPath.length; j++ ) {
				if( strTargetID.equals( strTempPath[j] ) ) {
					return true;
				}
			}
		}
		return false;
	}

}

