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

//
//機能名称 
//		SCORM1.3 データモデルユーティリティ クラス
//変更履歴
//		2004.01.20	A.Kudoh  新規作成
//
package jp.co.ntt.lms.lo.scorm.cbtcom;

import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
//import java.util.StringTokenizer;
import java.util.Vector;

/**
 * CMI データモデルユーティリティ クラス <BR>
 * @author A.kudoh
 * 
 */
public class CMIS13ModelUtil {

	/**
	 * SCORM v1.3 DataModel Name
	 */
	public static final String S13_LEARNER_ID	 	= "cmi.learner_id";
	public static final String S13_LEARNER_NAME	= "cmi.learner_name";
	public static final String S13_LOCATION		= "cmi.location";
	public static final String S13_CREDIT		 	= "cmi.credit";
	public static final String S13_LESSON_STATUS 	= "cmi.success_status";
	public static final String S13_COMP_STATUS 	= "cmi.completion_status";
	public static final String S13_ENTRY		 	= "cmi.entry";
	public static final String S13_SCORE_CHILD 	= "cmi.score._children";
	public static final String S13_SCORE_SCALE 	= "cmi.score.scaled";
	public static final String S13_SCORE_RAW	 	= "cmi.score.raw";
	public static final String S13_SCORE_MAX	 	= "cmi.score.max";
	public static final String S13_SCORE_MIN	 	= "cmi.score.min";
	public static final String S13_TOTAL_TIME	 	= "cmi.total_time";
	public static final String S13_MODE			= "cmi.mode";
	public static final String S13_MASTERY_SCORE 	= "cmi.scaled_passing_score";
	public static final String S13_MAX_TIME_ALLOWED = "cmi.max_time_allowed";
	public static final String S13_TIME_LIMIT_ACTION = "cmi.time_limit_action";
	public static final String S13_PREFERENCE_GRP	= "cmi.learner_preference";
	public static final String S13_EXIT			= "cmi.exit";
	public static final String S13_SESSION_TIME	= "cmi.session_time";
	public static final String S13_CMT_GRP		= "cmi.comments_from_learner";
	public static final String S13_INT_GRP		= "cmi.interactions";
	// NTTR*1
	public static final String S13_COMPLETION_THRESHOLD = "cmi.completion_threshold";
	public static final String S13_PROGRESS_MEASURE = "cmi.progress_measure";
	
	// AICC CMI DataModel Name
	private static final String AICC_LEARNER_ID	 	= "cmi.core.student_id";
	private static final String AICC_LEARNER_NAME 	= "cmi.core.student_name";
	private static final String AICC_LOCATION	 		= "cmi.core.lesson_location";
	private static final String AICC_CREDIT		 	= "cmi.core.credit";
	private static final String AICC_LESSON_STATUS	= "cmi.core.lesson_status";
	private static final String AICC_COMP_STATUS 		= "cmi.core.completion_status";
	private static final String AICC_ENTRY		 	= "cmi.core.entry";
	private static final String AICC_SCORE_CHILD 		= "cmi.core.score._children";
	private static final String AICC_SCORE_SCALE 		= "cmi.core.score.scaled";
	private static final String AICC_SCORE_RAW	 	= "cmi.core.score.raw";
	private static final String AICC_SCORE_MAX	 	= "cmi.core.score.max";
	private static final String AICC_SCORE_MIN	 	= "cmi.core.score.min";
	private static final String AICC_TOTAL_TIME	 	= "cmi.core.total_time";
	private static final String AICC_MODE		 		= "cmi.core.lesson_mode";
	private static final String AICC_MASTERY_SCORE 	= "cmi.student_data.mastery_score";
	private static final String AICC_MAX_TIME_ALLOWED = "cmi.student_data.max_time_allowed";
	private static final String AICC_TIME_LIMIT_ACTION = "cmi.student_data.time_limit_action";
	private static final String AICC_PREFERENCE_GRP	= "cmi.student_preference";
	private static final String AICC_EXIT			 	= "cmi.core.exit";
	private static final String AICC_SESSION_TIME	 	= "cmi.core.session_time";
	private static final String AICC_CMT_GRP 			= "cmi.evaluation.comments";
	private static final String AICC_INT_GRP 			= "cmi.interactions";
	//	 NTTR*2
	public static final String AICC_COMPLETION_THRESHOLD = "cmi.core.completion_threshold";
	public static final String AICC_PROGRESS_MEASURE = "cmi.core.progress_measure";

