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

//
//	ScormLoEnv
//	変更履歴
//		2004.02.01	新規作成
//		2004.09.14	M004	A.Shimoma
//

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

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

import jp.co.ntt.lms.lo.LOException;
import jp.co.ntt.lms.lo.LoEnvironment;
import jp.co.ntt.lms.lo.LoPropertyDef;
import jp.co.ntt.lms.xmo.Environment;
import jp.co.ntt.lms.xmo.util.DebugLog;

/**
 * SCORM LOプロパティ取得クラス。
 * @author T.Nishiki
 */
public class ScormLoEnv extends LoEnvironment {

	/**
	 * 設定ファイルのパス。
	 */
	private static final String INI_FILE_PATH = "/conf/lo/scorm.ini";

	/**
	 * 設定ファイルのProperties変換後のオブジェクト。
	 */
	private static Properties mproperties = null;

	/**
	 * 「プロパティ：SCORM LOサーバ名称」のプレフィックス。<br>
	 * このプレフィックスと数字を連結した値がキー名称となる。
	 */
	public static final String SCORM_LO_SERVER_PREFIX = "scorm_name_";

	/**
	 * 「プロパティ：SCORM LOサーバ名称」として設定できるキーの最大数。<br>
	 */
	private static final int SCORM_LO_SERVER_MAX = 99;

	/**
	 * プロパティキー：認証キー算出する際の分単位。
	 */
	private static final String AUTHENTIC_MINUTE_SPAN
		= "authentic_minute_span";

//ADD START 20041210 NTTR
	/**
	 * 「プロパティキー：sceのインストールフォルダ」のプレフィックス。<br>
	 */
	private static final String SCE_DIR = "sce_dir";
//ADD END

	/**
	 * プロパティキー：登録済み教材構造定義ファイルがあるディレクトリパス。
	 */
	private static final String MATERIAL_PATH = "material_path";

	/**
	 * プロパティキー：未登録の教材構造定義ファイルがあるディレクトリパス。
	 */
	private static final String MATERIAL_TEMP = "material_temp";

	/**
	 * プロパティキー：中断情報ファイルがあるディレクトリパス。
	 */
	private static final String RESUME_DIR_PATH = "resume_path";
	/**
	 * プロパティキー：トレース情報ファイルがあるディレクトリパス。
	 */
	private static final String TRACE_DIR_PATH = "trace_path";

	/**
	 * プロパティキー：登録メニューURLパス。
	 */
	private static final String MENU_URL_LO_INSERT = "insert_menu_url";

	/**
	 * プロパティキー：更新メニューURLパス。
	 */
	private static final String MENU_URL_LO_UPDATE = "update_menu_url";

	/**
	 * プロパティキー：削除メニューURLパス。
	 */
	private static final String MENU_URL_LO_DELETE = "delete_menu_url";

	/**
	 * プロパティキー：共通ログメニューURLパス。
	 */
	private static final String MENU_URL_LO_LOG = "lo_log_menu_url";

	/**
	 * プロパティキー：個別ログメニューURLパス。
	 */
	private static final String MENU_URL_INDIVIDUAL_LOG =
		"individual_log_menu_url";

	/**
	 * プロパティキー：SCORM LOサーバ起動URL。
	 */
	private static final String START_SCORM_LO_SERVER_URL =
		"start_scorm_lo_server_url";

	/**
	 * プロパティキー：教材構造定義・中断情報取得用URL。
	 */ 
	private static final String STUDY_INFO_URL = "study_info_url";

	/**
	 * プロパティキー：URLエンコード。
	 */
	private static final String CHARSET_URL_ENCODE = "charset_url_encode";

	/**
	 * プロパティキー：学習情報レスポンス・エンコード。
	 */
	public static final String CHARSET_RESPONSE_STUDY_INFO
		= "charset_response_studyinfo";

	/**
	 * プロパティキー：学習終了レスポンス・エンコード。
	 */
	public static final String CHARSET_RESPONSE_END_LEARN
		= "charset_response_endlearn";

	/**
	 * プロパティキー：中断情報ファイル・エンコード。
	 */
	public static final String CHARSET_RESUME_FILE = "charset_resume_file";

	/**
	 * プロパティキー：トレースログ情報ファイル・エンコード。
	 */
	public static final String CHARSET_TRACE_FILE = "charset_trace_file";

	/**
	 * プロパティキー：ユーザ個別ログ・メニューラベル名称のプレフィックス。
	 */
	private static final String USER_INDIVIDUAL_LOG_MENU_LABEL_PREFIX
		= "individual_log_user_menu_label_";

