/**
 * @(#)elementBooster.java
 * Copyright 2001 Nomura Research Institute, LTD. All rights reserved.
 * RID-3 : element booster
 * @author  Intelligent Technology Inc.
 * @version 1.00 2001/10/01-2001/03/25
 * @see 
 */

package	jp.co.nri.rid.xml;

// java
import	java.util.*;

// W3C DOM
import	org.w3c.dom.*;

/**
 * org.w3c.dom.Elementを使いやすくするためのラッパー
 */

public class elementBooster{
	
	/**
	 * @param	document	ドキュメント
	 * @param	element		エレメント
	 * @since	1.00
	 */
	public	elementBooster(documentBooster document ,Element element){
		myDocument	=	document;
		myElement	=	element;
	}
	
	/**
	 * @param	document	ドキュメント
	 * @param	name		エレメント名
	 * @since	1.00
	 */
	public	elementBooster(documentBooster document ,String name){
		myDocument	=	document;
		myElement	=	myDocument.document().createElement(name);
	}
	
	/**
	 * @param	element		エレメント
	 * @since	1.00
	 */
	public	elementBooster(Element element){
		myDocument	=	new documentBooster(element.getOwnerDocument());
		myElement	=	element;
	}
	
	/**
	 * コピーコンストラクタ
	 * @param	element		コピー元elementBoosterオブジェクト
	 * @since	1.00
	 */
	public	elementBooster(elementBooster element){
		myDocument	=	element.document();
		myElement	=	element.element();
	}
	
	/**
	 * ドキュメントを取得する。
	 * @return	このエレメントの入っているドキュメント
	 * @since	1.00
	 */
	public	documentBooster	document(){	return myDocument;	}
	
	/**
	 * Elementオブジェクトを取得する。
	 * @return	Elementオブジェクト
	 * @since	1.00
	 */
	public	Element			element(){	return myElement;	}
	
	/**
	 * このオブジェクトがnullかどうかを判定する。
	 * @return	nullならtrue
	 * @since	1.00
	 */
	public	boolean isNull(){
		if(null==myElement)	return true;
		return false;
	}
	
	/**
	 * このエレメントのタグ名を取得する。
	 * @return	このエレメントのタグ名。
	 * @since	1.00
	 */
	public	String	tagname(){ return myElement.getTagName(); }
	
	/**
	 * このエレメントのテキストを設定する。
	 * @param	text	テキスト値。
	 * @since	1.00
	 */
	public	void	text(String text){
		removeText();
		myElement.appendChild(myElement.getOwnerDocument().createTextNode(text));
	}
	
	/**
	 * このエレメントのテキストを削除する。
	 * @since	1.00
	 */
	protected	void	removeText(){
		NodeList	nl = myElement.getChildNodes();
		
		int mx = nl.getLength();
		for(int i = 0;i < mx;i++){
			Node n = nl.item(i);
			if(Node.TEXT_NODE == n.getNodeType()) myElement.removeChild(n);
		}
	}
	
	/**
	 * このエレメントのテキストを取得する。
	 * @return	このエレメントのテキスト。
	 * @since	1.00
	 */
	public	String	text(){
		NodeList	nl = myElement.getChildNodes();
		
		int mx = nl.getLength();
		for(int i = 0;i < mx;i++){
			Node n = nl.item(i);
			if(Node.TEXT_NODE == n.getNodeType()){
				String s;
//				try{ s = n.getNodeValue().trim(); }
				try{ s = n.getNodeValue(); }
				catch(NullPointerException e){ return null; }
				if(s.length() > 0)	return s;
				return null;
			}
		}
		
		return null;
	}
	
	/**
	 * このエレメントの属性を設定する。
	 * @param	name	属性名。
	 * @param	value	属性値。
	 * @since	1.00
	 */
	public	void	attribute(String name ,String value){
		if(null==name)	return;
		if(null==value)				myElement.removeAttribute(name);
		else if(0>=value.length())	myElement.removeAttribute(name);
		else						myElement.setAttribute(name ,value);
	}
	
	
	/**
	 * このエレメントの属性値を取得する。
	 * @param	name	属性名。
	 * @return	属性値。
	 * @since	1.00
	 */
	public	String	attribute(String name){
		String attribute = myElement.getAttribute(name);
		if(null==attribute)	return null;
//		if(0<attribute.trim().length())	return attribute;
		if(0<attribute.length())	return attribute;
		return null;
	}
	