	// AICC Error Code
	/**
	 * Element cannot have a value
	 */
	private static final int AICC_ERROR_204 = 204;
	/**
	 * Not implemented error
	 */
	private static final int AICC_ERROR_401 = 401;
	/**
	 * Element is read only.
	 */
	private static final int AICC_ERROR_403 = 403;
	/**
	 * Element is write only
	 */
	private static final int AICC_ERROR_404 = 404;
	/**
	 * Incorrect Data Type
	 */
	private static final int AICC_ERROR_405 = 405;

	// SCORM1.3 Error Code
	/**
	 * Unimplemented Data Model Element
	 */	
	public static final int S13_ERROR_402 = 402;
	/**
	 * Data Model Element Is Read Only 
	 */
	public static final int S13_ERROR_404 = 404;
	/**
	 * Data Model Element Is Write Only 
	 */
	public static final int S13_ERROR_405 = 405;
	/**
	 * Data Model Element Type Mismatch 
	 */
	public static final int S13_ERROR_406 = 406;
	
	/**
	 *  データモデル名マップ
	 */
	private	static HashMap m_hmName;

	/**
	 *  データモデルグループ名情報
	 */
	private	static Vector m_vcGroupName;

	/**
	 *  エラーコードマップ
	 */
	private	static HashMap m_hmErrorCode;
	
	/**
	 *  データモデルタイプ。<br>
	 * 　　true：SCORM1.3 モデル　false：AICC モデル
	 */
	private	static boolean m_bScorm13Type;

	/**
	 * 改行コード
	 */
	public		static final String CHAR_CRLF = System.getProperty("line.separator");

	/**
	 * スタティックイニシャライザ。<br>
	 * データモデル名マップ情報、エラーコードマップ情報を初期設定する。<br>
	 */
	static {

		m_hmName = new HashMap();
		m_hmErrorCode = new HashMap();
		m_bScorm13Type = true;

		m_vcGroupName = new Vector();

		// データモデル名マップ情報を設定する
		m_hmName.put(S13_LEARNER_ID, AICC_LEARNER_ID);
		m_hmName.put(S13_LEARNER_NAME, AICC_LEARNER_NAME);
		m_hmName.put(S13_LOCATION, AICC_LOCATION);
		m_hmName.put(S13_CREDIT, AICC_CREDIT);
		m_hmName.put(S13_LESSON_STATUS, AICC_LESSON_STATUS);
		m_hmName.put(S13_COMP_STATUS, AICC_COMP_STATUS);
		m_hmName.put(S13_ENTRY, AICC_ENTRY);
		m_hmName.put(S13_SCORE_CHILD, AICC_SCORE_CHILD);
		m_hmName.put(S13_SCORE_SCALE, AICC_SCORE_SCALE);
		m_hmName.put(S13_SCORE_RAW, AICC_SCORE_RAW);
		m_hmName.put(S13_SCORE_MAX, AICC_SCORE_MAX);
		m_hmName.put(S13_SCORE_MIN, AICC_SCORE_MIN);
		m_hmName.put(S13_TOTAL_TIME, AICC_TOTAL_TIME);
		m_hmName.put(S13_MODE, AICC_MODE);
		m_hmName.put(S13_MASTERY_SCORE,AICC_MASTERY_SCORE);
		m_hmName.put(S13_MAX_TIME_ALLOWED, AICC_MAX_TIME_ALLOWED);
		m_hmName.put(S13_TIME_LIMIT_ACTION, AICC_TIME_LIMIT_ACTION);
		m_hmName.put(S13_PREFERENCE_GRP, AICC_PREFERENCE_GRP);
		m_hmName.put(S13_EXIT,AICC_EXIT);
		m_hmName.put(S13_SESSION_TIME, AICC_SESSION_TIME);
		m_hmName.put(S13_CMT_GRP, AICC_CMT_GRP);

		// NTTR*3
		m_hmName.put(S13_COMPLETION_THRESHOLD, AICC_COMPLETION_THRESHOLD);
		m_hmName.put(S13_PROGRESS_MEASURE, AICC_PROGRESS_MEASURE);

		// データモデルグループ名情報を設定する
		m_vcGroupName.add(S13_PREFERENCE_GRP);
		m_vcGroupName.add(S13_CMT_GRP);

		// エラーコードマップ情報を設定する
		m_hmErrorCode.put(new Integer(AICC_ERROR_204), new Integer(S13_ERROR_404));
		m_hmErrorCode.put(new Integer(AICC_ERROR_401), new Integer(S13_ERROR_402));
		m_hmErrorCode.put(new Integer(AICC_ERROR_403), new Integer(S13_ERROR_404));
		m_hmErrorCode.put(new Integer(AICC_ERROR_404), new Integer(S13_ERROR_405));
		m_hmErrorCode.put(new Integer(AICC_ERROR_405), new Integer(S13_ERROR_406));

	}

