package de.duehl.swing.ui.error;

/*
 * Copyright 2016 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;

import de.duehl.swing.ui.GuiTools;
import de.duehl.basics.logging.FileLogger;
import de.duehl.basics.logging.Logger;

/**
 * Diese Klasse testet den Fehlerdialog, den viele andere Klassen verwenden.
 *
 * @version 1.01     2016-03-14
 * @author Christian Dühl
 */

public class ErrorDialogSwingTest {

    /** Startpunkt des Programms. */
    public static void main(String[] args) {
        new ErrorDialogSwingTest();
    }

    /** Der Hauptframe des Testprogramms. */
    private JFrame frame;

    /** Der verwendete Logger, um Fehlerdialoge mit Logger zu testen. */
    private Logger logger;

    /** Konstruktor. */
    public ErrorDialogSwingTest() {
        logger = FileLogger.create("ErrorDialogTest", ".log", "c:/temp");
        logger.log("Start");

        createGui();
        frame.setVisible(true);
    }

    /** Erstellt die Oberfläche. */
    private void createGui() {
        frame = new JFrame();
        frame.setPreferredSize(new Dimension(800, 600));
        frame.setTitle("Testprogramm für die Fehler.");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        logger.log("Frame created");

        GuiTools.setNiceLayoutManager();

        frame.add(createQuitButton(), BorderLayout.SOUTH);
        frame.add(createLookAndFeel(), BorderLayout.NORTH);
        frame.add(createErrorButtons(), BorderLayout.CENTER);

        frame.pack();
        logger.log("Frame packed");
    }

