//
// CopyRight (C) 2002, IPA, eLC, NTT Resonant Inc. All rights reserved.
//
//	Activity
//
//	変更履歴
//		2002.12.25  新規作成

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

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import javax.xml.transform.TransformerException;

import jp.co.ntt.lms.lo.scorm.kernel.exception.SystemException;
import jp.co.ntt.lms.lo.scorm.util.CachedNode;
import jp.co.ntt.lms.lo.scorm.util.XMLUtil;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
* アクティビティクラス<BR>
* アクティビティ情報を表すクラス<BR>
*/
public class Activity {
	/** item node */
	private CachedNode itemNode;

	/** 教材ID */
	private String courseIdentifier;

	/** SCO ID */
	private String identifier;

	/** child activity set */
	private Activity[] children;

	/** parent activity */
	private Activity parentActivity;

	/** sequencing */
	private Sequencing sequencing;

	/** resource */
	private Resource resource;

	/**
	 * コンストラクタ <BR>
	 * 
	 * @param manifestNode 教材構造定義中のアクティビティのノード <BR>
	 * @param itemNode Activity対象itemノード
	 * @param globalObjectives グローバルオブジェクティブの配列 <BR>
	 * @param courseID 教材ID <BR>
	 */
	public Activity(
		CachedNode manifestNode,
		CachedNode itemNode,
		GlobalObjective[] globalObjectives,
		String courseID)
		throws SystemException {

		try {
			this.itemNode = itemNode;

			/*
			 *  activity id の取得
			 *  なければ exception
			 */
			CachedNode identifierNode = itemNode.selectSingleChildNode("@identifier");
			if (identifierNode == null) {
				throw new SystemException("アクティビティのIDがありません。(no activity identifier)");
			}

			identifier = identifierNode.getNodeValue();

			/*
			 *  course id を取得
			 */
			courseIdentifier = courseID;

			/*
			 *  sequencing node を取得する
			 *  なくても、null のまま渡す
			 */
			CachedNode sequencingNode = itemNode.selectSingleChildNode("sequencing");

			//■自分の子のitemをnode listで取得
			CachedNode[] childItemNodes = itemNode.selectChildNodeList("item");

			boolean hasChildren = ((childItemNodes != null) && (childItemNodes.length > 0));

			sequencing = new Sequencing(this, manifestNode, sequencingNode, globalObjectives, hasChildren);

			// 取得ノードが存在すれば子アクティビティを持つので再帰する
			if (hasChildren) {
				//■子アクティビティをプロパティにセットする
				children = new Activity[childItemNodes.length];

				//■子の数だけ再帰する
				for (int i = 0; i < children.length; i++) {
					children[i] = new Activity(manifestNode, childItemNodes[i], globalObjectives, courseID);
					//親として自分をセットする
					children[i].setParent(this);
				}
			}
			else {
				// identifierRe
				CachedNode identifierRefNode = itemNode.selectSingleChildNode("@identifierref");

				// リソースの生成
				if (identifierRefNode != null) {
					// ドキュメントを取得して、リソースのコンストラクタに渡す
					resource =
						new Resource(
							identifierRefNode.getNodeValue(),
							manifestNode.selectSingleChildNode("resources"));
				}
			}
		}
		catch (Exception ex) {
			throw new SystemException(
				"アクティビティの作成に失敗しました。( activity constractor failed ) " + "[" + this.identifier + "]",
				ex);
		}
	}

	/**
	 * 中断情報取得 <BR>
	 *
	 * @param doc	<trackinginformation>タグがルートタグのDOM Documentを指定する
	 * @param parentNode 作成した中断情報を追加する為の(親の)エレメントノードを指定する。
	 * @param deep	子アクティビティの中断情報を取得するかどうかを指定する<br>
	 *				trueを指定した場合は取得する、falseを指定した場合は取得しない
	 * @param traceLog	トレース用・中断用振り分けフラグ<br>
	 */
	public void save(Document doc, Element parentNode, boolean deep, boolean traceLog) throws SystemException {
		Element activity =
			XMLUtil.insertAttribute(doc, XMLUtil.append(doc, parentNode, "activity"), "id", identifier);

		sequencing.save(doc, activity, traceLog);

		if (deep) {
			if (children != null) {
				for (int i = 0; i < children.length; i++) {
					children[i].save(doc, activity, true, traceLog);
				}
			}
		}
	}

	/*
	 * useCurrentAttemptの為の候補値を更新する
	 */
	public void setCandidatePreviousValue() throws SystemException {
		sequencing.setCandidatePreviousValue();
	}

