/*
このファイルの中身は、NTT オープンソースライセンス　バージョン 1.0（「本
契約」という）の適用を受けます。
本契約を遵守しない限り、このファイルを使用してはなりません。
本契約のコピーは、次のＵＲＬから入手できます。
【配布サイトのURL】 http://www.oss.ecl.ntt.co.jp/lms/

本契約に基づき頒布されるソフトウェアは、現状のまま、明示又は黙示のあらゆ
る種類の保証なしで、頒布されます。本契約に基づく権利及び制限を律する特定
の文言については、本契約を参照してください。

「オリジナルコード」は、 NTT Cyber Space Laboratories Code です。 
「オリジナルコード」の「初期開発者」は、日本電信電話株式会社です。  
日本電信電話株式会社により創作された部分は、Copyright (C) 2004 
日本電信電話株式会社 です。
全ての権利が留保されます。 
「コントリビュータ」：_____________________________________ 


The contents of this file are subject to the NTT Opensource License
Version 1.0 (the License); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
【配布サイトのURL】 http://www.oss.ecl.ntt.co.jp/lms/

Software distributed under the License is distributed on an AS IS
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.

The Original Code is NTT Cyber Space Laboratories Code .

The Initial Developer of the Original Code is NIPPON TELEGRAPH AND 
TELEPHONE CORPORATION.
Portions created by the NIPPON TELEGRAPH AND TELEPHONE CORPORATION 
are Copyright (C) 2004 NIPPON TELEGRAPH AND TELEPHONE CORPORATION. 
All Rights Reserved.

Contributor(s) ______________________________________.
*/

//
//	AICCログパースクラス
//			変更履歴
//				2004.01.08	新規作成	中山 雅文
//

package jp.co.ntt.lms.lo.WBT.Aicc;

import java.io.*;
import java.util.Vector;
import java.util.StringTokenizer;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.apache.xerces.parsers.DOMParser;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import org.xml.sax.InputSource;

import jp.co.ntt.lms.Common.RDF.*;

/**
 * AICCログパースクラス
 * <PRE>
 * 処理内容：入力されたAiccLogのXMLデータをパースし、DBのレコード
 * クラスに変換する。
 * </PRE>
 */

public class AiccLogConverter implements AiccConst
{

	//////////////////////////////////////////////////////////
	//	クラス変数
	//////////////////////////////////////////////////////////

	/** LOID */
	private String mstrLoID = null;

	/** USERID */
	private String mstrUserID = null;

	/** SessionID */
	private String mstrSessionID = null;

	/** XMLドキュメント */
	private	Document mDoc = null;

	/** XMLソース */
	private	String mSource = null;

	/** ルートエレメント */
	private Element mRootElement = null;

	/** 教材構造マテリアルログID */
	private	String mstrMaterialLogID = null;

	/** AiccCoreRecord */
	private AiccCoreRecord[] mobjAiccCoreRecords = null ;

	/** SectionLogRecord */
	private SectionLogRecord[] mobjSectionLogRecords = null ;

	/** AiccInteractionRecord */
	private AiccInteractionRecord[] mobjAiccInteractionRecords = null;

	/** AiccCommentRecord */
	private AiccCommentRecord[] mobjAiccCommentRecords = null;

	/** AiccObjectivesRecord */
	private AiccObjectivesRecord[] mobjAiccObjectivesRecords = null;

	/** Aiccの教材ID */
	private String mstrCourseID = null;

	/** AiccのBLOCKID */
	private String mstrBlockID = null;

	/** AiccのレッスンID */
	private String mstrLessonID = null;

	/** AiccUID */
	private String mstrUid = null;

	/** 教材構造を保持します */
	private RDFNode mobjRDFNode = null;

	/** UIDリストを保持します */
	private Vector mvecUidList = new Vector();

	//エラーメッセージ
	private static final String WRONG_ARGUMENT = "引数が不正です。";
	private static final String FAIL_PARSE = "パース処理に失敗しました。";
	private static final String NO_EXIST_MATERIALTAG = "Materialタグが存在しません。";
	private static final String WRONG_MATERIAL_ID = "MaterialタグのID属性が不正です。";

	/**
	*	コンストラクタ<br>
	*	XMLデータをパースしてインスタンスを生成します。
	*	@param strInput XMLデータ
	*/
	public AiccLogConverter(String strInput){
		mSource = strInput;
	}


