/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.ctecinf.swing;

import br.com.ctecinf.Log;
import br.com.ctecinf.Utils;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.util.Calendar;
import java.util.Locale;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.text.DefaultFormatterFactory;

/**
 *
 * @author Cássio Conceição
 * @since 19/09/2018
 * @version 201809
 * @see http://ctecinf.com.br
 */
public class OptionPane {

    public static boolean confirm(Object message) {
        return confirm(null, message, "Confirmar");
    }

    public static boolean confirm(Component parent, Object message) {
        return confirm(parent, message, "Confirmar");
    }

    public static boolean confirm(Component parent, Object message, String title) {
        String[] buttons = {"Sim", "Não"};
        return JOptionPane.showOptionDialog(parent, message, title, JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE, new ImageIcon(), buttons, buttons[0]) == 0;
    }

    public static void success(String message) {
        success(null, message, "Sucesso");
    }

    public static void success(Component parent, String message) {
        success(parent, message, "Sucesso");
    }

    public static void success(Component parent, String message, String title) {
        JOptionPane.showMessageDialog(parent, message, title, JOptionPane.QUESTION_MESSAGE, Image.parse(Image.SUCCESS));
    }

    public static void alert(String message) {
        alert(null, message, "Alerta");
    }

    public static void alert(Component component, String message) {
        alert(component, message, "Alerta");
    }

    public static void alert(Component component, String message, String title) {
        JOptionPane.showMessageDialog(component, message, title, JOptionPane.WARNING_MESSAGE);
    }

    public static void info(Object message) {
        info(null, message, "Informação");
    }

    public static void info(Component component, Object message) {
        info(component, message, "Informação");
    }

    public static void info(Component component, Object message, String title) {
        JOptionPane.showMessageDialog(component, message, title, JOptionPane.INFORMATION_MESSAGE);
    }

    public static void error(Object message) {
        error(null, message, "Erro");
    }

    public static void error(Component component, Object message) {
        error(component, message, "Erro");
    }

    public static void error(Component component, Object message, String title) {

        if (message instanceof Exception) {

            String msg = ((Exception) message).getLocalizedMessage() + "\n\n\n";

            for (StackTraceElement stack : ((Exception) message).getStackTrace()) {
                if (stack.getClassName().contains("ctecinf") && !stack.getClassName().contains("$")) {
                    msg += stack.getClassName() + " (" + stack.getLineNumber() + "): " + stack.getMethodName();
                    break;
                }
            }

            JOptionPane.showMessageDialog(component, msg, title, JOptionPane.ERROR_MESSAGE);

        } else {
            JOptionPane.showMessageDialog(component, message, title, JOptionPane.ERROR_MESSAGE);
        }

        Log.create(message);
    }

    public static void show(Component component) {
        OptionPane.show(component, 800, 600);
    }

    public static void show(Component component, int width, int height) {

        JPanel panel = new JPanel(new BorderLayout());
        panel.setPreferredSize(new Dimension(width, height));
        panel.add(new JScrollPane(component));

        JOptionPane.showMessageDialog(null, panel, "", JOptionPane.PLAIN_MESSAGE);
    }

    /**
     * Seleciona um arquivo
     *
     * @param filter Exemplo: new FileNameExtensionFilter("Arquivo SQL", "sql")
     *
     * @return java.io.File
     */
    public static File chooseFile(FileNameExtensionFilter... filter) {
        return chooseFile("Selecione um arquivo", filter);
    }

    /**
     * Seleciona um arquivo
     *
     * @param title
     * @param filter Exemplo: new FileNameExtensionFilter("Arquivo SQL", "sql");
     * @return
     */
    public static File chooseFile(String title, FileNameExtensionFilter... filter) {

        JFileChooser chooser = new JFileChooser(new File(System.getProperty("user.home")));
        chooser.setDialogTitle(title);
        chooser.setApproveButtonText("Selecionar");
        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);

        if (filter != null) {
            for (FileNameExtensionFilter f : filter) {
                chooser.setFileFilter(f);
            }
        }

