/*
このファイルの中身は、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) ______________________________________.
*/

//
//	Offline教材 オフラインログのitemタグデータ保持クラス
//			変更履歴
//				2004.01.08	新規作成	二條　智文
//
package jp.co.ntt.lms.lo.Offline.OfflineLog;

import org.w3c.dom.*;
import java.util.*;

/**
 * Offline教材 オフラインログのitemタグデータ保持クラス<BR>
 * オフラインログのitemノードを受け取り、自身の内部変数にデータを
 * 格納します。
 */
public class OfflineItem implements OfflineLogConst {

	// 自身のノードオブジェクトを保持します。
	private Element mobjItemElm = null;

	// エラーメッセージ
	private static final String ERR_PRE = "<items>-<item>:";
	private static final String ERR_NOT_ITEM = ERR_PRE + "itemタグではありません。";
	private static final String ERR_NOEXIST_ORG = ERR_PRE + "orgタグが存在しません。";
	private static final String ERR_NOEXIST_ID = ERR_PRE + "id属性が存在しません。";
	private static final String ERR_NOEXIST_TYPE = ERR_PRE + "type属性が存在しません。";
	private static final String ERR_INVALID_TYPE = ERR_PRE + "type属性が不正です。";

	// 属性保持
	// <items>-<item>-[id]属性を保持します
	private String mstrID;
	// <items>-<item>-[type]属性を保持します
	private String mstrType;
	private char mchrType;

	// <org>-<ses>エレメントデータを保持します。
	private Vector mvecSes = new Vector();

	// 学習回で振り分けたItemエレメントデータを保持します。
	private Hashtable mhtbItemSesFromMcnt = new Hashtable();

	/**
	 * コンストラクタです。
	 * @param objNode Itemエレメントオブジェクト
	 * @exception OfflineLogParseException パースエラー
	 */
	OfflineItem( Element objElement )
		throws OfflineLogParseException
	{
		// タグ名のチェック(item以外はエラーとする)
		String strTagName = objElement.getTagName();
		if( strTagName == null || !strTagName.equals( ITEM_ELM ) ) {
			throw new OfflineLogParseException( ERR_NOT_ITEM );
		}

		mobjItemElm = objElement;

		parse();

	}


	/**
	 * <items>-<item>-[id] 属性値を取得します。
	 * @return int <items>-<item>-[id] 属性値
	 */
	public String getID() {
		return mstrID;
	}

	/**
	 * <items>-<item>-[type] 属性値を取得します。
	 * @return int <items>-<item>-[type] 属性値
	 */
	public String getType() {
		return mstrType;
	}

	/**
	 * <items>-<item>-[type] 属性値をchar型に変換した値を取得します。
	 * @return int <items>-<item>-[type] 属性値をchar型に変換した値を
	 */
	public char getTypeChar() {
		return mchrType;
	}

	/**
	 * 保持しているsesエレメントデータの長さを取得します。
	 * @return int
	 */
	public int getSesLength() {
		return mvecSes.size();
	}

	/**
	 * 指定されたインデックスのsesエレメントデータを取得します。
	 * @return OfflineItemSes
	 */
	public OfflineItemSes getSes( int index ) {
		return (OfflineItemSes)mvecSes.get(index);
	}

	/**
	 * 学習回数と表示回数を指定してsesオブジェクトを取得します。
	 * @param intMCNT 学習回数
	 * @param intNCNT 表示回数
	 * @return OfflineItem intMCNT学習回目のintNCNT表示回目のsesオブジェクト
	 *                     存在しない場合はnullを返す。
	 */
	public OfflineItemSes getSesFromMcntNcnt( int intMCNT, int intNCNT ) {

		Hashtable htbNcnt = (Hashtable)mhtbItemSesFromMcnt.get( new Integer( intMCNT ) );

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

		return (OfflineItemSes)htbNcnt.get( new Integer( intNCNT ) );

	}

	/**
	 * 学習回数を指定して、その学習回数の滞在時間の合計を計算して返します。
	 * @param intMCNT 学習回数
	 * @return String 滞在時間の合計時間 HHHH:MM:SS.SS形式で返す。
	 *                指定した学習回数の情報がない場合はnullを返す。
	 */
	public String getTotalSt( int intMCNT ) {

		Hashtable htbNcnt = (Hashtable)mhtbItemSesFromMcnt.get( new Integer( intMCNT ) );

		if( htbNcnt == null ) {
			// 情報がない場合はnullを返す。
			return null;
		}

		long lngTotalTime = 0;

		Enumeration objValue = htbNcnt.elements();

		while(objValue.hasMoreElements() ) {
			OfflineItemSes objSes = (OfflineItemSes)objValue.nextElement();

			if( objSes.getSTLong() >= 0 ) {
				lngTotalTime += objSes.getSTLong();
			}
		}


		return OfflineUtil.formatTime( lngTotalTime );

	}