	/**
	 * アクティビティの中断情報を戻す <BR>
	 *
	 * @param parentNode 中断情報(<activity>タグ)を取得する(親の)エレメントをノードを指定する。
	 */
	public void initializeActivityInformation(CachedNode parentNode) throws SystemException {
		try {
			CachedNode activityNode;

			if (parentNode == null) {
				activityNode = null;
			}
			else {
				activityNode = parentNode.selectSingleNodeWithNodeTest("activity", "@id", identifier);
			}

			sequencing.initializeSequencingInformation(activityNode);

			//子がいる場合は子へセットする
			if (children != null) {
				//子の数だけ繰り返す
				for (int i = 0; i < children.length; i++) {
					children[i].initializeActivityInformation(activityNode);
				}
			}
		}
		catch (Exception ex) {
			throw new SystemException(
				"中断情報の設定に失敗しました。( setActivityInformation failed ) " + "[" + this.identifier + "]",
				ex);
		}
	}

	/**
	 * 試行情報の初期化<BR>
	 */
	public void initializeAttemptInformation() throws SystemException {
		// sequencing の試行情報の初期化
		sequencing.initializeAttemptInformation();
	}

	/**
	 * 終期化<BR>
	 */
	public void terminate() throws SystemException {

		try {
			itemNode = null;

			if (children != null) {
				for (int i = 0; i < children.length; i++) {
					children[i].terminate();
					children[i] = null;
				}
			}

			parentActivity = null;

			sequencing.terminate();
			sequencing = null;

			if (resource != null) {
				resource.terminate();
				resource = null;
			}
		}
		catch (SystemException e) {
			throw e;
		}
	}

	/**
	 * CBTCOM初期化
	 * @param userID
	 * @param userName
	 * @param URL
	 * @param parentNode
	 * @param deep
	 */
	public void initializeAPIAdapter(
		String userID,
		String userName,
		String URL,
		String encoding,
		CachedNode parentNode,
		boolean deep)
		throws SystemException, TransformerException {

		if ((parentNode != null) && (children == null)) {
			CachedNode activityNode = parentNode.selectSingleNodeWithNodeTest("activity", "@id", identifier);
			sequencing.initializeAPIAdapter(userID, userName, URL, encoding, activityNode);
		}
		else if (children == null) {
			sequencing.initializeAPIAdapter(userID, userName, URL, encoding, null);
		}

		if (deep) {
			//再帰呼び出しで子アクティビティへ設定
			if (children != null) {
				for (int i = 0; i < children.length; i++) {
					children[i].initializeAPIAdapter(userID, userName, URL, encoding, parentNode, true);
				}
			}
		}
	}

	/**
	 * CBTCOM初期化
	 * @param userID
	 * @param userName
	 * @param URL
	 * @param parentNode
	 * @param deep
	 */
	public void initializeAPIAdapter2(
		String userID,
		String userName,
		String URL,
		String encoding)
		throws SystemException, TransformerException {

		if (children == null) {
			sequencing.initializeAPIAdapter2(userID, userName, URL, encoding);
		}
	}
	
	/**
	 * 外部APIAdapterから中断情報を取得する <BR>
	 *
	 * @param doc	<communicationmodule>タグがルートタグのDOM Documentを指定する
	 * @param parentNode	中断情報(<activity>タグ)を追加する(親の)エレメントを指定する
	 */
	public void saveAPIAdapter(Document doc, Element parentNode) throws SystemException {
		if (children == null) {
			Element activity =
				XMLUtil.insertAttribute(doc, XMLUtil.append(doc, parentNode, "activity"), "id", identifier);

			sequencing.saveAPIAdapter(doc, activity);
		}

		//子アクティビティがあれば子アクティビティに再帰
		if (children != null) {
			for (int i = 0; i < children.length; i++) {
				children[i].saveAPIAdapter(doc, parentNode);
			}
		}
	}

	/**
	 * 外部APIAdpaterの再開を行う
	 */
	public void resumeAPIAdapter() throws SystemException {
		sequencing.resumeAPIAdapter();
	}

	/**
	 * トラッキング情報の同期
	 */
	public void synchronizeTrackingModel() throws SystemException {
		sequencing.synchronizeTrackingModel();
	}

	/**
	 * Sequencingのインスタンスの取得
	 *
	 * @return Sequencingクラスのインスタンスの参照 <BR>
	 */
	public Sequencing getSequencing() {
		return sequencing;
	}

	/**
	* 親をセットする
	* @param parent 親アクティビティとしてセットするアクティビティ <BR>
	*/
	public void setParent(Activity parent) {
		this.parentActivity = parent;
	}

	/**
	* 親アクティビティを返す。
	*
	* @return 親アクティビティを返す
	*/
	public Activity getParent() {
		return parentActivity;
	}

	/**
	* アクティビティIDを取得する
	* @return String アクティビティIDを返す
	*/
	public String getIdentifier() {
		return identifier;
	}

