/////////////////////////////////////////////////////////////////
//Copyright (C) 2005 NTT CORPORATION.
//
//	進捗クラス
//
//		変更履歴
//			2005.01.27  新規作成  Katsuhiko.Sakurai(UNITEC)
//
//	機能
//
//	このクラスは進捗を表すクラスです。
//
////////////////////////////////////////////////////////////////
package jp.co.ntt.lms.lo.progress;

import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import jp.co.ntt.lms.Common.RDF.RDFDocument;
import jp.co.ntt.lms.Common.RDF.RDFNode;
import jp.co.ntt.lms.lo.LoComData;
import jp.co.ntt.lms.lo.LoTopClient;
import jp.co.ntt.lms.lo.SmartForce.CourseUnitLogRecord;
import jp.co.ntt.lms.lo.progress.util.LOConfiguration;
import jp.co.ntt.lms.lo.progress.util.LearningProgressConfigurationManager;
import jp.co.ntt.lms.lo.progress.util.LearningStatusConfiguration;
import jp.co.ntt.lms.lo.progress.util.TimeSpan;
import jp.co.ntt.lms.lo.progress.util.XMOInformationGetter;
import jp.co.ntt.lms.xmo.Environment;
import jp.co.ntt.lms.xmo.Assignments.AssignmentsClient;
import jp.co.ntt.lms.xmo.GroupAndPeople.GroupAndPeopleClient;
import jp.co.ntt.lms.xmo.Lo.LoClient;
import jp.co.ntt.lms.xmo.LoRelation.LoRelationClient;
import jp.co.ntt.lms.xmo.util.DebugLog;
import jp.co.ntt.lms.xms.framework.XmsException;
import jp.co.ntt.lms.xms.framework.base.Logic;
import jp.co.ntt.lms.xms.framework.base.RemoteLogicClient;
import jp.co.ntt.lms.xms.logsumup.LoLogConstant;
import jp.co.ntt.lms.xms.logsumup.LoLogLearnMaterialStatusLogic;
import jp.co.ntt.lms.xms.logsumup.LoLogLearnStatusParam;
import jp.co.ntt.lms.xms.logsumup.LoLogLearnStatusResult;
import jp.co.ntt.lms.xms.logsumup.scorm.IndividualLogUserProgressLogic;
import jp.co.ntt.lms.xms.logsumup.scorm.IndividualLogUserProgressResult;
import jp.co.ntt.lms.xms.logsumup.scorm.IndividualLogUserProgressStoreData;
import jp.co.ntt.lms.xms.logsumup.scorm.ScormDocument;
import jp.co.ntt.lms.xms.logsumup.scorm.ScormItemList;

/**
* 進捗クラスです。
* 
* @author Katsuhiko Sakurai (UNITEC)
* @version 1.0
*/
public class LearningProgress {
	
	private Date startDate = null;
	private Date endDate = null;
	private String studyStatus = null;
	private String progress = null;
	private String progressRate = null;
	private String loID = null;
	private String userID = null;
	private boolean isAssigned = true;
	private String loType = null;
	private LoState loState = null;
	
	private LearningProgressConfigurationManager configManager = null; 
	
	private final static String NO_DATA_STRING = "---";
	private final String DATE_FORMAT_STRING = "yyyy/MM/dd";
	private final String PROGRESS_RATE_UNIT ="%";
	private final String LEARNING_SPAN_UNIT ="日";
	
	/**
	 * 進捗率100%を表す文字列
	 */
	private final String PROGRESS_RATE_COMPLETE = "100";
	
	/**
	 * 進捗率0%を表す文字列
	 */
	private final String PROGRESS_RATE_NOTSTART = "0";
	
	/**
	 * コンストラクタです。
	 * 
	 */
	public LearningProgress(){}
	
	/**
	 * コンストラクタです。
	 * 
	 * @param userID 対象となるグループIDもしくはユーザID
	 * @param loID 対象となるLoID 
	 * @throws Exception
	 */
	public LearningProgress(String userID, String loID) throws Exception{
		this(userID, loID, null);
	}
	
	/**
	 * コンストラクタです。
	 * 
	 * @param userID 対象となるグループIDもしくはユーザID
	 * @param loID 対象となるLoID 
	 * @param configManager 設定値管理オブジェクト 
	 * @throws Exception
	 */
	public LearningProgress(String userID, String loID, LearningProgressConfigurationManager configManager) throws Exception{
		
		this.userID = userID;
		this.loID = loID;
		this.configManager = configManager;
		
		// LO種別を取得
		LoClient loClient = XMOInformationGetter.getLO(loID);
		this.loType = (loClient == null) ? "" : loClient.getLoType();

		// 進捗データの初期化初期化
		this.setAssignmentNoData();

		// ユーザであれば進捗を作成
		if (userID.startsWith("GR") == false ) { 
			this.makeProgress(userID, loID, this.loType);
		}
	}
	
	/**
	 * 学習終了日を取得します。
	 * 
	 * @return Date 学習終了日 
	 */
	public Date getEndDate() {
		return this.endDate;
	}

	/**
	 * 整形化された学習終了日を取得します。
	 * 
	 * @return String 整形化された学習終了日 
	 */
	public String getFormattedEndDate() {
		return ( this.endDate ==null 
				? NO_DATA_STRING
				: new SimpleDateFormat(DATE_FORMAT_STRING).format(this.endDate));
	}

	/**
	 * 対象となるLOIDを取得します。
	 * 
	 * @return String LOID 
	 */
	public String getLoID() {
		return this.loID;
	}
	
	/**
	 * 進捗状況を取得します。
	 * 
	 * @return String 進捗状況
	 */
	public String getProgress() {
		return this.progress;
	}
	
	/**
	 * 整形化された進捗状況を取得します。
	 * 
	 * @return String 整形化された進捗状況
	 */
	public String getFormattedProgress() {
		return ( this.progress.length() == 0 ? NO_DATA_STRING : this.progress );
	}

	/**
	 * 進捗率を取得します。
	 * 
	 * @return String 進捗率
	 */
	public String getProgressRate() {
		return this.progressRate;
	}

	/**
	 * 整形化された進捗率を取得します。
	 * 
	 * @return String 整形化された進捗率
	 */
	public String getFormattedProgressRate() {
		
		// 進捗率が設定されていない場合
		// 進捗率が0%、100%の場合
		// データなし文字列を返す
		if (this.progressRate.length() == 0 
				|| this.progressRate.equals("100") 
				|| this.progressRate.equals("0")) {
			
			return NO_DATA_STRING;
			
		} else {
		
			return this.progressRate + PROGRESS_RATE_UNIT;
		}
	}