	/**	
	 * マッピング情報に従い、SCORM1.3のデータモデル名をAICC のCMIデータ
	 * モデル名に変換し、その名称を返却する<br>
	 * マッピング対象以外のデータモデル名が指定された場合は、指定された
	 * 名称をそのまま返却する<br>
	 * @param strS13Name String　SCORM1.3 データモデル名
	 * @return String　AICC CMIデータモデル名
	 */
	public static String changeAiccModelName(String strS13Name) {

		String strAiccName = null;

		// 入力パラメータチェック
		if ((strS13Name != null) && ("".equals(strS13Name) == false)) {
			strAiccName = (String)m_hmName.get(strS13Name);
		}
		if (strAiccName == null) {
			// フル文字列ではヒットしない配列を含むモデル名の場合
			// （例：cmi.learner_preference.n.text など）

			String strSubPath;
			StringBuffer sbReplace = new StringBuffer();
			int intCount = m_vcGroupName.size();
			for (int i=0; i < intCount; i++){
				strSubPath = (String)m_vcGroupName.get(i);
				if ( strS13Name.indexOf(strSubPath) != -1 ){
					// 変換するAICCのグループパス名を取り出す
					strAiccName = (String)m_hmName.get(strSubPath);
					if (strAiccName != null) {
						// AICCのグループパス名に置換する
						sbReplace.append(strAiccName);
						sbReplace.append(".");
						sbReplace.append(strS13Name.substring(strSubPath.length()+1));

						strAiccName = sbReplace.toString();
						break;
					}
				}
			}
			if (strAiccName == null) {
				// さらに特殊な変換の必要なモデル名の場合
				// 配列を含み、なおかつ変換対象がグループ名ではないモデル
				// （例：cmi.objectives.n.status など）
				strSubPath = "cmi.objectives";
				if (strS13Name.indexOf(strSubPath) != -1) {
					int iPos = strS13Name.lastIndexOf("success_status");
					if (iPos != -1) {
						sbReplace.append(strS13Name.substring(0,iPos));
						sbReplace.append("status");

						strAiccName = sbReplace.toString();
					}
				}
				strSubPath = "cmi.interactions";
				if (strS13Name.indexOf(strSubPath) != -1) {
					int iPos = strS13Name.lastIndexOf("timestamp");
					if (iPos != -1) {
						sbReplace.append(strS13Name.substring(0,iPos));
						sbReplace.append("date");

						strAiccName = sbReplace.toString();
					}
					else {
						iPos = strS13Name.lastIndexOf("learner_response");
						if (iPos != -1) {
							sbReplace.append(strS13Name.substring(0,iPos));
							sbReplace.append("student_response");

							strAiccName = sbReplace.toString();
						}
					}
				}

			}
			if (strAiccName == null) {
				strAiccName = strS13Name;
			}
		}
		return strAiccName;
	}

	/**	
	 * マッピング情報に従い、AICCのエラーコードをSCORM1.3のエラーコード
	 * に変換し、そのコードを返却する<br>
	 * マッピング対象以外のエラーコードが指定された場合は、指定された
	 * エラーコードをそのまま返却する。<br>
	 * @param intAiccCode int AICC エラーコード
	 * @return int　SCORM1.3 エラーコード
	 */
	public static int changeScormErrorCode(int intAiccCode) {

		Integer iobjScormCode = null;
		int intRetCode = 0;

		// 入力パラメータチェック
		if (intAiccCode >= 0) {
			iobjScormCode = (Integer)m_hmErrorCode.get(new Integer(intAiccCode));
		}
		if (iobjScormCode != null) {
			intAiccCode = iobjScormCode.intValue();
		}
		else {
			intRetCode = intAiccCode;
		}
		return intAiccCode;
	}

