/**
 * File:    WorkflowServiceView.java
 * Created: 26.02.2008
 *
 *
/*******************************************************************************
 * Copyright (c) 2005-2011
 * Eclipse Java Workflow Tooling (JWT) Project <www.eclipse.org/jwt>
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Mickaël Istria, Open Wide, Lyon, France
 *      - Creation and implementation
 *******************************************************************************/
package org.eclipse.jwt.wam.monitoring.views;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jwt.wam.api.WorkflowService;
import org.eclipse.jwt.wam.monitoring.actions.AddService;
import org.eclipse.jwt.wam.monitoring.composite.RootComposite;
import org.eclipse.jwt.wam.monitoring.composite.WorkflowBeanComposite;
import org.eclipse.jwt.wam.monitoring.composite.WorkflowServiceComposite;
import org.eclipse.jwt.wam.monitoring.serviceAPI.WorkflowServiceProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.UIJob;

public class WorkflowServicesView extends ViewPart
{

	private TreeViewer viewer;
	private Action addAction;
	private Action refresh;
	private Action delete;
	private Action doubleClickAction;
	private WorkflowServicesView thiz = null;

	/**
	 * Name comparator is a class in charge of providing functions to sort the
	 * tree. We chose that the "category" of an item would be its depth in the
	 * tree. Specific comparation are specified in {@link WorkflowBeanComposite}
	 * implementations (compareTo).
	 * 
	 * @author mistria
	 * 
	 */
	class NameComparator extends ViewerComparator
	{

		public int category(Object e)
		{
			return ((WorkflowBeanComposite) e).getCategory();
		}


		public int compare(Viewer viewer, Object e1, Object e2)
		{
			WorkflowBeanComposite item1 = (WorkflowBeanComposite) e1;
			WorkflowBeanComposite item2 = (WorkflowBeanComposite) e2;
			if (item1.getCategory() == item2.getCategory())
				return item1.compareTo(item2);
			else
				return item1.getCategory() - item2.getCategory();
		}
	}


	/**
	 * The constructor.
	 */
	public WorkflowServicesView()
	{
		thiz = this;
	}


	/**
	 * This is a callback that will allow us to create the viewer and initialize
	 * it.
	 */
	public void createPartControl(Composite parent)
	{
		viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);

		Tree tree = viewer.getTree();
		tree.setHeaderVisible(true);
		TreeColumn column1 = new TreeColumn(tree, SWT.LEFT);
		column1.setText("Name");
		column1.setWidth(200);
		TreeColumn column2 = new TreeColumn(tree, SWT.LEFT);
		column2.setText("Value");
		column2.setWidth(200);
		viewer.setContentProvider(new ViewContentProvider());
		viewer.setLabelProvider(new ViewLabelProvider());
		viewer.setComparator(new NameComparator());

		RootComposite root = new RootComposite();
		viewer.setInput(root);

