/*
 * @(#)DirectApplet.java    2.6.0g   2 December 2007
 *
 * Copyright 2007
 * College of Computer and Information Science
 * Northeastern University
 * Boston, MA  02115
 *
 * The Java Power Tools software may be used for educational
 * purposes as long as this copyright notice is retained intact
 * at the top of all source files.
 *
 * To discuss possible commercial use of this software, 
 * contact Richard Rasala at Northeastern University, 
 * College of Computer and Information Science,
 * 617-373-2462 or rasala@ccs.neu.edu.
 *
 * The Java Power Tools software has been designed and built
 * in collaboration with Viera Proulx and Jeff Raab.
 *
 * Should this software be modified, the words "Modified from 
 * Original" must be included as a comment below this notice.
 *
 * All ation rights are retained.  This software or its 
 * documentation may not be published in any media either
 * in whole or in part without explicit permission.
 *
 * This software was created with support from Northeastern 
 * University and from NSF grant DUE-9950829.
 */

package edu.neu.ccs.gui;

import edu.neu.ccs.util.*;

import java.awt.*;
import javax.swing.*;

/**
 * <p>Class <code>DirectApplet</code> provides a base class
 * for building an applet simply.  The designer must build
 * a derived class with one method:</p>
 * 
 * <pre>    public Object createGUI()</pre>
 * 
 * <p>The object returned by this method should either be a
 * <code>Component</code> or be capable of being converted
 * to such using <code>ComponentFactory.makeComponent</code>.
 * If so, the component will be the content of this applet. 
 * If not, an exception will be thrown and displayed in a
 * dialog.</p>
 * 
 * <p>The derived class may, of course, have additional
 * helper data and/or methods.</p>
 * 
 * <p>As of 2.6.0f, <code>DirectApplet</code> will add itself
 * to the count of open frame objects maintained by the
 * <code>JPTFrame</code> class.  The rationale for this
 * is discussed in the comments for <code>JPTFrame</code>.</p>
 * 
 * <p>As of 2.6.0g, <code>setSize</code> is called in the
 * built-in <code>init</code> method based on the size of
 * the component returned by <code>createGUI</code>.</p>
 * 
 * @author  Richard Rasala
 * @version 2.6.0g
 * @since   2.6.0
 */
public abstract class DirectApplet
    extends JApplet
{
    /**
     * Was the initialization by <code>createGUI</code>
     * successful?
     */
    protected boolean initializationSuccessful = false;
    
    
    /**
     * The component returned by <code>createGUI</code>
     * if the initialization call was successful.
     */
    protected Component component = null;
    
    
    /**
     * <p>The object returned by this method should either be a
     * <code>Component</code> or be capable of being converted
     * to such using <code>ComponentFactory.makeComponent</code>.
     * If so, the component will be the content of this applet. 
     * If not, an exception will be thrown and displayed in a
     * dialog.</p>
     * 
     * <p>This method must be instantiated in a derived class.</p>
     */
    public abstract Object createGUI();
    
    
    /**
     * <p>The standard init method for DirectApplet.</p>
     * 
     * <p>Executes a job on the event-dispatching thread to
     * create this applet's GUI.</p>
     * 
     * <p>If successful, increments the count of open frames
     * and applets maintained by <code>JPTFrame</code>.</p>
     */
    public final void init() {
        // Execute a job on the event-dispatching thread to
        // create this applet's GUI
        try {
            javax.swing.SwingUtilities.invokeAndWait(
                new Runnable() {
                    public void run() {
                        createAppletGUI();
                    }
                });
        }
        catch (Throwable t) {
            // Exceptions will be caught in createAppletGUI
        }
    }
    
    
    /**
     * <p>The default destroy method decrements the count of open
     * frames and applets maintained by <code>JPTFrame</code>.</p>
     * 
     * <p>If this method is overridden, the override method must
     * make the following call at its end:</p>
     * 
     * <pre>    super.destroy();</pre>
     */
    public void destroy() {
        if (initializationSuccessful)
            JPTFrame.decrementCounter();
    }
    
    
    /**
     * The standard createAppletGUI method for DirectApplet
     */
    private final void createAppletGUI() {
        Container pane = getContentPane();
        pane.setLayout(new CenterLayout());
        
        String message = "";
        
        try {
            Object object = createGUI();
            
            if (object == null) {
                message = "\nNull object returned from createGUI\n";
                
                throw new RuntimeException(message);
            }
            
            component =
                ComponentFactory.makeComponent(object);
            
            if (component == null) {
                message = "\nObject returned from createGUI\n" +
                    "is not a Component\n" +
                    "and cannot be converted to one\n\n" +
                    "class = " + object.getClass() + "\n";
                
                throw new RuntimeException(message);
            }
            
            pane.add(component);
            
            if (component instanceof JComponent) {
                JComponent c = (JComponent) component;
                
                setSize(c.getPreferredSize());
            }
            else {
                setSize(component.getSize());
            }
            
            initializationSuccessful = true;
            JPTFrame.incrementCounter();
        }
        catch (Throwable t) {
            String trace = StackTrace.getTrace(t);
            StringViewer.showStringInDialog(trace);
            return;
        }
    }
    
}

