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

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

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

import java.io.File;
import java.net.URLEncoder;
import java.util.Date;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Hashtable;
import java.util.Map;

import jp.co.ntt.lms.lo.LOException;
import jp.co.ntt.lms.lo.LoLogDataAccess;
import jp.co.ntt.lms.lo.LoLogSessionDataAccess;
import jp.co.ntt.lms.lo.LoPropertyDef;
import jp.co.ntt.lms.xmo.DataAccess;
import jp.co.ntt.lms.xmo.Environment;
import jp.co.ntt.lms.xmo.Lo.LoClient;
import jp.co.ntt.lms.xmo.People.PeopleClient;
import jp.co.ntt.lms.xmo.util.DebugLog;

/**
 * SCORM LO 教材学習開始URL生成クラス。<br>
 * @author T.Nishiki
 */
public class ScormLoURLMaker {

	/**
	 * SCORM LOサーバを起動するためのURLを生成します。<br>
	 *
	 * @param params パラメータ。
	 * 以下の値が設定されていることを期待しています。<br>
	 * <table border="1">
	 * 	<tr>
	 * 		<th>キー</th>
	 * 		<th>値</th>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>ScormLoPropertyDef.LOID</td>
	 * 		<td>学習する教材のLOID</td>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>ScormLoPropertyDef.USERID</td>
	 * 		<td>学習するユーザID</td>
	 * 	</tr>
	 * </table><br>
	 * @param dataAccess データアクセスクラス。
	 * @return  SCORM LOサーバを起動するためのURL。
	 * @throws LOException 生成する際にデータベースアクセスや
	 *                      ファイルアクセスなどで失敗した場合。
	 */
	public String makeStartLearnURL(Hashtable params, DataAccess dataAccess)
		throws LOException {
		// メソッド開始ログ
		DebugLog.write(
			getClass(),
			"HEAD makeStartLearnURL("
				+ params + "," + dataAccess + ")",
			DebugLog.ROW);

		// このメソッドの戻り値。
		String startScormLoServerURL = null;

		try {
			ScormLoEnv scormEnv = new ScormLoEnv();
			Hashtable macroParams = new Hashtable();

			////////////////////////////////////////////////////////////////////
			// ユーザID、LOIDの取得
			String userID = (String)params.get(LoPropertyDef.USER);
			String loID = (String)params.get(LoPropertyDef.LOID);
			macroParams.put(ScormLoConstant.START_PARAM_KEY_USERID, userID);
			macroParams.put(ScormLoConstant.START_PARAM_KEY_LOID, loID);
			////////////////////////////////////////////////////////////////////
			// ユーザ名を取得します。
			putUserInfo(macroParams, userID);
			////////////////////////////////////////////////////////////////////
			// 教材の情報を取得、パラメータに格納
			putLoInfo(macroParams, loID);
			////////////////////////////////////////////////////////////////////
			// 前回学習セッション回数を取得
			int previousStudySession = 0;
			// ScormSessionテーブルから最終学習の学習セッション回数を取得する。
			previousStudySession =
				ScormSessionDataAccess.getLastStudySessionCount(
					userID,
					loID,
					dataAccess);
			////////////////////////////////////////////////////////////////////
			// 学習開始か再開かを判断する。
			String commandType = null;
//2005.08.11 MOD start NTTR-an 学習終了後のエンジン起動コマンド選択処理の追加
			String launchMode = null;
			launchMode = scormEnv.getProperty("launchmode");
//			commandType = getCommandType(userID, loID,
//				previousStudySession, dataAccess);
			commandType = getCommandType(userID, loID,
			previousStudySession, dataAccess, launchMode);
			// マクロパラメータとして設定
			macroParams.put(ScormLoConstant.START_PARAM_KEY_COMD, commandType);
			////////////////////////////////////////////////////////////////////
			// 今回分の学習セッション回数を確定する。
			// =================================================================
			String studySession = null;
			if (commandType.equals(ScormLoConstant.START_PARAM_COMD_NEW)) {
				studySession = Integer.toString(previousStudySession + 1);
			}
			else {
				studySession = Integer.toString(previousStudySession);
			}
			// マクロパラメータとして設定
			macroParams.put(
				ScormLoConstant.START_PARAM_KEY_STUDYSESSION,
				studySession);
			////////////////////////////////////////////////////////////////////
			// ログインセッション回数
			// =================================================================
			// ログインセッション回数を取得
			LoLogDataAccess loLogDataAccess = new LoLogDataAccess();
			int previousLoginSession = 0;
			String loginSession = null;
			previousLoginSession =
				loLogDataAccess.getStudyCount(userID, loID, dataAccess);
			// マクロパラメータとして設定
			// 今回分のログインセッション回数は、前回＋１
			loginSession = Integer.toString(previousLoginSession + 1);
			macroParams.put(
				ScormLoConstant.START_PARAM_KEY_LOGINSESSION,
				loginSession);
			////////////////////////////////////////////////////////////////////
			// SCORM LOサーバを選択します。
			ScormServerInfoControl control =
				ScormServerInfoControl.getInstance();
			ScormServerInfo serverInfo = null;
			serverInfo = control.getServerSelected(userID, loID);
			// マクロパラメータとして設定
			macroParams.put(
				ScormLoConstant.START_PARAM_KEY_SERVERNAME,
				serverInfo.getServerName());
			////////////////////////////////////////////////////////////////////
			// 認証キーを取得します。
			String authenticKey = null;
			Environment environment = new Environment();
			String hostName = environment.getServerName();
			authenticKey = ScormLoUtil.makeAuthenticKey(
					userID, loID, hostName);
			// マクロパラメータとして設定
			macroParams.put(
				ScormLoConstant.START_PARAM_KEY_AUTHKEY,
				authenticKey);
			////////////////////////////////////////////////////////////////////
			// 学習終了時に呼び出すサーブレットを取得
			String endLearnURL = null;
			endLearnURL = scormEnv.getEndLearnServletURL();
			// エンコード
			endLearnURL =
				URLEncoder.encode(endLearnURL, scormEnv.getCharsetUrlEncode());
			// マクロパラメータとして設定
			macroParams.put(
				ScormLoConstant.START_PARAM_KEY_END_URL, endLearnURL);
			////////////////////////////////////////////////////////////////////
			// 教材構造定義取得時に呼び出すサーブレットを取得
			String studyInfoURL = null;
			studyInfoURL = scormEnv.getStudyInfoURL();
			// エンコード
			studyInfoURL =
				URLEncoder.encode(studyInfoURL, scormEnv.getCharsetUrlEncode());
			// マクロパラメータとして設定
			macroParams.put(
				ScormLoConstant.START_PARAM_KEY_STUDYINFO_URL, studyInfoURL);
			////////////////////////////////////////////////////////////////////
			// 開始日時を取得します。
			String startDateTime = getStartDateTime();
			// マクロパラメータとして設定
			macroParams.put(
				ScormLoConstant.START_PARAM_KEY_START_DATETIME, startDateTime);
			////////////////////////////////////////////////////////////////////
			// SCORM LOサーバ起動URLを取得します
			startScormLoServerURL =
				scormEnv.getStartScormLoServerURL(macroParams);
		}
		catch (LOException e) {
			throw e;
		}
		catch (Exception e) {
			DebugLog.write(this.getClass(), e, DebugLog.HIGHT);
			throw new LOException(e.getMessage());
		}
		// メソッド終了ログ
		DebugLog.write(
			getClass(),
			"TAIL makeStartLearnURL("
				+ params + "," + dataAccess + ")"
				+ " return " + startScormLoServerURL,
			DebugLog.ROW);
		return startScormLoServerURL;
	}