	/**
	 * 学習開始日を取得します。
	 * 
	 * @return Date 学習開始日
	 */
	public Date getStartDate() {
		return this.startDate;
	}
	
	/**
	 * 整形化した学習開始日を取得します。
	 * 
	 * @return String 整形化した学習開始日
	 */
	public String getFormattedStartDate() {
		return ( this.startDate ==null 
					? NO_DATA_STRING
					: new SimpleDateFormat(DATE_FORMAT_STRING).format(this.startDate));
	}

	/**
	 * 学習状況を取得します。
	 * 
	 * @return String 学習状況
	 */
	public String getStudyStatus() {
		return this.studyStatus;
	}

	/**
	 * 整形化された学習状況を取得します。
	 * 
	 * @return String 整形化された学習状況
	 */
	public String getFormattedStudyStatus() {
		return (this.studyStatus.length()==0 ? NO_DATA_STRING : this.studyStatus);
	}
	
	/**
	 * 学習期間を取得します。
	 * 
	 * @return String 学習期間
	 */
	public String getLearningSpan() {
		if (this.endDate == null || this.startDate == null ) {
			return "";
		} else {
			double endTime = this.endDate.getTime();
			double startTime = this.startDate.getTime();
			
			// 日数単位に変換し、端数は切り上げ
			int span = (int)Math.ceil( ( endTime - startTime ) / (24*60*60*1000) );
			return String.valueOf(span);
		}
	}
	
	/**
	 * 整形化した学習期間を取得します。
	 * 
	 * @return String 整形化した学習期間
	 */
	public String getFormattedLearningSpan() {
		
		String learningSpan = this.getLearningSpan();
		
		if (learningSpan.length() == 0 ) {
			return NO_DATA_STRING;
		} else {
			return learningSpan + LEARNING_SPAN_UNIT;
		}
	}
	
	/**
	 * 指定ユーザに指定LOがアサインされているかどうかを取得します。
	 * 
	 * @return boolean アサインされていればTrue
	 */
	public boolean isAssigned () {
		return this.isAssigned;
	}
	
	/**
	 * 進捗データの初期値を設定します。
	 *
	 */
	private void setAssignmentNoData() {
		this.startDate = null;
		this.endDate = null;
		this.studyStatus = "";
		this.progress = "";
		this.progressRate = "";
		this.loState = null;
	}
	