	/**
	 *	XMLデータをパースします。<BR>
	 *	レコードを作成しますので、事前にLoID,SessionID,UesrIDを設定してください。
	 *	@exception SAXException パースに失敗した場合
	 *	@exception IOException データ読み込みに失敗した場合
	 *	@exception AiccParseException 内部異常の場合
	 */
	public void parse() throws SAXException,AiccParseException,IOException
	{
		if ( mSource == null || mstrLoID == null || mstrUserID == null || mstrSessionID == null ){
			throw new AiccParseException(WRONG_ARGUMENT);
		}


		//パーサのインスタンスを生成する
		DOMParser parser = new DOMParser();

		//XMLデータを読み込む
		StringReader mSr = new StringReader(mSource);

		//ストリームを生成する
		InputSource is = new InputSource(mSr);

		//パースする
		parser.parse(is);

		//ドキュメントを取得する
		mDoc = parser.getDocument();

		//ドキュメントが取得できた時、
		try {
			// 教材構造を読み込む
			RDFDocument objDoc = new RDFDocument();
			mobjRDFNode = objDoc.load( new StringBuffer( mSource ) );
			// 教材IDの設定
			mstrCourseID = mobjRDFNode.getID();

			mstrMaterialLogID = mobjRDFNode.getChildNodes().getNode(0).getID();

		}
		catch( RDFParseException rp ) {
			throw new AiccParseException(rp.getMessage());
		}

		if(mDoc != null) {
			Element elementRoot = mDoc.getDocumentElement();
			mRootElement = elementRoot;
			mRootElement.normalize();

			Vector vecCores = new Vector();
			Vector vecInteractions = new Vector();
			Vector vecComments = new Vector();
			Vector vecObjectives = new Vector();
			Vector vecMaterials = new Vector();
			NodeList AiccLogList = getElementsByTagName(mRootElement, AICCLOG_ELM );
			Node AiccLog;
			NodeList MaterialLogList = getElementsByTagName(mRootElement, MATERIALLOG_ELM );
			Node MaterialLog;

			for ( int i=0; i<AiccLogList.getLength(); i++ ){

				AiccLog = AiccLogList.item(i);

				// Aiccの属性を取得する
				String strAiccID = ((Element)AiccLog).getAttribute( AICC_ID );

				// 現在読み込み中のAiccタグのBlockとAuを設定します
				setBaseInfo( strAiccID );

				// AiccLogエレメント配下の全Core情報を取得する */
				makeAiccCoreRecords((Element)AiccLog,vecCores);
				// AiccLogエレメント配下の全Interaction情報を取得する */
				makeAiccInteractionRecords((Element)AiccLog,vecInteractions);
				// AiccLogエレメント配下の全Comment情報を取得する */
				makeAiccCommentRecords((Element)AiccLog,vecComments);
				// AiccLogエレメント配下の全Objectives情報を取得する */
				makeAiccObjectivesRecords((Element)AiccLog,vecObjectives);
			}
			if ( vecCores.size() > 0 ){
				mobjAiccCoreRecords = new AiccCoreRecord[vecCores.size()];
				vecCores.copyInto( mobjAiccCoreRecords );
			}
			if ( vecInteractions.size() > 0 ){
				mobjAiccInteractionRecords = new AiccInteractionRecord[vecInteractions.size()];
				vecInteractions.copyInto( mobjAiccInteractionRecords );
			}
			if ( vecComments.size() > 0 ){
				mobjAiccCommentRecords = new AiccCommentRecord[vecComments.size()];
				vecComments.copyInto( mobjAiccCommentRecords );
			}
			if ( vecObjectives.size() > 0 ){
				mobjAiccObjectivesRecords = new AiccObjectivesRecord[vecObjectives.size()];
				vecObjectives.copyInto( mobjAiccObjectivesRecords );
			}

			for ( int i=0; i<MaterialLogList.getLength(); i++ ){

				MaterialLog = MaterialLogList.item(i);

				// Materialの属性を取得する
				String strMaterialLogID = getMaterialLogID(((Element)MaterialLog).getAttribute( MATERIAL_ID ));

				// MaterialLogエレメント配下の全情報を取得する */
				vecMaterials.add( makeSectionLogRecord( MaterialLog, strMaterialLogID ) );
			}
			if ( vecMaterials.size() > 0 ){
				mobjSectionLogRecords = new SectionLogRecord[vecMaterials.size()];
				vecMaterials.copyInto( mobjSectionLogRecords );
			}
		}
	}

