/*******************************************************************************
 * Copyright (c) 2006, 2007 IBM Corporation and others.
 * 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.ui.internal.navigator.resources.actions;

import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.IWorkingSetManager;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.WorkingSetFilterActionGroup;
import org.eclipse.ui.internal.navigator.workingsets.WorkingSetsContentProvider;
import org.eclipse.ui.navigator.CommonActionProvider;
import org.eclipse.ui.navigator.ICommonActionExtensionSite;
import org.eclipse.ui.navigator.IExtensionActivationListener;
import org.eclipse.ui.navigator.IExtensionStateModel;
import org.eclipse.ui.navigator.INavigatorContentService;

/**
 * @since 3.2
 * 
 */
public class WorkingSetActionProvider extends CommonActionProvider {

	private static final String TAG_CURRENT_WORKING_SET_NAME = "currentWorkingSetName"; //$NON-NLS-1$

	private boolean contributedToViewMenu = false; 

	private StructuredViewer viewer;

	private INavigatorContentService contentService;

	private WorkingSetFilterActionGroup workingSetActionGroup;
	private WorkingSetRootModeActionGroup workingSetRootModeActionGroup;

	private Object originalViewerInput = ResourcesPlugin.getWorkspace().getRoot();

	private IExtensionStateModel extensionStateModel;

	/**
	 * Provides a smart listener to monitor changes to the Working Set Manager.
	 * 
	 */
	public class WorkingSetManagerListener implements IPropertyChangeListener {

		private boolean listening = false;

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
		 */
		public void propertyChange(PropertyChangeEvent event) {

			Object input = viewer.getInput();
			if (input instanceof IWorkingSet) {
				IWorkingSet workingSet = (IWorkingSet) input;

				String property = event.getProperty();
				Object newValue = event.getNewValue();
				Object oldValue = event.getOldValue();

				if (IWorkingSetManager.CHANGE_WORKING_SET_REMOVE.equals(property) && oldValue == workingSet) {
					// setWorkingSet(null);
					if (viewer != null) {
						viewer.setInput(originalViewerInput);
					}
				} else if (IWorkingSetManager.CHANGE_WORKING_SET_NAME_CHANGE.equals(property) && newValue == workingSet) {
				} else if (IWorkingSetManager.CHANGE_WORKING_SET_CONTENT_CHANGE.equals(property) && newValue == workingSet) {
					// if (workingSet.isAggregateWorkingSet() && workingSet.isEmpty()) {
					// // act as if the working set has been made null
					// if (!emptyWorkingSet) {
					// emptyWorkingSet = true;
					// workingSetFilter.setWorkingSet(null);
					// }
					// } else {
					// // we've gone from empty to non-empty on our set.
					// // Restore it.
					// if (emptyWorkingSet) {
					// emptyWorkingSet = false;
					// workingSetFilter.setWorkingSet(workingSet);
					// }
					// }
					if (viewer != null) {
						viewer.refresh();
					}
				}
			}

		}

		/**
		 * Begin listening to the correct source if not already listening.
		 */
		public synchronized void listen() {
			if (!listening) {
				PlatformUI.getWorkbench().getWorkingSetManager().addPropertyChangeListener(managerChangeListener);
				listening = true;
			}
		}

		/**
		 * Begin listening to the correct source if not already listening.
		 */
		public synchronized void ignore() {
			if (listening) {
				PlatformUI.getWorkbench().getWorkingSetManager().removePropertyChangeListener(managerChangeListener);
				listening = false;
			}
		}
	}

	private IPropertyChangeListener filterChangeListener = new IPropertyChangeListener() {
		/*
		 * (non-Javadoc)
		 * 
		 * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
		 */
		public void propertyChange(PropertyChangeEvent event) {
			IWorkingSet oldWorkingSet = (IWorkingSet) event.getOldValue();
			IWorkingSet newWorkingSet = (IWorkingSet) event.getNewValue();


			if (newWorkingSet != null && !contentService.isActive(WorkingSetsContentProvider.EXTENSION_ID)) {
				contentService.getActivationService().activateExtensions(new String[]{WorkingSetsContentProvider.EXTENSION_ID}, false);
				contentService.getActivationService().persistExtensionActivations();
			}

			if (viewer != null) {
				if (newWorkingSet == null) {
					viewer.setInput(ResourcesPlugin.getWorkspace().getRoot());
				} else if(oldWorkingSet != newWorkingSet) {
					viewer.setInput(newWorkingSet);
				}
			}

		}
	};

	private WorkingSetManagerListener managerChangeListener = new WorkingSetManagerListener();