	/**
	 * プロパティキー：ユーザ個別ログ・メニュー遷移先のプレフィックス。
	 */
	private static final String USER_INDIVIDUAL_LOG_MENU_URL_PREFIX
		= "individual_log_user_menu_url_";

	/**
	 * プロパティキー：グループ個別ログ・メニューラベル名称のプレフィックス。
	 */
	private static final String GROUP_INDIVIDUAL_LOG_MENU_LABEL_PREFIX
		= "individual_log_group_menu_label_";

	/**
	 * プロパティキー：グループ個別ログ・メニュー遷移先のプレフィックス。
	 */
	private static final String GROUP_INDIVIDUAL_LOG_MENU_URL_PREFIX
		= "individual_log_group_menu_url_";

	/**
	 * パラメータマクロキー：ユーザID。
	 */
	private static final String URL_PARAM_USERID = "USERID";

	/**
	 * パラメータマクロキー：LOID。
	 */
	private static final String URL_PARAM_LOID = "LOID";

	/**
	 * パラメータマクロキー：AUID。
	 */
	private static final String URL_PARAM_LOTYPE = "LOTYPE";

	/**
	 * パラメータマクロキー：戻りURL。
	 */
	private static final String URL_PARAM_RETURN_URL = "RETURN_URL";

	/**
	 * パラメータマクロキー：所属グループID。
	 */
	private static final String URL_PARAM_BELONGING_GROUP_ID =
		"BELONGING_GROUP_ID";

//@2004.06.28 ADD NTTR SCORM-CP一時配置先フォルダ
	/**
	 * パラメータマクロキー：CP-ftpフォルダ
	 */
	private static final String MATERIAL_FTP = "material_ftp";
//ADD END

//  ADD 2005/02/15 START SUGAWARA [scorm取り込み]
	/**
	 * パラメータマクロキー：LOM取り込みファイル。
	 */
	private static final String LOM_ENTRY_FILE = "LOM_ENTRY_FILE";
//  ADD 2005/02/15 END SUGAWARA

// 2004.09.14 M004 ADD start NTTR(N)

	/**
	 * メニュー用文字列:進捗状況一覧
	 */
	public static final String PROGRESSSTATUS  = "進捗状況一覧";
	/**
	 * メニュー用文字列:演習回答状況
	 */
	public static final String REPLYSTATUS     = "演習回答状況";
	/**
	 * メニュー用文字列:演習成績分析
	 */
	public static final String RESULT_ANALYSIS = "演習成績分析";
	/**
	 * メニュー用文字列:CSV出力
	 */
	public static final String CSV_OUTPUT      = "CSV出力";

// 2004.09.14 M004 ADD end

// 2005.08.11 ADD start NTTR-an 学習終了後のエンジン起動コマンド選択処理の追加
	public static final String LAUNCH_MODE = "launchmode";
//	 2005.08.11 ADD end
	
	/**
	 * コンストラクタです。
	 * @throws LOException 環境ファイルの読込に失敗した場合。
	 */
	public ScormLoEnv() throws LOException {
		super();

		// メソッド開始ログ
		DebugLog.write(ScormLoEnv.class, "HEAD ScormLoEnv()", DebugLog.ROW);

		synchronized (this.getClass()) {
			//	環境情報の初期化が行われていない時のみ
			//	環境ファイルを読み込む
			if (mproperties == null) {
				mproperties = loadProperty(INI_FILE_PATH);
			}
		}

		// メソッド終了ログ
		DebugLog.write(ScormLoEnv.class, "TAIL ScormLoEnv()", DebugLog.ROW);
	}

	/**
	 * 登録済みの教材構造定義ファイルを格納するディレクトリ・パスを戻します。
	 *
	 * @return 登録済みの教材構造定義ファイルを格納するディレクトリ・パス。
	 * @throws LOException 取得に失敗した場合。
	 */
	public final String getMaterialPath() throws LOException {
		// メソッド開始ログ
		DebugLog.write(this.getClass(), "HEAD getMaterialPath()", DebugLog.ROW);

		String materialPath = getPathUnderSystemDir(MATERIAL_PATH);

		// メソッド終了ログ
		DebugLog.write(
			this.getClass(),
			"TAIL getMaterialPath()" + " return " + materialPath,
			DebugLog.ROW);
		return materialPath;
	}