	/**
	 * このエレメントの属性値を取得する。(int)
	 * @param	name	属性名。
	 * @return	属性値。
	 * @since	1.00
	 */
	public	int	attributeInt(String name){
		return numeric(attribute(name));
	}
	
	/**
	 * このエレメントの属性リストを取得する。
	 * @return	属性リスト。
	 * @since	1.00
	 */
	public	Attributes	attributes(){
		NamedNodeMap	nnm = myElement.getAttributes();
		
		Attributes attributes = new Attributes();
		
		int mx = nnm.getLength();
		for(int i = 0;i < mx;i++){
			Node n = nnm.item(i);
//			String value = n.getNodeValue().trim();
			String value = n.getNodeValue();
			if(0 >= value.length())	continue;
			attributes.add(n.getNodeName() ,value);
		}
		
		if(0 < attributes.count())	return attributes;
		return null;
	}
	
	/**
	 * このエレメントの属性を設定する。複数を一括で設定できる。
	 * @param	attributes	属性リスト。
	 * @since	1.00
	 */
	public void attributes(Attributes attributes){
		if(null==attributes)	return;
		
		Attribute[] a = attributes.attributes();
		if(null==a)	return;
		
		int mx = a.length;
		for(int i = 0;i < mx;i++) attribute(a[i].name ,a[i].value);
	}
	
	/**
	 * このエレメントの最初の子エレメントの属性リストを取得する。
	 * @param	name	タグ名。
	 * @since	1.00
	 */
	public	Attributes	childAttributes(String name){
		elementBooster child = child(name);
		if(null == child)	return null;
		
		return child.attributes();
	}
	
	/**
	 * 新しいエレメントを作成する。(子エレメントには追加しない)
	 * @param	name	タグ名。
	 * @return	新しく作成したエレメント。
	 * @since	1.00
	 */
	public	elementBooster	newElement(String name){
		if(null==name)	return null;
		Element	e = myElement.getOwnerDocument().createElement(name);
		if(null==e)		return null;
		return new elementBooster(myDocument ,e);
	}
	
	/**
	 * 子エレメントを追加する。
	 * @param	element	エレメント。
	 * @since	1.00
	 */
	public	void	add(elementBooster element){
		if(null!=element)	myElement.appendChild(element.element());
	}
	
	/**
	 * 子エレメントを追加する。
	 * @param	name	エレメント名。
	 * @return	子エレメントとして追加したエレメント。
	 * @since	1.00
	 */
	public	elementBooster	add(String name){
		elementBooster element = newElement(name);
		if(null==element)	return null;
		
		add(element);
		return element;
	}
	
	/**
	 * 属性も指定して子エレメントを追加する。
	 * @param	name		エレメント名。
	 * @param	attributes	属性。
	 * @return	子エレメントとして追加したエレメント。
	 * @since	1.00
	 */
	public	elementBooster	add(String name ,Attributes attributes){
		elementBooster element = add(name);
		if(null == element)	return null;
		
		if(null != attributes)	element.attributes(attributes);
		
		return element;
	}
	
	/**
	 * 指定したタグ名の最初の子エレメントを取得する。
	 * @param	name	タグ名。
	 * @return	エレメント。
	 * @since	1.00
	 */
	public	elementBooster	child(String name){
		if(null==name)	return null;
		NodeList nl = myElement.getChildNodes();
		if(null==nl)	return null;
		
		int mx = nl.getLength();
		if(0>=mx)	return null;
		for(int i=0;i<mx;i++){
			Node n = nl.item(i);
			if(Node.ELEMENT_NODE != n.getNodeType())	continue;
			if(!name.equals(n.getNodeName()))			continue;
			
			return new elementBooster(myDocument ,(Element)n);
		}
		
		return null;
	}
	