	/**
	 * 進捗を作成します。
	 * 
	 * @param userID ユーザIDもしくはグループID
	 * @param loID　LOID
	 * @param loType Lo種別
	 * @throws Exception
	 */
	private void makeProgress( String userID, String loID, String loType) throws Exception {
		
		DebugLog.write( this.getClass(), 
				MessageFormat.format("進捗生成開始：LOID={0},UserID={1},LOType={2}",new String[]{loID,userID,loType}),
						DebugLog.ROW );

		// ルートLOなら処理なし
		if (loID.equals("LO0")) return;
		
		// 指定ユーザに指定されたLOがアサインされているかチェック
		if (AssignmentsClient.checkAssignAuth(userID, loID, AssignmentsClient.LEARN_TYPE) == false ) {
			this.isAssigned = false;
			return;
		}
		
		// 進捗状況設定XMLファイルのデータを取得
		LearningProgressConfigurationManager configManager = ( this.configManager == null
																	? new LearningProgressConfigurationManager()
																	: this.configManager );
		
		LOConfiguration loConfig = configManager.getLOCongifuration(loID);
		LearningStatusConfiguration learningStatusConfig = configManager.getLearningStatusConfiguration();

		//● 学習開始日を取得
		Date learningStartDate = this.getLearningStartDate(userID, loID, loConfig);
		DebugLog.write( this.getClass(), "学習開始日取得終了：" + (learningStartDate==null ?"なし":learningStartDate.toString()), DebugLog.ROW );
		
		//● 学習終了日を取得
		Date learningEndData = this.getLearningEndDate(userID, loID, learningStartDate, loConfig);
		DebugLog.write( this.getClass(), "学習終了日取得終了："+ (learningEndData==null ?"なし":learningEndData.toString()), DebugLog.ROW );
				
		//● LO共通ログを取得
		LoLogLearnStatusResult commonLog = this.getLoLog(loID,userID);
		DebugLog.write( this.getClass(), "LO共通ログ取得終了：", DebugLog.ROW );
		
		//● LOの状態を取得
		LoState loState = this.getLoState(commonLog);
		
		//● 学習状況の取得
		String studyStatus = this.getStudyStatus(loState, learningStatusConfig);
		DebugLog.write( this.getClass(), "学習状況取得終了："+ studyStatus, DebugLog.ROW );
		
		//● LOの進捗率を取得
		String loProgressRate = this.makeLoProgressRate(loState, loConfig);
		DebugLog.write( this.getClass(), "LO進捗率："+loProgressRate, DebugLog.ROW );
		
		//● LO種別による振り分け処理
		String progressStatus=null;
		String progressRate=null;
		
		//■ コンテナの場合
		if (loType.equals("0")) {
			
			Map childProgressRateList = new HashMap();
			
			LoRelationClient loRelation = new LoRelationClient();
			List childLoIDs = loRelation.getLoIds( loID );

			Iterator ite = childLoIDs.iterator();
			while(ite.hasNext()){
				LearningProgress childLearningProgress = new LearningProgress(userID, ite.next().toString(), configManager);
				
				//進捗率リストに追加
				childProgressRateList.put(childLearningProgress.getLoID(), childLearningProgress.getProgressRate());
			}
			
			// 子供Loの進捗率の計算
			String childLoProgressRate = this.makeContainerProgressRate(childProgressRateList, loConfig);
			DebugLog.write( this.getClass(), "コンテナ子供の進捗率：" + childLoProgressRate, DebugLog.ROW );
			
			//● 進捗率の計算
			progressRate = this.makeProgressRate(loProgressRate, childLoProgressRate);
			DebugLog.write( this.getClass(), "コンテナ進捗率取得終了："+progressRate, DebugLog.ROW );
			
			// 最終的な進捗率から学習状況の変更
			if ( loState.isNotStart && progressRate.equals("0") == false ) {
				loState.isNotStart = false;
				studyStatus = this.getStudyStatus(loState, learningStatusConfig);
			}
			
		//■ XcalatⅡサーバ(WBT)の場合
		}else if(loType.equals("1")) {
			
			//● 個別ログの取得
			jp.co.ntt.lms.lo.WBT.IndividualLog.IndividualLogUserProgressStatusStoreData
										individualLog = this.getWBTIndividualLoLog(loID, userID);
			
			DebugLog.write( this.getClass(), "WBT個別ログ取得終了：", DebugLog.ROW );
			
			// ユニットログからユニットの状態を取得
			List unitStateList = this.getWBTStateList(individualLog);
			
			//ユニットの進捗率の計算
			String unitProgressRate = this.makeUnitProgressRate(unitStateList, loConfig);
			DebugLog.write( this.getClass(), "WBTユニット進捗率："+unitProgressRate, DebugLog.ROW );

			//● 進捗率の計算
			progressRate = this.makeProgressRate(loProgressRate, unitProgressRate);
			DebugLog.write( this.getClass(), "WBT進捗率取得終了："+progressRate, DebugLog.ROW );

		//■ SmartForceの場合
		}else if(loType.equals("4")) {
		
			//● 個別ログの取得
			CourseUnitLogRecord[] individualLog	= this.getSmartForceIndividualLoLog(loID, userID);
			
			DebugLog.write( this.getClass(), "SmartForce個別ログ取得終了：", DebugLog.ROW );
			
			// ユニットログからユニットの進捗率を取得
			String unitProgressRate = this.makeSmartForceUnitProgressRate(individualLog, loConfig);
			DebugLog.write( this.getClass(), "SmartForceユニット進捗率："+unitProgressRate, DebugLog.ROW );

			//● 進捗率の計算
			progressRate = this.makeProgressRate(loProgressRate, unitProgressRate);
			DebugLog.write( this.getClass(), "SmartForce進捗率取得終了："+progressRate, DebugLog.ROW );

		//■ Offlineの場合
		}else if(loType.equals("19")) {

			//● 個別ログの取得
			jp.co.ntt.lms.lo.Offline.IndividualLog.IndividualLogUserProgressStatusStoreData individualLog
				= this.getOfflineIndividualLoLog(loID, userID);
			
			DebugLog.write( this.getClass(), "Offline個別ログ取得終了：", DebugLog.ROW );
			
			// ユニットログからユニットの状態を取得
			List unitStateList = this.getOfflineStateList(individualLog);
			
			//ユニットの進捗率の計算
			String unitProgressRate = this.makeUnitProgressRate(unitStateList, loConfig);
			DebugLog.write( this.getClass(), "Offlineユニット進捗率："+unitProgressRate, DebugLog.ROW );

			//● 進捗率の計算
			progressRate = this.makeProgressRate(loProgressRate, unitProgressRate);
			DebugLog.write( this.getClass(), "Offline進捗率取得終了："+progressRate, DebugLog.ROW );

			
		//■ Scormの場合
		}else if (loType.equals("20")) {

			//● ユニットログの取得
			IndividualLogUserProgressResult individualLog = this.getScormIndividualLoLog(loID, userID);
			DebugLog.write( this.getClass(), "Scorm個別ログ取得終了：", DebugLog.ROW );
			
			// ユニットログからユニットの状態を取得
			List unitStateList = this.getUnitStateList(individualLog);
			
			//ユニットの進捗率の計算
			String unitProgressRate = this.makeUnitProgressRate(unitStateList, loConfig);
			DebugLog.write( this.getClass(), "Scormユニット進捗率："+unitProgressRate, DebugLog.ROW );

			//● 進捗率の計算
			progressRate = this.makeProgressRate(loProgressRate, unitProgressRate);
			DebugLog.write( this.getClass(), "Scorm進捗率取得終了："+progressRate, DebugLog.ROW );

		//■ 個別ログがない場合
		}else {
			
			// LOの進捗率を全体の進捗率とする
			progressRate = loProgressRate;
		}

		DebugLog.write( this.getClass(), "全体の進捗率："+progressRate, DebugLog.ROW );

		//● 進捗状況の算出
		progressStatus = this.makeProgressStatus(learningStartDate, learningEndData, progressRate, loConfig);
		DebugLog.write( this.getClass(), "進捗状況取得終了："+progressStatus, DebugLog.ROW );
		
		//● 取得した情報を保存
		this.startDate = learningStartDate;
		this.endDate = learningEndData;
		this.studyStatus = studyStatus;
		this.progressRate = progressRate;
		this.progress = progressStatus;
		this.loState = loState;
	}
	
	/**
	 * WBTの個別ログを取得します。
	 * 
	 * @param loID LOID
	 * @param userID　ユーザIDもしくはグループID
	 * @return IndividualLogUserProgressStatusStoreData WBTの個別ログデータ
	 * @throws Exception
	 */
	private jp.co.ntt.lms.lo.WBT.IndividualLog.IndividualLogUserProgressStatusStoreData getWBTIndividualLoLog(String loID, String userID) throws Exception {
		
		jp.co.ntt.lms.lo.WBT.IndividualLog.IndividualLogStoreData logData = 
			new jp.co.ntt.lms.lo.WBT.IndividualLog.IndividualLogStoreData();

		String realLoID = logData.getRealLoID(loID);

		// 教材種別を元にLoTopClientをインスタンス化
		// LOサーバ名の取得
		Environment env = new Environment();
		String serverName = env.getLoServerName();
		
		// LOクラスをインスタンス化します。
		LoClient lo = XMOInformationGetter.getLO(loID);
		String loType = lo.getLoType();
		LoTopClient loTopClient = new LoTopClient( serverName, loType );

		if( loTopClient.getData(realLoID) == false ) return null;
		if( loTopClient.getDataLength() == 0 ) return null;

		// LOから教材詳細情報を取得
		LoComData loComData = loTopClient.getDataInfo(0);

		// 教材IDの取得
		String	materialID = loComData.getMaterialID();

		// LOから教材詳細情報を取得
		Hashtable params = new Hashtable();
		params.put( "MATID", materialID );

		if( loTopClient.getMaterialStructFile(params) == false ) return null;
		
		String document = loTopClient.getMaterialFile();

		RDFDocument rdfDocument = new RDFDocument();
		RDFNode rdfNode = rdfDocument.load( new StringBuffer(document) );

		jp.co.ntt.lms.lo.WBT.IndividualLog.IndividualLogUserProgressStatusStoreData storeData = 
				new jp.co.ntt.lms.lo.WBT.IndividualLog.IndividualLogUserProgressStatusStoreData( loID, userID, loType , rdfNode);
		
		if( storeData.makeStoreData() == false ) return null;
		if( storeData.getMaxData() == 0 ) return null;
		
		return storeData;
	}

