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

//
//	セッションLOログデータアクセスクラス
//			変更履歴
//				2004.01.08	新規作成	二條智文
//
package jp.co.ntt.lms.lo;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.Vector;

import org.apache.commons.lang.StringEscapeUtils;

import jp.co.ntt.lms.xmo.DataAccess;
import jp.co.ntt.lms.xmo.Environment;
import jp.co.ntt.lms.xmo.util.DebugLog;
import jp.co.ntt.lms.xmo.util.XMODate;

/**
 * セッションLOログ　データアクセスクラスです。<BR>
 * @version 0.0.0.1 2004.01.08
 * @author T.Nijou
 */
public class LoLogSessionDataAccess {

	/** テーブル名を保持します */
	private static final String TABLE_NAME = "LoLogSession";

	/** テーブル定義 */
	private static final String FULLSCORE = "fullscore";				// 満点
	private static final String STUDY_START_DATE = "study_start_date";	// 学習開始日時
	private static final String RESIDANCETIME = "residanceTime";		// 累積滞在時間
	private static final String PASSDAY = "passday";					// 合格日
	private static final String STUDY_END_DATE = "study_end_date";		// 修了日
	private static final String HIGHTSCORE = "highScore";				// 最高点
	private static final String LOWSSCORE = "lowsScore";				// 最低点
	private static final String EXECISE_POINT = "execise_point";		// 得点
	private static final String USERID = "UserID";						// ユーザID
	private static final String LOID = "LOID";							// LOID
	private static final String SESSIONID = "SessionID";				// セッションID
	private static final String LUNCH_TIMES = "Lunchtimes";				// 学習回数
	private static final String CONDITION_KEY = "condition_key";		// ConditionKey	

	/**
	 * コンストラクタ
	 **/
	public LoLogSessionDataAccess() {
	}

	/**
	 * セッションLOログテーブルへ登録処理を行います
	 * @param objLoLogSession ログ情報データクラス
	 * @exception LOException LO独自例外
	 */
	public void insert( LoLogSessionRecord objLoLogSession )
		throws LOException
	{
		// データアクセスクラスをインスタンス化します
		DataAccess objDataAccess = new DataAccess(TABLE_NAME);
		try {
			// トランザクションを開始する
			objDataAccess.trans();

			insertAction( objLoLogSession, objDataAccess );

			// コミット処理
			objDataAccess.commit();
		}
		catch( SQLException e ) {
			e.printStackTrace();
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// ロールバック
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			// データベースエラーを設定
			throw new LOException( e.getMessage() );
		}
	}

	/**
	 * セッションLOログテーブルへの複数レコードの登録処理を行います<BR>
	 * @param objLoLogSession ログ情報データクラス
	 * @exception LOException LO独自例外
	 */
	public void insert( LoLogSessionRecord[] objLoLogSession )
		throws LOException
	{
		// データアクセスクラスをインスタンス化します
		DataAccess objDataAccess = new DataAccess(TABLE_NAME);
		try {
			// トランザクションを開始する
			objDataAccess.trans();

			// 登録処理を実行します(配列数文ループ)
			for( int i = 0; i < objLoLogSession.length; i++ ) {
				insertAction( objLoLogSession[i], objDataAccess );
			}

			// コミット処理
			objDataAccess.commit();
		}
		catch( SQLException e ) {
			e.printStackTrace();
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// ロールバック
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			// データベースエラーを設定
			throw new LOException( e.getMessage() );
		}
	}

	/**
	 * セッションLOログテーブルへの登録処理を行います<BR>
	 * トランザクションの管理は上位で行います。
	 * @param objLoLogSession ログ情報データクラス
	 * @exception SQLException DB操作に失敗した場合
	 */
	public void insert( LoLogSessionRecord objLoLogSession, DataAccess objDataAccess )
		throws SQLException
	{
		insertAction( objLoLogSession, objDataAccess );
	}

	/**
	 * セッションLOログテーブルへの複数レコードの登録処理を行います<BR>
	 * トランザクションの管理は上位で行います。
	 * @param objLoLogSession ログ情報データクラス
	 * @param objDataAccess データアクセスオブジェクト
	 * @exception SQLException DB操作に失敗した場合
	 */
	public void insert( LoLogSessionRecord[] objLoLogSession, DataAccess objDataAccess )
		throws SQLException
	{
		// 登録処理を実行します(配列数文ループ)
		for( int i = 0; i < objLoLogSession.length; i++ ) {
			insertAction( objLoLogSession[i], objDataAccess );
		}
	}

	/**
	 * セッションLOログテーブルへの登録処理を行います
	 * @param objLoLogSession ログ情報データクラス
	 * @exception SQLException DBエラー
	 */
	private void insertAction( LoLogSessionRecord objLoLogSession, DataAccess objDataAccess )
		throws SQLException
	{

		// DBに登録するデータをハッシュテーブルに格納します
		Hashtable htbData = setData( objLoLogSession );

		// 登録用SQLを生成します
		String strSQL = objDataAccess.getInsertSQL( htbData, TABLE_NAME );

		// 登録処理を実行
		objDataAccess.execute( strSQL );
	}

