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

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

import java.math.BigDecimal;

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 jp.co.ntt.lms.lo.scorm.util.XPathUtil;

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

/**
* Progress class<BR>
* ActivityごとのProgress情報を表すクラス<BR>
*/
public class Progress {
	/** 0.0000のBigDecimal */
	private static final BigDecimal zero = new BigDecimal("0.0").setScale(4, BigDecimal.ROUND_HALF_UP);

	/** 1.0000のBigDecimal */
	private static final BigDecimal one = new BigDecimal("1.0").setScale(4, BigDecimal.ROUND_HALF_UP);

	/** activity progress status */
	private boolean activityProgressStatus;

	/** activity absolute duration */
	private Duration activityAbsoluteDuration;

	/** activity experienced duration */
	private Duration activityExperiencedDuration;

	/** activity attempt count */
	private int activityAttemptCount;

	/** attempt progress status */
	private boolean attemptProgressStatus;

	/** attempt completion amount */
	private BigDecimal attemptCompletionAmount;

	/** attempt completion status */
	private boolean attemptCompletionStatus;

	/** attempt absolute duration */
	private Duration attemptAbsoluteDuration;

	/** attempt experienced duration */
	private Duration attemptExperiencedDuration;

	/** 前回attempt時の attempt progress status */
	private boolean previousAttemptProgressStatus[] = { false, false };

	/** 前回attempt時の attempt completion amount */
	private BigDecimal previousAttemptCompletionAmount[] = { zero, zero };

	/** 前回attempt時の attempt completion status */
	private boolean previousAttemptCompletionStatus[] = { false, false };

	/** 前回attempt時の attempt absolute duration */
	private Duration previousAttemptAbsoluteDuration[] = { new Duration(0), new Duration(0)};

	/** 前回attempt時の attempt experienced duration */
	private Duration previousAttemptExperiencedDuration[] = { new Duration(0), new Duration(0)};

	/** activity */
	private Activity activity;

	/**
	 * デフォルトコンストラクタ
	 */
	public Progress() {}

	/**
	 * コンストラクタ<BR>
	 * @param activity	このProgressのActivityを指定する<BR>
	 * @param manifestNode	教材構造ノード<BR>
	 */
	public Progress(Activity activity, CachedNode manifestNode) throws SystemException {
		this.activity = activity;

		activityProgressStatus = false;
		activityAbsoluteDuration = new Duration(0);
		activityExperiencedDuration = new Duration(0);
		activityAttemptCount = 0;

		attemptProgressStatus = false;
		attemptCompletionAmount = zero;
		attemptCompletionStatus = false;
		attemptAbsoluteDuration = new Duration(0);
		attemptExperiencedDuration = new Duration(0);
	}