	/**
	 * コンテナの進捗率を取得する
	 * 
	 * @param childProgressRateList コンテナの子供LOの進捗率リスト
	 * @param loConfig LOの外部ファイル設定情報
	 * @return　String　コンテナの進捗率
	 */
	private String makeContainerProgressRate(Map childProgressRateList, LOConfiguration loConfig) {

		double containerProgressRateSum =0;
		boolean couldGetWeight = true;
		double childLoProgressRateSum = 0;
		
		Iterator ite = childProgressRateList.keySet().iterator();
		while(ite.hasNext()) {

			String chiliLoID = ite.next().toString();
			String childProgressRate = childProgressRateList.get(chiliLoID).toString();
			
			if (childProgressRate.length() == 0) return "";

			// 子供LOの進捗率を加算
			try {
				childLoProgressRateSum += Double.parseDouble(childProgressRate);

			}catch(NumberFormatException nfe){
				DebugLog.write(this.getClass(), "コンテナの子供LOの進捗率数値変換エラー", DebugLog.MID);
				return "";
			}
			
			// LOの進捗状況が設定されていなければ重み取得なし
			if (loConfig == null) continue;
			
			// Lo毎の重みを取得
			String weight = loConfig.getUnitWeight(chiliLoID);
			
			// ユニット毎の重みが設定されていなければ、
			// 進捗率の判定不能なので各LOの進捗率の平均をとる
			if (weight.length() == 0) {
				couldGetWeight = false;
				continue;
			}
			
			//LOの進捗率を加算
			try {
				containerProgressRateSum += Integer.parseInt(childProgressRate) * Double.parseDouble(weight);

			}catch(NumberFormatException nfe){
				DebugLog.write(this.getClass(), "コンテナの子供LOの重み数値変換エラー", DebugLog.MID);
				return "";
			}
		}
		
		// 重みを取得できた場合は計算した進捗率を返す
		if(couldGetWeight) {
			return String.valueOf(Math.round(containerProgressRateSum));
		// 重みを取得できなかった場合は進捗率の平均を返す
		} else {
			return String.valueOf(Math.round(childLoProgressRateSum / childProgressRateList.keySet().size()));
		}
	}

	/**
	 * 学習状況文字列を取得する
	 * 
	 * @param loState LOの状態
	 * @param learningStatusConfig 学習状況名の外部設定ファイル情報
	 * @return　String　学習状況文字列
	 */
	private String getStudyStatus(LoState loState,
									LearningStatusConfiguration learningStatusConfig) {
		
		// 学習状況をを取得する
		if ( loState.isComplete ){
			return learningStatusConfig.getCompleteScreenName();
		} else if (loState.isNotStart ) {
			return learningStatusConfig.getNotStartScreenName();
		} else {
			return learningStatusConfig.getNotCompleteScreenName();
		}
	}

	/**
	 * 進捗状況を作成します。
	 * 
	 * @param startDate 学習開始日
	 * @param endDate　学習終了日
	 * @param progressRate 進捗率
	 * @param config　LOの外部設定ファイル情報
	 * @return String 進捗状況
	 */
	private String makeProgressStatus(Date startDate,
											Date endDate, 
											String progressRate, 
											LOConfiguration config) {
		
		if ( progressRate.length() == 0 || endDate == null || config == null ) return "";
		if ( progressRate.equals("100") ||  progressRate.equals("0") ) return "";

		// 当日を取得
		Date today = new Date();
		
		// 学習期間を取得
		long span = ( (endDate.getTime() - startDate.getTime() ) / (24*60*60*1000) ) +1;
		
		DebugLog.write( this.getClass(), "学習期間取得終了："+String.valueOf(span), DebugLog.ROW );

		// 標準進捗率を取得
		long standardProgressRate = ( ( ( today.getTime() - startDate.getTime() ) / (24*60*60*1000) ) +1 ) * 100 / span;
		
		// 標準進捗率が100％を超えた場合は100％に修正する
		if (standardProgressRate > 100) standardProgressRate = 100;
		
		DebugLog.write( this.getClass(), "標準進捗率取得終了："+String.valueOf(standardProgressRate), DebugLog.ROW );
		
		// 標準進捗率に対する割合を計算
		long ratioToStandardProgressRate = 0; 
		try {
			if (standardProgressRate == 0) {
				ratioToStandardProgressRate = 100;
			} else {
				ratioToStandardProgressRate = Integer.parseInt(progressRate) * 100 / standardProgressRate;
			}
		}catch(NumberFormatException nfe) {
			DebugLog.write(this.getClass(), "進捗率数値変換エラー", DebugLog.MID);
			return "";
		}
		
		DebugLog.write( this.getClass(), "標準進捗率に対する割合取得終了："+String.valueOf(ratioToStandardProgressRate), DebugLog.ROW );
		
		// 標準進捗率に対する割合に該当する名称を設定ファイルから取得する
		return config.getProgressStatusName(ratioToStandardProgressRate);
	}

	/**
	 * LOの共通進捗率を作成します。
	 * 
	 * @param loState LOの状態
	 * @param config　LO進捗設定
	 * @return String 　LOの進捗率
	 * @throws XmsException
	 */
	private String makeLoProgressRate(LoState loState, LOConfiguration config) throws XmsException {
		
		// ①指定されたLOの進捗状況設定ファイルが存在するか取得する
		// 設定ファイルが存在しなければ、LOの完了ステータスから100％もしくは0％を返す。
		// それ以外はユニットの完了ステータスから判定
		if (config == null) {
			if (loState.isComplete) return PROGRESS_RATE_COMPLETE;
			if (loState.isNotStart) return PROGRESS_RATE_NOTSTART;
			
			return "";
		}
		
		String completeRate = config.getCompleteRate();
		String notCompleteRate = config.getNotCompleteRate();
		String notStartRete = config.getNotStartRate();

		// 設定ファイルに進捗率が指定されていない場合、進捗率判定不能
		if (completeRate.length() == 0 || notCompleteRate.length() == 0 || notStartRete.length() == 0 ) return "";
				
		//② LOのステータスから外部定義された進捗率を返す
		String loProgressRate;
		if (loState.isComplete ){
			loProgressRate = completeRate;
		} else if (loState.isNotStart) {
			loProgressRate = notStartRete;
		} else {
			loProgressRate = notCompleteRate;
		}
		
		return loProgressRate;
	}

