/*
 * 作成日: 2006/10/23
 *
 * 携帯用ＳＣＯＲＭＢｅａｎクラス
 * 
 */
package jp.co.ntt.lms.imode.lo.scorm.engine;

import java.io.File;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.StringTokenizer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import jp.co.ntt.lms.imode.common.MobConst;
import jp.co.ntt.lms.imode.extension.CmiParameters;
import jp.co.ntt.lms.imode.extension.HacpDataParameters;
import jp.co.ntt.lms.imode.extension.RunTimeFormat;
import jp.co.ntt.lms.lo.scorm.engine.SCORMAPIAdapter;
import jp.co.ntt.lms.lo.scorm.util.SG;
import jp.co.ntt.lms.xmo.util.DebugLog;
import jp.co.ntt.lms.xms.framework.XmsException;

/**
 * ＳＣＯＲＭＡＰＩを提供するクラスです。
 *
 * @author ntc-sakai
 * 
 */
public class MobSCORMBean implements Serializable {

	/** HttpServletRequest */
	private HttpServletRequest req;

	/** 前処理スクリプトＵＲＬ */
	private String dispUrl;

	/** 後処理スクリプトＵＲＬ */
	private String postUrl;

	/** 学習終了状態 */
	private boolean endlearn;

	/** API ステータス */
	private String api_status;
	
	/** ＡＰＩエラーコード */
	private String api_errcode;

	/** 最後にSetValue("adl.nav.request", コマンド)したコマンド  */
	private String lastNavRequest;

	/** SCORM2004RTE用AICC_SID */
	private String aiccSid;

	/** ナビゲート実行フラグ true:実行 false:未実行 */
	private boolean navExeFlg;

	/** ＡＰＩステータス */
	private static final String STS_NOT_INI = "NotInitialize";
	private static final String STS_RUN     = "Running";
	private static final String STS_TERM    = "Terminated";

	private static final String GET_LMS_COMMENT = "command=GetLmsComments&version=S1.3&aicc_data=";

	/** CMIパラメータ */
	private CmiParameters cmiParameters = null;

	/** JSP教材forward用パス */
	private String forwardPath;

	/** HTML教材入力用パス */
	private String filePath;

	/**
	 * コンストラクト
	 * 
	 * @param manifestID マニフェストＩＤ
	 */
	public MobSCORMBean(String manifestID) {
		endlearn = false;
		navExeFlg = false;
		api_status = STS_NOT_INI;
		api_errcode = "0";
		lastNavRequest = "_none_";
		// 学習開始用ＵＲＬを設定
		this.postUrl = MobConst.C_START_POSTURL;
		makeContentsPath(manifestID);
		
	}

	/**
	 * forward用のパスとファイルパスを作成します。
	 * @param manifestID マニフェストＩＤ
	 */
	private void makeContentsPath(String manifestID)  {

		StringBuffer sbForward = new StringBuffer();

		// Forward用パス設定
		try {
			sbForward.append(SG.get("ForwardPath"));
		} catch (Exception e) {
			// <ForwardPath>が設定されていない場合、デフォルト値を使用する
			DebugLog.write(getClass(),
					"SCORMSG <ForwardPath> Not Found Error", DebugLog.HIGHT);
			sbForward.append("contents");
		}
		sbForward.append("/");
		sbForward.append(manifestID);
		sbForward.append("/");
		forwardPath =  sbForward.toString();

		// ｈｔｍｌファイルパス設定
		StringBuffer htmlPath = new StringBuffer();
		try {
			htmlPath.append(SG.get("ContentsBaseURL"));
		} catch (Exception e) {
			DebugLog.write(getClass(),
					"SCORMSG <ContentsBaseURL> Not Found Error", DebugLog.HIGHT);
			htmlPath.append(File.separator);
			htmlPath.append("usr");
			htmlPath.append(File.separator);
			htmlPath.append("local");
			htmlPath.append(File.separator);
			htmlPath.append("sce");
			htmlPath.append(File.separator);
			htmlPath.append("contents");
		}

		htmlPath.append(File.separator);
		htmlPath.append(manifestID);
		htmlPath.append(File.separator);
		filePath = htmlPath.toString();
	}

