/*
このファイルの中身は、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) ______________________________________.
*/

//
//	個別ログ(CSV)のSQL作成クラスです。
//		変更履歴
//			2004.09.14 新規作成 A.Shimoma
//

package jp.co.ntt.lms.lo.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;

import org.apache.commons.lang.StringEscapeUtils;

/**
 * 個別ログ(CSV)のSQLを動的に作成します。<BR>
 * @author A.Shimoma
 */
public class IndividualLogSQLMaker {


	// 内部変数
	/** クエリーを保持します */
	private String mstrQuery;

	/** ユーザID配列を保持します */
	private String mstrUserID[];

	/** UID配列を保持します */
	private String mstrUID[];

	/** クエリーのIN句($USER_LIST$)で用いるカラム名 */
	private String mstrInGroupColumn;
	/** クエリーのIN句($UID_LIST$)で用いるカラム名 */
	private String mstrInUIDColumn;

	/** SQL置換文字列です。*/
	private static final String USER_LIST = "USER_LIST";
	private static final String UID_LIST = "UID_LIST";

	/** IN句に連結可能な設定値 */
	private static final int MAXCONNECTECOUNT = 1000;

	/**
	 * コンストラクタです。 <BR>
	 * クエリーIDと対応するマクロ展開前のSQL文と検索条件Vectorを設定します
	 *
	 * @param strQuery マクロ展開前のクエリー
	 * @param strUserID
	 * @param strUID
	 * @param inGroupColumn		クエリーのIN句($USER_LIST$)で用いるカラム名
	 * @param inUIDColumn		クエリーのIN句($UID_LIST$)で用いるカラム名
	 */
	public IndividualLogSQLMaker (
		String strQuery,
		String[] strUserID,
		String[] strUID,
		String inGroupColumn,
		String inUIDColumn ) {

		mstrQuery = strQuery;
		mstrUserID = strUserID;
		mstrUID = strUID;
		mstrInGroupColumn = inGroupColumn;
		mstrInUIDColumn = inUIDColumn;
	}

	/**
	 * SQL文を作成します。
	 *
	 * @return String SQL
	 */
	public String makeQuery() {

		// 1000配列毎にカンマで連結した文字列をリストに設定します。
		List UserList = commaParseForSQL( Arrays.asList( mstrUserID ) );
		String userCondition = inConnection( UserList, mstrInGroupColumn );
		List UIDList = commaParseForSQL( Arrays.asList( mstrUID ) );
		String uidCondition = inConnection( UIDList, mstrInUIDColumn );

		// コンストラクタで受け取った文字列をマクロ展開します
		Hashtable htbMacro = new Hashtable();
		htbMacro.put( USER_LIST, userCondition );
		htbMacro.put( UID_LIST, uidCondition );

		return expand( mstrQuery, htbMacro );
	}


	/**
	 * リスト中の文字列を'Param1','Param2',・・・型の文字列にしてリストで戻す。<br>
	 * リストが1000を超える場合には複数の文字列を作成しリストにして戻す。<br>
	 *
	 * @param prmList 文字列リスト
	 * @return List シングルクォーテーションで囲った後カンマ区切りした文字列リスト。
	 */
	private List commaParseForSQL( List prmList ) {

		// ループ数の取得
		int roupCount = getInCount( prmList );
		// 返却用リスト
		List retList = new ArrayList();
		// リストが1000以上の場合は複数回ループ
		// 最低１度はループする。
		for ( int j = 0; j < roupCount; j++ ) {
			// リスト配下のログ集計
			// ループ開始カウント
			int intStart = j * MAXCONNECTECOUNT;
			// ループ終了カウント
			int intEnd = intStart + MAXCONNECTECOUNT;
			// ループ終了カウントよりリストサイズの方が小さい場合
			if ( prmList.size() < intEnd ) {
				intEnd = prmList.size();
			}
			StringBuffer stbTempSQL = new StringBuffer();
			//  ｢,｣ 区切りの文字列にする
			for ( int i = intStart, k =0 ; i < intEnd; i++, k++ ) {
				String strTemp = ( String ) prmList.get( i );
				if ( k == 0 ) {
					stbTempSQL.append( "'" + StringEscapeUtils.escapeSql(strTemp) + "'" );
				} else {
					stbTempSQL.append( ",'" + StringEscapeUtils.escapeSql(strTemp) + "'" );
				}
			}
			retList.add( stbTempSQL.toString() );
		}
		return retList;
	}

	/**
	 * IN句連結回数取得メソッド <BR>
	 * IN句連結回数を取得します。 <BR>
	 * lstが1000以上の場合、複数個分回のIN句をORで連結します。
	 * その為の回数を取得します。
	 *
	 * @param lst 条件となるデータが格納されたリスト
	 * @return sqlCount IN句連結回数
	 */
	private int getInCount(List lst) {

		int sqlCount = 0;

		if (lst.size() >= MAXCONNECTECOUNT) {
			sqlCount = lst.size() / MAXCONNECTECOUNT;
		}
		if (lst.size() % MAXCONNECTECOUNT != 0) {
			sqlCount++;
		}
		return sqlCount;
	}

	/**
	 * クエリーのIN句を生成します。<BR>
	 * 1000個カンマ区切りでIN句に設定します。
	 * 1000以上の場合はORで連結させます。
	 *
	 * @param lst
	 * @param condition
	 * @return
	 */
	private String inConnection( List lst, String condition ) {

		StringBuffer inPhrase = new StringBuffer();

		for ( int i = 0; i < lst.size(); i++ ) {
			if ( i != 0 ) {
				inPhrase.append( " OR " );
			}
			inPhrase.append( condition );
			inPhrase.append( " IN ( " );
			inPhrase.append( lst.get(i) );
			inPhrase.append( " ) " );
		}

		return inPhrase.toString();
	}

	/**
	 * 文字列をマクロ展開します <BR>
	 * '$'で囲まれた文字列を取得し、引数で渡されたHashtableから
	 * 取得した文字列をキーにして、値を取得し、入れ替えて返します。
	 *
	 * @param strBase 変換前
	 * @param htbTable マクロ情報
	 * @return String 変換後文字列
	 */
	private String expand( String strBase, Hashtable htbTable ) {

		// 返還前文字列をchar配列に変換します
		char[] chrBase = strBase.toCharArray();
		// 変換後の文字列を格納します
		StringBuffer sbBase = new StringBuffer();
		// '$'で囲まれてた文字列を格納します
		StringBuffer sbMacro = new StringBuffer();
		// マクロ文字列読み取り中か、普通の文字列読み取り中かを判断する
		boolean blMacro = false;
		// charの配列文ループします
		for ( int i = 0; i < chrBase.length; i++ ) {
			// '$'の部分はマクロ文字列として格納します
			if ( chrBase[i] == '$' ) {
				if ( blMacro ) {
					blMacro = false;
					// マクロ文字列をキーにして、値を入れる
					String strMacro = ( String ) htbTable.get( sbMacro.toString() );
					// 取得した文字列がnull以外なら、設定
					if ( strMacro != null ) {
						sbBase.append( ( String ) htbTable.get( sbMacro.toString() ) );
					}
					// マクロ文字列を初期化します
					sbMacro = new StringBuffer();
				} else {
					blMacro = true;
				}
				continue;
			}
			// マクロ読み取り中の場合
			if ( blMacro ) {
				sbMacro.append( chrBase[i] );
			}
			// 普通の文字列読み取り中
			else {
				sbBase.append( chrBase[i] );
			}
		}
		return sbBase.toString();
	}
}