	/**
	 * Aiccログ内の最初に見つかった<AiccLog>タグ内のID属性から
	 * UserIDと教材IDを取得します。<BR>
	 * インスタンス化せずに使用できるようにメソッドは static
	 * で宣言されています。
	 * ID属性は":"区切りで以下のように定義されます。<BR>
	 * Count属性も取得して追加します。<BR>
	 * <PRE>
	 *       教材ID:ユーザID:BLOCKまたはAUID
	 * <PRE>
	 * @param strInput XMLAiccログデータ
	 * @return String[] UserIDと教材IDと学習回数を配列で返します。
	 *                  [0]: UserID
	 *                  [1]: 教材ID
	 *                  [2]: 学習回数
	 * @exception SAXException パースに失敗した場合
	 * @exception IOException データ読み込みに失敗した場合
	 * @exception AiccParseException 内部異常の場合
	 */
	public static String[] getIDInfo( String strInput )
		throws SAXException,AiccParseException,IOException
	{
		if ( strInput == null ) {
			throw new AiccParseException();
		}

		//パーサのインスタンスを生成する
		DOMParser parser = new DOMParser();

		//XMLデータを読み込む
		StringReader mSr = new StringReader(strInput);

		//ストリームを生成する
		InputSource is = new InputSource(mSr);

		//パースする
		parser.parse(is);

		//ドキュメントを取得する
		Document pDoc = parser.getDocument();


		if(pDoc != null) {
			Element elementRoot = pDoc.getDocumentElement();
			elementRoot.normalize();
			NodeList AiccLogList = getElementsByTagName(elementRoot,MATERIALLOG_ELM );
			Node AiccLog;
			if( AiccLogList.getLength() > 0 ) {
				// Materialタグの先頭を取得する
				AiccLog = AiccLogList.item(0);
				// MaterialタグのID属性を取得する
				String strAiccID = ((Element)AiccLog).getAttribute( MATERIAL_ID );
				// ユーザIDを取得
				String[] strTmp = tokenID( strAiccID );
				// 学習回数を取得
				String strCountID = ((Element)AiccLog).getAttribute( MATERIAL_COUNT );
				String[] strRes = new String[3];
				strRes[0] = strTmp[0];
				strRes[1] = strTmp[1];
				strRes[2] = strCountID;
				return strRes;
			}
			else {
				// Aiccタグが存在しない場合
				throw new AiccParseException(NO_EXIST_MATERIALTAG);
			}
		}
		else {
			// ドキュメントが取得できない場合
			throw new AiccParseException(FAIL_PARSE);
		}
	}

	/**
	 * AiccログのID属性からユーザIDと教材IDを取り出して返します。
	 * ID属性は":"区切りで以下のように定義されます。<BR>
	 * <PRE>
	 *       教材ID:ユーザID:BLOCKまたはAUID
	 * <PRE>
	 * @param strAiccID ID
	 * @return String[] UserIDと教材IDを配列で返します。
	 *                  [0]: UserID
	 *                  [1]: 教材ID
	 * @exception AiccParseException 内部異常の場合
	 */
	private static String[] tokenID( String strAiccID )
		throws AiccParseException
	{
		// ":" でトークン分割します
		StringTokenizer objToken = new StringTokenizer( strAiccID, ":" );

		String[] strRes = new String[2];
		int i = 0;
		while( objToken.hasMoreElements() ) {
			switch(i) {
				case 0:
					// 教材IDの取得
					strRes[1] = objToken.nextToken();
					break;
				case 1:
					// ユーザIDの取得
					strRes[0] = objToken.nextToken();
					break;
				case 2:
					objToken.nextToken();
					break;
				default:
					objToken.nextToken();
					break;
			}
			i++;
		}
		// トークンの数が不正の場合
		if( i < 2 ) {
			throw new AiccParseException(WRONG_MATERIAL_ID);
		}

		return strRes;
	}

	/**
	 * 教材IDを返却します
	 * @return String 教材ID
	 */
	public String getCourseID() {
		return mstrCourseID;
	}

	/**
	*	AiccCoreRecord配列を返却します。<br>
	*	レコードが存在しない場合は、nullを返却します。
	*	@return AiccCoreRecord[] AiccCoreRecord配列
	*/
	public AiccCoreRecord[] getAiccCoreRecords()
	{
		return mobjAiccCoreRecords;
	}

	/**
	*	SectionLogRecord配列を返却します。<br>
	*	レコードが存在しない場合は、nullを返却します。
	*	@return SectionLogRecord[] SectionLogRecord配列
	*/
	public SectionLogRecord[] getSectionLogRecords()
	{
		return mobjSectionLogRecords;
	}

	/**
	 *	AiccCoreRecordを返却します。<br>
	*	レコードが存在しない場合は、nullを返却します。
	*	@return AiccCoreRecord AiccCoreRecord
	*/
	public AiccCoreRecord getAiccCoreRecord()
	{
		if( mobjAiccCoreRecords == null ) {
			return null;
		}
		if( mobjAiccCoreRecords.length > 0 ) {
			return mobjAiccCoreRecords[0];
		}
		return null;
	}