	/**
	 * 指定したタグ名の子エレメントをすべて取得する。
	 * @param	name	タグ名。
	 * @return	エレメント配列。
	 * @since	1.00
	 */
	public	elementBooster[]	children(String name){
		if(null==name)	return null;
		NodeList nl = myElement.getChildNodes();
		if(null==nl)	return null;
		
		Vector vec = new Vector();
		int mx = nl.getLength();
		if(0>=mx)	return null;
		for(int i=0;i<mx;i++){
			Node n = nl.item(i);
			if(Node.ELEMENT_NODE != n.getNodeType())	continue;
			if(!name.equals(n.getNodeName()))			continue;
			vec.add(new elementBooster(myDocument ,(Element)n));
		}
		if(0>=vec.size())	return null;
		
		return (elementBooster[])vec.toArray(new elementBooster[0]);
	}
	
	/**
	 * 指定したタグ名の子孫エレメントをすべて取得する。
	 * @param	name	タグ名。
	 * @return	エレメント配列。
	 * @since	1.00
	 */
	public	elementBooster[]	offspring(String name){
		if(null==name)	name = "*";
		NodeList list = myElement.getElementsByTagName(name);
		if(null==list)	return null;
		int mx = list.getLength();
		if(0==mx)		return null;
		elementBooster[] elements = new elementBooster[mx];
		for(int i=0;i<mx;i++){
			elements[i] = new elementBooster(myDocument ,(Element)list.item(i));
		}
		return elements;
	}
	
	/**
	 * 子孫エレメントをすべて取得する。
	 * @return	エレメント配列。
	 * @since	1.00
	 */
	public	elementBooster[]	offspring(){ return offspring(null); }
	
	/**
	 * 子エレメントをすべて削除する。
	 * @since	1.00
	 */
	public	void	removeChild(){
		NodeList	nl = myElement.getChildNodes();
		if(null==nl)	return;
		
		int mx = nl.getLength();
		for(int i = mx-1;0 <= i;i--){
			Node n = nl.item(i);
			if(null!=n) myElement.removeChild(n);
		}
	}
	
	/**
	 * タグ名を指定して子エレメントを削除する。
	 * @since	1.00
	 */
	public	void	removeChildren(String name){
		if(null==name)	return;
		NodeList nl = myElement.getChildNodes();
		if(null==nl)	return;
		
		for(int i=nl.getLength()-1;0<=i;i--){
			Node n = nl.item(i);
			if(Node.ELEMENT_NODE != n.getNodeType())	continue;
			if(!name.equals(n.getNodeName()))			continue;
			myElement.removeChild(n);
		}
	}
	
	/**
	 * このエレメントを削除する。
	 * @since	1.00
	 */
	public	void	remove(){
		myElement.getParentNode().removeChild(myElement);
	}
	
	/**
	 * 子エレメントをすべて取得する。
	 * @return	エレメント配列。
	 * @since	1.00
	 */
	public	elementBooster[]	children(){
		NodeList	nl = myElement.getChildNodes();
		if(null==nl)	return null;
		
		Vector vec = new Vector();
		int mx = nl.getLength();
		if(0>=mx)	return null;
		for(int i=0;i<mx;i++){
			Node	n	=	nl.item(i);
			if(Node.ELEMENT_NODE != n.getNodeType())	continue;
			vec.add(new elementBooster(myDocument ,(Element)n));
		}
		if(0>=vec.size())	return null;
		
		return (elementBooster[])vec.toArray(new elementBooster[0]);
	}
	
	/**
	 * 親エレメントを取得する。
	 * @return	親エレメント。
	 * @since	1.00
	 */
	public	elementBooster	parent(){
		try{
			Node	n	=	myElement.getParentNode();
			if(Node.ELEMENT_NODE != n.getNodeType())	return null;
			return new elementBooster(myDocument ,(Element)n);
		}catch(NullPointerException e){ return null; }
	}
	
	protected int numeric(String s){
		if(null==s)	return 0;
		if(0>=s.trim().length())	return 0;
		
		StringBuffer sb = new StringBuffer(s);
		for(int i=sb.length()-1;0<=i;i--){
			char c = sb.charAt(i);
			if(('0' <= c) && ('9' >= c))	continue;
			if(('-' == c) || ('.' == c))	continue;
			
			sb.deleteCharAt(i);
		}
		
		return Integer.parseInt(sb.toString());
	}
	
	protected	documentBooster	myDocument;
	protected	Element			myElement;
}