	/** 
	* アクティビティの持つ全子アクティビティを取得する
	* 
	* @return Activity[] 全子アクティビティの配列
	*/
	public Activity[] getChildren() {
		return children;
	}

	/**
	*  利用可能なアクティビティの取得 <BR>
	*
	* @return Activity[] 利用可能な子アクティビティの配列
	*/
	public Activity[] getAvailableChildren() {
		return sequencing.getStatus().getAvailableChildren();
	}

	/**
	*  利用可能なアクティビティの設定 <BR>
	*
	* @param availablechildren 利用可能な子アクティビティの配列
	*/
	public void setAvailableChildren(Activity[] availablechildren) {
		sequencing.getStatus().setAvailableChildren(availablechildren);
	}

	/**
	*  利用可能なアクティビティの削除 <BR>
	*/
	public void removeAvailableChildren() {
		sequencing.getStatus().setAvailableChildren(null);
		// 子アクティビティからも外す
		if ((this.children != null) && (children.length > 0)) {
			for (int i = 0; i < children.length; i++) {
				children[i].removeAvailableChildren();
			}
		}
	}

	/**
	* アクティビティがAvailableChildrenに含まれるか否か<BR>
	* @return boolean 含まれるか否かを示す<BR>
	*     ( true: 含まれる / false: 含まれない )<BR>
	*/
	public boolean isAvailable() {
		return sequencing.isAvailable();
	}

	/**
	* ステータスのオブジェクトを取得する<BR>
	* @return Status アクティビティのステータス<BR>
	*/
	public Status getStatus() {
		return sequencing.getStatus();
	}

	/**
	 * アクティビティがツリー構造上最後のアクティビティか判定する<BR>
	 * @return 判定結果
	 */
	public boolean canAvailableForward() {

		if (this.hasAvailableChildren()) {
			return true;
		}
		else {
			if (this.isAvailableLast()) {
				if (this.isRoot()) {
					return false;
				}
				return this.parentActivity.canParentAvailableForward();
			}
			else {
				return true;
			}
		}
	}

	/**
	 * アクティビティがツリー構造上最後のアクティビティか判定する<BR>
	 * 親アクティビティ再帰検索用<BR>
	 * @return 判定結果
	 */
	private boolean canParentAvailableForward() {

		if (this.isRoot()) {
			return false;
		}
		if (this.isAvailableLast()) {
			return this.parentActivity.canParentAvailableForward();
		}
		else {
			return true;
		}
	}

	/**
	 * アクティビティがツリー構造上最初のアクティビティか判定する<BR>
	 * @return 判定結果
	 */
	public boolean canAvailableBackward() {
		if (this.isAvailableFirst()) {
			if (this.isRoot()) {
				return false;
			}
			return this.parentActivity.canParentAvailableBackward();
		}
		else {
			return true;
		}
	}

	/**
	 * アクティビティがツリー構造上最初のアクティビティか判定する<BR>
	 * 親アクティビティ再帰検索用<BR>
	 * @return 判定結果
	 */
	private boolean canParentAvailableBackward() {

		if (this.isRoot()) {
			return false;
		}
		if (this.isAvailableFirst()) {
			return this.parentActivity.canParentAvailableBackward();
		}
		else {
			return true;
		}
	}

	/**
	*	Available Children の最初か否か<BR>
	*
	*  @return boolean 最初か否かを示す<BR>
	*    true:    Available Childrenの最初のアクティビティである<BR>
	*    false:   Available Childrenの最初のアクティビティではない<BR>
	*/
	public boolean isAvailableFirst() {
		if (this.isRoot()) {
			return true;
		}

		return parentActivity.getAvailableChildren()[0].getIdentifier().equals(identifier);
	}

	/**
	* クラスタの abailable children の最後のアクティビティ<BR>
	* かどうかのチェック<BR>
	* 
	* @return 最後のアクティビティかどうか<BR>
	* ( true: 最後のアクティビティ / false: 最後のアクティビティでない )<BR>
	*/
	public boolean isAvailableLast() {
		if (this.isRoot()) {
			return true;
		}

		Activity[] availableSibling = parentActivity.getAvailableChildren();

		return availableSibling[availableSibling.length - 1].getIdentifier().equals(identifier);
	}

	/**
	*	自分が子を持つかの判定<BR>
	* 
	* @return 子アクティビティを持つかどうかを示す <BR>
	* ( true: 子アクティビティを持つ / false: 子アクティビティを持たない)<BR>
	*/
	public boolean hasChildren() {
		if ((this.children == null) || (children.length <= 0)) {
			return false;
		}

		return true;
	}

