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

//
//機能名称 
//		  PutParam用情報取得のクラス
//変更履歴
//			  2003.11.24	gxl  新規作成		
//
package jp.co.ntt.lms.lo.scorm.cbtcom;

//import java.util.StringTokenizer;
import java.util.NoSuchElementException;

//import jp.co.ntt.lms.lo.scorm.cbtcom.CMIS13Error;

/**
 * PutParam用情報取得のクラス
 * @version 0.1.0
 * @author gxl
 * 
 */
public class MaintenancePutParam implements IMaintenancePutParam {
	
	/**
	 * データモデル区分
	 */
	private String modal = null;
   
	/**
     * MaintenancePutParamクラスのコンストラクタ<br>
     * @param inModal データモデル
     */
	public MaintenancePutParam(String inModal) {
    	modal = inModal;
	}
   
	/**
     * PutParamメソッド<br>
     * @param element　エレメント
     * @param data　設定の値
     * @return エラーコード
     */
	public int putParam(CMIElement element, StringBuffer data) {
    	if ( "putElement".equals( modal ) ) {
    		return putElement( element, data );
    	} else if ( "putLesson".equals( modal ) ) {
    		return putLesson();
    	} else if ( "putExit".equals( modal ) ) {
    		return putExit();
    	} else if ( "putScore".equals( modal ) ) {
    		return putScore();
    	} else if ( "putCoreGroup".equals( modal ) ) {
    		return putCoreGroup( element, data );
    	} else if ( "putCoreLessonGroup".equals( modal ) ) {
    		return putCoreLessonGroup( element, data );
    	} else if ( "putCommentsGroup".equals( modal ) ) {
			return putCommentsGroup( element, data );
		} else if ( "putObjectivesStatusGroup".equals( modal ) ) {
			return putObjectivesStatusGroup( element, data );
		} else if ( "putStudentDataGroup".equals( modal ) ) {
			return putStudentDataGroup( element, data );
		} else if ( "putStudentPreferencesGroup".equals( modal ) ) {
			return putStudentPreferencesGroup( element, data );
		} else if ( "putGroup".equals( modal ) ) {
			return putGroup( element, data );
		} else {
			return HACPError.HACP_ERR_SUCCESSFUL;
		}
	}
   
	/**
     * putElementメソッド<br>
     * @param element　エレメント
     * @param data　設定の値
     * @return エラーコード
     */
	private int putElement(CMIElement element, StringBuffer data) {
		element.localSetValue(element.getName(), data.toString(), false);
		return HACPError.HACP_ERR_SUCCESSFUL;
	}
   
	/**
     * putLessonメソッド<br>
     * @return エラーコード
     */
	private int putLesson() {
		return HACPError.HACP_ERR_SUCCESSFUL;
	}
   
	/**
     * putExitメソッド<br>
     * @return エラーコード
     */
	private int putExit() {
		return HACPError.HACP_ERR_SUCCESSFUL;
	}
   
	/**
     * putScoreメソッド<br>
     * @return エラーコード
     */
	private int putScore() {
		return HACPError.HACP_ERR_SUCCESSFUL;
	}
   
	/**
	 * Core グループの putParam<br>
	 * @param element CMIElement データモデルオブジェクト
	 * @param data　StringBuffer 設定値
	 * @return HACPエラーコード
	 */
	private int putCoreGroup(CMIElement element, StringBuffer data) {

		int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;
		if (CMIS13ModelUtil.isScorm13() != true) {
			// クライアントからのAICC2.x形式での受信要求である場合
			intErrCode = putCoreGroupForAICC(element, data);
		}
		else {
			// クライアントからのSCORM1.3形式での受信要求である場合
			intErrCode = putCoreGroupForSCORM(element, data);
		}
		return intErrCode;
	}

