/*******************************************************************************
 * Copyright (c) 2004, 2009 Tasktop Technologies 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:
 *     Tasktop Technologies - initial API and implementation
 *     Raphael Ackermann - bug 160315
 *******************************************************************************/

package org.eclipse.mylyn.internal.tasks.ui;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.mylyn.internal.tasks.core.AbstractTask;
import org.eclipse.mylyn.internal.tasks.core.AbstractTaskCategory;
import org.eclipse.mylyn.internal.tasks.core.TaskCategory;
import org.eclipse.mylyn.internal.tasks.core.UnmatchedTaskContainer;
import org.eclipse.mylyn.internal.tasks.ui.actions.NewCategoryAction;
import org.eclipse.mylyn.internal.tasks.ui.util.TaskContainerComparator;
import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal;
import org.eclipse.mylyn.tasks.core.IRepositoryElement;
import org.eclipse.mylyn.tasks.core.ITask;
import org.eclipse.mylyn.tasks.ui.TasksUiImages;

/**
 * @author Mik Kersten
 */
public class MoveToCategoryMenuContributor implements IDynamicSubMenuContributor {

	public MenuManager getSubMenuManager(final List<IRepositoryElement> selectedElements) {
		final MenuManager subMenuManager = new MenuManager(
				Messages.MoveToCategoryMenuContributor_Set_Category_Menu_Item);

		// Compute selected tasks
		List<AbstractTask> selectedTasks = new ArrayList<AbstractTask>(selectedElements.size());
		for (IRepositoryElement element : selectedElements) {
			if (element instanceof ITask) {
				selectedTasks.add((AbstractTask) element);
			}
		}
		subMenuManager.setVisible(!selectedTasks.isEmpty());

		List<AbstractTaskCategory> categories = new ArrayList<AbstractTaskCategory>(TasksUiInternal.getTaskList()
				.getCategories());
		Collections.sort(categories, new TaskContainerComparator());
		for (final AbstractTaskCategory category : categories) {
			if (!(category instanceof UnmatchedTaskContainer)) {
				String text = handleAcceleratorKeys(category.getSummary());
				Action action = new Action(text, IAction.AS_RADIO_BUTTON) {
					@Override
					public void run() {
						moveToCategory(selectedElements, category);
					}
				};
				action.setImageDescriptor(TasksUiImages.CATEGORY);
				if (selectedTasks.size() == 1) {
					if (category.contains(selectedTasks.get(0).getHandleIdentifier())) {
						action.setChecked(true);
					}
				}
				subMenuManager.add(action);
			}
		}
		// add New Category action at the end of the Move to Category Submenu
		// and move selected actions to this newly created category
		Action action = new NewCategoryAction() {
			@Override
			public void run() {
				TaskCategory category = createCategory();
				if (category != null) {
					moveToCategory(selectedElements, category);
				}
			}
		};
		subMenuManager.add(new Separator());
		subMenuManager.add(action);
		return subMenuManager;
	}

	/**
	 * public for testing Deals with text where user has entered a '@' or tab character but which are not meant to be
	 * accelerators. from: Action#setText: Note that if you want to insert a '@' character into the text (but no
	 * accelerator, you can simply insert a '@' or a tab at the end of the text. see Action#setText
	 */
	public String handleAcceleratorKeys(String text) {
		if (text == null) {
			return null;
		}

		int index = text.lastIndexOf('\t');
		if (index == -1) {
			index = text.lastIndexOf('@');
		}
		if (index >= 0) {
			return text.concat("@"); //$NON-NLS-1$
		}
		return text;
	}

	/**
	 * @param selectedElements
	 * @param category
	 */
	private void moveToCategory(final List<IRepositoryElement> selectedElements, AbstractTaskCategory category) {
		for (IRepositoryElement element : selectedElements) {
			if (element instanceof ITask) {
				TasksUiInternal.getTaskList().addTask((AbstractTask) element, category);
			}
		}
	}

}