	/**
	 * LOログセッションテーブルを登録または更新します。<BR>
	 * トランザクションは上位が行います。
	 * @param LoLogSessionRecord 更新内容
	 * @param String ユーザID
	 * @param String LOID
	 * @param String 学習回数
	 * @exception SQLException DBエラー
	 */
	public void insertUpdate(	LoLogSessionRecord objLoLogSession,
								String strUserID,
								String strLoID,
								String strLunchtimes,
								DataAccess objDataAccess )
		throws SQLException
	{
		// 登録または更新用のHashtableを作成する
		Hashtable htbData = setData( objLoLogSession );

		// 登録更新を振り分けます
		if( getLoLog( strUserID, strLoID, strLunchtimes, objDataAccess ) == null ) {
			// 登録処理
			insertAction( htbData, objDataAccess );
		}
		else {
			updateAction( htbData, strUserID, strLoID, strLunchtimes, objDataAccess );
		}
	}

	/**
	 * ユーザIDとLOIDを指定して、検索を行います<BR>
	 * このメソッドを使用する際はトランザクションは上位で管理します。
	 * @param String ユーザID
	 * @param String LOID
	 * @param String 学習回数
	 * @param DataAccess データアクセスオブジェクト
	 * @return LoLogSessionRecord[] 検索結果 検索結果がない場合はnull
	 * @excetption SQLException DBエラー
	 */
	public LoLogSessionRecord getLoLog(String strUserID, String strLoID, String StudyCount, DataAccess objDataAccess)
		throws SQLException
	{
		if( strUserID == null && strLoID == null && StudyCount == null) {
			return null;
		}

		Hashtable htbParam = new Hashtable();
		htbParam.put( USERID, strUserID );
		htbParam.put( LOID, strLoID );
		htbParam.put( LUNCH_TIMES, StudyCount );

		Vector vecResult = selectAction( htbParam, objDataAccess );
		Vector vecLogList = (Vector)vecResult.get(0);
		if( vecLogList.size() > 0 ) {
			LoLogSessionRecord objRecord = (LoLogSessionRecord)vecLogList.get(0);
			return objRecord;
		}

		return null;
	}

	/**
	 * 検索処理実行メソッドです。<BR>
	 * パラメータのチェックおよびトランザクションの管理は
	 * 上位メソッド内で行ってください。<BR>
	 * @param htbParam 検索情報
	 * @param DataAccess データアクセスオブジェクト
	 * @return Vector 検索結果
	 * @exception SQLException DBエラーが発生した場合
	 */
	private Vector selectAction( Hashtable htParam, DataAccess objDataAccess )
		throws SQLException
	{

		// SQLの組み立て
		StringBuffer sbSQL = new StringBuffer();
		sbSQL.append( "SELECT * FROM " + TABLE_NAME );
		// 条件文の取得
		String strCondition = (String)htParam.get( CONDITION_KEY );

		if( strCondition != null ) {
			sbSQL.append( strCondition );
		}
		else {
			sbSQL.append( createCondition( htParam ) );
		}

		// クエリーを実行します
		ResultSet rs = objDataAccess.executeQuery(sbSQL.toString());

		Vector vecReturn = new Vector();
		Vector vecRet = new Vector();
		while(rs.next()) {
			String strFullScore = rs.getString( FULLSCORE );
			String strStudyStartDate = XMODate.parseTime(rs.getTimestamp( STUDY_START_DATE ));
			String strResidenceTime = rs.getString( RESIDANCETIME );
			String strPassDay = XMODate.parseTime(rs.getTimestamp( PASSDAY ));
			String strStudyEndDate = XMODate.parseTime(rs.getTimestamp( STUDY_END_DATE ));
			String strHighScore = rs.getString( HIGHTSCORE );
			String strLowScore = rs.getString( LOWSSCORE );
			String strExecisePoint = rs.getString( EXECISE_POINT );
			String strUserID = rs.getString( USERID );
			String strLOID = rs.getString( LOID );
			String strSessionID = rs.getString( SESSIONID );
			String strLunchTimes = rs.getString( LUNCH_TIMES );
			LoLogSessionRecord objData = new LoLogSessionRecord();
			objData.setFullScore( strFullScore );
			objData.setStudyStartDate( strStudyStartDate );
			objData.setResidanceTime( strResidenceTime );
			objData.setPassday( strPassDay );
			objData.setStudyEndDate( strStudyEndDate );
			objData.setHighScore( strHighScore );
			objData.setLowScore( strLowScore );
			objData.setExecisePoint( strExecisePoint );
			objData.setUserID( strUserID );
			objData.setLoID( strLOID );
			objData.setUserID( strSessionID );
			objData.setLoID( strLunchTimes );

			vecReturn.add( objData );
		}
		vecRet.add(vecReturn);
		return vecRet;
	}

	/**
	 * LOログセッションテーブルへの登録処理を行います
	 * @param htbData ログ情報データ
	 * @exception SQLException DBエラー
	 */
	private void insertAction( Hashtable htbData, DataAccess objDataAccess )
		throws SQLException
	{

		// 登録用SQLを生成します
		String strSQL = objDataAccess.getInsertSQL( htbData, TABLE_NAME );

		// 登録処理を実行
		objDataAccess.execute( strSQL );
	}