	/**
	 * AICC2.x用のPutParamコマンド（HACP通信）形式で指定された
	 * Core グループの情報を内部メモリに設定する。<br>
	 * @param element CMIElement データモデルオブジェクト
	 * @param data StringBuffer Coreグループ情報
	 * @return int HACPエラーコード
	 */
	private int putCoreGroupForAICC(CMIElement element, StringBuffer data) {

		int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;	

		CMINode node = null;

		if ( ( element ) instanceof CMINode ) {
			node = (CMINode)element;
		}

		boolean blnCbtV3 = element.isV3Above();

		String strLineDelimiter = CMIUtil.checkLineDelimiter(data.toString());

		// 必須項目チェックフラグを初期化
		// Lesson_Location
		boolean bln_Lesson_Location = false;
    	// Lesson_Status
		boolean bln_Lesson_Status = false;
		// Score
		boolean bln_Score = false;
		// Time
		boolean bln_Time = false;

		if (node != null) {
			CMITokenizer tokenizer = new CMITokenizer(data.toString(), strLineDelimiter);
			CMITokenizer pairDivider;
			CMIElement	child = null;
			String strLine = null;
			String strKeyWord = null;
			String strValue = null;
			String strSubpath = null;

			while(tokenizer.hasMoreTokens()) {
				// カレント行を取得する
				strLine = tokenizer.nextToken();
				// カレント行がコメント行 かつ 最終行でなければ、次の行を処理する
				if (CMIUtil.isComment(strLine)) {
					continue;
				}
				pairDivider = new CMITokenizer(strLine, "=");
				strKeyWord = pairDivider.nextToken();
				strValue = pairDivider.nextToken();

				strKeyWord = strKeyWord.toLowerCase();
				if ("lesson_location".equals(strKeyWord)) {
					// 必須項目マーク
					bln_Lesson_Location = true;		
					strSubpath = "lesson_location";
					child = node.getChild(strSubpath);
					child.setLessonValue(strValue);
					if (blnCbtV3) {
						child.setLocalValue(strValue);
					}
				} else if ("lesson_status".equals(strKeyWord)) {
					// 必須項目マーク
					bln_Lesson_Status = true;		
					CMITokenizer tokenValue = new CMITokenizer(strValue, ",");
					String strVal;

					if (tokenValue.hasMoreTokens()) {
						strVal = tokenValue.nextToken();

						// lesson_status/success_status
						strSubpath = "lesson_status";
						try {
							// バージョンがAICCのときにsuccess_statusの
							// SCORM1.3用データにパースする
							strVal = CMIS13ModelUtil.parseSuccessStatus(strVal);
						}
						catch( S13LogFormatException exp ) {
							element.setError(CMIError.ERR_INCORRECT_DATA_TYPE);
							element.setVendorError("SCORM 1.3 Format Error[" + strSubpath + "]");
						}
						child = node.getChild(strSubpath);
						child.setLessonValue(strVal);
						if (blnCbtV3) {
							child.setLocalValue(strVal);
						}

						// completion_status
						strSubpath = "completion_status";
						try {
							// バージョンがAICCのときにcompletion_statusの
							// SCORM1.3用データにパースする
							strVal = CMIS13ModelUtil.parseCompletionStatus(strVal);
						}
						catch( S13LogFormatException exp ) {
							element.setError(CMIError.ERR_INCORRECT_DATA_TYPE);
							element.setVendorError("SCORM 1.3 Format Error[" + strSubpath + "]");
						}
						child = node.getChild(strSubpath);
						child.setLessonValue(strVal);
						if (blnCbtV3) {
							child.setLocalValue(strVal);
						}
					}

					strSubpath = "exit";
					strVal = "";
					if (tokenValue.hasMoreTokens()) {
						strVal = tokenValue.nextToken();
					}
					child = node.getChild(strSubpath);
					child.setLessonValue(strVal);
					if (blnCbtV3) {
						child.setLocalValue(strVal);
					}
				} else if ("score".equals(strKeyWord)) {
					// 必須項目マーク
					bln_Score = true;		
					CMITokenizer tokenValue = new CMITokenizer(strValue, ",");
					String val;

					// score.scaled/score.raw
					if (tokenValue.hasMoreTokens()) {
						val = tokenValue.nextToken();
						strSubpath = "score.raw";
						child = node.getNChild(strSubpath);
						child.setLessonValue(val);
						if (blnCbtV3) {
							child.setLocalValue(val);
						}
						strSubpath = "score.scaled";
						try {
							val = CMIS13ModelUtil.parseS13Score(val);
						}
						catch( S13LogFormatException exp ) {
							element.setError(CMIError.ERR_INCORRECT_DATA_TYPE);
							element.setVendorError("SCORM 1.3 Format Error[" + strSubpath + "]");
						}
						child = node.getNChild(strSubpath);
						child.setLessonValue(val);
						if (blnCbtV3) {
							child.setLocalValue(val);
						}
					}

					// score.max
					strSubpath = "score.max";
					if (tokenValue.hasMoreTokens()) {
						val = tokenValue.nextToken();
						child = node.getNChild(strSubpath);
						child.setLessonValue(val);
						if (blnCbtV3) {
							child.setLocalValue(val);
						}
					}

					// score.min
					strSubpath = "score.min";
					if (tokenValue.hasMoreTokens()) {
						val = tokenValue.nextToken();
						child = node.getNChild(strSubpath);
						child.setLessonValue(val);
						if (blnCbtV3) {
							child.setLocalValue(val);
						}
					}
				} else if ("time".equals(strKeyWord)) {
					// 必須項目マーク
					bln_Time = true;		
					// session_time
					strSubpath = "session_time";
					child = node.getChild(strSubpath);
					try {
						strValue = CMIS13ModelUtil.parseS13Timespan(strValue);
					}
					catch( S13LogFormatException exp ) {
						element.setError(CMIError.ERR_INCORRECT_DATA_TYPE);
						element.setVendorError("SCORM 1.3 Format Error[" + strSubpath + "]");
					}
					child.setLessonValue(strValue);
					if (blnCbtV3) {
						child.setLocalValue(strValue);
					}
				} else {
					// warning
					int ecode = element.getError();
					if (ecode == CMIError.ERR_NO_ERROR) {
						element.setError(CMIError.WARNING_INVALID_DATANAME);
						element.setVendorError("Invalid DataName[" + strKeyWord + "]");
					}
					// HACPError にはしない。
					// errCode = HACP_ERR_INVALID_COMMAND;
				}
			}
		}

		// 必須項目名の最終チェック
		int intEcode = element.getError();
		if (intEcode == CMIError.ERR_NO_ERROR) {
			if (!bln_Lesson_Location) {		// Lesson_Location
				element.setError(CMIError.WARNING_INSUFFICIENT_DATANAME);
				element.setVendorError("Insufficient DataName[Lesson_Location]");
			} else if (!bln_Lesson_Status) {	// Lesson_Status
				element.setError(CMIError.WARNING_INSUFFICIENT_DATANAME);
				element.setVendorError("Insufficient DataName[Lesson_Status]");
			} else if (!bln_Score) {			// Score
				element.setError(CMIError.WARNING_INSUFFICIENT_DATANAME);
				element.setVendorError("Insufficient DataName[Score]");
			} else if (!bln_Time) {			// Time
				element.setError(CMIError.WARNING_INSUFFICIENT_DATANAME);
				element.setVendorError("Insufficient DataName[Time]");
			}
		}
		return intErrCode;
	}

	/**
	 * CoreLessonグループの putParam<br>
	 * @param element　エレメント
	 * @param data　設定の値
	 * @return エラーコード
	 */
	private int putCoreLessonGroup(CMIElement element, StringBuffer data) {

		int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;
		//	顧客要望により元に戻す。
		boolean blnCbtV3 = element.isV3Above();

		element.setLessonValue(data.toString());
		//if (blnCbtV3) {
			element.setLocalValue(data.toString());
		//}
		return intErrCode;
	}
   
	/**
	 * commentsグループの putParam<br>
	 * @param element　エレメント
	 * @param data　設定の値
	 * @return エラーコード
	 */
	private int putCommentsGroup(CMIElement  element, StringBuffer data) {

	    int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;
		//	顧客要望により元に戻す。
		boolean blnCbtV3 = element.isV3Above();

		element.setLessonValue(data.toString());
		if (blnCbtV3) {
			element.setLocalValue(data.toString());
		}
		return intErrCode;
	}

	/**
	 * SCORM1.3用のPutParamコマンド（HACP通信）形式で指定された
	 * Objectives Status グループの情報を内部メモリに設定する。<br>
	 * @param element CMIElement データモデルオブジェクト
	 * @param data StringBuffer Objectives_Statusグループ情報
	 * @return int HACPエラーコード
	 */
	private int putObjectivesStatusGroup(CMIElement element, StringBuffer data) {

		int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;
		if (CMIS13ModelUtil.isScorm13() != true) {
			// クライアントからのAICC2.x形式での受信要求である場合
			intErrCode = putObjectivesStatusGroupForAICC(element, data);
		}
		else {
			// クライアントからのSCORM1.3形式での受信要求である場合
			intErrCode = putObjectivesStatusGroupForSCORM(element, data);
		}
		return intErrCode;
	}