	/**
	 * HttpServletRequestを戻します。
	 * @return req Httpリクエスト
	 */
	public HttpServletRequest getReq() {
		return req;
	}

	/**
	 * HttpServletRequestを設定します。
	 * @param req Httpリクエスト
	 */
	public void setReq(HttpServletRequest req) {
		this.req = req;
	}

	/**
	 * 前処理ＵＲＬファイル有無チェック結果を戻します。
	 * 
	 * @return ファイル有る場合はtrue ファイル無い場合false
	 */
	public boolean isDispUrl() {
		// 前処理スクリプトＵＲＬが設定されて無い場合
		if (dispUrl == null || dispUrl.equals("")) {
			// ファイル無しを戻す
			return false;
		}

		// 前処理スクリプトファイル有無チェック
		File dispFile = new File(filePath + dispUrl);
		return dispFile.exists();
	}

	/**
	 * 後処理ＵＲＬファイル有無チェック結果を戻します。
	 * 
	 * @return ファイル有る場合はtrue ファイル無い場合はfalse
	 */
	public boolean isPostUrl() {
		// 後処理スクリプトＵＲＬが設定されて無い場合
		if (postUrl == null || postUrl.equals("")) {
			// ファイル無しを戻す
			return false;
		}
		// 学習開始後処理スクリプト又はデフォルト後処理スクリプト
		if (postUrl.equals(MobConst.C_DEFAULT_POSTURL) ||
			postUrl.equals(MobConst.C_START_POSTURL)) {
			return true;
		}

		StringBuffer postPath = new StringBuffer();
		// 教材ファイルパス設定
		postPath.append(filePath);
		// 後処理スクリプトＵＲＬファイル名を設定
		postPath.append(postUrl);
		// 後処理スクリプトファイル有無チェック
		File dispFile = new File(postPath.toString());
		return dispFile.exists();
	}

	/**
	 * パス＋前処理スクリプトＵＲＬを戻します。<br>
	 * htmlファイルの場合、ファイルパスを付加します。<br>
	 * 上記以外の場合、forwardパスを付加します。
	 * 
	 * @return dispUrl パス＋前処置スクリプトＵＲＬ
	 */
	public String getDispUrlPath() {
		// パス付き前処理スクリプトＵＲＬ
		StringBuffer sb = new StringBuffer();

		// 前処理スクリプトＵＲＬ判定
		if (dispUrl != null && !dispUrl.equals("")) {
			// 前処理スクリプトＵＲＬの拡張子判定
			if (dispUrl.toLowerCase().endsWith(".htm") ||
				dispUrl.toLowerCase().endsWith(".html")) {
				// ｈｔｍｌファイルの場合、ファイルパスを付加
				sb.append(filePath);
			} else {
				// ｈｔｍｌファイル以外の場合、フォワード用パスを付加
				sb.append(forwardPath);
			}
			sb.append(dispUrl);
		}

		return sb.toString();
	}

	/**
	 * 前処理スクリプトＵＲＬを戻します。
	 * 
	 * @return dispUrl 前処置スクリプトＵＲＬ
	 */
	public String getDispUrl() {
		return dispUrl;
	}

	/**
	 * 前処理スクリプトＵＲＬを設定します。
	 * @param dispUrl　前処理スクリプトＵＲＬ
	 */
	public void setDispUrl(String dispUrl) {
		// 前処理スクリプトＵＲＬ設定
		this.dispUrl = dispUrl;
	}

	/**
	 * forwardパス＋後処理スクリプトＵＲＬを戻します。
	 * 
	 * @return postUrl forwardパス＋後処理スクリプトＵＲＬ
	 */
	public String getPostUrlPath() {
		// パス付き後処理スクリプトＵＲＬ
		StringBuffer sb = new StringBuffer();
		
		// 開始用、デフォルト後処理スクリプト以外の場合forwardPathを付加する
		if (postUrl != null && !postUrl.equals("")) {
			if (!postUrl.equals(MobConst.C_DEFAULT_POSTURL) &&
			    !postUrl.equals(MobConst.C_START_POSTURL)) {
				// forwardPath設定
				sb.append(forwardPath);
			}
			// 後処理スクリプトファイル名設定
			sb.append(postUrl);
		}

		return sb.toString();
	}

