import	java.net.URL;
import	java.io.IOException;
import	java.util.Enumeration;
import	java.util.Hashtable;
import	java.awt.Dimension;
import	java.awt.event.WindowEvent;
import	java.awt.event.WindowAdapter;
import	javax.swing.JTree;
import	javax.swing.tree.DefaultMutableTreeNode;
import	javax.swing.event.TreeSelectionListener;
import	javax.swing.event.TreeSelectionEvent;
import	javax.swing.tree.TreeSelectionModel;
import	javax.swing.tree.TreePath;
import	javax.swing.JEditorPane;
import	javax.swing.JScrollPane;
import	javax.swing.JSplitPane;
import	javax.swing.JFrame;
import	javax.xml.parsers.DocumentBuilder;
import	javax.xml.parsers.DocumentBuilderFactory;
import	org.w3c.dom.Document;
import	org.w3c.dom.Element;
import	org.w3c.dom.Node;
import	org.w3c.dom.NodeList;
import	org.w3c.dom.NamedNodeMap;

/**
 * XML document viewer.
 * Copyright (c) 2003 by Phil Selby
 * All rights reserved.
 * Permission granted to use and/or publish this code provided
 * that this copyright notice remains intact.
 */

public class XDocletConfigViewer extends JFrame {

	private static final String	pgmName = "XDocletConfigViewer";
	private static final int	singleSelect =
	  TreeSelectionModel.SINGLE_TREE_SELECTION;

	public XDocletConfigViewer( Element elem ) {
		super("XDocletConfigViewer");
		DefaultMutableTreeNode top = createXMLNode( elem );
		JTree	tree = new JTree( top );
		tree.putClientProperty( "JTree.lineStyle", "Angled" );
		tree.getSelectionModel().setSelectionMode( singleSelect );
		expandAll( tree, top );
		JScrollPane scrollPane = new JScrollPane( tree );
		getContentPane().add( scrollPane );
	}

	private DefaultMutableTreeNode createXMLNode( Element elem ) {
		DefaultMutableTreeNode node = null;
		DefaultMutableTreeNode leafNode = null;
		NamedNodeMap	attrList = elem.getAttributes();
		String		userData = null;
		NodeList	nl = elem.getChildNodes();
		Node		n = null;
		int		numChildren = nl.getLength();

		/*
		 * build node name and attributes
		 */

		userData = elem.getNodeName() +
		  getAttributes( attrList );

		/*
		 * handle terminal nodes
		 */

		if( numChildren == 1 ) {
			n = elem.getFirstChild();
			if( n.getNodeType() != Node.TEXT_NODE ) {
				node = new DefaultMutableTreeNode( userData );
				leafNode = new DefaultMutableTreeNode(
				  n.getNodeValue(), false );
				node.add( leafNode );
				return( node );
			}
			node = new DefaultMutableTreeNode( userData, false );
			return( node );
		}

		/*
		 * recurse through children
		 */

		node = new DefaultMutableTreeNode( userData );
		for( int i = 0; i < numChildren; i++ ) {
			n = nl.item( i );
			if( n.getNodeType() == Node.ELEMENT_NODE ) {
				DefaultMutableTreeNode	subNode =
				  createXMLNode( (Element) n );
				node.add( subNode );
			}
		}

		return( node );
	}

	/*
	 * expand all nodes
	 */

	private void expandAll( JTree tree, DefaultMutableTreeNode root ) {
		if( root.isLeaf() )
			return;
		Enumeration	en = root.children();
		while( en.hasMoreElements() )
			expandAll( tree,
			  (DefaultMutableTreeNode) en.nextElement() );
		tree.expandPath( new TreePath( root.getPath() ) );
	}

	/*
	 * format attribute values
	 */

	private String getAttributes( NamedNodeMap attrs ) {
		StringBuffer	sb = new StringBuffer();
		if( attrs == null )
			return( sb.toString() );
		Node	node = null;
		for( int i = 0; i < attrs.getLength(); i++ ) {
			node = attrs.item( i );
			if( sb.length() == 0 )
				sb.append( " " );
			else
				sb.append( ", " );
			sb.append( node.getNodeName() + " = " +
			  node.getNodeValue() );
		}
		return( sb.toString() );
	}

	public static void main(String[] args) throws IOException {
		Document	doc = null;
		Element		top = null;

		/*
		 * ensure correct usage
		 */

		if( args.length != 1 ) {
			System.err.println( "Usage: " + pgmName +
			  " filename" );
			System.exit( 12 );
		}

		/*
		 * parse the document
		 */

		try {
			DocumentBuilderFactory	factory =
			  DocumentBuilderFactory.newInstance();
			DocumentBuilder	builder = factory.newDocumentBuilder();
			doc = builder.parse( args[0] );
			top = doc.getDocumentElement();
		}
		catch( Exception e ) {
			e.printStackTrace();
			System.exit( 12 );
		}

		/*
		 * build the viewer
		 */

		XDocletConfigViewer app = new XDocletConfigViewer( top );
		app.addWindowListener( new WindowAdapter() {
			public void windowClosing( WindowEvent e ) {
				System.exit( 0 );
			}
		} );
		app.setSize( 500, 400 );
		app.setVisible(true);
	}
}