	/**
	*	AiccInteractionRecord配列を返却します。<br>
	*	レコードが存在しない場合は、nullを返却します。
	*	@return AiccCoreRecord[] AiccInteractionRecord配列
	*/
	public AiccInteractionRecord[] getAiccInteractionRecords()
	{
		return mobjAiccInteractionRecords;
	}

	/**
	*	AiccCommentRecord配列を返却します。<br>
	*	レコードが存在しない場合は、nullを返却します。
	*	@return AiccCommentRecord[] AiccCommentRecord配列
	*/
	public AiccCommentRecord[] getAiccCommentRecords()
	{
		return mobjAiccCommentRecords;
	}

	/**
	*	AiccObjectivesRecord配列を返却します。<br>
	*	レコードが存在しない場合は、nullを返却します。
	*	@return AiccObjectivesRecord[] AiccObjectivesRecord配列
	*/
	public AiccObjectivesRecord[] getAiccObjectivesRecords()
	{
		return mobjAiccObjectivesRecords;
	}

	/**
	 * ユーザIDを設定します。
	 * @param String
	 */
	public void setUserID(String strUserID ){
		mstrUserID = strUserID;
	}
	/**
	 * LoIDを設定します。
	 * @param String
	 */
	public void setLoID(String strLoID ){
		mstrLoID = strLoID;
	}
	/**
	 * セッションIDを設定します。
	 * @param String
	 */
	public void setSessionID(String strSessionID ){
		mstrSessionID = strSessionID;
	}


	/**
	 *	一つのAiccLog要素配下の全Coreレコードを検索します。<br>
 	 *	@param Element AiccLog１要素
	 *	@param Vector  Core情報を格納するVector
	 *
	 */
	private void makeAiccCoreRecords (Element Parent, Vector vecWork)
												throws SAXException, AiccParseException{
		if ( Parent == null || vecWork == null){
			throw new AiccParseException();
		}

		NodeList CoreList = getElementsByTagName( Parent,CORE_ELM );
		Node CoreNode;

		if ( CoreList.getLength() == 0 ){
			return ;
		}

		for ( int i=0; i < CoreList.getLength(); i++ ){
			CoreNode = CoreList.item(i);
			vecWork.add( makeAiccCoreRecord( CoreNode ) );
		}

		return;
	}

	/**
	 *	一つのAiccLog要素配下の全Interactionレコードを検索します。<br>
	 *	@param Element AiccLog１要素
	 *	@param Vector  Interaction情報を格納するVector
	 *
	 */
	private void makeAiccInteractionRecords (Element Parent,Vector vecWork)
												throws SAXException, AiccParseException{
		if ( Parent == null || vecWork == null){
			throw new AiccParseException();
		}
		NodeList InteractList = getElementsByTagName( Parent,INTERACTION_ELM );
		Node InteractNode;

		if ( InteractList.getLength() == 0 ){
			return ;
		}

		// 解答回数定義　デフォルト１回
		int intResponseTimes = 1;
		for ( int i=0; i < InteractList.getLength(); i++ ){
			InteractNode = InteractList.item(i);
			AiccInteractionRecord objInteTemp = makeAiccInteractionRecord( InteractNode );
			// 解答回数をセットする
			objInteTemp.setResponseTimes( new Integer(intResponseTimes++).toString() );
			vecWork.add( objInteTemp );
		}

		AiccInteractionRecord[] result = new AiccInteractionRecord[vecWork.size()];
		vecWork.copyInto( result );

		return ;
	}

	/**
	 *	一つのAiccLog要素配下の全Commentレコードを検索します。<br>
 	 *	@param Element AiccLog１要素
	 *	@param Vector  Comment情報を格納するVector
	 *
	 */
	private void makeAiccCommentRecords (Element Parent,Vector vecWork)
									throws SAXException, AiccParseException{
		if ( Parent == null || vecWork == null){
			throw new AiccParseException();
		}

		NodeList CommentList = getElementsByTagName(Parent, COMMENT_ELM );
		if ( CommentList.getLength() == 0 ){
			return ;
		}

		Node CommentNode;
		for ( int i=0; i < CommentList.getLength(); i++ ){
			CommentNode = CommentList.item(i);
			vecWork.add( makeAiccCommentRecord( CommentNode ) );
		}

		return ;
	}