	/**
	 *  available children を持っているか否かの判定<BR>
	 *  ( 学習可能な子アクティビティ)
	 *  @return true   available children を持っている<BR>
	 *               false available children を持っていない<BR>
	 */
	public boolean hasAvailableChildren() {
		Activity[] availableChildren = this.getStatus().getAvailableChildren();

		if ((availableChildren == null) || (availableChildren.length <= 0)) {
			return false;
		}

		return true;
	}

	/**
	*  自分の配下の子孫アクティビティからアクティビティID指定で <BR>
	*  アクティビティを取得する
	* 
	* @param activityIdentifier 取得したいアクティビティID <BR>
	* @return ID指定のアクティビティ <BR>
	* アクティビティがない場合はnullを返す 
	*/
	public Activity getActivity(String activityIdentifier) {
		// IDが同じならthisを返す
		if (this.identifier.equals(activityIdentifier)) {
			return this;
		}

		// そうでない場合は子に探してもらう
		if (children != null) {
			for (int i = 0; i < children.length; i++) {
				Activity target = children[i].getActivity(activityIdentifier);
				if (target != null) {
					return target;
				}
			}
		}

		return null;
	}

	/**
	* アクティビティが教材構造ツリー中のルートアクティビティ <BR>
	* かどうかをチェックする
	* 
	* @return アクティビティがツリー中のルートアクティビティかどうか<BR>
	* を示す。( true: ルートのアクティビティである / false: ルートのアクティビティでない )<BR>
	*/
	public boolean isRoot() {
		return (this.parentActivity == null);
	}

	/**
	* 教材構造ツリー中のルートのアクティビティを返す <BR>
	* 
	* @return ルートのアクティビティを返す
	* ( ない場合はnullを返す)
	*/
	public Activity getRoot() {
		Activity root = this.getParent();

		// 返り値がnullなら親はないので自分を返す
		if (root == null) {
			return this;
		}

		//そうでなければ、getParentを繰り返す
		while (root.getParent() != null) {
			root = root.getParent();
		}

		return root;
	}

	/**
	*	クラスタ中の子アクティビティにおける順番を取得する
	*
	* @return クラスタ内での順番
	*/
	public int getOrder() throws SystemException {
		// rootの場合Orderは0とする
		if (this.isRoot()) {
			return 0;
		}

		// そうでない場合、親があるので、子の中から探す
		Activity[] set = this.getParent().getChildren();

		// childrenの中から検索する
		for (int i = 0; i < set.length; i++) {
			if (this.identifier.equals(set[i].getIdentifier())) {
				return i; //順番を返す
			}
		}

		throw new SystemException("対象アクティビティが見つかりません (getOrder failed) [" + this.identifier + "]");
	}

	/**
	*	クラスタ中の子アクティビティにおける順番を取得する<BR>
	*
	* @return クラスタ内での順番<BR>
	*             ただし root の場合は 0 を返す<BR>
	*/
	public int getAvailableOrder() throws SystemException {
		// rootの場合Orderは0とする
		if (this.isRoot()) {
			return 0;
		}

		// そうでない場合、親があるので、子の中から探す
		Activity[] set = this.getParent().getAvailableChildren();

		// childrenの中から検索する
		for (int i = 0; i < set.length; i++) {
			if (this.identifier.equals(set[i].getIdentifier())) {
				return i; //順番を返す
			}
		}

		throw new SystemException("対象アクティビティが見つかりません。(getAvailableOrder failed) [" + this.identifier + "]");
	}

	/**
	*  教材IDを取得する<BR>
	*
	* @return 教材ID
	*/
	public String getCourseIdentifier() {
		return courseIdentifier;
	}

	/**
	* isVisibleのフラグを返す <BR>
	* (目次中でタイトルを表示するか否かのフラグ) <BR>
	* 
	* @return 目次の表次の可否を示す <BR>
	*  ( true: 表示する / false: 表示しない ) <BR>
	*/
	public boolean getIsVisibleFlag() {
		CachedNode isVisibleNode = itemNode.selectSingleChildNode("@isvisible");

		if (isVisibleNode == null) {
			return true;
		}

		return Boolean.valueOf(isVisibleNode.getNodeValue()).booleanValue();
	}

	/**
	* タイトルを返す <BR>
	* @return タイトルを示す<BR>
	*/
	public String getTitle() {
		CachedNode titleNode = itemNode.selectSimpleSingleNode("title/text()");

		if (titleNode == null) {
			return null;
		}

		return titleNode.getNodeValue();
	}

	/**
	* リソース情報の取得 <BR>
	*
	* @return リソースオブジェクト<BR>
	*/
	public Resource getResource() {
		return resource;
	}

