/*
 * $Id: GuiDemo.java,v 1.4 2000/02/17 04:12:42 mode Exp $
 *
 * Copyright (c) 1998-1999 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
 * modify and redistribute this software in source and binary code form,
 * provided that i) this copyright notice and license appear on all copies of
 * the software; and ii) Licensee does not utilize the software in a manner
 * which is disparaging to Sun.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
 * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
 * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control of
 * aircraft, air traffic, aircraft navigation or aircraft communications; or in
 * the design, construction, operation or maintenance of any nuclear
 * facility. Licensee represents and warrants that it will not use or
 * redistribute the Software for such purposes.
 */

package project;

import java.awt.*;
import java.awt.event.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Properties;

import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

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

import com.sun.xml.tree.XmlDocument;
import com.sun.xml.tree.XmlDocumentBuilder;
import com.sun.xml.tree.SimpleElementFactory;
import com.sun.xml.parser.Resolver;
import org.xml.sax.Parser;


public class GuiDemo extends JApplet
{
    private XmlDocument			doc;

    //
    // usage:  main someprops.props someplay.xml 
    //
    public static void main (String argv [])
    {
	try {
	    if (argv.length != 2) {
		System.err.println ("usage: java project.GuiDemo "
		    + "someprops.props someplay.xml");
		System.exit (1);
	    }

	    //
	    // Load the document, using the appropriate custom
	    // DOM elements.
	    //
	    XmlDocument			doc = createDocument (
		Resolver.createInputSource (new File (argv [1])),
		new FileInputStream (argv [0]),
		new ErrorPrinter ()
		);

	    //
	    // Render in a simple frame.
	    //
	    JFrame	frame = new JFrame ();
	    GuiDemo	applet = new GuiDemo ();

	    applet.doc = doc;

	    frame.getContentPane ().add ("Center", applet);
	    frame.addWindowListener (new WindowAdapter () {
		    public void windowClosing (WindowEvent e) {
			System.exit (0);
		    }});
	    frame.pack ();
	    frame.setSize (new Dimension (800, 600));
	    applet.init ();
	    applet.start ();
	    frame.setVisible (true);
	    
	} catch (Throwable t) {
            t.printStackTrace (System.out);
	}
    }

    //
    // Applet "main"
    //
    public void init() {
	if (doc == null) {
	    Exception	err = null;

	    try {
		String		playURI = getParameter ("play");
		String		propsURI = getParameter ("elements");
		doc = createDocument (
		    Resolver.createInputSource (
			    new URL (getDocumentBase (), playURI),
			    true),
		    new URL (getDocumentBase (), propsURI).openStream (),
		    new ErrorDialog ()
		    );
	    } catch (SAXException e) {
		err = e;
	    } catch (IOException e) {
		err = e;
	    } catch (RuntimeException e) {
		err = e;
	    } catch (ParserConfigurationException e) {
	   	err = e; 
	    }
	    if (err != null) {
		err.printStackTrace (System.err);
		return;
	    }
	}
	getContentPane ().add ("Center", new TreePanel (doc));
    }

    static private XmlDocument createDocument (
	InputSource	input,
	InputStream	propsStream,
	ErrorHandler	errorHandler
    ) throws SAXException, IOException, ParserConfigurationException
    {
	try {
	    XmlDocumentBuilder		builder = new XmlDocumentBuilder ();
	    builder.setIgnoringLexicalInfo (true);
	    SAXParserFactory spf = SAXParserFactory.newInstance();
	    spf.setValidating (true);
	    SAXParser sp = spf.newSAXParser ();
	    Parser parser = sp.getParser ();
	    JFrame			frame;

	    //
	    // Configure the builder to create the right elements.
	    //
	    {
		Properties		props;
		SimpleElementFactory	factory;

		props = new Properties ();
		props.load (propsStream);
		factory = new SimpleElementFactory ();
		factory.addMapping (props, GuiDemo.class.getClassLoader ());
		builder.setElementFactory (factory);
	    }

	    //
	    // Configure the parser
	    //
	    parser.setErrorHandler (errorHandler);
	    parser.setEntityResolver (new Resolver ());
	    parser.setDocumentHandler (builder);
	    parser.parse (input);

	    // Look at how the different versions print themselvs...
	    if (false) {
		builder.getDocument ().write (System.out);
		System.exit (0);
	    }

	    return builder.getDocument ();
	    
	} catch (SAXParseException e) {
	    // already reported
	    throw e;

	} catch (SAXException e) {
	    e.printStackTrace (System.out);
	    throw e;

	} catch (IOException e) {
	    e.printStackTrace (System.out);
	    throw e;

	}
    }