	/**
	 * LOログセッションテーブルへの更新処理を行います
	 * @param htbParam 更新情報
	 * @param strUserID ユーザID
	 * @param strLoID LOID
	 * @param strLunchtimes 学習回数
	 */
	public void updateAction(	Hashtable htbParam,
								String strUserID,
								String strLoID,
								String strLunchtimes,
								DataAccess objDataAccess )
		throws SQLException
	{
		String strCondition = createCondition( strUserID, strLoID, strLunchtimes );
		String strSQL = objDataAccess.getUpdateSQL( htbParam, TABLE_NAME );
		strSQL += strCondition;

		// 更新処理を実行
		objDataAccess.execute( strSQL );
	}

	/**
	 * UserIDとLOIDをキーにして、重複した行を取り除いたレコード数(これが学習回数になります)を返します。
	 * @param strUserID ユーザID
	 * @param strLoID LOID
	 * @return int 学習回数
	 * @exception SQLException 検索処理で例外が発生した場合
	 */
	public int getStudyCount( String strUserID, String strLoID )
		throws LOException
	{

		// 戻り値
		int intStudyCount = 0;

		// SQLの組み立て
		String strSQL = "SELECT COUNT(DISTINCT " + SESSIONID + ") as count FROM " + TABLE_NAME + " WHERE " +
						USERID + "='" + StringEscapeUtils.escapeSql(strUserID) + "' AND " + LOID + "='" + StringEscapeUtils.escapeSql(strLoID) + "'";

		// データアクセスクラスをインスタンス化します
		DataAccess objDataAccess = new DataAccess(TABLE_NAME);
		try {
			// トランザクションを開始する
			objDataAccess.trans();

			ResultSet rs = objDataAccess.executeQuery(strSQL);

			if( rs.next() ) {
				String strTemp = rs.getString( "count" );
				try {
					intStudyCount = new Integer( strTemp ).intValue();
				}
				catch( NumberFormatException ne ) {}
			}

			// コミット処理
			objDataAccess.commit();
		}
		catch( SQLException e ) {
			e.printStackTrace();
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// ロールバック
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			// データベースエラーを設定
			throw new LOException( e.getMessage() );
		}
		return intStudyCount;
	}

	/**
	 * UserIDとLOIDをキーにして、一番大きい最高点を取得します
	 * @param strUserID ユーザID
	 * @param strLoID LOID
	 * @param objDataAccess
	 * @return String highScore 一番大きい最高点 レコードが一件もないときはnullを返す
	 * @exception SQLException 検索処理で例外が発生した場合
	 */
	public String getMaxHighScore( String strUserID, String strLoID, DataAccess objDataAccess )
		throws SQLException
	{
		return getScoreCom( strUserID, strLoID, HIGHTSCORE, objDataAccess );
	}

	/**
	 * UserIDとLOIDをキーにして、一番小さい最低点を取得します
	 * @param strUserID ユーザID
	 * @param strLoID LOID
	 * @param objDataAccess
	 * @return String LowScore 一番小さい最低点 レコードが一件もないときはnullを返す
	 * @exception SQLException 検索処理で例外が発生した場合
	 */
	public String getMinLowScore( String strUserID, String strLoID, DataAccess objDataAccess )
		throws SQLException
	{
		return getScoreCom( strUserID, strLoID, LOWSSCORE, objDataAccess );
	}

	/**
	 * UserIDとLOIDをキーにして、一番大きい満点を取得します
	 * @param strUserID ユーザID
	 * @param strLoID LOID
	 * @param objDataAccess
	 * @return String fullscore 一番大きい満点 レコードが一件もないときはnullを返す
	 * @exception SQLException 検索処理で例外が発生した場合
	 */
	public String getMaxFullScore( String strUserID, String strLoID, DataAccess objDataAccess )
		throws SQLException
	{
		return getScoreCom( strUserID, strLoID, FULLSCORE, objDataAccess );
	}

	/**
	 * 内部関数
	 * 得点の取得メソッド共通
	 * @param strUserID ユーザID
	 * @param strLoID LOID
	 * @param strFieldName 取得フィールド名
	 * @param objDataAccess
	 * @return String Score 取得結果 レコードが一件もないときはnullを返す
	 * @exception SQLException 検索処理で例外が発生した場合
	 */
	private String getScoreCom( String strUserID, String strLoID, String strFieldName, DataAccess objDataAccess )
		throws SQLException
	{
		String strScore = null;
		String strSelect = null;
		if( HIGHTSCORE.equals( strFieldName ) ) {
			strSelect = "MAX(" + HIGHTSCORE + ")";
		}
		else if( LOWSSCORE.equals( strFieldName ) ) {
			strSelect = "MIN(" + LOWSSCORE + ")";
		}
		else if( FULLSCORE.equals( strFieldName ) ) {
			strSelect = "MAX(" + FULLSCORE + ")";
		}
		else {
			return null;
		}

		// SQLの組み立て
		StringBuffer strSQL = new StringBuffer();
		strSQL.append( "SELECT " );
		strSQL.append( strSelect  );
		strSQL.append( " as score FROM " );
		strSQL.append( TABLE_NAME );
		strSQL.append( " WHERE " );
		strSQL.append( USERID + "='" + StringEscapeUtils.escapeSql(strUserID) + "' " );
		strSQL.append( " AND " + LOID + "='" + StringEscapeUtils.escapeSql(strLoID) + "'" );

		ResultSet rs = objDataAccess.executeQuery(new String(strSQL));

		if( rs.next() ) {
			strScore = rs.getString( "score" );
		}

		return strScore;
	}