	/**
	 * 未登録の教材構造定義ファイルを格納するディレクトリ・パスを戻します。
	 *
	 * @return 未登録の教材構造定義ファイルディレクトリ・パス。
	 * @throws LOException 取得に失敗した場合。
	 */
	public final String getTempMaterialPath() throws LOException {
		// メソッド開始ログ
		DebugLog.write(
			this.getClass(),
			"HEAD getTempMaterialPath()",
			DebugLog.ROW);

		String tempPath = getPathUnderSystemDir(MATERIAL_TEMP);

		// メソッド終了ログ
		DebugLog.write(
			this.getClass(),
			"TAIL getTempMaterialPath()" + " return " + tempPath,
			DebugLog.ROW);
		return tempPath;
	}

//@2004.06.28 ADD NTTR CP一時配置先フォルダ(ftp)パスの返却
	/**
	 * CP一時配置先(ZIP圧縮形式CPファイル)の格納先ディレクトリ・パスを戻します。
	 *
	 * @return CP一時配置先ディレクトリ・パス。
	 * @throws LOException 取得に失敗した場合。
	 */
	public final String getFtpMaterialPath() throws LOException {
		// メソッド開始ログ
		DebugLog.write(
			this.getClass(),
			"HEAD getFtpMaterialPath()",
			DebugLog.ROW);

		String ftpPath = getPathUnderSystemDir(MATERIAL_FTP);

		// メソッド終了ログ
		DebugLog.write(
			this.getClass(),
			"TAIL getFtpMaterialPath()" + " return " + ftpPath,
			DebugLog.ROW);
		return ftpPath;
	}
// ADD END



//ADD START 20041210 NTTR SCORMエンジンインストールパス返却
	/**
	 * SCORMエンジンインストールディレクトリ・パスを戻します。
	 *
	 * @return 未登録の教材構造定義ファイルディレクトリ・パス。
	 * @throws LOException 取得に失敗した場合。
	 */
	public final String getScePath() throws LOException {
		// メソッド開始ログ
		DebugLog.write(
			this.getClass(),
			"HEAD getScePath()",
			DebugLog.ROW);

		String scedir = getPathUnderSystemDir(SCE_DIR);

		// メソッド終了ログ
		DebugLog.write(
			this.getClass(),
			"TAIL getScePath()" + " return " + scedir,
			DebugLog.ROW);
		return scedir;
	}
//ADD END





	/**
	 * 中断情報ファイルを格納するルート・ディレクトリ・パスを取得します。<br>
	 * @return 中断情報ファイルを格納するルート・ディレクトリ・パス。
	 * @throws LOException 取得に失敗した場合。
	 */
	public final String getResumeDirPath() throws LOException {
		// メソッド開始ログ
		DebugLog.write(
			this.getClass(),
			"HEAD getResumeDirPath()",
			DebugLog.ROW);

		String resumeDirPath = getPathUnderSystemDir(RESUME_DIR_PATH);
		// メソッド終了ログ
		DebugLog.write(
			this.getClass(),
			"TAIL getResumeDirPath() return " + resumeDirPath,
			DebugLog.ROW);

		return resumeDirPath;
	}

	/**
	 * トレース情報ファイルを格納するルート・ディレクトリ・パスを取得します。<br>
	 * @return トレース情報ファイルを格納するルート・ディレクトリ・パス。
	 * @throws LOException 取得に失敗した場合。
	 */
	public final String getTraceDirPath() throws LOException {
		// メソッド開始ログ
		DebugLog.write(this.getClass(), "HEAD getTraceDirPath()", DebugLog.ROW);

		String traceDirPath = getPathUnderSystemDir(TRACE_DIR_PATH);

		// メソッド終了ログ
		DebugLog.write(
			this.getClass(),
			"TAIL getTraceDirPath() return " + traceDirPath,
			DebugLog.ROW);
		return traceDirPath;
	}

	/**
	 * 評価ウィンドウオープンフラグを取得します。
	 *
	 * @return 設定ファイルに指定されているフラグ値。
	 * @throws LOException 取得に失敗した場合。
	 */
	public final String getEstimation() throws LOException {
		return getProperty(ESTIMATION, mproperties);
	}

	/**
	 * LO登録メニュー項目で使用するURLを取得します。
	 * @param params パラメータ（未使用）。
	 * @return 登録メニューURL文字列。
	 * @throws LOException 取得に失敗した場合。
	 */
	public final String getInsertMenuURL(Hashtable params)
			throws LOException {
		return getPathUnderSystemURL(MENU_URL_LO_INSERT);
	}

	/**
	 * LO更新メニュー項目で使用するURLを取得します。
	 * @param params パラメータ（未使用）。
	 * @return 更新メニューURL文字列。
	 * @throws LOException 取得に失敗した場合。
	 */
	public String getUpdateMenuURL(Hashtable params) throws LOException {
		return getPathUnderSystemURL(MENU_URL_LO_UPDATE);
	}