    /** Erzeugt den Button zum Beenden des Programms. */
    private Component createQuitButton() {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        logger.log("QuitButton-Panel created");

        JButton quitButton = new JButton("Beenden");
        quitButton.setFocusable(false);
        quitButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                quit();
            }
        });
        panel.add(quitButton, BorderLayout.EAST);

        return panel;
    }

    /** Beendet die Gui. */
    public void quit() {
        frame.setVisible(false);
        frame.dispose();
    }

    /** Erstellt den Oberen Teil zur Auswahl des LookAndFeels. */
    private Component createLookAndFeel() {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        GuiTools.createTitle(panel);
        logger.log("LookAndFeel-Panel created");

        {
            JPanel actualPanel = new JPanel();
            panel.setLayout(new BorderLayout());

            JLabel titleLabel = new JLabel("Aktuelles Layout:");
            titleLabel.setBorder(new EmptyBorder(5, 15, 5, 15));
            actualPanel.add(titleLabel, BorderLayout.WEST);

            LookAndFeel actualLookAndFeel = UIManager.getLookAndFeel();
            JLabel actualLaFLabel = new JLabel(actualLookAndFeel.toString());
            actualLaFLabel.setBorder(new EmptyBorder(20, 10, 20, 10));
            actualPanel.add(actualLaFLabel, BorderLayout.CENTER);

            panel.add(actualPanel, BorderLayout.NORTH);
        }

        {
            List<String> lookAndFeelNames = new ArrayList<>();
            lookAndFeelNames.add("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
            //lookAndFeelNames.add("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
            lookAndFeelNames.add("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
            lookAndFeelNames.add("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
            lookAndFeelNames.add("javax.swing.plaf.metal.MetalLookAndFeel");

            final JComboBox<String> box = new JComboBox<>();
            for (String lookAndFeelName : lookAndFeelNames) {
                box.addItem(lookAndFeelName);
            }
            //box.setBorder(new EmptyBorder(20, 10, 20, 10));
            box.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent event) {
                    System.out.println("EVENT: " + event);
                    String lookAndFeelName = (String) box.getSelectedItem();
                    setLookAndFeel(lookAndFeelName);
                }
            });

            panel.add(box, BorderLayout.CENTER);
        }

        return panel;
    }

    /** Setzt das Look & Feel. */
    private void setLookAndFeel(String lookAndFeelName) {
        try {
            UIManager.setLookAndFeel(lookAndFeelName);
            //frame.validate();
            //frame.revalidate();
            //frame.repaint();
            SwingUtilities.updateComponentTreeUI(frame);
            frame.pack();
        }
        catch (Exception exception) {
            ErrorDialog dialog = new ErrorDialog("Es ist ein Fehler beim "
                    + "Setzen des Look & Feels aufgetreten:\n\t"
                    + lookAndFeelName, exception, frame.getForeground(),
                    frame.getBackground(), frame.getLocation());
            dialog.setVisible(true);
        }
    }

    /** Erzeugt den mittleren Bereich mit den Test-Buttons. */
    private Component createErrorButtons() {
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(0, 1, 10, 10));
        GuiTools.createTitle(panel);
        logger.log("ErrorButtons-Panel created");

        {
            JButton errorButton = new JButton("Fehler ohne Exception auslösen");
            panel.add(errorButton);
            errorButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    logger.log("Es wurde auf den ersten Button geklickt.");
                    errorWithoutException();
                }
            });
        }

        {
            JButton errorButton = new JButton("Fehler mit Exception auslösen");
            panel.add(errorButton);
            errorButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    logger.log("Es wurde auf den zweiten Button geklickt.");
                    errorWithException();
                }
            });
        }

        {
            JButton errorButton = new JButton(
                    "Fehler mit Exception und langem Text auslösen");
            panel.add(errorButton);
            errorButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    logger.log("Es wurde auf den zweiten Button geklickt.");
                    errorWithLongTextException();
                }
            });
        }

        {
            JButton errorButton = new JButton("Fehler ohne Exception mit "
                    + "Logger auslösen");
            panel.add(errorButton);
            errorButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    logger.log("Es wurde auf den dritten Button geklickt.");
                    errorWithoutExceptionWithLogger();
                }
            });
        }

        {
            JButton errorButton4 = new JButton("Fehler mit Exception mit "
                    + "Logger auslösen");
            panel.add(errorButton4);
            errorButton4.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    logger.log("Es wurde auf den vierten Button geklickt.");
                    errorWithExceptionWithLogger();
                }
            });
        }

        {
            JButton errorButton5 = new JButton("Fehler mit Exception mit "
                    + "Logger und kurzem Log (Zeile 3) auslösen");
            panel.add(errorButton5);
            errorButton5.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    logger.log("Es wurde auf den fünften Button geklickt.");
                    errorWithExceptionWithLoggerShortLogfile();
                }
            });
        }

        {
            JButton errorButton5 = new JButton("Fehler mit Exception mit "
                    + "mehreren Caused By Exceptions auslösen");
            panel.add(errorButton5);
            errorButton5.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    logger.log("Es wurde auf den sechsten Button geklickt.");
                    errorWithDeepCausedBy();
                }
            });
        }


        return panel;
    }

    /** Erzeugt einen Fehler ohne Exception und Logger. */
    private void errorWithoutException() {
        ErrorDialog dialog = new ErrorDialog("Es ist ein Fehler aufgetreten "
                + "mit einem sehr langen Beschreibungstext um mal zu "
                + "sehen, wie das dann so aussieht und was der "
                + "Dialog daraus macht.", Color.BLACK, Color.WHITE, frame.getLocation());
        dialog.setVisible(true);
    }

    /** Erzeugt einen Fehler mit Exception und ohne Logger. */
    private void errorWithException() {
        try {
            throw new Exception("Oh oh oh!");
        }
        catch (Exception exception) {
            ErrorDialog dialog = new ErrorDialog(
                    "Es ist ein Fehler aufgetreten", exception, Color.YELLOW,
                    Color.DARK_GRAY, frame.getLocation());
            dialog.setVisible(true);
        }
    }

    /**
     * Erzeugt einen Fehler mit langem Fehlertext (mehrzeilig) mit Exception und
     * ohne Logger.
     */
    private void errorWithLongTextException() {
        try {
            throw new Exception("Oh oh oh!\n\tOb das wohl vernünftig "
                    + "aussieht?\n\tWir werden sehen!\n\t"
                    + "Ich befürchte das Schlimmste!");
        }
        catch (Exception exception) {
            ErrorDialog dialog = new ErrorDialog(
                    "Es ist ein Fehler aufgetreten\n"
                            + "\tPunkt 1: foo\n"
                            + "\tPunkt 2: bar\n"
                            + "\tPunkt 3: baz\n"
                            + "\tPunkt 4: foo bar\n"
                            + "\tPunkt 5: foo baz\n"
                            + "\tPunkt 6: foo bar baz\n"
                            + "\tPunkt 7: Hühnerkram\n"
                            + "\tPunkt 8: Umlaute äöüßÄÖÜ\n",
                    exception, frame.getLocation());
            dialog.setVisible(true);
        }
    }

    /** Erzeugt einen Fehler ohne Exception und mit Logger. */
    private void errorWithoutExceptionWithLogger() {
        ErrorDialog dialog = new ErrorDialog("Es ist ein Fehler aufgetreten",
                null, logger.getLogFileName(), Color.GREEN, Color.BLUE, frame.getLocation());
        dialog.setVisible(true);
    }

    /** Erzeugt einen Fehler mit Exception und mit Logger. */
    private void errorWithExceptionWithLogger() {
        try {
            throw new Exception("Oh weh, oh weh!");
        }
        catch (Exception exception) {
            ErrorDialog dialog = new ErrorDialog(
                    "Es ist ein Fehler aufgetreten", exception, null,
                    logger.getLogFileName(), Color.DARK_GRAY, Color.YELLOW,
                    frame.getLocation());
            dialog.setVisible(true);
        }
    }

    /**
     * Erzeugt einen Fehler mit Exception und mit Logger. Unterschied zu
     * errorWithExceptionWithLogger ist mir nicht klar.
     */
    private void errorWithExceptionWithLoggerShortLogfile() {
        try {
            throw new Exception("Oh weh, oh weh eine Ausnnahme!");
        }
        catch (Exception exception) {
            ErrorDialog dialog = new ErrorDialog(
                    "Es ist ein Fehler aufgetreten", exception, null,
                    logger.getLogFileName(), Color.DARK_GRAY, Color.YELLOW,
                    frame.getLocation(), 3);
            dialog.setVisible(true);
        }
    }

    /** Erzeugt einen Fehler mit Exception mit mehreren Caused By. */
    private void errorWithDeepCausedBy() {
        try {
            try {
                try {
                    try {
                        try {
                            throw new RuntimeException("Erster aufgetretener Fehler.");
                        }
                        catch (Exception e) {
                            throw new RuntimeException("Zweiter aufgetretener Fehler.", e);
                        }
                    }
                    catch (Exception e) {
                        throw new RuntimeException("Dritter aufgetretener Fehler.", e);
                    }
                }
                catch (Exception e) {
                    throw new RuntimeException("Vierter aufgetretener Fehler.", e);
                }
            }
            catch (Exception e) {
                throw new RuntimeException("Fünfter aufgetretener Fehler.", e);
            }
        }
        catch (Exception exception) {
            ErrorDialog dialog = new ErrorDialog("Es ist ein Fehler aufgetreten", exception,
                    frame.getLocation());
            dialog.setVisible(true);
        }
    }

}