	/**
	 * 後処理スクリプトＵＲＬを戻します。
	 * @return postUrl 後処理スクリプトＵＲＬ
	 */
	public String getPostUrl() {
		return postUrl;
	}

	/**
	 * 後処理スクリプトＵＲＬを設定します。
	 * 
	 * @param postUrl 後処理スクリプトＵＲＬ 
	 */
	public void setPostUrl(String postUrl) {
		this.postUrl = postUrl;
	}

	/**
	 * 学習終了状態を戻します。
	 * @return endlean 学習終了の場合true 学習中の場合false
	 */
	public boolean isEndlearn() {
		return endlearn;
	}

	/**
	 * 学習終了状態を設定します。
	 * @param endlearn true:学習終了 false:学習中
	 */
	public void setEndlearn(boolean endlearn) {
		this.endlearn = endlearn;
	}

	/**
	 * エンジンにナビゲーション要求を行ないます。
	 * 
	 * @param command ナビゲーションコマンド
	 * @param activityID アクテビティＩＤ
	 */
	public void navigate(String command, String activityID) {
		try {
			// ナビゲーション要求
			NavigateEngine naveng = new NavigateEngine();
			naveng.execute(req, command, activityID);
			endlearn = naveng.isEndLean();
			// ナビゲーションコマンド判定
			if (!endlearn) {
				// 中断、終了以外の場合、前処理スクリプトＵＲＬを設定する。
				dispUrl = naveng.getScoUrl();
				setDispUrl(dispUrl);
				aiccSid = naveng.getAiccSid();
				// ナビゲーションフラグを実行にする。
				navExeFlg= true;;
			}
		} catch (XmsException e) {
			// ＬＯＧ出力
			DebugLog.write(getClass(),
					"[navigate]NavigateEngine Error command = " + command +
					" activityid = " + activityID,	DebugLog.HIGHT);
			// 一般的な例外エラー
			api_errcode = "101";
		}

	}

	/**
	 * ＡＰＩのイニシャライズを行ないます。
	 * エラーコードはGetLastErrorメソッドで取得することが出来ます。
	 * 
	 * @return 正常の場合true エラーの場合false
	 */
	public boolean Initialize() {
		// ＡＰＩ状態チェック
		if (api_status != null && api_status.equals(STS_RUN)) {
			// 初期化済みエラー
			api_errcode = "103";
			return false;
		} else if (api_status != null && api_status.equals(STS_TERM)) {
			// 終了済みエラー
			api_errcode = "104";
			return false;
		}

		// sessionからapi adapterを取得する
		HttpSession session = req.getSession();
		SCORMAPIAdapter adapter = (SCORMAPIAdapter)session.getAttribute("SCORM.API_ADAPTER");

		if (adapter == null) {
			// session Time out エラー
			// ＬＯＧ出力
			DebugLog.write(getClass(),
					"[Initialize]SessionTimeout(apiAdapter is null)",
					DebugLog.HIGHT);
			// 一般的な例外エラー
			api_errcode = "101";
			return false;
		}

		try {
			// SCORM2004RTE取得(GetParam)
			String param ="command=GetParam&version=S1.3&session_id=" + aiccSid + "&aicc_data=";
			String result = adapter.hacp(param);

			// GetPrameのaicc dataをRTEデータモデルに変換後HashTableにセット
			HacpDataParameters hacpGetData = new HacpDataParameters();
			hacpGetData.setHacpDataText(result);
			String strGetData = hacpGetData.get("aicc_data");
			cmiParameters = new CmiParameters();
			cmiParameters.setCmiDataParam(strGetData);

			// SCORM2004RTE取得(GetLMSComments)
			String lmscpmment = adapter.hacp(GET_LMS_COMMENT);

			// GetLMSCommentsのaicc dataをRTEデータモデルに変換後HashTableにセット
			HacpDataParameters hacpLMSComments = new HacpDataParameters();
			hacpLMSComments.setHacpDataText(lmscpmment);
			String strLMSComments = hacpLMSComments.get("aicc_data");
			cmiParameters.setCmiDataLmsComments(strLMSComments);

			// APIエラーコードに正常を設定
			api_errcode = "0";
			// APIステータスをランニング状態にする
			api_status = STS_RUN;
			// ラストナビゲーションを初期化
			lastNavRequest = "_none_";
		} catch (Exception e) {
			// ＬＯＧ出力
			DebugLog.write(getClass(),
					"[Initialize]Exception Error(101)",
					DebugLog.HIGHT);
			// 一般的な例外エラー
			api_errcode = "101";
			return false;
		}
		return true;
	}