	/**
	 * LoLogSessionテーブルの最新レコードの教材完了日を取得します。
	 * @param String ユーザID
	 * @param String LOID
	 * @return String[] 教材開始日と教材完了日の配列
	 */
	public String[] getStudyDateList(String strUserID, String strLoID, DataAccess objDataAccess)
		throws SQLException
	{
		// 最新学習時間取得SQL文の組み立て
		StringBuffer strSQL = new StringBuffer();

		strSQL.append("SELECT MAX(study_start_date) AS maxstartdate FROM ");
		strSQL.append(TABLE_NAME);
		if(strUserID != null || strLoID != null)
		{
			strSQL.append(" WHERE ");
			if(strUserID != null)
			{
				strSQL.append(USERID + "='" + StringEscapeUtils.escapeSql(strUserID) + "' ");
			}
			if(strUserID != null && strLoID != null)
			{
				strSQL.append(" AND ");	
			}
			if(strLoID != null)
			{
				strSQL.append(LOID + "='" + StringEscapeUtils.escapeSql(strLoID) + "' ");
			}
		}

		// 結果格納用String
		String strMaxStartDate = "";
		String strMaxEndDate = "";

		ResultSet rs = objDataAccess.executeQuery(strSQL.toString());
		while(rs.next())
		{
			strMaxStartDate = XMODate.parseTime(rs.getTimestamp("maxstartdate"));
		}

		if(strMaxStartDate != null && !strMaxStartDate.equals(""))
		{
			// 最新学習終了レコード取得SQL文の組み立て
			StringBuffer strSQL2 = new StringBuffer();

			strSQL2.append("SELECT * FROM ");
			strSQL2.append(TABLE_NAME);
			strSQL2.append(" WHERE ");
			if(strUserID != null || strLoID != null)
			{
				if(strUserID != null)
				{
					strSQL2.append(USERID + "='" + StringEscapeUtils.escapeSql(strUserID) + "' AND ");
				}
				if(strLoID != null)
				{
					strSQL2.append(LOID + "='" + StringEscapeUtils.escapeSql(strLoID) + "' AND ");
				}
			}
			try{
				//XMS.iniファイルロードクラスのインスタンス
				Environment objEnv=new Environment();
				//SQLServerの場合
				if(objEnv.getDBType().equals( objEnv.DB_SQLSERVER )){
					strSQL2.append(STUDY_START_DATE + "='" + StringEscapeUtils.escapeSql(strMaxStartDate) + "' ");
				//Oracleの場合
				}else if(objEnv.getDBType().equals( objEnv.DB_ORACLE )){
					strSQL2.append(STUDY_START_DATE + "=TO_DATE('" + StringEscapeUtils.escapeSql(strMaxStartDate) + "','YYYY/MM/DD HH24:MI:SS')");
				//PostgreSQLの場合
				}else if(objEnv.getDBType().equals( objEnv.DB_POSTGRE )){
					strSQL2.append(STUDY_START_DATE + "=TO_TIMESTAMP('" + StringEscapeUtils.escapeSql(strMaxStartDate) + "','YYYY/MM/DD HH24:MI:SS')");
				}
			}
			catch(Exception ex)
			{

			}
			DebugLog.write( this.getClass(),strSQL2.toString(), DebugLog.ROW );
			ResultSet rs2 = objDataAccess.executeQuery(strSQL2.toString());
			while(rs2.next())
			{
				strMaxEndDate = rs2.getString(STUDY_END_DATE);
			}
		}

		String[] strResult = new String[2];
		strResult[0] = strMaxStartDate;
		strResult[1] = strMaxEndDate;
		return strResult;
	}

