/**
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * Copyright © 2009 Mindoo GmbH
 *
 * @author Tammo Riedinger
 *
 */
package com.mindoo.ec09.example4.actions;

import java.util.LinkedHashMap;

import javax.swing.Action;
import javax.swing.SwingUtilities;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExecutableExtension;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuCreator;
import org.eclipse.swt.events.MenuAdapter;
import org.eclipse.swt.events.MenuEvent;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.ui.IWorkbenchWindowPulldownDelegate2;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionDelegate;

import com.mindoo.ec09.example4.SampleView;
import com.mindoo.ec09.framework.actions.PopupAction;

/**
 * Global action to run a Swing-action with a specified name (parameter following the class of the action in plugin.xml,
 * e.g. "com.mindoo.ec09.example3.actions.SwingActionDelegate:Open document").<br>
 * The action will be run for the currently active view.<br>
 * If the swt-action is mapped to a swing-action that implements {@link PopupAction}, then it will create a sub-menu for all
 * child-actions of that {@link PopupAction} (not recursively). For these actions, you can use <code>style="pulldown"</code>
 * in the plugin.xml action-declaration.
 * 
 * @author Tammo Riedinger
 */
public class SwingActionDelegate extends ActionDelegate implements IWorkbenchWindowActionDelegate, IExecutableExtension, IWorkbenchWindowPulldownDelegate2, IMenuCreator {
	private String m_actionName;
	private Menu m_menu;
	

	public void setInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException {
		if (data!=null)
			m_actionName=data.toString();
	}

	public void init(IWorkbenchWindow window) {
	}
	
	@Override
	public void run(IAction action) {
		// invoke the action with the configured name on the active sample-view, if any
		IWorkbenchWindow activeWindow=PlatformUI.getWorkbench().getActiveWorkbenchWindow();
		if (activeWindow==null)
			return;
		
		IWorkbenchPage activePage=activeWindow.getActivePage();
		if (activePage==null)
			return;
		
		IWorkbenchPart activePart=activePage.getActivePart();
		if (!(activePart instanceof SampleView))
			return;
		
		((SampleView)activePart).runSwingAction(m_actionName);
	}
	
	/**
	 * Method to find the corresponding Swing action, if any.
	 * 
	 * @return		the action or <code>null</code>
	 */
	private Action findMenuAction() {
		// find the currently active view
		IWorkbenchWindow activeWindow=PlatformUI.getWorkbench().getActiveWorkbenchWindow();
		if (activeWindow==null)
			return null;
		
		IWorkbenchPage activePage=activeWindow.getActivePage();
		if (activePage==null)
			return null;
		
		final IWorkbenchPart activePart=activePage.getActivePart();
		if (!(activePart instanceof SampleView))
			return null;
		
		// find the Swing action in Swing-EDT
		final Action[] a=new Action[1];
		try {
			SwingUtilities.invokeAndWait(new Runnable() { // ATTENTION: This bears the risk of dead-locking!
				public void run() {
					a[0]=((SampleView)activePart).swing_findAction(m_actionName);
				}
			});
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return a[0];
	}

	public Menu getMenu(Menu menu) {
		Action a=findMenuAction();

		if (a instanceof PopupAction) {
			setMenu(new Menu(menu));

			initMenu((PopupAction)a);
			return m_menu;
		}
		else {
			setMenu(null);
			return null;
		}
	}

	public Menu getMenu(Control parent) {
		Action a=findMenuAction();

		if (a instanceof PopupAction) {
			setMenu(new Menu(parent));

			initMenu((PopupAction)a);
			return m_menu;
		}
		else {
			setMenu(null);
			return null;
		}
	}
	
	/**
	 * Creates the menu for a PopupAction.
	 * 
	 * 
	 * param a		the action
	 */
	protected void initMenu(final PopupAction a) {
		// add listener to repopulate the menu each time
		// it is shown because of dynamic history list
		m_menu.addMenuListener(new MenuAdapter() {
			public void menuShown(MenuEvent e) {
				Menu m = (Menu)e.widget;
				MenuItem[] items = m.getItems();
				for (int i=0; i < items.length; i++)
					items[i].dispose();

				fillMenu(m,a);
			}
		});
	}

	/**
	 * Fills a menu with the child-actions of a {@link PopupAction}.
	 * 
	 * @param menu			the parent-menu
	 * @param popupAction	the action providing the child-actions
	 */
	protected void fillMenu(Menu menu, final PopupAction popupAction) {
		// read information from the child-actions
		// in a real application you would need to read more infos
		// or some kind of action-definition
		// and further more do this stop recursively
		final LinkedHashMap<Action,String> actionInfo=new LinkedHashMap<Action,String>();
		try {
			SwingUtilities.invokeAndWait(new Runnable() { // ATTENTION: This bears the risk of dead-locking!
				public void run() {
					for (Action childAction:popupAction.getChildActions())
						actionInfo.put(childAction,(String)childAction.getValue(Action.NAME));
				}
			});
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		if (actionInfo.size()>0) {
			// now create wrapper actions for each child-action and put it to the menu
			for (final Action a:actionInfo.keySet()) {
				IAction swtAction=new org.eclipse.jface.action.Action(actionInfo.get(a)) {
					@Override
					public void run() {
						// invoke the action on the active sample-view
						IWorkbenchWindow activeWindow=PlatformUI.getWorkbench().getActiveWorkbenchWindow();
						if (activeWindow==null)
							return;
						
						IWorkbenchPage activePage=activeWindow.getActivePage();
						if (activePage==null)
							return;
						
						IWorkbenchPart activePart=activePage.getActivePart();
						if (!(activePart instanceof SampleView))
							return;
						
						((SampleView)activePart).runSwingAction(a);					
					}
				};
				
				new ActionContributionItem(swtAction).fill(menu,-1);
			}
		}
	}

	/**
	 * Sets this action's drop-down menu, disposing the previous menu.
	 * 
	 * @param menu the new menu
	 */
	private void setMenu(Menu menu) {
		if (m_menu != null)
			m_menu.dispose();

		m_menu = menu;
	}
}