	/**
	 * AICC2.x用のPutParamコマンド（HACP通信）形式で指定された
	 * Objectives Status グループの情報を内部メモリに設定する。<br>
	 * @param element CMIElement データモデルオブジェクト
	 * @param data StringBuffer Objectives_Statusグループ情報
	 * @return int HACPエラーコード
	 */
	private int putObjectivesStatusGroupForAICC(CMIElement element, StringBuffer data) {

	    int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;
		CMINode node = null;

		if ( ( element ) instanceof CMINode ) {
			node = (CMINode)element;
		}

		boolean blnCbtV3 = element.isV3Above();
		String strLineDelimiter = CMIUtil.checkLineDelimiter(data.toString());

		int version = element.getVersion();

		if (node != null) {
			CMITokenizer strTokenizer = new CMITokenizer(data.toString(), strLineDelimiter);
			CMITokenizer strPairDivider;
			CMITokenizer strPairKeyWord;
			String strLine = null;
			String strKeyWord = null;
			String strNArrayID = null;
			String strCurArrayID = null;
			String strValue = null;
			String strSubpath = null;
			CMINode	cmiCurNode = null;
			CMIArrayNode attemptsNode = null;
			boolean bTopAdd;

			int intSelectMode = 0;

			//現在扱っているJ_IDのattemptsノードを初期化済みならtrue
			//初期化していないならfalse
			//古いscoreとstatusが中途半端に残ることを防ぐために使用
			//Ver3.0以下のときのみ使用する
			//Ver3.5以上のケースは今回の改修対象外であるため
			boolean bIsClearedAttempt = false;

			while (strTokenizer.hasMoreTokens()) {
				// カレント行を取得する
				strLine = strTokenizer.nextToken();
				// カレント行がコメント行 かつ 最終行でなければ、次の行を処理する
				if (CMIUtil.isComment(strLine)) {
					continue;
				}
				strPairDivider = new CMITokenizer(strLine, "=");
				strKeyWord = strPairDivider.nextToken();
				try{
					strValue = strPairDivider.nextToken();
				} catch (NoSuchElementException nseE) {
					strValue = "";
				}


				strPairKeyWord = new CMITokenizer(strKeyWord, ".");
				strKeyWord = strPairKeyWord.nextToken();
				try{
					strNArrayID = strPairKeyWord.nextToken();
				}catch(NoSuchElementException nseE) {
					strNArrayID = null;
				}
				
				strKeyWord = strKeyWord.toLowerCase();

				if ("j_id".equals(strKeyWord)) {
					//attemptsを未初期化というステータスに変更
					bIsClearedAttempt = false;

					// 該当する(id が一致する)ノードを抽出する。
					// 先頭のj_id の状態で決定する
					// if (selectMode == OBJID_SELECT_UNKNOWN) {
					if (strValue == null || "".equals(strValue)) {
						// 添え字対応
						intSelectMode = 2;
					} else {
						// 該当ID対応
						intSelectMode = 1;
					}
					
					// データ配列を保持する。
					strCurArrayID = strNArrayID;
					int childCount = node.getChildCount();
					// pCurNode 初期化
					cmiCurNode = null;
					// トップ追加フラグ
					bTopAdd = false;

					if (intSelectMode == 2) {
						// ID が空の時の処理
						// 添え字に該当するオブジェクトを選択する
						int intNId = Integer.parseInt(strNArrayID);
						intNId -= 1;
						CMINode cmiNode= (CMINode)node.getChild(String.valueOf(intNId));
						if (cmiNode != null) {
							// id が一致したノードを保持する
							cmiCurNode = cmiNode;
							// トップ追加フラグ
							bTopAdd = true;

							// id に空("")をセットする
							strSubpath = "id";
							String StrID = cmiNode.getLocalValue(strSubpath);
							cmiNode.setLessonValue(strSubpath, strValue);
							if (blnCbtV3) {
								cmiNode.setLocalValue(strSubpath, strValue);
							}
						} 
					} else {
						// ID が設定されている時の処理
						// ID に該当するオブジェクトを選択する
						for (int i=0; i < childCount; i++) {
							CMINode cmiNode= (CMINode)node.getChild(i);
							strSubpath = "id";
							String StrID = cmiNode.getLocalValue(strSubpath);
							if (StrID != null && StrID.equals(strValue)) {
								// id が一致したノードを保持する
								cmiCurNode = cmiNode;
								// トップ追加フラグ
								bTopAdd = true;
								break;
							}
						}
					}
				} else if ("j_score".equals(strKeyWord)) {
					// j_score.n の添え字n の値とカレントノードの添え字を比較する
					// 一致するノード以外の場合、添え字n に該当するノードを取得する
					if (strNArrayID != null && !strNArrayID.equals(strCurArrayID)) {
						// カレントノードのアドレス変数をクリア（NULL）する
						cmiCurNode = null;	
						// カレントノードの添え字 に添え字n を代入する。
						strCurArrayID = strNArrayID;

						// ID を判定する前にj_score を受信した時の処理
						// 添え字nに該当するオブジェクトを選択する
						int nId = Integer.parseInt(strNArrayID);
						nId -= 1;
						CMINode cmiNode= (CMINode)node.getChild(String.valueOf(nId));
						if ( cmiNode != null ) {
							// id が一致したノードを保持する
							cmiCurNode = cmiNode;
							// トップ追加フラグ
							bTopAdd = true;

						}
					}
					if ( cmiCurNode != null ) {

						if ( 3500 <= version ) {
							// score ノードを取得する
							CMITokenizer token_ScoreValue = new CMITokenizer(strValue, ",");
							String strScoreValue = null;

							// 各値の設定
							// score.raw
							strSubpath = "score.raw";
							// token_ScoreValueにまだ値が残っていれば
							if(token_ScoreValue.hasMoreTokens()){
								// 値を scorevalueに格納する
								strScoreValue = token_ScoreValue.nextToken();
								// lessonValue localValue それぞれに、値を格納する
								cmiCurNode.setLessonValue(strSubpath, strScoreValue);
								cmiCurNode.setLocalValue(strSubpath, strScoreValue);

								strSubpath = "score.scaled";
								try {
									strScoreValue = CMIS13ModelUtil.parseS13Score(strScoreValue);
								}
								catch( S13LogFormatException exp ) {
									element.setError(CMIError.ERR_INCORRECT_DATA_TYPE);
									element.setVendorError("SCORM 1.3 Format Error[" + strSubpath + "]");
								}
								cmiCurNode.setLessonValue(strSubpath, strScoreValue);
								cmiCurNode.setLocalValue(strSubpath, strScoreValue);

							}

							// score.max
							strSubpath = "score.max";
							// token_ScoreValueにまだ値が残っていれば
							if(token_ScoreValue.hasMoreTokens()){
								// 値を scorevalueに格納する
								strScoreValue = token_ScoreValue.nextToken();
								// lessonValue localValue それぞれに、値を格納する
								cmiCurNode.setLessonValue(strSubpath, strScoreValue);
								cmiCurNode.setLocalValue(strSubpath, strScoreValue);
							}

							// score.min
							strSubpath = "score.min";
							// token_ScoreValueにまだ値が残っていれば
							if(token_ScoreValue.hasMoreTokens()){
								// 値を scorevalueに格納する
								strScoreValue = token_ScoreValue.nextToken();
								// lessonValue localValue それぞれに、値を格納する
								cmiCurNode.setLessonValue(strSubpath, strScoreValue);
								cmiCurNode.setLocalValue(strSubpath, strScoreValue);
							}
						} else {
							// AICCバージョン3.5未満時の、複数スコア対応のための改修
							//
							// このあたりのブロックで、j_scoreが要求としてきた場合に、スコアのメモリへの保存処理を行っている。
							// よって、ここにVer3.0〜Ver3.4及びVer3.0未満ののAICCのバージョンのための処理を書く。

							// attempts ノードを取得する
							strSubpath = "attempts";
							// cmi.objectives.n 配下のパスを指定する
							attemptsNode = (CMIArrayNode)cmiCurNode.getChild(strSubpath);

							if( 3000 <= version){
								// AICCバージョンが3.5未満かつ3.0以上の場合
								// raw,max,minの組を切り出すために使用
								CMITokenizer token_Score = new CMITokenizer(strValue, ";");

							    // SCOREの数（raw,max,minの組の数）回繰り返す
								int scoreCount=0;	// スコア数を格納
								while(token_Score.hasMoreTokens()){
									// 値を raw,max,min に展開する
									String scoreString;		// score(raw,max,min)全体
									String scaledString;	// 正規化された得点
									String rawString;		// 生の得点
									String maxString;		// 最大得点
									String minString;		// 最小得点

									scoreString = token_Score.nextToken();
									// １回分のraw,max,minの組を切り出す。
									// raw,max,minを個々に切り出すために使用
									CMITokenizer token_IndividualScore = new CMITokenizer(scoreString, ",");

									// 各値を設定する
									// raw
									strSubpath = String.valueOf(scoreCount) + ".score.raw";
									if (token_IndividualScore.hasMoreTokens()) {
										rawString = token_IndividualScore.nextToken();
										attemptsNode.setLessonValue(strSubpath, rawString);
										attemptsNode.setLocalValue(strSubpath, rawString);

									// scaled
										strSubpath = String.valueOf(scoreCount) + ".score.scaled";
										scaledString = rawString;
										try {
											scaledString = CMIS13ModelUtil.parseS13Score(scaledString);
										}
										catch( S13LogFormatException exp ) {
											element.setError(CMIError.ERR_INCORRECT_DATA_TYPE);
											element.setVendorError("SCORM 1.3 Format Error[" + strSubpath + "]");
										}
										attemptsNode.setLessonValue(strSubpath, scaledString);
										attemptsNode.setLocalValue(strSubpath, scaledString);

									}
									// max
									strSubpath = String.valueOf(scoreCount) + ".score.max";
									if (token_IndividualScore.hasMoreTokens()) {
										maxString = token_IndividualScore.nextToken();
										attemptsNode.setLessonValue(strSubpath, maxString);
										attemptsNode.setLocalValue(strSubpath, maxString);
									}
									// min
									strSubpath = String.valueOf(scoreCount) + ".score.min";
									if (token_IndividualScore.hasMoreTokens()) {
										minString = token_IndividualScore.nextToken();
										attemptsNode.setLessonValue(strSubpath, minString);
										attemptsNode.setLocalValue(strSubpath, minString);
									}
									scoreCount++;
								}
							}else{
								// AICCバージョンが3未満の場合
								// scoreを取り出すために使用
								CMITokenizer token_IndividualScore = new CMITokenizer(strValue, ",");

								// SCOREの数だけ繰り返す
								int scoreCount=0;	// 複数スコア数を格納
								while(token_IndividualScore.hasMoreTokens()){
									// 生のスコアを格納するために使用
									String rawString;

									// raw値を設定する
									strSubpath = String.valueOf(scoreCount) + ".score.raw";
									rawString = token_IndividualScore.nextToken();
									attemptsNode.setLessonValue(strSubpath, rawString);

									if (scoreCount == 0) {

										// raw値を設定する(SCORM1.3 サーバにて取得（getValue）用）
										strSubpath = "score.raw";
										cmiCurNode.setLessonValue(strSubpath, rawString);

										// scaled値を設定する
										String scaledString;
										strSubpath = String.valueOf(scoreCount) + ".score.scaled";
										scaledString = rawString;
										try {
											scaledString = CMIS13ModelUtil.parseS13Score(scaledString);
										}
										catch( S13LogFormatException exp ) {
											element.setError(CMIError.ERR_INCORRECT_DATA_TYPE);
											element.setVendorError("SCORM 1.3 Format Error[" + strSubpath + "]");
										}
										attemptsNode.setLessonValue(strSubpath, scaledString);

										strSubpath = "score.scaled";
										cmiCurNode.setLessonValue(strSubpath, scaledString);

									}
									scoreCount++;
								}
							}
						}
					} 
				} else if ("j_status".equals(strKeyWord)) {
					// j_status.n の添え字n の値とカレントノードの添え字を比較する
					// 一致するノード以外の場合、添え字n に該当するノードを取得する
					if (strNArrayID != null && !strNArrayID.equals(strCurArrayID)) {
						// カレントノードのアドレス変数をクリア（NULL）する
						cmiCurNode = null;
						// カレントノードの添え字 に添え字n を代入する。
						strCurArrayID = strNArrayID;

						// ID を判定する前にj_score を受信した時の処理
						// 添え字に該当するオブジェクトを選択する
						int nId = Integer.parseInt(strNArrayID);
						nId -= 1;
						CMINode pNode= (CMINode)node.getChild(String.valueOf(nId));
						if (pNode != null) {
							// id が一致したノードを保持する
							cmiCurNode = pNode;
							// トップ追加フラグ
							bTopAdd = true;

						} 
					}
					if (cmiCurNode != null) {
						String strPassStatus = null;
						String strCompStatus = null;
						if(version >= 3500){
							// objectives.status の値を設定する
							strSubpath = "status";
							try {
								// バージョンがAICCのときにsuccess_statusの
								// SCORM1.3用データにパースする
								strPassStatus =
									CMIS13ModelUtil.parseSuccessStatus(strValue);
							}
							catch( S13LogFormatException exp ) {
								element.setError(CMIError.ERR_INCORRECT_DATA_TYPE);
								element.setVendorError("SCORM 1.3 Format Error[" + strSubpath + "]");
							}
							cmiCurNode.setLessonValue(strSubpath, strPassStatus);
							cmiCurNode.setLocalValue(strSubpath, strPassStatus);

							// objectives.completion_status の値を設定する
							strSubpath = "completion_status";
							try {
								// バージョンがAICCのときにcompletion_statusの
								// SCORM1.3用データ値にパースする
								strCompStatus =
									CMIS13ModelUtil.parseCompletionStatus(strValue);
							}
							catch( S13LogFormatException exp ) {
								element.setError(CMIError.ERR_INCORRECT_DATA_TYPE);
								element.setVendorError("SCORM 1.3 Format Error[" + strSubpath + "]");
							}
							cmiCurNode.setLessonValue(strSubpath, strCompStatus);
							cmiCurNode.setLocalValue(strSubpath, strCompStatus);
						}else {						
							// attempts ノードを取得する
							strSubpath = "attempts";
							attemptsNode = (CMIArrayNode)cmiCurNode.getChild(strSubpath);

							// objectives.n.status の値を設定する
							strSubpath = String.valueOf(0) + ".status";
							try {
								// バージョンがAICCのときにcompletion_statusの
								// SCORM1.3用データ値にパースする
								strPassStatus =
									CMIS13ModelUtil.parseSuccessStatus(strValue);
							}
							catch( S13LogFormatException exp ) {
								element.setError(CMIError.ERR_INCORRECT_DATA_TYPE);
								element.setVendorError("SCORM 1.3 Format Error[" + strSubpath + "]");
							}
							attemptsNode.setLessonValue(strSubpath, strValue);
							if (blnCbtV3) {
								attemptsNode.setLocalValue(strSubpath, strValue);
							}			

							strSubpath = "status";
							cmiCurNode.setLessonValue(strSubpath, strPassStatus);

							// objectives.n.completion_status の値を設定する
							strSubpath = "completion_status";
							try {
								// バージョンがAICCのときにcompletion_statusの
								// SCORM1.3用データ値にパースする
								strCompStatus =
									CMIS13ModelUtil.parseCompletionStatus(strValue);
							}
							catch( S13LogFormatException exp ) {
								element.setError(CMIError.ERR_INCORRECT_DATA_TYPE);
								element.setVendorError("SCORM 1.3 Format Error[" + strSubpath + "]");
							}
							cmiCurNode.setLessonValue(strSubpath, strCompStatus);
							if (blnCbtV3) {
								cmiCurNode.setLocalValue(strSubpath, strCompStatus);
							}			
							bTopAdd = false;
						}
					} 
				} else {
					intErrCode = HACPError.HACP_ERR_INVALID_COMMAND;
				}
			}
		}
		return intErrCode;
	}