	/**
	 *	一つのAiccLog要素配下の全Objectivesレコードを検索します。<br>
 	 *	@param Element AiccLog１要素
	 *	@param Vector  Objectives情報を格納するVector
	 *
	 */
	private void makeAiccObjectivesRecords (Element Parent,Vector vecWork)
										throws SAXException, AiccParseException{
		if ( Parent == null || vecWork == null){
			throw new AiccParseException();
		}
		NodeList ObjectivesList = getElementsByTagName(Parent, OBJECTIVES_ELM );
		if ( ObjectivesList.getLength() == 0 ){
			return ;
		}

		Node ObjectivesNode;
		for ( int i=0; i < ObjectivesList.getLength(); i++ ){
			ObjectivesNode = ObjectivesList.item(i);
			vecWork.add( makeAiccObjectivesRecord( ObjectivesNode ) );
		}

		return ;
	}

	/**
	 *	Coreレコードを生成します。<br>
	 *	同じタグが複数存在した場合、先頭のタグが有効になります。
	 *	タグが存在しない場合、対象の情報はnullのままです。
	 *	@param childElementName 検索するエレメント名<br>
	 *	@return 取得したノード。ノードを取得できなかった場合はnullが返る。
	 *
	 */
	private AiccCoreRecord makeAiccCoreRecord (Node CoreNode) throws SAXException, AiccParseException {
		if ( CoreNode == null ){
			throw new AiccParseException();
		}

		AiccCoreRecord result = new AiccCoreRecord();

		result.setUserID(mstrUserID);
		result.setLoID(mstrLoID);
		result.setSessionID(mstrSessionID);
		result.setBlockID(mstrBlockID);
		result.setCourseID(mstrCourseID);
		result.setUid( mstrUid );

		NodeList children = CoreNode.getChildNodes();
		if ( children.getLength() == 0 ){
			return result;
		}

		String LessonStatus = getNodeValueByName( children, LESSON_STATUS );
		if ( LessonStatus != null ){
			result.setLessonStatus( LessonStatus );
		}

		String Score = getNodeValueByName( children, LESSON_SCORE );
		if ( Score != null ){
			result.setScore( Score );
		}

		String StayTime = getNodeValueByName( children, STAY_TIME );
		if ( StayTime != null ){
			result.setStayTime( StayTime );
		}

		String LessonLocation = getNodeValueByName( children, LESSON_LOCATION );
		if ( LessonLocation != null ){
			result.setLessonLocation( LessonLocation );
		}

		String Exist = getNodeValueByName( children, EXIST );
		if ( Exist != null ){
			result.setExist( Exist );
		}

		return result;
	}

	/**
	 *	SectionLogレコードを生成します。<br>
	 *	同じタグが複数存在した場合、先頭のタグが有効になります。
	 *	タグが存在しない場合、対象の情報はnullのままです。
	 *	@param childElementName 検索するエレメント名<br>
	 *	@return 取得したノード。ノードを取得できなかった場合はnullが返る。
	 *
	 */
	private SectionLogRecord makeSectionLogRecord (Node MateriNode, String strMaterialLogID) throws SAXException, AiccParseException {

		if ( MateriNode == null ){
			throw new AiccParseException();
		}

		SectionLogRecord result = new SectionLogRecord();

		result.setUserID(mstrUserID);
		result.setLoID(mstrLoID);
		result.setSessionID(mstrSessionID);
		result.setBlockID(mstrBlockID);
		result.setCourseID(mstrCourseID);
		result.setUid( strMaterialLogID );
		result.setMaterialLogID( strMaterialLogID );

		NodeList children = MateriNode.getChildNodes();
		if ( children.getLength() == 0 ){
			return result;
		}

		String LessonStatus = getNodeValueByName( children, LESSON_STATUS );
		if ( LessonStatus != null ){
			result.setLessonStatus( LessonStatus );
		}

		String StayTime = getNodeValueByName( children, STAY_TIME );
		if ( StayTime != null ){
			result.setTime( StayTime );
		}

		return result;
	}