	/**
	 * LO削除メニュー項目で使用するURLを取得します。
	 * @param params パラメータ（未使用）。
	 * @return 削除メニューURL文字列。
	 * @throws LOException 取得に失敗した場合。
	 */
	public String getDeleteMenuURL(Hashtable params) throws LOException {
		return getPathUnderSystemURL(MENU_URL_LO_DELETE);
	}

	/**
	 * 個別ログメニュー項目で使用するURLを取得します。
	 * @param params パラメータ。<br>
	 * 以下の値が設定されていることを期待しています。<br>
	 * <table border="1">
	 * 	<tr>
	 * 		<th>キー</th>
	 * 		<th>値</th>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>LoPropertyDef.TARGET_ID</td>
	 * 		<td>ログ参照対象のユーザID</td>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>LoPropertyDef.LOID</td>
	 * 		<td>ログ参照対象のLOID</td>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>LoPropertyDef.RETURN_URL</td>
	 * 		<td>戻りURL</td>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>LoPropertyDef.AUID</td>
	 * 		<td>ログ参照するAUID</td>
	 * 	</tr>
	 * </table><br>
	 * @return 個別ログメニューURL文字列。
	 * @throws LOException 取得に失敗した場合。
	 * @see LoPropertyDef
	 */
	public String getIndividualLogMenuURL(Hashtable params)
		throws LOException {
		////////////////////////////////////////////////////////////////////////
		// メソッド開始ログ
		DebugLog.write(
			this.getClass(),
			"HEAD getIndividualLogMenuURL(" + params + ")",
			DebugLog.ROW);
		String individualLogPath = null;

		////////////////////////////////////////////////////////////////////////
		// マクロ展開用にパラメータ値を取得・格納
		Hashtable macro = new Hashtable();
		// =====================================================================
		// ユーザID
		String userID = (String)params.get(LoPropertyDef.TARGET_ID);
		if (userID == null) {
			userID = "";
		}
		macro.put(URL_PARAM_USERID, userID);
		// LOID
		String loID = (String)params.get(LoPropertyDef.LOID);
		if (loID == null) {
			loID = "";
		}
		macro.put(URL_PARAM_LOID, loID);
		// LO種別
		String loType = (String)params.get(LoPropertyDef.LO_TYPE);
		if (loType == null) {
			loType = "";
		}
		macro.put(URL_PARAM_LOTYPE, loType);
		////////////////////////////////////////////////////////////////////////
		// パスの生成
		individualLogPath
			= getPathUnderSystemURL(MENU_URL_INDIVIDUAL_LOG, macro);
		////////////////////////////////////////////////////////////////////////
		// メソッド終了ログ
		DebugLog.write(
			this.getClass(),
			"TAIL getIndividualLogMenuURL("
				+ params
				+ ")"
				+ " return "
				+ individualLogPath,
			DebugLog.ROW);
		return individualLogPath;
	}

	/**
	 * 共通ログメニュー項目で使用するURLを取得します。
	 * @param params パラメータ。<br>
	 * 以下の値が設定されていることを期待しています。<br>
	 * <table border="1">
	 * 	<tr>
	 * 		<th>キー</th>
	 * 		<th>値</th>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>LoPropertyDef.TARGET_ID</td>
	 * 		<td>ログ参照対象のユーザID</td>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>LoPropertyDef.LOID</td>
	 * 		<td>ログ参照対象のLOID</td>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>LoPropertyDef.RETURN_URL</td>
	 * 		<td>戻りURL</td>
	 * 	</tr>
	 * 	<tr>
	 * 		<td>LoPropertyDef.TARGET_PARENT_ID</td>
	 * 		<td>ログ参照対象のユーザの所属グループID</td>
	 * 	</tr>
	 * </table><br>
	 * @return 共通ログメニューURL文字列。
	 * @throws LOException 取得に失敗した場合。
	 * @see LoPropertyDef
	 */
	public String getLoLogURL(Hashtable params) throws LOException {
		////////////////////////////////////////////////////////////////////////
		// メソッド開始ログ
		DebugLog.write(
			this.getClass(),
			"HEAD getLoLogURL(" + params + ")",
			DebugLog.ROW);
		////////////////////////////////////////////////////////////////////////
		// マクロ展開用にパラメータ値を取得・格納
		Hashtable macro = new Hashtable();
		// =====================================================================
		// ユーザID
		String userID = (String) params.get(LoPropertyDef.TARGET_ID);
		if (userID == null) {
			userID = "";
		}
		macro.put(URL_PARAM_USERID, userID);
		// LOID
		String loID = (String) params.get(LoPropertyDef.LOID);
		if (loID == null) {
			loID = "";
		}
		macro.put(URL_PARAM_LOID, loID);
		// 戻りURL
		String returnURL = (String) params.get(LoPropertyDef.RETURN_URL);
		if (returnURL == null) {
			returnURL = "";
		}
		macro.put(URL_PARAM_RETURN_URL, returnURL);
		// グループID
		String groupID = (String) params.get(LoPropertyDef.TARGET_PARENT_ID);
		if (groupID == null) {
			groupID = "";
		}
		macro.put(URL_PARAM_BELONGING_GROUP_ID, groupID);
		// LO種別
		String loType = (String)params.get(LoPropertyDef.LO_TYPE);
		if (loType == null) {
			loType = "";
		}
		macro.put(URL_PARAM_LOTYPE, loType);
		////////////////////////////////////////////////////////////////////////
		// パスの生成
		String logPath = getPathUnderSystemURL(MENU_URL_LO_LOG, macro);
		////////////////////////////////////////////////////////////////////////
		// メソッド終了ログ
		DebugLog.write(
			this.getClass(),
			"TAIL getLoLogURL(" + params + ")" + " return " + logPath,
			DebugLog.ROW);
		return logPath;
	}

