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

// 
//	機能名称	
//		MI データモデル 評価データ( evaluationData ) クラス     
//
//		変更履歴	
//			2003.12.01 gxl 新規作成
//

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

import java.io.File;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;
//import java.util.StringTokenizer;

/**
 * CMI データモデル 評価データ( evaluationData ) クラス. <br>
 * @author gxl
 */
public class CMIEvaluationData extends CMIObjBase {

	/**
	 * CmiEvaluationDataクラスのコンストラクタ<br>		
	 */
	public CMIEvaluationData() {
		// オープン状態フラグを初期化(未オープンに)する
		m_isOpen = false;
		// プロトタイプデータをセットする
		m_proto = CMIElementProto.g_evaluationProto;
		// 子データモデルを生成する
		makeChildren(CMIElementProto.g_evaluationProto);	
	}

	/**			
	 * CmiEvaluationDataクラスのコンストラクタ<br>		
	 * @param cbt CMICBTオブジェクト
	 */		
	public CMIEvaluationData(CMICBT cbt) {
		// オープン状態フラグを(未オープンに)初期化する
		m_isOpen = false;	
		// プロトタイプデータをセットする
		m_proto = CMIElementProto.g_evaluationProto;
		// CBTオブジェクトをセットする
		m_CBT = cbt;						
		// 上記は、makeChildren より前にセットする必要がある。
		
		// 子データモデルを生成する
		makeChildren(CMIElementProto.g_evaluationProto);	
	}
	
	/**			
	 * デストラクタ <br>		
	 */		
	public void finalize() {
	}

	/**			
	 * セッションを開始　 <br>		
	 * @return 　String　CBT起動URL
	 */		
	public String open() {
		// CBTオブジェクトのオープンをコールする
		return m_CBT.open();	
	}
	
	/**			
	 * セッションを終了　 <br>		
	 */		
	public void close() {
		// CBTオブジェクトのクローズをコールする
		m_CBT.close();	
	}
	
	/**			
	 * 自オブジェクトのオープン処理を実行　 <br>		
	 */		
	public void myOpen() {
		// オープン状態フラグをオープン済みにする
		m_isOpen = true;	
	}

	/**		
	 * セッションを終了　 <br>	
	 */	
	public void myClose() {
		// オープン状態フラグを未オープンにする
		m_isOpen = false;		
	}
	
	/**			
	 * (LocalValueに)値を設定　 <br>		
	 * @param name String データモデルパス名
	 * @param value String データ値
	 */		
	public void setValue(String name, String value) {
		// エラー情報をクリアする
		m_CBT.clearError();

		if (!m_isOpen) {
			// オープン状態ならば、指定パスのエレメントに値をセットする
			CMIParameterPath param = new CMIParameterPath(name);
			String strDataModelName = param.popFirstElement();
			String strCategory = param.getNthElement(1);

			localSetValue(param.getPath(), value);
		}
		else {
			// 未オープン状態ならば、初期化エラーをセットする
			setError(CMIError.ERR_NOT_INITALIZED);
			setVendorError(getVendorData("CMIEvaluationData.setValue", this));
		}
	}
	
	/**			
	 * (ローカル値の)値を取得　 <br>
	 * @param name String データモデルパス名		
	 * @return 　String  データ値
	 */		
	public String getValue(String name) {
		// エラー情報をクリアする
		m_CBT.clearError();

		// 指定パスのエレメントの値を取得する
		String retStr = null;
		CMIParameterPath param = new CMIParameterPath(name);
		String strDataModelName = param.popFirstElement();
		String strCategory = param.getNthElement(1);

		retStr = localGetValue(param.getPath());
		// 取得した値を返す
		return retStr;
	}
	
	/**			
	 * AICCデータをPutParam のデータとして処理　 <br>		
	 * @param aiccData AICC データ		
	 * @param response レスポンス		
	 * @return 　int  HACPエラーコード		
	 */		
	public int doPutParam(String aiccData, StringBuffer response) {
		// データモデルからパラメータファイルの値を取得する
		String strCharFilePath = m_CBT.getLocalValue("evaluation.parameter");
		if ( strCharFilePath != null ) {
			// パラメータファイルが指定されているならば、そのファイルにAICCデータを
			// (上書き)保存する
			writeToFile(aiccData, "evaluation.parameter", ".PRM", false);
		}
		// エラーコード(成功)を返す
		return HACPError.HACP_ERR_SUCCESSFUL;
	}

	/**				
	* AICCデータをGetParam のデータとして処理､　 <br>			
	* EvaluationData における処理はない	
	* @param aiccData AICC データ			
	* @param response レスポンス			
	* @return 　int  HACPエラーコード			
	*/			
	public int doGetParam(String aiccData, StringBuffer response) {
		// エラーコード(成功)を返す
		return HACPError.HACP_ERR_SUCCESSFUL;
	}
	