	/**
	 * LoLogSessionテーブルの検索処理を行います
	 * @param strUserID ユーザID
	 * @param strLoID LOID
	 * @return Vector 結果（LoLogSessionRecordを格納)
	 */
	public Vector getSessionLog( String strUserID, String strLoID )
		throws LOException
	{

		// SQL文の組み立て
		StringBuffer strSQL = new StringBuffer();

		strSQL.append( "SELECT * FROM " );
		strSQL.append( TABLE_NAME );
		if( strUserID != null || strLoID != null ) {
			strSQL.append( " WHERE " );
			if( strUserID != null ) {
				strSQL.append( USERID + "='" + StringEscapeUtils.escapeSql(strUserID) + "' " );
			}
			if(strUserID != null && strLoID != null)
			{
				strSQL.append( " AND " );
			}
			if( strLoID != null ) {
				strSQL.append( LOID + "='" + StringEscapeUtils.escapeSql(strLoID) + "' " );
			}
		}
		strSQL.append( " ORDER BY " + SESSIONID );
		strSQL.append( ", " + STUDY_START_DATE );
		strSQL.append( ", " + STUDY_END_DATE );

		DataAccess objDataAccess = new DataAccess(TABLE_NAME);
		// 結果格納用Vector
		Vector vecResult = new Vector();
		try {
			// トランザクションを開始する
			objDataAccess.trans();

			ResultSet rs = objDataAccess.executeQuery(strSQL.toString());

			while( rs.next() ) {
				LoLogSessionRecord objRecord = new LoLogSessionRecord();
				// セッションレコードにコピー
				objRecord.setFullScore( rs.getString( FULLSCORE ) );
				objRecord.setStudyStartDate( XMODate.parseTime( rs.getTimestamp( STUDY_START_DATE ) ) );
				objRecord.setResidanceTime( rs.getString( RESIDANCETIME ) );
				objRecord.setPassday( XMODate.parseTime( rs.getTimestamp( PASSDAY ) ) );
				objRecord.setStudyEndDate( XMODate.parseTime( rs.getTimestamp( STUDY_END_DATE ) ) );
				objRecord.setHighScore( rs.getString( HIGHTSCORE ) );
				objRecord.setLowScore( rs.getString( LOWSSCORE ) );
				objRecord.setExecisePoint( rs.getString( EXECISE_POINT ) );
				objRecord.setUserID( rs.getString( USERID ) );
				objRecord.setLoID( rs.getString( LOID ) );
				objRecord.setSessionID( rs.getString( SESSIONID ) );
				objRecord.setLunchTimes( rs.getString( LUNCH_TIMES ) );

				// 結果格納用Vectorに格納
				vecResult.add( objRecord );
			}

			// コミット処理
			objDataAccess.commit();
		}
		catch( SQLException e ) {
			e.printStackTrace();
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// ロールバック
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			// データベースエラーを設定
			throw new LOException( e.getMessage() );
		}

		return vecResult;

	}

	/**
	 * LoLogSessionテーブルの検索処理を行います
	 * @param strUserID ユーザIDリスト
	 * @param strLoID LoIDリスト
	 * @param strConditionKey Where句追加
	 * @return Vector 結果（LoLogSessionRecordを格納)
	 */
	public Vector getSessionLog(String[] strUserIDList,
								String[] strLoIDList,
								String strConditionKey)
		throws LOException
	{
		int i            = 0;
		String strAllSQL = "";
		int intLoIndex   = 0;
		Vector vecResult = new Vector();										// 結果格納用Vector

		DataAccess objDataAccess = new DataAccess(TABLE_NAME);
		try
		{
			// トランザクションを開始する
			objDataAccess.trans();
			while(intLoIndex < strLoIDList.length)
			{
				// Lo検索条件の組み立て
				StringBuffer strLoSQL = new StringBuffer();
				try
				{
					for(i = 0; i < 100; i++)
					{
						strLoSQL.append("'");
						strLoSQL.append(StringEscapeUtils.escapeSql(strLoIDList[intLoIndex++]));
						strLoSQL.append("'");
						strLoSQL.append(",");
					}
				}
				catch(ArrayIndexOutOfBoundsException ae)
				{
					// 最後の"'"を削除します
					strLoSQL.deleteCharAt(strLoSQL.length() - 1);
				}
				finally
				{
					// 最後の","を削除します
					strLoSQL.deleteCharAt(strLoSQL.length() - 1);
				}

				// User検索条件の組み立て
				int intUserIndex = 0;
				while(intUserIndex < strUserIDList.length)
				{
					StringBuffer strUserSQL = new StringBuffer();
					try
					{
						for(i = 0; i < 100; i++)
						{
							strUserSQL.append("'");
							strUserSQL.append(StringEscapeUtils.escapeSql(strUserIDList[intUserIndex++]));
							strUserSQL.append("'");
							strUserSQL.append(",");
						}
					}
					catch(ArrayIndexOutOfBoundsException ae)
					{
						// 最後の"'"を削除します
						strUserSQL.deleteCharAt(strUserSQL.length() - 1);
					}
					finally
					{
						// 最後の","を削除します
						strUserSQL.deleteCharAt(strUserSQL.length() - 1);
					}

					StringBuffer strSQL = new StringBuffer();
					strSQL.append("SELECT * FROM ");
					strSQL.append(TABLE_NAME);
					strSQL.append(" WHERE LOID in (");
					strSQL.append(strLoSQL);
					strSQL.append(") AND UserID in (");
					strSQL.append(strUserSQL);
					strSQL.append(")");
					if(strConditionKey != null)
					{
						strSQL.append(" AND " + strConditionKey);
					}
					strSQL.append( " ORDER BY " + SESSIONID );
					strSQL.append( ", " + STUDY_START_DATE );
					strSQL.append( ", " + STUDY_END_DATE );

					strAllSQL = strSQL.toString();
					ResultSet rs = objDataAccess.executeQuery(strAllSQL);
					while( rs.next() )
					{
						LoLogSessionRecord objRecord = new LoLogSessionRecord();
						// セッションレコードにコピー
						objRecord.setFullScore( rs.getString( FULLSCORE ) );
						objRecord.setStudyStartDate( XMODate.parseTime( rs.getTimestamp( STUDY_START_DATE ) ) );
						objRecord.setResidanceTime( rs.getString( RESIDANCETIME ) );
						objRecord.setPassday( XMODate.parseTime( rs.getTimestamp( PASSDAY ) ) );
						objRecord.setStudyEndDate( XMODate.parseTime( rs.getTimestamp( STUDY_END_DATE ) ) );
						objRecord.setHighScore( rs.getString( HIGHTSCORE ) );
						objRecord.setLowScore( rs.getString( LOWSSCORE ) );
						objRecord.setExecisePoint( rs.getString( EXECISE_POINT ) );
						objRecord.setUserID( rs.getString( USERID ) );
						objRecord.setLoID( rs.getString( LOID ) );
						objRecord.setSessionID( rs.getString( SESSIONID ) );
						objRecord.setLunchTimes( rs.getString( LUNCH_TIMES ) );
						// 結果格納用Vectorに格納
						vecResult.add( objRecord );
					}
				}
			}
			// コミット処理
			objDataAccess.commit();
		}
		catch( SQLException e )
		{
			e.printStackTrace();
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// ロールバック
			try
			{
				objDataAccess.rollback();
			}
			catch( Exception ex ) {}
			// データベースエラーを設定
			throw new LOException( e.getMessage() );
		}
		return vecResult;
	}