  /**
   * 学習回数を指定して、その学習回のステータスを返します。
   * @param intMCNT 学習回数
   * @return String Statusを返す。
   *                指定した学習回数の情報がない場合はnullを返す。
   */
  public String getStatus( int intMCNT ) {

	  Hashtable htbNcnt = (Hashtable)mhtbItemSesFromMcnt.get( new Integer( intMCNT ) );

	  if( htbNcnt == null ) {
		  // 情報がない場合はnullを返す。
		  return null;
	  }

	  char  chrStatus = 0;
	  int    i = 0;
	  String strStatus = null;

	  Enumeration objValue = htbNcnt.elements();

	  while(objValue.hasMoreElements() ) {
		  i++;
		  OfflineItemSes objSes = (OfflineItemSes)objValue.nextElement();
	  	  
		  // 表示回数が一回目の場合は無条件にStatusをセット
		  if( i == 1){
			  chrStatus = objSes.getStatusChar();
			  strStatus = objSes.getStatus();	  	   
		  // 表示回毎にStatusの大きい方をStatusにセット
		  }else{
			  if( chrStatus == PASSED_STATUS ) {
				if( objSes.getStatusChar() == PASSED_STATUS ) {
					chrStatus = objSes.getStatusChar();
					strStatus = objSes.getStatus();	  	   
				}
			  }else if( chrStatus == COMPLETED_STATUS) {
			  	if( objSes.getStatusChar() == PASSED_STATUS || objSes.getStatusChar() == COMPLETED_STATUS) {
					chrStatus = objSes.getStatusChar();
					strStatus = objSes.getStatus();	  	   	  	
			  	}
			  }else {
				chrStatus = objSes.getStatusChar();
				strStatus = objSes.getStatus();	  	   
			  }
		  }
	  }
	  return strStatus;
  }
  
  /**
   * 学習回数を指定して、その学習回の最新点を返します。
   * @param intMCNT 学習回数
   * @return String RawScoreを返す。
   *                指定した学習回数の情報がない場合はnullを返す。
   */
  public String getRawScore( int intMCNT ) {

	  Hashtable htbNcnt = (Hashtable)mhtbItemSesFromMcnt.get( new Integer( intMCNT ) );

	  if( htbNcnt == null ) {
		  // 情報がない場合はnullを返す。
		  return null;
	  }

	  int  intNCNT = 0;
	  String strRawScore = null;

	  Enumeration objValue = htbNcnt.elements();

	  while(objValue.hasMoreElements() ) {
		  OfflineItemSes objSes = (OfflineItemSes)objValue.nextElement();
		  // 最新の表示回のScoreをRawScoreにセット
		  if( objSes.getNCNT() > intNCNT ) {
			  strRawScore = objSes.getScore();
			  intNCNT = objSes.getNCNT();
		  }
	  }
	  return strRawScore;
  }

  /**
   * 学習回数を指定して、その学習回の最高点を返します。
   * @param intMCNT 学習回数
   * @return String MaxScoreを返す。
   *                指定した学習回数の情報がない場合はnullを返す。
   */
  public String getMaxScore( int intMCNT ) {

	  Hashtable htbNcnt = (Hashtable)mhtbItemSesFromMcnt.get( new Integer( intMCNT ) );

	  if( htbNcnt == null ) {
		  // 情報がない場合はnullを返す。
		  return null;
	  }

	  long   lngMaxScore = 0;
	  int    i = 0;
	  String strMaxScore = null;

	  Enumeration objValue = htbNcnt.elements();

	  while(objValue.hasMoreElements() ) {
		  i++;
		  OfflineItemSes objSes = (OfflineItemSes)objValue.nextElement();
	  	  
	  	  // 表示回数が一回目の場合は無条件にMaxScoreをセット
	  	  if( i == 1){
	  	  	  lngMaxScore = objSes.getScoreLong();
			  strMaxScore = objSes.getScore();	  	   
		  // 表示回毎にScoreの大きい方をMaxScoreにセット
	  	  }else{
			  if( objSes.getScoreLong() > lngMaxScore ) {
				  lngMaxScore = objSes.getScoreLong();
				  strMaxScore = objSes.getScore();
			  }
	  	  }
	  }
	  return strMaxScore;
  }