        if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
            return chooser.getSelectedFile();
        }

        return null;
    }

    /**
     * Seleciona um diretorio
     *
     * @return java.io.File
     */
    public static File chooseDirectory() {
        return chooseDirectory("Selecione um diretório");
    }

    /**
     * Seleciona um diretorio
     *
     * @param title
     * @return java.io.File
     */
    public static File chooseDirectory(String title) {

        JFileChooser chooser = new JFileChooser(new File(System.getProperty("user.home")));
        chooser.setDialogTitle(title);
        chooser.setApproveButtonText("Selecionar");
        chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

        if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
            return chooser.getSelectedFile();
        }

        return null;
    }

    public static void print(Printable printable) {

        PrinterJob pj = PrinterJob.getPrinterJob();
        pj.setPrintable(printable);

        if (pj.printDialog()) {

            try {
                pj.print();
            } catch (PrinterException ex) {
                error(ex);
            }
        }
    }

    public static final <T> T input(String title, T value, JFormattedTextField.AbstractFormatter formatter) {
        return input(null, title, value, formatter);
    }

    public static final <T> T input(Component parent, String title, T value, JFormattedTextField.AbstractFormatter formatter) {

        final JFormattedTextField input = new JFormattedTextField();
        input.setFont(input.getFont().deriveFont(18f));

        String[] buttons = {"Confirmar", "Cancelar"};

        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(null, title, TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, input.getFont().deriveFont(Font.BOLD)), BorderFactory.createEmptyBorder(0, 0, 0, 0)));

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.fill = GridBagConstraints.BOTH;
        gbc.gridwidth = GridBagConstraints.BOTH;
        gbc.weightx = GridBagConstraints.BOTH;

        panel.add(input, gbc);

        final JOptionPane pane = new JOptionPane(panel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_OPTION, null, buttons, buttons[0]);

        if (formatter != null) {
            input.setFormatterFactory(new DefaultFormatterFactory(formatter));
        }

        input.addFocusListener(new FocusAdapter() {
            @Override
            public void focusGained(FocusEvent e) {
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        input.selectAll();
                    }
                });
            }
        });

        input.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    pane.setValue("Confirmar");
                }
            }
        });

        input.setColumns(30);
        input.setValue(value);

        JDialog dialog = pane.createDialog(parent, "");
        dialog.setAlwaysOnTop(true);
        dialog.addWindowFocusListener(new WindowAdapter() {
            @Override
            public void windowGainedFocus(WindowEvent e) {
                input.requestFocus();
            }
        });
        dialog.pack();
        dialog.setLocationRelativeTo(null);
        dialog.setVisible(true);
        dialog.dispose();

        if (pane.getValue() != null && pane.getValue().equals("Confirmar")) {
            return formatter != null ? (T) input.getValue() : (input.getText().isEmpty() ? null : (T) input.getText());
        }

        return null;
    }

    public static final <T> T choice(String title, Object[] choices) {
        return choice(null, title, choices);
    }

    public static final <T> T choice(Component parent, String title, Object[] choices) {

        if (choices.length == 0) {
            return null;
        }

        final JList choice = new JList(choices);

        choice.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        choice.setVisibleRowCount(8);
        choice.setFont(choice.getFont().deriveFont(Font.PLAIN, 18f));
        choice.setSelectedIndex(0);

        JLabel label = new JLabel(title);
        label.setFont(label.getFont().deriveFont(Font.BOLD, 18f));

        JPanel panel = new JPanel(new BorderLayout(10, 10));
        panel.add(label, BorderLayout.NORTH);
        panel.add(new JScrollPane(choice), BorderLayout.CENTER);

        String[] buttons = {"Confirmar", "Cancelar"};

        final JOptionPane pane = new JOptionPane(panel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_OPTION, null, buttons, buttons[0]);

        choice.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 2) {
                    pane.setValue("Confirmar");
                }
            }
        });

        JDialog dialog = pane.createDialog(parent, "");
        dialog.setAlwaysOnTop(true);
        dialog.addWindowFocusListener(new WindowAdapter() {
            @Override
            public void windowGainedFocus(WindowEvent e) {
                choice.requestFocus();
            }
        });
        dialog.pack();
        dialog.setLocationRelativeTo(null);
        dialog.setVisible(true);
        dialog.dispose();

        if (pane.getValue() != null && pane.getValue().equals("Confirmar")) {
            return (choice.getSelectedValue() == null ? null : (T) choice.getSelectedValue());
        }

        return null;
    }

    /**
     * @param yearInterval Número de anos
     * @return Calendar
     */
    public static Calendar choiceMonth(int yearInterval) {
        return choiceMonth(null, yearInterval);
    }

    /**
     * @param parent
     * @param yearInterval Número de anos
     * @return Calendar
     */
    public static Calendar choiceMonth(Component parent, int yearInterval) {

        Calendar dt = Utils.dateFromServer();

        String[] months = new String[12];
        Locale locale = new Locale("pt", "BR");
        int mNow = dt.get(Calendar.MONTH);
        dt.set(Calendar.DATE, 1);
        for (int i = 0; i < months.length; i++) {
            dt.set(Calendar.MONTH, i);
            months[i] = dt.getDisplayName(Calendar.MONTH, Calendar.LONG, locale);
        }

        final JComboBox inMonths = new JComboBox(months);
        inMonths.setSelectedIndex(mNow);

        Integer[] years = new Integer[yearInterval * 2];
        int year = dt.get(Calendar.YEAR);
        int index = 0;
        for (int i = dt.get(Calendar.YEAR) - yearInterval; i < dt.get(Calendar.YEAR); i++) {
            years[index] = i;
            index++;
        }
        for (int i = dt.get(Calendar.YEAR); i < dt.get(Calendar.YEAR) + yearInterval; i++) {
            years[index] = i;
            index++;
        }

        JComboBox inYears = new JComboBox(years);
        inYears.setSelectedItem(year);

        String[] buttons = {"Confirmar", "Cancelar"};

        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(null, "Selecione o mês e ano", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, panel.getFont().deriveFont(Font.BOLD)), BorderFactory.createEmptyBorder(0, 0, 0, 0)));

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.fill = GridBagConstraints.BOTH;
        gbc.gridwidth = GridBagConstraints.BOTH;
        gbc.weightx = GridBagConstraints.BOTH;

        gbc.gridx = 1;
        panel.add(new JLabel("Mês:"), gbc);

        gbc.gridx = 2;
        panel.add(inMonths, gbc);

        gbc.gridx = 3;
        panel.add(new JLabel("Ano:"), gbc);

        gbc.gridx = 4;
        panel.add(inYears, gbc);

        JOptionPane pane = new JOptionPane(panel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_OPTION, null, buttons, buttons[0]);

        JDialog dialog = pane.createDialog(parent, "Selecione o mês");
        dialog.setAlwaysOnTop(true);
        dialog.addWindowFocusListener(new WindowAdapter() {
            @Override
            public void windowGainedFocus(WindowEvent e) {
                inMonths.requestFocus();
            }
        });
        dialog.setVisible(true);
        dialog.dispose();

        if (pane.getValue() != null && pane.getValue().equals("Confirmar")) {

            dt.set(Calendar.MONTH, inMonths.getSelectedIndex());
            dt.set(Calendar.YEAR, (int) inYears.getSelectedItem());

            return dt;
        }

        return null;
    }

}