	/**
     * student dataグループの putParam<br>
     * @param element　エレメント
     * @param data　設定の値
     * @return エラーコード
     */
	private int putStudentDataGroup(CMIElement element, StringBuffer data) {

	    int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;
	    CMINode node = null;
		if ( ( element ) instanceof CMINode ) {
		   node = (CMINode)element;
		}

		boolean bCbtV3 = element.isV3Above();
		String strLineDelimiter = CMIUtil.checkLineDelimiter(data.toString());
	
		if ( node != null ) {
			CMITokenizer strTokenizer = new CMITokenizer(data.toString(), strLineDelimiter);
			CMITokenizer pairDivider;
			CMITokenizer pairKeyWord;
			CMIElement child = null;
			String strLine;
			String strKeyWord = null;
			String nArrayID = null;
			String strCurArrayID = null;
			String strValue = null;
			String strSubPath = null;
			int intCurNum = 0;
			int intNum = 0;

			while(strTokenizer.hasMoreTokens()){
				// カレント行を取得する
				strLine = strTokenizer.nextToken();
				// カレント行がコメント行 かつ 最終行でなければ、次の行を処理する
				if (CMIUtil.isComment(strLine)) {
					continue;
				}
				pairDivider = new CMITokenizer(strLine,"=");
				strKeyWord = pairDivider.nextToken();
				try{
					strValue = pairDivider.nextToken();
				}catch(NoSuchElementException nseE) {
					strValue = "";
				}

				pairKeyWord = new CMITokenizer(strKeyWord, ".");
				strKeyWord = pairKeyWord.nextToken();
				try{
					nArrayID = pairKeyWord.nextToken();
				}catch(NoSuchElementException nseE) {
					nArrayID = null;
				}
				strKeyWord = strKeyWord.toLowerCase();

				if ("tries_during_lesson".equals(strKeyWord)) {
					strSubPath = "tries_during_lesson";
					child = node.getChild(strSubPath);
					child.setLessonValue(strValue);
					if (bCbtV3) {
						child.setLocalValue(strValue);
					}
				} else if ("try_score".equals(strKeyWord)) {
					// tries ノードを取得する
					strSubPath = "tries";
					CMINode triesNode = (CMINode)node.getChild(strSubPath);

					// 処理対象の 配列ノードを取得する
					if (strCurArrayID == null) {
						// 初データ処理
						intNum = triesNode.getChildCount();
						// データ配列を保持する。
						strCurArrayID = nArrayID;	
						// 対象の配列番号を保持する。	
						intCurNum = intNum;
					} else if (nArrayID != null && nArrayID.equals(strCurArrayID)) {
						// 添え字N が前と同じときの処理
						intNum = intCurNum;
					} else {
						// 添え字N が前と違ったときの処理
						intNum = triesNode.getChildCount();
						// データ配列を保持する。
						strCurArrayID = nArrayID;
						// 対象の配列番号を保持する。
						intCurNum = intNum;
					}

					// 値を raw,max,min に展開する
					CMITokenizer token_ScoreValue = new CMITokenizer(strValue, ",");
					String strScoreValue;

					// 各値を設定する
					// raw
					strSubPath = String.valueOf(intNum) + ".score.raw";
					if (token_ScoreValue.hasMoreTokens()) {
						strScoreValue = token_ScoreValue.nextToken();
						triesNode.setLessonValue(strSubPath, strScoreValue);
						if (bCbtV3) {
							triesNode.setLocalValue(strSubPath, strScoreValue);
						}
					}
					// max
					strSubPath = String.valueOf(intNum) + ".score.max";
					if (token_ScoreValue.hasMoreTokens()) {
						strScoreValue = token_ScoreValue.nextToken();
						triesNode.setLessonValue(strSubPath, strScoreValue);
						if (bCbtV3) {
							triesNode.setLocalValue(strSubPath, strScoreValue);
						}
					}
					// min
					strSubPath = String.valueOf(intNum) + ".score.min";
					if (token_ScoreValue.hasMoreTokens()) {
						strScoreValue = token_ScoreValue.nextToken();
						triesNode.setLessonValue(strSubPath, strScoreValue);
						if (bCbtV3) {
							triesNode.setLocalValue(strSubPath, strScoreValue);
						}
					}
				} else if ("try_status".equals(strKeyWord)) {
					// tries ノードを取得する
					strSubPath = "tries";
					CMINode triesNode = (CMINode)node.getChild(strSubPath);

					// 処理対象の 配列ノードを取得する
					if (strCurArrayID == null) {
						// 初データ処理
						intNum = triesNode.getChildCount();
						// データ配列を保持する。
						strCurArrayID = nArrayID;
						// 対象の配列番号を保持する。
						intCurNum = intNum;
					} else if (nArrayID != null && nArrayID.equals(strCurArrayID)) {
						// 添え字N が前と同じときの処理
						intNum = intCurNum;
					} else {
						// 添え字N が前と違ったときの処理
						intNum = triesNode.getChildCount();
						//  データ配列を保持する。
						strCurArrayID = nArrayID;
						// 対象の配列番号を保持する。
						intCurNum = intNum;
					}

					strSubPath = String.valueOf(intNum) + ".status";
					triesNode.setLessonValue(strSubPath, strValue);
					if (bCbtV3) {
						triesNode.setLocalValue(strSubPath, strValue);
					}
				} else if ("try_time".equals(strKeyWord)) {
					// tries ノードを取得する
					strSubPath = "tries";
					CMINode triesNode = (CMINode)node.getChild(strSubPath);

					// 処理対象の 配列ノードを取得する
					if (strCurArrayID == null) {
						// 初データ処理
						intNum = triesNode.getChildCount();
						// データ配列を保持する。
						strCurArrayID = nArrayID;
						// 対象の配列番号を保持する。
						intCurNum = intNum;
					} else if (nArrayID != null && nArrayID.equals(strCurArrayID)) {
						// 添え字N が前と同じときの処理
						intNum = intCurNum;
					} else {
						// 添え字N が前と違ったときの処理
						intNum = triesNode.getChildCount();
						// データ配列を保持する。
						strCurArrayID = nArrayID;
						// 対象の配列番号を保持する。
						intCurNum = intNum;
					}

					strSubPath = String.valueOf(intNum) + ".time";
					try {
						strValue = CMIS13ModelUtil.parseS13Timespan(strValue);
					}
					catch( S13LogFormatException exp ) {
						element.setError(CMIError.ERR_INCORRECT_DATA_TYPE);
						element.setVendorError("AICC Format Error[" + strSubPath + "]");
					}
					triesNode.setLessonValue(strSubPath, strValue);
					if (bCbtV3) {
						triesNode.setLocalValue(strSubPath, strValue);
					}
				} else {
					intErrCode = HACPError.HACP_ERR_INVALID_COMMAND;
				}
			}
		}
		return intErrCode;
	}