	/**
	 * AICC2.x形式のタイマー文字列を分析してSCORM1.3形式の
	 * PyYmMdDThHmMs.sSの文字列に変換する。<br>
	 * @param strAiccTime String AICC形式（HHHH:MM:SS.SS）の文字列
	 * @return String SCORM1.3形式（PyYmMdDThHmMs.sS）に変換した値
	 * @exception S13LogFormatException 変換に失敗した場合
	 */
	public static String parseS13Timespan( String strAiccTime )
		throws S13LogFormatException
	{
		String strTimespan = "";
		// パラメータチェック
		if( (strAiccTime == null) || ("".equals(strAiccTime) == true) ) {
			throw new S13LogFormatException("Invalid Timespan : " + strAiccTime );
		}

		/*
		 * AICC2.x形式のタイマー文字列をSCORM1.3形式のフォーマットで編集する
		 */
		// タイマー値をミリ秒で取得する
		long lngSecond = parseTimespanToLong(strAiccTime);
		// 取得したミリ秒のタイマー値をSCORM1.3フォーマットで編集する
		strTimespan = formatS13Timespan(lngSecond);
		
		return strTimespan;
	}

	/**
	 * SCORM1.3形式(PyYmMdDThHmMs.sS)のタイマー文字列を分析してAICC2.x
	 * 形式のタイマー文字列（HHHH:MM:SS.SS）に変換する。<br>
	 * @param strTime String SCORM1.3形式(PyYmMdDThHmMs.sS)の文字列
	 * @return String AICC2.x形式（HHHH:MM:SS.SS）に変換した値
	 * @exception S13LogFormatException 変換に失敗した場合
	 */
	public static String parseAiccTimespan( String strTime )
		throws S13LogFormatException
	{
		String strTimespan = "";
		// パラメータチェック
		if( (strTime == null) || ("".equals(strTime) == true) ) {
			throw new S13LogFormatException("Invalid Timespan : " + strTime );
		}

		/*
		 * SCORM1.3形式のタイマー文字列をAICC2.x形式のフォーマットで編集する
		 */
		// タイマー値をミリ秒で取得する
		long lngSecond = parseTimeintervalToLong(strTime);
		// 取得したミリ秒のタイマー値をAICC2.xフォーマットで編集する
		strTimespan = formatAiccTimespan(lngSecond);
		
		return strTimespan;
	}

	/**
	 * AICC2.x形式（HHHH:MM:SS.SS）のTimespan型文字列をlong型のミリ秒に
	 * 変換する。<br>
	 * @param strAiccTime String AICC形式（HHHH:MM:SS.SS）の文字列
	 * @return long ミリ秒に変換した値
	 * @exception S13LogFormatException 変換に失敗した場合
	 */
	public static long parseTimespanToLong( String strAiccTime )
		throws S13LogFormatException
	{
		// パラメータチェック
		if( (strAiccTime == null) || ("".equals(strAiccTime) == true) ) {
			throw new S13LogFormatException("Invalid Time : " + strAiccTime );
		}

//		StringTokenizer token = new StringTokenizer( strAiccTime, ":" );
		CMITokenizer token = new CMITokenizer( strAiccTime, ":" );

		long lngHour = 0;
		long lngMinute = 0;
		float fltSecond = 0;

		int intCount = 0;
		try {
			while( token.hasMoreTokens() ) {

				String strValue = token.nextToken();
				switch( intCount ) {
					case 0:
						// 時間
						lngHour = Long.parseLong( strValue );
						break;
					case 1:
						// 分
						lngMinute = Long.parseLong( strValue );
						break;
					case 2:
						// 秒
						fltSecond = Float.parseFloat( strValue );
						break;
					default:
						break;
				}

				// カウントアップ
				intCount++;
			}
		}
		catch( NumberFormatException ne ) {
			throw new S13LogFormatException(ne.getMessage());
		}

		if( intCount != 3 ) {
			throw new S13LogFormatException("Invalid Time : " + strAiccTime );
		}

		long lngRes = 0;

		lngRes = (lngHour * 3600000L) + (lngMinute * 60000L) + (long)(fltSecond * 1000L);

		return lngRes;
	}