	/**
	 * RTEデータ、ナビゲーションの設定を行ないます。
	 * エラーコードはGetLastErrorメソッドで取得することが出来ます。
	 * 
	 * @param strKey キー
	 * @param strValue 値
	 * @return 正常の場合true エラーの場合false
	 */
	public boolean SetValue(String strKey, String strValue) {
		boolean bRtn;
		// チェック
		// ＡＰＩ状態チェック
		if (api_status != null && api_status.equals(STS_NOT_INI)) {
			// 初期化前エラー
			api_errcode = "132";
			return false;
		} else if (api_status != null && api_status.equals(STS_TERM)) {
			// 終了済みエラー
			api_errcode = "133";
			return false;
		}

		if (strKey == null) {
			api_errcode = "401";
			bRtn = false;
		}else if (strKey.equals("adl.nav.request")) {
			bRtn = NavSetValue(strValue);
		} else if (strKey.startsWith("cmi.")) {
			// データモデル（key）チェック
			RunTimeFormat rte = new RunTimeFormat();
			api_errcode = rte.cmiCheck(strKey, "w");
			if (api_errcode.equals("0")) {
				// 正常時、RTEデータ設定
				cmiParameters.put(strKey, strValue);
				bRtn = true;
			} else {
				// データモデルチェックエラー
				bRtn = false;
			}
		} else {
			// データモデルエラー
			api_errcode = "401";
			bRtn = false;
		}
		return bRtn;
	}

	/**
	 * ナビゲーション設定します。
	 * 
	 * @param strValue 値
	 * @return 正常の場合 エラーの場合false
	 */
	private boolean NavSetValue(String strValue) {
		boolean bRtn;
		// データモデルチェック
		if (strValue.equals("continue")   ||
			strValue.equals("previous")   ||
			strValue.equals("exit")       ||
			strValue.equals("exitAll")    ||
			strValue.equals("suspendAll") ||
			strValue.equals("_none_")) {
			// 正常時
			lastNavRequest = strValue;
			api_errcode = "0";
			bRtn = true;
		} else if (	strValue.startsWith("{target=") &&
				strValue.endsWith("}choice")) {
			if (strValue.length() > ("{target=".length() + "}choice".length())) {
				// 正常時
				lastNavRequest = strValue;
				api_errcode = "0";
				bRtn = true;
			} else {
				// データモデルエラー
				api_errcode = "401";
				bRtn = false;
			}
		} else {
			// データモデルエラー
			api_errcode = "401";
			bRtn = false;
		}

		return bRtn;
	}

	/**
	 * RTEデータ、ナビゲーション情報等を取得します。
	 * エラーコードはGetLastErrorメソッドで取得することが出来ます。
	 * 
	 * @param strKey データモデル
	 * @return RTEデータ又は、ナビゲーション情報
	 */
	public String GetValue(String strKey) {
		String strValue = null;
		// チェック
		// ＡＰＩ状態チェック
		if (api_status != null && api_status.equals(STS_NOT_INI)) {
			// 初期前エラー
			api_errcode = "122";
		} else if (api_status != null && api_status.equals(STS_TERM)) {
			// 終了済みエラー
			api_errcode = "123";
		} else 	if (strKey.startsWith("adl.nav.")) {
			strValue = NavGetValue(strKey);
			if (strValue != null) {
				api_errcode = "0";
			} else {
				api_errcode = "401";
			}
		} else {
			// データモデル（key）チェック
			RunTimeFormat rte = new RunTimeFormat();
			api_errcode = rte.cmiCheck(strKey, "r");
			if (api_errcode.equals("0")) {
				// 正常時RTEデータを設定
				strValue = (String) cmiParameters.get(strKey);
				strValue = (strValue == null) ? "": strValue;
			}
		}

		return strValue;
	}