	/**
	 * 進捗率を作成します。
	 * 
	 * @param loProgressRate　LOの共通進捗率
	 * @param unitProgressRate　ユニットの進捗率
	 * @return String 進捗率
	 * @throws XmsException
	 */
	private String makeProgressRate(String loProgressRate, String unitProgressRate) throws XmsException {
		
		// LOの進捗率が100ならLOの進捗率を返す
		if ( loProgressRate.equals(PROGRESS_RATE_COMPLETE) ) return loProgressRate;
		
		// ユニットの進捗率が0ならLOの進捗率を返す
		return ( unitProgressRate.equals(PROGRESS_RATE_NOTSTART) 
					? loProgressRate
					: unitProgressRate);
	}

	/**
	 * ユニットの進捗率を作成します。
	 * 
	 * @param unitStateList ユニットの学習状況のリスト 
	 * @param config LOの外部設定ファイル情報
	 * @return String ユニットの進捗率
	 * @throws XmsException
	 */
	private String makeUnitProgressRate(List unitStateList, LOConfiguration config) throws XmsException {
		
		if(config == null) return "";
		
		String completeRate = config.getCompleteRate();
		String notCompleteRate = config.getNotCompleteRate();
		String notStartRete = config.getNotStartRate();
		
		// 設定ファイルに進捗率が指定されていない場合、進捗率判定不能
		if (completeRate.length() == 0 || notCompleteRate.length() == 0 || notStartRete.length() == 0 ) return "";
				
		// ユニット毎のステータスから進捗率を取得する
		String unitProgressRate;
		boolean couldGetWeight = true;
		double unitProgressRateSum =0;
		double unitProgressRateOnWeightSum =0;
		Iterator ite = unitStateList.iterator();
		while(ite.hasNext()) {
			LoState unitState = (LoState)ite.next();
			
			// ステータスにより進捗率を取得
			if (unitState.isComplete) {
				unitProgressRate = completeRate;
			} else if (unitState.isNotStart) {
				unitProgressRate = notStartRete;
			} else {
				unitProgressRate = notCompleteRate;
			}
			
			// ユニットの進捗率を加算
			try {
				unitProgressRateSum += Double.parseDouble(unitProgressRate);
				
			}catch(NumberFormatException nfe) {
				DebugLog.write(this.getClass(), "ユニットの進捗率数値変換エラー", DebugLog.MID);
				return "";
			}
			
			// ユニット毎の重みを取得
			String activityID = unitState.id;

			String weight = config.getUnitWeight(activityID);
			DebugLog.write( this.getClass(), 
					MessageFormat.format("ユニットのID={0}, ユニットの重み={1}", new String[]{activityID,weight}),
					DebugLog.ROW );
			
			// ユニット毎の重みが設定されていなければ、
			// 進捗率の判定不能
			if (weight.length() == 0) couldGetWeight = false;
			
			//ユニットの進捗率を重みつきで加算
			try{
				unitProgressRateOnWeightSum += Integer.parseInt(unitProgressRate) * Double.parseDouble(weight);
			
			}catch(NumberFormatException nfe){
				DebugLog.write(this.getClass(), "ユニットの重み数値変換エラー", DebugLog.MID);
				return "";
			}
		}
		
		// 重みが設定されていれば重みつきの進捗率を返す
		if (couldGetWeight) {
			return String.valueOf(Math.round(unitProgressRateOnWeightSum));
		//　重みが設定されていなければ進捗率の平均を返す
		} else {
			return String.valueOf(Math.round(unitProgressRateSum / unitStateList.size()));
		}

	}

	/**
	 * ユニットの状態リストを取得します。
	 * 
	 * @param individualLog ユニットの個別ログ情報
	 * @return List ユニットの状態リスト
	 * @throws XmsException
	 */
	private List getUnitStateList(IndividualLogUserProgressResult individualLog) throws XmsException {
		
		ArrayList list = new ArrayList();
		
		// ユニットのステータスを取得する
		Iterator ite = individualLog.getLog().iterator();
		while(ite.hasNext()) {
			IndividualLogUserProgressStoreData unitLog = (IndividualLogUserProgressStoreData)ite.next();
			LoState unitState = new LoState(unitLog.strActivityID, unitLog.blUnitComplete, (unitLog.datStartDate == null));
			list.add(unitState);
		}

		return list;
	}

	/**
	 * SmartForceのユニットの進捗率を作成します。
	 * 
	 * @param individualLog SmartForceの個別ログリスト
	 * @param config LOの外部設定ファイル情報
	 * @return String SmartForceのユニットの進捗率
	 * @throws XmsException
	 */
	private String makeSmartForceUnitProgressRate(CourseUnitLogRecord[] individualLog, LOConfiguration config) throws XmsException {
		
		boolean couldGetWeight = true;
		double unitProgressRateSum =0;
		double unitProgressRateOnWeightSum =0;
		
		// 個別ログがなければ個別ログの進捗率なし
		if ( individualLog == null || individualLog.length == 0 || config == null) return "";
		
		for(int i=0; i<individualLog.length; i++) {

			// ユニットログが存在しなければ教材の進捗率を返却する
			if (individualLog[i].getUnitCount().equals("0")) {
				return individualLog[i].getProgressRate();
			}
			
			// ユニットの進捗率取得
			String unitProgressRate = individualLog[i].getUnitProgress();
			if ( unitProgressRate.length() == 0) return individualLog[i].getProgressRate();
			
			// ユニットの進捗率を加算
			try {
				unitProgressRateSum += Double.parseDouble(unitProgressRate);
				
			}catch(NumberFormatException nfe) {
				DebugLog.write(this.getClass(), "SmartForceユニットの進捗率数値変換エラー", DebugLog.MID);
				return "";
			}
			
			// ユニットID取得
			String unitID = individualLog[i].getUnitOrder();

			// ユニットの重み取得
			String weight = config.getUnitWeight(unitID);
			
			// ユニット毎の重みが設定されていなければ、進捗率の判定不能
			if (weight.length() == 0) couldGetWeight = false;
			
			//ユニットの進捗率を重みつきで加算
			try{
				unitProgressRateOnWeightSum += Integer.parseInt(unitProgressRate) * Double.parseDouble(weight);
			
			}catch(NumberFormatException nfe){
				DebugLog.write(this.getClass(), "SmartForceユニットの重み数値変換エラー", DebugLog.MID);
				return "";
			}
		}

		// 重みが設定されていれば重みつきの進捗率を返す
		if (couldGetWeight) {
			return String.valueOf(Math.round(unitProgressRateOnWeightSum));
		//　重みが設定されていなければ進捗率の平均を返す
		} else {
			return String.valueOf(Math.round(unitProgressRateSum / individualLog.length));
		}
	}