	/**
	 * student Preferencesグループの putParam<br>
	 * @param element　エレメント
	 * @param data　設定の値
	 * @return エラーコード
	 */
	private int putStudentPreferencesGroup(CMIElement element, StringBuffer data) {

		int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;
		CMINode node = null;
		if ( ( element ) instanceof CMINode ) {
		   node = (CMINode)element;
		}
				

		//	顧客要望により元に戻す。
		boolean bCbtV3 = element.isV3Above();
		String strLineDelimiter = CMIUtil.checkLineDelimiter(data.toString());
	
		if (node != null) {
			CMITokenizer tokenizer = new CMITokenizer(data.toString(), strLineDelimiter);
			CMITokenizer pairDivider;
			CMITokenizer pairKeyWord;
			String strLine = null;
			String strKeyWord = null;
			String nArrayID = null;
			String curArrayID = null;
			String strValue = null;
			String strSubPath = null;
	
			while (tokenizer.hasMoreTokens()){ 
				// カレント行を取得する
				strLine = tokenizer.nextToken();
				// カレント行がコメント行 かつ 最終行でなければ、次の行を処理する
				if (CMIUtil.isComment(strLine)) {
					continue;
				}
	
				pairDivider = new CMITokenizer(strLine,"=");
				strKeyWord = pairDivider.nextToken();
				try{
					strValue = pairDivider.nextToken();
				}catch(NoSuchElementException nseE) {
					strValue = "";
				}
	
				pairKeyWord = new CMITokenizer(strKeyWord, ".");
				strKeyWord = pairKeyWord.nextToken();
				try{
					nArrayID = pairKeyWord.nextToken();
				}catch(NoSuchElementException nseE) {
					nArrayID = null;
				}
				strKeyWord = strKeyWord.toLowerCase();
	
				if ("audio".equals(strKeyWord)) {
					strSubPath = "audio";
					node.setLessonValue(strSubPath, strValue);
					node.setLocalValue(strSubPath, strValue);
				} else if ("language".equals(strKeyWord)) {
					strSubPath = "language";
					node.setLessonValue(strSubPath, strValue);
					node.setLocalValue(strSubPath, strValue);
				} else if ("lesson_type".equals(strKeyWord)) {
					strSubPath = "lesson_type";
					node.setLessonValue(strSubPath, strValue);
					node.setLocalValue(strSubPath, strValue);
				} else if ("speed".equals(strKeyWord)) {
					strSubPath = "speed";
					node.setLessonValue(strSubPath, strValue);
					node.setLocalValue(strSubPath, strValue);
				} else if ("text".equals(strKeyWord)) {
					strSubPath = "text";
					node.setLessonValue(strSubPath, strValue);
					node.setLocalValue(strSubPath, strValue);
				} else if ("text_color".equals(strKeyWord)) {
					strSubPath = "text_color";
					node.setLessonValue(strSubPath, strValue);
					node.setLocalValue(strSubPath, strValue);
				} else if ("text_location".equals(strKeyWord)) {
					strSubPath = "text_location";
					node.setLessonValue(strSubPath, strValue);
					node.setLocalValue(strSubPath, strValue);
				} else if ("text_size".equals(strKeyWord)) {
					strSubPath = "text_size";
					node.setLessonValue(strSubPath, strValue);
					node.setLocalValue(strSubPath, strValue);
				} else if ("video".equals(strKeyWord)) {
					strSubPath = "video";
					node.setLessonValue(strSubPath, strValue);
					node.setLocalValue(strSubPath, strValue);
				} else if ("window".equals(strKeyWord)) {
					int nId = Integer.parseInt(nArrayID);
					nId -= 1;
	
					strSubPath = "windows." + String.valueOf(nId);
					node.setLessonValue(strSubPath, strValue);
					node.setLocalValue(strSubPath, strValue);
				} else {
					intErrCode = HACPError.HACP_ERR_INVALID_COMMAND;
				}
			}
		}
		return intErrCode;
	}
   