	/**
	 * 学習開始か再開か判断します。
	 * @param userID ユーザID。
	 * @param loID LOID。
	 * @param studySession 学習回数。
	 * @param dataAccess データアクセスクラス・オブジェクト。
	 * @return 学習開始／再開のフラグ文字列。
	 *
	 * @throws LOException データベースやファイルアクセスに失敗した場合。
	 * @see ScormLoConstant#START_PARAM_COMD_NEW
	 * @see ScormLoConstant#START_PARAM_COMD_CONT
	 */
	private static String getCommandType(
//		String userID, String loID, int studySession, DataAccess dataAccess)
	    String userID, String loID, int studySession, DataAccess dataAccess, String launchMode)
		throws LOException {

		// メソッド開始ログ
		DebugLog.write(
			ScormLoURLMaker.class,
			"HEAD getCommandType("
				+ userID
				+ "," + loID
				+ "," + studySession
				+ "," + dataAccess
				+ "," + launchMode
				+ ")",
			DebugLog.ROW);

		// このメソッドの戻り値
		String commandType = null;
		try {
			////////////////////////////////////////////////////////////////////
			// １．LoLogSessionより、最終学習の学習開始日時／終了日時を取得する。
			// 　　レコードが存在しない->学習開始
			// 　　開始日時があって、終了日時がある->学習開始
			// 　　開始日時があって、終了日時がない->学習再開
			// ２．再開と判断した場合、中断情報ファイルを確認する。
			// 　　ファイルが存在しない場合は、学習開始と判断する。
			// =================================================================
			// LoLogSessionから最終開始日時を取得
			LoLogSessionDataAccess loLogSessionDataAccess =
				new LoLogSessionDataAccess();
			String[] lastStudyDates =
				loLogSessionDataAccess.getStudyDateList(
					userID,	loID, dataAccess);
			String lastStartDate = lastStudyDates[0];
			String lastEndDate = lastStudyDates[1];
			// 最終学習開始日時が存在しない＝レコードがない->学習開始
			if (lastStartDate == null || lastStartDate.equals("")) {
				commandType = ScormLoConstant.START_PARAM_COMD_NEW;
			}
			// 最終学習開始日時があって、最終学習開終了日時が存在しない->学習再開
			else if (lastEndDate == null || lastEndDate.equals("")) {
				commandType = ScormLoConstant.START_PARAM_COMD_CONT;
			}
			// 最終学習開始／終了日時がともに存在する->学習開始
			else {
//2005.08.11 ADD start NTTR-an 学習終了後のエンジン起動コマンド選択処理の追加
			    if( launchMode.equals(ScormLoConstant.START_PARAM_COMD_NEW)) {
			        commandType = ScormLoConstant.START_PARAM_COMD_NEW;
			    }
			    else{
			        commandType = ScormLoConstant.START_PARAM_COMD_CONT;
			    }
//2005.08.11 ADD end
			}
			// =================================================================
			// 再開の場合、中断情報ファイルの存在を確認する。
			if (commandType.equals(ScormLoConstant.START_PARAM_COMD_CONT)) {
				File resumeFile = null;
				resumeFile =
					ScormLoUtil.getResumeFile(userID, loID, studySession);
				if (resumeFile.isFile() == false) {
					commandType = ScormLoConstant.START_PARAM_COMD_NEW;
				}
			}
		}
		catch (SQLException e) {
			DebugLog.write(ScormLoURLMaker.class, e, DebugLog.HIGHT);
			throw new LOException(e.getMessage());
		}

		// メソッド終了ログ
		DebugLog.write(
			ScormLoURLMaker.class,
			"TAIL getCommandType("
				+ userID
				+ "," + loID
				+ "," + studySession
				+ "," + dataAccess
				+ "," + launchMode
				+ ")"
				+ "return " + commandType,
			DebugLog.ROW);
		return commandType;
	}