	/**
	 * ナビゲーション情報取得<br>
	 * <table border="1">
	 * <tr><th>コマンド</th><th>説明</th></tr>
	 * <tr><td>adl.nav.request</td><td>最後にセットしたナビゲーションを戻します。</td></tr>
	 * <tr>
	 * <td>adl.nav.request.request_valid(コマンド)</td>
	 * <td>コマンドの有効・無効を戻します。コマンド：continue,previous</td>
	 * </tr>
	 * <tr>
	 * <td>adl.nav.request.request_valid.choice{target=uri}</td>
	 * <td>コマンドの有効・無効を戻します。uriが存在しない場合は、nullを戻します。</td>
	 * </tr>
	 * </table>
	 * @param strKey adl.nav.xxxx コマンド
	 * @return null:データモデルエラー null以外:データ値
	 */
	private String NavGetValue(String strKey) {
		String rtn = null;
		// データモデルチェック
		// adl.nav.request
		String [] dataModel = strKey.split("\\.");
	
		switch (dataModel.length) {
		case 3:
			// adl.nav.request
			if (dataModel[2].equals("request")) {
				// adl.nav.requestの場合、最後に実行したコマンドを戻す
				rtn = lastNavRequest;
			}
			break;

		case 4:
			// adl.nav.request_valid.continue||previous
			if (dataModel[2].equals("request_valid") &&
				(dataModel[3].equals("continue") ||
				 dataModel[3].equals("previous"))) {
				// request_valid.continue
				// request_valid.previousの場合
				// コマンド実行の可否を戻す
				NavigateEngine naveng = new NavigateEngine();
				rtn = naveng.getRequestValid(req, dataModel[3], null);
			}
			break;
		
		case 5:
			// adl.nav.request_valid.choice.{target=uri}
			if (dataModel[2].equals("request_valid") &&
				// 2010.10.06 taku-harada mod >>
				//dataModel[3].equals("choice") &&
				(dataModel[3].equals("choice") || dataModel[3].equals("jump"))&&
				// 2010.10.06 taku-harada mod <<
				dataModel[4].startsWith("{target=") &&
				dataModel[4].endsWith("}")) {
				// URIが指定されているか？　"{target=}"の場合エラー
				if (("{target=".length() + "}".length()) < dataModel[4].length() ) {
					// "{target=uri}"のuri取得
					String url = dataModel[4].substring("{target=".length(), (dataModel[4].length() - "}".length()));
					// 指定されたuriがChoice可能かチェックする
					NavigateEngine naveng = new NavigateEngine();
					rtn = naveng.getRequestValid(req, dataModel[3], url);
				}
			}
			break;

 		default:
			// データモデルエラー
			break;
		}
		return rtn;
	}

	/**
	 * RTEデータをエンジンへ送信します。
	 * 
	 * @return errcode 正常の場合true エラーの場合false
	 */
	public boolean Commit() {
		// ＬＯＧ出力
		DebugLog.write(getClass(), "[Commit]ＡＰＩ状態チェック",	DebugLog.ROW);
		// ＡＰＩ状態チェック
		if (api_status != null && api_status.equals(STS_NOT_INI)) {
			// 初期前エラー
			api_errcode = "142";
			return false;
		} else if (api_status != null && api_status.equals(STS_TERM)) {
			// 終了済みエラー
			api_errcode = "143";
			return false;
		}
		// ＬＯＧ出力
		DebugLog.write(getClass(), "[Commit]PutParam",	DebugLog.ROW);
		// エンジンへデータ送信
		api_errcode = putData();

		if (api_errcode == null) {
			// 一般的な例外エラー
			api_errcode = "391";
			// ＬＯＧ出力
			DebugLog.write(getClass(), "[Commit]putData() error",	DebugLog.HIGHT);
		}
		
		return api_errcode.equals("0");
	}