	/**
	 *	Interactionレコードを生成します。<br>
	 *	同じタグが複数存在した場合、先頭のタグが有効になります。
	 *	タグが存在しない場合、対象の情報はnullのままです。
	 *	@param childElementName 検索するエレメント名<br>
	 *	@return 取得したノード。ノードを取得できなかった場合はnullが返る。
	 *
	 */
	private AiccInteractionRecord makeAiccInteractionRecord (Node InteractNode) throws SAXException, AiccParseException{
		if ( InteractNode == null ){
			throw new AiccParseException();
		}

		AiccInteractionRecord result = new AiccInteractionRecord();

		result.setUserID(mstrUserID);
		result.setLoID(mstrLoID);
		result.setSessionID(mstrSessionID);
		result.setBlockID(mstrBlockID);
		result.setUid( mstrUid );

		NodeList children = InteractNode.getChildNodes();
		if ( children.getLength() == 0 ){
			return result;
		}

		String CourseID = getNodeValueByName( children, COURSE_ID );
		if ( CourseID != null ){
			result.setCourseID( CourseID );
		}

		String StudentID = getNodeValueByName( children, STUDENT_ID );
		if ( StudentID != null ){
			result.setStudentID( StudentID );
		}

		String LessonID = getNodeValueByName( children, LESSON_ID );
		if ( LessonID != null ){
			result.setLessonID( LessonID );
		}

		String Date = getNodeValueByName( children, DATE );
		if ( Date != null ){
			result.setDate( Date );
		}

		String Time = getNodeValueByName( children, TIME );
		if ( Time != null ){
			result.setTime( Time );
		}

		String InteractionID = getNodeValueByName( children, INTERACTION_ID );
		if ( InteractionID != null ){
			result.setInteractionID( InteractionID );
		}

		String ObjectiveID = getNodeValueByName( children, OBJECTIVE_ID );
		if ( ObjectiveID != null ){
			result.setObjectiveID( ObjectiveID );
		}

		String TypeInteraction = getNodeValueByName( children, TYPE_INTERACTION );
		if ( TypeInteraction != null ){
			result.setTypeInteraction( TypeInteraction );
		}

		String CorrectResponse = getNodeValueByName( children, CORRECT_RESPONSE );
		if ( CorrectResponse != null ){
			result.setCorrectResponse( CorrectResponse );
		}

		String ResponseValue = getNodeValueByName( children, RESPONSE_VALUE );
		if ( ResponseValue != null ){
			result.setResponseValue( ResponseValue );
		}

		String StudentResponse = getNodeValueByName( children, STUDENT_RESPONSE );
		if ( StudentResponse != null ){
			result.setStudentResponse( StudentResponse );
		}

		String Result = getNodeValueByName( children, RESULT );
		if ( Result != null ){
			result.setResult( Result );
		}

		String Weighting = getNodeValueByName( children, WEIGHTING );
		if ( Weighting != null ){
			result.setWeighting( Weighting );
		}

		String Latency = getNodeValueByName( children, LATENCY );
		if ( Latency != null ){
			result.setLatency( Latency );
		}

		return result;
	}

	/**
	 *	Commentレコードを生成します。<br>
	 *	同じタグが複数存在した場合、先頭のタグが有効になります。
	 *	タグが存在しない場合、対象の情報はnullのままです。
	 *	@param childElementName 検索するエレメント名<br>
	 *	@return 取得したノード。ノードを取得できなかった場合はnullが返る。
	 *
	 */
	private AiccCommentRecord makeAiccCommentRecord (Node CommentNode) throws SAXException, AiccParseException{
		if ( CommentNode == null ){
			throw new AiccParseException();
		}

		AiccCommentRecord result = new AiccCommentRecord();

		result.setUserID(mstrUserID);
		result.setLoID(mstrLoID);
		result.setSessionID(mstrSessionID);
		result.setBlockID(mstrBlockID);
		result.setUid( mstrUid );

		NodeList children = CommentNode.getChildNodes();
		if ( children.getLength() == 0 ){
			return result;
		}

		String CourseID = getNodeValueByName( children, COURSE_ID );
		if ( CourseID != null ){
			result.setCourseID( CourseID );
		}

		String StudentID = getNodeValueByName( children, STUDENT_ID );
		if ( StudentID != null ){
			result.setStudentID( StudentID );
		}

		String LessonID = getNodeValueByName( children, LESSON_ID );
		if ( LessonID != null ){
			result.setLessonID( LessonID );
		}

		String Date = getNodeValueByName( children, DATE );
		if ( Date != null ){
			result.setDate( Date );
		}

		String Time = getNodeValueByName( children, TIME );
		if ( Time != null ){
			result.setTime( Time );
		}

		String Location = getNodeValueByName( children, LOCATION );
		if ( Location != null ){
			result.setLocation( Location );
		}

		String Comment = getNodeValueByName( children, COMMENT );
		if ( Comment != null ){
			result.setComment( Comment );
		}


		return result;
	}