	/**
	 * putGroupメソッド<br>
	 * @param element　エレメント
	 * @param data　設定の値
	 * @return エラーコード
	 */
	private int putGroup(CMIElement element, StringBuffer data) {

		int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;
		CMINode node = null;
		if ( ( element ) instanceof CMINode ) {
		   node = (CMINode)element;
		}				
					
		if (node != null) {
			CMITokenizer tokenizer = new CMITokenizer(data.toString(), CMIElement.STR_CRLF);
			CMITokenizer pairDivider;
			String strLine;
			String strKeyWord;
			String strValue;
	
			while (tokenizer.hasMoreTokens()){
				// カレント行を取得する
				strLine = tokenizer.nextToken();
				// カレント行がコメント行 かつ 最終行でなければ、次の行を処理する
				if (CMIUtil.isComment(strLine)) {
					continue;
				}
	
				pairDivider = new CMITokenizer(strLine, "=");
				strKeyWord = pairDivider.nextToken();
				strValue = pairDivider.nextToken();
	
				CMIElement child = node.getChildByKeyWord(strKeyWord);
				if (child != null) {
					child.putParam(strKeyWord, strValue);
				} else {
					intErrCode = HACPError.HACP_ERR_INVALID_COMMAND;
				}
			}
		}
		return intErrCode;
	}

