/* $Id: SmlElement.java 125 2011-03-09 09:49:51Z ohura $ */
/*
 * 作成日： 2004/10/12
 *
 * TODO この生成されたファイルのテンプレートを変更するには次を参照。
 * ウィンドウ ＞ 設定 ＞ Java ＞ コード・スタイル ＞ コード・テンプレート
 */
package sml_editor.node;

import java.util.NoSuchElementException;
import java.util.Vector;

import org.w3c.dom.Element;
import org.w3c.dom.Node;

/**
 * @author kawamura
 *
 * TODO この生成された型コメントのテンプレートを変更するには次を参照。
 * ウィンドウ ＞ 設定 ＞ Java ＞ コード・スタイル ＞ コード・テンプレート
 */
public class SmlElement extends SmlChildNode {
	
	private Element fElement;
	private Vector<SmlNode> fChildren = new Vector<SmlNode>();
	

	/**
	 * @param elem
	 */
	public SmlElement(Element elem) {
		fElement = elem;
	}

	/* (Javadoc なし)
	 * @see editor.node.SMLNode#getNode()
	 */
	public Node getNode() {
		return fElement;
	}

	/* (Javadoc なし)
	 * @see editor.node.SMLNode#appendChild(editor.node.SMLNode)
	 */
	public SmlNode appendChild(SmlNode newChild) {
		return insertBefore(newChild, null);
	}
	
	public SmlNode appendChild2(SmlNode newChild) {
		return insertBefore2(newChild, null);
	}
	
	/* (Javadoc なし)
	 * @see editor.node.SMLNode#insertBefore(editor.node.SMLNode)
	 */
	public SmlNode insertBefore(SmlNode newChild, SmlNode refChild) {
		SmlNode node = insertBefore2(newChild, refChild);
		if(refChild == null) {
			fElement.insertBefore(newChild.getNode(), null);
		} else {
			fElement.insertBefore(newChild.getNode(), refChild.getNode());
		}
		return node;
	}

	/**
	 * newChildをrefChildの前に追加する。その際文字数の設定は行わない
	 * @return
	 */
	public SmlNode insertBefore2(SmlNode newChild, SmlNode refChild) {
		if(refChild == null) {
			fChildren.add(newChild);
		} else {
			int index = fChildren.indexOf(refChild);
			fChildren.add(index, newChild);
		}
		newChild.setParentNode(this);
		plusLength(newChild.getLength());
		return newChild;
	}

	/* (Javadoc なし)
	 * @see editor.node.SMLNode#removeChild(editor.node.SMLNode)
	 */
	public SmlNode removeChild(SmlNode oldChild) {
		fChildren.remove(oldChild);
		fElement.removeChild(oldChild.getNode());
		plusLength(-1 * oldChild.getLength());
		return oldChild;
	}

	/* (Javadoc なし)
	 * @see editor.node.SMLNode#replaceChild(editor.node.SMLNode, editor.node.SMLNode)
	 */
	public SmlNode replaceChild(SmlNode newChild, SmlNode oldChild) {
		insertBefore(newChild, oldChild);
		removeChild(oldChild);
		return oldChild;
	}

	/* (Javadoc なし)
	 * @see editor.node.SMLNode#getFirstChild()
	 */
	public SmlNode getFirstChild() {
		try {
			return (SmlNode)fChildren.firstElement();
		} catch (NoSuchElementException e) {
			// 子ノードが無いときはnullを返す
			return null;
		}
	}

	/* (Javadoc なし)
	 * @see editor.node.SMLNode#getLastChild()
	 */
	public SmlNode getLastChild() {
		try {
			return (SmlNode)fChildren.lastElement();
		} catch (NoSuchElementException e) {
			// 子ノードが無いときはnullを返す
			return null;
		}
	}

	/* (Javadoc なし)
	 * @see editor.node.SMLNode#hasAttributes()
	 */
	public boolean hasAttributes() {
		return fElement.hasAttributes();
	}

	/* childNode が何番目の子かを調べる */
	protected int indexOf(SmlNode childNode) {
		return fChildren.indexOf(childNode);
	}

	protected SmlNode getChild(int index) {
		try {
			return (SmlNode)fChildren.get(index);
		} catch(ArrayIndexOutOfBoundsException e) {
			return null;
		}
	}
	
	/* (Javadoc なし)
	 * @see editor.node.SMLChildNode#caluculateLength()
	 */
	protected int calculateLength() {
		int sum = 0;
		for(int i = 0; i < fChildren.size(); i++) {
			sum += ((SmlNode)fChildren.get(i)).getLength();
		}
		return sum;
	}
	
	/**
	 * 文字数を設定する
	 * @param increment - 増分
	 */
	void plusLength(int increment) {
		int length = fLength + increment;
		if(fParent != null) {
			fLength = length;
			fParent.plusLength(increment);
		} else {
			fLength = length;
		}
	}

	/* (Javadoc なし)
	 * @see editor.node.SMLNode#getNodeType()
	 */
	public short getNodeType() {
		return SmlNode.ELEMENT_NODE;
	}

	/**
	 * @return タグ名
	 */
	public String getTagName() {
		return fElement.getTagName();
	}
}