	/**
	* choice コントロールモードのフラグ <BR>
	* 子アクティビティに対するchoiceのナビゲーションリクエストを <BR>
	* 許可するか否かのフラグ <BR>
	*
	* @return choiceナビゲーションリクエストの可否 <BR>
	* ( true: 選択可能 / false: 選択不可 ) <BR>
	*/
	public boolean getChoiceFlag() throws SystemException {
		return sequencing.getControlModeFlag("choice");
	}

	/**
	* choiceExit コントロールモードのフラグ<BR>
	* クラスタ中のアクティビティがchoiceによって、完了の可否のフラグ <BR>
	*
	* @return choiceナビゲーションイベントの可否<BR>
	* ( true: choiceで完了可能 / false: choiceで完了不可) <BR>
	*/
	public boolean getChoiceExitFlag() throws SystemException {
		return sequencing.getControlModeFlag("choiceExit");
	}
	
	// 2010.10.05 taku-harada add >>
	/**
	* jump コントロールモードのフラグ <BR>
	* 子アクティビティに対するjumpのナビゲーションリクエストを <BR>
	* 許可するか否かのフラグ <BR>
	*
	* @return jumpナビゲーションリクエストの可否 <BR>
	* ( true: 選択可能 / false: 選択不可 ) <BR>
	*/
	public boolean getJumpFlag() throws SystemException {
		return sequencing.getControlModeFlag("jump");
	}
	// 2010.10.05 taku-harada add <<

	/**
	* flow コントロールモードのフラグ <BR>
	* クラスタ中のアクティビティに対する <BR>
	* continue/previousナビゲーションリクエストを許可するか否かのフラグ <BR>
	* 
	* @return boolean continue/previousナビゲーションリクエストの可否を示す <BR>
	* ( true: continue/previousが可能 / /false: continue/previousは不可) <BR>
	*/
	public boolean getFlowFlag() throws SystemException {
		return sequencing.getControlModeFlag("flow");
	}

	/**
	* forward only コントロールモードのフラグ<BR>
	* クラスタ中のアクティビティがflowによって、進むことのできる方向を制限するフラグ<BR>
	* 
	* @return 方向を制限するか否かを示す <BR>
	*  true: クラスタ中の遷移方向を順方向のみに制限する <BR>
	*  false: クラスタ中の遷移方向を制限しない <BR>
	*/
	public boolean getForwardOnlyFlag() throws SystemException {
		return sequencing.getControlModeFlag("forwardOnly");
	}

	/**
	* 補助リソースを返す<BR>
	*
	* @return 補助リソースの配列を返す <BR>
	*/
	public AuxiliaryResource[] getAuxiliaryResources() throws SystemException {
		return sequencing.getAuxiliaryResources();
	}

	/**
	* アクティビティのProgress情報を返す <BR>
	*
	* @return アクティビティのProgress情報を返す <BR>
	* 
	*/
	public Progress getProgress() {
		return sequencing.getProgress();
	}

	/**
	* アクティビティに関連した全Objectiveを返す<BR>
	* 
	* @return アクティビティに関連した全Objectiveを返す <BR>
	*/
	public LocalObjective[] getObjective() throws SystemException {
		return sequencing.getObjective();
	}

	/**
	* アクティビティに関連したObjectiveの内、指定したObjectiveを返す<BR>
	* @param ObjectiveID
	* @return 指定したObjectiveを返却 <BR>
	*/
	public LocalObjective getObjective(String ObjectiveID) throws SystemException {
		return sequencing.getObjective(ObjectiveID);
	}

	/**
	* ロールアップに利用するObjectiveを返す <BR>
	*
	* @return ロールアップに関連するObjectiveを返す <BR>
	*/
	public LocalObjective getObjectiveContributeToRollup() {
		return sequencing.getObjectiveContributeToRollup();
	}
	/**
	* 外部アダプタを取得する<BR>
	*
	* @return 外部アダプタ<BR>
	*/
	public SCORMCommunicationModule getCommunicationModule() throws SystemException {
		return sequencing.getCommunicationModule();
	}

	/**
	 * dataFromLMS値の取得を行う
	 *
	 * @return data From LMS
	 */
	public String getDataFromLMS() {
		CachedNode dataFromLMSNode = itemNode.selectSimpleSingleNode("dataFromLMS/text()");

		if (dataFromLMSNode != null) {
			return dataFromLMSNode.getNodeValue();
		}else{
			dataFromLMSNode = itemNode.selectSimpleSingleNode("datafromlms/text()");
			if (dataFromLMSNode != null){
				return dataFromLMSNode.getNodeValue();
			}
		}
		return null;
	}

