package org.limewire.ui.swing.components;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.HeadlessException;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.Window;
import java.util.ArrayList;
import java.util.List;

import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.UIManager;

import org.limewire.ui.swing.util.GuiUtils;
import org.limewire.ui.swing.util.I18n;


/**
 * A simple wrapper around {@link JOptionPane} methods that
 * forces the parent component to be a visible frame,
 * allowing it to blink in the task bar.
 */
public class FocusJOptionPane {
    
    /**
     * Contains a string representation of the text of all of the currently 
     * visible message dialogs. Presently this is only applicable to dialogs
     * displayed via showMessageDialog.
     */
    private static final List<String> visibleDialogs = new ArrayList<String>();
    
    public static Component createFocusComponent() {
        JFrame frame = new LimeJFrame("WireShare");
        frame.setUndecorated(true);
        frame.setSize(0, 0);
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        frame.setLocation(screenSize.width / 2, screenSize.height / 2);
        frame.setVisible(true);
        return frame;
     }
    
    /**
     * @see JOptionPane#showMessageDialog(Component, Object, String, int)
     */
    public static void showMessageDialog(Component parentComponent, Object message, String title,
            int messageType) throws HeadlessException {
        String messageString = message.toString();
        // if the message text is already present in a visible message dialog,
        // then we needn't show it again. just ignore it and return.
        //
        // later, when the dialog is closed, we'll remove its text from this
        // list.
        if (visibleDialogs.contains(messageString))
            return;
            
        visibleDialogs.add(messageString);
        
        boolean dispose = false;
        parentComponent = getWindowForComponent(parentComponent);
        if(parentComponent == null) {
            parentComponent = createFocusComponent();
            dispose = true;
        }
        
        Color oldOptionColor = UIManager.getColor("OptionPane.background");
        Color oldPanelColor = UIManager.getColor("Panel.background");
        if(GuiUtils.getMainFrame() != null) {
            UIManager.put("OptionPane.background", GuiUtils.getMainFrame().getBackground());
            UIManager.put("Panel.background", GuiUtils.getMainFrame().getBackground());
        }
        try {
            JOptionPane.showMessageDialog(parentComponent, message, title, messageType);
        } finally {
            visibleDialogs.remove(messageString);
            
            if (dispose)
                ((JFrame)parentComponent).dispose();
            UIManager.put("OptionPane.background", oldOptionColor);
            UIManager.put("Panel.background", oldPanelColor);
        }
    }

    /**
     * @see JOptionPane#showConfirmDialog(Component, Object, String, int)
     */
    public static int showConfirmDialog(Component parentComponent, Object message, String title,
            int optionType) throws HeadlessException {
        boolean dispose = false;
        parentComponent = getWindowForComponent(parentComponent);
        if(parentComponent == null) {
            parentComponent = createFocusComponent();
            dispose = true;
        }
        return showConfirmationDialog(parentComponent, message, title, optionType, JOptionPane.QUESTION_MESSAGE, null, null, dispose);
    }
    
    /**
     * @see JOptionPane#showConfirmDialog(Component, Object, String, int)
     */
    public static int showConfirmDialog(Component parentComponent, Object message, String title,
            int optionType, int messageType) throws HeadlessException {
        boolean dispose = false;
        parentComponent = getWindowForComponent(parentComponent);
        if(parentComponent == null) {
            parentComponent = createFocusComponent();
            dispose = true;
        }
        return showConfirmationDialog(parentComponent, message, title, optionType, messageType, null, null, dispose); 
    }

    /**
     * @see JOptionPane#showOptionDialog(Component, Object, String, int, int,
     *      Icon, Object[], Object)
     */
    public static int showOptionDialog(Component parentComponent, Object message, String title,
            int optionType, int messageType, Icon icon, Object[] options, Object initialValue)
            throws HeadlessException {
        boolean dispose = false;
        parentComponent = getWindowForComponent(parentComponent);
        if(parentComponent == null) {
            parentComponent = createFocusComponent();
            dispose = true;
        }
        return showConfirmationDialog(parentComponent, message, title, optionType, messageType, options, initialValue, 
                dispose);
    }
    
    /**
     * Ensures that the colors for the dialog are set properlly prior to being shown.
     */
    private static int showConfirmationDialog(Component parentComponent, Object message, String title,
            int optionType, int messageType, Object[] options, Object initialValue, boolean dispose) {
        Color oldOptionColor = UIManager.getColor("OptionPane.background");
        Color oldPanelColor = UIManager.getColor("Panel.background");
        UIManager.put("OptionPane.background", GuiUtils.getMainFrame().getBackground());
        UIManager.put("Panel.background", GuiUtils.getMainFrame().getBackground());
        
        try {
            return JOptionPane.showOptionDialog(parentComponent, message, title, optionType, messageType,
                    null, options, initialValue);
        } finally {
            if(dispose)
                ((JFrame)parentComponent).dispose();
            UIManager.put("OptionPane.background", oldOptionColor);
            UIManager.put("Panel.background", oldPanelColor);
        }
    }
    
    public static JDialog createDialog(String title, JComponent parent, JComponent contentPane) {
        JDialog dialog;
        Window window = FocusJOptionPane.getWindowForComponent(parent);
        if (window instanceof Frame) {
            dialog = new LimeJDialog((Frame)window, title, true);   
        } else {
            dialog = new LimeJDialog((Dialog)window, title, true);
        }
        
        Container frameContentPane = dialog.getContentPane();
        frameContentPane.setLayout(new BorderLayout());
        frameContentPane.add(contentPane, BorderLayout.CENTER);
        contentPane.setOpaque(false);
        frameContentPane.setBackground(GuiUtils.getMainFrame().getBackground());

        dialog.setResizable(false);
        dialog.setLocationRelativeTo(parent);
        dialog.pack();
        
        return dialog;
    }
    
    public static int showYesNoMessage(String message, String title, int defaultOption, JComponent parent) {
        final String[] options = {I18n.tr("Yes"), I18n.tr("No")};
        
        int option;
        Color oldOptionColor = UIManager.getColor("OptionPane.background");
        Color oldPanelColor = UIManager.getColor("Panel.background");
        UIManager.put("OptionPane.background", GuiUtils.getMainFrame().getBackground());
        UIManager.put("Panel.background", GuiUtils.getMainFrame().getBackground());
        try {
            option = FocusJOptionPane.showOptionDialog(getWindowForComponent(parent), 
                         getLabel(message), 
                         title,
                         JOptionPane.YES_NO_OPTION, 
                         JOptionPane.WARNING_MESSAGE, null,
                         options, defaultOption);
        } catch(InternalError ie) {
            option = JOptionPane.NO_OPTION;
        } finally {
            UIManager.put("OptionPane.background", oldOptionColor);
            UIManager.put("Panel.background", oldPanelColor);
        }
        
        return option;
    }
    
    private static JComponent getLabel(String message) {
        if(message.startsWith("<html")) {
            HTMLLabel label = new HTMLLabel(message);
            label.setMargin(new Insets(5, 5, 5, 5));
            return label;
        } else {
            return new MultiLineLabel(message, 400);
        }
    }
    
    public static Window getWindowForComponent(Component parentComponent) throws HeadlessException {
        if (parentComponent == null) {
            return GuiUtils.getMainFrame();
        }
        
        if (parentComponent instanceof Frame || parentComponent instanceof Dialog) {
            return (Window) parentComponent;
        }
        
        return FocusJOptionPane.getWindowForComponent(parentComponent.getParent());
    }
}
