/*******************************************************************************
 * Copyright (C) 2011, Bernard Leach <leachbj@bouncycastle.org>
 * Copyright (C) 2011, Dariusz Luksza <dariusz@luksza.org>
 *
 * 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.io.IOException;
import java.util.Collections;

import org.eclipse.compare.ITypedElement;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.egit.core.project.RepositoryMapping;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.UIText;
import org.eclipse.egit.ui.internal.CompareUtils;
import org.eclipse.egit.ui.internal.GitCompareFileRevisionEditorInput;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.IndexDiff;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.handlers.HandlerUtil;

/**
 * Compares the index content of a file with the version of the file in
 * the HEAD commit.
 */
public class CompareIndexWithHeadActionHandler extends RepositoryActionHandler {
	public Object execute(ExecutionEvent event) throws ExecutionException {
		final Repository repository = getRepository(true, event);
		// assert all resources map to the same repository
		if (repository == null)
			return null;
		final IResource[] resources = getSelectedResources(event);
		final IFile baseFile = (IFile) resources[0];
		final String gitPath = RepositoryMapping.getMapping(baseFile)
				.getRepoRelativePath(baseFile);
		ITypedElement base;

		ITypedElement next;
		try {
			base = CompareUtils.getHeadTypedElement(baseFile);
			Ref head = repository.getRef(Constants.HEAD);
			RevWalk rw = new RevWalk(repository);
			RevCommit commit = rw.parseCommit(head.getObjectId());

			next = CompareUtils.getFileRevisionTypedElement(gitPath,
					commit, repository);
		} catch (IOException e) {
			Activator.handleError(e.getMessage(), e, true);
			return null;
		}

		final GitCompareFileRevisionEditorInput in = new GitCompareFileRevisionEditorInput(
				base, next, null);

		IWorkbenchPage workBenchPage = HandlerUtil.getActiveWorkbenchWindowChecked(event).getActivePage();
		CompareUtils.openInCompare(workBenchPage, in);

		return null;
	}

	@Override
	public boolean isEnabled() {
		IStructuredSelection selection = getSelection();
		if (selection.size() != 1)
			return false;

		IResource resource = (IResource) getAdapter(selection.getFirstElement(), IResource.class);
		// action is only working on files. Avoid calculation
		// of unnecessary expensive IndexDiff on a folder
		if (resource == null || !(resource instanceof IFile))
			return false;

		Repository repository = getRepository();
		if (repository == null)
			return false;

		return isStaged(repository, resource);
	}

	private Object getAdapter(Object adaptable, Class c) {
		if (c.isInstance(adaptable))
			return adaptable;
		if (adaptable instanceof IAdaptable) {
			IAdaptable a = (IAdaptable) adaptable;
			Object adapter = a.getAdapter(c);
			if (c.isInstance(adapter))
				return adapter;
		}
		return null;
	}

	private boolean isStaged(Repository repository,
			IResource resource) {
		String resRelPath = RepositoryMapping.getMapping(resource).getRepoRelativePath(resource);

		// This action at the moment only works for files anyway
		if (resRelPath == null || resRelPath.length() == 0) {
			return false;
		}

		try {
			FileTreeIterator fileTreeIterator = new FileTreeIterator(repository);
			IndexDiff indexDiff = new IndexDiff(repository, Constants.HEAD,
					fileTreeIterator);
			indexDiff.setFilter(PathFilterGroup.createFromStrings(Collections.singletonList(resRelPath)));
			indexDiff.diff();

			return indexDiff.getAdded().contains(resRelPath) || indexDiff.getChanged().contains(resRelPath)
					|| indexDiff.getRemoved().contains(resRelPath);
		} catch (IOException e) {
			Activator.error(NLS.bind(UIText.GitHistoryPage_errorLookingUpPath,
					resource.getFullPath().toString()), e);
			return false;
		}
	}
}

@@ -1158,16 +1158,105 @@
 rInput;%0A
+import org.eclipse.egit.ui.internal.GitCompareFileRevisionEditorInput.EmptyTypedElement;%0A
 import o
@@ -2535,16 +2535,175 @@
 .HEAD);%0A
+%09%09%09if (head == null %7C%7C head.getObjectId() == null)%0A%09%09%09%09// Initial import, not yet a HEAD commit%0A%09%09%09%09next = new EmptyTypedElement(%22%22); //$NON-NLS-1$%0A%09%09%09else %7B%0A%09
 %09%09%09RevWa
@@ -2735,16 +2735,17 @@
 itory);%0A
+%09
 %09%09%09RevCo
@@ -2798,16 +2798,17 @@
 ));%0A%0A%09%09%09
+%09
 next = C
@@ -2852,24 +2852,25 @@
 nt(gitPath,%0A
+%09
 %09%09%09%09%09commit,
@@ -2883,16 +2883,21 @@
 itory);%0A
+%09%09%09%7D%0A
 %09%09%7D catc

Fix NPE when comparing index with HEAD for initial commit