	/**
	 * SCORM1.3形式（PyYmMdDThHmMs.sS）のTimeinterval型文字列を
	 * long型のミリ秒に変換する。<br>
	 * @param strScoTime String SCORM形式（PyYmMdDThHmMs.sS）の文字列
	 * @return long ミリ秒に変換した値
	 * @exception S13LogFormatException 変換に失敗した場合
	 */
	public static long parseTimeintervalToLong( String strScoTime )
		throws S13LogFormatException
	{
		// パラメータチェック
		if( (strScoTime == null) || ("".equals(strScoTime) == true) ) {
			throw new S13LogFormatException("Invalid Time : " + strScoTime );
		}

		long lngYear = 0;
		long lngMonth = 0;
		long lngDay = 0;
		long lngHour = 0;
		long lngMinute = 0;
		float fltSecond = 0;

		String strDate = "";
		String strTime = "";
		if (strScoTime.startsWith("P") != true) {
			throw new S13LogFormatException("Type Mismatch  non-P");
		} 
		int intPos = strScoTime.indexOf('T');
		if (intPos != -1){
			// 時間の指定が省略されていない場合
			strDate = strScoTime.substring(0,intPos);
			strTime = strScoTime.substring(intPos,strScoTime.length());
		}
		else{
			// 時間の指定が省略された場合
			strDate = strScoTime;
		}

		try {

			// 年の取得
			int intStartPos = 1;	// プレフィックスPを取り除く
			intPos = strDate.indexOf('Y');
			if (intPos != -1){
				lngYear = Long.parseLong(strDate.substring(intStartPos,intPos));
				intStartPos = intPos + 1;
			}
			// 月の取得
			intPos = strDate.indexOf('M',intStartPos);
			if (intPos != -1){
				lngMonth = Long.parseLong(strDate.substring(intStartPos,intPos));
				intStartPos = intPos + 1;
			}
			// 日の取得
			intPos = strDate.indexOf('D',intStartPos);
			if (intPos != -1){
				lngDay = Long.parseLong(strDate.substring(intStartPos,intPos));
			}
			// 時の取得
			intStartPos = 1;	// プレフィックスTを取り除く
			intPos = strTime.indexOf('H');
			if (intPos != -1){
				lngHour = Long.parseLong(strTime.substring(intStartPos,intPos));
				intStartPos = intPos + 1;
			}
			// 分の取得
			intPos = strTime.indexOf('M',intStartPos);
			if (intPos != -1){
				lngMinute = Long.parseLong(strTime.substring(intStartPos,intPos));
				intStartPos = intPos + 1;
			}
			// 秒の取得
			intPos = strTime.indexOf('S',intStartPos);
			if (intPos != -1){
				fltSecond = Float.parseFloat(strTime.substring(intStartPos,intPos));
			}
		}
		catch( NumberFormatException ne ) {
			throw new S13LogFormatException(ne.getMessage());
		}

		long lngRes = 0;

		lngRes = (lngYear * 3600000L * 24L * 30L * 12L)
			 + (lngMonth * 3600000L * 24L * 30L);
		lngRes = lngRes + (lngDay * 3600000L * 24L) + (lngHour * 3600000L);
		lngRes = lngRes + (lngMinute * 60000L) + (long)(fltSecond * 1000L);

		return lngRes;
	}

	/**
	 * long型のミリ秒をPyYmMdDThHmMs.sS 形式の文字列に変換する。<br>
	 * @param lngTime ミリ秒
	 * @return String PyYmMdDThHmMs.sS 形式の文字列
	 */
	public static String formatS13Timespan( long lngTime ) {

		String strTimespan = "";

		// 余りを保持する
		long lngRem = 0;

		// 年の算出
		int intYear = (int)(lngTime / (3600000L * 24L * 30L * 12L));
		lngRem = lngTime % (3600000L * 24L * 30L * 12L);

		// 月の算出
		int intMonth = (int)(lngRem / (3600000L * 24L * 30L));
		lngRem = lngRem % (3600000L * 24L * 30L);

		// 日の算出
		int intDay = (int)(lngRem / (3600000L * 24L));
		lngRem = lngTime % (3600000L * 24L);

		// 時の算出
		int intHour = (int)(lngRem / 3600000L);
		lngRem = lngTime % 3600000L;

		// 分の算出
		int intMinute = (int)(lngRem / 60000L);
		lngRem = lngRem % 60000L;

		// 秒の算出
		float fltSecond = lngRem / 1000F;

		// 年のフォーマット
		DecimalFormat objYearFormat = new DecimalFormat( "####" );
		String strYear = objYearFormat.format( intYear );

		// 月のフォーマット
		DecimalFormat objMonthFormat = new DecimalFormat( "##" );
		String strMonth = objMonthFormat.format( intMonth );

		// 日のフォーマット
		DecimalFormat objDayFormat = new DecimalFormat( "##" );
		String strDay = objDayFormat.format( intDay );

		// 時間のフォーマット
		DecimalFormat objHourFormat = new DecimalFormat( "##" );
		String strHour = objHourFormat.format( intHour );

		// 分のフォーマット
		DecimalFormat objMinuteFormat = new DecimalFormat( "##" );
		String strMinute = objMinuteFormat.format( intMinute );

		// 秒のフォーマット
		DecimalFormat objSecondFormat = new DecimalFormat( "#0.##" );
		String strSecond = objSecondFormat.format( fltSecond );

		// 日付をPyYmMdD フォーマットで編集
		strTimespan = "P" + strYear + "Y" + strMonth + "M" + strDay + "D";

		// 時間をThHmMs.sS フォーマットで編集
		strTimespan = strTimespan + "T" + strHour + "H" + strMinute + "M";
		strTimespan = strTimespan + strSecond + "S";
		
		return strTimespan;
	}
		