	/**
	 * SCORM1.3データ値をHACP通信のAICC形式データにマッピングした際の<br>
	 * Core グループ（[Core]配下のデータ郡）のパラメータ値を設定する<br>
	 * @param element CMIElement データモデルオブジェクト
	 * @param data StringBuffer Objectives_Statusグループ情報
	 * @return int HACPエラーコード
	 *					  0 : Successful
	 *					404 : Data Model Element Is Read Only
	 *					405 : Data Model Element Is Write Only
	 *					406 : Data Model Element Type Mismatch
	 *					407 : Data Model Element Value Out Of Range
	 */
	private int putCoreGroupForSCORM(CMIElement element, StringBuffer data) {

		int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;	
		CMINode node = null;

		if ( ( element ) instanceof CMINode ) {
			node = (CMINode)element;
		}

		String strLineDelimiter = CMIUtil.checkLineDelimiter(data.toString());

		if (node != null) {
			CMITokenizer tokenizer = new CMITokenizer(data.toString(), strLineDelimiter);
			CMITokenizer pairDivider;
			CMIElement	child = null;
			String strLine = null;
			String strKeyWord = null;
			String strValue = null;
			String strSubpath = null;

			while(tokenizer.hasMoreTokens()) {
				// カレント行を取得する
				strLine = tokenizer.nextToken();
				// カレント行がコメント行 かつ 最終行でなければ、次の行を処理する
				if (CMIUtil.isComment(strLine)) {
					continue;
				}
				pairDivider = new CMITokenizer(strLine, "=");
				strKeyWord = pairDivider.nextToken();
				strValue = pairDivider.nextToken();

				// データ値を文字コードUTF-8でURLデコードする
				strValue = CMIUtil.urlDecode(strValue);

				strKeyWord = strKeyWord.toLowerCase();
				if ("lesson_location".equals(strKeyWord)) {
					strSubpath = "lesson_location";
					child = node.getChild(strSubpath);
					child.setLessonValue(strValue);
					child.setLocalValue(strValue);
				} else if ("lesson_status".equals(strKeyWord)) {
					CMITokenizer tokenValue = new CMITokenizer(strValue, ",");
					String strVal;

					// SCORM1.3では、success_statusデータの格納先として扱う
					strSubpath = "lesson_status";
					if (tokenValue.hasMoreTokens()) {
						strVal = tokenValue.nextToken();

						String strCredit = node.getLocalValue("credit");
						if ((strCredit != null) 
							&& ("credit".equalsIgnoreCase(strCredit) == true) )
						{
							child = node.getChild(strSubpath);
							child.setLessonValue(strVal);
							child.setLocalValue(strVal);
						}
					}
					strSubpath = "completion_status";
					if (tokenValue.hasMoreTokens()) {
						strVal = tokenValue.nextToken();
						child = node.getChild(strSubpath);
						child.setLessonValue(strVal);
						child.setLocalValue(strVal);
					}

					strSubpath = "exit";
					if (tokenValue.hasMoreTokens()) {
						strVal = tokenValue.nextToken();
						if("''".equals(strVal) == true) {
							strVal = "";
						}
						child = node.getChild(strSubpath);
						child.setLessonValue(strVal);
						child.setLocalValue(strVal);
					}
				} else if ("score".equals(strKeyWord)) {
					CMITokenizer tokenValue = new CMITokenizer(strValue, ",");
					String val;

					strSubpath = "score.scaled";
					if (tokenValue.hasMoreTokens()) {
						val = tokenValue.nextToken();
						child = node.getNChild(strSubpath);
						child.setLessonValue(val);
						child.setLocalValue(val);
					}

					strSubpath = "score.raw";
					if (tokenValue.hasMoreTokens()) {
						val = tokenValue.nextToken();
						child = node.getNChild(strSubpath);
						child.setLessonValue(val);
						child.setLocalValue(val);
					}

					strSubpath = "score.max";
					if (tokenValue.hasMoreTokens()) {
						val = tokenValue.nextToken();
						child = node.getNChild(strSubpath);
						child.setLessonValue(val);
						child.setLocalValue(val);
					}

					strSubpath = "score.min";
					if (tokenValue.hasMoreTokens()) {
						val = tokenValue.nextToken();
						child = node.getNChild(strSubpath);
						child.setLessonValue(val);
						child.setLocalValue(val);
					}
				} else if ("time".equals(strKeyWord)) {
					strSubpath = "session_time";
					child = node.getChild(strSubpath);
					child.setLessonValue(strValue);
					child.setLocalValue(strValue);
				} 
				// 2011.09.09 taku-harada add >>
				else if ("progress_measure".equals(strKeyWord)) {
					strSubpath = "progress_measure";
					child = node.getChild(strSubpath);
					child.setLessonValue(strValue);
					child.setLocalValue(strValue);
				}
				// 2011.09.09 taku-harada add <<
				else {
					// warning
					int ecode = element.getError();
					if (ecode == CMIError.ERR_NO_ERROR) {
						element.setError(CMIError.WARNING_INVALID_DATANAME);
						element.setVendorError("Invalid DataName[" + strKeyWord + "]");
					}
					// HACPError にはしない。
					// errCode = HACP_ERR_INVALID_COMMAND;
				}
			}
		}
		return intErrCode;
	}