	/**
	 * 学習画面のウィンドウサイズ(縦)を取得します。
	 *
	 * @return 学習画面のウィンドウサイズ(縦)。
	 * @throws LOException 取得に失敗した場合。
	 */
	public String getWinHeight() throws LOException {
		return getProperty(WIN_HEIGHT, mproperties);
	}

	/**
	 * 学習画面のウィンドウサイズ(横)を取得します。
	 *
	 * @return 学習画面のウィンドウサイズ(横)。
	 * @throws LOException 取得に失敗した場合。
	 */
	public String getWinWidth() throws LOException {
		return getProperty(WIN_WIDTH, mproperties);
	}

	/**
	 * SCORM LOサーバ起動用URLを取得します。<br>
	 *
	 * @param params 生成時に埋め込むパラメータ。
	 * @return SCORM LOサーバより呼び出されるURL。
	 * @throws LOException 取得に失敗した場合。
	 * @see ScormLoConstant
	 */
	public String getStartScormLoServerURL(Hashtable params)
		throws LOException {
		// メソッド開始ログ
		DebugLog.write(
			this.getClass(),
			"HEAD getStartScormLoServerURL(" + params + ")",
			DebugLog.ROW);

		String strURL = null;
		strURL = getProperty(START_SCORM_LO_SERVER_URL, mproperties);
		strURL = expand(strURL, params);

		// メソッド終了ログ
		DebugLog.write(
			this.getClass(),
			"TAIL getStartScormLoServerURL("
				+ params
				+ ")"
				+ " return "
				+ strURL,
			DebugLog.ROW);

		return strURL;
	}

	/**
	 * 教材構造定義・中断情報の取得用URLを取得します。<br>
	 * 学習開始時にSCORM LOサーバより教材構造定義・中断情報を
	 * 取得するために呼び出されるURLを取得します。<br>
	 *
	 * @return SCORM LOサーバより呼び出されるURL。
	 * @throws LOException 取得に失敗した場合。
	 */
	public String getStudyInfoURL() throws LOException {
		// メソッド開始ログ
		DebugLog.write(this.getClass(), "HEAD getStudyInfoURL()", DebugLog.ROW);

		String strURL = getPathUnderSystemURL(STUDY_INFO_URL);
		// メソッド終了ログ
		DebugLog.write(
			this.getClass(),
			"TAIL getStudyInfoURL()" + " return " + strURL,
			DebugLog.ROW);

		return strURL;
	}

	/**
	 * 学習終了時のSCORM LOサーバより呼び出されるURLを取得します。<br>
	 * @return SCORM LOサーバより呼び出されるURL。
	 * @throws LOException 取得に失敗した場合。
	 * @see jp.co.ntt.lms.lo.LoEnvironment#getEndLearnServletURL()
	 */
	public String getEndLearnServletURL() throws LOException {
		// メソッド開始ログ
		DebugLog.write(
			this.getClass(),
			"HEAD getEndLearnServletURL()",
			DebugLog.ROW);

		String strURL = getPathUnderSystemURL(END_SERVLET_URL);
		// メソッド終了ログ
		DebugLog.write(
			this.getClass(),
			"TAIL getEndLearnServletURL()",
			DebugLog.ROW);

		return strURL;
	}