	/**
	 * 中断情報取得<BR>
	 *
	 * @return progressの中断情報の文字列<BR>
	 */
	public void save(Document doc, Element parent, boolean traceLog) throws SystemException {
		try {
			boolean activityProgressStatus;
			String activityAbsoluteDuration = "";
			String activityExperiencedDuration = "";
			String activityAttemptCount = "";

			if (!traceLog) {
				activityProgressStatus = this.activityProgressStatus;
				if (activityProgressStatus) {
					activityAbsoluteDuration = this.activityAbsoluteDuration.toString();
					activityExperiencedDuration = this.activityExperiencedDuration.toString();
					activityAttemptCount = Integer.toString(this.activityAttemptCount);
				}
			}
			else {
				activityProgressStatus = getActivityProgressStatus();
				if (activityProgressStatus) {
					activityAbsoluteDuration = getActivityAbsoluteDuration().toString();
					activityExperiencedDuration = getActivityExperiencedDuration().toString();
					activityAttemptCount = Integer.toString(getActivityAttemptCount());
				}
			}

			boolean attemptProgressStatus;
			String attemptCompletionAmount = "";
			String attemptCompletionStatus = "";
			String attemptAbsoluteDuration = "";
			String attemptExperiencedDuration = "";

			if (!traceLog) {
				attemptProgressStatus = this.attemptProgressStatus;
				attemptCompletionAmount = this.attemptCompletionAmount.toString();
				if (attemptProgressStatus) {
					attemptCompletionStatus = Boolean.toString(this.attemptCompletionStatus);
				}
				attemptAbsoluteDuration = this.attemptAbsoluteDuration.toString();
				attemptExperiencedDuration = this.attemptExperiencedDuration.toString();
			}
			else {
				attemptProgressStatus = getAttemptProgressStatus();
				if (attemptProgressStatus) {
					attemptCompletionAmount = getAttemptCompletionAmount().toString();
					attemptCompletionStatus = Boolean.toString(getAttemptCompletionStatus());
					attemptAbsoluteDuration = getAttemptAbsoluteDuration().toString();
					attemptExperiencedDuration = getAttemptExperiencedDuration().toString();
				}
			}

			XMLUtil.append(
				doc,
				parent,
				"progress",
				new Element[] {
					XMLUtil.createElement(doc, "activityprogressstatus", Boolean.toString(activityProgressStatus)),
					XMLUtil.createElement(doc, "activityabsoluteduration", activityAbsoluteDuration),
					XMLUtil.createElement(doc, "activityexperiencedduration", activityExperiencedDuration),
					XMLUtil.createElement(doc, "activityattemptcount", activityAttemptCount),
					XMLUtil.createElement(doc, "attemptprogressstatus", Boolean.toString(attemptProgressStatus)),
					XMLUtil.createElement(doc, "attemptcompletionamount", attemptCompletionAmount),
					XMLUtil.createElement(doc, "attemptcompletionstatus", attemptCompletionStatus),
					XMLUtil.createElement(doc, "attemptabsoluteduration", attemptAbsoluteDuration),
					XMLUtil.createElement(doc, "attemptexperiencedduration", attemptExperiencedDuration),
					XMLUtil.createElement(
						doc,
						"previous",
						new Element[] {
							XMLUtil.createElement(
								doc,
								"attemptprogressstatus",
								Boolean.toString(previousAttemptProgressStatus[0])),
							XMLUtil.createElement(
								doc,
								"attemptcompletionamount",
								previousAttemptCompletionAmount[0].toString()),
							XMLUtil.createElement(
								doc,
								"attemptcompletionstatus",
								(!previousAttemptProgressStatus[0])
									? null
									: Boolean.toString(previousAttemptCompletionStatus[0])),
							XMLUtil.createElement(
								doc,
								"attemptabsoluteduration",
								previousAttemptAbsoluteDuration[0].toString()),
							XMLUtil.createElement(
								doc,
								"attemptexperiencedduration",
								previousAttemptExperiencedDuration[0].toString()),
							}),
					XMLUtil.createElement(
						doc,
						"candidateprevious",
						new Element[] {
							XMLUtil.createElement(
								doc,
								"attemptprogressstatus",
								Boolean.toString(previousAttemptProgressStatus[1])),
							XMLUtil.createElement(
								doc,
								"attemptcompletionamount",
								previousAttemptCompletionAmount[1].toString()),
							XMLUtil.createElement(
								doc,
								"attemptcompletionstatus",
								(!previousAttemptProgressStatus[1])
									? null
									: Boolean.toString(previousAttemptCompletionStatus[1])),
							XMLUtil.createElement(
								doc,
								"attemptabsoluteduration",
								previousAttemptAbsoluteDuration[1].toString()),
							XMLUtil.createElement(
								doc,
								"attemptexperiencedduration",
								previousAttemptExperiencedDuration[1].toString()),
							}),
					});
		}
		catch (Exception ex) {
			throw new SystemException("save failed [ActivityID:" + activity.getIdentifier() + "]", ex);
		}
	}