  /**
   * 学習回数を指定して、その学習回の最低点を返します。
   * @param intMCNT 学習回数
   * @return String MinScoreを返す。
   *                指定した学習回数の情報がない場合はnullを返す。
   */
  public String getMinScore( int intMCNT ) {

	  Hashtable htbNcnt = (Hashtable)mhtbItemSesFromMcnt.get( new Integer( intMCNT ) );

	  if( htbNcnt == null ) {
		  // 情報がない場合はnullを返す。
		  return null;
	  }

	  long   lngMinScore = 0;
	  int    i = 0;
	  String strMinScore = null;

	  Enumeration objValue = htbNcnt.elements();

	  while(objValue.hasMoreElements() ) {
		  i++;
		  OfflineItemSes objSes = (OfflineItemSes)objValue.nextElement();
	  	  
		  // １件目の場合は無条件にMinScoreをセット
		  if( i == 1){
			  lngMinScore = objSes.getScoreLong();
			  strMinScore = objSes.getScore();	  	   
		  // 表示回毎にScoreの小さい方をMinScoreにセット
		  }else{
			  if( objSes.getScoreLong() < lngMinScore ) {
				  lngMinScore = objSes.getScoreLong();
				  strMinScore = objSes.getScore();
			  }
		  }
	  }
	  return strMinScore;
  }

//----------------------------------- 内部関数 ---------------------------------
	/**
	 * コンストラクタで受け取ったエレメントないのデータを
	 * 取得して、自身の変数に格納します。
	 */
	private void parse()
		throws OfflineLogParseException
	{

		// 属性値の設定
		// <items>-<item>-[id]属性を保持します
		mstrID = mobjItemElm.getAttribute( ITEM_ID_ATTR );
		if( mstrID.equals("") ) {
			// 未設定の場合はnullとする
			mstrID = null;
		}

		// <items>-<item>-[type]属性を保持します
		mstrType = mobjItemElm.getAttribute( ITEM_TYPE_ATTR );
		try {
			mchrType = OfflineUtil.parseElementType( mstrType );
		}
		catch( OfflineLogFormatException fe ) {
			// 属性値が不正の場合はnullとし、char値は0(null文字)とする
			mstrType = null;
			mchrType = 0;
		}

		// 直下の<org>エレメントを取得する
		Node[] objOrgList = OfflineUtil.getNodeList( mobjItemElm, ITEM_ORG_ELM );

		int intOrgLength = objOrgList.length;

		if( intOrgLength == 0 ) {
			// <org>エレメントが存在しない場合は、エラーとする。
			throw new OfflineLogParseException( ERR_NOEXIST_ORG );
		}

		Element objOrgElm = (Element)objOrgList[0];

		// <org>エレメント配下の<ses>エレメントリストを取得する
		NodeList objSesList = objOrgElm.getElementsByTagName( ITEM_SES_ELM );

		Element objSesElm = null;
		for ( int i=0; i<objSesList.getLength(); i++ ){
			objSesElm = (Element)objSesList.item(i);

			OfflineItemSes objSes = new OfflineItemSes( objSesElm, mchrType );
			// itemエレメントリスト用のVectorに追加する。
			mvecSes.add( objSes );

			// 学習回で振り分けてHashtableに格納します。
			int intMCNT = objSes.getMCNT();
			int intNCNT = objSes.getNCNT();

			// 種別がブロック以外でかつMCNT、NCNT属性値が設定されている場合のみ行う。
			if( mchrType != BLOCK_TYPE &&
				intMCNT >= 0 &&
				intNCNT >= 0 )
			{
				Integer objMCNT = new Integer( intMCNT );
				Integer objNCNT = new Integer( intNCNT );

				Hashtable htbItems = (Hashtable)mhtbItemSesFromMcnt.get( objMCNT );

				if( htbItems == null ) {
					// まだVectorが格納されていない場合はインスタンス化して、格納する。
					htbItems = new Hashtable();
					mhtbItemSesFromMcnt.put( objMCNT, htbItems );
				}

				// 表示回数で振り分けてHashtableに格納する。
				htbItems.put( objNCNT, objSes );
			}
		}

	}
//----------------------------------- 内部関数 ---------------------------------

}