	/**
	 * long型のミリ秒をHHHH:MM:SS.SS 形式の文字列に変換します
	 * @param lngTime ミリ秒に変換した値
	 * @return String HHHH:MM:SS.SS形式の文字列
	 */
	public static String formatAiccTimespan( long lngTime ) {
		// 余りを保持する
		long lngRem = 0;

		// 時間の算出
		int intHour = (int)(lngTime / 3600000L);
		lngRem = lngTime % 3600000L;

		// 分の算出
		int intMinute = (int)(lngRem / 60000L);
		lngRem = lngRem % 60000L;

		// 秒の算出
		float fltSecond = lngRem / 1000F;

		String strInterval = "";
		if ( 10000 <= intHour ) {
			strInterval = "9999:59:59.99";
		}
		else {

			// 時間のフォーマット
			DecimalFormat objHourFormat = new DecimalFormat( "0000" );
			String strHour = objHourFormat.format( intHour );

			// 分のフォーマット
			DecimalFormat objMinuteFormat = new DecimalFormat( "00" );
			String strMinute = objMinuteFormat.format( intMinute );

			// 秒のフォーマット
			DecimalFormat objSecondFormat = new DecimalFormat( "00.##" );
			String strSecond = objSecondFormat.format( fltSecond );

			strInterval = strHour + ":" + strMinute + ":" + strSecond;
		}
		return strInterval;
	}


	/**
	 * AICC2.x形式の日付文字列、時間文字列を分析してSCORM1.3形式の<br>
	 * YYYY-MM-DDThh:mm:ss.sTZD 形式の文字列に変換する <br>
	 * @param strDate yyyy/MM/dd形式の日付文字列
	 * @param strTime HH:mm:ss.SS形式の日付文字列
	 * @return String 日付に変換した値
	 * @exception S13LogFormatException 変換に失敗した場合
	 */
	public static String parseS13Date( String strDate, String strTime )
		throws S13LogFormatException
	{
		Date objDate = null;
		String strRetDate = "";
		// パラメータチェック
		if(((strDate == null) || ("".equals(strDate) == true)) &&
			((strTime == null) || ("".equals(strTime) == true))) {
			throw new S13LogFormatException(
				"Invalid DateTime : " + strDate );
		}
		if ((strDate == null) || ("".equals(strDate) == true)) {
			strDate = getSystemDate("yyyy/MM/dd");
		}
		if ((strTime == null) || ("".equals(strTime) == true)) {
			strTime = "00:00:00.00";	// 初期値を設定
		}

		/*
		 * 日付文字列からDateオブジェクトを生成する
		 */
		// 日付オブジェクト取得（parse）用のインスタンスを生成する
		DateFormat objParseFormat = 
			new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss.SS" );

		// 日付文字列のフォーマット変換用のインスタンスを生成する
		DateFormat objFormat = 
			new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.SS" );
		objParseFormat.setLenient( false );
		try {
			int iPos = strTime.indexOf(".");
			if (iPos == -1) {
				strTime = strTime + ".00";
			}
			objDate = objParseFormat.parse( strDate + " " + strTime );
		}
		catch( ParseException pe ) {
			throw new S13LogFormatException( pe.getMessage() );
		}
		strRetDate = objFormat.format(objDate);
		strRetDate = strRetDate.replace(' ','T');
		return strRetDate;
	}

