/*******************************************************************************
 * Copyright (c) 2005, 2008 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.core.resources.mapping;

import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;

/**
 * A remote mapping context provides a model element with a view of the remote
 * state of local resources as they relate to a repository operation that is in
 * progress. A repository provider can pass an instance of this interface to a
 * model element when obtaining a set of traversals for a model element. This
 * allows the model element to query the remote state of a resource in order to
 * determine if there are resources that exist remotely but do not exist locally
 * that should be included in the traversal.
 * <p>
 * This class may be subclassed by clients.
 * </p>
 * 
 * @see ResourceMapping
 * @see ResourceMappingContext
 * @since 3.2
 */
public abstract class RemoteResourceMappingContext extends ResourceMappingContext {

	/**
	 * Refresh flag constant (bit mask value 1) indicating that the mapping will
	 * be making use of the contents of the files covered by the traversals
	 * being refreshed.
	 */
	public static final int FILE_CONTENTS_REQUIRED = 1;

	/**
	 * Refresh flag constant (bit mask value 0) indicating that no additional
	 * refresh behavior is required.
	 */
	public static final int NONE = 0;

	/**
	 * For three-way comparisons, returns an instance of IStorage in order to
	 * allow the caller to access the contents of the base resource that
	 * corresponds to the given local resource. The base of a resource is the
	 * contents of the resource before any local modifications were made. If the
	 * base file does not exist, or if this is a two-way comparison, <code>null</code> 
	 * is returned. The provided local file handle need not exist locally. A exception 
	 * is thrown if the corresponding base resource is not a file.
	 * <p>
	 * This method may be long running as a server may need to be contacted to
	 * obtain the contents of the file.
	 * </p>
	 * 
	 * @param file the local file
	 * @param monitor a progress monitor, or <code>null</code> if progress
	 * reporting is not desired
	 * @return a storage that provides access to the contents of the local
	 * resource's corresponding remote resource. If the remote file does not
	 * exist, <code>null</code> is returned
	 * @exception CoreException if the contents could not be fetched. Reasons
	 * include:
	 * <ul>
	 * <li>The server could not be contacted for some reason.
	 * <li>The corresponding remote resource is not a container (status code
	 * will be {@link IResourceStatus#RESOURCE_WRONG_TYPE}).</li>
	 * </ul>
	 */
	public abstract IStorage fetchBaseContents(IFile file, IProgressMonitor monitor) throws CoreException;

	/**
	 * Returns the members of the base resource corresponding to the given container. 
	 * The container and the returned members need not exist locally and may not 
	 * include all children that exist locally. An empty list is returned if the base resource 
	 * is empty or does not exist. An exception is thrown if the base resource is not 
	 * capable of having members. This method returns <code>null</code> if
	 * the base members cannot be computed, in which case clients should call 
	 * {@link #fetchMembers(IContainer, IProgressMonitor)} which returns the 
	 * combined members for the base and remote.
	 * </p>
	 * <p>
	 * This method may be long running as a server may need to be contacted to
	 * obtain the members of the base resource.
	 * </p>
	 * <p>
	 * This default implementation always returns <code>null</code>, but subclasses 
	 * may override.
	 * </p>
	 * @param container the local container
	 * @param monitor a progress monitor, or <code>null</code> if progress
	 * reporting is not desired
	 * @return the members of the base resource corresponding to the given container
	 * @exception CoreException if the members could not be fetched. Reasons
	 * include:
	 * <ul>
	 * <li>The server could not be contacted for some reason.</li>
	 * <li>The base resource is not a container (status code
	 * will be {@link IResourceStatus#RESOURCE_WRONG_TYPE}).</li>
	 * </ul>
	 * @since 3.3
	 */
	public IResource[] fetchBaseMembers(IContainer container, IProgressMonitor monitor) throws CoreException {
		//default implementation does nothing
		//thwart compiler warning
		return null;
	}