	/**
	 * オフラインLOのユニットの状態リストを取得します。
	 * 
	 * @param individualLog オフラインLOの個別ログ情報
	 * @return List オフラインLOのユニットの状態リスト
	 * @throws XmsException
	 */
	private List getOfflineStateList(jp.co.ntt.lms.lo.Offline.IndividualLog.IndividualLogUserProgressStatusStoreData individualLog) throws XmsException {
		
		final int FIELD_SECTION_ID = 10;
		final int FIELD_LEARNING_SATART_DATE = 1;
		final int FIELD_COMPLETE = 7;
		final String STR_COMPLETE = "1";
		
		ArrayList list = new ArrayList();
		
		// 個別ログがなければ空のリストを返す
		if(individualLog == null) return list;
		
		// ユニットのステータスを取得する
		for(int i=0; i<individualLog.getMaxData(); i++) {
			List auLog = individualLog.getStoreData( i );
			LoState unitState = new LoState(auLog.get(FIELD_SECTION_ID).toString(), 
											auLog.get(FIELD_COMPLETE).equals(STR_COMPLETE), 
											( auLog.get(FIELD_LEARNING_SATART_DATE).toString().length() != 0 ) );
			list.add(unitState);
		}

		return list;
	}

	/**
	 * WBTのユニットの状態リストを取得します。
	 * 
	 * @param individualLog WBTの個別ログ情報
	 * @return　List WBTのユニットの状態リスト
	 * @throws XmsException
	 */
	private List getWBTStateList(jp.co.ntt.lms.lo.WBT.IndividualLog.IndividualLogUserProgressStatusStoreData individualLog) throws XmsException {
		
		final int FIELD_SECTION_ID = 10;
		final int FIELD_LEARNING_SATART_DATE = 1;
		final int FIELD_COMPLETE = 7;
		final String STR_COMPLETE = "1";
		
		ArrayList list = new ArrayList();
		
		// ログが取得できなかった場合、空のリストを返す
		if (individualLog == null ) return list;
		
		// ユニットのステータスを取得する
		for(int i=0; i<individualLog.getMaxData(); i++) {
			List auLog = individualLog.getStoreData( i );
			LoState unitState = new LoState(auLog.get(FIELD_SECTION_ID).toString(), 
											auLog.get(FIELD_COMPLETE).equals(STR_COMPLETE), 
											( auLog.get(FIELD_LEARNING_SATART_DATE).toString().length() != 0 ) );
			list.add(unitState);
		}

		return list;
	}

	/**
	 * LOの状態を取得します。
	 * 
	 * @param commonLog LOの共通ログ情報
	 * @return LoState LOの情報
	 * @throws XmsException
	 */
	private LoState getLoState(LoLogLearnStatusResult commonLog) throws XmsException {
		
		// ●　LOのステータスを取得する
		boolean isComplete = commonLog.getCompleteCondition().equals("1");
		boolean isNotStart = ( commonLog.getDateStart() == null || commonLog.getDateStart().equals("") );
		String id = commonLog.getId();
		
		return new LoState(id, isComplete, isNotStart);
	}

	/**
	 * Scormの個別ログ情報を取得します。
	 * 
	 * @param loID LoID
	 * @param userID ユーザIDもしくはグループID
	 * @return Scormの個別ログ情報
	 * @throws Exception
	 */
	private IndividualLogUserProgressResult getScormIndividualLoLog(String loID, String userID) throws Exception {
		
		LoClient lo = XMOInformationGetter.getLO(loID);
		
		ScormDocument scormDoc = this.getScormDocument(loID, lo.getLoType());
		
		// ロジック取得
		Logic logic = new IndividualLogUserProgressLogic(
					                userID,
					                loID,
					                lo.getLoType(),
					                lo.getForeignID(),
									"",
									scormDoc.getRootItemID(),
							        new ScormItemList(scormDoc, scormDoc.getRootItemID()) );
		
		DebugLog.write( this.getClass(), "Scorm個別ログロジック取得成功：", DebugLog.ROW );

		// RMIクライアント
		RemoteLogicClient remote = new RemoteLogicClient();

		// ログ取得
		//LogicResult result = remote.doLogic(logic);
		IndividualLogUserProgressResult result = (IndividualLogUserProgressResult)remote.doLogic(logic);
		
		result.beforeFirst();
		result.next();
			
		return result;
	}

	/**
	 * OfflineLOの個別ログ情報を取得します。
	 * 
	 * @param loID LoID
	 * @param userID ユーザIDもしくはグループID
	 * @return IndividualLogUserProgressStatusStoreData OfflineLOの個別ログ情報
	 * @throws Exception
	 */
	private jp.co.ntt.lms.lo.Offline.IndividualLog.IndividualLogUserProgressStatusStoreData getOfflineIndividualLoLog(String loID, String userID) throws Exception {
		
		jp.co.ntt.lms.lo.Offline.IndividualLog.IndividualLogStoreData logData 
			= new jp.co.ntt.lms.lo.Offline.IndividualLog.IndividualLogStoreData();
		
		String realLoID = logData.getRealLoID(loID);

		// 教材種別を元にLoTopClientをインスタンス化
		// LOサーバ名の取得
		Environment env = new Environment();
		String serverName = env.getLoServerName();
		
		// LOクラスをインスタンス化します。
		LoClient lo = XMOInformationGetter.getLO(loID);
		String loType = lo.getLoType();
		LoTopClient loTopClient = new LoTopClient( serverName, loType );

		if( loTopClient.getData(realLoID) == false ) return null;
		if( loTopClient.getDataLength() == 0 ) return null;

		// LOから教材詳細情報を取得
		LoComData loComData = loTopClient.getDataInfo(0);

		// 教材IDの取得
		String	materialID = loComData.getMaterialID();

		// LOから教材詳細情報を取得
		Hashtable params = new Hashtable();
		params.put( "MATID", materialID );

		if( loTopClient.getMaterialStructFile(params) == false ) return null;
		
		String document = loTopClient.getMaterialFile();

		RDFDocument rdfDocument = new RDFDocument();
		RDFNode rdfNode = rdfDocument.load( new StringBuffer(document) );
		
		jp.co.ntt.lms.lo.Offline.IndividualLog.IndividualLogUserProgressStatusStoreData storeData 
			= new jp.co.ntt.lms.lo.Offline.IndividualLog.IndividualLogUserProgressStatusStoreData( loID, userID, loType , rdfNode);
		
		if( storeData.makeStoreData() == false ) return null;
		if( storeData.getMaxData() == 0 ) return null;
		
		return storeData;
	}

