/*******************************************************************************
 * Copyright (c) 2010, 2015 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.ui.internal.handlers;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.runtime.Adapters;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
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.Event;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.internal.testing.ContributionInfoMessages;
import org.eclipse.ui.testing.ContributionInfo;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;

/**
 * @since 3.6
 *
 */
public class SpyHandler extends AbstractHandler {

	@Override
	public Object execute(ExecutionEvent event) {
		Shell shell = HandlerUtil.getActiveShell(event);
		if (shell != null) {
			Control control = shell.getDisplay().getFocusControl();
			if (control != null) {
				showTooltip(control);
			}
		}
		return null;
	}

	protected void showTooltip(Control control) {
		ContributionInfo contributionInfo = null;
		Point offset = new Point(0, 0);
		while (control != null) {
			if (control instanceof Table) {
				Table table = (Table) control;
				if (table.getSelectionCount() == 1) {
					TableItem tableItem = table.getSelection()[0];
					contributionInfo = getContributionInfo(tableItem.getData(),
							ContributionInfoMessages.ContributionInfo_TableItem);
					if (contributionInfo != null) {
						Rectangle bounds = tableItem.getBounds();
						offset = new Point(bounds.x, bounds.y);
						break;
					}
				}
			} else if (control instanceof Tree) {
				Tree tree = (Tree) control;
				if (tree.getSelectionCount() == 1) {
					TreeItem treeItem = tree.getSelection()[0];
					contributionInfo = getContributionInfo(treeItem.getData(),
							ContributionInfoMessages.ContributionInfo_TreeItem);
					if (contributionInfo != null) {
						Rectangle bounds = treeItem.getBounds();
						offset = new Point(bounds.x, bounds.y);
						break;
					}
				}
			}
			String optionalElementType;

			// "force" a contribution info if we are at a shell
			if (control instanceof Shell)
				optionalElementType = ContributionInfoMessages.ContributionInfo_Window;
			else
				optionalElementType = null;

			contributionInfo = getContributionInfo(control.getData(), optionalElementType);

			if (contributionInfo != null) {
				break;
			}
			control = control.getParent();
		}
		if (contributionInfo == null) {
			return;
		}
		doShowTooltip(control, offset, contributionInfo);
	}

	/**
	 * @param control
	 * @param offset
	 * @param contributionInfo
	 */
	protected void doShowTooltip(Control control, Point offset,
			final ContributionInfo contributionInfo) {
		ToolTip toolTip = new ToolTip(control, ToolTip.NO_RECREATE, true) {

			@Override
			protected Composite createToolTipContentArea(Event event, Composite parent) {
				// Create the content area
				Composite composite = new Composite(parent, SWT.NONE);
				Color fg = parent.getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND);
				Color bg = parent.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND);
				composite.setForeground(fg);
				composite.setBackground(bg);
				Text text = new Text(composite, SWT.READ_ONLY);
				text.setForeground(fg);
				text.setBackground(bg);
				String info = NLS.bind(ContributionInfoMessages.ContributionInfo_ContributedBy,
						contributionInfo.getElementType(), contributionInfo.getBundleId());
				text.setText(info);
				GridLayoutFactory.fillDefaults().margins(2, 2).generateLayout(composite);
				return composite;
			}
		};
		toolTip.setHideOnMouseDown(false);
		toolTip.setHideDelay(3000);
		toolTip.show(offset);
	}

	/**
	 * Returns a ContributionInfo for the given data object (typically, a data
	 * object associated with a widget). If the data object is a
	 * ContributionInfo, return it. If it can be adapted to ContributionInfo,
	 * return the result of the adaptation. Otherwise, if a non-null
	 * 'optionalElementType' string is given, return a contribution info based
	 * on it and the bundle that contains the given object's class.
	 */
	ContributionInfo getContributionInfo(Object data, String optionalElementType) {
		if (data instanceof ContributionInfo) {
			return (ContributionInfo) data;
		}
		ContributionInfo result = Adapters.adapt(data, ContributionInfo.class);
		if (optionalElementType != null && result == null && data != null) {
			Bundle bundle = FrameworkUtil.getBundle(data.getClass());
			if (bundle != null) {
				result = new ContributionInfo(bundle.getSymbolicName(), optionalElementType, null);
			}
		}
		return result;
	}
}