/*
 * Copyright
 *   2007 axYus - www.axyus.com
 *
 * This file is part of XEMELIOS.
 *
 * XEMELIOS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * XEMELIOS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with XEMELIOS; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package fr.gouv.finances.cp.utils.ui;

import java.awt.BorderLayout;
import java.awt.Dialog;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.StringTokenizer;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

import fr.gouv.finances.cp.utils.WordWrap;

/**
 * A dialog to display exceptions. You can use helper-methods
 * {@link #displayException(Dialog,Throwable)} and {@link #displayException(Frame,Throwable)}
 */
public class DisplayExceptionDlg extends JDialog implements ActionListener {
    /**
	 * Comment for <code>serialVersionUID</code>
	 */
	private static final long serialVersionUID = 3979274659365664560L;
//	private Throwable toDisplay = null;
    private JButton pbClose = null;
    private JButton pbHideShow = null;
    private JPanel center = null;
    /**
     * Creates a non-modal dialog without a title with the
     * specified <code>Dialog</code> as its owner.
     * <p>
     * This constructor sets the component's locale property to the value
     * returned by <code>JComponent.getDefaultLocale</code>.
     *
     * @param owner the non-null <code>Dialog</code> from which the dialog is displayed
     * @exception HeadlessException if GraphicsEnvironment.isHeadless()
     * returns true.
     * @see GraphicsEnvironment#isHeadless
     * @see JComponent#getDefaultLocale
     */
    public DisplayExceptionDlg(Dialog owner, Throwable toDisplay) throws HeadlessException {
        super(owner,true);
        initialize(toDisplay);
    }
    public DisplayExceptionDlg(Throwable toDisplay) throws HeadlessException {
    	super();
    	setModal(true);
    	initialize(toDisplay);
    }

    /**
     * Creates a non-modal dialog without a title with the
     * specified <code>Frame</code> as its owner.  If <code>owner</code>
     * is <code>null</code>, a shared, hidden frame will be set as the
     * owner of the dialog.
     * <p>
     * This constructor sets the component's locale property to the value
     * returned by <code>JComponent.getDefaultLocale</code>.
     *
     * @param owner the <code>Frame</code> from which the dialog is displayed
     * @exception HeadlessException if GraphicsEnvironment.isHeadless()
     * returns true.
     * @see GraphicsEnvironment#isHeadless
     * @see JComponent#getDefaultLocale
     */
    public DisplayExceptionDlg(Frame owner,Throwable toDisplay) throws HeadlessException {
        super(owner,"Erreur",true);
        initialize(toDisplay);
    }

    protected void initialize(Throwable toDisplay) {
//        this.toDisplay = toDisplay;
        while(toDisplay.getCause()!=null) toDisplay = toDisplay.getCause();
        JPanel pane = new JPanel(new BorderLayout());
        String[] msg = beautify(toDisplay.getMessage());
        JPanel msgPane = new JPanel(new VerticalFlowLayout());
        for(int i=0;i<msg.length;i++) msgPane.add(new JLabel(msg[i]));
        pane.add(msgPane,BorderLayout.NORTH);
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        while(toDisplay!=null) {
            toDisplay.printStackTrace(pw);
            pw.println("caused by...");
            toDisplay = toDisplay.getCause();
        }
        pw.flush();
        String ex = sw.toString();
        pw.close();
        JTextArea ml = new JTextArea(ex);
        ml.setColumns(60);
        ml.setRows(20);
        center = new JPanel();
        center.add(new JScrollPane(ml));
        pane.add(center,BorderLayout.CENTER);
        center.setVisible(false);
        JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.CENTER));
        buttonPane.add(pbClose=new JButton("Fermer"));
        buttonPane.add(pbHideShow=new JButton("Afficher"));
        pane.add(buttonPane,BorderLayout.SOUTH);
        setContentPane(pane);
        pbClose.addActionListener(this);
        pack();
        setLocationRelativeTo(getOwner());
        pbHideShow.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent e) {
				boolean visible = center.isVisible();
				if(visible) {
					center.setVisible(false);
					pbHideShow.setText("Afficher");
				} else {
					center.setVisible(true);
					pbHideShow.setText("Cacher");
				}
				pack();
			}
		});
        setVisible(true);
    }

    /**
     * Invoked when an action occurs.
     */
    public void actionPerformed(ActionEvent e) {
        dispose();
    }
    
    /**
     * Displays <tt>toDisplay</tt> exception in a EDT-thread-safe way
     * @param owner
     * @param toDisplay
     */
    public static void displayException(Frame owner,Throwable toDisplay) {
        Runnable code = new Displayer(owner,toDisplay);
        if(SwingUtilities.isEventDispatchThread()) code.run();
        else SwingUtilities.invokeLater(code);
    }
    /**
     * Displays <tt>toDisplay</tt> exception in a EDT-thread-safe way
     * @param owner
     * @param toDisplay
     */
    public static void displayException(Dialog owner,Throwable toDisplay) {
        Runnable code = new Displayer(owner,toDisplay);
        if(SwingUtilities.isEventDispatchThread()) code.run();
        else SwingUtilities.invokeLater(code);
    }
    /**
     * Cuts msg at 80chars max per line
     * @param msg
     * @return
     */
    protected static String[] beautify(String msg) {
    	if(msg==null) return new String[0];
    	String s = WordWrap.wrap(msg,80);
    	StringTokenizer st = new StringTokenizer(s,"\n\r\f");
    	String[] ret = new String[st.countTokens()];
    	for(int i=0;i<st.countTokens();i++) ret[i]=st.nextToken();
    	return ret;
    }

    private static class Displayer implements Runnable {
        private Frame fOwner;
        private Dialog dOwner;
        private Throwable t;
        
        public Displayer(Frame owner,Throwable t) {
            super();
            this.fOwner=owner;
            this.t=t;
        }
        public Displayer(Dialog owner,Throwable t) {
            super();
            this.dOwner=owner;
            this.t=t;
        }
        public void run() {
            if(fOwner!=null) new DisplayExceptionDlg(fOwner,t);
            else new DisplayExceptionDlg(dOwner,t);
        }
    }
}