	/**
	 *	Objectivesレコードを生成します。<br>
	 *	同じタグが複数存在した場合、先頭のタグが有効になります。
	 *	タグが存在しない場合、対象の情報はnullのままです。
	 *	@param childElementName 検索するエレメント名<br>
	 *	@return 取得したノード。ノードを取得できなかった場合はnullが返る。
	 *
	 */
	private AiccObjectivesRecord makeAiccObjectivesRecord (Node ObjectivesNode) throws SAXException, AiccParseException{
		if ( ObjectivesNode == null ){
			throw new AiccParseException();
		}

		AiccObjectivesRecord result = new AiccObjectivesRecord();

		result.setUserID(mstrUserID);
		result.setLoID(mstrLoID);
		result.setSessionID(mstrSessionID);
		result.setBlockID(mstrBlockID);
		result.setUid( mstrUid );

		NodeList children = ObjectivesNode.getChildNodes();
		if ( children.getLength() == 0 ){
			return result;
		}

		String CourseID = getNodeValueByName( children, COURSE_ID );
		if ( CourseID != null ){
			result.setCourseID( CourseID );
		}

		String StudentID = getNodeValueByName( children, STUDENT_ID );
		if ( StudentID != null ){
			result.setStudentID( StudentID );
		}

		String LessonID = getNodeValueByName( children, LESSON_ID );
		if ( LessonID != null ){
			result.setLessonID( LessonID );
		}

		String Date = getNodeValueByName( children, DATE );
		if ( Date != null ){
			result.setDate( Date );
		}

		String Time = getNodeValueByName( children, TIME );
		if ( Time != null ){
			result.setTime( Time );
		}

		String ObjectiveID = getNodeValueByName( children, OBJECTIVE_ID );
		if ( ObjectiveID != null ){
			result.setObjectiveID( ObjectiveID );
		}

		String Score = getNodeValueByName( children, SCORE );
		if ( Score != null ){
			result.setScore( Score );
		}

		String Status = getNodeValueByName( children, STATUS );
		if ( Status != null ){
			result.setStatus( Status );
		}


		String MasteryTime = getNodeValueByName( children, MASTERY_TIME );
		if ( MasteryTime != null ){
			result.setMasteryTime( MasteryTime );
		}


		return result;
	}
	/**
	 * AiccLogのID属性値から教材IDとBlockIDとAuIDを設定します。<BR>
	 * AiccLogのID属性値は以下のような形式です。
	 * <PRE>
	 *    教材ID:ユーザID:LessonID
	 * </PRE>
	 * BlockIDに関してはAuの直近の親BlockIDとします。
	 * @param strAiccID AiccID
	 */
	private void setBaseInfo( String strAiccID ) {
		// ":" でトークン分割します
		StringTokenizer objToken = new StringTokenizer( strAiccID, ":" );

		//
		int i = 0;
		while( objToken.hasMoreElements() ) {
			switch(i) {
				case 0:
					// 教材IDの取得( 教材IDは教材構造から取得する。
					objToken.nextToken();
					break;
				case 1:
					// ユーザIDの取得
					objToken.nextToken();
					break;
				case 2:
					// LessonIDの取得
					mstrLessonID = objToken.nextToken();
					break;
				default:
					objToken.nextToken();
					break;
			}
			i++;
		}

		// レッスンIDを元に直近のBlockIDを取得します
		RDFNode objNode = mobjRDFNode.searchNode( mstrLessonID );
		if( objNode != null ) {
			RDFNode objParentNode = objNode.getParentNode();

			// UIDの取得
			mstrUid = objNode.getID();
			// UIDリストに追加する
			mvecUidList.add( mstrUid );

			// ブロックIDを設定します
			mstrBlockID = objParentNode.getID();
		}
	}
	/**
	 * MaterialLogのID属性値からMaterialLogIDを取得します。<BR>
	 * @param strMaterialLogAttribute ID属性
	 * @return String MaterialLogID
	 */
	private String getMaterialLogID( String strMaterialLogAttribute ) {

		// ":" でトークン分割します
		StringTokenizer objToken = new StringTokenizer( strMaterialLogAttribute, ":" );

		int i = 0;
		while( objToken.hasMoreElements() ) {
			switch(i) {
				case 0:
				case 1:
					i++;
					objToken.nextToken();
					continue;
				case 2:
					// MaterialLogIDの取得
					return objToken.nextToken();
				default:
					return "";
			}
		}
		return "";
	}
	/**
	 * MaterialLogのID属性値からMaterialLogIDを取得します。<BR>
	 * @param strMaterialLogAttribute ID属性
	 * @return String MaterialLogID
	 */
	public SectionLogRecord getMaterialMaterialLog() {

		if (mobjSectionLogRecords == null || mstrMaterialLogID == null) {
			return null;
		}

		SectionLogRecord objResult = null;

		for(int i = 0;i < mobjSectionLogRecords.length; i++) {

			if( mobjSectionLogRecords[i].getMaterialLogID().equals( mstrMaterialLogID ) ) {
				objResult = mobjSectionLogRecords[i];
				break;
			}
		}
		return objResult;
	}