	/**		
	*  AICCデータをPutComments のデータとして処理　 <br>	
	* @param aiccData AICC データ	
	* @param response レスポンス	
	* @return 　int  HACPエラーコード	
	*/	
	public int doPutComments(String aiccData, StringBuffer response) {
		
		int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;
		String strLineDelimiter = CMIUtil.checkLineDelimiter(aiccData);
		CMITokenizer tokenizer = new CMITokenizer(aiccData, strLineDelimiter);
		String strLine = null;
		CMICsvRow titleLine = new CMICsvRow();
		CMICsvRow dataLine = new CMICsvRow();

		// AICCデータを１行ずつ処理し、AICCデータがある間繰り返す
		for(int intLine = 0; tokenizer.hasMoreTokens();){	

			// カレント行を取得する
			strLine = tokenizer.nextToken();
			// カレント行がコメント行ならば、次の行を処理する
			if (CMIUtil.isComment(strLine)) {
				continue;
			}
			if (intLine == 0) {
				// カレントが先頭行ならば、カレント行をタイトル行とみなす
				titleLine.setCsvData(strLine);
			} else {
				// カレントが先頭行でなければ、カレント行をデータ行とみなす
				dataLine.setCsvData(strLine);
				// データ行の項目数を取得する
				int intCount = dataLine.getCount();	
				// evaluation.comments の最新の配列番号を取得する
				String strSubPath = "evaluation.comments";
				CMINode objectives_Node = (CMINode)getNChild(strSubPath);
				int intNum = objectives_Node.getChildCount();

				String strTitle = null;
				String strValue = null;
				String strDate = null;
				String strTime = null;
				// データ行の項目数分繰り返す
				for (int i = 0; i < intCount; i++) {
					// タイトル行からカレント項目のタイトルを取得する
					strTitle = titleLine.getNthItem(i);
					strTitle = strTitle.toLowerCase();
					
					// データ行からカレント項目のデータを取得する
					strValue = dataLine.getNthItem(i);

					// データ値が空データの場合、設定なしとして扱う
					if ("".equals(strValue) == true){
						// 次のデータ項目を取り出す
						continue;
					}

					// タイトルに相当するエレメントのパスを生成し、そのエレメントに
					// データをセットする
					//course_id
					if ("course_id".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".course_id";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					//student_id 
					else if ("student_id".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".student_id";
						objectives_Node.setLessonValue(strSubPath, strValue);
					} 
					//lesson_id
					else if ("lesson_id".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".lesson_id";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					//date
					else if ("date".equals(strTitle)) {
						strDate = strValue;
						strSubPath = String.valueOf(intNum) + ".date";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					//time
					else if ("time".equals(strTitle)) {
						strTime = strValue;
						strSubPath = String.valueOf(intNum) + ".time";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// SCORM1.3の日付形式に変換する
					if ((strDate != null) && (strTime != null))
					{
						try {
							strValue = CMIS13ModelUtil.parseS13Date(strDate,strTime);
							strSubPath = String.valueOf(intNum) + ".date";
							objectives_Node.setLessonValue(strSubPath, strValue);
						}
						catch (S13LogFormatException ex) {
							setError(CMIError.ERR_ELEMENT_TYPE_MISMATCH);

							// ベンダーエラーメッセージを作成する
							StringBuffer sbMsg = new StringBuffer();
							sbMsg.append("CMIEvaluationData.doPutComments");
							sbMsg.append("/");
							sbMsg.append(this.getPath() + "." + strSubPath);
							setVendorError(getVendorData(sbMsg.toString()));
							sbMsg.delete(0,sbMsg.length());
						}
						strTime = null;
						strDate = null;
					}
					//location
					else if ("location".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".location";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					//comment
					else if ("comment".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".content";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
				}
			}
			// カレント行のカウントをインクリメントする
			intLine++;	
		}
		// AICCデータをログファイルに書き出す
		if (getError() == CMIError.ERR_NO_ERROR){
			intErrCode = getPutComments("",response);
			writeToFile(response.toString(), "evaluation.comments", ".CMT", false);
			response.delete(0,response.length());
		}

		// 返却するエラーコードを判定する
		// 　エラーコードが No Error(0) の場合　　：成功      --> HACP_ERR_SUCCESSFUL(0)
		// 　エラーコードが No Error(0) 以外の場合：CMIエラー --> HACP_ERR_CMI(4)
		if (getError() != CMIError.ERR_NO_ERROR){
			intErrCode = HACPError.HACP_ERR_CMI;
		}
		return intErrCode;	
	}
	
	/**			
	*  AICCデータをPutInteractions のデータとして処理　 <br>		
	* @param aiccData AICC データ		
	* @param response レスポンス		
	* @return 　int  HACPエラーコード		
	*/
	public int doPutInteractions(String aiccData, StringBuffer response) {
		
		int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;
		String strLineDelimiter = CMIUtil.checkLineDelimiter(aiccData);
		CMITokenizer tokenizer = new CMITokenizer(aiccData, strLineDelimiter);
		String strLine = null;
		CMICsvRow titleLine = new CMICsvRow();
		CMICsvRow dataLine = new CMICsvRow();

		// AICCデータを１行ずつ処理し、AICCデータがある間繰り返す
		for ( int intLine = 0; tokenizer.hasMoreTokens(); ) {

			// カレント行を取得する
			strLine = tokenizer.nextToken();
			// カレント行がコメント行ならば、次の行を処理する
			if (CMIUtil.isComment(strLine)) {
				continue;
			}
			if (intLine == 0) {
				// カレントが先頭行ならば、カレント行をタイトル行とみなす
				titleLine.setCsvData(strLine);
			} else {
				// カレントが先頭行でなければ、カレント行をデータ行とみなす
				dataLine.setCsvData(strLine);
				// データ行の項目数を取得する
				int intCount = dataLine.getCount();	
				// evaluation.interactions の最新の配列番号を取得する
				String strSubPath = "interactions";
				CMINode objectives_Node = (CMINode)getNChild(strSubPath);
				int intNum = objectives_Node.getChildCount();

				String strTitle = null;
				String strValue = null;
				String strDate = null;
				String strTime = null;
				// データ行の項目数分繰り返す
				for (int i = 0; i < intCount; i++) {
					// タイトル行からカレント項目のタイトルを取得する
					strTitle = titleLine.getNthItem(i);
					strTitle = strTitle.toLowerCase();
					// データ行からカレント項目のデータを取得する
					strValue = dataLine.getNthItem(i);

					// データ値が空データの場合、設定なしとして扱う
					if ("".equals(strValue) == true){
						// 次のデータ項目を取り出す
						continue;
					}

					// タイトルに相当するエレメントのパスを生成し、そのエレメントに
					// データをセットする
					// course_id
					if ("course_id".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".course_id";
						objectives_Node.setLessonValue(strSubPath, strValue);
					} 
					// student_id
					else if ("student_id".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".student_id";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// lesson_id
					else if ("lesson_id".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".lesson_id";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// date
					else if ("date".equals(strTitle)) {
						strDate = strValue;
						strSubPath = String.valueOf(intNum) + ".date";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// time
					else if ("time".equals(strTitle)) {
						strTime = strValue;
						strSubPath = String.valueOf(intNum) + ".time";
						objectives_Node.setLessonValue(strSubPath, strValue);
					} 
					// SCORM1.3の日付形式に変換する
					if ((strDate != null) && (strTime != null))
					{
						try {
							strValue = CMIS13ModelUtil.parseS13Date(strDate,strTime);
							strSubPath = String.valueOf(intNum) + ".date";
							objectives_Node.setLessonValue(strSubPath, strValue);
						}
						catch (S13LogFormatException ex) {
							setError(CMIError.ERR_ELEMENT_TYPE_MISMATCH);

							// ベンダーエラーメッセージを作成する
							StringBuffer sbMsg = new StringBuffer();
							sbMsg.append("CMIEvaluationData.doPutInteractions");
							sbMsg.append("/");
							sbMsg.append(this.getPath() + "." + strSubPath);
							setVendorError(getVendorData(sbMsg.toString()));
							sbMsg.delete(0,sbMsg.length());
						}
						strTime = null;
						strDate = null;
					}
					// interaction_id
					else if ("interaction_id".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".id";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// objective_id
					else if ("objective_id".equals(strTitle)) {
						CMITokenizer inner_tokenizer = 
													new CMITokenizer(strValue, ";");
						for(int j=0; inner_tokenizer.hasMoreTokens(); j++){
							String val;
							strSubPath = String.valueOf(intNum) + ".objectives." 
																+ String.valueOf(j) + ".id";
							val = inner_tokenizer.nextToken();
							objectives_Node.setLessonValue(strSubPath, val);
						}
					}
					// type_interaction
					else if ("type_interaction".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".type";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// correct_response
					else if ("correct_response".equals(strTitle)) {
						CMITokenizer inner_tokenizer = new CMITokenizer(strValue, ";");
						for(int j=0; inner_tokenizer.hasMoreTokens(); j++){
							String val;
							strSubPath = String.valueOf(intNum) + ".correct_responses." 
													+ String.valueOf(j) + ".pattern";
							val = inner_tokenizer.nextToken();
							objectives_Node.setLessonValue(strSubPath, val);
						}
					}
					// student_response
					else if ("student_response".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".student_response";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// result
					else if ("result".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".result";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// weighting
					else if ("weighting".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".weighting";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// latency
					else if ("latency".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".latency";
						try {
							strValue = CMIS13ModelUtil.parseS13Timespan(strValue);
						}
						catch (S13LogFormatException ex) {
							setError(CMIError.ERR_ELEMENT_TYPE_MISMATCH);
							// ベンダーエラーメッセージを作成する
							StringBuffer sbMsg = new StringBuffer();
							sbMsg.append("CMIEvaluationData.doPutInteractions");
							sbMsg.append("/");
							sbMsg.append(this.getPath() + "." + strSubPath);
							setVendorError(getVendorData(sbMsg.toString()));
							sbMsg.delete(0,sbMsg.length());
						}
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
				}
			}
			// カレント行のカウントをインクリメントする
			intLine++;	
		}
		if (getError() == CMIError.ERR_NO_ERROR){
			intErrCode = getPutInteractions("",response);
			// AICCデータをログファイルに書き出す(追加)
			writeToFile(response.toString(), "evaluation.interactions", ".INT", false);
			response.delete(0,response.length());
		}
		// 返却するエラーコードを判定する
		// 　エラーコードが No Error(0) の場合　　：成功      --> HACP_ERR_SUCCESSFUL(0)
		// 　エラーコードが No Error(0) 以外の場合：CMIエラー --> HACP_ERR_CMI(4)
		if (getError() != CMIError.ERR_NO_ERROR){
			intErrCode = HACPError.HACP_ERR_CMI;
		}
		return intErrCode;	
	}
	
	/**				
	*  AICCデータをPutPerformance のデータとして処理　 <br>			
	* @param aiccData AICC データ			
	* @param response レスポンス			
	* @return 　int  HACPエラーコード			
	*/			
	public int doPutPerformance(String aiccData, StringBuffer response) {
		// AICCデータをログファイルに書き出す(追加)
		writeToFile(aiccData, "evaluation.performance", ".PFC", false);
		// エラーコード(成功)を返す
		return HACPError.HACP_ERR_SUCCESSFUL;		
	}

	/**			
	*  AICCデータをPutPath のデータとして処理　 <br>		
	* @param aiccData AICC データ		
	* @param response レスポンス		
	* @return 　int  HACPエラーコード		
	*/		
	public int doPutPath(String aiccData, StringBuffer response) {
		
		int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;
		String strLineDelimiter = CMIUtil.checkLineDelimiter(aiccData);
		CMITokenizer tokenizer = new CMITokenizer(aiccData, strLineDelimiter);
		String strLine = null;
		CMICsvRow titleLine = new CMICsvRow();
		CMICsvRow dataLine = new CMICsvRow();

		// AICCデータを１行ずつ処理し、AICCデータがある間繰り返す
		for(int intLine = 0; tokenizer.hasMoreTokens();){
			// カレント行を取得する
			strLine = tokenizer.nextToken();
			// カレント行がコメント行ならば、次の行を処理する
			if (CMIUtil.isComment(strLine)) {
				continue;
			}
			if (intLine == 0) {
				// カレントが先頭行ならば、カレント行をタイトル行とみなす
				titleLine.setCsvData(strLine);
			} else {
				// カレントが先頭行でなければ、カレント行をデータ行とみなす
				dataLine.setCsvData(strLine);
				// データ行の項目数を取得する
				int intCount = dataLine.getCount();
				// evaluation.objectives 最新の配列番号を取得する
				String strSubPath = "paths";
				CMINode objectives_Node = (CMINode)getNChild(strSubPath);
				int intNum = objectives_Node.getChildCount();

				String strTitle = null;
				String strValue = null;
				// データ行の項目数分繰り返す
				for (int i = 0; i < intCount; i++) {
					// タイトル行からカレント項目のタイトルを取得する
					strTitle = titleLine.getNthItem(i);
					// データ行からカレント項目のデータを取得する
					strValue = dataLine.getNthItem(i);		// データ取得

					// タイトルに相当するエレメントのパスを生成し、そのエレメントに
					// データをセットする
					// course_id
					if ("course_id".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".course_id";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// student_id
					else if ("student_id".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".student_id";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// lesson_id
					else if ("lesson_id".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".lesson_id";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// date
					else if ("date".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".date";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// time
					else if ("time".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".time";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// element_location
					else if ("element_location".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".location_id";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// status
					else if ("status".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".status";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// why_left
					else if ("why_left".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".why_left";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// time_in_element
					else if ("time_in_element".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".time_in_element";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
				}
			}
			// カレント行のカウントをインクリメントする
			intLine++;	
		}
		// AICCデータをログファイルに書き出す(追加)
		writeToFile(aiccData, "evaluation.path", ".PTH", true);
		// エラーコード(成功)を返す
		return intErrCode;		
	}
	
	/**			
	*  AICCデータをPutObjectives のデータとして処理　 <br>		
	* @param aiccData AICC データ		
	* @param response レスポンス		
	* @return 　int  HACPエラーコード		
	*/		
	public int doPutObjectives(String aiccData, StringBuffer response) {
		
		int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;
		String strLineDelimiter = CMIUtil.checkLineDelimiter(aiccData);
		CMITokenizer tokenizer = new CMITokenizer(aiccData, strLineDelimiter);
		String strLine = null;
		CMICsvRow titleLine = new CMICsvRow();
		CMICsvRow dataLine = new CMICsvRow();

		// AICCデータを１行ずつ処理し、AICCデータがある間繰り返す
		for(int intLine = 0; tokenizer.hasMoreTokens();){
			// カレント行を取得する
			strLine = tokenizer.nextToken();
			// カレント行がコメント行ならば、次の行を処理する
			if (CMIUtil.isComment(strLine)) {
				continue;
			}
			if (intLine == 0) {
				// カレントが先頭行ならば、カレント行をタイトル行とみなす
				titleLine.setCsvData(strLine);
			} else {
				// カレントが先頭行でなければ、カレント行をデータ行とみなす
				dataLine.setCsvData(strLine);
				// データ行の項目数を取得する
				int intCount = dataLine.getCount();

				// evaluation.objectives_status 最新の配列番号を取得する
				String strSubPath = "objectives_status";
				CMINode objectives_Node = (CMINode)getNChild(strSubPath);
				int intNum = objectives_Node.getChildCount();
				
				String strTitle = null;
				String strValue = null;
				// データ行の項目数分繰り返す
				for (int i = 0; i < intCount; i++) {
					// タイトル行からカレント項目のタイトルを取得する
					strTitle = titleLine.getNthItem(i);
					// データ行からカレント項目のデータを取得する
					// データ取得
					strValue = dataLine.getNthItem(i);

					// タイトルに相当するエレメントのパスを生成し、そのエレメントに
					// データをセットする
					// course_id
					if ("course_id".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".course_id";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// student_id
					else if ("student_id".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".student_id";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// lesson_id
					else if ("lesson_id".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".lesson_id";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// date
					else if ("date".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".date";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// time
					else if ("time".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".time";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// objective_id
					else if ("objective_id".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".id";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// score
					else if ("score".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".scores";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// status
					else if ("status".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".status";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
					// mastery_time
					else if ("mastery_time".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".mastery_time";
						objectives_Node.setLessonValue(strSubPath, strValue);
					}
				}
			}
			// カレント行のカウントをインクリメントする
			intLine++;	
		}
		// AICCデータをログファイルに書き出す(追加)
		writeToFile(aiccData, "evaluation.objectives_status", ".OBJ", true);
		// エラーコード(成功)を返す
		return intErrCode;		
	}
	
	/**			
	*  出力データをログファイルに書き出　 <br>		
	* @param aiccData AICC データ		
	* @param paramPath  出力パスのパラメータ名		
	* @param ext  出力ファイルの拡張子		
	* @param append  追加か上書きかのスイッチ		
	*/		
	private void writeToFile(String aiccData, String paramPath, 
										String ext, boolean append) {

		String strFilePath = null;
		//出力データ（コピー）
		String strOutData = null;
		
		String strLineDelimiter = null;
		int intDelimiterSize;
		
		// データモデルのログファイル名エレメントから値を取得する
		String charFilePath = m_CBT.getLocalValue(paramPath);

		if ( charFilePath != null && !"".equals(charFilePath)) {
			// 値が取得できたならば、その値をログファイルのパスとする
			strFilePath = charFilePath;
		}
		// filePath が空のときは、file_pathを使ってファイル名を作る
		if (strFilePath == null) {
			// ログファイルのパスが取得できていなければ ファイルパスの値から生成する
			// データモデルのファイルパス エレメントから値を取得する
			charFilePath = m_CBT.getLocalValue("evaluation.file_path");
			if (charFilePath != null) {
				// 値が取得できたならば、その値をログファイルのパスとする
				strFilePath = charFilePath;
			}
			if (strFilePath == null || "".equals(strFilePath)) {
				// ログファイルのパスが取得できていなければ、ブランクパスとする
			}
			// ログファイルのパスにエクステンションを付加する
			strFilePath += ext;
		}

		// AICCデータの行デリミタを取得する
		strLineDelimiter = CMIUtil.checkLineDelimiter(aiccData);
		intDelimiterSize = strLineDelimiter.length();
		// ファイルパスのファイルをオープンする			
		File logFile = new File(strFilePath);
		try {
			synchronized(this) {
				if ( append ) {
					// 追加タイプのデータならば、ファイルの有無にあわせて処理する
					boolean blnCanWrite = logFile.canWrite();
					if  ( blnCanWrite ) {
						// すでにファイルが存在するならば、先頭行は、出力せず、
						// データだけを保存する
						int head = aiccData.indexOf(strLineDelimiter);
						if (head != -1) {
							strOutData = aiccData.substring(head + intDelimiterSize);
						} else {
							strOutData = aiccData;
						}
					} else {
						strOutData = aiccData;
					}
				}
				else {
					// 追加タイプのデータでなければ、データで上書きする
					strOutData = aiccData;
				}
				// ファイルパスのディレクトリを生成する
				makeDirectories(strFilePath);			

				BufferedWriter bw = new BufferedWriter(new FileWriter(logFile, append));
				// ファイルがオープンできたならば、データをファイルに書き出す
				bw.write(strOutData, 0, strOutData.length());
				// 最後が改行でなければ、改行を出力
				String last2 = "";
				if (strOutData.length() >= intDelimiterSize) {
					last2 = strOutData.substring(strOutData.length() - intDelimiterSize);
				}
				if (!last2.equals(strLineDelimiter)) {
					bw.write(strLineDelimiter, 0, strLineDelimiter.length());
				}
				// ファイルをクローズする
				bw.flush();
				bw.close();
			}
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}	
	}

	/**						
	*  ディレクトリを作成　 <br>					
	* @param path パス					
	*/					
	private void makeDirectories(String path) {
		
		String strFilePath = null;
		String strFile = null;
		int lastSeparator = path.lastIndexOf(File.separator);
		if (lastSeparator != -1) {				
			strFilePath = path.substring(0, lastSeparator);
			strFile = path.substring(lastSeparator + 1);
		} else {
			strFile = path;
		}
		
		try{
			if (strFilePath != null) {
				File dirs = new File(strFilePath);
				if (!dirs.exists()){
					if ( !dirs.mkdirs() ) {

					}
				}
			}
			 
			if ( strFile != null && !"".equals(strFile) ) {
				File nfile = new File(path);
				if ( !nfile.exists() ) {
					if ( !nfile.createNewFile() ) {

					}
				}
			}
		} catch ( SecurityException se ) {

		} catch ( IOException se ) {

		}
	}

	/**			
	 * 指定されたパラメータログ出力用のHACPフォーマットのSCORM1.3データをログ出力する。<br>
	 * @param scoData String SCORM1.3 データ		
	 * @param response StringBuffer 応答データ（未使用 I/F共通化のため実装）
	 * @return 　int  HACPエラーコード
	 */		
	public int doPutParamToS13(String scoData, StringBuffer response) {
		// データモデルからパラメータファイルの値を取得する
		String strCharFilePath = m_CBT.getLocalValue("evaluation.parameter");
		if ( strCharFilePath != null ) {
			// パラメータファイルが指定されているならば、そのファイルにSCORM1.3
			// データを(上書き)保存する
			writeToFile(scoData, "evaluation.parameter", ".prm", false);
		}
		// エラーコード(成功)を返す
		return HACPError.HACP_ERR_SUCCESSFUL;		
	}

	/**
	 * PutCommentsコマンドで受信したHACPフォーマットのSCORM1.3データを内部メモリへ
	 * 保管する。内部メモリに保管後、その保管データを取り出しログ出力する。<br>
	 * @param scoData SCORM1.3 データ	
	 * @param response 応答データ（未使用 I/F共通化のため実装）
	 * @return 　int  HACPエラーコード	
	 */	
	public int doPutCommentsToS13(String scoData, StringBuffer response) {
		
		int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;
		String strLineDelimiter = CMIUtil.checkLineDelimiter(scoData);
		CMITokenizer tokenizer = new CMITokenizer(scoData, strLineDelimiter);
		String strLine = null;
		CMICsvRow titleLine = new CMICsvRow();
		CMICsvRow dataLine = new CMICsvRow();

		// SCORM1.3データを１行ずつ処理し、AICCデータがある間繰り返す
		for(int intLine = 0; tokenizer.hasMoreTokens();){	

			// カレント行を取得する
			strLine = tokenizer.nextToken();
			// カレント行がコメント行ならば、次の行を処理する
			if (CMIUtil.isComment(strLine)) {
				continue;
			}
			if (intLine == 0) {
				// カレントが先頭行ならば、カレント行をタイトル行とみなす
				titleLine.setCsvData(strLine);
			} else {
				// カレントが先頭行でなければ、カレント行をデータ行とみなす
				dataLine.setCsvData(strLine);
				// データ行の項目数を取得する
				int intCount = dataLine.getCount();	
				// evaluation.comments の最新の配列番号を取得する
				String strSubPath = "evaluation.comments";
				CMINode comments_Node = (CMINode)getNChild(strSubPath);
				int intNum = comments_Node.getChildCount();

				String strTitle = null;
				String strValue = null;
				// データ行の項目数分繰り返す
				for (int i = 0; i < intCount; i++) {
					// タイトル行からカレント項目のタイトルを取得する
					strTitle = titleLine.getNthItem(i);
					strTitle = strTitle.toLowerCase();
					// データ行からカレント項目のデータを取得する
					strValue = dataLine.getNthItem(i);

					// データ値をUTF-8でURLデコードし、内部保管する
					strValue = CMIUtil.urlDecode(strValue);

					// タイトルに相当するエレメントのパスを生成し、そのエレメントに
					// データをセットする
					//date
					if ("date".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".date";
						comments_Node.setLessonValue(strSubPath, strValue);
					}
					//location
					else if ("location".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".location";
						comments_Node.setLessonValue(strSubPath, strValue);
					}
					//comment
					else if ("comment".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".content";
						comments_Node.setLessonValue(strSubPath, strValue);
					}
				}
			}
			// カレント行のカウントをインクリメントする
			intLine++;	
		}
		intErrCode = getPutComments("",response);
		if (intErrCode == HACPError.HACP_ERR_SUCCESSFUL) {
			// SCORM1.3データをログファイルに書き出す(追加)
			scoData = response.toString();
			response.delete(0,response.length());
			writeToFile(scoData, "evaluation.comments", ".cmt", false);
		}
		// エラーコード(成功)を返す
		return intErrCode;	
	}
	
	/**			
	 * PutInteractionsコマンドで受信したHACPフォーマットのSCORM1.3データを
	 * 内部メモリへ保管する。内部メモリに保管後、その保管データを取り出し
	 * ログ出力する。<br>
	 * @param scoData SCORM1.3 データ
	 * @param response レスポンス（未使用 I/F共通化のために定義）
	 * @return 　int  HACPエラーコード		
	 */
	public int doPutInteractionsToS13(String scoData, StringBuffer response) {
		
		int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;
		String strLineDelimiter = CMIUtil.checkLineDelimiter(scoData);
		CMITokenizer tokenizer = new CMITokenizer(scoData, strLineDelimiter);
		String strLine = null;
		CMICsvRow titleLine = new CMICsvRow();
		CMICsvRow dataLine = new CMICsvRow();

		// SCORM1.3データを１行ずつ処理し、SCORM1.3データがある間繰り返す
		for ( int intLine = 0; tokenizer.hasMoreTokens(); ) {

			// カレント行を取得する
			strLine = tokenizer.nextToken();
			// カレント行がコメント行ならば、次の行を処理する
			if (CMIUtil.isComment(strLine)) {
				continue;
			}
			if (intLine == 0) {
				// カレントが先頭行ならば、カレント行をタイトル行とみなす
				titleLine.setCsvData(strLine);
			} else {
				// カレントが先頭行でなければ、カレント行をデータ行とみなす
				dataLine.setCsvData(strLine);
				// データ行の項目数を取得する
				int intCount = dataLine.getCount();	
				// evaluation.interactions の最新の配列番号を取得する
				String strSubPath = "evaluation.interactions";
				CMINode interactions_Node = (CMINode)getNChild(strSubPath);
				int intNum = interactions_Node.getChildCount();

				String strTitle = null;
				String strValue = null;
				// データ行の項目数分繰り返す
				for (int i = 0; i < intCount; i++) {
					// タイトル行からカレント項目のタイトルを取得する
					strTitle = titleLine.getNthItem(i);
					strTitle = strTitle.toLowerCase();
					// データ行からカレント項目のデータを取得する
					strValue = dataLine.getNthItem(i);

					// データ値をUTF-8でURLデコードし、内部保管する
					strValue = CMIUtil.urlDecode(strValue);

					// タイトルに相当するエレメントのパスを生成し、そのエレメントに
					// データをセットする
					// date
					if ("date".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".date";
						interactions_Node.setLessonValue(strSubPath, strValue);
					}
					// interaction_id
					else if ("interaction_id".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".id";
						interactions_Node.setLessonValue(strSubPath, strValue);
					}
					// objective_id
					else if ("objective_id".equals(strTitle)) {
						CMITokenizer inner_tokenizer = 
													new CMITokenizer(strValue, ";");
						for(int j=0; inner_tokenizer.hasMoreTokens(); j++){
							String val;
							strSubPath = String.valueOf(intNum) + ".objectives." 
																+ String.valueOf(j) + ".id";
							val = inner_tokenizer.nextToken();
							interactions_Node.setLessonValue(strSubPath, val);
						}
					}
					// type_interaction
					else if ("type_interaction".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".type";
						interactions_Node.setLessonValue(strSubPath, strValue);
					}
					// correct_response
					else if ("correct_response".equals(strTitle)) {
						CMITokenizer inner_tokenizer = new CMITokenizer(strValue, ";");
						for(int j=0; inner_tokenizer.hasMoreTokens(); j++){
							String val;
							strSubPath = String.valueOf(intNum) + ".correct_responses." 
													+ String.valueOf(j) + ".pattern";
							val = inner_tokenizer.nextToken();
							interactions_Node.setLessonValue(strSubPath, val);
						}
					}
					// student_response
					else if ("student_response".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".student_response";
						interactions_Node.setLessonValue(strSubPath, strValue);
					}
					// result
					else if ("result".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".result";
						interactions_Node.setLessonValue(strSubPath, strValue);
					}
					// weighting
					else if ("weighting".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".weighting";
						interactions_Node.setLessonValue(strSubPath, strValue);
					}
					// latency
					else if ("latency".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".latency";


						interactions_Node.setLessonValue(strSubPath, strValue);
					}
					// description
					else if ("description".equals(strTitle)) {
						strSubPath = String.valueOf(intNum) + ".description";
						interactions_Node.setLessonValue(strSubPath, strValue);
					}
				}
			}
			// カレント行のカウントをインクリメントする
			intLine++;	
		}
		intErrCode = getPutInteractions("",response);
		if (intErrCode == HACPError.HACP_ERR_SUCCESSFUL) {
			scoData = response.toString();
			response.delete(0,response.length());
			writeToFile(scoData, "evaluation.interactions", ".int", false);
		}
		// エラーコード(成功)を返す
		return intErrCode;	
	}

	/**
	 * 内部メモリへ保持しているPutCommentsコマンドで受信したHACPフォーマット
	 * のSCORM1.3データを取得する。<br>
	 * @param scoData String SCORM1.3 データ
	 * @param response String 取得したComments from Learnerデータ
	 * @return 　int  HACPエラーコード	
	 */	
	private int getPutComments(String scoData, StringBuffer response) {
		
		int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;

		//	"cmi.comments_from_learner"
		String strSubPath = "evaluation.comments";
		CMINode comments_Node = (CMINode)getNChild(strSubPath);

		// Comment from Learnerデータの件数を取得する
		//	"comments_from_learner._count"
		int intNum = comments_Node.getChildCount();

		// タイトル行を作成する
		String strTitleLine = "\"Date\",\"Location\",\"Comment\"";
		strTitleLine = strTitleLine + CMIElement.STR_CRLF;
		response.append(strTitleLine);

		// SCORM1.3のCommentデータを１行ずつ処理し、AICCデータフォーマットを作成する
		for(int i = 0; i < intNum; i++){

			String strValue = null;

			// タイトルに相当するエレメントのパスを生成し、そのエレメントに
			// データをセットする
			//date
			strSubPath = String.valueOf(i) + ".date";
			strValue = comments_Node.getLessonValue(strSubPath);
			if (strValue == null) {
				strValue = "";
			}
			// 文字コードをUTF-8にエンコードする
			strValue = CMIUtil.urlEncode(strValue);
			response.append("\"" + strValue + "\",");
	
			//location
			strSubPath = String.valueOf(i) + ".location";
			strValue = comments_Node.getLessonValue(strSubPath);
			if (strValue == null) {
				strValue = "";
			}
			// 文字コードをUTF-8にエンコードする
			strValue = CMIUtil.urlEncode(strValue);
			response.append("\"" + strValue + "\",");
	
			//comment
			strSubPath = String.valueOf(i) + ".content";
			strValue = comments_Node.getLessonValue(strSubPath);
			if (strValue == null) {
				strValue = "";
			}
			// 文字コードをUTF-8にエンコードする
			strValue = CMIUtil.urlEncode(strValue);
			response.append("\"" + strValue + "\"" + CMIElement.STR_CRLF);
		}
		// エラーコード(成功)を返す
		return intErrCode;	
	}

	/**
	 * 内部メモリへ保持しているPutInteractionsコマンドで受信したHACP
	 * フォーマットのSCORM1.3データを取得する。<br>
	 * @param scoData String SCORM1.3 データ
	 * @param response String 取得したinteractionsデータ
	 * @return 　int  HACPエラーコード	
	 */	
	private int getPutInteractions(String scoData, StringBuffer response) {
		
		int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;

		//	"cmi.interactions"
		String strSubPath = "evaluation.interactions";
		CMINode interactions_Node = (CMINode)getNChild(strSubPath);

		// Interactionsデータの件数を取得する
		//	"cmi.interactions._count"
		int intNum = interactions_Node.getChildCount();

		// タイトル行を作成する
		String strTitleLine = "\"Date\",\"Interaction_ID\",\"Objective_ID\",";
		strTitleLine = strTitleLine + "\"Type_Interaction\",";
		strTitleLine = strTitleLine + "\"Correct_Response\",";
		strTitleLine = strTitleLine + "\"Student_Response\",";
		strTitleLine = strTitleLine + "\"Result\",\"Weighting\",";
		strTitleLine = strTitleLine + "\"Latency\",\"Description\"";
		strTitleLine = strTitleLine + CMIElement.STR_CRLF;
		response.append(strTitleLine);

		// SCORM1.3のInteractionsデータを１行ずつ処理し、AICCデータフォーマットを作成する
		for(int i = 0; i < intNum; i++){

			String strValue = null;

			// インタラクションに該当するタイトルに相当するエレメントのパスを生成し、そのエレメントに
			// データをセットする
			//timestamp
			strSubPath = String.valueOf(i) + ".date";
			strValue = interactions_Node.getLessonValue(strSubPath);
			if (strValue == null) {
				strValue = "";
			}
			// 文字コードをUTF-8にエンコードする
			strValue = CMIUtil.urlEncode(strValue);
			response.append("\"" + strValue + "\",");

			//interaction_id
			strSubPath = String.valueOf(i) + ".id";
			strValue = interactions_Node.getLessonValue(strSubPath);
			response.append("\"" + strValue + "\",");

			//cmi.interactions.n.objectives
			strSubPath = String.valueOf(i) + ".objectives";
			CMINode objectives_Node = (CMINode)interactions_Node.getNChild(strSubPath);
	
			// ObjectivesIDデータの件数を取得する
			//	"cmi.interactions.n.objectives._count"
			int intNum2 = objectives_Node.getChildCount();
			// ObjectivesIDを１件ずつ処理し、AICCデータフォーマットを作成する
			response.append("\"");
			for(int j = 0; j < intNum2; j++){
				
				//objective_id
				strSubPath = String.valueOf(j) + ".id";
				strValue = objectives_Node.getLessonValue(strSubPath);
				if (strValue == null) {
					strValue = "";
				}
				// 文字コードをUTF-8にエンコードする
				strValue = CMIUtil.urlEncode(strValue);
				response.append(strValue + CMIUtil.urlEncode(";"));
			}
			response.append("\",");

			//type_interaction
			strSubPath = String.valueOf(i) + ".type";
			strValue = interactions_Node.getLessonValue(strSubPath);
			if (strValue == null) {
				strValue = "";
			}
			// 文字コードをUTF-8にエンコードする
			strValue = CMIUtil.urlEncode(strValue);
			response.append("\"" + strValue + "\",");
	
			//cmi.interactions.n.correct_responses
			strSubPath = String.valueOf(i) + ".correct_responses";
			CMINode correct_Node = (CMINode)interactions_Node.getNChild(strSubPath);
	
			// Correct_Responseデータの件数を取得する
			//	"cmi.interactions.n.correct_responses._count"
			intNum2 = correct_Node.getChildCount();
			// Correct_Responseを１件ずつ処理し、AICCデータフォーマットを作成する
			response.append("\"");
			for(int j = 0; j < intNum2; j++){
				
				//correct_response
				strSubPath = String.valueOf(j) + ".pattern";
				strValue = correct_Node.getLessonValue(strSubPath);
				if (strValue == null) {
					strValue = "";
				}
				// 文字コードをUTF-8にエンコードする
				strValue = CMIUtil.urlEncode(strValue);
				response.append(strValue + CMIUtil.urlEncode(";"));
	
			}
			response.append("\",");
	
			strSubPath = String.valueOf(i) + ".student_response";
			strValue = interactions_Node.getLessonValue(strSubPath);
			if (strValue == null) {
				strValue = "";
			}
			// 文字コードをUTF-8にエンコードする
			strValue = CMIUtil.urlEncode(strValue);
			response.append("\"" + strValue + "\",");
	
			strSubPath = String.valueOf(i) + ".result";
			strValue = interactions_Node.getLessonValue(strSubPath);
			if (strValue == null) {
				strValue = "";
			}
			// 文字コードをUTF-8にエンコードする
			strValue = CMIUtil.urlEncode(strValue);
			response.append("\"" + strValue + "\",");
	
			strSubPath = String.valueOf(i) + ".weighting";
			strValue = interactions_Node.getLessonValue(strSubPath);
			response.append("\"" + strValue + "\",");
	
			strSubPath = String.valueOf(i) + ".latency";
			strValue = interactions_Node.getLessonValue(strSubPath);
			response.append("\"" + strValue + "\",");
	
			strSubPath = String.valueOf(i) + ".description";
			strValue = interactions_Node.getLessonValue(strSubPath);
			if (strValue == null) {
				strValue = "";
			}
			// 文字コードをUTF-8にエンコードする
			strValue = CMIUtil.urlEncode(strValue);
			response.append("\"" + strValue + "\"" + CMIElement.STR_CRLF);
		}
		// エラーコード(成功)を返す
		return intErrCode;	
	}

}