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.codemanipulation;
  
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  
  import org.eclipse.wst.jsdt.core.IJavaScriptElement;
  import org.eclipse.wst.jsdt.core.IJavaScriptProject;
  import org.eclipse.wst.jsdt.core.dom.AbstractTypeDeclaration;
  import org.eclipse.wst.jsdt.core.dom.JavaScriptUnit;
  import org.eclipse.wst.jsdt.core.dom.IBinding;
  import org.eclipse.wst.jsdt.core.dom.ITypeBinding;
  import org.eclipse.wst.jsdt.core.dom.Modifier;
  import org.eclipse.wst.jsdt.core.dom.Name;
  import org.eclipse.wst.jsdt.core.dom.rewrite.ImportRewrite;
  import org.eclipse.wst.jsdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
  import org.eclipse.wst.jsdt.internal.corext.dom.ScopeAnalyzer;
  import org.eclipse.wst.jsdt.internal.corext.util.JavaModelUtil;
  
  /**
  *
  * Provisional API: This class/interface is part of an interim API that is still under development and expected to
  * change significantly before reaching stability. It is being made available at this early stage to solicit feedback
  * from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken
  * (repeatedly) as the API evolves.
  */
  public class ContextSensitiveImportRewriteContext extends ImportRewriteContext {
  	
  	private final JavaScriptUnit fCompilationUnit;
  	private final int fPosition;
  	private IBinding[] fDeclarationsInScope;
  	private Name[] fImportedNames;
  	private final ImportRewrite fImportRewrite;
  	
  	public ContextSensitiveImportRewriteContext(JavaScriptUnit compilationUnit, int position, ImportRewrite importRewrite) {
  		fCompilationUnit= compilationUnit;
  		fPosition= position;
  		fImportRewrite= importRewrite;
  		fDeclarationsInScope= null;
  		fImportedNames= null;
  	}
  
  	public int findInContext(String qualifier, String name, int kind) {
  		int defaultResult= fImportRewrite.getDefaultImportRewriteContext().findInContext(qualifier, name, kind);
  		if (defaultResult != ImportRewriteContext.RES_NAME_UNKNOWN)
  			return defaultResult;
  		
  		if (fImportRewrite.isImportMatchesType()) {
  			IBinding[] declarationsInScope = getDeclarationsInScope();
  			for (int i = 0; i < declarationsInScope.length; i++) {
  				if (declarationsInScope[i] instanceof ITypeBinding) {
  					ITypeBinding typeBinding = (ITypeBinding) declarationsInScope[i];
  					if (isSameType(typeBinding, qualifier, name)) {
  						return RES_NAME_FOUND;
  					} else if (isConflicting(typeBinding, name)) {
  						return RES_NAME_CONFLICT;
  					}
  				} else if (declarationsInScope[i] != null) {
  					if (isConflicting(declarationsInScope[i], name)) {
  						return RES_NAME_CONFLICT;
  					}
  				}
  			}
  			Name[] names = getImportedNames();
  			for (int i = 0; i < names.length; i++) {
  				IBinding binding = names[i].resolveBinding();
  				if (binding instanceof ITypeBinding) {
  					ITypeBinding typeBinding = (ITypeBinding) binding;
  					if (isConflictingType(typeBinding, qualifier, name)) {
  						return RES_NAME_CONFLICT;
  					}
  				}
  			}
  			List list = fCompilationUnit.types();
  			for (Iterator iter = list.iterator(); iter.hasNext();) {
  				AbstractTypeDeclaration type = (AbstractTypeDeclaration) iter
  						.next();
  				ITypeBinding binding = type.resolveBinding();
  				if (binding != null) {
  					if (isSameType(binding, qualifier, name)) {
  						return RES_NAME_FOUND;
  					} else {
  						ITypeBinding decl = containingDeclaration(binding,
  								qualifier, name);
  						while (decl != null && !decl.equals(binding)) {
  							int modifiers = decl.getModifiers();
  							if (Modifier.isPrivate(modifiers))
  								return RES_NAME_CONFLICT;
  							decl = decl.getDeclaringClass();
  						}
  					}
  				}
  			}
  		}
  		String[] addedImports= fImportRewrite.getAddedImports();
  		String qualifiedName= JavaModelUtil.concatenateName(qualifier, name);
  		for (int i= 0; i < addedImports.length; i++) {
  			String addedImport= addedImports[i];
  			if (qualifiedName.equals(addedImport)) {
  				return RES_NAME_FOUND;
  			} else {
  				if (isConflicting(name, addedImport))
  					return RES_NAME_CONFLICT;
  			}
  		}
  		
  //		if (qualifier.equals("java.lang")) { //$NON-NLS-1$
  //			//No explicit import statement required
  //			IJavaScriptElement parent= fCompilationUnit.getJavaElement().getParent();
  //			if (parent instanceof IPackageFragment) {
  //				IPackageFragment packageFragment= (IPackageFragment)parent;
  //				try {
  //					IJavaScriptUnit[] compilationUnits= packageFragment.getCompilationUnits();
  //					for (int i= 0; i < compilationUnits.length; i++) {
  //						IJavaScriptUnit cu= compilationUnits[i];
  //						IType[] allTypes= cu.getAllTypes();
  //						for (int j= 0; j < allTypes.length; j++) {
  //							IType type= allTypes[j];
  //							String packageTypeName= type.getFullyQualifiedName();
  //							if (isConflicting(name, packageTypeName))
  //								return RES_NAME_CONFLICT;
  //						}
  //					}
  //				} catch (JavaScriptModelException e) {
  //				}
  //			}
  //		}
  		
  		return RES_NAME_UNKNOWN;
  	}
  
  	private boolean isConflicting(String name, String importt) {
  		int index= importt.lastIndexOf('.');
  		String importedName;
  		if (index == -1) {
  			importedName= importt;
  		} else {
  			importedName= importt.substring(index + 1, importt.length());
  		}
  		if (importedName.equals(name)) {
  			return true;
  		}
  		return false;
  	}
  	
  	private ITypeBinding containingDeclaration(ITypeBinding binding, String qualifier, String name) {
  		ITypeBinding[] declaredTypes= binding.getDeclaredTypes();
  		for (int i= 0; i < declaredTypes.length; i++) {
  			ITypeBinding childBinding= declaredTypes[i];
  			if (isSameType(childBinding, qualifier, name)) {
  				return childBinding;
  			} else {
  				ITypeBinding result= containingDeclaration(childBinding, qualifier, name);
  				if (result != null) {
  					return result;
  				}
  			}
  		}
  		return null;
  	}
  
  	private boolean isConflicting(IBinding binding, String name) {
  		return binding.getName().equals(name);
  	}
  
  	private boolean isSameType(ITypeBinding binding, String qualifier, String name) {
  		String qualifiedName= JavaModelUtil.concatenateName(qualifier, name);
  		return binding.getQualifiedName().equals(qualifiedName);
  	}
  	
  	private boolean isConflictingType(ITypeBinding binding, String qualifier, String name) {
  		binding= binding.getTypeDeclaration();
  		return !isSameType(binding, qualifier, name) && isConflicting(binding, name);
  	}
  	
  	private IBinding[] getDeclarationsInScope() {
  		if (fDeclarationsInScope == null) {
  			ScopeAnalyzer analyzer= new ScopeAnalyzer(fCompilationUnit);
  			fDeclarationsInScope= analyzer.getDeclarationsInScope(fPosition, ScopeAnalyzer.METHODS | ScopeAnalyzer.TYPES | ScopeAnalyzer.VARIABLES);
  		}
  		return fDeclarationsInScope;
  	}
  	
  	private Name[] getImportedNames() {
  		if (fImportedNames == null) {
  			IJavaScriptProject project= null;
  			IJavaScriptElement javaElement= fCompilationUnit.getJavaElement();
  			if (javaElement != null)
  				project= javaElement.getJavaScriptProject();
  			
  			List imports= new ArrayList();
  			ImportReferencesCollector.collect(fCompilationUnit, project, null, imports, null);
  			fImportedNames= (Name[])imports.toArray(new Name[imports.size()]);
  		}
  		return fImportedNames;
  	}
  }
  