	/**
	 * Progress情報の初期化<BR>
	 */
	public void initializeProgressInformation(CachedNode parent) throws SystemException {
		// アクティビティの初期化
		initializeActivityProgressInformation();

		// アクティビティの学習毎情報の初期化
		initializeAttemptProgressInformation();

		if (parent == null) {
			return;
		}

		try {
			Node progressNode = XPathUtil.selectSingleChildNode(parent.getNode(), "progress");

			// activity progress status
			activityProgressStatus =
				Boolean
					.valueOf(
						XPathUtil
							.selectSimpleSingleNode(progressNode, "activityprogressstatus/text()")
							.getNodeValue())
					.booleanValue();

			if (activityProgressStatus) {
				// activity absolute duration
				activityAbsoluteDuration =
					new Duration(
						XPathUtil
							.selectSimpleSingleNode(progressNode, "activityabsoluteduration/text()")
							.getNodeValue());

				// activity experienced duration
				activityExperiencedDuration =
					new Duration(
						XPathUtil
							.selectSimpleSingleNode(progressNode, "activityexperiencedduration/text()")
							.getNodeValue());

				// activity attempt count
				activityAttemptCount =
					Integer.parseInt(
						XPathUtil.selectSimpleSingleNode(progressNode, "activityattemptcount/text()").getNodeValue());
			}

			// activity attempt progress status
			attemptProgressStatus =
				Boolean
					.valueOf(
						XPathUtil
							.selectSimpleSingleNode(progressNode, "attemptprogressstatus/text()")
							.getNodeValue())
					.booleanValue();

			// activity attempt completion amount
			attemptCompletionAmount =
				new BigDecimal(
					XPathUtil.selectSimpleSingleNode(progressNode, "attemptcompletionamount/text()").getNodeValue());

			if (attemptProgressStatus) {
				// activity attempt completion status
				attemptCompletionStatus =
					Boolean
						.valueOf(
							XPathUtil
								.selectSimpleSingleNode(progressNode, "attemptcompletionstatus/text()")
								.getNodeValue())
						.booleanValue();
			}

			// activity attempt absolute duration
			attemptAbsoluteDuration =
				new Duration(
					XPathUtil.selectSimpleSingleNode(progressNode, "attemptabsoluteduration/text()").getNodeValue());

			// activity attempt experienced duration
			attemptExperiencedDuration =
				new Duration(
					XPathUtil
						.selectSimpleSingleNode(progressNode, "attemptexperiencedduration/text()")
						.getNodeValue());

			Node previousNode = XPathUtil.selectSingleChildNode(progressNode, "previous");

			previousAttemptProgressStatus[0] =
				Boolean
					.valueOf(
						XPathUtil
							.selectSimpleSingleNode(previousNode, "attemptprogressstatus/text()")
							.getNodeValue())
					.booleanValue();

			previousAttemptCompletionAmount[0] =
				new BigDecimal(
					XPathUtil.selectSimpleSingleNode(previousNode, "attemptcompletionamount/text()").getNodeValue());

			if (previousAttemptProgressStatus[0]) {
				previousAttemptCompletionStatus[0] =
					Boolean
						.valueOf(
							XPathUtil
								.selectSimpleSingleNode(previousNode, "attemptcompletionstatus/text()")
								.getNodeValue())
						.booleanValue();
			}

			previousAttemptAbsoluteDuration[0] =
				new Duration(
					XPathUtil.selectSimpleSingleNode(previousNode, "attemptabsoluteduration/text()").getNodeValue());

			previousAttemptExperiencedDuration[0] =
				new Duration(
					XPathUtil
						.selectSimpleSingleNode(previousNode, "attemptexperiencedduration/text()")
						.getNodeValue());

			Node candidatePreviousNode = XPathUtil.selectSingleChildNode(progressNode, "candidateprevious");

			previousAttemptProgressStatus[1] =
				Boolean
					.valueOf(
						XPathUtil
							.selectSimpleSingleNode(candidatePreviousNode, "attemptprogressstatus/text()")
							.getNodeValue())
					.booleanValue();

			previousAttemptCompletionAmount[1] =
				new BigDecimal(
					XPathUtil
						.selectSimpleSingleNode(candidatePreviousNode, "attemptcompletionamount/text()")
						.getNodeValue());

			if (previousAttemptProgressStatus[1]) {
				previousAttemptCompletionStatus[1] =
					Boolean
						.valueOf(
							XPathUtil
								.selectSimpleSingleNode(candidatePreviousNode, "attemptcompletionstatus/text()")
								.getNodeValue())
						.booleanValue();
			}

			previousAttemptAbsoluteDuration[1] =
				new Duration(
					XPathUtil
						.selectSimpleSingleNode(candidatePreviousNode, "attemptabsoluteduration/text()")
						.getNodeValue());

			previousAttemptExperiencedDuration[1] =
				new Duration(
					XPathUtil
						.selectSimpleSingleNode(candidatePreviousNode, "attemptexperiencedduration/text()")
						.getNodeValue());
		}
		catch (SystemException ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new SystemException(
				"initializeProgressInformation failed [ActivityID:" + activity.getIdentifier() + "]",
				ex);
		}
	}

	/**
	 * 試行情報の初期化<BR>
	 */
	public void initializeAttemptInformation() throws SystemException {
		try {
			// アクティビティの学習毎情報の初期化
			initializeAttemptProgressInformation();
		}
		catch (SystemException ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new SystemException(
				"initializeAttemptInformation failed [ActivityID:" + activity.getIdentifier() + "]",
				ex);
		}
	}