	/**
	 * ユーザ関連の情報を取得し、パラメータとして格納します。<br>
	 * @param macroParams 格納するパラメータ。
	 * @param userID ユーザ情報を取得するユーザID。
	 * @throws LOException 情報取得中に例外が発生した場合。
	 */
	private static void putUserInfo(Map macroParams, String userID)
			throws LOException {
		// メソッド開始ログ
		DebugLog.write(
			ScormLoURLMaker.class,
			"HEAD putUserInfo(" + macroParams + "," + userID + ")",
			DebugLog.ROW);

		try {
			PeopleClient people = null;
			people = new PeopleClient();
			people.setWhereUserID(userID);

			if (people.select() == false) {
				throw new LOException(people.getMessage());
			}
			if (people.next()) {
				ScormLoEnv scormEnv = new ScormLoEnv();
				String userName = people.getUserName();
				userName = URLEncoder.encode(
					userName, scormEnv.getCharsetUrlEncode());
				// マクロパラメータとして設定
				macroParams.put(
					ScormLoConstant.START_PARAM_KEY_STUDENT_NAME, userName);
			}
		}
		catch (LOException e) {
			throw e;
		}
		catch (Exception e) {
			DebugLog.write(ScormLoURLMaker.class, e, DebugLog.HIGHT);
			throw new LOException(e.getMessage());
		}
		// メソッド終了ログ
		DebugLog.write(
			ScormLoURLMaker.class,
			"TAIL putUserInfo(" + macroParams + "," + userID + ")",
			DebugLog.ROW);
	}