	/**
	 * SmartForceの個別ログ情報を取得します。
	 * 
	 * @param loID LoID
	 * @param userID ユーザIDもしくはグループID
	 * @return CourseUnitLogRecord[] SmartForceの個別ログ情報
	 * @throws Exception
	 */
	private CourseUnitLogRecord[] getSmartForceIndividualLoLog(String loID, String userID) throws Exception {
		
		Environment env = new Environment();
		String serverName = env.getLoServerName();

		// LOクラスをインスタンス化します。
		LoClient lo = XMOInformationGetter.getLO(loID);
		String loType = lo.getLoType();
		LoTopClient loTopClient = new LoTopClient( serverName, loType );
		
		// LOID→RealLOIDへ変換
		String realLOID = lo.getRealLOID();
		
		// 個別ログ取得
		if(loTopClient.getIndividualLog(userID, realLOID) == false) return null;

		// 結果データ取得
		CourseUnitLogRecord[] courceUnitList = (CourseUnitLogRecord[])loTopClient.getIndividualLog();
		
		return courceUnitList;
	}

	/**
	 * アサイン情報を取得します。
	 * 
	 * @param userID ユーザIDもしくはグループID
	 * @param loID LoID
	 * @return AssignmentsClient アサイン情報
	 * @throws Exception
	 */
	private AssignmentsClient getAssignment( String userID, String loID ) throws Exception {
		
		String membershipID = this.getMembershipID(userID);
		String materialID = this.getMaterialID(loID);
		
		if (membershipID == null || materialID == null) return null;
		
		AssignmentsClient client = new AssignmentsClient();
		
		client.setWhereMemberShipID(membershipID);
		client.setWhereMaterialID(materialID);

		if( client.select() == false ) return null;
		if( client.next() == false ) return null;
		
		return client;
	}
	
	/**
	 * 指定したユーザを子供に持つメンバーIDを取得します。
	 * 
	 * @param childID ユーザID
	 * @return String メンバーID
	 * @throws Exception
	 */
	private String getMembershipID( String childID ) throws Exception {
		
		GroupAndPeopleClient client = new GroupAndPeopleClient();
		client.setWhereChildID(childID);
		
		if( client.select() == false ) return null;
		if( client.next() == false ) return null;
		
		return client.getMemberShipID();
	}

	/**
	 * LOの標準学習時間を取得します。
	 * 
	 * @param loID LOID
	 * @return String LO標準学習時間
	 * @throws Exception
	 */
	private String getLOLearningSpan( String loID ) throws Exception {
		
		LoClient loClient = new LoClient();

		// 検索条件にLOIDを設定する
		loClient.setTimeSpan( loID );
		
		return loClient.getTimeSpan();
	}

	/**
	 * 指定したLOを子供に持つコンポーネントIDを取得します。
	 * 
	 * @param childID ユーザID
	 * @return String コンポーネントID
	 * @throws Exception
	 */
	private String getMaterialID( String childID ) throws Exception {
		
		LoRelationClient client = new LoRelationClient();
		client.setWhereChildID(childID);
		
		if( client.select() == false ) return null;
		if( client.next() == false ) return null;
		
		return client.getmaterialID();
	}

	/**
	 * 学習開始日を取得します。
	 * 
	 * @param userID ユーザID
	 * @param loID LoID
	 * @param config LOの外部ファイル設定情報
	 * @return Date 学習開始日
	 * @throws Exception
	 */
	private Date getLearningStartDate( String userID, String loID, LOConfiguration config ) throws Exception {

		// アサインLOを取得
		String assignedLOID = XMOInformationGetter.getAssignedParentLOID(loID, userID, AssignmentsClient.LEARN_TYPE);
		if( assignedLOID.length() ==0 ) return null;
		LoClient assignedLO = XMOInformationGetter.getLO(assignedLOID);
			
		// LOのアサイン情報を取得
		AssignmentsClient assignment = this.getAssignment(userID, assignedLO.getLoID());

		// LOのカスタムアサインの日付を取得
		Date customStartDate = assignment.getOpeningDate();
		
		//カスタムアサインの学習開始日が設定されている場合
		//カスタムアサインの学習開始日を学習開始日とする
		if ( customStartDate != null ) return customStartDate;

		//TODO: マイラーニング・パス機能からの取得
//		LoClient lo = XMOInformationGetter.getLO(loID);
//		Date loStartDate = lo.getStartDate();
//		if (loStartDate != null ) return loStartDate;
		
		if ( config != null ) {
			Date configStartDate = config.getStartDate();
			if (configStartDate != null ) return configStartDate;
		}
		
		//上記以外の場合、LOの割当日を学習開始日とする
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

		return sdf.parse(assignment.getStudyStartDate());
	}

	/**
	 * 学習終了日を取得します。
	 * 
	 * @param userID ユーザID
	 * @param loID LoID
	 * @param startDate 学習開始日
	 * @param config Loの外部ファイル設定情報
	 * @return Date 学習終了日
	 * @throws Exception
	 */
	private Date getLearningEndDate( String userID, String loID, Date startDate, LOConfiguration config ) throws Exception {

		// アサインLOを取得
		String assignedLOID = XMOInformationGetter.getAssignedParentLOID(loID, userID, AssignmentsClient.LEARN_TYPE);
		if( assignedLOID.length() ==0 ) return null;
		LoClient assignedLO = XMOInformationGetter.getLO(assignedLOID);

		// LOのアサイン情報を取得
		AssignmentsClient assignment = this.getAssignment(userID, assignedLOID);

		// LOのカスタムアサインの日付を取得
		Date customEndDate = assignment.getClosingDate();
		
		//カスタムアサインの学習終了日が設定されていて、学習開始日よりも後の日付であれば
		//カスタムアサインの学習終了日を学習終了日とする
		if ( customEndDate != null && customEndDate.after(startDate)) return customEndDate;

		//マイラーニングパスの学習時間を取得
		TimeSpan timeSpan = null;
		String loTimeSpan = this.getLOLearningSpan(loID);
		if (loTimeSpan != null ) timeSpan = TimeSpan.parseTimeSpan(loTimeSpan);

		//取得できなければ、XMLファイルから取得
		if (timeSpan == null && config != null ) timeSpan = config.getTimeSpan();
		DebugLog.write(this.getClass(), "終了日："+(timeSpan==null?"なし":timeSpan.toString()),DebugLog.ROW);
		
		//LOの学習時間が設定されている場合
		//学習開始日 + LOの学習時間を学習終了日とする
		if (timeSpan != null ) {
			
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(startDate);

			calendar.add(Calendar.YEAR, timeSpan.getYears());
			calendar.add(Calendar.MONTH, timeSpan.getMonths());
			calendar.add(Calendar.DATE, timeSpan.getDays());
			calendar.add(Calendar.HOUR, timeSpan.getHours());
			calendar.add(Calendar.MINUTE, timeSpan.getMinutes());
			calendar.add(Calendar.SECOND, timeSpan.getSeconds());
			
			// Date型に変換
			Date loLearningSpan = calendar.getTime();
			if (loLearningSpan.after(startDate)) return loLearningSpan;
		}
		
		//上記以外の場合、学習終了日なし
		return null;
	}
	
