package usda.weru.util;

import java.io.PrintWriter;
import java.io.StringWriter;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; 
import usda.weru.remoteDataAccess.exceptions.BackgroundLoadException;
import usda.weru.remoteDataAccess.exceptions.BackgroundLoadException.BackgroundLoadExceptionType;
import usda.weru.weps.Weps;
import usda.weru.weps.wepsRunControl.WrcException;

/**
 *
 * @author Joseph Levin <joelevin@weru.ksu.edu>
 */
public class WepsExceptionHandler implements Thread.UncaughtExceptionHandler {

    Weps source;
    
    public WepsExceptionHandler(Weps w)
    {
        source = w;
    }
    
    /**
     *
     * @param t
     * @param e
     */
    @Override
    public void uncaughtException(Thread t, final Throwable e) {

        //Log the exception
        Logger logger;
        StackTraceElement[] trace = e.getStackTrace();
        if (trace.length > 0) {
            StackTraceElement topOfTheStack = trace[0];
            logger = LogManager.getLogger(topOfTheStack.getClassName());
        } else {
            logger = LogManager.getLogger(WepsExceptionHandler.class);
        }

        if (e.getCause() != null && e.getCause().getCause() != null) {
            Throwable ee = e.getCause();
            
            if (ee instanceof BackgroundLoadException) {
                if (Weps.getInstance().getCsipInputController().getDownloadingCount() > 0) {
                    Weps.getInstance().getCsipInputController().clearProgress();
                    if (((BackgroundLoadException)ee).getType() == BackgroundLoadExceptionType.CONNECTION) {
                        JOptionPane.showMessageDialog(Weps.getInstance(), 
                                "Could not connect to server.\n"+
                                "Some elements will be disabled until WEPS is restarted\n"+
                                "and the background process can complete.", 
                                "Background load failure", JOptionPane.ERROR_MESSAGE);
                    } else {
                        JOptionPane.showMessageDialog(Weps.getInstance(), "Unknown server error", "Background load failure", JOptionPane.ERROR_MESSAGE);
                    }
                }
                return;
            }
            
            ee = ee.getCause();
            if (ee instanceof WrcException) {
                if (!((WrcException)ee).getFatal()) {
                    return;
                }
            }
        }        
        
        if (e instanceof OutOfMemoryError) {
            Util.logMemoryUsage();
            logger.warn("Out of memory.  Running garbage collector and attempting to recover.");
            Runtime.getRuntime().gc();
            Thread.yield();
            return;
        } else {
            logger.error("Unexpected Error", e);
        }

        Runnable task = new Runnable() {

            @Override
            public void run() {
                int report = JOptionPane.showConfirmDialog(null,
                        "An unexpected error was detected.\nWould you like to submit a bug report?",
                        "Unexpected Error", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE);
                if (JOptionPane.YES_OPTION == report) {
                    //fill in the message with the stacktrace
                    StringWriter buffer = new StringWriter();
                    e.printStackTrace(new PrintWriter(buffer));
                    Mantis.message("Unexpected " + e.getClass().getSimpleName(), e.getMessage()
                            + "\n" + buffer.toString(), source.getExceptionPackage());
                }
            }
        };

        //Dispatch to the swing thread for handling the error reporting.
        if (!SwingUtilities.isEventDispatchThread()) {
            SwingUtilities.invokeLater(task);
        } else {
            task.run();
        }
    }
}