	/**
	 * SCORM1.3用のPutParamコマンド（HACP通信）形式で指定された
	 * Objectives Status グループの情報を内部メモリに設定する。<br>
	 * @param element CMIElement データモデルオブジェクト
	 * @param data StringBuffer Objectives_Statusグループ情報
	 * @return int HACPエラーコード
	 */
	private int putObjectivesStatusGroupForSCORM(CMIElement element, StringBuffer data) {

	    int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;
		CMINode node = null;

		if ( ( element ) instanceof CMINode ) {
			node = (CMINode)element;
		}

		String strLineDelimiter = CMIUtil.checkLineDelimiter(data.toString());

		if (node != null) {
			CMITokenizer strTokenizer = new CMITokenizer(data.toString(), strLineDelimiter);
			CMITokenizer strPairDivider;
			CMITokenizer strPairKeyWord;
			String strLine = null;
			String strKeyWord = null;
			String strNArrayID = null;
			String strCurArrayID = null;
			String strValue = null;
			String strSubpath = null;
			CMINode	cmiCurNode = null;
			CMIArrayNode attemptsNode = null;
			boolean bTopAdd;

			int intSelectMode = 0;

			boolean bIsClearedAttempt = false;

			while (strTokenizer.hasMoreTokens()) {
				// カレント行を取得する
				strLine = strTokenizer.nextToken();
				// カレント行がコメント行 かつ 最終行でなければ、次の行を処理する
				if (CMIUtil.isComment(strLine)) {
					continue;
				}
				strPairDivider = new CMITokenizer(strLine, "=");
				strKeyWord = strPairDivider.nextToken();
				try{
					strValue = strPairDivider.nextToken();
				} catch (NoSuchElementException nseE) {
					strValue = "";
				}
				// データ値を文字コードUTF-8でURLデコードする
				strValue = CMIUtil.urlDecode(strValue);

				strPairKeyWord = new CMITokenizer(strKeyWord, ".");
				strKeyWord = strPairKeyWord.nextToken();
				try{
					strNArrayID = strPairKeyWord.nextToken();
				}catch(NoSuchElementException nseE) {
					strNArrayID = null;
				}

				strKeyWord = strKeyWord.toLowerCase();

				if ("j_id".equals(strKeyWord)) {
					//attemptsを未初期化というステータスに変更
					bIsClearedAttempt = false;

					// 該当する(id が一致する)ノードを抽出する。
					// 先頭のj_id の状態で決定する
					// if (selectMode == OBJID_SELECT_UNKNOWN) {
					if (strValue == null || "".equals(strValue)) {
						// 添え字対応
						intSelectMode = 2;
					} else {
						// 該当ID対応
						intSelectMode = 1;
					}
					
					// データ配列を保持する。
					strCurArrayID = strNArrayID;
					int childCount = node.getChildCount();
					// pCurNode 初期化
					cmiCurNode = null;
					// トップ追加フラグ
					bTopAdd = false;

					if (intSelectMode == 2) {
						// ID が空の時の処理
						// 添え字に該当するオブジェクトを選択する
						int intNId = Integer.parseInt(strNArrayID);
						intNId -= 1;
						CMINode cmiNode= (CMINode)node.getChild(String.valueOf(intNId));
						if (cmiNode != null) {
							// id が一致したノードを保持する
							cmiCurNode = cmiNode;
							// トップ追加フラグ
							bTopAdd = true;

							// id に空("")をセットする
							strSubpath = "id";
							String StrID = cmiNode.getLocalValue(strSubpath);
							cmiNode.setLessonValue(strSubpath, strValue);
							cmiNode.setLocalValue(strSubpath, strValue);
						} 
					} else {
						// ID が設定されている時の処理
						// ID に該当するオブジェクトを選択する
						for (int i=0; i < childCount; i++) {
							CMINode cmiNode= (CMINode)node.getChild(i);
							strSubpath = "id";
							String StrID = cmiNode.getLocalValue(strSubpath);
							if (StrID != null && StrID.equals(strValue)) {
								// id が一致したノードを保持する
								cmiCurNode = cmiNode;
								// トップ追加フラグ
								bTopAdd = true;
								break;
							}
						}
					}
				} else if ("j_score".equals(strKeyWord)) {
					// j_score.n の添え字n の値とカレントノードの添え字を比較する
					// 一致するノード以外の場合、添え字n に該当するノードを取得する
					if (strNArrayID != null && !strNArrayID.equals(strCurArrayID)) {
						// カレントノードのアドレス変数をクリア（NULL）する
						cmiCurNode = null;	
						// カレントノードの添え字 に添え字n を代入する。
						strCurArrayID = strNArrayID;

						// ID を判定する前にj_score を受信した時の処理
						// 添え字nに該当するオブジェクトを選択する
						int nId = Integer.parseInt(strNArrayID);
						nId -= 1;
						CMINode cmiNode= (CMINode)node.getChild(String.valueOf(nId));
						if ( cmiNode != null ) {
							// id が一致したノードを保持する
							cmiCurNode = cmiNode;
							// トップ追加フラグ
							bTopAdd = true;

						}
					}
					if ( cmiCurNode != null ) {

						// score ノードを取得する
						CMITokenizer token_ScoreValue = new CMITokenizer(strValue, ",");
						String strScoreValue = null;

						// 各値の設定
						// score.scaled
						strSubpath = "score.scaled";
						if(token_ScoreValue.hasMoreTokens()){
							// 値を scorevalueに格納する
							strScoreValue = token_ScoreValue.nextToken();
							// lessonValue localValue それぞれに、値を格納する
							cmiCurNode.setLessonValue(strSubpath, strScoreValue);
							cmiCurNode.setLocalValue(strSubpath, strScoreValue);
						}

						// score.raw
						strSubpath = "score.raw";
						// token_ScoreValueにまだ値が残っていれば
						if(token_ScoreValue.hasMoreTokens()){
							// 値を scorevalueに格納する
							strScoreValue = token_ScoreValue.nextToken();
							// lessonValue localValue それぞれに、値を格納する
							cmiCurNode.setLessonValue(strSubpath, strScoreValue);
							cmiCurNode.setLocalValue(strSubpath, strScoreValue);
						}

						// score.max
						strSubpath = "score.max";
						// token_ScoreValueにまだ値が残っていれば
						if(token_ScoreValue.hasMoreTokens()){
							// 値を scorevalueに格納する
							strScoreValue = token_ScoreValue.nextToken();
							// lessonValue localValue それぞれに、値を格納する
							cmiCurNode.setLessonValue(strSubpath, strScoreValue);
							cmiCurNode.setLocalValue(strSubpath, strScoreValue);
						}

						// score.min
						strSubpath = "score.min";
						// token_ScoreValueにまだ値が残っていれば
						if(token_ScoreValue.hasMoreTokens()){
							// 値を scorevalueに格納する
							strScoreValue = token_ScoreValue.nextToken();
							// lessonValue localValue それぞれに、値を格納する
							cmiCurNode.setLessonValue(strSubpath, strScoreValue);
							cmiCurNode.setLocalValue(strSubpath, strScoreValue);
						}
					}
				} else if ("j_status".equals(strKeyWord)) {
					// j_status.n の添え字n の値とカレントノードの添え字を比較する
					// 一致するノード以外の場合、添え字n に該当するノードを取得する
					if (strNArrayID != null && !strNArrayID.equals(strCurArrayID)) {
						// カレントノードのアドレス変数をクリア（NULL）する
						cmiCurNode = null;
						// カレントノードの添え字 に添え字n を代入する。
						strCurArrayID = strNArrayID;

						// ID を判定する前にj_score を受信した時の処理
						// 添え字に該当するオブジェクトを選択する
						int nId = Integer.parseInt(strNArrayID);
						nId -= 1;
						CMINode pNode= (CMINode)node.getChild(String.valueOf(nId));
						if (pNode != null) {
							// id が一致したノードを保持する
							cmiCurNode = pNode;
							// トップ追加フラグ
							bTopAdd = true;

						} 
					}
					if (cmiCurNode != null) {

						// status ノードを取得する
						CMITokenizer token_StatusValue = new CMITokenizer(strValue, ",");
						String strStatusValue = null;

						// objectives.status の値を設定する
						strSubpath = "status";
						// token_StatusValueにまだ値が残っていれば
						if(token_StatusValue.hasMoreTokens()){
							// 値を statusvalueに格納する
							strStatusValue = token_StatusValue.nextToken();
							cmiCurNode.setLessonValue(strSubpath, strStatusValue);
							cmiCurNode.setLocalValue(strSubpath, strStatusValue);
						}

						// objectives.completion_status の値を設定する
						strSubpath = "completion_status";
						// token_StatusValueにまだ値が残っていれば
						if(token_StatusValue.hasMoreTokens()){
							// 値を statusvalueに格納する
							strStatusValue = token_StatusValue.nextToken();
							cmiCurNode.setLessonValue(strSubpath, strStatusValue);
							cmiCurNode.setLocalValue(strSubpath, strStatusValue);
						}
					}
				} else {
					// warning
					int ecode = element.getError();
					if (ecode == CMIError.ERR_NO_ERROR) {
						element.setError(CMIError.WARNING_INVALID_DATANAME);
						element.setVendorError("Invalid DataName[" + strKeyWord + "]");
					}
				}
			}
		}
		return intErrCode;
	}

}
