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

//
//	IndividualLogUserProgressLogic
//	変更履歴
//		2004.02.01	新規作成
//

package jp.co.ntt.lms.xms.logsumup.scorm;

import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringEscapeUtils;

import jp.co.ntt.lms.xmo.DataAccess;
import jp.co.ntt.lms.xmo.Lo.LoClient;
import jp.co.ntt.lms.xmo.People.PeopleClient;
import jp.co.ntt.lms.xmo.XMOException;
import jp.co.ntt.lms.xms.framework.XmsException;
import jp.co.ntt.lms.xms.framework.XmsInnerException;
import jp.co.ntt.lms.xms.framework.XmsSystemException;
import jp.co.ntt.lms.xms.framework.base.Logic;
import jp.co.ntt.lms.xms.framework.base.LogicResult;
import jp.co.ntt.lms.xms.logsumup.scorm.ScormItemList;

/**
 * ログ集計グループ比較集計ロジック・クラス。<br>
 */
public class IndividualLogUserProgressLogic implements Logic {

    /**
     * リクエストされたユーザーID
     */
    private String UserID;
    /**
     * リクエストされたLOID
     */
    private String LOID;
    /**
     * リクエストされたLoType
     */
    private String LOType;
    /**
     * リクエストされた配下フラグ
     */
    private String Reflex;
	/**
	 * リクエストされた配下フラグ
	 */
	private String StudyCount;
	/**
	 * リクエストされたＡｕＩＤ
	 */
	private String UID;
    /**
     * セッションより取り出された教材構造
     */
    private ScormItemList CurrentScormNode;

    /**
     * 集計結果格納クラス
     */
    IndividualLogUserProgressResult result = new IndividualLogUserProgressResult();

    /**
     * コンストラクタ。<br>
     */
    public IndividualLogUserProgressLogic() {
    }

    /**
     * コンストラクタ。<br>
     * @param UserID 画面で選択したユーザID
     * @param LOID 画面で選択したLOID
     * @param LOType LOタイプ
     * @param Reflex 
     * @param StudyCount 学習回数
     * @param UID 画面で選択したノード
     * @param itemList 
     */
    public IndividualLogUserProgressLogic(
        String  UserID,
        String  LOID,
        String  LOType,
        String  Reflex,
        String  StudyCount,
        String	UID,
        ScormItemList itemList)
        throws XmsException {

        // パラメータチェック
        if (LOID.equals("")
            || UserID.equals("")
            || LOType.equals("")
            || itemList == null){
            throw new XmsInnerException("parameter is null.");
        }

        this.LOID = LOID;
        this.UserID = UserID;
        this.LOType = LOType;
        this.Reflex = Reflex;
        this.StudyCount = StudyCount;
        this.UID = UID;
        // 教材リストを作成し設定
        this.CurrentScormNode = itemList;
    }