	/**
	 * Scorm LOサーバ情報を取得します。<br>
	 * Scorm LOサーバ情報を設定ファイルから取得し、配列として戻します。
	 * 設定がない場合、空の配列を戻します。
	 * @return 取得したScorm LOサーバ情報を配列で戻します。
	 */
	public final ScormServerInfo[] getScormLoServerList() {
		// メソッド開始ログ
		DebugLog.write(
			this.getClass(),
			"HEAD getScormLoServerList()",
			DebugLog.ROW);

		// このメソッドの戻り値。
		ScormServerInfo[] servers = null;
		// 配列変換・一時格納用リスト
		List serverList = null;
		// 設定ファイルから取得した１サーバ情報。
		ScormServerInfo serverInfo = null;

		serverList = new ArrayList();
		for (int i = 1; i <= SCORM_LO_SERVER_MAX; i++) {
			String serverNo = null;
			String serverName = null;
			// 取得するプロパティ・キー名称設定
			serverNo = SCORM_LO_SERVER_PREFIX + Integer.toString(i);
			//設定ファイルからサーバ情報取得
			try {
				serverName = getProperty(serverNo, mproperties);
			}
			// 例外が発生した場合、スローせずに処理の中断でとどめる。
			catch (LOException e) {

				break;
			}
			// 名称を取得できなかった場合スローする。
			if (serverName == null) {
				break;
			}
			// 取得した情報からサーバ情報を生成し、リストに格納
			serverInfo = new ScormServerInfo(serverNo, serverName);
			serverList.add(serverInfo);
		}
		// 配列へ変換
		servers = new ScormServerInfo[serverList.size()];
		serverList.toArray(servers);

		// メソッド終了ログ
		DebugLog.write(
			this.getClass(),
			"TAIL getScormLoServerList() return " + servers,
			DebugLog.ROW);
		return servers;
	}

	/**
	 * URL文字列をエンコードする際の文字コードを取得します。。
	 *
	 * @return URL文字列をエンコードする際の文字コード。
	 * @throws LOException 取得に失敗した場合。
	 */
	public String getCharsetUrlEncode() throws LOException {
		return getProperty(CHARSET_URL_ENCODE, mproperties);
	}

	/**
	 * キーを元にプロパティ値を取得します。<br>
	 * SCORM LOのプロパティに該当しない場合は、LO共通プロパティを取得します。<br>
	 * @param propertyName 取得するキー名称。
	 * @return 指定したプロパティの値文字列。
	 * @throws LOException 指定したプロパティがない場合。
	 */
	public String getProperty( String propertyName )
		throws LOException {
		String propertyValue = null;
		try {
			propertyValue = getProperty( propertyName, mproperties );
		}
		catch (LOException e) {
		}
		// 値取得に失敗した場合は、LO共通から取得します。
		if (propertyValue == null) {
			propertyValue = super.getProperty( propertyName );
		}
		return propertyValue;
	}

	/**
	 * キーを元にプロパティ値を取得します。
	 * @param propertyName 取得するキー名称。
	 * @param properties 取得元のプロパティ。
	 * @return 指定したプロパティの値文字列。
	 * @throws LOException 指定したプロパティがない場合。
	 */
	public String getProperty(String propertyName, Properties properties)
		throws LOException {

		String strValue = null;
		try {
			if (properties != null) {
				strValue = properties.getProperty(propertyName);
				if (strValue == null) {
					String errMessage = "Not found properties:" + propertyName;
					throw new LOException(errMessage);
				}
			}
		}
		catch (LOException e) {
			throw e;
		}
		catch (Exception e) {
			DebugLog.write(this.getClass(), e, DebugLog.HIGHT);
			throw new LOException(e.getMessage());
		}
		return strValue;
	}

	/**
	 * 認証キーを算出する際に切り詰める分単位を取得します。
	 *
	 * @return 切り詰める分単位。
	 */
	public int getAuthenticMinuteSpan() {

		String strMinuteSpan = null;
		int intMinuteSpan = 0;
		try {
			strMinuteSpan = getProperty(AUTHENTIC_MINUTE_SPAN, mproperties);
			intMinuteSpan = Integer.parseInt(strMinuteSpan);
		}
		catch (Exception e) {
			intMinuteSpan = 5;
		}

		return intMinuteSpan;
	}