    static class ErrorPrinter implements ErrorHandler
    {
	private void message (String level, SAXParseException e)
	{
	    System.out.print ("** ");
	    System.out.println (level);
	    System.out.print ("   URI = ");
	    System.out.print (e.getSystemId ());
	    System.out.print (" Line = ");
	    System.out.println (e.getLineNumber ());
	    System.out.print ("   Message = ");
	    System.out.println (e.getMessage ());

	    /*
	    if (e.getException () != null)
		e.getException ().printStackTrace (System.out);
	    else
		e.printStackTrace (System.out);
	    */
	}

	public void error (SAXParseException e)
	{
	    // normally a validity error
	    message ("Error (recoverable)", e);
	}

	public void warning (SAXParseException e)
	{
	    message ("Warning", e);
	}

	public void fatalError (SAXParseException e)
	{
	    message ("FATAL ERROR", e);
	}
    }

    class ErrorDialog implements ErrorHandler
    {
	private void message (String level, int type, SAXParseException e)
	throws SAXParseException
	{
	    String	messages [] = new String [6];

	    messages [0] = level;
	    messages [1] = "URI " + e.getSystemId ();
	    messages [2] = "Line " + e.getLineNumber ();
	    messages [3] = "";
	    messages [4] = e.getMessage ();

	    // XXX may want to dump the exception, too

	    if (type != JOptionPane.INFORMATION_MESSAGE) {
		messages [5] = "Press 'Yes' to continue parsing.";
		int value = JOptionPane.showConfirmDialog (
		    GuiDemo.this,
		    messages,
		    "Continue Parsing?", JOptionPane.YES_NO_OPTION,
		    type);
		if (value == JOptionPane.YES_OPTION)
		    return;
	    } else {
		messages [5] = "This error is not recoverable.";
		JOptionPane.showMessageDialog (
		    GuiDemo.this,
		    messages,
		    "Fatal XML Error",
		    type);
	    }
	    throw e;
	}

	public void warning (SAXParseException e)
	throws SAXParseException
	{
	    message ("Warning reported by XML parser",
		JOptionPane.WARNING_MESSAGE, e);
	}

	public void error (SAXParseException e)
	throws SAXParseException
	{
	    // normally a validity error
	    message ("Found a non-fatal XML Error",
		JOptionPane.ERROR_MESSAGE, e);
	}

	public void fatalError (SAXParseException e)
	throws SAXParseException
	{
	    message ("Found a fatal XML Error",
		JOptionPane.INFORMATION_MESSAGE, e);
	}
    } 
    
    
    // modeled after Java Tutorial's TreeDemo
    static class TreePanel extends JSplitPane
	implements TreeSelectionListener
    {
    	private JTree		tree;
    	private JEditorPane	text;
    	
    	TreePanel (XmlDocument doc) {
    	    super (JSplitPane.HORIZONTAL_SPLIT);

    	    setBorder (BorderFactory.createEmptyBorder (5, 5, 5, 5));
    	    
	    Element		root;

    	    root = doc.getDocumentElement ();
	    root.normalize ();
    	    tree = new JTree ((TreeNode)root);
            tree.getSelectionModel ()
            	.setSelectionMode (TreeSelectionModel.SINGLE_TREE_SELECTION);
            tree.addTreeSelectionListener (this);
            
            text = new JEditorPane ();
            text.setEditable (false);
	    text.setContentType ("text/html");	// html 3.2

	    //
	    // Were we to add a JDK 1.2 dependency here (later!), the
	    // document could be a BeanContext and the editor would be
	    // a BeanContextService.  Then scene elements (and others!)
	    // could look up that editor as needed, after selecting a
	    // node invoked a selected() method.
	    //
	    // Instead, we've got a simpler approach.
	    //
	    NodeList		scenes;
	    Node		node;

	    scenes = root.getElementsByTagName ("SCENE");
	    for (int i = 0; (node = scenes.item (i)) != null; i++) {
		if (node instanceof SceneElement)
		    ((SceneElement)node).setEditor (text);
	    }

            // The right pane is used to render each scene.
            
            JScrollPane		treeView, textView;
            
            setLeftComponent (treeView = new JScrollPane (tree));
            setRightComponent (textView = new JScrollPane (text));
            
            Dimension minimumSize = new Dimension (100, 50);
            textView.setMinimumSize (minimumSize);
            treeView.setMinimumSize (minimumSize);

            setPreferredSize (new Dimension (780, 580));
            setDividerLocation (250);
    	}

	public void valueChanged (TreeSelectionEvent e)
	{
	    TreePath	path = tree.getSelectionPath ();
	    Object	selected;

	    if (path == null)	// rm selection
		return;
	    selected = path.getLastPathComponent ();
	    if (selected instanceof SceneElement)
		((SceneElement)selected).draw ();
	}
    }
}