	/**
	 * ユーザ関連の情報を取得し、パラメータとして格納します。<br>
	 * @param macroParams 格納するパラメータ。
	 * このメソッド呼出後は以下の値が設定されます。<br>
	 * 	<tr>
	 * 		<th>キー</th>
	 * 		<th>値</th>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>ScormConstant.START_PARAM_KEY_FOREIGN_LOID</td>
	 * 		<td>学習する教材の外部ID</td>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>ScormConstant.START_PARAM_KEY_MANIFESTID</td>
	 * 		<td>学習する教材の教材ID</td>
	 * 	</tr>
	 * </table><br>
	 *
	 * @param loID 教材情報を取得するLOID。
	 * @throws LOException 情報取得中に例外が発生した場合。
	 */
	private static void putLoInfo(Map macroParams, String loID)
		throws LOException {
		// メソッド開始ログ
		DebugLog.write(
			ScormLoURLMaker.class,
			"HEAD putLoInfo(" + macroParams + "," + loID + ")",
			DebugLog.ROW);

		try {
			// 外部IDを取得
			LoClient client = new LoClient();
			client.setWhereLoID(loID);
			if (client.select() == false) {
				throw new LOException(client.getMessage());
			}
			if (client.next()) {
				String foreignID = client.getForeignID();
				macroParams.put(
					ScormLoConstant.START_PARAM_KEY_FOREIGN_LOID, foreignID);
			}
			// 教材IDを取得
			Hashtable condition = new Hashtable();
			condition.put(LoPropertyDef.LOID, loID);
			ScormLoDataAccess scormLoDataAccess = new ScormLoDataAccess();
			ScormLoData[] loData = scormLoDataAccess.getLoData(condition);
			if (loData.length == 0 ) {
				throw new LOException("Not Found Scorm Lo[" + loID + "]");
			}
			String materialID = loData[0].getMaterialID();
			macroParams.put(
				ScormLoConstant.START_PARAM_KEY_MANIFESTID, materialID);
		}
		catch (LOException e) {
			throw e;
		}
		catch (Exception e) {
			DebugLog.write(ScormLoURLMaker.class, e, DebugLog.HIGHT);
			throw new LOException(e.getMessage());
		}

		// メソッド終了ログ
		DebugLog.write(
			ScormLoURLMaker.class,
			"TAIL putLoInfo(" + macroParams + "," + loID + ")",
			DebugLog.ROW);
	}


	/**
	 * 学習開始日時を文字列として戻します。<br>
	 * 現在日時を取得して文字列に変換して戻します。<br>
	 *
	 * @return 学習開始日時を書式化した文字列（フォーマットは以下を参照）。
	 * @see ScormLoConstant#START_STUDY_DATETIME_FORMAT
	 */
	private static String getStartDateTime() {
		// このメソッドの戻り値
		String currentTime = null;
		// 現在日時を取得して変換
		SimpleDateFormat dateFormat = null;
		dateFormat = new SimpleDateFormat(
			ScormLoConstant.START_STUDY_DATETIME_FORMAT);
		currentTime = dateFormat.format(new Date());
		return currentTime;
	}
}