	/**
	 * CompletionThreshold値の取得を行う
	 *
	 * @return CompletionThreshold
	 */
	public String getCompletionThreshold() {
		// 2011.09.02 taku-harada mod >>
		// 2010.10.01 taku-harada mod >>
		CachedNode completionThreshold = itemNode.selectSimpleSingleNode("completionThreshold/text()");

		if (completionThreshold != null) {
			return completionThreshold.getNodeValue();
		}
//		CachedNode completionThreshold = itemNode.selectSimpleSingleNode("completionThreshold");
//		if (completionThreshold != null) {
//			CachedNode minProgressMeasure = completionThreshold.selectSingleChildNode("@minProgressMeasure");
//			if (minProgressMeasure != null) {
//				return minProgressMeasure.getNodeValue();
//			}
//		}
		// 2010.10.01 taku-harada mod <<
		// 2011.09.02 taku-harada mod >>
		
		return null;
	}

	// 2011.09.09 taku-harada add >>
	/**
	 * ProgressMeasure値の取得を行う
	 *
	 * @return  ProgressMeasure
	 */
	public String getProgressMeasure() {
		CachedNode progressMeasure = itemNode.selectSimpleSingleNode("progressMeasure/text()");

		if (progressMeasure != null) {
			return progressMeasure.getNodeValue();
		}
		
		return null;
	}
	// 2011.09.09 taku-harada add <<

	/**
	 * data値の取得を行う
	 *
	 * @return dataノードの子ノードリスト
	 */
	public Vector<Map<String, String>> getData() {
		CachedNode completionThreshold = itemNode.selectSimpleSingleNode("data");
		
		if (completionThreshold != null) {
			CachedNode[] mapNodes = completionThreshold.selectChildNodeList("map");

			Vector<Map<String, String>> vec = new Vector<Map<String, String>>();

			for (int i = 0; i < mapNodes.length; i++) {
				Map<String, String> map = new HashMap<String, String>();

				String targetID = "";
				String writeSharedData = "";
				String readSharedData = "";
				
				CachedNode targetID_ch = mapNodes[i].selectSingleChildNode("@targetID");
				CachedNode writeSharedData_ch = mapNodes[i].selectSingleChildNode("@writeSharedData");
				CachedNode readSharedData_ch = mapNodes[i].selectSingleChildNode("@readSharedData");
				
				if(targetID_ch != null)targetID = targetID_ch.getNodeValue();
				if(writeSharedData_ch != null)writeSharedData = writeSharedData_ch.getNodeValue();
				if(readSharedData_ch != null)readSharedData = readSharedData_ch.getNodeValue();
				
				map.put("targetID", targetID);
				map.put("writeSharedData", writeSharedData);
				map.put("readSharedData", readSharedData);
				
				vec.add(map);
			}
			
			return vec;

		}
		
		return null;
	}

	/**
	 * hideLMSUI値の取得を行う
	 *
	 * @return hide LMSUI
	 */
	public String[] getHideLMSUI() {
		CachedNode[] hideLMSUINodes =
			itemNode.selectSimpleNodeList("presentation/navigationInterface/hideLMSUI/text()");

		if (hideLMSUINodes == null) {
			return null;
		}

		String[] hideLMSUI = new String[hideLMSUINodes.length];

		for (int i = 0; i < hideLMSUI.length; i++) {
			hideLMSUI[i] = hideLMSUINodes[i].getNodeValue();
		}

		return hideLMSUI;
	}

	/**
	 * persistState値の取得を行う
	 *
	 * @return persistState値
	 */
	public boolean getPersistState() {
		CachedNode persistStateNode = itemNode.selectSimpleSingleNode("persistState/text()");

		if (persistStateNode == null) {
			return false;
		}

		return Boolean.valueOf(persistStateNode.getNodeValue()).booleanValue();
	}

	/**
	 * timeLimitAction値の取得を行う
	 *
	 * @return timeLimitAction値
	 */
	public String getTimeLimitAction() {
		CachedNode timeLimitActionNode = itemNode.selectSimpleSingleNode("timeLimitAction/text()");

		if (timeLimitActionNode != null) {
			return timeLimitActionNode.getNodeValue();
		}else{
			timeLimitActionNode = itemNode.selectSimpleSingleNode("timelimitaction/text()");
			if (timeLimitActionNode != null){
				return timeLimitActionNode.getNodeValue();
			}
		}

		return null;
	}

	/**
	 * parameters属性値の取得を行う
	 *
	 * @return parameters属性値
	 */
	public String getParameters() {
		CachedNode parametersNode = itemNode.selectSimpleSingleNode("@parameters");

		if (parametersNode != null) {
			return parametersNode.getNodeValue();
		}

		return null;
	}

	/**
	 * @param learningLogFolder	学習ログの出力先を指定する。
	 *
	 * @return (次)SCOへのURLを返却する。
	 */
	public String getURL(String learningLogFolder) throws SystemException {
		return sequencing.getURL(learningLogFolder);
	}