	/**
	 * 登録、更新処理時のデータを組み立てます
	 * @param htData
	 * @return Hashtable
	 */
	private Hashtable setData( Hashtable htbParam ) {
		Hashtable htbData = new Hashtable();
		putData( htbData, htbParam, FULLSCORE );
		putData( htbData, htbParam, STUDY_START_DATE );
		putData( htbData, htbParam, RESIDANCETIME );
		putData( htbData, htbParam, PASSDAY );
		putData( htbData, htbParam, STUDY_END_DATE );
		putData( htbData, htbParam, HIGHTSCORE );
		putData( htbData, htbParam, LOWSSCORE );
		putData( htbData, htbParam, EXECISE_POINT );
		putData( htbData, htbParam, USERID );
		putData( htbData, htbParam, LOID );
		putData( htbData, htbParam, SESSIONID );
		putData( htbData, htbParam, LUNCH_TIMES );
		return htbData;
	}

	/**
	 * 登録、更新処理時のデータをLoLogRecordから作成します
	 * @param objLoLogRecord
	 */
	private Hashtable setData( LoLogSessionRecord objRecord ) {
		Hashtable htbData = new Hashtable();
		putData( htbData, FULLSCORE, objRecord.getFullScore() );
		putData( htbData, STUDY_START_DATE, objRecord.getStudyStartDate() );
		putData( htbData, RESIDANCETIME, objRecord.getResidanceTime() );
		putData( htbData, PASSDAY, objRecord.getPassday() );
		putData( htbData, STUDY_END_DATE, objRecord.getStudyEndDate() );
		putData( htbData, HIGHTSCORE, objRecord.getHighScore() );
		putData( htbData, LOWSSCORE, objRecord.getLowScore() );
		putData( htbData, EXECISE_POINT, objRecord.getExecisePoint() );
		putData( htbData, USERID, objRecord.getUserID() );
		putData( htbData, LOID, objRecord.getLoID() );
		putData( htbData, SESSIONID, objRecord.getSessionID() );
		putData( htbData, LUNCH_TIMES, objRecord.getLunchTimes() );

		return htbData;
	}

	/**
	 * 安全にHashtableに追加するメソッドです
	 */
	private void putData( Hashtable htbData, Hashtable htbParam, String strKey ) {
		String strValue = (String)htbParam.get( strKey );
		if( strValue != null ) {
			htbData.put( strKey, strValue );
		}
	}

	/**
	 * 安全にHashtableに追加するメソッドです
	 */
	private void putData( Hashtable htbData, String strKey, String strValue ) {
		if( strKey == null || strValue == null ) {
			return;
		}

		if( !strValue.equals( "" ) ) {
			htbData.put( strKey, strValue );
		}
	}

	/**
	 * HashtableからユーザIDとLOIDを取得して条件文を作成します
	 */
	private String createCondition( Hashtable htbData ) {
		String strUserID = (String)htbData.get( USERID );
		String strLoID = (String)htbData.get( LOID );
		String strLunchtimes = (String)htbData.get( LUNCH_TIMES );
		return createCondition( strUserID, strLoID, strLunchtimes );
	}

