/*******************************************************************************
 * Copyright (c) 2005, 2013 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.debug.ui;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.views.DebugUIViewsMessages;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.PopupDialog;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.IHandlerActivation;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.keys.IBindingService;

import com.ibm.icu.text.MessageFormat;

/**
 * A <code>PopupDialog</code> that is automatically positioned relative
 * to a specified anchor point. The popup can be dismissed in the same
 * manor as all popup dialogs, but additionally allows clients the option
 * of specifying a command id that can be used to persist the contents of
 * the dialog.
 * <p>
 * Clients may subclass this.
 * @since 3.2
 */
public abstract class DebugPopup extends PopupDialog {

    private Point fAnchor;

    private IHandlerActivation fActivation;

    private IHandlerService fHandlerService;

	private String fCommandId;

	private boolean fPersisted = false;

    /**
     * Constructs a new popup dialog of type <code>PopupDialog.INFOPOPUPRESIZE_SHELLSTYLE</code>
     * @param parent The parent shell
     * @param anchor point at which to anchor the popup dialog in Display coordinate space.
     * 	Since 3.3, <code>null</code> can be specified to use a default anchor point
     * @param commandId The command id to be used for persistence of
     *  the dialog, or <code>null</code>
     */
    public DebugPopup(Shell parent, Point anchor, String commandId) {
        super(parent, PopupDialog.INFOPOPUPRESIZE_SHELLSTYLE, true, true, false, true, false, null, null);
        fAnchor = anchor;
        fCommandId = commandId;
    }

    /**
     * Returns the text to be shown in the popups's information area.
     * May return <code>null</code>.
     * <p>
     * By default, if this dialog has a persistence command associated with it,
     * the text displayed is of the form "Press {key-sequence} to {action}". The
     * action text is specified by the method <code>getActionText()</code>.
     * </p>
     * @return The text to be shown in the popup's information area or <code>null</code>
     */
    protected String getInfoText() {
    	if (getCommandId() != null && getActionText() != null) {
	        IWorkbench workbench = PlatformUI.getWorkbench();
	        IBindingService bindingService = workbench.getAdapter(IBindingService.class);
	        String formattedBinding = bindingService.getBestActiveBindingFormattedFor(getCommandId());

	        String infoText = null;
	        if (formattedBinding != null) {
				infoText = MessageFormat.format(DebugUIViewsMessages.InspectPopupDialog_1, new Object[] {
						formattedBinding, getActionText() });
	        }
	        return infoText;
    	}
    	return null;
    }

    /**
     * Returns the text to be shown as the action performed when this dialog's
     * persist command is invoked, or <code>null</code>.
     * <p>
     * Subclasses should override as necessary.
     * </p>
     * @return the text to be shown as the action performed when this dialog's
     *  persist command is invoked
     */
    protected String getActionText() {
    	return null;
    }

    /**
     * Returns the command id to be used for persisting the contents of the
     * dialog. If the contents should not be persisted, this method should
     * return null.
     *
     * @return The command id to be used for persisting the contents of the
     * dialog or <code>null</code>
     */
    protected String getCommandId() {
        return fCommandId;
    }

    /**
     * Persists the contents of the dialog. Subclasses should override as required,
     * but also call super.persist().
     */
    protected void persist() {
    	fPersisted = true;
    }

    /**
     * Returns whether the command handler was invoked to persist this popup's result.
     *
     * @return whether the command handler was invoked to persist this popup's result
     */
    protected boolean wasPersisted() {
    	return fPersisted;
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.jface.dialogs.PopupDialog#createDialogArea(org.eclipse.swt.widgets.Composite)
     */
    @Override
	protected abstract Control createDialogArea(Composite parent);


    /**
     * Returns the initial location to use for the shell based upon the
     * current selection in the viewer. Bottom is preferred to top, and
     * right is preferred to left, therefore if possible the popup will
     * be located below and to the right of the selection.
     *
     * @param initialSize
     *            the initial size of the shell, as returned by
     *            <code>getInitialSize</code>.
     * @return the initial location of the shell
     */
    @Override
	protected Point getInitialLocation(Point initialSize) {
    	if (fAnchor == null) {
    		return super.getInitialLocation(initialSize);
    	}
        Point point = fAnchor;
        Rectangle monitor = getShell().getMonitor().getClientArea();
        if (monitor.width < point.x + initialSize.x) {
            point.x = Math.max(0, point.x - initialSize.x);
        }
        if (monitor.height < point.y + initialSize.y) {
            point.y = Math.max(0, point.y - initialSize.y);
        }
        return point;
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.jface.dialogs.PopupDialog#getDialogSettings()
     */
    @Override
	protected IDialogSettings getDialogSettings() {
        IDialogSettings settings = DebugUIPlugin.getDefault().getDialogSettings();
        return settings;
    }


    /* (non-Javadoc)
     * @see org.eclipse.jface.dialogs.PopupDialog#open()
     */
    @Override
	public int open() {
        IWorkbench workbench = PlatformUI.getWorkbench();
        String commandId = getCommandId();
        if (commandId != null) {
            IHandler fCloseHandler = new AbstractHandler() {
                @Override
				public Object execute(ExecutionEvent event) throws ExecutionException {
                    persist();
                    close();
                    return null;
                }
            };

            fHandlerService = workbench.getAdapter(IHandlerService.class);
            fActivation = fHandlerService.activateHandler(commandId, fCloseHandler);
        }

        String infoText = getInfoText();
        if (infoText != null) {
			setInfoText(infoText);
		}

        return super.open();
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.dialogs.PopupDialog#close()
     */
    @Override
	public boolean close() {
        if (fActivation != null) {
			fHandlerService.deactivateHandler(fActivation);
		}

        return super.close();
    }
}