	/**
	 * RTEデータをエンジンに送信後ナビゲーションが設定されていたら
	 * エンジンへナビゲーション要求します。
	 * 
	 * @return　正常の場合true エラーの場合false
	 */
	public boolean Terminate() {
		// ＡＰＩ状態チェック
		if (api_status != null && api_status.equals(STS_NOT_INI)) {
			// 初期前エラー
			api_errcode = "112";
			return false;
		} else if (api_status != null && api_status.equals(STS_TERM)) {
			// 終了済みエラー
			api_errcode = "113";
			return false;
		}

		api_errcode = putData();

		if (api_errcode == null) {
			// 一般的な例外エラー
			api_errcode = "391";
			return false;
		} else if (!api_errcode.equals("0")) {
			return false;
		}
		// adl.nav.requestが設定されている場合、ナビゲーション要求する。
		// ナビゲーションコマンド用ワーククリア
		// 
		api_errcode = putCommand("EXITAU", "");

		if (api_errcode == null) {
			// 一般的な例外エラー
			api_errcode = "391";
			return false;
		} else if (!api_errcode.equals("0")) {
			return false;
		}
		// ＡＰＩ状態ステータスを終了にする。
		api_status = STS_TERM;
		// 
		if (lastNavRequest != null && !lastNavRequest.equals("_none_")) {
			String command;
			String activityID = null;
			if (lastNavRequest.startsWith("{target=") &&
				lastNavRequest.endsWith("}choice")) {
				command = "choice";
				activityID = lastNavRequest.substring("{target=".length(), (lastNavRequest.length() - "}choice".length()));
			} else {
				command = lastNavRequest;
			}
			navigate(command, activityID);
			if (!api_errcode.equals("0")) {
				return false;
			}
		}
		return true;
	}

	/**
	 * RTEデータをAICCデータに変換しエンジンへ送信します。
	 * 
	 * @return errcode 送信結果
	 */
	private String putData() {
		String errCode;

		// エンジンへAICCデータ送信 PutParam
		errCode = putCommand("PutParam", cmiParameters.getAiccDataParam());
		// 送信結果判定
		if (errCode == null || !errCode.equals("0")) {
			// 一般的な例外エラー
			// ＬＯＧ出力
			DebugLog.write(getClass(),
					"[putData]putCommand(PutParam, aicc) error " + errCode,
					DebugLog.HIGHT);
			return errCode;
		}

		// Interactionsデータ取得
		String interactionsData = cmiParameters.getAiccDataInteractions();

		if (interactionsData != null) {
			// interactionsデータが存在する場合
			// ＬＯＧ出力
			DebugLog.write(getClass(), "[Commit]PutParam(interaction)",	DebugLog.ROW);
			// エンジンへAICCデータ送信 PutInteractions
			errCode = putCommand("PutInteractions", interactionsData);

			// 送信結果判定
			if (errCode == null || !errCode.equals("0")) {
				// 一般的な例外エラー
				// ＬＯＧ出力
				DebugLog.write(getClass(),
						"[putData]putCommand(PutInteractions, aicc) error " + errCode,
						DebugLog.HIGHT);
				return errCode;
			}
		}

		// PutCommentsデータ取得
		String commentsData = cmiParameters.getAiccDataComments();

		if (commentsData != null) {
			// ＬＯＧ出力
			DebugLog.write(getClass(), "[Commit]PutParam(PutComments)",	DebugLog.ROW);
			// エンジンへAICCデータ送信 PutComments
			errCode = putCommand("PutComments", commentsData);

			// 送信結果判定
			if (errCode == null || !errCode.equals("0")) {
				// 一般的な例外エラー
				// ＬＯＧ出力
				DebugLog.write(getClass(),
						"[putData]putCommand(PutComments, aicc) error " + errCode,
						DebugLog.HIGHT);
				return errCode;
			}
		}

		return errCode;
	}