	/**
	 * ユーザIDとLOIDから条件文を作成します
	 */
	private String createCondition( String strUserID, String strLoID, String strLunchtimes ) {

		String strUserIDCon = null;
		String strLoIDCon = null;
		String strLunchtimesCon = null;
		StringBuffer sbCondition = new StringBuffer();
		if( strUserID != null ) {
			strUserIDCon = USERID + " ='" + StringEscapeUtils.escapeSql(strUserID) + "'";
		}
		if( strLoID != null ) {
			strLoIDCon = LOID + " ='" + StringEscapeUtils.escapeSql(strLoID) + "'";
		}
		if( strLunchtimes != null ) {
			strLunchtimesCon = LUNCH_TIMES + " ='" + StringEscapeUtils.escapeSql(strLunchtimes) + "'";
		}

		if( strUserIDCon != null || strLoIDCon != null || strLunchtimesCon != null ) {
			sbCondition.append( " WHERE " );
			if( strUserIDCon != null ) {
				sbCondition.append( strUserIDCon );
				if( strLoIDCon != null ) {
					sbCondition.append( " AND " );
				}
			}
			if( strLoIDCon != null ) {
				sbCondition.append( strLoIDCon );
				if( strLunchtimesCon != null ) {
					sbCondition.append( " AND " );
				}
			}
			if( strLunchtimesCon != null ) {
				sbCondition.append( strLunchtimesCon );
			}
		}

		return sbCondition.toString();
	}

	/**
	 * ユーザIDとLOIDを指定してレコードを削除します。
	 * @param strUserID ユーザID
	 * @param strLoID LOID
	 * @exception SQLException
	 */
	public void delete( String strUserID, String strLoID, DataAccess objDataAccess )
		throws SQLException
	{
		StringBuffer sbSQL = new StringBuffer();
		sbSQL.append( "DELETE FROM " + TABLE_NAME );
		sbSQL.append( " WHERE " + USERID + "='" + StringEscapeUtils.escapeSql(strUserID) + "' AND " );
		sbSQL.append( LOID + "='" + StringEscapeUtils.escapeSql(strLoID) + "'" );

		objDataAccess.execute( new String( sbSQL ) );
	}

	/**
	 * LOIDを指定してレコードを削除します。
	 * 
	 * @param strLoID LOID
	 * @param objDataAccess
	 * @exception SQLException
	 */
	public void delete( String strLoID, DataAccess objDataAccess )
		throws SQLException {
		StringBuffer sbSQL = new StringBuffer();
		sbSQL.append( "DELETE FROM " + TABLE_NAME );
		sbSQL.append( " WHERE " + LOID + "='" + StringEscapeUtils.escapeSql(strLoID) + "'" );

		objDataAccess.execute( sbSQL.toString() );
	}

	/**
	 * 最新の得点を取得します。<BR>
	 * 最新の得点とは学習開始日がもっとも最近の得点です。
	 * @param strUserID
	 * @param strLoID
	 * @return String 最新の得点
	 */
	public String getNewestExcisePoint(String strUserID, String strLoID, DataAccess objDataAccess )
		throws SQLException
	{
		StringBuffer sbSQL = new StringBuffer();

		sbSQL.append( "SELECT " + EXECISE_POINT + " FROM " + TABLE_NAME + " WHERE " );
		sbSQL.append( LOID + "='" + StringEscapeUtils.escapeSql(strLoID) + "' AND " + USERID + "='" + StringEscapeUtils.escapeSql(strUserID) + "' AND " );
		sbSQL.append( STUDY_START_DATE + "=(SELECT MAX(" + STUDY_START_DATE + ") FROM " + TABLE_NAME );
		sbSQL.append( " WHERE " + USERID + "='" + StringEscapeUtils.escapeSql(strUserID) + "' AND " + LOID + "='" + StringEscapeUtils.escapeSql(strLoID) + "')");

		ResultSet rs = objDataAccess.executeQuery(new String(sbSQL) );

		String strExcisePoint = null;
		if( rs.next() ) {
			strExcisePoint = rs.getString(EXECISE_POINT);
		}

		return strExcisePoint;
	}

	/**
	 * 最初の合格日付を取得します。<BR>
	 * @param strUserID
	 * @param strLoID
	 * @return String 最新の得点
	 */
	public String getFirstPassDay(String strUserID, String strLoID, DataAccess objDataAccess )
		throws SQLException
	{
		StringBuffer sbSQL = new StringBuffer();

		sbSQL.append( "SELECT " + PASSDAY + " FROM " + TABLE_NAME + " WHERE " );
		sbSQL.append( LOID + "='" + StringEscapeUtils.escapeSql(strLoID) + "' AND " + USERID + "='" + StringEscapeUtils.escapeSql(strUserID) + "' AND " );
		sbSQL.append( PASSDAY + "=(SELECT MIN(" + PASSDAY + ") FROM " + TABLE_NAME + " WHERE " );
		sbSQL.append( USERID + "='" + StringEscapeUtils.escapeSql(strUserID) + "' AND " + LOID + "='" + StringEscapeUtils.escapeSql(strLoID) + "')");

		ResultSet rs = objDataAccess.executeQuery(new String(sbSQL) );

		String strPassDay = null;
		if( rs.next() ) {
			strPassDay = XMODate.parseTime( rs.getTimestamp( PASSDAY ) );
		}

		return strPassDay;
	}