		makeActions();
		hookContextMenu();
		hookDoubleClickAction();
		contributeToActionBars();
	}


	private void hookContextMenu()
	{
		MenuManager menuMgr = new MenuManager("#PopupMenu");
		menuMgr.setRemoveAllWhenShown(true);
		menuMgr.addMenuListener(new IMenuListener()
		{

			public void menuAboutToShow(IMenuManager manager)
			{
				WorkflowServicesView.this.fillContextMenu(manager);
			}
		});
		Menu menu = menuMgr.createContextMenu(viewer.getControl());
		viewer.getControl().setMenu(menu);
		getSite().registerContextMenu(menuMgr, viewer);
	}


	private void contributeToActionBars()
	{
		IActionBars bars = getViewSite().getActionBars();
		fillLocalPullDown(bars.getMenuManager());
		fillLocalToolBar(bars.getToolBarManager());
	}


	private void fillLocalPullDown(IMenuManager manager)
	{
		manager.add(addAction);
		manager.add(new Separator());
		manager.add(refresh);
	}


	private void fillContextMenu(IMenuManager manager)
	{
		manager.add(addAction);
		// Other plug-ins can contribute there actions here
		manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
		manager.add(refresh);
		manager.add(delete);
	}


	private void fillLocalToolBar(IToolBarManager manager)
	{
		manager.add(addAction);
		manager.add(refresh);
	}


	private void makeActions()
	{
		addAction = new Action()
		{

			public void run()
			{
				AddService.getInstance().addService(thiz);
			}
		};
		addAction.setText("Add a Workflow Service");
		addAction
				.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
						.getImageDescriptor(
								org.eclipse.ui.ide.IDE.SharedImages.IMG_OBJS_TASK_TSK));

		refresh = new Action()
		{

			public void run()
			{
				showMessage("Refresh not implemented");
			}
		};
		refresh.setText("Reflesh workflow state");
		refresh.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
				.getImageDescriptor(ISharedImages.IMG_TOOL_REDO));

		delete = new Action()
		{

			public void run()
			{
				ISelection selection = viewer.getSelection();
				Object obj = ((IStructuredSelection) selection).getFirstElement();
				if (!(obj instanceof WorkflowServiceComposite))
					showMessage("Can only delete a WorkflowService");
				else
				{
					((RootComposite) viewer.getInput())
							.remove((WorkflowServiceComposite) obj);
					viewer.refresh();
				}
			}
		};
		delete.setText("delete this workflow engine");
		delete.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
				.getImageDescriptor(ISharedImages.IMG_TOOL_DELETE));

		doubleClickAction = new Action()
		{

			public void run()
			{
				ISelection selection = viewer.getSelection();
				Object obj = ((IStructuredSelection) selection).getFirstElement();
				showMessage("Double-click detected on " + obj.toString());
			}
		};
	}


	/**
	 * Adds a Workflow Service to the viewer Does not create a Job
	 * 
	 * @param name
	 * @param workflowService
	 * @param login
	 */
	public void addService(String name, WorkflowService workflowService, String login)
	{
		((RootComposite) (viewer.getInput())).addService(name, workflowService, login);
		viewer.refresh();
	}


	/**
	 * Opens a Job that retrieve the WorkflowService from the
	 * WorkflowServiceProvider and add it in the TreeViewer
	 * 
	 * @param name
	 * @param workflowServiceProvider
	 * @param login
	 */
	public void addService(WorkflowServiceProvider workflowServiceProvider)
	{
		new AddServiceJob(workflowServiceProvider).schedule();
	}

	/**
	 * UI Job, must be distinct from non-UI Job
	 * 
	 * @see http
	 *      ://dev.eclipse.org/newslists/news.eclipse.platform.rcp/msg24320.html
	 * @author mistria
	 */
	private class RefreshViewerJob extends UIJob
	{

		public RefreshViewerJob(String name)
		{
			super(name);
		}


		@Override
		public IStatus runInUIThread(IProgressMonitor monitor)
		{
			viewer.refresh();
			return Status.OK_STATUS;
		}
	}

	/***
	 * Job for addService
	 */
	public class AddServiceJob extends Job
	{

		private WorkflowServiceProvider wfServiceProvider = null;


		public AddServiceJob(WorkflowServiceProvider wfServiceProvider)
		{
			super("Retrieving workflow service");
			this.wfServiceProvider = wfServiceProvider;
		}


		@Override
		public IStatus run(IProgressMonitor monitor)
		{
			WorkflowService wfService = wfServiceProvider.getWorkflowService();
			// TODO replace "bsoa" by something more clever
			((RootComposite) (viewer.getInput())).addService("test", wfService, "bsoa");
			new RefreshViewerJob("Updating view").schedule();
			return Status.OK_STATUS;
		}
	}


	private void hookDoubleClickAction()
	{
		viewer.addDoubleClickListener(new IDoubleClickListener()
		{

			public void doubleClick(DoubleClickEvent event)
			{
				doubleClickAction.run();
			}
		});
	}


	private void showMessage(String message)
	{
		MessageDialog.openInformation(viewer.getControl().getShell(), "Sample View",
				message);
	}


	/**
	 * Passing the focus request to the viewer's control.
	 */
	public void setFocus()
	{
		viewer.getControl().setFocus();
	}
}