	/**
	 * ユーザ選択時の個別ログポップアップメニュー内容を取得します。<br>
	 * 設定ファイルより、１メニューごとにメニュー情報を取得して
	 * 文字列配列として生成し、それら（メニュー情報の）文字列配列の配列を
	 * 戻します。
	 * 情報を取得できなかった場合は長さ０の配列を戻します。 <br>
	 * @return 以下の要素で構成される文字列配列の配列を戻します。<br>
	 * <table border="1">
	 * 	<tr>
	 * 		<th>インデックス</th>
	 * 		<th>要素の値</th>
	 *  </tr>
	 * 	<tr>
	 * 		<td>0</td>
	 * 		<td>メニュー名称</td>
	 *  </tr>
	 * 	<tr>
	 * 		<td>1</td>
	 * 		<td>URL</td>
	 *  </tr>
	 * </table><br>
	 */
	public String[][] getUserIndividualLogMenuInfos() {
		String[][] menuInfos = null;
		menuInfos = getIndividualLogMenuInfos(
				USER_INDIVIDUAL_LOG_MENU_LABEL_PREFIX,
				USER_INDIVIDUAL_LOG_MENU_URL_PREFIX);
		return menuInfos;
	}

	/**
	 * グループ選択時の個別ログポップアップメニュー内容を取得します。<br>
	 * 設定ファイルより、１メニューごとにメニュー情報を取得して
	 * 文字列配列として生成し、それら（メニュー情報の）文字列配列の配列を
	 * 戻します。
	 * 情報を取得できなかった場合は長さ０の配列を戻します。 <br>
	 * @return 以下の要素で構成される文字列配列の配列を戻します。<br>
	 * <table border="1">
	 * 	<tr>
	 * 		<th>インデックス</th>
	 * 		<th>要素の値</th>
	 *  </tr>
	 * 	<tr>
	 * 		<td>0</td>
	 * 		<td>メニュー名称</td>
	 *  </tr>
	 * 	<tr>
	 * 		<td>1</td>
	 * 		<td>URL</td>
	 *  </tr>
	 * </table><br>
	 */
	public String[][] getGroupIndividualLogMenuInfos() {
		String[][] menuInfos = null;
		menuInfos = getIndividualLogMenuInfos(
				GROUP_INDIVIDUAL_LOG_MENU_LABEL_PREFIX,
				GROUP_INDIVIDUAL_LOG_MENU_URL_PREFIX);
		return menuInfos;
	}

	/**
	 * システムパス配下のURLを取得します。<br>
	 * @param propertyName 取得するプロパティ名称。
	 * @return システムURLを展開した形で、指定した名称に対応するパスを戻します。
	 * @throws LOException 取得に失敗した場合。
	 */
	private String getPathUnderSystemURL(String propertyName)
		throws LOException {
		// メソッド開始ログ
		DebugLog.write(
			this.getClass(),
			"HEAD getPathUnderSystemURL(" + propertyName + ")",
			DebugLog.ROW);

		String strURL = null;
		try {
			Hashtable macro = new Hashtable();
			strURL = getPathUnderSystemURL(propertyName, macro);
		}
		catch (LOException e) {
			throw e;
		}
		catch (Exception e) {
			DebugLog.write(this.getClass(), e, DebugLog.HIGHT);
			throw new LOException(e.getMessage());
		}
		// メソッド終了ログ
		DebugLog.write(
			this.getClass(),
			"TAIL getPathUnderSystemURL(" + propertyName + ")"
			+ " return " + strURL,
			DebugLog.ROW);

		return strURL;
	}

	/**
	 * システムパス配下のURLを取得します。<br>
	 * @param propertyName 取得するプロパティ名称。
	 * @param macro 展開するマクロテーブル。
	 * @return システムURLを展開した形で、指定した名称に対応するパスを戻します。
	 * @throws LOException 取得に失敗した場合。
	 */
	private String getPathUnderSystemURL(String propertyName, Hashtable macro)
		throws LOException {
		// メソッド開始ログ
		DebugLog.write(
			this.getClass(),
			"HEAD getPathUnderSystemURL(" + propertyName + "," + macro + ")",
			DebugLog.ROW);

		String strURL = null;
		try {
			strURL = getProperty(propertyName, mproperties);
			macro.put(Environment.SYSTEM_URL, mobjEnv.getSystemURL());
			strURL = expand(strURL, macro);
		}
		catch (LOException e) {
			throw e;
		}
		catch (Exception e) {
			DebugLog.write(this.getClass(), e, DebugLog.HIGHT);
			throw new LOException(e.getMessage());
		}
		// メソッド終了ログ
		DebugLog.write(
			this.getClass(),
			"TAIL getPathUnderSystemURL(" + propertyName + "," + macro + ")"
			+ (" return " + strURL),
			DebugLog.ROW);

		return strURL;
	}