	/**
	 * Returns the combined members of the base and remote resources corresponding 
	 * to the given container. The container need not exist locally and the result may
	 * include entries that do not exist locally and may not include all local
	 * children. An empty list is returned if the remote resource which
	 * corresponds to the container is empty or if the remote does not exist. An
	 * exception is thrown if the corresponding remote is not capable of having
	 * members.
	 * <p>
	 * This method may be long running as a server may need to be contacted to
	 * obtain the members of the container's corresponding remote resource.
	 * </p>
	 * 
	 * @param container the local container
	 * @param monitor a progress monitor, or <code>null</code> if progress
	 * reporting is not desired
	 * @return returns the combined members of the base and remote resources 
	 * corresponding to the given container.
	 * @exception CoreException if the members could not be fetched. Reasons
	 * include:
	 * <ul>
	 * <li>The server could not be contacted for some reason.</li>
	 * <li>The corresponding remote resource is not a container (status code
	 * will be {@link IResourceStatus#RESOURCE_WRONG_TYPE}).</li>
	 * </ul>
	 */
	public abstract IResource[] fetchMembers(IContainer container, IProgressMonitor monitor) throws CoreException;

	/**
	 * Returns an instance of IStorage in order to allow the caller to access
	 * the contents of the remote that corresponds to the given local resource.
	 * If the remote file does not exist, <code>null</code> is returned. The
	 * provided local file handle need not exist locally. A exception is thrown
	 * if the corresponding remote resource is not a file.
	 * <p>
	 * This method may be long running as a server may need to be contacted to
	 * obtain the contents of the file.
	 * </p>
	 * 
	 * @param file the local file
	 * @param monitor a progress monitor, or <code>null</code> if progress
	 * reporting is not desired
	 * @return a storage that provides access to the contents of the local
	 * resource's corresponding remote resource. If the remote file does not
	 * exist, <code>null</code> is returned
	 * @exception CoreException if the contents could not be fetched. Reasons
	 * include:
	 * <ul>
	 * <li>The server could not be contacted for some reason.</li>
	 * <li>The corresponding remote resource is not a container (status code
	 * will be {@link IResourceStatus#RESOURCE_WRONG_TYPE}).</li>
	 * </ul>
	 */
	public abstract IStorage fetchRemoteContents(IFile file, IProgressMonitor monitor) throws CoreException;

	/**
	 * Returns the members of the remote resource corresponding to the given container. 
	 * The container and the returned members need not exist locally and may not 
	 * include all children that exist locally. An empty list is returned if the remote resource 
	 * is empty or does not exist. An exception is thrown if the remote resource is not 
	 * capable of having members. This method returns <code>null</code> if
	 * the remote members cannot be computed, in which case clients should call 
	 * {@link #fetchMembers(IContainer, IProgressMonitor)} which returns the 
	 * combined members for the base and remote.
	 * </p>
	 * <p>
	 * This method may be long running as a server may need to be contacted to
	 * obtain the members of the remote resource.
	 * </p>
	 * <p>
	 * This default implementation always returns <code>null</code>, but subclasses 
	 * may override.
	 * </p>
	 * @param container the local container
	 * @param monitor a progress monitor, or <code>null</code> if progress
	 * reporting is not desired
	 * @return the members of the remote resource corresponding to the given container
	 * @exception CoreException if the members could not be fetched. Reasons
	 * include:
	 * <ul>
	 * <li>The server could not be contacted for some reason.</li>
	 * <li>The remote resource is not a container (status code
	 * will be {@link IResourceStatus#RESOURCE_WRONG_TYPE}).</li>
	 * </ul>
	 * @since 3.3
	 */
	public IResource[] fetchRemoteMembers(IContainer container, IProgressMonitor monitor) throws CoreException {
		//default implementation does nothing
		//thwart compiler warning
		return null;
	}

	/**
	 * Return the list of projects that apply to this context.
	 * In other words, the context is only capable of querying the
	 * remote state for projects that are contained in the 
	 * returned list.
	 * @return the list of projects that apply to this context
	 */
	public abstract IProject[] getProjects();

	/**
	 * For three-way comparisons, this method indicates whether local
	 * modifications have been made to the given resource. For two-way
	 * comparisons, calling this method has the same effect as calling
	 * {@link #hasRemoteChange(IResource, IProgressMonitor)}.
	 * 
	 * @param resource the resource being tested
	 * @param monitor a progress monitor
	 * @return whether the resource contains local modifications
	 * @exception CoreException if the contents could not be compared. Reasons
	 * include:
	 * <ul>
	 * <li>The server could not be contacted for some reason.</li>
	 * <li>The corresponding remote resource is not a container (status code
	 * will be {@link IResourceStatus#RESOURCE_WRONG_TYPE}).</li>
	 * </ul>
	 */
	public abstract boolean hasLocalChange(IResource resource, IProgressMonitor monitor) throws CoreException;