	/**
	 * 引数で指定されたコマンドを基にエンジンへAICCデータを送信します。
	 * @param command コマンド
	 * @param aiccData AICCデータ
	 * @return errcode 送信結果
	 */
	private String putCommand(String command, String aiccData) {
		// sessionからapi adapterを取得する
		HttpSession session = req.getSession();
		SCORMAPIAdapter adapter = (SCORMAPIAdapter)session.getAttribute("SCORM.API_ADAPTER");

		if (adapter == null) {
			// session Time out エラー
			// ＬＯＧ出力
			DebugLog.write(getClass(),
					"[putdata]SessionTimeout(apiAdapter is null)",
					DebugLog.HIGHT);
			return null;
		}

		StringBuffer sbCommand = new StringBuffer();
		sbCommand.append("command=");
		sbCommand.append(command);
		sbCommand.append("&version=S1.3&session_id=");
		sbCommand.append(aiccSid);
		sbCommand.append("&aicc_data=");
		try {
			sbCommand.append(URLEncoder.encode(aiccData, "UTF-8"));
		} catch (UnsupportedEncodingException e1) {
			sbCommand.append(aiccData);
		}

		// SCORM2004RTE送信(PutParam)
		String result = null;
		try {
			DebugLog.write(getClass(), "[putdata]-> " + sbCommand.toString(), DebugLog.ROW);
			result = adapter.hacp(sbCommand.toString());
			DebugLog.write(getClass(), "[putdata]<- " + result, DebugLog.ROW);
		} catch (Exception e) {
			DebugLog.write(getClass(), "[putdara]hacp error " + sbCommand.toString(), DebugLog.HIGHT);
			return null;
		}
		// 送信結果判定
		return aiccErrGet(result);
	}

	/**
	 * 送信結果情報からエラーコードを取得します。
	 * 
	 * @param aiccData 送信結果データ
	 * @return errcode エラーコード
	 */
	private String aiccErrGet(String aiccData) {
		StringTokenizer st = new StringTokenizer(aiccData, "\n");
		boolean bErrFlg = false;
		boolean bDetailFlg = false;
		String errCode = null;
		String detailCode = null;
		while(st.hasMoreTokens()) {
			int startpos;
			String value = st.nextToken().trim();
			if (!bErrFlg) {
				// errorコード取得
				startpos = value.indexOf("error=");
				if (startpos >= 0) {
					value = value.substring(startpos);
					errCode = value.replaceAll("error=", "");
					bErrFlg = true;
				}
			}
			if (!bDetailFlg) {
				// detail_error取得
				startpos = value.indexOf("detail_error=");
				if (startpos >= 0) {
					value = value.substring(startpos);
					detailCode = value.replaceAll("detail_error=", "");
					bDetailFlg = true;;
				}
			}
			// エラーコード＆詳細コードが取得出来た?
			if (bErrFlg && bDetailFlg) {
				break;
			}
		}

		if (errCode != null && errCode.equals("0")) {
			if (detailCode != null) {
				errCode = detailCode;
			}
		}
		return errCode;
	}

	/**
	 * APIステータス状態を戻します。
	 * <table border="1">
	 * <tr><td>Notinitialize</td><td>イニシャライズ前</td></tr>
	 * <tr><td>running</td><td>実行中</td></tr>
	 * <tr><td>Terminated</td><td>終了</td></tr>
	 * </table>
	 * 
	 * @return APIステータスコード
	 */
	public String getApi_status() {
		return api_status;
	}

	/**
	 * APIエラーコードを戻します。
	 * 
	 * @return APIエラーコード
	 */
	public String GetLastError() {
		return api_errcode;
	}

	/**
	 * ナビゲーション状態を初期化します。
	 *
	 */
	public void NaviInitialize() {
		// ナビゲーション実行済みの場合、イニシャライズ前状態に設定
		if (navExeFlg) {
			// ＡＰＩ状態ステータスをイニシャライズ前に設定
			api_status = STS_NOT_INI;
			// ＡＰＩエラーコードを正常に設定
			api_errcode = "0";
			// ラストナビゲーションをクリア
			lastNavRequest = "_none_";
			// ナビゲーション実行フラグをクリア
			navExeFlg = false;
		}
	}
}
