
package com.basilv.core.richui;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

/**
 * Handles uncaught exceptions by displaying a dialog to the user and logging the exception. 
 */
public class ExceptionHandler {

    /**
     * Register this class as the exception handler to use for the Swing Event Dispatch Thread.
     */
    public static void registerExceptionHandler() {
        // See java.awt.EventDispatchThread.handleException()
        System.setProperty("sun.awt.exception.handler", ExceptionHandler.class.getName());            
    }
    
    /**
     * Create an instance.
     */
    public ExceptionHandler() {
    }

    /**
     * Handle the supplied exception.
     * @param throwable the throwable.
     */ 
	public void handle(Throwable throwable) {
        if (throwable instanceof ThreadDeath) {
            return;
        }
        
        handleThrowable(getVisibleFrame(), 
            "An application error occurred. Please contact application support.", 
            throwable);
    }

    /**
     * Return the visible frame.
     * @return the visible frame.
     */
    private static Frame getVisibleFrame() {
        Frame[] frames = Frame.getFrames();
        for (int i = 0; i < frames.length; i++) {
            Frame frame = frames[i];
            if (frame.isVisible()) {
                return frame;
            }
        }
        return null;
    }

	public static void handleThrowable(String message, Throwable throwable) {
		handleThrowable(null, message, throwable);
	}
    
    /**
     * Handle the specified throwable by displaying the specified message to the
     * user along with details about the throwable and logging the issue.
     * 
     * @param parentOfErrorDialog
     *            Parent component for the error dialog.
     * @param message
     *            A message summarizing the problem.
     * @param throwable
     *            The throwable that caused the problem.
     */
	public static void handleThrowable(Component parentOfErrorDialog, String message, Throwable throwable) {
		Logger.getLogger(ExceptionHandler.class.getName()).log(Level.SEVERE, message, throwable);

		// Display infomation to user in error dialog
		StringWriter stringWriter = new StringWriter();
		PrintWriter writer = new PrintWriter(stringWriter);
		throwable.printStackTrace(writer);
		String stackTraceString = stringWriter.getBuffer().toString();

		// Creating scrolling text area of limited size to
		// display the stack trace in - since it is almost always
		// quite large
		JTextArea textArea = new JTextArea(stackTraceString);
		textArea.setEditable(false);
		JScrollPane scrollingTextArea = new JScrollPane(textArea);

		Dimension currentSize = scrollingTextArea.getPreferredSize();
		final int maxWidth = 450;
		final int maxHeight = 300;
		int width = Math.min(currentSize.width, maxWidth);
		int height = Math.min(currentSize.height, maxHeight);

		scrollingTextArea.setPreferredSize(new Dimension(width, height));

		// Display the error dialog
		Object[] dialogContents = { message, scrollingTextArea };
		JOptionPane.showMessageDialog(parentOfErrorDialog, dialogContents, "Error", JOptionPane.ERROR_MESSAGE);
	}

}