	/**
	 *  指定したシステム日付を取得する
	 *  @return String	システム日付
	 */
	public static String getSystemDate(String strFormat)
	{
		DateFormat objFormat = new SimpleDateFormat( strFormat );

		return objFormat.format(new Date());
	}

	/**
	 * AICC2.x形式のステータス文字列の先頭文字を判断してSCORM1.3
	 * 形式の合格ステータス文字列に変換する。
	 * 先頭文字が下記以外の（変換対象外）の文字列はエラーとする。
	 * <PRE>
	 *    n(not attempted)  →  unknown
	 *    i(incomplete)     →  unknown
	 *    f(failed)         →  failed
	 *    c(completed)      →  unknown
	 *    p(passed)         →  passed
	 *    b(browsed)        →  unknown	
	 * </PRE>
	 * @param strAiccStatus ステータス文字列
	 * @return String SCORM1.3形式のステータス文字列
	 * @exception S13LogFormatException
	 */
	public static String parseSuccessStatus( String strAiccStatus )
		throws S13LogFormatException
	{

		// パラメータチェック
		if( (strAiccStatus == null) || ("".equals(strAiccStatus) == true) ) {
			throw new S13LogFormatException(
				"Invalid Status : " + strAiccStatus );
		}

		// AICC2.xのステータス値をSCORM1.3の合格ステータス値に変換する
		String strStatus = "";

		strAiccStatus = strAiccStatus.toLowerCase();	// 小文字に変換
		char cstatus = strAiccStatus.charAt(0);

		if( (cstatus == 'n') || (cstatus == 'i') || (cstatus == 'c') ||
			(cstatus == 'b') ) {

			strStatus = "unknown";
		}
		else if (cstatus == 'p') {
			strStatus = "passed";
		}
		else if (cstatus == 'f') {
			strStatus = "failed";
		}
		else {
			throw new S13LogFormatException(
				"Invalid Status : " + strAiccStatus );
		}
		return strStatus;
	}

	/**
	 * AICC2.x形式のステータス文字列の先頭文字を判断してSCORM1.3
	 * 形式の完了ステータス文字列に変換する。
	 * 先頭文字が下記以外の（変換対象外）の文字列はエラーとする。
	 * <PRE>
	 *    n(not attempted)  →  unknown
	 *    i(incomplete)     →  incomplete
	 *    f(failed)         →  incomplete
	 *    c(completed)      →  completed
	 *    p(passed)         →  completed
	 *    b(browsed)        →  incomplete
	 * </PRE>
	 * @param strAiccStatus ステータス文字列
	 * @return String SCORM1.3形式のステータス文字列
	 * @exception S13LogFormatException
	 */
	public static String parseCompletionStatus( String strAiccStatus )
		throws S13LogFormatException
	{

		// パラメータチェック
		if( (strAiccStatus == null) || ("".equals(strAiccStatus) == true) ) {
			throw new S13LogFormatException(
				"Invalid Status : " + strAiccStatus );
		}

		// AICC2.xのステータス値をSCORM1.3の合格ステータス値に変換する
		String strStatus = "";

		strAiccStatus = strAiccStatus.toLowerCase();	// 小文字に変換
		char cstatus = strAiccStatus.charAt(0);

		if( cstatus == 'n' ) {
			strStatus = "unknown";
		}
		else if ((cstatus == 'i') || (cstatus == 'f') || (cstatus == 'b')) {
			strStatus = "incomplete";
		}
		else if ((cstatus == 'c') || (cstatus == 'p')) {
			strStatus = "completed";
		}
		else {
			throw new S13LogFormatException(
				"Invalid Status : " + strAiccStatus );
		}
		return strStatus;
	}