	/**
	 * 最初の合格日付を取得します。<BR>
	 * @param strUserID
	 * @param strLoID
	 * @return String 最新の得点
	 */
	public String getFirstStudyEndDate(String strUserID, String strLoID, DataAccess objDataAccess )
		throws SQLException
	{
		StringBuffer sbSQL = new StringBuffer();

		sbSQL.append( "SELECT " + STUDY_END_DATE + " FROM " + TABLE_NAME + " WHERE " );
		sbSQL.append( LOID + "='" + StringEscapeUtils.escapeSql(strLoID) + "' AND " + USERID + "='" + StringEscapeUtils.escapeSql(strUserID) + "' AND " );
		sbSQL.append( STUDY_END_DATE + "=(SELECT MIN(" + STUDY_END_DATE + ") FROM " + TABLE_NAME + " WHERE " );
		sbSQL.append( USERID + "='" + StringEscapeUtils.escapeSql(strUserID) + "' AND " + LOID + "='" + StringEscapeUtils.escapeSql(strLoID) + "')");

		ResultSet rs = objDataAccess.executeQuery(new String(sbSQL) );

		String strStudyEndDate = null;
		if( rs.next() ) {
			strStudyEndDate = XMODate.parseTime( rs.getTimestamp( STUDY_END_DATE ) );
		}

		return strStudyEndDate;
	}

	/**
	 * 指定したユーザ、教材の組み合わせの総学習時間を求めます。<br>
	 * このメソッド内では、トランザクションに関する操作は行いません。<br>
	 *
	 * @param userID ユーザID。
	 * @param loID 教材のLOID。
	 * @param dataAccess データアクセス・オブジェクト。
	 * @return LoLogSessionテーブルより、指定したユーザ、教材の組み合わせに
	 *          該当するレコードの学習時間合計値を戻します。
	 *          該当するレコードがない場合、０を戻します。
	 * @throws LOException データベースアクセス例外が発生したとき。
	 */
	public static long getResidanceTime(
			String userID, String loID, DataAccess dataAccess)
			throws LOException {
		// このメソッドの戻り値（総学習時間数）
		long residanceTime = 0L;
		ResultSet rs = null;
		boolean successFlag = false;

		StringBuffer query = new StringBuffer();
		try {
			query.append( "SELECT SUM(" + RESIDANCETIME + ")" );
			query.append( " as totalResidance" );
			query.append( " FROM " + TABLE_NAME );
			query.append( " WHERE " + LOID + "='" + StringEscapeUtils.escapeSql(loID) + "'" );
			query.append( " AND " + USERID + "='" + StringEscapeUtils.escapeSql(userID) + "'" );
			// クエリー発行
			rs = dataAccess.executeQuery(query.toString());
			// レコードがあれば、取得。
			if ( rs.next() ) {
				residanceTime = rs.getLong( "totalResidance" );
			}
			successFlag = true;
		}
		catch (SQLException e) {
			DebugLog.write(LoLogSessionDataAccess.class, e, DebugLog.HIGHT);
			throw new LOException(e.getMessage());
		}
		finally {
			if (rs != null) {
				try {
					rs.close();
				}
				catch (SQLException e) {
					DebugLog.write(
						LoLogSessionDataAccess.class, e, DebugLog.HIGHT);
					if (successFlag) {
						throw new LOException(e.getMessage());
					}
				}
			}
		}
		return residanceTime;
	}

	/**
	 * 指定のユーザ・教材のの組合わせで
	 * 同じ起動回数のレコードが存在するか確認します。<br>
	 * @param userID ユーザID。
	 * @param loID 教材のLOID。
	 * @param loginSession 起動回数。
	 * @return レコードが存在すればtrue、存在しなければfalse。
	 * @throws LOException データベースアクセスに失敗した場合。
	 */
	public static boolean isExistLoginSession(
			String userID, String loID, String loginSession)
			throws LOException {
		boolean existFlag = false;
		ResultSet rs = null;
		StringBuffer query = new StringBuffer();
		boolean successFlag = false;
		DataAccess dataAccess = null;

		try {
			query.append( "SELECT " + SESSIONID );
			query.append( " FROM " + TABLE_NAME );
			query.append( " WHERE " + LOID + "='" + StringEscapeUtils.escapeSql(loID) + "'" );
			query.append( " AND " + USERID + "='" + StringEscapeUtils.escapeSql(userID) + "'" );
			query.append( " AND " + SESSIONID + "='" + StringEscapeUtils.escapeSql(loginSession) + "'" );
			// クエリー発行
			dataAccess = new DataAccess(TABLE_NAME);
			dataAccess.trans();
			rs = dataAccess.executeQuery(query.toString());
			// レコードがあれば、取得。
			existFlag = rs.next();

			dataAccess.commit();
			successFlag = true;
		}
		catch (SQLException e) {
			DebugLog.write(LoLogSessionDataAccess.class, e, DebugLog.HIGHT);
			try {
				dataAccess.rollback();
			}
			catch (SQLException e1) {
				DebugLog.write(
					LoLogSessionDataAccess.class, e1, DebugLog.HIGHT);
			}
			throw new LOException(e.getMessage());
		}
		finally {
			if (rs != null) {
				try {
					rs.close();
				}
				catch (SQLException e) {
					DebugLog.write(
						LoLogSessionDataAccess.class, e, DebugLog.HIGHT);
					if (successFlag) {
						throw new LOException(e.getMessage());
					}
				}
			}
		}
		return existFlag;
	}
}