    /**
     * 集計ロジック・メソッド。<br>
     * 個別ログメニュー画面より選択されたActivityID数回分、<br>、
     * 配下のログデータを取得し集計します。<br>
     * @param dataAccess DataAccessオブジェクト
     * @return LogicResult 集計結果
     * @exception XmsException
     * @see IndividualLogGroupProgressResult
     */
    public LogicResult doLogic(DataAccess dataAccess) throws XmsException {

        // パラメータチェック
        if (dataAccess == null) {
            throw new XmsInnerException("parameter is null.");
        }

        ResultSet rs = null;

        try {
            // ログ共通用Commonクラスの生成
            // LoLogCommon_inc cominc = new LoLogCommon_inc();

            // LO情報取得
            LoClient loclient = new LoClient();
            loclient.setWhereLoID(LOID);
            loclient.select();
            loclient.next();
			// リアルLOIDを取得し上書き設定する
			LOID = loclient.getRealLOID();
			// Resultへの情報設定
			// リアルＬＯＩＤを設定
			result.strLOID			= LOID;
			// ＬＯタイトル設定
			result.strLOName 		= loclient.getLoTytle();
			// 外部ＬＯＩＤ設定
			result.strForeignLOID	= loclient.getForeignID();
			// LoType設定
			result.LOType			= LOType;
			// UID設定
			result.strUID			= UID;
			// ユーザID設定
			result.strUserID 		= UserID;
			// ユーザ名称設定
			PeopleClient objPeople = new PeopleClient();
			objPeople.setWhereUserID( UserID );
			if( !objPeople.select() ) {
				throw new XMOException( objPeople.getMessage() );
			}
			if( objPeople.next() ) {
				result.strUserName = objPeople.getUserName();
			}
			// 取得学習回数を設定
			String MaxStudyCnt = "";
			// 最新学習回数を取得し設定する
			StringBuffer sbSQL = new StringBuffer();
			sbSQL.append("SELECT ");
			sbSQL.append(	"MAX(StudySessionCount) as MaxStudyCnt ");
			sbSQL.append("FROM ");
			sbSQL.append(	"scormsession ");
			sbSQL.append("WHERE ");
			sbSQL.append(	"userid ='" + StringEscapeUtils.escapeSql(UserID) + "'");
			sbSQL.append("AND ");
			sbSQL.append(	"loid ='" + StringEscapeUtils.escapeSql(LOID) + "'");
			rs = dataAccess.executeQuery(sbSQL.toString());
			// データベースから情報取得
			while (rs.next()) {
				MaxStudyCnt = rs.getString("MaxStudyCnt");
			}
			// 指定学習回数を設定
			if(StudyCount.equals("")){
				StudyCount = MaxStudyCnt;
			}
			// 最大学習回数を設定
			result.StudySessionCntMax = MaxStudyCnt;
			result.StudySessionCnt	  = StudyCount;
			
			// 教材リスト一覧の条件文を作成する
			String Condition_ActivityID = "";
			sbSQL = new StringBuffer();
			for (int j = 0; j < CurrentScormNode.getMaxRow(); j++) {
				String AuID = CurrentScormNode.getAuID(j);
				if(CurrentScormNode.getMaxRow() - 1 == j){
					// 最後のレコード
					sbSQL.append("'" + StringEscapeUtils.escapeSql(AuID) + "'");

				}else{
					// 最後のレコード
					sbSQL.append("'" + StringEscapeUtils.escapeSql(AuID) + "',");
				}

			}
			Condition_ActivityID = sbSQL.toString();
			// 個別リスト情報生成
			try {
				// SQL文生成
				sbSQL = new StringBuffer();
				sbSQL.append("SELECT ");
				sbSQL.append(	"RTRIM(A.ActivityID) as ActivityID, ");
				sbSQL.append(	"A.StudySessionCount as StudySessionCount, ");
				sbSQL.append(	"A.AccessCount as AccessCount, ");
				sbSQL.append(	"A.TotalTime as TotalTime, ");
				sbSQL.append(	"A.stStudyDate as stStudyDate, ");
				sbSQL.append(	"A.edStudyDate as edStudyDate, ");
				sbSQL.append(	"B.NewScaledScore as NewScaledScore, ");
				sbSQL.append(	"B.NewRawScore as NewRawScore, ");
				sbSQL.append(	"A.MaxScaledScore as MaxScaledScore, ");
				sbSQL.append(	"A.MaxRawScore as MaxRawScore, ");
				sbSQL.append(	"A.CompStNum as CompSt, ");
				sbSQL.append(	"A.SuccStNum as SuccSt ");
				sbSQL.append("FROM ");
				sbSQL.append(	"(SELECT ");
				sbSQL.append(		"A.userid as userid, ");
				sbSQL.append(		"A.loid as loid, ");
				sbSQL.append(		"A.ActivityID as activityID, ");
				sbSQL.append(		"A.StudySessionCount as StudySessionCount, ");
				sbSQL.append(		"count(*) as AccessCount, ");
				sbSQL.append(		"SUM(A.Attempt_Session_Time) as TotalTime, ");
				sbSQL.append(		"MIN(A.LearnSession_Date) as stStudyDate, ");
				sbSQL.append(		"MAX(A.LearnSession_Date) as edStudyDate, ");
				sbSQL.append(		"MAX(A.ScaledScore)	as MaxScaledScore, ");
				sbSQL.append(		"MAX(A.RawScore) as MaxRawScore, ");
				sbSQL.append(		"CASE SUM(CASE completion_status WHEN 'completed' THEN 1 ELSE 0 END) WHEN 0 THEN 0 ELSE 1 END as CompStNum, ");
				sbSQL.append(		"CASE SUM(CASE Success_status    WHEN 'passed'    THEN 1 ELSE 0 END) WHEN 0 THEN 0 ELSE 1 END as SuccStNum ");
				sbSQL.append(	"FROM ");
				sbSQL.append(		"scorm_attempt A ");
				sbSQL.append(	"WHERE ");
				sbSQL.append(		"loid = '" + StringEscapeUtils.escapeSql(LOID) + "' ");
				sbSQL.append(	"AND ");
				sbSQL.append(		"userid = '" + StringEscapeUtils.escapeSql(UserID) + "' ");
				sbSQL.append(	"AND ");
				sbSQL.append(		"studySessionCount = " + StringEscapeUtils.escapeSql(StudyCount) + " ");
				sbSQL.append(	"AND ");
				sbSQL.append(		"ActivityID IN (" + Condition_ActivityID + ") ");
				sbSQL.append(	"GROUP BY ");
				sbSQL.append(		"userid,loid,ActivityID,A.StudySessionCount ");
				sbSQL.append(	") A ");
				sbSQL.append("INNER JOIN ");
				sbSQL.append(	"(SELECT ");
				sbSQL.append(		"A.userid            	as userid, ");
				sbSQL.append(		"A.loid              	as loid, ");
				sbSQL.append(		"A.ActivityID        	as activityID, ");
				sbSQL.append(		"A.StudySessionCount 	as StudySessionCount, ");
				sbSQL.append(		"A.AttemptCount      	as AttemptCount, ");
				sbSQL.append(		"A.LearnSessionCount	as LearnSessionCount, ");
				sbSQL.append(		"A.ScaledScore			as NewScaledScore, ");
				sbSQL.append(		"A.RawScore				as NewRawScore ");
				sbSQL.append(	"FROM ");
				sbSQL.append(		"scorm_attempt A ");
				sbSQL.append(	"INNER JOIN ");
				sbSQL.append(		"(SELECT ");
				sbSQL.append(			"A.userid            as userid, ");
				sbSQL.append(			"A.loid              as loid, ");
				sbSQL.append(			"A.ActivityID        as activityID, ");
				sbSQL.append(			"A.StudySessionCount as StudySessionCount, ");
				sbSQL.append(			"A.AttemptCount      as AttemptCount, ");
				sbSQL.append(			"MAX(A.LearnSessionCount) as LearnSessionCount ");
				sbSQL.append(		"FROM ");
				sbSQL.append(			"scorm_attempt A ");
				sbSQL.append(		"INNER JOIN ");
				sbSQL.append(			"(SELECT ");
				sbSQL.append(				"A.userid            as userid, ");
				sbSQL.append(				"A.loid              as loid, ");
				sbSQL.append(				"A.ActivityID        as activityID, ");
				sbSQL.append(				"A.StudySessionCount as StudySessionCount, ");
				sbSQL.append(				"MAX(A.AttemptCount) as AttemptCount ");
				sbSQL.append(			"FROM ");
				sbSQL.append(				"scorm_attempt A ");
				sbSQL.append(			"WHERE ");
				sbSQL.append(				"loid = '" + StringEscapeUtils.escapeSql(LOID) + "' ");
				sbSQL.append(			"AND ");
				sbSQL.append(				"userid = '" + StringEscapeUtils.escapeSql(UserID) + "' ");
				sbSQL.append(			"AND ");
				sbSQL.append(				"studySessionCount = " + StringEscapeUtils.escapeSql(StudyCount) + " ");
				sbSQL.append(			"AND ");
				sbSQL.append(				"ActivityID IN (" + Condition_ActivityID + ") ");
				sbSQL.append(			"GROUP BY ");
				sbSQL.append(				"userid,loid,ActivityID,A.StudySessionCount ");
				sbSQL.append(			") B ");
				sbSQL.append(		"ON ");
				sbSQL.append(			"A.userid = B.userid ");
				sbSQL.append(		"AND ");
				sbSQL.append(			"A.loid = B.loid ");
				sbSQL.append(		"AND ");
				sbSQL.append(			"A.ActivityID = B.ActivityID ");
				sbSQL.append(		"AND ");
				sbSQL.append(			"A.StudySessionCount = B.StudySessionCount ");
				sbSQL.append(		"AND ");
				sbSQL.append(			"A.AttemptCount = B.AttemptCount ");
				sbSQL.append(		"GROUP BY ");
				sbSQL.append(			"A.userid,A.loid,A.activityid,A.StudySessionCount,A.AttemptCount ");
				sbSQL.append(		") B ");
				sbSQL.append(	"ON ");
				sbSQL.append(		"A.userid = B.userid ");
				sbSQL.append(	"AND ");
				sbSQL.append(		"A.loid = B.loid ");
				sbSQL.append(	"AND ");
				sbSQL.append(		"A.activityid = B.activityid ");
				sbSQL.append(	"AND ");
				sbSQL.append(		"A.StudySessionCount = B.StudySessionCount ");
				sbSQL.append(	"AND ");
				sbSQL.append(		"A.AttemptCount = B.AttemptCount ");
				sbSQL.append(	"AND ");
				sbSQL.append(		"A.LearnSessionCount = B.LearnSessionCount ");
				sbSQL.append(	") B ");
				sbSQL.append("ON ");
				sbSQL.append(	"A.userid = B.userid ");
				sbSQL.append("AND ");
				sbSQL.append(	"A.loid = B.loid ");
				sbSQL.append("AND ");
				sbSQL.append(	"A.activityid = B.activityid ");
				sbSQL.append("AND ");
				sbSQL.append(	"A.StudySessionCount = B.StudySessionCount ");
				// クエリーの実行
				rs = dataAccess.executeQuery(sbSQL.toString());
				// 取得したレコード数ループ
				List objDbList = new ArrayList();
				while (rs.next()) {
					// ユーザ別集計結果格納データクラス生成
					IndividualLogUserProgressStoreData user = new IndividualLogUserProgressStoreData();
					// ActivityID設定
					user.strActivityID = rs.getString("ActivityID");
					// 学習開始日設定
					user.datStartDate  = rs.getTimestamp("stStudyDate");
					// 最終アクセス日設定
					user.datEndDate = rs.getTimestamp("edStudyDate");
					// アクセス回数設定
					user.lngAccessCount = rs.getLong("AccessCount");
					// 累積滞在時間設定
					user.dwResidanceTime = rs.getDouble("TotalTime");
					// 正規化済み得点（最新）設定
					user.dwStoreScaledNewScore = rs.getDouble("NewScaledScore");
					// 得点（最新）設定
					user.dwStoreNewScore = rs.getDouble("NewRawScore");
					// 正規化済み得点（最高）設定
					user.dwStoreScaledMaxScore = rs.getDouble("MaxScaledScore");
					// 得点（最高）設定
					user.dwStoreMaxScore = rs.getDouble("MaxRawScore");
					// 完了ユニット設定
					if(rs.getInt("CompSt") == 1){
						user.blUnitComplete = true;
					}else{
						user.blUnitComplete = false;
					}
					// 合格ユニット設定
					if(rs.getInt("SuccSt") == 1){
						user.blUnitPass = true;
					}else{
						user.blUnitPass = false;
					}
					// 取得したレコードをセット
					objDbList.add(user);
				}
				ResultCreate(objDbList);
			} catch (Exception e) {
				throw new XmsSystemException(e);
			} finally {
				// 終期処理
				if (rs != null) {
					try {
						rs.close();
					} catch (Exception e) {
						throw new XmsSystemException(e);
					}
					rs = null;
				}
			}
		} catch (XmsException e) {
			throw e;
		} catch (Exception e) {
			throw new XmsSystemException(e);
		}
		return result;
	}

