package org.greenstone.gatherer.util;

import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;
import org.w3c.dom.*;

public class DOMTree
    extends JTree {

    public DOMTree(Document document) {
	super();
	setDocument(document);
    }

    public void setDocument(Document document) {
	setModel(new DefaultTreeModel(new DOMTreeNode(document.getDocumentElement(), null)));
    }

    private class DOMTreeNode 
	implements TreeNode {

	private Node node = null;
	private NodeList children = null;
	private String text = null;
	private TreeNode parent = null;
	private TreeNode self = null;

	DOMTreeNode(Node node, TreeNode parent) {
	    this.node = node;
	    this.parent = parent;
	    this.self = this;
	}
	
	/** Returns the children of the receiver as an Enumeration. */
	public Enumeration children() {
	    if(children == null) {
		children = node.getChildNodes();
	    }
	    return new NodeListEnumeration();
	}
          
	/** Returns true if the receiver allows children. */
	public boolean getAllowsChildren() {
	    return true;
	}
          
	/** Returns the child TreeNode at index childIndex. */
	public TreeNode getChildAt(int childIndex) {
	    if(children == null) {
		children = node.getChildNodes();
	    }
	    return new DOMTreeNode(children.item(childIndex), this);
	}
          
	/** Returns the number of children TreeNodes the receiver contains. */
	public int getChildCount() {
	    if(children == null) {
		children = node.getChildNodes();
	    }
	    return children.getLength();
	}
          
	/** Returns the index of node in the receivers children. */
	public int getIndex(TreeNode find_node) {
	    if(children == null) {
		children = node.getChildNodes();
	    }
	    Node target_node = ((DOMTreeNode)find_node).getNode();
	    int children_count = children.getLength();
	    for(int i = 0; i < children_count; i++) {
		Node test_node = children.item(i);
		if(target_node == test_node) {
		    test_node = null;
		    target_node = null;
		    return i;
		}
		test_node = null;
	    }
	    target_node = null;
	    return -1;
	}
	    
	public Node getNode() {
	    return node;
	}

	/** Returns the parent TreeNode of the receiver. */
	public TreeNode getParent() {
	    return parent;
	}
	    
	/** Returns true if the receiver is a leaf. */
	public boolean isLeaf() {
	    return !node.hasChildNodes();
	}

	public String toString() {
	    if(text == null) {
		StringBuffer temp = new StringBuffer(node.getNodeName());
		String value = node.getNodeValue();
		if(value != null && value.length() != 0) {
		    temp.append("=\"");
		    temp.append(value);
		    temp.append("\"");
		}
		value = null;
		if(node instanceof Element) {
		    Element element = (Element) node;
		    temp.append(": ");
		    NamedNodeMap attributes = element.getAttributes();
		    int attribute_count = attributes.getLength();
		    for(int i = 0; i < attribute_count; i++) {
			Node attribute = attributes.item(i);
			temp.append(attribute.getNodeName());
			temp.append("=\"");
			temp.append(attribute.getNodeValue());
			if(i < attribute_count - 1) {
			    temp.append("\" ");
			}
			else {
			    temp.append("\"");
			}
		    }
		    attributes = null;
		    element = null;
		}
		text = temp.toString();
		temp = null;
	    }
	    return text;
	}

	private class NodeListEnumeration
	    implements Enumeration {
	    private int index = 0;
	    /** Tests if this enumeration contains more elements. */
	    public boolean hasMoreElements() {
		return index < children.getLength();
	    }
	    /** Returns the next element of this enumeration if this enumeration object has at least one more element to provide. */
	    public Object nextElement() {
		int old_index = index;
		index = index + 1;
		return new DOMTreeNode(children.item(old_index), self);
	    }
	}
    }
}