	/**
	 * アクティビティの進捗情報の初期化<BR>
	 */
	private void initializeActivityProgressInformation() {
		activityProgressStatus = false;
		activityAbsoluteDuration = new Duration(0);
		activityExperiencedDuration = new Duration(0);
		activityAttemptCount = 0;
	}

	/*
	 * useCurrentAttemptの為の候補値を更新する
	 */
	public void setCandidatePreviousValue() throws SystemException {
		// 前回attempt情報の保存
		previousAttemptProgressStatus[1] = getAttemptProgressStatus();
		if (previousAttemptProgressStatus[1]) {
			previousAttemptCompletionAmount[1] = getAttemptCompletionAmount();
			previousAttemptCompletionStatus[1] = getAttemptCompletionStatus();
			previousAttemptAbsoluteDuration[1] = getAttemptAbsoluteDuration();
			previousAttemptExperiencedDuration[1] = getAttemptExperiencedDuration();
		}
	}

	/**
	 * アクティビティの学習毎の進捗情報の初期化<BR>
	 */
	private void initializeAttemptProgressInformation() throws SystemException {
		try {
			// 前回attempt情報の更新
			previousAttemptProgressStatus[0] = previousAttemptProgressStatus[1];
			if (previousAttemptProgressStatus[0]) {
				previousAttemptCompletionAmount[0] = previousAttemptCompletionAmount[1];
				previousAttemptCompletionStatus[0] = previousAttemptCompletionStatus[1];
				previousAttemptAbsoluteDuration[0] = previousAttemptAbsoluteDuration[1];
				previousAttemptExperiencedDuration[0] = previousAttemptExperiencedDuration[1];
			}

			attemptProgressStatus = false;
			attemptCompletionAmount = zero;
			attemptCompletionStatus = false;
			attemptAbsoluteDuration = new Duration(0);
			attemptExperiencedDuration = new Duration(0);
		}
		catch (Exception ex) {
			throw new SystemException(
				"initializeAttemptProgressInformation failed [ActivityID:" + activity.getIdentifier() + "]",
				ex);
		}
	}

	/**
	 * 終期化
	 */
	public void termiante() {
		activity = null;
	}

	/**
	 * Activity Progress Statusのセット
	 *
	 * @param result
	 */
	public void setActivityProgressStatus(boolean result) {
		activityProgressStatus = result;
	}

	/**
	 * activity progress status の取得<BR>
	 *
	 * @return boolean	 true 有効<BR>
	 *					 false 無効<BR>
	 */
	public boolean getActivityProgressStatus() throws SystemException {
		if (!activity.getSequencing().getDeliveryControlFlag("tracked")) {
			return false;
		}

		return activityProgressStatus;
	}

	/**
	 * Activity Absolute Durationのセット
	 *
	 * @param duration
	 */
	public void setActivityAbsoluteDuration(Duration duration) {
		activityAbsoluteDuration = duration;
	}

	/**
	 *  activity absolute duration の取得<BR>
	 *
	 *  @return duration activity absolute duration<BR>
	 */
	public Duration getActivityAbsoluteDuration() {
		return activityAbsoluteDuration;
	}

	/**
	 * Activity Experienced durationのセット
	 *
	 * @param duration
	 */
	public void setActivityExperiencedDuration(Duration duration) {
		activityExperiencedDuration = duration;
	}

	/**
	 * activity experienced duration の取得<BR>
	 *
	 * @return duration activity experienced duration<BR>
	 */
	public Duration getActivityExperiencedDuration() throws SystemException {
		return activityExperiencedDuration;
	}

	/**
	 * activity attemp count のセット
	 *
	 * @param count	カウント
	 */
	public void setActivityAttemptCount(int count) {
		activityAttemptCount = count;
	}

	/**
	 * activity attempt count の取得<BR>
	 *
	 * @return activity attempt count<BR>
	 */
	public int getActivityAttemptCount() {
		return activityAttemptCount;
	}

	/**
	 * Activity attempt progress status のセット
	 *
	 * @param status	true:有効, false:無効
	 */
	public void setAttemptProgressStatus(boolean status) {
		attemptProgressStatus = status;
	}

