/*******************************************************************************
 * Copyright (C) 2014 Robin Stocker <robin@nibor.org> 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
 *******************************************************************************/
package org.eclipse.egit.ui.internal.actions;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.internal.CommonUtils;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.commit.CommitEditor;
import org.eclipse.egit.ui.internal.commit.RepositoryCommit;
import org.eclipse.egit.ui.internal.selection.SelectionUtils;
import org.eclipse.egit.ui.internal.stash.StashCreateUI;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.Separator;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.CompoundContributionItem;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.menus.IWorkbenchContribution;
import org.eclipse.ui.services.IServiceLocator;

/**
 * The "Stashes" submenu, for stashing changes and listing the existing stashes.
 */
public class StashesMenu extends CompoundContributionItem implements
		IWorkbenchContribution {

	private IServiceLocator serviceLocator;

	public void initialize(IServiceLocator locator) {
		this.serviceLocator = locator;
	}

	@Override
	protected IContributionItem[] getContributionItems() {
		Repository repository = getRepository();

		List<IContributionItem> items = new ArrayList<IContributionItem>();

		items.add(createStashChangesItem(repository));
		items.add(new Separator());
		items.addAll(createStashItems(repository));

		return items.toArray(new IContributionItem[0]);
	}

	private static IContributionItem createStashChangesItem(
			final Repository repository) {
		Action action = new Action(UIText.StashesMenu_StashChangesActionText) {
			@Override
			public void run() {
				StashCreateUI stashCreateUI = new StashCreateUI(repository);
				Shell shell = PlatformUI.getWorkbench()
						.getActiveWorkbenchWindow().getShell();
				stashCreateUI.createStash(shell);
			}

			@Override
			public boolean isEnabled() {
				return StashCreateHandler.isEnabled(repository);
			}
		};
		return new ActionContributionItem(action);
	}

	private static Collection<IContributionItem> createStashItems(
			Repository repository) {
		if (repository == null)
			return Collections.singleton(createNoStashedChangesItem());

		try {
			Collection<RevCommit> stashCommits = Git.wrap(repository)
					.stashList().call();

			if (stashCommits.isEmpty())
				return Collections.singleton(createNoStashedChangesItem());

			List<IContributionItem> items = new ArrayList<IContributionItem>(
					stashCommits.size());

			int index = 0;
			for (final RevCommit stashCommit : stashCommits)
				items.add(createStashItem(repository, stashCommit, index++));

			return items;
		} catch (GitAPIException e) {
			String repoName = repository.getWorkTree().getName();
			String message = MessageFormat.format(
					UIText.StashesMenu_StashListError, repoName);
			Activator.logError(message, e);
			return Collections.singleton(createNoStashedChangesItem());
		}
	}

	private static IContributionItem createNoStashedChangesItem() {
		Action action = new Action(UIText.StashesMenu_NoStashedChangesText) {
			@Override
			public boolean isEnabled() {
				return false;
			}
		};
		return new ActionContributionItem(action);
	}

	private Repository getRepository() {
		if (serviceLocator == null)
			return null;

		IHandlerService handlerService = CommonUtils.getService(serviceLocator, IHandlerService.class);
		if (handlerService == null)
			return null;

		IEvaluationContext evaluationContext = handlerService.getCurrentState();
		return SelectionUtils.getRepository(evaluationContext);
	}

	private static ActionContributionItem createStashItem(
			final Repository repo, final RevCommit stashCommit, int index) {
		String text = MessageFormat.format(UIText.StashesMenu_StashItemText,
				Integer.valueOf(index), stashCommit.getShortMessage());
		Action action = new Action(text) {
			@Override
			public void run() {
				RepositoryCommit repositoryCommit = new RepositoryCommit(repo,
						stashCommit);
				repositoryCommit.setStash(true);
				CommitEditor.openQuiet(repositoryCommit);
			}
		};
		return new ActionContributionItem(action);
	}

}
