package org.jboss.installer.common;

import org.jboss.installer.Installer;
import org.jboss.installer.core.LanguageUtils;
import org.jboss.installer.dialogs.downloader.DownloadDisplayPanel;
import org.jboss.installer.screens.DefaultScreen;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.border.EmptyBorder;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.List;

public class InstallerDialogs {

    public static final String ERROR_TITLE_KEY = "generic.error.title";
    public static final int DIALOG_TEXT_MAX_WIDTH = DefaultScreen.FRAME_WIDTH - 200;
    private static final String WARNING_TITLE_KEY = "generic.warning.title";

    public static final String MESSAGE_KEY = "generic.message.title";
    private static final String GENERIC_OK = "generic.ok";
    private static final String GENERIC_YES = "generic.yes";
    private static final String GENERIC_NO = "generic.no";
    private static final String GENERIC_DOWNLOAD_TITLE = "generic.download.title";
    public static final String DOWNLOAD_UNREACHABLE = "generic.download.unreachable_file";

    public static void showErrorMessage(String text, LanguageUtils langUtils, Component parent) {
        final JComponent ta = wrapText(List.of(text));
        Object[] options = new Object[]{langUtils.getString(GENERIC_OK)};
        JOptionPane.showOptionDialog(parent, ta,
                langUtils.getString(ERROR_TITLE_KEY), JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE,
                null, options, options[0]);
    }

    public static int showWarningMessage(List<String> messages, LanguageUtils langUtils, Component parent) {
        final JComponent ta = wrapText(messages);
        Object[] options = new Object[]{langUtils.getString(GENERIC_YES), langUtils.getString(GENERIC_NO)};
        return JOptionPane.showOptionDialog(parent, ta,
                langUtils.getString(WARNING_TITLE_KEY), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
                null, options, options[1]);
    }

    public static int showWarningMessage(String text, LanguageUtils langUtils, Component parent) {
        return showWarningMessage(List.of(text), langUtils, parent);
    }

    public static void showInfoMessage(String text, LanguageUtils langUtils, Component parent) {
        final JComponent ta = wrapText(List.of(text));
        Object[] options = new Object[]{langUtils.getString(GENERIC_OK)};
        JOptionPane.showOptionDialog(parent, ta,
                langUtils.getString(MESSAGE_KEY), JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE,
                null, options, options[0]);
    }

    public static boolean showQuestionMessage(String text, Object[] options, Component parent) {
        final JComponent ta = wrapText(List.of(text));
        return JOptionPane.showOptionDialog(parent, ta,
                Installer.getInstallerFrameTitle(), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
                null, options, options[1]) == JOptionPane.YES_OPTION;
    }

    public static boolean showDownloadMessage(Component parent, DownloadDisplayPanel panel, LanguageUtils langUtils) {
        return JOptionPane.showOptionDialog(parent, panel, langUtils.getString(GENERIC_DOWNLOAD_TITLE), JOptionPane.OK_CANCEL_OPTION,
                JOptionPane.PLAIN_MESSAGE, null, panel.getButtons(), panel.getOKButton()) == JOptionPane.OK_OPTION;
    }

    // wrap the text in TextArea to make it possible to copy/paste the content
    private static JComponent wrapText(List<String> messages) {
        final JTextPane ta = new JTextPane();
        ta.setEditable(false);
        // use the html to wrap wrong messages
        ta.setContentType("text/html");
        final String text;
        if (messages.size() == 1) {
            text = "<p style='width:400px; margin-top:0'>" +
                    messages.get(0).replaceAll("\\n", "<br/>") +
                    "</p>";
        } else {
            final StringBuilder sb = new StringBuilder("<ul style=\"margin-top:0;margin-bottom:0\">");
            for (String msg : messages) {
                sb.append("<li><p style='width:400px; margin-top:0;'>")
                        .append(msg.replaceAll("\\n", "<br/>"))
                        .append("</p></li>");
            }
            sb.append("</ul>");
            text = sb.toString();
        }
        ta.setText("<html><body>" + text + "</body></html>");
        ta.setBackground(Color.WHITE);
        disableFocusCycle(ta);
        JScrollPane scrollPane = new JScrollPane(ta);
        scrollPane.setBorder(new EmptyBorder(0,0,0,0));
        // swing ignores setMaxSize, so we need to do some resizing for long messages
        scrollPane.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                final Dimension d = e.getComponent().getSize();
                // if the new size exceeds the max, force max size. Have to repeat it for parent OptionPane to resize it as well
                if (d.getHeight() > 600) {
                    e.getComponent().setSize(new Dimension((int)d.getWidth(), 600));
                    e.getComponent().setPreferredSize(new Dimension((int)d.getWidth(), 600));

                    // find root of the option pane
                    Component pane = e.getComponent();
                    while (pane.getParent() != null && !(pane.getParent() instanceof JFrame)) {
                        pane = pane.getParent();
                    }
                    pane.setSize(new Dimension((int)pane.getSize().getWidth() + 50, 650));
                    pane.setPreferredSize(new Dimension((int)pane.getSize().getWidth() + 50, 650));
                }
            }
        });
        return scrollPane;
    }

    private static void disableFocusCycle(JTextPane ta) {
        // make the text area not focusable to remove it from TAB focus cycle
        ta.setFocusable(false);

        // but when a mouse enters the area, make it possible to select the text
        // ideally would mark as non-focusable on leaving, but that removes the text selection
        ta.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                ta.setFocusable(true);
            }
        });

        // so when focus is lost, mark it as unfocusable
        ta.addFocusListener(new FocusListener() {
            @Override
            public void focusLost(FocusEvent e) {
                ta.setFocusable(false);
            }

            @Override
            public void focusGained(FocusEvent e) {
            }
        });
    }
}
