/*
 * @(#)ErrorDialog.java    1.0.1  29 September 2004
 *
 * Copyright 2004
 * 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 publication 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.*;
import edu.neu.ccs.filter.*;
import edu.neu.ccs.util.*;
import java.awt.*;
import java.text.ParseException;
import javax.swing.*;
import javax.swing.text.*;

/**
 * <P>A modal dialog box for input of 
 * <CODE>{@link Stringable Stringable}</CODE> objects 
 * that is used by the standard error handling strategy
 * for <CODE>Fragile</CODE> components in the JPT.</P>
 *
 * @author  Jeff Raab
 * @version 2.2
 * @since   1.0
 * @see Fragile
 * @see TextFieldView
 * @see TextAreaView
 */
public class ErrorDialog extends InputDialog {
    
    /** 
     * Annotation used to display the error message 
     * of exception that initiated the error recovery strategy.
     */
    protected Annotation errorMessage = null;

    /** Original malformed view state for the input component. */
    protected String originalValue = null;
    
    /** 
     * Filter used by the input component
     * that generated the exception
     * that initiated the error recovery strategy. 
     */
    protected StringableFilter filter = null;
    
    //////////////////
    // Constructors //
    //////////////////

    /**
     * <P>Constructs a modal dialog for error recovery
     * initiated by the given input component
     * when trying to set the state of the given model object.
     *
     * If the input operation is mandatory,
     * the dialog persists until valid input is provided
     * and cannot be disposed by the user.</P>
     *
     * @param modelObject the <CODE>Stringable</CODE> object 
     *      to be set from the view state of the input component
     * @param viewObject the graphical interface object 
     *      to use for input of the model object
     * @param filterObject the input filter used by the view object
     * @param exception the parse exception 
     *      that initiated the error recovery strategy
     * @throws NullPointerException if any of the given parameters
     *      is <CODE>null</CODE>
     */
     public ErrorDialog(
        Stringable modelObject, 
        TypedView viewObject,
        StringableFilter filterObject, 
        ParseException exception) {

        // build the input dialog
        super(viewObject);
        
        // test for null parameters
        if ((modelObject == null) ||
            (viewObject == null) ||
            (exception == null))
        {
            throw new NullPointerException(
                "Null parameter in constructor.");
        }

        // store parameters
        model = modelObject;
        filter = filterObject;
        originalValue = view.getViewState();

        // show the initial error message
        errorMessage = new Annotation(
            XObject.formatErrorMessage(
                exception, 
                view.getViewState()));
        
        // find a good font size to use for the message
        int size = new JLabel("0").getFont().getSize() + 2;
        
        errorMessage.setFont(new Font("monospaced", Font.BOLD, size));
        getContentPane().add(errorMessage, BorderLayout.NORTH);
        
        // size appropriately and center on screen
        pack();
        center();
    }

    ///////////////////////
    // Protected methods //
    ///////////////////////
    
    /**
     * Attempts to set the state of the model object 
     * from the view state of the input object, 
     * and if successful, disposes of the dialog.
     */
    protected void ok() {
        
        // try to set the state of the model object 
        try {
        
            // check that a number is in range
            try {
                model.fromStringData(view.getViewState());

                // apply filter
                if (filter != null) {
                    try {
                        model = filter.filterStringable(model);
                    }
                    catch (FilterException ex) {
        
                        // translate filter exception to a
                        // parse exception in this case
                        throw new ParseException(
                            ex.getMessage(), -1);
                    }
                }
            }

            // translate number format exception to a
            // parse exception
            catch (NumberFormatException ex) {
                throw new ParseException(
                    ex.getMessage(), -1);
            }

            // close the dialog
            setVisible(false);
            dispose();
        }
        
        // handle another error if encountered
        catch (ParseException ex) {
            
            // show the new error message
            errorMessage.setText(
                XObject.formatErrorMessage(ex, view.getViewState()));
          
            // size appropriately and center on screen
            pack();
            center();
        }
    }

    /**
     * Resets the view state of the view object 
     * to the original erroneous view state.
     */
    protected void reset() {
        view.setViewState(originalValue);
    }
    
    /**
     * Resets the view state of the view object 
     * to the original erroneous view state
     * and then closes the dialog, 
     * noting that the dialog was dismissed by cancellation.
     *
     * @see InputDialog#wasCancelled()
     */
    protected void cancel() {
        reset();
        super.cancel();
    }
}