	/**
	 * attempt progress statusの取得<BR>
	 *
	 * @return boolean 
	 *		 true	activity attempt completion status, amountが有効<BR>
	 *		 false	activity attempt completion status, amountが無効<BR>
	 */
	public boolean getAttemptProgressStatusForEvaluation() throws SystemException {
		try {
			if (!activity.isRoot()
				&& !activity.getParent().getSequencing().getControlModeFlag("useCurrentAttemptProgressInfo")) {
				return previousAttemptProgressStatus[0];
			}

			return getAttemptProgressStatus();
		}
		catch (SystemException ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new SystemException(
				"getAttemptProgressStatusForEvaluation failed [ActivityID:" + activity.getIdentifier() + "]",
				ex);
		}
	}

	/**
	 * attempt progress status の取得<BR>
	 * ( use current attempt completion status によらない )<BR>
	 *
	 * @return boolean	true 有効<BR>
	 *					false 無効<BR>
	 */
	public boolean getAttemptProgressStatus() throws SystemException {
		try {
			if (!activity.getSequencing().getDeliveryControlFlag("tracked")) {
				return false;
			}

			if ((!activity.hasChildren()) && (!activity.hasAvailableChildren())) {
				if (activity.getCommunicationModule().getAttemptProgressStatus().booleanValue()) {
					return true;
				}
			}

			return attemptProgressStatus;
		}
		catch (SystemException ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new SystemException(
				"getAttemptProgressStatus failed [ActivityID:" + activity.getIdentifier() + "]",
				ex);
		}
	}

	/**
	 * attempt progress status の取得<BR>
	 * 
	 *
	 * @return boolean	true 有効<BR>
	 *					false 無効<BR>
	 */
	public boolean getAttemptProgressStatus(boolean isCurrent) throws SystemException {
		try {
			if (activity.isRoot())
			{
				return attemptProgressStatus;
			}
			
			if(!activity.getParent().getSequencing().getControlModeFlag("useCurrentAttemptProgressInfo")) {
				return getAttemptProgressStatus();
			}else{
				if(isCurrent){
					return getAttemptProgressStatus();
				}
				else // falseの時は常にfalseを返す
				{
					return false;
				}
			}
		}
		catch (SystemException ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new SystemException(
				"getAttemptProgressStatusForEvaluation failed [ActivityID:" + activity.getIdentifier() + "]",
				ex);
		}
	}

	/**
	 * attempt completion amountのセット<BR>
	 *
	 * @param amount 完了率を0.0〜1.0の小数で指定する<BR>
	 */
	public void setAttemptCompletionAmount(BigDecimal amount) {
		attemptCompletionAmount = amount.setScale(4, BigDecimal.ROUND_HALF_UP);
	}

	/**
	 * attempt completion amount の取得<BR>
	 *
	 * @return	完了率<BR>
	 *			0.0から1.0の小数<BR>
	 */
	public BigDecimal getAttemptCompletionAmountForEvaluation() throws SystemException {
		try {
			if (!activity.isRoot()
				&& !activity.getParent().getSequencing().getControlModeFlag("useCurrentAttemptProgressInfo")) {
				return previousAttemptCompletionAmount[0];
			}

			return getAttemptCompletionAmount();
		}
		catch (SystemException ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new SystemException(
				"getAttemptCompletionAmountForEvaluation failed [ActivityID:" + activity.getIdentifier() + "]",
				ex);
		}
	}

	/**
	 * attempt completion amount の取得<BR>
	 * ( use current attempt completion status によらない )<BR>
	 *
	 * @return	完了度<BR>
	 *			0.0から1.0の小数<BR>
	 */
	public BigDecimal getAttemptCompletionAmount() throws SystemException {
		try {
			if (activity.hasAvailableChildren()) {
				return attemptCompletionAmount;
			}

			return getAttemptCompletionStatus() ? one : zero;
		}
		catch (SystemException ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new SystemException(
				"getAttemptCompletionAmount failed [ActivityID:" + activity.getIdentifier() + "]",
				ex);
		}
	}

	/**
	 * attempt completion statusのセット<BR>
	 *
	 * @param status	true:学習完了<BR>
	 *					false:学習未完了<BR>
	 */
	public void setAttemptCompletionStatus(boolean status) {
		attemptCompletionStatus = status;
	}