	/**
	 * UIDリストを取得します
	 * @return String[] UIDリスト
	 */
	public String[] getUidList() {
		Vector vecList = getUidList( mobjRDFNode );
		String[] strRes = new String[vecList.size()];
		vecList.copyInto(strRes);
		return strRes;
	}

	/**
	 * UIDリストを取得します。
	 * @return Vector UIDリスト
	 */
	public Vector getUidList(RDFNode objNode) {
		Vector vecList = new Vector();

		RDFNodeList objNodeList = objNode.getChildNodes();
		int intLength = objNodeList.getLength();
		for( int i = 0; i < intLength; i++ ) {
			RDFNode objChildNode = objNodeList.getNode(i);
			if( objChildNode.getNodeType() == RDFNode.AU_NODE ) {
				// ノードタイプがAUの場合
				vecList.add( objChildNode.getID() );
			}
			else {
				// ノードタイプがAU以外の場合は再帰呼び出し
				Vector vecChildList = getUidList(objChildNode);
				vecList.addAll( vecChildList );
			}
		}

		return vecList;
	}

	/**
	 *	指定された要素名の値を返却します。<br>
	 *	@param InputNode 検索するノードオブジェクト<br>
 	 *	@param NodeName 検索するエレメント名<br>
	 *	@return 値。ノードを取得できなかった場合はnullが返る。
	 *
	 */
	private String getNodeValueByName( NodeList InputNodeList, String NodeName ){
		String result = null;

		for ( int i=0; i < InputNodeList.getLength(); i++ ){
			if ( InputNodeList.item(i).getNodeName().equalsIgnoreCase( NodeName ) == true ){
				Node FirstChild = InputNodeList.item(i).getFirstChild();
				if ( FirstChild != null ){
					result = FirstChild.getNodeValue();
					break;
				}
			}
		}

		return result;
	}

	/**
	 *	Aiccノードリストを返却します。<br>
	 *	@param objElement 検索するエレメントオブジェクト<br>
 	 *	@param strTagName 検索するタグ名<br>
	 *	@return 値。Aiccノードリストを返す。
	 *
	 */

	private static NodeList getElementsByTagName( Element objElement, String strTagName ) {
		AiccNodeList objList = new AiccNodeList();

		// nullチェック
		if( objElement == null ) {
			return objList;
		}

		// 子リスト分再帰処理を行う。
		NodeList objChildList = objElement.getChildNodes();
		Node objChildNode = null;
		for( int i = 0; i < objChildList.getLength(); i++ ) {
			objChildNode = objChildList.item(i);
			getElementsByTagNameReflex( objList, objChildNode, strTagName );
		}

		return objList;
	}
	/**
	 *	再帰の基点メソッド。<br>
	 *	@param objList 検索するAiccノードオブジェクト<br>
 	 *	@param objNode 検索するエレメントオブジェクト<br>
	 *	@param strTagName 検索するタグ名
	 *
	 */
	private static void getElementsByTagNameReflex( AiccNodeList objList, Node objNode, String strTagName ) {

		// nullチェック
		if( objList == null || objNode == null ) {
			return;
		}

		// テキストノードの場合は何もせずにreturn
		if(objNode.getNodeType() == Node.TEXT_NODE) {
			return;
		}


		// 引数のElementから名前を取得し大文字小文字を無視して等価チェックを行う
		String NodeName = objNode.getNodeName();

		if( NodeName.equalsIgnoreCase(strTagName) ) {
			// マッチしたらリストに追加
			objList.add( objNode );
		}

		// 子リスト分再帰処理を行う。
		NodeList objChildList = objNode.getChildNodes();
		Node objChildNode = null;
		for( int i = 0; i < objChildList.getLength(); i++ ) {
			objChildNode = objChildList.item(i);
			getElementsByTagNameReflex( objList, objChildNode, strTagName );
		}
	}
	/**
	 * AiccNodeListインナークラス
	 * <PRE>
	 * 処理内容：NodeListインタフェースの実装をインナークラスで行う。
	 * </PRE>
	 */

	static class AiccNodeList implements NodeList {

		// ノード保持
		private Vector vecNodeList = new Vector();

		/**
		 * getLengthメソッド実装
		 * @return ノードリストサイズ
		 */
		public int getLength() {
			// ここに実装を書く
			return vecNodeList.size();
		}

		/**
		 * itemメソッドの実装
		 * @return indexの値
		 */
		public Node item(int index) {
			return (Node)vecNodeList.get(index);
		}

		/**
		 * Node追加メソッド
		 * ノード追加
		 */
		public void add(Node node) {
			vecNodeList.add(node);
		}
	}
}