	/**
	 * SCORM1.3形式の２つのステータス文字列を判断して、AICC2.x形式の
	 * ステータス文字列に変換する。
	 * 下記以外の（変換対象外）の文字列はエラーとする。
	 * <PRE>
	 *    success_status  completion_status  
	 *        unknown         unknown        →  not attempted
	 *        unknown         incomplete     →  incomplete
	 *        unknown         completed      →  completed
	 *        failed          -              →  failed
	 *        passed          -              →  passed
	 * </PRE>
	 * @param strSuccessStatus 合格ステータス文字列
	 * @param strCompStatus 完了ステータス文字列
	 * @return String AICC2.x形式のステータス文字列
	 * @exception S13LogFormatException
	 */
	public static String parseAiccStatus(
			String strSuccessStatus, String strCompStatus)
		throws S13LogFormatException
	{

		// パラメータチェック
		// Success_statusのチェック
		if( (strSuccessStatus == null) || "".equals(strSuccessStatus)) {
			throw new S13LogFormatException(
				"Invalid Success_status : " + strSuccessStatus );
		}
		// Completion_statusのチェック
		if( (strCompStatus == null) || "".equals(strCompStatus)) {
			throw new S13LogFormatException(
				"Invalid Completion_status : " + strCompStatus );
		}

		String strStatus = "";

		// SCORM1.3のステータス値をAICC2.xステータス値に変換する
		if(("unknown".equalsIgnoreCase(strSuccessStatus) == true)
			&& ("unknown".equalsIgnoreCase(strCompStatus) == true)) {

				strStatus = "not attempted";
		}
		else if(("unknown".equalsIgnoreCase(strSuccessStatus) == true)
			&& ("incomplete".equalsIgnoreCase(strCompStatus) == true)) {

				strStatus = "incomplete";
			
		}
		else if(("unknown".equalsIgnoreCase(strSuccessStatus) == true)
			&& ("completed".equalsIgnoreCase(strCompStatus) == true)) {

				strStatus = "completed";
			
		}
		else if( "failed".equalsIgnoreCase(strSuccessStatus) == true ) {

				strStatus = "failed";
			
		}
		else if( "passed".equalsIgnoreCase(strSuccessStatus) == true ) {

				strStatus = "passed";
			
		}
		else {
			throw new S13LogFormatException(
				"Invalid Success_status : " + strSuccessStatus + CHAR_CRLF +
				"Invalid Completion_status : " + strCompStatus);
		}
		return strStatus;
	}

	/**
	 * AICC2.x形式のScoreのraw値を判断して、SCORM1.3形式のScoreのscaled値に
	 * 変換する。
	 * <PRE>
	 *    変換式
	 *      Scoreのraw値が-101以下、または101以上の場合
	 *        Scoreのscaled値 = 0（固定値）
	 *      Scoreのraw値が-100以上100以下の場合
	 *        Scoreのscaled値 = Scoreのraw値 / 100
	 * </PRE>
	 * @param strAiccScore String AICC2.xのScoreのraw値
	 * @return String SCORM1.3形式のScoreのscaled値
	 */
	public static String parseS13Score(String strAiccScore)
		throws S13LogFormatException
	{
		String strScore = "";
		// パラメータチェック
		// ScoreのRaw値のチェック
		if( (strAiccScore == null) || "".equals(strAiccScore)) {
			throw new S13LogFormatException(
				"Invalid Score raw : " + strAiccScore );
		}

		// AICC2.x形式のScoreのraw値からscaledの値を求める
		try {
			float fScoreRaw = Float.parseFloat(strAiccScore);
			if ((-100 <= fScoreRaw) && (fScoreRaw <= 100)) {
				fScoreRaw = fScoreRaw / 100;
			}
			else if ((fScoreRaw < -100) || (100 < fScoreRaw)) {
				fScoreRaw = 0;
			}
			strScore = Float.toString(fScoreRaw);
		}
		catch( NumberFormatException ne ) {
			throw new S13LogFormatException( ne.getMessage() );
		}
		return strScore;
	}

	/**
	 * スコア判定用のデータモデル名を取得する<br>
	 * @return String 合格判定用のデータモデル名
	 */
	public static String getCheckScoreName() {
		String strName;
		if (isScorm13() == true) {
			// 受信モデル種別が、SCORM1.3 モデルの場合
			strName = "core.score.scaled";
		}
		else {
			// 受信モデル種別が、AICC モデルの場合
			strName = "core.score.raw";
		}
		return strName;
	}

	/**
	 * 受信モデルの種別を設定する<br>
	 * SCORM1.3データモデルならtrue、AICC2.xデータモデルならfalseを
	 * 設定する<br>
	 * @param bType boolean データモデル種別
	 */
	public static void setScorm13(boolean bType) {
		m_bScorm13Type = bType;
	}

	/**
	 * 現在の受信モデルがSCORM1.3であるか確認する<br>
	 * SCORM1.3データモデルならtrue、AICC2.xデータモデルならfalseを
	 * 返却する<br>
	 * @return boolean データモデル種別
	 */
	public static boolean isScorm13() {
		return m_bScorm13Type;
	}

}
