content: /*******************************************************************************
   * Copyright (c) 2000, 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.wst.jsdt.internal.corext.util;
  
  import java.util.ArrayList;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Set;
  
  import org.eclipse.core.resources.IContainer;
  import org.eclipse.core.resources.IFile;
  import org.eclipse.core.resources.IProject;
  import org.eclipse.core.resources.IResource;
  import org.eclipse.core.resources.IResourceVisitor;
  import org.eclipse.core.resources.mapping.RemoteResourceMappingContext;
  import org.eclipse.core.resources.mapping.ResourceMapping;
  import org.eclipse.core.resources.mapping.ResourceMappingContext;
  import org.eclipse.core.resources.mapping.ResourceTraversal;
  import org.eclipse.core.runtime.Assert;
  import org.eclipse.core.runtime.CoreException;
  import org.eclipse.core.runtime.IProgressMonitor;
  import org.eclipse.core.runtime.NullProgressMonitor;
  import org.eclipse.wst.jsdt.core.IClassFile;
  import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
  import org.eclipse.wst.jsdt.core.IJavaScriptElement;
  import org.eclipse.wst.jsdt.core.IJavaScriptModel;
  import org.eclipse.wst.jsdt.core.IJavaScriptProject;
  import org.eclipse.wst.jsdt.core.IPackageFragment;
  import org.eclipse.wst.jsdt.core.IPackageFragmentRoot;
  import org.eclipse.wst.jsdt.core.IType;
  import org.eclipse.wst.jsdt.core.JavaScriptModelException;
  import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
  import org.eclipse.wst.jsdt.internal.ui.browsing.LogicalPackage;
  import org.eclipse.wst.jsdt.internal.ui.model.JavaModelProvider;
  
  /**
   * An abstract super class to describe mappings from a Java element to a
   * set of resources. The class also provides factory methods to create
   * resource mappings.
   * 
   * 
   */
  public abstract class JavaElementResourceMapping extends ResourceMapping {
  	
  	protected JavaElementResourceMapping() {
  	}
  	
  	public IJavaScriptElement getJavaElement() {
  		Object o= getModelObject();
  		if (o instanceof IJavaScriptElement)
  			return (IJavaScriptElement)o;
  		return null;
  	}
  	
  	public boolean equals(Object obj) {
  		if (!(obj instanceof JavaElementResourceMapping))
  			return false;
  		return getJavaElement().equals(((JavaElementResourceMapping)obj).getJavaElement());
  	}
  	
  	public int hashCode() {
  		IJavaScriptElement javaElement= getJavaElement();
  		if (javaElement == null)
  			return super.hashCode();
  		
  		return javaElement.hashCode();
  	}
  	
  	public String getModelProviderId() {
  		return JavaModelProvider.JAVA_MODEL_PROVIDER_ID;
  	}
  	
  	public boolean contains(ResourceMapping mapping) {
  		if (mapping instanceof JavaElementResourceMapping) {
  			JavaElementResourceMapping javaMapping = (JavaElementResourceMapping) mapping;
  			IJavaScriptElement element = getJavaElement();
  			IJavaScriptElement other = javaMapping.getJavaElement();
  			if (other != null && element != null)
  				return element.getPath().isPrefixOf(other.getPath());
  		}
  		return false;
  	}
  	
  	//---- the factory code ---------------------------------------------------------------
  	
  	private static final class JavaModelResourceMapping extends JavaElementResourceMapping {
  		private final IJavaScriptModel fJavaModel;
  		private JavaModelResourceMapping(IJavaScriptModel model) {
  			Assert.isNotNull(model);
  			fJavaModel= model;
  		}
  		public Object getModelObject() {
  			return fJavaModel;
  		}
  		public IProject[] getProjects() {
  			IJavaScriptProject[] projects= null;
  			try {
  				projects= fJavaModel.getJavaScriptProjects();
  			} catch (JavaScriptModelException e) {
  				JavaScriptPlugin.log(e);
  				return new IProject[0];
  			}
  			IProject[] result= new IProject[projects.length];
  			for (int i= 0; i < projects.length; i++) {
  				result[i]= projects[i].getProject();
  			}
  			return result;
  		}
  		public ResourceTraversal[] getTraversals(ResourceMappingContext context, IProgressMonitor monitor) throws CoreException {
  			IJavaScriptProject[] projects= fJavaModel.getJavaScriptProjects();
  			ResourceTraversal[] result= new ResourceTraversal[projects.length];
  			for (int i= 0; i < projects.length; i++) {
  				result[i]= new ResourceTraversal(new IResource[] {projects[i].getProject()}, IResource.DEPTH_INFINITE, 0);
  			}
  			return result;
  		}
  	}
  	
  	private static final class JavaProjectResourceMapping extends JavaElementResourceMapping {
  		private final IJavaScriptProject fProject;
  		private JavaProjectResourceMapping(IJavaScriptProject project) {
  			Assert.isNotNull(project);
  			fProject= project;
  		}
  		public Object getModelObject() {
  			return fProject;
  		}
  		public IProject[] getProjects() {
  			return new IProject[] {fProject.getProject() };
  		}
  		public ResourceTraversal[] getTraversals(ResourceMappingContext context, IProgressMonitor monitor) throws CoreException {
  			return new ResourceTraversal[] {
  				new ResourceTraversal(new IResource[] {fProject.getProject()}, IResource.DEPTH_INFINITE, 0)
  			};
  		}
  	}
  	
  	private static final class PackageFragementRootResourceMapping extends JavaElementResourceMapping {
  		private final IPackageFragmentRoot fRoot;
  		private PackageFragementRootResourceMapping(IPackageFragmentRoot root) {
  			Assert.isNotNull(root);
  			fRoot= root;
  		}
  		public Object getModelObject() {
  			return fRoot;
  		}
  		public IProject[] getProjects() {
  			return new IProject[] {fRoot.getJavaScriptProject().getProject() };
  		}
  		public ResourceTraversal[] getTraversals(ResourceMappingContext context, IProgressMonitor monitor) throws CoreException {
  			return new ResourceTraversal[] {
  				new ResourceTraversal(new IResource[] {fRoot.getResource()}, IResource.DEPTH_INFINITE, 0)
  			};
  		}
  	}
  	
  	private static final class LocalPackageFragementTraversal extends ResourceTraversal {
  		private final IPackageFragment fPack;
  		public LocalPackageFragementTraversal(IPackageFragment pack) throws CoreException {
  			super(new IResource[] {pack.getResource()}, IResource.DEPTH_ONE, 0);
  			fPack= pack;
  		}
  		public void accept(IResourceVisitor visitor) throws CoreException {
  			IFile[] files= getPackageContent(fPack);
  			final IResource resource= fPack.getResource();
  			if (resource != null)
  				visitor.visit(resource);
  			for (int i= 0; i < files.length; i++) {
  				visitor.visit(files[i]);
  			}
  		}
  	}
  	
  	private static final class PackageFragmentResourceMapping extends JavaElementResourceMapping {
  		private final IPackageFragment fPack;
  		private PackageFragmentResourceMapping(IPackageFragment pack) {
  			Assert.isNotNull(pack);
  			fPack= pack;
  		}
  		public Object getModelObject() {
  			return fPack;
  		}
  		public IProject[] getProjects() {
  			return new IProject[] { fPack.getJavaScriptProject().getProject() };
  		}
  		public ResourceTraversal[] getTraversals(ResourceMappingContext context, IProgressMonitor monitor) throws CoreException {
  			if (context instanceof RemoteResourceMappingContext) {
  				return new ResourceTraversal[] {
  					new ResourceTraversal(new IResource[] {fPack.getResource()}, IResource.DEPTH_ONE, 0)
  				};
  			} else {
  				return new ResourceTraversal[] { new LocalPackageFragementTraversal(fPack) };
  			}
  		}
  		public void accept(ResourceMappingContext context, IResourceVisitor visitor, IProgressMonitor monitor) throws CoreException {
  			if (context instanceof RemoteResourceMappingContext) {
  				super.accept(context, visitor, monitor);
  			} else {
  				// We assume a local context.
  				IFile[] files= getPackageContent(fPack);
  				if (monitor == null)
  					monitor= new NullProgressMonitor();
  				monitor.beginTask("", files.length + 1); //$NON-NLS-1$
  				final IResource resource= fPack.getResource();
  				if (resource != null)
  					visitor.visit(resource);
  				monitor.worked(1);
  				for (int i= 0; i < files.length; i++) {
  					visitor.visit(files[i]);
  					monitor.worked(1);
  				}
  			}
  		}
  	}
  	
  	private static IFile[] getPackageContent(IPackageFragment pack) throws CoreException {
  		List result= new ArrayList();
  		IContainer container= (IContainer)pack.getResource();
  		if (container != null) {
  			IResource[] members= container.members();
  			for (int m= 0; m < members.length; m++) {
  				IResource member= members[m];
  				if (member instanceof IFile) {
  					IFile file= (IFile)member;
  					if ("class".equals(file.getFileExtension()) && file.isDerived()) //$NON-NLS-1$
  						continue;
  					result.add(member);
  				}
  			}
  		}
  		return (IFile[])result.toArray(new IFile[result.size()]);
  	}
  	
  	
  	private static final class CompilationUnitResourceMapping extends JavaElementResourceMapping {
  		private final IJavaScriptUnit fUnit;
  		private CompilationUnitResourceMapping(IJavaScriptUnit unit) {
  			Assert.isNotNull(unit);
  			fUnit= unit;
  		}
  		public Object getModelObject() {
  			return fUnit;
  		}
  		public IProject[] getProjects() {
  			return new IProject[] {fUnit.getJavaScriptProject().getProject() };
  		}
  		public ResourceTraversal[] getTraversals(ResourceMappingContext context, IProgressMonitor monitor) throws CoreException {
  			return new ResourceTraversal[] {
  				new ResourceTraversal(new IResource[] {fUnit.getResource()}, IResource.DEPTH_ONE, 0)
  			};
  		}
  	}
  
  	private static final class ClassFileResourceMapping extends JavaElementResourceMapping {
  		private final IClassFile fClassFile;
  		private ClassFileResourceMapping(IClassFile classFile) {
  			fClassFile= classFile;
  		}
  		public Object getModelObject() {
  			return fClassFile;
  		}
  		public IProject[] getProjects() {
  			return new IProject[] { fClassFile.getJavaScriptProject().getProject() };
  		}
  		public ResourceTraversal[] getTraversals(ResourceMappingContext context, IProgressMonitor monitor) throws CoreException {
  			return new ResourceTraversal[] {
  				new ResourceTraversal(new IResource[] {fClassFile.getResource()}, IResource.DEPTH_ONE, 0)
  			};
  		}
  	}
  	
  	private static final class LogicalPackageResourceMapping extends ResourceMapping {
  		private final IPackageFragment[] fFragments;
  		private LogicalPackageResourceMapping(IPackageFragment[] fragments) {
  			fFragments= fragments;
  		}
  		public Object getModelObject() {
  			return fFragments;
  		}
  		public IProject[] getProjects() {
  			Set result= new HashSet();
  			for (int i= 0; i < fFragments.length; i++) {
  				result.add(fFragments[i].getJavaScriptProject().getProject());
  			}
  			return (IProject[])result.toArray(new IProject[result.size()]);
  		}
  		public ResourceTraversal[] getTraversals(ResourceMappingContext context, IProgressMonitor monitor) throws CoreException {
  			List result= new ArrayList();
  			if (context instanceof RemoteResourceMappingContext) {
  				for (int i= 0; i < fFragments.length; i++) {
  					result.add(new ResourceTraversal(
  						new IResource[] {fFragments[i].getResource()}, IResource.DEPTH_ONE, 0));
  				}
  			} else {
  				for (int i= 0; i < fFragments.length; i++) {
  					result.add(new LocalPackageFragementTraversal(fFragments[i]));
  				}
  			}
  			return (ResourceTraversal[])result.toArray(new ResourceTraversal[result.size()]);
  		}
  		
  		public String getModelProviderId() {
  			return JavaModelProvider.JAVA_MODEL_PROVIDER_ID;
  		}
  	}
  	
  	public static ResourceMapping create(IJavaScriptElement element) {
  		switch (element.getElementType()) {
  			case IJavaScriptElement.TYPE:
  				return create((IType)element);
  			case IJavaScriptElement.JAVASCRIPT_UNIT:
  				return create((IJavaScriptUnit)element);
  			case IJavaScriptElement.CLASS_FILE:
  				return create((IClassFile)element);
  			case IJavaScriptElement.PACKAGE_FRAGMENT:
  				return create((IPackageFragment)element);
  			case IJavaScriptElement.PACKAGE_FRAGMENT_ROOT:
  				return create((IPackageFragmentRoot)element);
  			case IJavaScriptElement.JAVASCRIPT_PROJECT:
  				return create((IJavaScriptProject)element);
  			case IJavaScriptElement.JAVASCRIPT_MODEL:
  				return create((IJavaScriptModel)element);
  			default:
  				return null;
  		}		
  		
  	}
  
  	public static ResourceMapping create(final IJavaScriptModel model) {
  		return new JavaModelResourceMapping(model);
  	}
  	
  	public static ResourceMapping create(final IJavaScriptProject project) {
  		return new JavaProjectResourceMapping(project);
  	}
  	
  	public static ResourceMapping create(final IPackageFragmentRoot root) {
  		if (root.isExternal())
  			return null;
  		return new PackageFragementRootResourceMapping(root);
  	}
  	
  	public static ResourceMapping create(final IPackageFragment pack) {
  		// test if in an archive
  		IPackageFragmentRoot root= (IPackageFragmentRoot)pack.getAncestor(IJavaScriptElement.PACKAGE_FRAGMENT_ROOT);
  		if (!root.isArchive()) {
  			return new PackageFragmentResourceMapping(pack);
  		}
  		return null;
  	}
  	
  	public static ResourceMapping create(IJavaScriptUnit unit) {
  		if (unit == null)
  			return null;
  		return new CompilationUnitResourceMapping(unit.getPrimary());
  	}
  	
  	public static ResourceMapping create(IClassFile classFile) {
  		// test if in a archive
  		IPackageFragmentRoot root= (IPackageFragmentRoot)classFile.getAncestor(IJavaScriptElement.PACKAGE_FRAGMENT_ROOT);
  		if (!root.isArchive()) {
  			return new ClassFileResourceMapping(classFile);
  		}
  		return null;
  	}
  	
  	public static ResourceMapping create(IType type) {
  		// top level types behave like the CU
  		IJavaScriptElement parent= type.getParent();
  		if (parent instanceof IJavaScriptUnit) {
  			return create((IJavaScriptUnit)parent);
  		}
  		return null;
  	}
  	
  	public static ResourceMapping create(LogicalPackage logicalPackage) {
  		IPackageFragment[] fragments= logicalPackage.getFragments();
  		List toProcess= new ArrayList(fragments.length);
  		for (int i= 0; i < fragments.length; i++) {
  			// only add if not part of an archive
  			IPackageFragmentRoot root= (IPackageFragmentRoot)fragments[i].getAncestor(IJavaScriptElement.PACKAGE_FRAGMENT_ROOT);
  			if (!root.isArchive()) {
  				toProcess.add(fragments[i]);
  			}
  		}
  		if (toProcess.size() == 0)
  			return null;
  		return new LogicalPackageResourceMapping((IPackageFragment[])toProcess.toArray(new IPackageFragment[toProcess.size()]));
  	}
  }
  