	/**
	 * 画面出力レコード返却・メソッド。<br>
	 * ＤＢから取得したレコードをユニット名称やユニット種別を付与した形でレコードを作成する
	 * @return List
	 * @exception XmsException
	 * @see IndividualLogGroupProgressResult
	 */
	private void ResultCreate(List lstDbData){
		// 画面出力用の教材構造リスト単位にてループ
		for(int i = 0 ; i < CurrentScormNode.getMaxRow() ; i++ ){
			IndividualLogUserProgressStoreData lstResulttmp = new IndividualLogUserProgressStoreData();
			// リスト種別を設定
			switch (CurrentScormNode.getAuType(i)){
				case ScormNodeConst.ASSET_NODE:
				case ScormNodeConst.SCO_NODE:
					lstResulttmp.iActivityType = 1;
					break;
				case ScormNodeConst.BLOCK_NODE:
				case ScormNodeConst.UNKNOWN_NODE:
					lstResulttmp.iActivityType = 0;
					break;
				default:
					lstResulttmp.iActivityType = 0;
					break;
			}
			// リスト種別によって設定内容を分岐
			if(lstResulttmp.iActivityType == 0){
				// クラスタの場合はユニット名のみ設定する
				lstResulttmp.strActivityName = CurrentScormNode.getAuTitle(i);	// ユニット名設定
				lstResulttmp.strActivityID = CurrentScormNode.getAuID(i);		// ActivityID設定
				result.addLog(lstResulttmp);									// リストへ設定
			}else if(lstResulttmp.iActivityType == 1){
				// リーフの場合はActivityIDにて一致するかを検索し一致したらデータを設定する
				lstResulttmp.strActivityName = CurrentScormNode.getAuTitle(i);	//	ユニット名設定
				lstResulttmp.strActivityID = CurrentScormNode.getAuID(i);		//	ActivityID設定
				for(int nCnt = 0;nCnt < lstDbData.size();nCnt++){
					IndividualLogUserProgressStoreData objDb 
						= (IndividualLogUserProgressStoreData)lstDbData.get(nCnt);	// ＤＢデータオブジェクトを取得
					if(lstResulttmp.strActivityID.equals(objDb.strActivityID)){
						// 検索結果が一致した場合はＤＢデータを設定
						if(objDb.datStartDate != null){
							lstResulttmp.datStartDate		= objDb.datStartDate;				// 学習開始日時
						}
						if(objDb.datEndDate != null){
							lstResulttmp.datEndDate			= objDb.datEndDate;					// 最終アクセス日時
						}
						lstResulttmp.lngAccessCount			= objDb.lngAccessCount;				// アクセス回数
						lstResulttmp.dwResidanceTime		= objDb.dwResidanceTime / 60;		// 累積滞在時間(分) 秒→分変換
						lstResulttmp.dwStoreScaledNewScore	= objDb.dwStoreScaledNewScore * 100;// 正規化済み得点（最新）パーセント変換
						lstResulttmp.dwStoreNewScore		= objDb.dwStoreNewScore;			// 得点（最新）
						lstResulttmp.dwStoreScaledMaxScore	= objDb.dwStoreScaledMaxScore * 100;// 正規化済み得点（最高）パーセント変換
						lstResulttmp.dwStoreMaxScore		= objDb.dwStoreMaxScore;			// 得点（最高）
						lstResulttmp.blUnitComplete			= objDb.blUnitComplete;				// 完了ユニットフラグ
						lstResulttmp.blUnitPass				= objDb.blUnitPass;					// 合格ユニットフラグ
						// 集計処理
						if(lstResulttmp.lngAccessCount > 0){
							// アクセス数（回）集計処理
							result.flAccessCountCnt = result.flAccessCountCnt + lstResulttmp.lngAccessCount;
						}
						if(lstResulttmp.dwResidanceTime > 0){
							// 累積滞在時間集計処理
							result.dwResidanceTimeCnt = result.dwResidanceTimeCnt + lstResulttmp.dwResidanceTime;
						}
						if(lstResulttmp.dwStoreScaledNewScore > 0){
							// 正規化済み得点（最新）集計処理
							result.dwStoreScaledNewScore	= result.dwStoreScaledNewScore + lstResulttmp.dwStoreScaledNewScore;
						}
						if(lstResulttmp.dwStoreNewScore > 0){
							// 得点（最新）集計処理
							result.dwStoreNewScore = result.dwStoreNewScore + lstResulttmp.dwStoreNewScore;
						}
						if(lstResulttmp.dwStoreScaledMaxScore > 0){
							// 正規化済み得点（最高）集計処理
							result.dwStoreScaledMaxScore = result.dwStoreScaledMaxScore + lstResulttmp.dwStoreScaledMaxScore;
						}
						if(lstResulttmp.dwStoreMaxScore > 0){
							// 得点（最高）集計処理
							result.dwStoreMaxScore = result.dwStoreMaxScore + lstResulttmp.dwStoreMaxScore;
						}
						if(lstResulttmp.blUnitComplete){
							result.flUnitComplete++;								// 合計完了ユニット数
						}
						if(lstResulttmp.blUnitPass){
							result.flUnitPass++;									// 合計完了ユニット数
						}
						result.flValidCnt++;										// 有効ＤＢレコード数
						break;
					}
				}
				result.flAUCount++;			// レコード数の合計
				result.addLog(lstResulttmp);	// リストへ設定
			}
		}
	}
}