	/**
	 * Activity is Activeのフラグを参照する <BR>
	 *
	 * @return アクティビティの状態を示す( true:学習中 / false:未学習中 ) <BR>
	 */
	public boolean isActive() {
		return sequencing.getStatus().getActivityIsActive();
	}

	/**
	 * Activity is Suspendedのフラグを設定する
	 *
	 * @param status 状態を指定する。(true:活動中, false:未活動中)
	 */
	public void setActive(boolean status) {
		sequencing.getStatus().setActivityIsActive(status);
	}

	/**
	 * Activity is Suspendedのフラグを参照する
	 *
	 * @return boolean アクティビティの中断状態を示す(true：中断 /false:完了もしくは未学習) <BR>
	 */
	public boolean isSuspended() {
		return sequencing.getStatus().getActivityIsSuspended();
	}

	/**
	 * Activity is Suspendedのフラグを設定する
	 *
	 * @param status 状態を指定する。(true:中断状態, false:未中断状態)
	 */
	public void setSuspended(boolean status) {
		sequencing.getStatus().setActivityIsSuspended(status);
	}

	/**
	 * プライマリオブジェクティブのObjective Progress Statusを取得する
	 *
	 * @return プライマリオブジェクティブのObjective Progress Status
	 */
	public boolean getObjectiveProgressStatus() throws SystemException {
		return sequencing.getObjectiveContributeToRollup().getObjectiveProgressStatus();
	}

	public boolean getObjectiveLocalProgressStatus() throws SystemException {
		return sequencing.getObjectiveContributeToRollup().getObjectiveLocalProgressStatus();
	}
	/**
	 * プライマリオブジェクティブのObjective Satisfied Statusを取得する
	 *
	 * @return プライマリオブジェクティブのObjective Satisfied Status
	 */
	public boolean getObjectiveSatisfiedStatus() throws SystemException {
		return sequencing.getObjectiveContributeToRollup().getObjectiveSatisfiedStatus();
	}

	/**
	 * プライマリオブジェクティブのObjective Measure Statusを取得する
	 *
	 * @return プライマリオブジェクティブのObjective Measure Status
	 */
	public boolean getObjectiveMeasureStatus() throws SystemException {
		return sequencing.getObjectiveMeasureStatus();
	}

	/**
	 * プライマリオブジェクティブのObjective Normalized Measure取得する
	 *
	 * @return プライマリオブジェクティブのObjective Normalized Measure
	 */
	public BigDecimal getObjectiveNormalizedMeasure() throws SystemException {
		return sequencing.getObjectiveNormalizedMeasure();
	}

	/**
	 * Activity Progress Statusを設定する
	 *
	 * @param status Activity Progress Status
	 */
	public void setActivityProgressStatus(boolean status) {
		sequencing.setActivityProgressStatus(status);
	}

	/**
	 * Activity Progress Statusを取得する
	 *
	 * @return Activity Progress Status
	 */
	public boolean getActivityProgressStatus() throws SystemException {
		try {
			return sequencing.getActivityProgressStatus();
		}
		catch (SystemException e) {
			throw e;
		}
	}

	/**
	 * Activity Absolute Durationを設定する
	 *
	 * @param duration Activity Absolute Duration
	 */
	public void setActivityAbsoluteDuration(Duration duration) throws SystemException {
		sequencing.setActivityAbsoluteDuration(duration);
	}

	/**
	 * Activity Absolute Durationを取得する
	 *
	 * @return Activity Absolute Duration
	 */
	public Duration getActivityAbsoluteDuration() throws SystemException {
		return sequencing.getActivityAbsoluteDuration();
	}

	/**
	 * Activity Experienced Durationを設定する
	 *
	 * @param duration Activity Experienced Duration
	 */
	public void setActivityExperiencedDuration(Duration duration) throws SystemException {
		sequencing.setActivityExperiencedDuration(duration);
	}

	/**
	 * Activity Experienced Durationを取得する
	 *
	 * @return Activity Experienced Duration
	 */
	public Duration getActivityExperiencedDuration() throws SystemException {
		return sequencing.getActivityExperiencedDuration();
	}

	/**
	 * Activity Attempt Countを取得する
	 *
	 * @param count Activity Attempt Count
	 */
	public void setActivityAttemptCount(int count) {
		sequencing.setActivityAttemptCount(count);
	}

	/**
	 * Activity Attempt Countを取得する
	 *
	 * @return Activity Attempt Count
	 */
	public int getActivityAttemptCount() {
		return sequencing.getActivityAttemptCount();
	}

	/**
	 * Attempt Progress Statusを設定する
	 *
	 * @param status Attempt Progress Status
	 */
	public void setAttemptProgressStatus(boolean status) throws SystemException {
		sequencing.setAttemptProgressStatus(status);
	}

