/*******************************************************************************
 * Copyright (c) 2014, 2018 Red Hat, Inc.
 * 
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *    lufimtse :  Leo Ufimtsev lufimtse@redhat.com
 *******************************************************************************/

package org.eclipse.linuxtools.profiling.ui;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;

/**
 * <h1>UI sycned Message Dialogue </h1>
 * <p>
 * This class is for launching common messages <b>from background threads</b> and <b>getting a return value</b>.
 * </p>
 * <p>
 * When you're not in a U.I thread, getting the 'shell' causes a runtime exception. <br>
 * Never the less, sometimes you need user feedback when executing a background job. <br>
 * (e.g missing flags when launching a profiling tools, ask the user if he wants the flag to be added). <br>
 * This class aims to implement wrappers for the standard openTYPE message dialogues so that <br>
 * they could be launched from any background thread.
 * </p>
 *
 * <p> Note, methods in this subclass have a postfix of 'SyncedRunnable'.
 *  @since 3.1
 */
public class MessageDialogSyncedRunnable extends MessageDialog {

    /**
     * Calls parent, identical to parent implementation in all respects. <br>
     * <p> Neccessary to supress compiler warnings. Use static methods in this class instead </p>
     * <p> For details and paramater description, please see: <br> </p>
     * {@link org.eclipse.jface.dialogs.MessageDialog#MessageDialog(Shell, String, Image, String, int, String[], int) }
     *
     *
     * @param parentShell
     *            the parent shell
     * @param dialogTitle
     *            the dialog title, or <code>null</code> if none
     * @param dialogTitleImage
     *            the dialog title image, or <code>null</code> if none
     * @param dialogMessage
     *            the dialog message
     * @param dialogImageType
     *            one of the following values:
     *            <ul>
     *            <li><code>MessageDialog.NONE</code> for a dialog with no
     *            image</li>
     *            <li><code>MessageDialog.ERROR</code> for a dialog with an
     *            error image</li>
     *            <li><code>MessageDialog.INFORMATION</code> for a dialog
     *            with an information image</li>
     *            <li><code>MessageDialog.QUESTION </code> for a dialog with a
     *            question image</li>
     *            <li><code>MessageDialog.WARNING</code> for a dialog with a
     *            warning image</li>
     *            </ul>
     * @param dialogButtonLabels
     *            an array of labels for the buttons in the button bar
     * @param defaultIndex
     *            the index in the button label array of the default button
     */
    protected MessageDialogSyncedRunnable(Shell parentShell, String dialogTitle,
            Image dialogTitleImage, String dialogMessage, int dialogImageType,
            String[] dialogButtonLabels, int defaultIndex) {
        super(parentShell, dialogTitle, dialogTitleImage, dialogMessage, dialogImageType,
                dialogButtonLabels, defaultIndex);
    }

    /**
     * <h1>Open Question Dialogue.</h1>
     * <p>
     * Identical to parent implementation {@link MessageDialog#openQuestion(Shell, String, String) openQuestion} <br>
     *  except that you do not need to provide a shell.
     * </p>
     * <p>
     * Convenience method to open a simple Yes/No question  dialog.
     * </p>
     *
     * @param title      the dialog's title, or <code>null</code> if none
     * @param message    the message
     * @return <code>true </code> if the user presses the Yes button,
     *         <code>false</code> otherwise
     */
    public static boolean openQuestionSyncedRunnable(final String title, final String message) {
       return openInSyncedRunnable(DialogueType.QUESTION, title, message);
    }

    /**
     * <h1>Open Confirmation Dialogue. </h1>
     * <p>
     * Identical to parent implementation {@link MessageDialog#openConfirm(Shell, String, String) openConfirm}<br>
     * except that you do not need to provide a shell.
     * </p>
     *
     * <p> Convenience method to open a simple confirm (OK/Cancel) dialog. </p>
     *
     * @param title the dialog's title, or <code>null</code> if none
     * @param message the message
     * @return <code>true</code> if the user presses the OK button,
     *         <code>false</code> otherwise
     */
    public static boolean openConfirmSyncedRunnable(final String title, final String message) {
        return openInSyncedRunnable(DialogueType.CONFIRMATION, title, message);
    }

    /**
     * <h1>Open Information Dialogue.</h1>
     * <p>
     * Identical to parent implementation {@link MessageDialog#openInformation(Shell, String, String) openInformation} <br>
     * except that you do not need to provide a shell.
     * </p>
     * <p>
     * Convenience method to open a simple confirm (OK/Cancel) dialog.
     * </p>
     *
     * @param title     the dialog's title, or <code>null</code> if none
     * @param message   the message
     */
    public static void openInformationSyncedRunnable(final String title, final String message) {
        //We discard boolean and don't return anything.
        openInSyncedRunnable(DialogueType.INFO, title, message);
     }

    /**
     * <h1>Open Error Dialogue.</h1>
     * <p>
     * Identical to parent implementation  {@link MessageDialog#openError(Shell, String, String) openError}<br>
     * except that you do not need to provide a shell:
     * </p>
     *<p>
     *Convenience method to open a standard error dialog.
     *</p>
     *
     * @param title     the dialog's title, or <code>null</code> if none
     * @param message   the message
     */
    public static void openErrorSyncedRunnable(final String title, final String message) {
        //We discard boolean and don't return anything.
        openInSyncedRunnable(DialogueType.ERROR, title, message);
    }

    private static enum DialogueType {INFO, ERROR, CONFIRMATION, QUESTION}

    /* To prevent code duplication... */
    private static boolean openInSyncedRunnable(final DialogueType type, final String title, final String message) {

        //We define a 'final' variable that will be accessible in the runnable object.
        final BooleanWithGetSet userChoiceBool = new BooleanWithGetSet(false);

        //To generate U.I, we make a syncronised call the U.I thread,
        //otherwise we get an U.I exception.
        PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
		    Shell parent = PlatformUI.getWorkbench().getDisplay().getActiveShell();
		    switch (type) {
		    case INFO:
		        MessageDialog.openInformation(parent, title, message);
		        break;
		    case ERROR:
		        MessageDialog.openError(parent, title, message);
		        break;
		    case CONFIRMATION:
		        boolean okPressed = MessageDialog.openConfirm(parent, title, message);
		        userChoiceBool.setVal(okPressed);
		        break;
		    case QUESTION:
		        boolean okPressedQ = MessageDialog.openQuestion(parent, title, message);
		        userChoiceBool.setVal(okPressedQ);
		        break;
		    default:
		        break;
		    }
		    return;
      });
        return userChoiceBool.getVal();
    }
}