	/**
	 * For two-way comparisons, return whether the contents of the corresponding
	 * remote differs from the content of the local file in the context of the
	 * current operation. By this we mean that this method will return
	 * <code>true</code> if the remote contents differ from the local
	 * contents.
	 * <p>
	 * For three-way comparisons, return whether the contents of the
	 * corresponding remote differ from the contents of the base. In other
	 * words, this method returns <code>true</code> if the corresponding
	 * remote has changed since the last time the local resource was updated
	 * with the remote contents.
	 * <p>
	 * For two-way comparisons, return <code>true</code> if the remote
	 * contents differ from the local contents. In this case, this method is
	 * equivalent to {@link #hasLocalChange(IResource, IProgressMonitor)}
	 * <p>
	 * This can be used by clients to determine if they need to fetch the remote
	 * contents in order to determine if the resources that constitute the model
	 * element are different in the remote location. If the local file exists
	 * and the remote file does not, or the remote file exists and the local
	 * does not then the contents will be said to differ (i.e. <code>true</code>
	 * is returned). Also, implementors will most likely use a timestamp based
	 * comparison to determine if the contents differ. This may lead to a
	 * situation where <code>true</code> is returned but the actual contents
	 * do not differ. Clients must be prepared handle this situation.
	 * </p>
	 * 
	 * @param resource the local resource
	 * @param monitor a progress monitor, or <code>null</code> if progress
	 * reporting is not desired
	 * @return whether the contents of the corresponding remote differ from the
	 * base.
	 * @exception CoreException if the contents could not be compared. Reasons
	 * include:
	 * <ul>
	 * <li>The server could not be contacted for some reason.</li>
	 * <li>The corresponding remote resource is not a container (status code
	 * will be {@link IResourceStatus#RESOURCE_WRONG_TYPE}).</li>
	 * </ul>
	 */
	public abstract boolean hasRemoteChange(IResource resource, IProgressMonitor monitor) throws CoreException;

	/**
	 * Return <code>true</code> if the context is associated with an operation
	 * that is using a three-way comparison and <code>false</code> if it is
	 * using a two-way comparison.
	 * 
	 * @return whether the context is a three-way or two-way
	 */
	public abstract boolean isThreeWay();

	/**
	 * Refresh the known remote state for any resources covered by the given
	 * traversals. Clients who require the latest remote state should invoke
	 * this method before invoking any others of the class. Mappings can use
	 * this method as a hint to the context provider of which resources will be
	 * required for the mapping to generate the proper set of traversals.
	 * <p>
	 * Note that this is really only a hint to the context provider. It is up to
	 * implementors to decide, based on the provided traversals, how to
	 * efficiently perform the refresh. In the ideal case, calls to
	 * {@link #hasRemoteChange(IResource, IProgressMonitor)} and 
	 * {@link #fetchMembers} would not need to contact the server after a call to a 
	 * refresh with appropriate traversals.  Also, ideally, if 
	 * {@link #FILE_CONTENTS_REQUIRED} is on of the flags, then the contents 
	 * for these files will be cached as efficiently as possible so that calls to 
	 * {@link #fetchRemoteContents} will also not need to contact the server. This 
	 * may not be possible for all context providers, so clients cannot assume that 
	 * the above mentioned methods will not be long running. It is still advisable 
	 * for clients to call {@link #refresh} with as much details as possible since, in 
	 * the case where a provider is optimized, performance will be much better.
	 * </p>
	 * 
	 * @param traversals the resource traversals that indicate which resources
	 * are to be refreshed
	 * @param flags additional refresh behavior. For instance, if
	 * {@link #FILE_CONTENTS_REQUIRED} is one of the flags, this indicates
	 * that the client will be accessing the contents of the files covered by
	 * the traversals. {@link #NONE} should be used when no additional
	 * behavior is required
	 * @param monitor a progress monitor, or <code>null</code> if progress
	 * reporting is not desired
	 * @exception CoreException if the refresh fails. Reasons include:
	 * <ul>
	 * <li>The server could not be contacted for some reason. </li>
	 * </ul>
	 */
	public abstract void refresh(ResourceTraversal[] traversals, int flags, IProgressMonitor monitor) throws CoreException;
}