	/**
	 * Attempt Progress Statusを取得する
	 *
	 * @return Attempt Progress Status
	 */
	public boolean getAttemptProgressStatus() throws SystemException {
		return sequencing.getAttemptProgressStatus();
	}

	public boolean getAttemptProgressStatus(boolean isCurrent) throws SystemException {
		return sequencing.getAttemptProgressStatus(isCurrent);
	}
	/**
	 * Attempt Completion Amountを設定する
	 *
	 * @param amount Attempt Completion Amount
	 */
	public void setAttemptCompletionAmount(BigDecimal amount) throws SystemException {
		sequencing.setAttemptCompletionAmount(amount);
	}

	/**
	 * Attempt Completion Amountを取得する
	 *
	 * @return Attempt Completion Amount
	 */
	public BigDecimal getAttemptCompletionAmount() throws SystemException {
		return sequencing.getAttemptCompletionAmount();
	}

	/**
	 * Attempt Completion Statusを設定する
	 *
	 * @param status Attempt Completion Status
	 */
	public void setAttemptCompletionStatus(boolean status) throws SystemException {
		sequencing.setAttemptCompletionStatus(status);
	}

	/**
	 * Attempt Completion Statusを取得する
	 *
	 * @return Attempt Completion Status
	 */
	public boolean getAttemptCompletionStatus() throws SystemException {
		return sequencing.getAttemptCompletionStatus();
	}

	/**
	 * Attempt Absolute Durationを設定する
	 *
	 * @param duration Attempt Absolute Duration
	 */
	public void setAttemptAbsoluteDuration(Duration duration) {
		sequencing.setAttemptAbsoluteDuration(duration);
	}

	/**
	 * Attempt Absolute Durationを取得する
	 *
	 * @return カレントアクティビティのAttempt Absolute Duration
	 */
	public Duration getAttemptAbsoluteDuration() {
		return sequencing.getAttemptAbsoluteDuration();
	}

	/**
	 * Attempt Experienced Durationを設定する
	 *
	 * @param duration Attempt Experienced Duration
	 */
	public void setAttemptExperiencedDuration(Duration duration) {
		sequencing.setAttemptExperiencedDuration(duration);
	}

	/**
	 * Attempt Experienced Durationを取得する
	 *
	 * @return Attempt Experienced Duration
	 */
	public Duration getAttemptExperiencedDuration() {
		return sequencing.getAttemptExperiencedDuration();
	}

	/**
	 * カレントアクティビティがPrevious可能かどうかを取得する
	 *
	 * @return Previous可能な場合はtrueを、それ以外の場合はfalseを返却する
	 */
	public boolean canPrevious() throws SystemException {
		boolean result = false;

		if (parentActivity == null) {
			result = false;
		}
		else if (parentActivity.getFlowFlag()) {
			result = !parentActivity.getForwardOnlyFlag();
		}

		if (result) {
			result = canAvailableBackward();
		}

		return result;
	}

	/**
	 * カレントアクティビティがContinue可能かどうかを取得する
	 *
	 * @return Continue可能な場合はtrueを、それ以外の場合はfalseを返却する
	 */
	public boolean canContinue() throws SystemException {
		boolean result = false;

		if (parentActivity == null) {
			result = false;
		}
		else {
			result = parentActivity.getFlowFlag();
		}

		if (result) {
			result = canAvailableForward();
		}

		return result;
	}

	/**
	 * カレントアクティビティがExit可能かどうかを取得する
	 *
	 * @return Exit可能な場合はtrueを、それ以外の場合はfalseを返却する
	 */
	public boolean canExit() {
		return isActive();
	}

	/**
	 * カレントアクティビティがChoice可能かどうかを取得する
	 *
	 * @return Choice可能な場合はtrueを、それ以外の場合はfalseを返却する
	 */
	public boolean canChoice() throws SystemException {
		if (parentActivity == null) {
			return true;
		}
		return parentActivity.getChoiceFlag();
	}

	// 2010.10.05 taku-harada add >>
	/**
	 * カレントアクティビティがJump可能かどうかを取得する
	 *
	 * @return Jump可能な場合はtrueを、それ以外の場合はfalseを返却する
	 */
	public boolean canJump() throws SystemException {
		if (parentActivity == null) {
			return true;
		}
		return parentActivity.getJumpFlag();
	}
	// 2010.10.05 taku-harada add <<

	public boolean getUseCurrentAttempt(){
		return sequencing.getUseCurrentAttempt();
	}

	public void setUseCurrentAttempt(boolean tmpflag){
		sequencing.setUseCurrentAttempt(tmpflag);
	}
}
