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


/**
 * @author kawamura
 *
 * TODO この生成された型コメントのテンプレートを変更するには次を参照。
 * ウィンドウ ＞ 設定 ＞ Java ＞ コード・スタイル ＞ コード・テンプレート
 */
public abstract class SmlChildNode implements SmlNode {

	protected int fLength;
	protected SmlElement fParent;

	/* (Javadoc なし)
	 * @see editor.node.SMLNode#getLength()
	 */
	public int getLength() {
		return fLength;
	}

	/* (Javadoc なし)
	 * @see editor.node.SMLNode#getParentNode()
	 */
	public SmlNode getParentNode() {
		return fParent;
	}
	
	public void setParentNode(SmlElement parent) {
		if(fParent != null && fParent != parent) {
			fParent.removeChild(this);
		}
		fParent = parent;
	}

	public SmlNode getNextSibling() {
		int index = fParent.indexOf(this);
		return (SmlNode)fParent.getChild(index + 1);
	}

	/* (Javadoc なし)
	 * @see editor.node.SMLNode#getPreviousSibling()
	 */
	public SmlNode getPreviousSibling() {
		int index = fParent.indexOf(this);
		return (SmlNode)fParent.getChild(index - 1);
	}
	
	/* (Javadoc なし)
	 * @see editor.node.SMLNode#appendChild(editor.node.SMLNode)
	 */
	public SmlNode appendChild(SmlNode newChild) {
		// TODO RuntimeExceptionを投げるように…
		return null;
	}

	/* (Javadoc なし)
	 * @see editor.node.SMLNode#removeChild(editor.node.SMLNode)
	 */
	public SmlNode removeChild(SmlNode oldChild) {
		// TODO 自動生成したメソッド・スタブ
		return null;
	}

	/* (Javadoc なし)
	 * @see editor.node.SMLNode#replaceChild(editor.node.SMLNode, editor.node.SMLNode)
	 */
	public SmlNode replaceChild(SmlNode newChild, SmlNode oldChild) {
		// TODO 自動生成したメソッド・スタブ
		return null;
	}

	/* (Javadoc なし)
	 * @see editor.node.SmlNode#insertBefore(editor.node.SmlNode, editor.node.SmlNode)
	 */
	public SmlNode insertBefore(SmlNode newChild, SmlNode refChild) {
		// TODO 自動生成したメソッド・スタブ
		return null;
	}

	/* (Javadoc なし)
	 * @see editor.node.SMLNode#getFirstChild()
	 */
	public SmlNode getFirstChild() {
		// TODO 自動生成したメソッド・スタブ
		return null;
	}

	/* (Javadoc なし)
	 * @see editor.node.SMLNode#getLastChild()
	 */
	public SmlNode getLastChild() {
		// TODO 自動生成したメソッド・スタブ
		return null;
	}

	/* (Javadoc なし)
	 * @see editor.node.SMLNode#hasAttributes()
	 */
	public boolean hasAttributes() {
		// TODO 自動生成したメソッド・スタブ
		return false;
	}
	
	/* (Javadoc なし)
	 * @see editor.node.SmlNode#getNodeName()
	 */
	public String getNodeName() {
		// TODO 自動生成したメソッド・スタブ
		return null;
	}

	/* (Javadoc なし)
	 * @see editor.node.SmlNode#setNodeValue(java.lang.String)
	 */
	public void setNodeValue(String nodeValue) {
		// TODO 自動生成したメソッド・スタブ
		
	}

	/* (Javadoc なし)
	 * @see editor.node.SmlNode#getNodeValue()
	 */
	public String getNodeValue() {
		// TODO 自動生成したメソッド・スタブ
		return null;
	}
	
	/* (Javadoc なし)
	 * @see editor.node.SmlNode#isNodeAncestor(editor.node.SmlNode)
	 */
	public boolean isNodeAncestor(SmlNode anotherNode) {
		if (anotherNode == null) {
		    return false;
		}

		SmlNode ancestor = this;

		do {
		    if (ancestor == anotherNode) {
		    	return true;
		    }
		    ancestor = ancestor.getParentNode();
		} while(ancestor != null);

		return false;
	}

	/* (Javadoc なし)
	 * @see editor.node.SmlNode#getSharedAncestor(editor.node.SmlNode)
	 */
	public SmlNode getSharedAncestor(SmlNode anotherNode) {
		// javax.swing.tree.DefaultMutableTreeNodeより拝借
		if (anotherNode == this) {
			return this;
		} else if (anotherNode == null) {
			return null;
		}
		
		int level1, level2, diff;
		SmlNode node1, node2;
		
		level1 = getLevel();
		level2 = anotherNode.getLevel();
		
		if (level2 > level1) {
			diff = level2 - level1;
			node1 = anotherNode;
			node2 = this;
		} else {
			diff = level1 - level2;
			node1 = this;
			node2 = anotherNode;
		}
		
		// Go up the tree until the nodes are at the same level
		while (diff > 0) {
			node1 = node1.getParentNode();
			diff--;
		}
		
		// Move up the tree until we find a common ancestor.  Since we know
		// that both nodes are at the same level, we won't cross paths
		// unknowingly (if there is a common ancestor, both nodes hit it in
		// the same iteration).
		
		do {
			if (node1 == node2) {
				return node1;
			}
			node1 = node1.getParentNode();
			node2 = node2.getParentNode();
		} while (node1 != null);// only need to check one -- they're at the
		// same level so if one is null, the other is
		
		if (node1 != null || node2 != null) {
			throw new Error ("nodes should be null");
		}
		
		return null;
	}
	
	public int getLevel() {
		int levels = 0;
		SmlNode ancestor = this.getParentNode();
		while(ancestor != null){
			levels++;
			ancestor = ancestor.getParentNode();
		}
		
		return levels;
	}
	
	public boolean isRootElement() {
		return fParent == null;
	}
	
	public String getPathFromRootElement() {
		SmlElement parent= fParent;
		SmlNode child = this;
		StringBuffer buffer = new StringBuffer();
		while(parent != null) {
			int num = parent.indexOf(child);
			buffer.insert(0, "/" + num);
			child = parent;
			parent = (SmlElement)parent.getParentNode();
		}
		return buffer.toString();
	}
	
	protected abstract int calculateLength();
}