	/**
	 * システムパス配下のディレクトリパスを取得します。<br>
	 * @param propertyName 取得するプロパティ名称。
	 * @return システムディレクトリを展開した形で、
	 *          指定した名称に対応するパスを戻します。
	 * @throws LOException 取得に失敗した場合。
	 */
	private String getPathUnderSystemDir(String propertyName)
		throws LOException {
		// メソッド開始ログ
		DebugLog.write(
			this.getClass(),
			"HEAD getPathUnderSystemDir(" + propertyName + ")",
			DebugLog.ROW);

		String strURL = null;
		try {
			strURL = getProperty(propertyName, mproperties);
			Hashtable macro = new Hashtable();
			macro.put(Environment.SYSTEM_DIR, mobjEnv.getSystemDir());

			strURL = expand(strURL, macro);
		}
		catch (LOException e) {
			throw e;
		}
		catch (Exception e) {
			DebugLog.write(this.getClass(), e, DebugLog.HIGHT);
			throw new LOException(e.getMessage());
		}
		// メソッド終了ログ
		DebugLog.write(
			this.getClass(),
			"TAIL getPathUnderSystemDir(" + propertyName + ")",
			DebugLog.ROW);

		return strURL;
	}

	/**
	 * 個別ログポップアップメニュー内容を取得します。<br>
	 * 設定ファイルより、１メニューごとにメニュー情報を取得して
	 * 文字列配列として生成し、それら（メニュー情報の）文字列配列の配列を
	 * 戻します。
	 * 情報を取得できなかった場合は長さ０の配列を戻します。 <br>
	 * @param labelKeyPrefix
	 *         メニューラベルを取得するためのプロパティキーのプレフィックス。
	 * @param urlKeyPrefix
	 *         メニューURLを取得するためのプロパティキーのプレフィックス。
	 * @return 以下の要素で構成される文字列配列の配列を戻します。<br>
	 * <table border="1">
	 * 	<tr>
	 * 		<th>インデックス</th>
	 * 		<th>要素の値</th>
	 *  </tr>
	 * 	<tr>
	 * 		<td>0</td>
	 * 		<td>メニュー名称</td>
	 *  </tr>
	 * 	<tr>
	 * 		<td>1</td>
	 * 		<td>URL</td>
	 *  </tr>
	 * </table><br>
	 */
	private String[][] getIndividualLogMenuInfos(
			String labelKeyPrefix, String urlKeyPrefix) {
		// 戻り値の配列生成用
		List menuInfoList = new ArrayList();
		// インデックスを１から順に連番で、メニューのラベルとURLを
		// 設定ファイルから取得する。
		for (int index = 1; true; index++) {
			// メニューラベルを取得するキー
			String keyMenuLabel = labelKeyPrefix + index;
			// メニューURLを取得するキー
			String keyMenuUrl = urlKeyPrefix + index;
			// 設定ファイルから読み込み
			String menuLabel = null;
			String menuUrl = null;
			try {
				menuLabel = getProperty(keyMenuLabel, mproperties);
				menuUrl = getPathUnderSystemURL(keyMenuUrl);
			}
			catch (LOException e) {
				// 読み込みできなかった時点で終了
				break;
			}

			// 読み込んだ情報を配列化して、リストに登録
			String[] oneMenuInfo = new String[] {
				menuLabel, menuUrl,
			};
			menuInfoList.add(oneMenuInfo);
		}

		// リストから配列に変換
		String[][] menuInfos = new String[menuInfoList.size()][];
		menuInfoList.toArray(menuInfos);
		return menuInfos;
	}
//  ADD 2005/02/15 START SUGAWARA [scorm取り込み]
	/**
	 * 登録済みの教材構造定義ファイルを格納するディレクトリ・パスを戻します。
	 *
	 * @return 登録済みの教材構造定義ファイルを格納するディレクトリ・パス。
	 * @throws LOException 取得に失敗した場合。
	 */
	public final String getLomEntryFile() throws LOException {
		// メソッド開始ログ
		DebugLog.write(this.getClass(), "HEAD getLomEntryFile()", DebugLog.ROW);
//		System.out.println(this.getClass() + " HEAD getLomEntryFile()");
		String lomEntryFile = getPathUnderSystemDir(LOM_ENTRY_FILE);

		// メソッド終了ログ
		DebugLog.write(
			this.getClass(),
			"TAIL getLomEntryFile()" + " return " + lomEntryFile,
			DebugLog.ROW);
		return lomEntryFile;
	}
//  ADD 2005/02/15 END SUGAWARA
}