	/**
	 * attempt completion status の取得<BR>
	 *
	 * @return boolean	attempt completion status を返す<BR>
	 *					true : 完了<BR>
	 *					false : 未完了<BR>
	 */
	public boolean getAttemptCompletionStatusForEvaluation() throws SystemException {
		try {
			if (!activity.isRoot()
				&& !activity.getParent().getSequencing().getControlModeFlag("useCurrentAttemptProgressInfo")) {
				return previousAttemptCompletionStatus[0];
			}

			return getAttemptCompletionStatus();
		}
		catch (SystemException ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new SystemException(
				"getAttemptCompletionStatusForEvaluation failed [ActivityID:" + activity.getIdentifier() + "]",
				ex);
		}
	}

	/**
	 * attempt completion status の取得<BR>
	 *
	 * @return boolean	attempt completion status を返す<BR>
	 *					true : 完了<BR>
	 *					false : 未完了<BR>
	 */
	public boolean getAttemptCompletionStatus(boolean isCurrent) throws SystemException {
		try {
			if (activity.isRoot()){
				return getAttemptCompletionStatus();
			}
			
			if(!activity.getParent().getSequencing().getControlModeFlag("useCurrentAttemptProgressInfo")) {
				return getAttemptCompletionStatus();
			}
			else
			{
				if(isCurrent){
					return getAttemptCompletionStatus();
				}
				else // falseの時は常にfalseを返す
				{
					return false;
				}
			}

			
		}
		catch (SystemException ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new SystemException(
				"getAttemptCompletionStatusForEvaluation failed [ActivityID:" + activity.getIdentifier() + "]",
				ex);
		}
	}
	/**
	 * attempt completion status の取得<BR>
	 * ( use current attempt completion status によらない)<BR>
	 *
	 * @return boolean	true 学習完了状態にある<BR>
	 *					false 学習未完了状態にある<BR>
	 */
	public boolean getAttemptCompletionStatus() throws SystemException {
		try {
			if ((!activity.hasChildren()) && (!activity.hasAvailableChildren())) {
				Boolean result = activity.getCommunicationModule().getAttemptCompletionStatus();

				if (result != null) {
					return result.booleanValue();
				}
			}

			return attemptCompletionStatus;
		}
		catch (SystemException ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new SystemException(
				"getAttemptCompletionStatus failed [ActivityID:" + activity.getIdentifier() + "]",
				ex);
		}
	}

	/**
	 * attempt absolute duration へのセット
	 *
	 * @param duration attempt absolute duration<BR>
	 */
	public void setAttemptAbsoluteDuration(Duration duration) {
		attemptAbsoluteDuration = duration;
	}

	/**
	 *  attempt absolute duration の取得<BR>
	 *
	 *  @return activity attempt absolute duration<BR>
	 */
	public Duration getAttemptAbsoluteDurationForEvaluation() throws SystemException {
		try {
			if (!activity.isRoot()
				&& !activity.getParent().getSequencing().getControlModeFlag("useCurrentAttemptProgressInfo")) {
				return previousAttemptAbsoluteDuration[0];
			}

			return getAttemptAbsoluteDuration();
		}
		catch (SystemException ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new SystemException(
				"getAttemptAbsoluteDurationForEvaluation failed [ActivityID:" + activity.getIdentifier() + "]",
				ex);
		}
	}

	/**
	 *  attempt absolute duration の取得<BR>
	 *
	 *  @return activity attempt absolute duration<BR>
	 */
	public Duration getAttemptAbsoluteDuration() {
		return attemptAbsoluteDuration;
	}

	/**
	 * attempt experienced duration のセット<BR>
	 *
	 * @param  duration activity attempt experienced duration<BR>
	 */
	public void setAttemptExperiencedDuration(Duration duration) {
		attemptExperiencedDuration = duration;
	}

	/**
	 * attempt experienced duration の取得<BR>
	 *
	 *  @return duration アクティビティの学習回毎の実学習時間<BR>
	 */
	public Duration getAttemptExperiencedDurationForEvaluation() throws SystemException {
		try {
			if (!activity.isRoot()
				&& !activity.getParent().getSequencing().getControlModeFlag("useCurrentAttemptProgressInfo")) {
				return previousAttemptExperiencedDuration[0];
			}

			return getAttemptExperiencedDuration();
		}
		catch (SystemException ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new SystemException(
				"getAttemptExperiencedDurationForEvaluation failed [ActivityID:" + activity.getIdentifier() + "]",
				ex);
		}
	}

	/**
	 * attempt experienced duration の取得<BR>
	 *
	 *  @return duration アクティビティの学習回毎の実学習時間<BR>
	 */
	public Duration getAttemptExperiencedDuration() {
		return attemptExperiencedDuration;
	}
}