	/**
	 * 共通LOログを取得します。
	 * 
	 * @param loID LoID
	 * @param userID ユーザID
	 * @return LoLogLearnStatusResult 共通Loログ情報
	 * @throws Exception
	 */
	private LoLogLearnStatusResult getLoLog(String loID, String userID) throws Exception {
		
		// ロジック取得
		Logic logic = new LoLogLearnMaterialStatusLogic(
									this.getLoLogLearnStatusParam(),
									LoLogConstant.LOG_SELECT_U_M,
									loID,
									new ArrayList(),
									userID,
									new ArrayList(),
									1,
									1);

		DebugLog.write( this.getClass(), "共通ログロジック取得成功：", DebugLog.ROW );

		// RMIクライアント
		RemoteLogicClient remote = new RemoteLogicClient();
		
		// ログ取得
		//LogicResult result = remote.doLogic(logic);
		LoLogLearnStatusResult result = (LoLogLearnStatusResult)remote.doLogic(logic);
		result.beforeFirst();
		result.next();

		return result;
	}
	
	/**
	 * 共通ログ取得用検索パラメータを取得します。
	 * 
	 * @return LoLogLearnStatusParam　共通ログ取得用パラメータ
	 */
	private LoLogLearnStatusParam getLoLogLearnStatusParam() {
		
		LoLogLearnStatusParam param = new LoLogLearnStatusParam();
		
		//学習開始日(date_start)
		param.setDateStartCondition("0");
		param.setDateStart("");
		//最終アクセス日時(date_last)
		param.setDateLastCondition("0");	//select以上/以下
		param.setDateLast("");

		//総アクセス回数(total_access)
		param.setTotalAccessCondition("0");
		param.setTotalAccess("");

		//累積滞在時間(total_learn_time)					
		param.setTotalLearnTimeCondition("0");
		param.setTotalLearnTime("");
		//完了LO数(mat_complete)
		param.setMatCompleteCondition("");
		param.setMatComplete("");
		//合格ＬＯ数(mat_pass)					
		param.setMatPassCondition("");
		param.setMatPass("");	
		//最新得点(mat_newest_score)					
		param.setMatNewestScoreCondition("0");
		param.setMatNewestScore("");
		//最高得点(mat_high_score)					
		param.setMatHighScoreCondition("0");
		param.setMatHighScore("");
		//完了者数(user_complete_condition)							
		param.setUserCompleteCondition("");
		param.setUserComplete("");
		//合格者数(user_pass)							
		param.setUserPassCondition("");
		param.setUserPass("");
		//完了(complete_condition)
		param.setCompleteCondition("");
		//合格(pass_condition)					
		param.setPassCondition("");
		//menuから来た
		param.setMenu("no");
		//所属グループID
		param.setBelonggroupid("");
		//配下直下フラグ
		param.setSubordinateFlg("off");
		
		return param;
	}
	
	/**
	 * ScormDocumentを取得します。
	 * 
	 * @param loID LoID
	 * @param loType Lo種別
	 * @return ScormDocument ScormDocument
	 * @throws Exception
	 */
	private ScormDocument getScormDocument(String loID, String loType ) throws Exception {

		// RealLoIDの取得
		LoClient loClient = new LoClient();
		if(loClient.getRealLOIDFromLOID(loID) == false) throw new Exception();
		
		String realLoID = loClient.getRealLOIDResult();

		// 教材種別を元にLoTopClientをインスタンス化
		// LOサーバ名の取得
		Environment env = new Environment();
		String loServerName = env.getLoServerName();

		// LOクラスをインスタンス化します。
		LoTopClient loTopClient = new LoTopClient( loServerName, loType );

		String materialID = null;
		
		// LOから教材詳細情報を取得
		if( loTopClient.getData(realLoID) ) {
			if( loTopClient.getDataLength() > 0 ) {
				LoComData loComData = loTopClient.getDataInfo(0);
				// 教材IDの取得
				materialID = loComData.getMaterialID();
			}
		}

		// LOから教材詳細情報を取得
		Hashtable params = new Hashtable();
		String document = null;
		params.put( "MATID", materialID );
		if( loTopClient.getMaterialStructFile(params) ) {
			document = loTopClient.getMaterialFile();
		}
		else{
			//教材構造ファイルの取得に失敗しました。;
			Exception e = new Exception();
			e.printStackTrace();
			throw e;
		}

		String strSectionTopID = null;
		String strSectionTopTitle = null;

		// Scorm教材構造定義取得処理（初期Scormノード作成処理）
		ScormDocument scormDocument = new ScormDocument();
		scormDocument.parseXML( document );
		// ルートＩＤの設定
		strSectionTopID = scormDocument.getRootItemID();
		if(strSectionTopID.equals(null)){
			throw new Exception();
		}
		// ルートタイトルの設定
		strSectionTopTitle = scormDocument.getRootTitle();
		if(strSectionTopTitle.equals(null)){
			throw new Exception();
		}

		return scormDocument;
	}
	
	/**
	 * Lo状態クラス
	 * 
	 * @author Katsuhiko Sakurai (UNITEC)
	 * @version 1.0
	 */
	private class LoState {
		
		private String id = null;
		private boolean isComplete = false;
		private boolean isNotStart = true;
		
		/**
		 * コンストラクタです。
		 * 
		 * @param id LoID
		 * @param isComplete 完了しているかどうか　True:完了
		 * @param isNotStart まだ開始していないかどうか　True:未着手
		 */
		public LoState(String id, boolean isComplete, boolean isNotStart ){
			this.id = id;
			this.isComplete = isComplete;
			this.isNotStart = isNotStart;
		}
		
		/**
		 * LoIDを取得します。
		 * 
		 * @return String LoID
		 */
		public String getId() {
			return this.id;
		}
		
		/**
		 * 完了しているかどうかを判別します。
		 * 
		 * @return boolean 完了しているかどうか True:完了
		 */
		public boolean isComplete() {
			return this.isComplete;
		}

		/**
		 * 未着手かどうかを判別します。
		 * 
		 * @return boolean 未着手かどうか True:未着手
		 */
		public boolean isNotStart() {
			return this.isNotStart;
		}
	}
}
