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

//
//	ScormDocument
//	変更履歴
//		2004.02.01	新規作成
//

package jp.co.ntt.lms.xms.logsumup.scorm;

import java.util.List;
import java.util.ArrayList;
import java.io.StringReader;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.xpath.XPathAPI;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

/**
 * ScormNodeクラスの基底クラスです。
 * 
 */
public class ScormDocument {
	/**
	 * 教材構造DOM Document。
	 */
	private Document manifestDocument;

	/**
	 * デフォルト&lt;organization&gt;ノード。
	 */
	private Node organizationNode;

	/**
	 * &lt;resources&gt;ノード。
	 */
	private Node resourcesNode;

	/**
	 * コンストラクタ<BR>
	 * 　XMLファイルを解析する上での初期化処理を行います。
	 */
	public ScormDocument(){
	}

	/**
	 * パース処理
	 * 　ドキュメントのパースを実行してDocumentオブジェクトを取得
	 * @param strXML : パース対象のドキュメント情報
	 */
	public void parseXML(String strXML){
		try{
			// ドキュメントビルダーファクトリを生成
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			// ドキュメントビルダーを生成
			factory.setIgnoringComments(true);
			DocumentBuilder builder = factory.newDocumentBuilder();
			// XMLデータの読み込み
			StringReader reader = new StringReader(strXML);
			InputSource source = new InputSource(reader);
			// パースを実行してDocumentオブジェクトを取得
			manifestDocument = builder.parse(source);

			// デフォルトorganizationノード
			organizationNode = XPathAPI.selectSingleNode(
				manifestDocument,
				"/manifest/organizations/organization"
				+ "[@identifier=/manifest/organizations/@default]");
			// resourcesノード
			resourcesNode = XPathAPI.selectSingleNode(
				manifestDocument,"/manifest/resources");

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * クライアントへ返却する為の現在のノード直下リストを作成します。
	 * @param targetID リスト化するitemノードの親itemのidentifier属性
	 * @return 指定したIDに一致するitemを親とするitemの情報に関するXML文字列。
	 */
	public String getChildListXml(String targetID){

		StringBuffer childListBuffer = new StringBuffer();

		try {
			NodeList itemList = null;

			// ルート直下か直下で無いかで分岐を行い、ノードリストを設定する
			if(getRootItemID().equals(targetID)){
				itemList = XPathAPI.selectNodeList(
						organizationNode,"./item");
			} else {
				// 指定のIDの<item>直下の<item>を取得する。
				itemList = XPathAPI.selectNodeList(
						organizationNode,"descendant::item[@identifier='" + targetID + "']/item");
			}
			// リスト作成処理開始
			childListBuffer.append("<childlenlist>\n");
			for( int i = 0; i < itemList.getLength(); i++ ) {
				Element item = (Element)itemList.item(i);
				// IDを取得
				String	itemID = "";
				itemID = item.getAttribute(ScormNodeConst.ID_AT_IDENTIFIER);
				// タイトルを取得
				Node titleTextNode = XPathAPI.selectSingleNode(
					item, "./title/text()");
				String	title = null;
				if (titleTextNode != null) {
					title = titleTextNode.getNodeValue();
				} else {
					title = "";
				}
				// ノードの種別を取得
				int nodeType = getItemType(item);
				String iconID = null;
				switch( nodeType ) {
					// アセットの場合
					case ScormNodeConst.ASSET_NODE:
						iconID = "au";
						break;
					// SCOの場合
					case ScormNodeConst.SCO_NODE:
						iconID = "au";
						break;
					// ブロックの場合
					case ScormNodeConst.BLOCK_NODE:
						iconID = "block";
						break;
					default:
						break;
				}
				// 最後のノードにはType="L"をつけて返却する
				if (i + 1 == itemList.getLength()) {
					childListBuffer.append( "<child title=\"" + title + "\" iconid=\"" + iconID + "\" id=\"" + itemID + "\"  type=\"L\"/>\n" );
				}else{
					childListBuffer.append( "<child title=\"" + title + "\" iconid=\"" + iconID + "\" id=\"" + itemID + "\"  type=\"\"/>\n" );
				}
			}
			childListBuffer.append("</childlenlist>\n");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return childListBuffer.toString();	
	}
	
	/**
	 * 
	 * 指定したIDに該当するitemとそれ以下のitemの配列を戻します。
	 * @param targetID 取得対象のitemのidentifier属性。
	 * @return targetIDに該当するitemを含めて、その子孫のitemノードリスト。
	 *          該当するノードがない場合、要素数０のリストを戻します。
	 * 			ルートを指定した場合はルート自身を含みません
	 * 
	 */

	public List getDescendantItems(String targetID) {
		NodeList itemList 		= null;
		List 	 items 			= new ArrayList();
		try{
			// ルート直下か直下で無いかで分岐を行い、ノードリストを設定する
			Node targetItem = null;
			String SearchPath = null;
			if(getRootItemID().equals(targetID)){
				targetItem = organizationNode;
				// ルートからのサーチパスを設定
				SearchPath = ".//item";
			} else {
				// 指定のIDの<item>直下の<item>を取得する。
				targetItem = XPathAPI.selectSingleNode(
						organizationNode,"descendant::item[@identifier='" + targetID + "']");
				// ルート以外からのサーチパスを設定
				SearchPath = ".|.//item";
			}
			// 指定されたIDに一致するitemを取得し、
			// そのitemを含めて子孫のitemノードを取得する。
			if (targetItem != null) {
				// 対象のitemか、対象のitem配下のitemを取得
				itemList = XPathAPI.selectNodeList(targetItem, SearchPath);
				for ( int i = 0; i < itemList.getLength(); i++) {
					items.add(itemList.item(i));
				}
			} else {
				items = null;
			}
		}catch (Exception e) {
			items = null;
		}
		return items;
	}
	
	/**
	 * 指定したitemノードの種別を取得します。<br>
	 * itemノードのidentifierref属性が指し示すリソースを取得し、
	 * その種別を戻します。
	 * リソースの中に存在しないものは全てブロックとします。<br>
	 *
	 * @param item 種別を判定するitemノード。
	 * @return itemの種別。参照のいずれかの値を戻します。
	 * @see ScormNodeConst#ASSET_NODE 
	 * @see ScormNodeConst#SCO_NODE 
	 * @see ScormNodeConst#BLOCK_NODE 
	 */
	public int getItemType(Node item){
		int nodeType = 0;
		try {
			// リソースへの参照ID属性ノードを取得
			Node resourceIdNode = XPathAPI.selectSingleNode(
					item, "./@identifierref");
			if (resourceIdNode != null ) {
				String resourceID = resourceIdNode.getNodeValue();
				// 指定されたリソースIDに一致するresourceノードの
				// scormType属性を取得する。
				Node scormType = XPathAPI.selectSingleNode(
						resourcesNode,
						"./resource[@identifier='" +resourceID + "']"
							+ "/@scormType");
// MOD Start 2005.07.13 NTTR-an 1.2履歴表示対応
				if (scormType == null ) {
//					nodeType = ScormNodeConst.BLOCK_NODE;
				    scormType = XPathAPI.selectSingleNode(
							resourcesNode,
							"./resource[@identifier='" +resourceID + "']"
								+ "/@scormtype");
				}
//	MOD End
				// 取得できない場合は、ブロック
				if (scormType == null ) {
				    nodeType = ScormNodeConst.BLOCK_NODE;
				}
				
				// 取得できた場合は属性の値から判断する。
				else {
					String scormTypeValue = scormType.getNodeValue();
					if(scormTypeValue.equals("asset")){
						nodeType = ScormNodeConst.ASSET_NODE;
					}
					else if (scormTypeValue.equals("sco")){
						nodeType = ScormNodeConst.SCO_NODE;
					}
					else{
						nodeType = ScormNodeConst.BLOCK_NODE;
					}
				}
			}
			// リソースを取得できない場合、ブロック。
			else {
				nodeType = ScormNodeConst.BLOCK_NODE;
			}
		}
		catch (Exception e) {
			nodeType = ScormNodeConst.BLOCK_NODE;
		}
		
		return nodeType;
	}

	/**
	 * ルートのＡＵＩＤを取得します。<br>
	 * organizationNodeノードのidentifier属性の値を取得し戻します。
	 * この処理を行う前にパースは必須です。
	 * @return RootのAuIDの値を戻します。<BR>
	 *          パース処理がされていない場合やノードが取得できていない<BR>
	 *          場合はNULLが戻ります。
	 */
	public String getRootItemID(){
		String RootID = null;
		try{
			Node RootIDNode = XPathAPI.selectSingleNode(
					organizationNode, "./@identifier");
			if (RootIDNode != null ) {
				RootID = RootIDNode.getNodeValue();
			}	
		}catch (Exception e){
			e.printStackTrace();
		}
		return RootID;
	}

	/**
	 * ルートのタイトルを取得します。<br>
	 * organizationNodeノード配下のtitle属性の値を取得し戻します。
	 * この処理を行う前にパースは必須です。
	 * @return Rootのtitleの値を戻します。<BR>
	 *          パース処理がされていない場合やノードが取得できていない<BR>
	 *          場合はNULLが戻ります。
	 */
	public String getRootTitle(){
		String RootTitle = null;
		try{
			Node RootIDNode = XPathAPI.selectSingleNode(
					organizationNode, "./title/text()");
			if (RootIDNode != null ) {
				RootTitle = RootIDNode.getNodeValue();
			}	
		}catch (Exception e){
			e.printStackTrace();
		}
		return RootTitle;
	}

}