	private IExtensionActivationListener activationListener = new IExtensionActivationListener() {

		private IWorkingSet workingSet;

		public void onExtensionActivation(String aViewerId, String[] theNavigatorExtensionIds, boolean isActive) {

			for (int i = 0; i < theNavigatorExtensionIds.length; i++) {
				if (WorkingSetsContentProvider.EXTENSION_ID.equals(theNavigatorExtensionIds[i])) {
					if (isActive) {
						extensionStateModel = contentService.findStateModel(WorkingSetsContentProvider.EXTENSION_ID);
						workingSetRootModeActionGroup.setStateModel(extensionStateModel);

						if (workingSet != null) {
							viewer.setInput(workingSet);  
							workingSetActionGroup.setWorkingSet(workingSet); 
							workingSetRootModeActionGroup.setShowTopLevelWorkingSets(true);
						}
						managerChangeListener.listen();					


					} else {
						Object input = viewer.getInput();
						if (input instanceof IWorkingSet) {
							workingSet = (IWorkingSet) input;
							if (viewer != null && input != originalViewerInput) {
								viewer.setInput(originalViewerInput);
							}
						} else {
							workingSet = null;
						}
						managerChangeListener.ignore();
						workingSetActionGroup.setWorkingSet(null);
						workingSetRootModeActionGroup.setShowTopLevelWorkingSets(false);

					}
				}
			}
		}

	};

	 

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.navigator.CommonActionProvider#init(org.eclipse.ui.navigator.ICommonActionExtensionSite)
	 */
	public void init(ICommonActionExtensionSite aSite) {
		viewer = aSite.getStructuredViewer();
		contentService = aSite.getContentService();

		extensionStateModel = contentService.findStateModel(WorkingSetsContentProvider.EXTENSION_ID);

		workingSetActionGroup = new WorkingSetFilterActionGroup(aSite.getViewSite().getShell(), filterChangeListener);

		if (extensionStateModel != null) {
			workingSetRootModeActionGroup = new WorkingSetRootModeActionGroup(viewer, extensionStateModel);
		}


		if (contentService.isActive(WorkingSetsContentProvider.EXTENSION_ID)) {
			managerChangeListener.listen();
		}

		contentService.getActivationService().addExtensionActivationListener(activationListener);
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.ui.navigator.CommonActionProvider#restoreState(org.eclipse.ui.IMemento)
	 */
	public void restoreState(IMemento aMemento) {
		super.restoreState(aMemento);
		
		boolean showWorkingSets = true;
		if(aMemento != null) {
			Integer showWorkingSetsInt = aMemento.getInteger(WorkingSetsContentProvider.SHOW_TOP_LEVEL_WORKING_SETS); 
			showWorkingSets = showWorkingSetsInt == null || showWorkingSetsInt.intValue() == 1;
			extensionStateModel.setBooleanProperty(WorkingSetsContentProvider.SHOW_TOP_LEVEL_WORKING_SETS, showWorkingSets);
			workingSetRootModeActionGroup.setShowTopLevelWorkingSets(showWorkingSets);

			if(viewer != null) {
				String lastWorkingSetName = aMemento.getString(TAG_CURRENT_WORKING_SET_NAME);			
				IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager();			
				IWorkingSet lastWorkingSet = workingSetManager.getWorkingSet(lastWorkingSetName);			 
				viewer.setInput(lastWorkingSet);
				workingSetActionGroup.setWorkingSet(lastWorkingSet);
			} 
		} else {
			showWorkingSets = false;
			
			extensionStateModel.setBooleanProperty(WorkingSetsContentProvider.SHOW_TOP_LEVEL_WORKING_SETS, showWorkingSets);
			workingSetRootModeActionGroup.setShowTopLevelWorkingSets(showWorkingSets);			 
		}
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.ui.navigator.CommonActionProvider#saveState(org.eclipse.ui.IMemento)
	 */
	public void saveState(IMemento aMemento) {
		super.saveState(aMemento);
		  	
		if(aMemento != null) {
			int showWorkingSets = extensionStateModel.getBooleanProperty(WorkingSetsContentProvider.SHOW_TOP_LEVEL_WORKING_SETS) ? 1 : 0;		
			aMemento.putInteger(WorkingSetsContentProvider.SHOW_TOP_LEVEL_WORKING_SETS, showWorkingSets); 
			
			if(viewer != null) {
				Object input = viewer.getInput();
				if(input instanceof IWorkingSet) {
					IWorkingSet workingSet = (IWorkingSet) input;
					aMemento.putString(TAG_CURRENT_WORKING_SET_NAME, workingSet.getName());
				}
			}
		}
		
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.actions.ActionGroup#fillActionBars(org.eclipse.ui.IActionBars)
	 */
	public void fillActionBars(IActionBars actionBars) { 
		if (!contributedToViewMenu) {
			try {
				super.fillActionBars(actionBars);
				workingSetActionGroup.fillActionBars(actionBars);
				if (workingSetRootModeActionGroup != null) {
					workingSetRootModeActionGroup.fillActionBars(actionBars);
				}
			} finally {
				contributedToViewMenu = true;
			}
		} 
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.actions.ActionGroup#dispose()
	 */
	public void dispose() {
		super.dispose();
		workingSetActionGroup.dispose();
		if (workingSetRootModeActionGroup != null) {
			workingSetRootModeActionGroup.dispose();
		}

		managerChangeListener.ignore();

		contentService.getActivationService().removeExtensionActivationListener(activationListener);
	}
}
