/*******************************************************************************
 * 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
 *     Matt Chapman, mpchapman@gmail.com - 89977 Make JDT .java agnostic
 *******************************************************************************/
package org.eclipse.wst.jsdt.internal.corext.refactoring.rename;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IProduct;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.GroupCategory;
import org.eclipse.ltk.core.refactoring.GroupCategorySet;
import org.eclipse.ltk.core.refactoring.IResourceMapper;
import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.RefactoringStatusContext;
import org.eclipse.ltk.core.refactoring.TextChange;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
import org.eclipse.ltk.core.refactoring.participants.IParticipantDescriptorFilter;
import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
import org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor;
import org.eclipse.ltk.core.refactoring.participants.RenameArguments;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.wst.jsdt.core.Flags;
import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
import org.eclipse.wst.jsdt.core.IField;
import org.eclipse.wst.jsdt.core.IImportDeclaration;
import org.eclipse.wst.jsdt.core.IJavaScriptElement;
import org.eclipse.wst.jsdt.core.IJavaScriptProject;
import org.eclipse.wst.jsdt.core.ILocalVariable;
import org.eclipse.wst.jsdt.core.IMember;
import org.eclipse.wst.jsdt.core.IFunction;
import org.eclipse.wst.jsdt.core.IPackageFragment;
import org.eclipse.wst.jsdt.core.ISourceRange;
import org.eclipse.wst.jsdt.core.IType;
import org.eclipse.wst.jsdt.core.ITypeHierarchy;
import org.eclipse.wst.jsdt.core.JavaScriptCore;
import org.eclipse.wst.jsdt.core.JavaScriptModelException;
import org.eclipse.wst.jsdt.core.Signature;
import org.eclipse.wst.jsdt.core.dom.AST;
import org.eclipse.wst.jsdt.core.dom.ASTVisitor;
import org.eclipse.wst.jsdt.core.dom.JavaScriptUnit;
import org.eclipse.wst.jsdt.core.dom.FunctionDeclaration;
import org.eclipse.wst.jsdt.core.dom.Modifier;
import org.eclipse.wst.jsdt.core.dom.TypeDeclaration;
import org.eclipse.wst.jsdt.core.refactoring.IJavaScriptElementMapper;
import org.eclipse.wst.jsdt.core.refactoring.IJavaScriptRefactorings;
import org.eclipse.wst.jsdt.core.refactoring.RenameTypeArguments;
import org.eclipse.wst.jsdt.core.refactoring.descriptors.JavaScriptRefactoringDescriptor;
import org.eclipse.wst.jsdt.core.refactoring.descriptors.RenameJavaScriptElementDescriptor;
import org.eclipse.wst.jsdt.core.search.IJavaScriptSearchConstants;
import org.eclipse.wst.jsdt.core.search.IJavaScriptSearchScope;
import org.eclipse.wst.jsdt.core.search.SearchMatch;
import org.eclipse.wst.jsdt.core.search.SearchPattern;
import org.eclipse.wst.jsdt.core.search.TypeReferenceMatch;
import org.eclipse.wst.jsdt.internal.corext.refactoring.Checks;
import org.eclipse.wst.jsdt.internal.corext.refactoring.JDTRefactoringDescriptor;
import org.eclipse.wst.jsdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
import org.eclipse.wst.jsdt.internal.corext.refactoring.JavaRefactoringArguments;
import org.eclipse.wst.jsdt.internal.corext.refactoring.RefactoringAvailabilityTester;
import org.eclipse.wst.jsdt.internal.corext.refactoring.RefactoringCoreMessages;
import org.eclipse.wst.jsdt.internal.corext.refactoring.RefactoringScopeFactory;
import org.eclipse.wst.jsdt.internal.corext.refactoring.RefactoringSearchEngine;
import org.eclipse.wst.jsdt.internal.corext.refactoring.SearchResultGroup;
import org.eclipse.wst.jsdt.internal.corext.refactoring.base.JavaStatusContext;
import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.RenameCompilationUnitChange;
import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.RenameResourceChange;
import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.TextChangeCompatibility;
import org.eclipse.wst.jsdt.internal.corext.refactoring.code.ScriptableRefactoring;
import org.eclipse.wst.jsdt.internal.corext.refactoring.participants.JavaProcessors;
import org.eclipse.wst.jsdt.internal.corext.refactoring.tagging.IQualifiedNameUpdating;
import org.eclipse.wst.jsdt.internal.corext.refactoring.tagging.IReferenceUpdating;
import org.eclipse.wst.jsdt.internal.corext.refactoring.tagging.ISimilarDeclarationUpdating;
import org.eclipse.wst.jsdt.internal.corext.refactoring.tagging.ITextUpdating;
import org.eclipse.wst.jsdt.internal.corext.refactoring.util.Changes;
import org.eclipse.wst.jsdt.internal.corext.refactoring.util.JavaElementUtil;
import org.eclipse.wst.jsdt.internal.corext.refactoring.util.QualifiedNameFinder;
import org.eclipse.wst.jsdt.internal.corext.refactoring.util.QualifiedNameSearchResult;
import org.eclipse.wst.jsdt.internal.corext.refactoring.util.RefactoringASTParser;
import org.eclipse.wst.jsdt.internal.corext.refactoring.util.ResourceUtil;
import org.eclipse.wst.jsdt.internal.corext.refactoring.util.TextChangeManager;
import org.eclipse.wst.jsdt.internal.corext.util.JavaModelUtil;
import org.eclipse.wst.jsdt.internal.corext.util.JdtFlags;
import org.eclipse.wst.jsdt.internal.corext.util.Messages;
import org.eclipse.wst.jsdt.internal.corext.util.SearchUtils;
import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
import org.eclipse.wst.jsdt.internal.ui.refactoring.RefactoringSaveHelper;
import org.eclipse.wst.jsdt.ui.JavaScriptElementLabels;

public class RenameTypeProcessor extends JavaRenameProcessor implements ITextUpdating, IReferenceUpdating, IQualifiedNameUpdating, ISimilarDeclarationUpdating, IResourceMapper, IJavaScriptElementMapper {

	private static final String ATTRIBUTE_QUALIFIED= "qualified"; //$NON-NLS-1$
	private static final String ATTRIBUTE_TEXTUAL_MATCHES= "textual"; //$NON-NLS-1$
	private static final String ATTRIBUTE_PATTERNS= "patterns"; //$NON-NLS-1$
	private static final String ATTRIBUTE_SIMILAR_DECLARATIONS= "similarDeclarations"; //$NON-NLS-1$
	private static final String ATTRIBUTE_MATCHING_STRATEGY= "matchStrategy"; //$NON-NLS-1$
	
    private static final GroupCategorySet CATEGORY_TYPE_RENAME= new GroupCategorySet(new GroupCategory("org.eclipse.wst.jsdt.internal.corext.refactoring.rename.renameType.type", RefactoringCoreMessages.RenameTypeProcessor_changeCategory_type, RefactoringCoreMessages.RenameTypeProcessor_changeCategory_type_description)); //$NON-NLS-1$
    private static final GroupCategorySet CATEGORY_METHOD_RENAME= new GroupCategorySet(new GroupCategory("org.eclipse.wst.jsdt.internal.corext.refactoring.rename.renameType.method", RefactoringCoreMessages.RenameTypeProcessor_changeCategory_method, RefactoringCoreMessages.RenameTypeProcessor_changeCategory_method_description)); //$NON-NLS-1$
    private static final GroupCategorySet CATEGORY_FIELD_RENAME= new GroupCategorySet(new GroupCategory("org.eclipse.wst.jsdt.internal.corext.refactoring.rename.renameType.field", RefactoringCoreMessages.RenameTypeProcessor_changeCategory_fields, RefactoringCoreMessages.RenameTypeProcessor_changeCategory_fields_description)); //$NON-NLS-1$ 
    private static final GroupCategorySet CATEGORY_LOCAL_RENAME= new GroupCategorySet(new GroupCategory("org.eclipse.wst.jsdt.internal.corext.refactoring.rename.renameType.local", RefactoringCoreMessages.RenameTypeProcessor_changeCategory_local_variables, RefactoringCoreMessages.RenameTypeProcessor_changeCategory_local_variables_description)); //$NON-NLS-1$			
    
	private IType fType;
	private SearchResultGroup[] fReferences;
	private TextChangeManager fChangeManager;
	private QualifiedNameSearchResult fQualifiedNameSearchResult;
	
	private boolean fUpdateReferences;
	
	private boolean fUpdateTextualMatches;

	private boolean fUpdateQualifiedNames;
	private String fFilePatterns;

	public static final String IDENTIFIER= "org.eclipse.wst.jsdt.ui.renameTypeProcessor"; //$NON-NLS-1$
	
	// --- similar elements

	private boolean fUpdateSimilarElements;
	private Map/* <IJavaScriptElement, String> */fFinalSimilarElementToName= null;
	private int fRenamingStrategy;

	// Preloaded information for the UI.
	private LinkedHashMap/* <IJavaScriptElement, String> */fPreloadedElementToName= null;
	private Map/* <IJavaScriptElement, Boolean> */fPreloadedElementToSelection= null;
	private LinkedHashMap/* <IJavaScriptElement, String> */fPreloadedElementToNameDefault= null;

	// Cache information to decide whether to
	// re-update references and preload info
	private String fCachedNewName= null;
	private boolean fCachedRenameSimilarElements= false;
	private int fCachedRenamingStrategy= -1;
	private RefactoringStatus fCachedRefactoringStatus= null;

	public static final class ParticipantDescriptorFilter implements IParticipantDescriptorFilter {

		public boolean select(IConfigurationElement element, RefactoringStatus status) {
			IConfigurationElement[] params= element.getChildren(PARAM);
			for (int i= 0; i < params.length; i++) {
				IConfigurationElement param= params[i];
				if ("handlesSimilarDeclarations".equals(param.getAttribute(NAME)) && //$NON-NLS-1$
						"false".equals(param.getAttribute(VALUE))) { //$NON-NLS-1$
					return false;
				}
			}
			return true;
		}
	}

	private class NoOverrideProgressMonitor extends SubProgressMonitor {
		public NoOverrideProgressMonitor(IProgressMonitor monitor, int ticks) {
			super(monitor, ticks, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL);
		}
		public void setTaskName(String name) {
			// do nothing
		}
	}

	/**
	 * Creates a new rename type processor.
	 * @param type the type, or <code>null</code> if invoked by scripting
	 */
	public RenameTypeProcessor(IType type) {
		fType= type;
		if (type != null)
			setNewElementName(type.getElementName());
		fUpdateReferences= true; //default is yes
		fUpdateTextualMatches= false;
		fUpdateSimilarElements= false; // default is no
		fRenamingStrategy= RenamingNameSuggestor.STRATEGY_EXACT;
	}
	
	public IType getType() {
		return fType;
	}

	public String getIdentifier() {
		return IDENTIFIER;
	}
	
	public boolean isApplicable() throws CoreException {
		return RefactoringAvailabilityTester.isRenameAvailable(fType);
	}
	 
	public String getProcessorName() {
		return RefactoringCoreMessages.RenameTypeRefactoring_name;
	}
	
	protected String[] getAffectedProjectNatures() throws CoreException {
		return JavaProcessors.computeAffectedNatures(fType);
	}

	public Object[] getElements() {
		return new Object[] {fType};
	}
	
	protected RenameModifications computeRenameModifications() {
		RenameModifications result= new RenameModifications();
		result.rename(fType, new RenameTypeArguments(getNewElementName(), getUpdateReferences(), 
			getUpdateSimilarDeclarations(), getSimilarElements()), createParticipantDescriptorFilter());
		if (isPrimaryType()) {
			IJavaScriptUnit cu= fType.getJavaScriptUnit();
			String newCUName= getNewCompilationUnit().getElementName();
			result.rename(cu, new RenameArguments(newCUName, getUpdateReferences()));
		}
		return result;
	}
		
	/*
	 * Note: this is a handle-only method!
	 */
	private boolean isPrimaryType() {
		String cuName= fType.getJavaScriptUnit().getElementName();
		String typeName= fType.getElementName();
		return Checks.isTopLevel(fType) && JavaScriptCore.removeJavaScriptLikeExtension(cuName).equals(typeName);
	}
	
	//---- IRenameProcessor ----------------------------------------------
	
	public String getCurrentElementName(){
		return fType.getElementName();
	}
	
	public String getCurrentElementQualifier(){
		return JavaModelUtil.getTypeContainerName(fType);
	}
	
	public RefactoringStatus checkNewElementName(String newName){
		Assert.isNotNull(newName, "new name"); //$NON-NLS-1$
		RefactoringStatus result= Checks.checkTypeName(newName);
		if (Checks.isAlreadyNamed(fType, newName))
			result.addFatalError(RefactoringCoreMessages.RenameTypeRefactoring_choose_another_name);	 
		return result;
	}
	
	public Object getNewElement() {
		if (Checks.isTopLevel(fType)) {
			return getNewCompilationUnit().getType(getNewElementName());
		} else {
			return fType.getDeclaringType().getType(getNewElementName());
		}
	}

	private IJavaScriptUnit getNewCompilationUnit() {
		IJavaScriptUnit cu= fType.getJavaScriptUnit();
		if (isPrimaryType()) {
			IPackageFragment parent= fType.getPackageFragment();
			String renamedCUName= JavaModelUtil.getRenamedCUName(cu, getNewElementName());
			return parent.getJavaScriptUnit(renamedCUName);
		} else {
			return cu;
		}
	}

	//---- JavaRenameProcessor -------------------------------------------
	
	protected RenameArguments createRenameArguments() {
		return new RenameTypeArguments(getNewElementName(), getUpdateReferences(), 
			getUpdateSimilarDeclarations(), getSimilarElements());
	}
	
	protected IParticipantDescriptorFilter createParticipantDescriptorFilter() {
		if (!getUpdateSimilarDeclarations())
			return null;
		return new ParticipantDescriptorFilter();
	}
	
	protected IFile[] getChangedFiles() throws CoreException {
		List result= new ArrayList();
		result.addAll(Arrays.asList(ResourceUtil.getFiles(fChangeManager.getAllCompilationUnits())));
		if (fQualifiedNameSearchResult != null)
			result.addAll(Arrays.asList(fQualifiedNameSearchResult.getAllFiles()));
		if (willRenameCU())
			result.add(ResourceUtil.getFile(fType.getJavaScriptUnit()));
		return (IFile[]) result.toArray(new IFile[result.size()]);
	}
	
	public int getSaveMode() {
		return RefactoringSaveHelper.SAVE_NON_JAVA_UPDATES;
	}
	
	//---- ITextUpdating -------------------------------------------------

	public boolean canEnableTextUpdating() {
		return true;
	}
	
	public boolean getUpdateTextualMatches() {
		return fUpdateTextualMatches;
	}
	public void setUpdateTextualMatches(boolean update) {
		fUpdateTextualMatches= update;
	}

	//---- IReferenceUpdating --------------------------------------
		
	public void setUpdateReferences(boolean update){
		fUpdateReferences= update;
	}
	
	public boolean canEnableUpdateReferences(){
		return true;
	}
	
	public boolean getUpdateReferences(){
		return fUpdateReferences;
	}

	//---- IQualifiedNameUpdating ----------------------------------

	public boolean canEnableQualifiedNameUpdating() {
		return !fType.getPackageFragment().isDefaultPackage() && !(fType.getParent() instanceof IType);
	}
	
	public boolean getUpdateQualifiedNames() {
		return fUpdateQualifiedNames;
	}
	
	public void setUpdateQualifiedNames(boolean update) {
		fUpdateQualifiedNames= update;
	}
	
	public String getFilePatterns() {
		return fFilePatterns;
	}
	
	public void setFilePatterns(String patterns) {
		Assert.isNotNull(patterns);
		fFilePatterns= patterns;
	}
	
	// ---- ISimilarDeclarationUpdating

	public boolean canEnableSimilarDeclarationUpdating() {
		
		IProduct product= Platform.getProduct();
		if (product != null) {
			String property= product.getProperty("org.eclipse.wst.jsdt.ui.refactoring.handlesSimilarDeclarations"); //$NON-NLS-1$
			if ("false".equalsIgnoreCase(property)) //$NON-NLS-1$
				return false;
		}

		return true;
	}

	public void setUpdateSimilarDeclarations(boolean update) {
		fUpdateSimilarElements= update;
	}

	public boolean getUpdateSimilarDeclarations() {
		return fUpdateSimilarElements;
	}

	public int getMatchStrategy() {
		return fRenamingStrategy;

	}

	public void setMatchStrategy(int selectedStrategy) {
		fRenamingStrategy= selectedStrategy;
	}

	/**
	 * @return the similar elements of the type, i.e. IFields, IMethods, and
	 * ILocalVariables. Returns <code>null</code> iff similar declaration updating
	 * is not requested.
	 */
	public IJavaScriptElement[] getSimilarElements() {
		if (fFinalSimilarElementToName == null)
			return null;
		Set keys= fFinalSimilarElementToName.keySet();
		return (IJavaScriptElement[])keys.toArray(new IJavaScriptElement[keys.size()]);
	}

	/**
	 * {@inheritDoc}
	 */
	public IResource getRefactoredResource(IResource element) {
		if (element instanceof IFile) {
			if (Checks.isTopLevel(fType) && element.equals(fType.getResource()))
				return getNewCompilationUnit().getResource();
		}
		return element;
	}
	
	/**
	 * {@inheritDoc}
	 */
	public IJavaScriptElement getRefactoredJavaScriptElement(IJavaScriptElement element) {
		if (element instanceof IJavaScriptUnit) {
			if (Checks.isTopLevel(fType) && element.equals(fType.getJavaScriptUnit()))
				return getNewCompilationUnit();
		} else if (element instanceof IMember) {
			final IType newType= (IType) getNewElement();
			final RefactoringHandleTransplanter transplanter= new RefactoringHandleTransplanter(fType, newType, fFinalSimilarElementToName);
			return transplanter.transplantHandle((IMember) element);
		} 
		return element;
	}

	public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
		IType primary= (IType) fType.getPrimaryElement();
		if (primary == null || !primary.exists()) {
			String message= Messages.format(RefactoringCoreMessages.RenameTypeRefactoring_does_not_exist, new String[] { JavaModelUtil.getFullyQualifiedName(fType), fType.getJavaScriptUnit().getElementName()});
			return RefactoringStatus.createFatalErrorStatus(message);
		}
		fType= primary;
		return Checks.checkIfCuBroken(fType);
	}

	protected RefactoringStatus doCheckFinalConditions(IProgressMonitor pm, CheckConditionsContext context) throws CoreException {
		Assert.isNotNull(fType, "type"); //$NON-NLS-1$
		Assert.isNotNull(getNewElementName(), "newName"); //$NON-NLS-1$
		RefactoringStatus result= new RefactoringStatus();
		
		int referenceSearchTicks= fUpdateReferences || fUpdateSimilarElements ? 15 : 0;
		int affectedCusTicks= fUpdateReferences || fUpdateSimilarElements ? 10 : 1;
		int similarElementTicks= fUpdateSimilarElements ? 85 : 0;
		int createChangeTicks = 5;
		int qualifiedNamesTicks= fUpdateQualifiedNames ? 50 : 0;
		
		try{
			pm.beginTask("", 12 + referenceSearchTicks + affectedCusTicks + similarElementTicks + createChangeTicks + qualifiedNamesTicks); //$NON-NLS-1$
			pm.setTaskName(RefactoringCoreMessages.RenameTypeRefactoring_checking);

			fChangeManager= new TextChangeManager(true);
			
			result.merge(checkNewElementName(getNewElementName()));
			if (result.hasFatalError())
				return result;
			result.merge(Checks.checkIfCuBroken(fType));
			if (result.hasFatalError())
				return result;
			pm.worked(1);
		
			result.merge(checkTypesInCompilationUnit());
			pm.worked(1);
		
			result.merge(checkForMethodsWithConstructorNames());
			pm.worked(1);
		
			result.merge(checkImportedTypes());	
			pm.worked(1);
		
			if (Checks.isTopLevel(fType) && (JdtFlags.isPublic(fType)))
				result.merge(Checks.checkCompilationUnitNewName(fType.getJavaScriptUnit(), getNewElementName()));
			pm.worked(1);	
			
			if (isPrimaryType())
				result.merge(checkNewPathValidity());
			pm.worked(1);	
			
			result.merge(checkEnclosingTypes());
			pm.worked(1);	
			
			result.merge(checkEnclosedTypes());
			pm.worked(1);	
			
			result.merge(checkTypesInPackage());
			pm.worked(1);	
			
			result.merge(checkTypesImportedInCu());
			pm.worked(1);	
		
//			result.merge(Checks.checkForMainAndNativeMethods(fType));
//			pm.worked(1);	
		
			// before doing any expensive analysis
			if (result.hasFatalError())
				return result;
							
			result.merge(analyseEnclosedTypes());
			pm.worked(1);
			// before doing _the really_ expensive analysis
			if (result.hasFatalError())
				return result;
			
			// Load references, including similarly named elements
			if (fUpdateReferences || fUpdateSimilarElements) {
				pm.setTaskName(RefactoringCoreMessages.RenameTypeRefactoring_searching);
				result.merge(initializeReferences(new SubProgressMonitor(pm, referenceSearchTicks)));
			} else {
				fReferences= new SearchResultGroup[0];
			}
	
			pm.setTaskName(RefactoringCoreMessages.RenameTypeRefactoring_checking); 
			if (pm.isCanceled())
				throw new OperationCanceledException();
			
			if (fUpdateReferences || fUpdateSimilarElements) {
				result.merge(analyzeAffectedCompilationUnits(new SubProgressMonitor(pm, affectedCusTicks)));
			} else {
				Checks.checkCompileErrorsInAffectedFile(result, fType.getResource());
				pm.worked(affectedCusTicks);
			}
			
			if (result.hasFatalError())
				return result;
			
			if (fUpdateSimilarElements) {
				result.merge(initializeSimilarElementsRenameProcessors(new SubProgressMonitor(pm, similarElementTicks), context));
				if (result.hasFatalError())
					return result;
			}

			createChanges(new SubProgressMonitor(pm, createChangeTicks));
	
			if (fUpdateQualifiedNames)			
				computeQualifiedNameMatches(new SubProgressMonitor(pm, qualifiedNamesTicks));
	
			return result;
		} finally {
			pm.done();
		}	
	}
	
	/**
	 * Initializes the references to the type and the similarly named elements. This
	 * method creates both the fReferences and the fPreloadedElementToName
	 * fields.
	 * 
	 * May be called from the UI.
	 * @param monitor 
	 * @return initialization status 
	 * @throws JavaScriptModelException some fundamental error with the underlying model
	 * @throws OperationCanceledException if user canceled the task
	 * 
	 */
	public RefactoringStatus initializeReferences(IProgressMonitor monitor) throws JavaScriptModelException, OperationCanceledException {

		Assert.isNotNull(fType);
		Assert.isNotNull(getNewElementName());

		// Do not search again if the preconditions have not changed.
		// Search depends on the type, the new name, the similarly named elements, and
		// the strategy

		if (fReferences != null && (getNewElementName().equals(fCachedNewName)) && (fCachedRenameSimilarElements == getUpdateSimilarDeclarations()) && (fCachedRenamingStrategy == fRenamingStrategy))
			return fCachedRefactoringStatus;

		fCachedNewName= getNewElementName();
		fCachedRenameSimilarElements= fUpdateSimilarElements;
		fCachedRenamingStrategy= fRenamingStrategy;
		fCachedRefactoringStatus= new RefactoringStatus();

		
		try {
			SearchPattern pattern= SearchPattern.createPattern(fType, IJavaScriptSearchConstants.REFERENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE);
			fReferences= RefactoringSearchEngine.search(
					pattern,
					RefactoringScopeFactory.create(fType),
					new TypeOccurrenceCollector(fType),
					monitor,
					fCachedRefactoringStatus);
			fReferences= Checks.excludeCompilationUnits(fReferences, fCachedRefactoringStatus);

			fPreloadedElementToName= new LinkedHashMap();
			fPreloadedElementToSelection= new HashMap();

			final String unQualifiedTypeName= fType.getElementName();

			monitor.beginTask("", fReferences.length); //$NON-NLS-1$

			if (getUpdateSimilarDeclarations()) {

				RenamingNameSuggestor sugg= new RenamingNameSuggestor(fRenamingStrategy);

				for (int i= 0; i < fReferences.length; i++) {
					final IJavaScriptUnit cu= fReferences[i].getCompilationUnit();
					if (cu == null)
						continue;

					final SearchMatch[] results= fReferences[i].getSearchResults();

					for (int j= 0; j < results.length; j++) {

						if (! (results[j] instanceof TypeReferenceMatch))
							continue;

						final TypeReferenceMatch match= (TypeReferenceMatch) results[j];
						final List matches= new ArrayList();

						if (match.getLocalElement() != null)
							matches.add(match.getLocalElement());
						else
							matches.add(match.getElement());

						final IJavaScriptElement[] others= match.getOtherElements();
						if (others != null)
							matches.addAll(Arrays.asList(others));

						for (Iterator iter= matches.iterator(); iter.hasNext();) {
							final IJavaScriptElement element= (IJavaScriptElement) iter.next();

							if (! (element instanceof IFunction) && ! (element instanceof IField) && ! (element instanceof ILocalVariable))
								continue;
							
							if (!isInDeclaredType(match.getOffset(), element))
								continue;

							if (element instanceof IField) {
								final IField currentField= (IField) element;
								final String newFieldName= sugg.suggestNewFieldName(currentField.getJavaScriptProject(), currentField.getElementName(), Flags.isStatic(currentField.getFlags()),
										unQualifiedTypeName, getNewElementName());

								if (newFieldName != null)
									fPreloadedElementToName.put(currentField, newFieldName);
							}

							if (element instanceof IFunction) {
								final IFunction currentMethod= (IFunction) element;
								addMethodRename(unQualifiedTypeName, sugg, currentMethod);
							}

							if (element instanceof ILocalVariable) {
								final ILocalVariable currentLocal= (ILocalVariable) element;
								final boolean isParameter;
								
								if (JavaModelUtil.isParameter(currentLocal)) {
									addMethodRename(unQualifiedTypeName, sugg, (IFunction) currentLocal.getParent());
									isParameter= true;
								} else
									isParameter= false;

								final String newLocalName= sugg
										.suggestNewLocalName(currentLocal.getJavaScriptProject(), currentLocal.getElementName(), isParameter, unQualifiedTypeName, getNewElementName());

								if (newLocalName != null)
									fPreloadedElementToName.put(currentLocal, newLocalName);
							}
						}
					}
					if (monitor.isCanceled())
						throw new OperationCanceledException();
				}
			}

			for (Iterator iter= fPreloadedElementToName.keySet().iterator(); iter.hasNext();) {
				IJavaScriptElement element= (IJavaScriptElement) iter.next();
				fPreloadedElementToSelection.put(element, Boolean.TRUE);
			}
			fPreloadedElementToNameDefault= (LinkedHashMap) fPreloadedElementToName.clone();

		} catch (OperationCanceledException e) {
			fReferences= null;
			fPreloadedElementToName= null;
			throw new OperationCanceledException();
		}
		return fCachedRefactoringStatus;
	}

	/**
	 * @param matchOffset 
	 * @param parentElement 
	 * @return true iff the given search match offset (must be a match of a type
	 * reference) lies before the element name of its enclosing java element,
	 * false if not. In other words: If this method returns true, the match is
	 * the declared type (or return type) of the enclosing element.
	 * @throws JavaScriptModelException 
	 * 
	 */
	private boolean isInDeclaredType(int matchOffset, IJavaScriptElement parentElement) throws JavaScriptModelException {
		if (parentElement != null) {
			int enclosingNameOffset= 0;
			if (parentElement instanceof IFunction || parentElement instanceof IField)
				enclosingNameOffset= ((IMember) parentElement).getNameRange().getOffset();
			else if (parentElement instanceof ILocalVariable)
				enclosingNameOffset= ((ILocalVariable) parentElement).getNameRange().getOffset();

			return (matchOffset < enclosingNameOffset);
		}
		return false;
	}
	
	private void addMethodRename(final String unQualifiedTypeName, RenamingNameSuggestor sugg, final IFunction currentMethod) throws JavaScriptModelException {
		if (!currentMethod.isConstructor()) {
			final String newMethodName= sugg.suggestNewMethodName(currentMethod.getElementName(), unQualifiedTypeName, getNewElementName());

			if (newMethodName != null)
				fPreloadedElementToName.put(currentMethod, newMethodName);
		}
	}

	private RefactoringStatus checkNewPathValidity() {
		IContainer c= fType.getJavaScriptUnit().getResource().getParent();
		
		String notRename= RefactoringCoreMessages.RenameTypeRefactoring_will_not_rename; 
		IStatus status= c.getWorkspace().validateName(getNewElementName(), IResource.FILE);
		if (status.getSeverity() == IStatus.ERROR)
			return RefactoringStatus.createWarningStatus(status.getMessage() + ". " + notRename); //$NON-NLS-1$
		
		status= c.getWorkspace().validatePath(createNewPath(getNewElementName()), IResource.FILE);
		if (status.getSeverity() == IStatus.ERROR)
			return RefactoringStatus.createWarningStatus(status.getMessage() + ". " + notRename); //$NON-NLS-1$

		return new RefactoringStatus();
	}
	
	private String createNewPath(String newName) {
		return fType.getJavaScriptUnit().getResource().getFullPath().removeLastSegments(1).append(newName).toString();
	}
	
	private RefactoringStatus checkTypesImportedInCu() throws CoreException {
		IImportDeclaration imp= getImportedType(fType.getJavaScriptUnit(), getNewElementName());
		
		if (imp == null)
			return null;	
			
		String msg= Messages.format(RefactoringCoreMessages.RenameTypeRefactoring_imported, 
											new Object[]{getNewElementName(), fType.getJavaScriptUnit().getResource().getFullPath()});
		IJavaScriptElement grandParent= imp.getParent().getParent();
		if (grandParent instanceof IJavaScriptUnit)
			return RefactoringStatus.createErrorStatus(msg, JavaStatusContext.create(imp));

		return null;	
	}
	
	private RefactoringStatus checkTypesInPackage() throws CoreException {
		IType type= Checks.findTypeInPackage(fType.getPackageFragment(), getNewElementName());
		if (type == null || ! type.exists())
			return null;
		String msg= Messages.format(RefactoringCoreMessages.RenameTypeRefactoring_exists, 
																	new String[]{getNewElementName(), fType.getPackageFragment().getElementName()});
		return RefactoringStatus.createErrorStatus(msg, JavaStatusContext.create(type));
	}
	
	private RefactoringStatus checkEnclosedTypes() throws CoreException {
		IType enclosedType= findEnclosedType(fType, getNewElementName());
		if (enclosedType == null)
			return null;
		String msg= Messages.format(RefactoringCoreMessages.RenameTypeRefactoring_encloses,  
																		new String[]{JavaModelUtil.getFullyQualifiedName(fType), getNewElementName()});
		return RefactoringStatus.createErrorStatus(msg, JavaStatusContext.create(enclosedType));
	}
	
	private RefactoringStatus checkEnclosingTypes() {
		IType enclosingType= findEnclosingType(fType, getNewElementName());
		if (enclosingType == null)
			return null;
			
		String msg= Messages.format(RefactoringCoreMessages.RenameTypeRefactoring_enclosed,
								new String[]{JavaModelUtil.getFullyQualifiedName(fType), getNewElementName()});
		return RefactoringStatus.createErrorStatus(msg, JavaStatusContext.create(enclosingType));
	}
	
	private static IType findEnclosedType(IType type, String newName) throws CoreException {
		IType[] enclosedTypes= type.getTypes();
		for (int i= 0; i < enclosedTypes.length; i++){
			if (newName.equals(enclosedTypes[i].getElementName()) || findEnclosedType(enclosedTypes[i], newName) != null)
				return enclosedTypes[i];
		}
		return null;
	}
		
	private static IType findEnclosingType(IType type, String newName) {
		IType enclosing= type.getDeclaringType();
		while (enclosing != null){
			if (newName.equals(enclosing.getElementName()))
				return enclosing;
			else 
				enclosing= enclosing.getDeclaringType();	
		}
		return null;
	}
	
	private static IImportDeclaration getImportedType(IJavaScriptUnit cu, String typeName) throws CoreException {
		IImportDeclaration[] imports= cu.getImports();
		String dotTypeName= "." + typeName; //$NON-NLS-1$
		for (int i= 0; i < imports.length; i++){
			if (imports[i].getElementName().endsWith(dotTypeName))
				return imports[i];
		}
		return null;
	}
	
	private RefactoringStatus checkForMethodsWithConstructorNames()  throws CoreException{
		IFunction[] methods= fType.getFunctions();
		for (int i= 0; i < methods.length; i++){
			if (methods[i].isConstructor())
				continue;
			RefactoringStatus check= Checks.checkIfConstructorName(methods[i], methods[i].getElementName(), getNewElementName());	
			if (check != null)
				return check;
		}
		return null;
	}	
	
	private RefactoringStatus checkImportedTypes() throws CoreException {
		RefactoringStatus result= new RefactoringStatus();
		IImportDeclaration[] imports= fType.getJavaScriptUnit().getImports();	
		for (int i= 0; i < imports.length; i++)
			analyzeImportDeclaration(imports[i], result);
		return result;
	}
	
	private RefactoringStatus checkTypesInCompilationUnit() {
		RefactoringStatus result= new RefactoringStatus();
		if (! Checks.isTopLevel(fType)){ //the other case checked in checkTypesInPackage
			IType siblingType= fType.getDeclaringType().getType(getNewElementName());
			if (siblingType.exists()){
				String msg= Messages.format(RefactoringCoreMessages.RenameTypeRefactoring_member_type_exists, 
																		new String[]{getNewElementName(), JavaModelUtil.getFullyQualifiedName(fType.getDeclaringType())});
				result.addError(msg, JavaStatusContext.create(siblingType));
			}
		}
		return result;
	}
	
	private RefactoringStatus analyseEnclosedTypes() throws CoreException {
		final ISourceRange typeRange= fType.getSourceRange();
		final RefactoringStatus result= new RefactoringStatus();
		JavaScriptUnit cuNode= new RefactoringASTParser(AST.JLS3).parse(fType.getJavaScriptUnit(), false);
		cuNode.accept(new ASTVisitor(){
			
			public boolean visit(TypeDeclaration node){ // enums and annotations can't be local
				if (node.getStartPosition() <= typeRange.getOffset())
					return true;
				if (node.getStartPosition() > typeRange.getOffset() + typeRange.getLength())
					return true;
		
				if (getNewElementName().equals(node.getName().getIdentifier())){
					RefactoringStatusContext	context= JavaStatusContext.create(fType.getJavaScriptUnit(), node);
					String msg= null;
					if (node.isLocalTypeDeclaration()){
						msg= Messages.format(RefactoringCoreMessages.RenameTypeRefactoring_local_type, 
									new String[]{JavaElementUtil.createSignature(fType), getNewElementName()});
					}	
					else if (node.isMemberTypeDeclaration()){
						msg= Messages.format(RefactoringCoreMessages.RenameTypeRefactoring_member_type, 
								new String[]{JavaElementUtil.createSignature(fType), getNewElementName()});
					}	
					if (msg != null)	
						result.addError(msg, context);
				}
		
				FunctionDeclaration[] methods= node.getMethods();
				for (int i= 0; i < methods.length; i++) {
					if (Modifier.isNative(methods[i].getModifiers())){
						RefactoringStatusContext	context= JavaStatusContext.create(fType.getJavaScriptUnit(), methods[i]);
						String msg= Messages.format(RefactoringCoreMessages.RenameTypeRefactoring_enclosed_type_native, node.getName().getIdentifier());
						result.addWarning(msg, context); 
					}	
				}
				return true;
			}
		});
		return result;
	}
	
	private static IJavaScriptUnit getCompilationUnit(IImportDeclaration imp) {
		return (IJavaScriptUnit)imp.getParent().getParent();
	}
	
	private void analyzeImportedTypes(IType[] types, RefactoringStatus result, IImportDeclaration imp) throws CoreException {
		for (int i= 0; i < types.length; i++) {
			//could this be a problem (same package imports)?
			if (JdtFlags.isPublic(types[i]) && types[i].getElementName().equals(getNewElementName())){
				String msg= Messages.format(RefactoringCoreMessages.RenameTypeRefactoring_name_conflict1, 
																			new Object[]{JavaModelUtil.getFullyQualifiedName(types[i]), getFullPath(getCompilationUnit(imp))});
				result.addError(msg, JavaStatusContext.create(imp));
			}
		}
	}
	
	private static IJavaScriptElement convertFromImportDeclaration(IImportDeclaration declaration) throws CoreException {
			if (declaration.isOnDemand()){ 
				String packageName= declaration.getElementName().substring(0, declaration.getElementName().length() - 2);
				return JavaModelUtil.findTypeContainer(declaration.getJavaScriptProject(), packageName);
			} else 
				return JavaModelUtil.findTypeContainer(declaration.getJavaScriptProject(), declaration.getElementName());
	}

	private void analyzeImportDeclaration(IImportDeclaration imp, RefactoringStatus result) throws CoreException{
		if (!imp.isOnDemand())
			return; //analyzed earlier
		
		IJavaScriptElement imported= convertFromImportDeclaration(imp);
		if (imported == null)
			return;
			
		if (imported instanceof IPackageFragment){
			IJavaScriptUnit[] cus= ((IPackageFragment)imported).getJavaScriptUnits();
			for (int i= 0; i < cus.length; i++) {
				analyzeImportedTypes(cus[i].getTypes(), result, imp);
			}	
		} else {
			//cast safe: see JavaModelUtility.convertFromImportDeclaration
			analyzeImportedTypes(((IType)imported).getTypes(), result, imp);
		}
	}
	
	/*
	 * Analyzes all compilation units in which type is referenced
	 */
	private RefactoringStatus analyzeAffectedCompilationUnits(IProgressMonitor pm) throws CoreException {
		RefactoringStatus result= new RefactoringStatus();
			
		result.merge(Checks.checkCompileErrorsInAffectedFiles(fReferences, fType.getResource()));	
		
		pm.beginTask("", fReferences.length); //$NON-NLS-1$
		result.merge(checkConflictingTypes(pm));
		return result;
	}
	
	private RefactoringStatus checkConflictingTypes(IProgressMonitor pm) throws CoreException {
		RefactoringStatus result= new RefactoringStatus();
		IJavaScriptSearchScope scope= RefactoringScopeFactory.create(fType);
		SearchPattern pattern= SearchPattern.createPattern(getNewElementName(),
				IJavaScriptSearchConstants.TYPE, IJavaScriptSearchConstants.ALL_OCCURRENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE);
		IJavaScriptUnit[] cusWithReferencesToConflictingTypes= RefactoringSearchEngine.findAffectedCompilationUnits(pattern, scope, pm, result);
		if (cusWithReferencesToConflictingTypes.length == 0)
			return result;
		IJavaScriptUnit[] 	cusWithReferencesToRenamedType= getCus(fReferences);

		IJavaScriptUnit[] intersection= isIntersectionEmpty(cusWithReferencesToRenamedType, cusWithReferencesToConflictingTypes);
		if (intersection.length == 0)
			return result;
		
		for (int i= 0; i < intersection.length; i++) {
			RefactoringStatusContext context= JavaStatusContext.create(intersection[i]);
			String message= Messages.format(RefactoringCoreMessages.RenameTypeRefactoring_another_type, 
				new String[]{getNewElementName(), intersection[i].getElementName()});
			result.addError(message, context);
		}	
		return result;
	}
	
	private static IJavaScriptUnit[] isIntersectionEmpty(IJavaScriptUnit[] a1, IJavaScriptUnit[] a2){
		Set set1= new HashSet(Arrays.asList(a1));
		Set set2= new HashSet(Arrays.asList(a2));
		set1.retainAll(set2);
		return (IJavaScriptUnit[]) set1.toArray(new IJavaScriptUnit[set1.size()]);
	}
	
	private static IJavaScriptUnit[] getCus(SearchResultGroup[] searchResultGroups){
		List cus= new ArrayList(searchResultGroups.length);
		for (int i= 0; i < searchResultGroups.length; i++) {
			IJavaScriptUnit cu= searchResultGroups[i].getCompilationUnit();
			if (cu != null)
				cus.add(cu);
		}
		return (IJavaScriptUnit[]) cus.toArray(new IJavaScriptUnit[cus.size()]);
	}
	
	private static String getFullPath(IJavaScriptUnit cu) {
		Assert.isTrue(cu.exists());
		return cu.getResource().getFullPath().toString();
	}

	public Change createChange(IProgressMonitor monitor) throws CoreException {
		try {
			monitor.beginTask(RefactoringCoreMessages.RenameTypeRefactoring_creating_change, 4);
			String project= null;
			IJavaScriptProject javaProject= fType.getJavaScriptProject();
			if (javaProject != null)
				project= javaProject.getElementName();
			int flags= JavaScriptRefactoringDescriptor.JAR_MIGRATION | JavaScriptRefactoringDescriptor.JAR_REFACTORING | RefactoringDescriptor.STRUCTURAL_CHANGE;
			try {
				if (!Flags.isPrivate(fType.getFlags()))
					flags|= RefactoringDescriptor.MULTI_CHANGE;
				if (fType.isAnonymous() || fType.isLocal())
					flags|= JavaScriptRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
			} catch (JavaScriptModelException exception) {
				JavaScriptPlugin.log(exception);
			}
			final String description= Messages.format(RefactoringCoreMessages.RenameTypeProcessor_descriptor_description_short, fType.getElementName());
			final String header= Messages.format(RefactoringCoreMessages.RenameTypeProcessor_descriptor_description, new String[] { JavaScriptElementLabels.getElementLabel(fType, JavaScriptElementLabels.ALL_FULLY_QUALIFIED), getNewElementName()});
			final String comment= new JDTRefactoringDescriptorComment(project, this, header).asString();
			final RenameJavaScriptElementDescriptor descriptor= new RenameJavaScriptElementDescriptor(IJavaScriptRefactorings.RENAME_TYPE);
			descriptor.setProject(project);
			descriptor.setDescription(description);
			descriptor.setComment(comment);
			descriptor.setFlags(flags);
			descriptor.setJavaElement(fType);
			descriptor.setNewName(getNewElementName());
			descriptor.setUpdateQualifiedNames(fUpdateQualifiedNames);
			descriptor.setUpdateTextualOccurrences(fUpdateTextualMatches);
			descriptor.setUpdateReferences(fUpdateReferences);
			if (fUpdateQualifiedNames && fFilePatterns != null && !"".equals(fFilePatterns)) //$NON-NLS-1$
				descriptor.setFileNamePatterns(fFilePatterns);
			descriptor.setUpdateSimilarDeclarations(fUpdateSimilarElements);
			descriptor.setMatchStrategy(fRenamingStrategy);
			final DynamicValidationRefactoringChange result= new DynamicValidationRefactoringChange(descriptor, RefactoringCoreMessages.RenameTypeProcessor_change_name);
			
			if (fChangeManager.containsChangesIn(fType.getJavaScriptUnit())) {
				TextChange textChange= fChangeManager.get(fType.getJavaScriptUnit());
				if (textChange instanceof TextFileChange) {
					((TextFileChange) textChange).setSaveMode(TextFileChange.FORCE_SAVE);
				}
			}
			result.addAll(fChangeManager.getAllChanges());
			if (willRenameCU()) {
				IResource resource= fType.getJavaScriptUnit().getResource();
				if (resource != null && resource.isLinked()) {
					String ext= resource.getFileExtension();
					String renamedResourceName;
					if (ext == null)
						renamedResourceName= getNewElementName();
					else
						renamedResourceName= getNewElementName() + '.' + ext;
					result.add(new RenameResourceChange(null, fType.getJavaScriptUnit().getResource(), renamedResourceName, comment));
				} else {
					String renamedCUName= JavaModelUtil.getRenamedCUName(fType.getJavaScriptUnit(), getNewElementName());
					result.add(new RenameCompilationUnitChange(fType.getJavaScriptUnit(), renamedCUName));
				}
			}
			monitor.worked(1);
			return result;
		} finally {
			fChangeManager= null;
		}
	}
	
	public Change postCreateChange(Change[] participantChanges, IProgressMonitor pm) throws CoreException {
		if (fQualifiedNameSearchResult != null) {
			try {
				return fQualifiedNameSearchResult.getSingleChange(Changes.getModifiedFiles(participantChanges));
			} finally {
				fQualifiedNameSearchResult= null;
			}
		} else {
			return null;
		}
	}
	
	private boolean willRenameCU() throws CoreException{
		String name = JavaScriptCore.removeJavaScriptLikeExtension(fType.getJavaScriptUnit().getElementName());
		if (! (Checks.isTopLevel(fType) && name.equals(fType.getElementName())))
			return false;
		if (! checkNewPathValidity().isOK())
			return false;
		if (! Checks.checkCompilationUnitNewName(fType.getJavaScriptUnit(), getNewElementName()).isOK())
			return false;
		return true;	
	}
	
	private void createChanges(IProgressMonitor pm) throws CoreException {
		try{
			pm.beginTask("", 12); //$NON-NLS-1$
			pm.setTaskName(RefactoringCoreMessages.RenameTypeProcessor_creating_changes); 
			
			if (fUpdateReferences)
				addReferenceUpdates(fChangeManager, new SubProgressMonitor(pm, 3));

			// Similar names updates have already been added.
	
			pm.worked(1);
			
			IResource resource= fType.getJavaScriptUnit().getResource();
			// if we have a linked resource then we don't use CU renaming 
			// directly. So we have to update the code by ourselves.
			if ((resource != null && resource.isLinked()) || !willRenameCU()) {
				addTypeDeclarationUpdate(fChangeManager);
				pm.worked(1);
				
				addConstructorRenames(fChangeManager);
				pm.worked(1);
			} else {
				pm.worked(2);
			}
			
			if (fUpdateTextualMatches) {
				pm.subTask(RefactoringCoreMessages.RenameTypeRefactoring_searching_text); 
				TextMatchUpdater.perform(new SubProgressMonitor(pm, 1), RefactoringScopeFactory.create(fType), this, fChangeManager, fReferences);
				if (fUpdateSimilarElements)
					addSimilarElementsTextualUpdates(fChangeManager, new SubProgressMonitor(pm, 3));
			}
			
		} finally{
			pm.done();
		}	
	}
	
	private void addTypeDeclarationUpdate(TextChangeManager manager) throws CoreException {
		String name= RefactoringCoreMessages.RenameTypeRefactoring_update; 
		int typeNameLength= fType.getElementName().length();
		IJavaScriptUnit cu= fType.getJavaScriptUnit();
		TextChangeCompatibility.addTextEdit(manager.get(cu), name, new ReplaceEdit(fType.getNameRange().getOffset(), typeNameLength, getNewElementName()));
	}
	
	private void addConstructorRenames(TextChangeManager manager) throws CoreException {
		IJavaScriptUnit cu= fType.getJavaScriptUnit();
		IFunction[] methods= fType.getFunctions();
		int typeNameLength= fType.getElementName().length();
		for (int i= 0; i < methods.length; i++){
			if (methods[i].isConstructor()) {
				/*
				 * constructor declarations cannot be fully qualified so we can use simple replace here
				 *
				 * if (methods[i].getNameRange() == null), then it's a binary file so it's wrong anyway 
				 * (checked as a precondition)
				 */				
				String name= RefactoringCoreMessages.RenameTypeRefactoring_rename_constructor; 
				TextChangeCompatibility.addTextEdit(manager.get(cu), name, new ReplaceEdit(methods[i].getNameRange().getOffset(), typeNameLength, getNewElementName()));
			}
		}
	}
	
	private void addReferenceUpdates(TextChangeManager manager, IProgressMonitor pm) {
		pm.beginTask("", fReferences.length); //$NON-NLS-1$
		for (int i= 0; i < fReferences.length; i++){
			IJavaScriptUnit cu= fReferences[i].getCompilationUnit();
			if (cu == null)
				continue;
					
			String name= RefactoringCoreMessages.RenameTypeRefactoring_update_reference; 
			SearchMatch[] results= fReferences[i].getSearchResults();

			for (int j= 0; j < results.length; j++){
				SearchMatch match= results[j];
				ReplaceEdit replaceEdit= new ReplaceEdit(match.getOffset(), match.getLength(), getNewElementName());
				TextChangeCompatibility.addTextEdit(manager.get(cu), name, replaceEdit, CATEGORY_TYPE_RENAME);
			}
			pm.worked(1);
		}
	}
	
	private void computeQualifiedNameMatches(IProgressMonitor pm) throws CoreException {
		IPackageFragment fragment= fType.getPackageFragment();
		if (fQualifiedNameSearchResult == null)
			fQualifiedNameSearchResult= new QualifiedNameSearchResult();
		QualifiedNameFinder.process(fQualifiedNameSearchResult, fType.getFullyQualifiedName(),  
			fragment.getElementName() + "." + getNewElementName(), //$NON-NLS-1$
			fFilePatterns, fType.getJavaScriptProject().getProject(), pm);
	}

	public RefactoringStatus initialize(RefactoringArguments arguments) {
		if (arguments instanceof JavaRefactoringArguments) {
			final JavaRefactoringArguments extended= (JavaRefactoringArguments) arguments;
			final String handle= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_INPUT);
			if (handle != null) {
				final IJavaScriptElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false);
				if (element == null || !element.exists() || element.getElementType() != IJavaScriptElement.TYPE)
					return ScriptableRefactoring.createInputFatalStatus(element, getRefactoring().getName(), IJavaScriptRefactorings.RENAME_TYPE);
				else
					fType= (IType) element;
			} else
				return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_INPUT));
			final String name= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_NAME);
			if (name != null && !"".equals(name)) //$NON-NLS-1$
				setNewElementName(name);
			else
				return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_NAME));
			final String patterns= extended.getAttribute(ATTRIBUTE_PATTERNS);
			if (patterns != null && !"".equals(patterns)) //$NON-NLS-1$
				fFilePatterns= patterns;
			final String references= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_REFERENCES);
			if (references != null) {
				fUpdateReferences= Boolean.valueOf(references).booleanValue();
			} else
				return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_REFERENCES));
			final String matches= extended.getAttribute(ATTRIBUTE_TEXTUAL_MATCHES);
			if (matches != null) {
				fUpdateTextualMatches= Boolean.valueOf(matches).booleanValue();
			} else
				return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_TEXTUAL_MATCHES));
			final String qualified= extended.getAttribute(ATTRIBUTE_QUALIFIED);
			if (qualified != null) {
				fUpdateQualifiedNames= Boolean.valueOf(qualified).booleanValue();
			} else
				return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_QUALIFIED));
			final String similarDeclarations= extended.getAttribute(ATTRIBUTE_SIMILAR_DECLARATIONS);
			if (similarDeclarations != null)
				fUpdateSimilarElements= Boolean.valueOf(similarDeclarations).booleanValue();
			else
				return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_SIMILAR_DECLARATIONS));
			final String similarDeclarationsMatchingStrategy= extended.getAttribute(ATTRIBUTE_MATCHING_STRATEGY);
			if (similarDeclarationsMatchingStrategy != null) {
				try {
					fRenamingStrategy= Integer.valueOf(similarDeclarationsMatchingStrategy).intValue();
				} catch (NumberFormatException e) {
					return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_illegal_argument, new String[] {similarDeclarationsMatchingStrategy, ATTRIBUTE_QUALIFIED}));
				}
			} else
				return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_MATCHING_STRATEGY));
		} else
			return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
		return new RefactoringStatus();
	}
	
	// --------- Similar names

	/**
	 * Creates and initializes the refactoring processors for similarly named elements
	 * @param progressMonitor 
	 * @param context 
	 * @return status
	 * @throws CoreException 
	 */
	private RefactoringStatus initializeSimilarElementsRenameProcessors(IProgressMonitor progressMonitor, CheckConditionsContext context) throws CoreException {

		Assert.isNotNull(fPreloadedElementToName);
		Assert.isNotNull(fPreloadedElementToSelection);

		final RefactoringStatus status= new RefactoringStatus();
		final Set handledTopLevelMethods= new HashSet();
		final Set warnings= new HashSet();
		final List processors= new ArrayList();
		fFinalSimilarElementToName= new HashMap();
		
		JavaScriptUnit currentResolvedCU= null;
		IJavaScriptUnit currentCU= null;
		
		int current= 0;
		final int max= fPreloadedElementToName.size();

		progressMonitor.beginTask("", max * 3); //$NON-NLS-1$
		progressMonitor.setTaskName(RefactoringCoreMessages.RenameTypeProcessor_checking_similarly_named_declarations_refactoring_conditions); 

		for (Iterator iter= fPreloadedElementToName.keySet().iterator(); iter.hasNext();) {

			final IJavaScriptElement element= (IJavaScriptElement) iter.next();
			
			current++;
			progressMonitor.worked(3);

			// not selected? -> skip
			if (! ((Boolean) (fPreloadedElementToSelection.get(element))).booleanValue())
				continue;

			// already registered? (may happen with overridden methods) -> skip
			if (fFinalSimilarElementToName.containsKey(element))
				continue;
			
			// JavaScriptUnit changed? (note: fPreloadedElementToName is sorted by JavaScriptUnit)
			IJavaScriptUnit newCU= (IJavaScriptUnit) element.getAncestor(IJavaScriptElement.JAVASCRIPT_UNIT);
			
			if (!newCU.equals(currentCU)) {

				checkCUCompleteConditions(status, currentResolvedCU, currentCU, processors);
				
				if (status.hasFatalError())
					return status;
				
				// reset values
				currentResolvedCU= null;
				currentCU= newCU;
				processors.clear();
			}
			
			final String newName= (String) fPreloadedElementToName.get(element);
			RefactoringProcessor processor= null;
			
			if (element instanceof ILocalVariable) {
				final ILocalVariable currentLocal= (ILocalVariable) element;

				if (currentResolvedCU == null)
					currentResolvedCU= new RefactoringASTParser(AST.JLS3).parse(currentCU, true);
				
				processor= createLocalRenameProcessor(currentLocal, newName, currentResolvedCU);

				// don't check for conflicting rename => is done by #checkCUCompleteConditions().
				
				if (status.hasFatalError())
					return status;
				fFinalSimilarElementToName.put(currentLocal, newName);
			}
			if (element instanceof IField) {
				final IField currentField= (IField) element;
				processor= createFieldRenameProcessor(currentField, newName);

				status.merge(checkForConflictingRename(currentField, newName));
				if (status.hasFatalError())
					return status;
				fFinalSimilarElementToName.put(currentField, newName);
			}
			if (element instanceof IFunction) {
				IFunction currentMethod= (IFunction) element;
				if (MethodChecks.isVirtual(currentMethod)) {
					
					final IType declaringType= currentMethod.getDeclaringType();
					ITypeHierarchy hierarchy= null;
					if (!declaringType.isInterface()) 
						hierarchy= declaringType.newTypeHierarchy(new NullProgressMonitor());
					
					final IFunction topmost= MethodChecks.getTopmostMethod(currentMethod, hierarchy, new NullProgressMonitor());
					if (topmost != null)
						currentMethod= topmost;
					if (handledTopLevelMethods.contains(currentMethod))
						continue;
					handledTopLevelMethods.add(currentMethod);
					final IFunction[] ripples= MethodChecks.getOverriddenMethods(currentMethod, new NullProgressMonitor());

					if (checkForWarnings(warnings, newName, ripples))
						continue;

					status.merge(checkForConflictingRename(ripples, newName));
					if (status.hasFatalError())
						return status;

					processor= createVirtualMethodRenameProcessor(currentMethod, newName, ripples, hierarchy);
					fFinalSimilarElementToName.put(currentMethod, newName);
					for (int i= 0; i < ripples.length; i++) {
						fFinalSimilarElementToName.put(ripples[i], newName);
					}
				} else {
					
					status.merge(checkForConflictingRename(new IFunction[] { currentMethod }, newName));
					if (status.hasFatalError())
						break;
					
					fFinalSimilarElementToName.put(currentMethod, newName);
					
					processor= createNonVirtualMethodRenameProcessor(currentMethod, newName);
				}
			}
			
			progressMonitor.subTask(Messages.format(RefactoringCoreMessages.RenameTypeProcessor_progress_current_total, new Object[] { String.valueOf(current), String.valueOf(max)}));

			status.merge(processor.checkInitialConditions(new NoOverrideProgressMonitor(progressMonitor, 1)));

			if (status.hasFatalError())
				return status;

			status.merge(processor.checkFinalConditions(new NoOverrideProgressMonitor(progressMonitor, 1), context));

			if (status.hasFatalError())
				return status;
			
			processors.add(processor);

			progressMonitor.worked(1);
			
			if (progressMonitor.isCanceled())
				throw new OperationCanceledException();
		}

		// check last CU
		checkCUCompleteConditions(status, currentResolvedCU, currentCU, processors);
		
		status.merge(addWarnings(warnings));

		progressMonitor.done();
		return status;
	}

	private void checkCUCompleteConditions(final RefactoringStatus status, JavaScriptUnit currentResolvedCU, IJavaScriptUnit currentCU, List processors) throws CoreException {

		// check local variable conditions
		List locals= getProcessorsOfType(processors, RenameLocalVariableProcessor.class);
		if (!locals.isEmpty()) {
			RenameAnalyzeUtil.LocalAnalyzePackage[] analyzePackages= new RenameAnalyzeUtil.LocalAnalyzePackage[locals.size()];
			TextChangeManager manager= new TextChangeManager();
			int current= 0;
			TextChange textChange= manager.get(currentCU);
			textChange.setKeepPreviewEdits(true);
			for (Iterator iterator= locals.iterator(); iterator.hasNext();) {
				RenameLocalVariableProcessor localProcessor= (RenameLocalVariableProcessor) iterator.next();
				RenameAnalyzeUtil.LocalAnalyzePackage analyzePackage= localProcessor.getLocalAnalyzePackage();
				analyzePackages[current]= analyzePackage;
				for (int i= 0; i < analyzePackage.fOccurenceEdits.length; i++) {
					TextChangeCompatibility.addTextEdit(textChange, "", analyzePackage.fOccurenceEdits[i], GroupCategorySet.NONE); //$NON-NLS-1$
				}
				current++;
			}
			status.merge(RenameAnalyzeUtil.analyzeLocalRenames(analyzePackages, textChange, currentResolvedCU, false));
		}

		/*
		 * There is room for performance improvement here: One could move
		 * shadowing analyzes out of the field and method processors and perform
		 * it here, thus saving on working copy creation. Drawback is increased
		 * heap consumption.
		 */
	}

	private List getProcessorsOfType(List processors, Class type) {
		List tmp= new ArrayList();
		for (Iterator iter= processors.iterator(); iter.hasNext();) {
			RefactoringProcessor element= (RefactoringProcessor) iter.next();
			if (element.getClass().equals(type))
				tmp.add(element);
		}
		return tmp;
	}

	// ------------------ Error checking -------------

	/**
	 * Checks whether one of the given methods, which will all be renamed to
	 * "newName", shares a type with another already registered method which is
	 * renamed to the same new name and shares the same parameters.
	 * @param methods 
	 * @param newName 
	 * @return status
	 * 
	 * @see #checkForConflictingRename(IField, String)
	 */
	private RefactoringStatus checkForConflictingRename(IFunction[] methods, String newName) {
		RefactoringStatus status= new RefactoringStatus();
		for (Iterator iter= fFinalSimilarElementToName.keySet().iterator(); iter.hasNext();) {
			IJavaScriptElement element= (IJavaScriptElement) iter.next();
			if (element instanceof IFunction) {
				IFunction alreadyRegisteredMethod= (IFunction) element;
				String alreadyRegisteredMethodName= (String) fFinalSimilarElementToName.get(element);
				for (int i= 0; i < methods.length; i++) {
					IFunction method2= methods[i];
					if ( (alreadyRegisteredMethodName.equals(newName)) && (method2.getDeclaringType().equals(alreadyRegisteredMethod.getDeclaringType()))
							&& (sameParams(alreadyRegisteredMethod, method2))) {
						String message= Messages.format(RefactoringCoreMessages.RenameTypeProcessor_cannot_rename_methods_same_new_name, new String[] { alreadyRegisteredMethod.getElementName(),
								method2.getElementName(), alreadyRegisteredMethod.getDeclaringType().getFullyQualifiedName(), newName });
						status.addFatalError(message);
						return status;
					}
				}
			}
		}
		return status;
	}

	private static boolean sameParams(IFunction method, IFunction method2) {

		if (method.getNumberOfParameters() != method2.getNumberOfParameters())
			return false;

		String[] params= method.getParameterTypes();
		String[] params2= method2.getParameterTypes();

		for (int i= 0; i < params.length; i++) {
			String t1= Signature.getSimpleName(Signature.toString(params[i]));
			String t2= Signature.getSimpleName(Signature.toString(params2[i]));
			if (!t1.equals(t2)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * If suffix matching is enabled, the refactoring may suggest two fields to
	 * have the same name which reside in the same type. Same thing may also
	 * happen if the user makes poor choices for the field names.
	 * 
	 * Consider: FooBarThing fFooBarThing; FooBarThing fBarThing;
	 * 
	 * Rename "FooBarThing" to "DifferentHunk". Suggestion for both fields is
	 * "fDifferentHunk" (and rightly so).
	 * @param currentField 
	 * @param newName 
	 * @return status
	 */
	private RefactoringStatus checkForConflictingRename(IField currentField, String newName) {
		RefactoringStatus status= new RefactoringStatus();
		for (Iterator iter= fFinalSimilarElementToName.keySet().iterator(); iter.hasNext();) {
			IJavaScriptElement element= (IJavaScriptElement) iter.next();
			if (element instanceof IField) {
				IField alreadyRegisteredField= (IField) element;
				String alreadyRegisteredFieldName= (String) fFinalSimilarElementToName.get(element);
				if (alreadyRegisteredFieldName.equals(newName)) {
					if (alreadyRegisteredField.getDeclaringType().equals(currentField.getDeclaringType())) {
						
						String message= Messages.format(RefactoringCoreMessages.RenameTypeProcessor_cannot_rename_fields_same_new_name, new String[] { alreadyRegisteredField.getElementName(),
								currentField.getElementName(), alreadyRegisteredField.getDeclaringType().getFullyQualifiedName(), newName });
						status.addFatalError(message);
						return status;
					}
				}
			}
		}
		return status;
	}

	private RefactoringStatus addWarnings(final Set warnings) {
		RefactoringStatus status= new RefactoringStatus();

		// Remove deleted ripple methods from user selection and add warnings
		for (Iterator iter= warnings.iterator(); iter.hasNext();) {
			final Warning warning= (Warning) iter.next();
			final IFunction[] elements= warning.getRipple();
			if (warning.isSelectionWarning()) {
				String message= Messages.format(RefactoringCoreMessages.RenameTypeProcessor_deselected_method_is_overridden,
						new String[] { JavaScriptElementLabels.getElementLabel(elements[0], JavaScriptElementLabels.ALL_DEFAULT),
								JavaScriptElementLabels.getElementLabel(elements[0].getDeclaringType(), JavaScriptElementLabels.ALL_DEFAULT) });
				status.addWarning(message);
			}
			if (warning.isNameWarning()) {
				String message= Messages.format(
						RefactoringCoreMessages.RenameTypeProcessor_renamed_method_is_overridden, new String[] {
								JavaScriptElementLabels.getElementLabel(elements[0], JavaScriptElementLabels.ALL_DEFAULT),
								JavaScriptElementLabels.getElementLabel(elements[0].getDeclaringType(), JavaScriptElementLabels.ALL_DEFAULT) });
				status.addWarning(message);
			}
			for (int i= 0; i < elements.length; i++)
				fPreloadedElementToSelection.put(elements[i], Boolean.FALSE);
		}
		return status;
	}

	/*
	 * If one of the methods of this ripple was deselected or renamed by
	 * the user, deselect the whole chain and add warnings.
	 */
	private boolean checkForWarnings(final Set warnings, final String newName, final IFunction[] ripples) {

		boolean addSelectionWarning= false;
		boolean addNameWarning= false;
		for (int i= 0; i < ripples.length; i++) {
			String newNameOfRipple= (String) fPreloadedElementToName.get(ripples[i]);
			Boolean selected= (Boolean) fPreloadedElementToSelection.get(ripples[i]);

			// selected may be null here due to supermethods like
			// setSomeClass(Object class) (subsignature match)
			// Don't add a warning.
			if (selected == null)
				continue;

			if (!selected.booleanValue())
				addSelectionWarning= true;

			if (!newName.equals(newNameOfRipple))
				addNameWarning= true;
		}
		if (addSelectionWarning || addNameWarning)
			warnings.add(new Warning(ripples, addSelectionWarning, addNameWarning));

		return (addSelectionWarning || addNameWarning);
	}

	private class Warning {

		private IFunction[] fRipple;
		private boolean fSelectionWarning;
		private boolean fNameWarning;

		public Warning(IFunction[] ripple, boolean isSelectionWarning, boolean isNameWarning) {
			fRipple= ripple;
			fSelectionWarning= isSelectionWarning;
			fNameWarning= isNameWarning;
		}

		public boolean isNameWarning() {
			return fNameWarning;
		}

		public IFunction[] getRipple() {
			return fRipple;
		}

		public boolean isSelectionWarning() {
			return fSelectionWarning;
		}
	}

	// ----------------- Processor creation --------

	private RenameMethodProcessor createVirtualMethodRenameProcessor(IFunction currentMethod, String newMethodName, IFunction[] ripples, ITypeHierarchy hierarchy) throws JavaScriptModelException {
		RenameMethodProcessor processor= new RenameVirtualMethodProcessor(currentMethod, ripples, fChangeManager, hierarchy, CATEGORY_METHOD_RENAME);
		initMethodProcessor(processor, newMethodName);
		return processor;
	}

	private RenameMethodProcessor createNonVirtualMethodRenameProcessor(IFunction currentMethod, String newMethodName) {
		RenameMethodProcessor processor= new RenameNonVirtualMethodProcessor(currentMethod, fChangeManager, CATEGORY_METHOD_RENAME);
		initMethodProcessor(processor, newMethodName);
		return processor;
	}

	private void initMethodProcessor(RenameMethodProcessor processor, String newMethodName) {
		processor.setNewElementName(newMethodName);
		processor.setUpdateReferences(getUpdateReferences());
	}

	private RenameFieldProcessor createFieldRenameProcessor(final IField field, final String newName) {
		final RenameFieldProcessor processor= new RenameFieldProcessor(field, fChangeManager, CATEGORY_FIELD_RENAME);
		processor.setNewElementName(newName);
		processor.setRenameGetter(false);
		processor.setRenameSetter(false);
		processor.setUpdateReferences(getUpdateReferences());
		processor.setUpdateTextualMatches(false);
		return processor;
	}
	
	private RenameLocalVariableProcessor createLocalRenameProcessor(final ILocalVariable local, final String newName, final JavaScriptUnit compilationUnit) {
		final RenameLocalVariableProcessor processor= new RenameLocalVariableProcessor(local, fChangeManager, compilationUnit, CATEGORY_LOCAL_RENAME);
		processor.setNewElementName(newName);
		processor.setUpdateReferences(getUpdateReferences());
		return processor;
	}

	// ----------- Edit creation -----------


	/**
	 * Updates textual matches for fields.
	 * 
	 * Strategy for matching text matches: Match and replace all fully qualified
	 * field names, but non-qualified field names only iff there are no fields
	 * which have the same original, but a different new name. Don't add java
	 * references; duplicate edits may be created but do not matter.
	 * @param manager 
	 * @param monitor 
	 * @throws CoreException 
	 */
	private void addSimilarElementsTextualUpdates(TextChangeManager manager, IProgressMonitor monitor) throws CoreException {

		final Map simpleNames= new HashMap();
		final List forbiddenSimpleNames= new ArrayList();

		for (Iterator iter= fFinalSimilarElementToName.keySet().iterator(); iter.hasNext();) {
			final IJavaScriptElement element= (IJavaScriptElement) iter.next();
			if (element instanceof IField) {

				if (forbiddenSimpleNames.contains(element.getElementName()))
					continue;

				final String registeredNewName= (String) simpleNames.get(element.getElementName());
				final String newNameToCheck= (String) fFinalSimilarElementToName.get(element);
				if (registeredNewName == null)
					simpleNames.put(element.getElementName(), newNameToCheck);
				else if (!registeredNewName.equals(newNameToCheck))
					forbiddenSimpleNames.add(element.getElementName());
			}
		}

		for (Iterator iter= fFinalSimilarElementToName.keySet().iterator(); iter.hasNext();) {
			final IJavaScriptElement element= (IJavaScriptElement) iter.next();
			if (element instanceof IField) {
				final IField field= (IField) element;
				final String newName= (String) fFinalSimilarElementToName.get(field);
				TextMatchUpdater.perform(monitor, RefactoringScopeFactory.create(field), field.getElementName(), field.getDeclaringType().getFullyQualifiedName(), newName, manager,
						new SearchResultGroup[0], forbiddenSimpleNames.contains(field.getElementName()));
			}
		}
	}

	// ------ UI interaction

	/**
	 * @return the map of similarly named elements (IJavaScriptElement -> String with new name)
	 * This map is live. Callers may change the new names of the elements; they
	 * may not change the key set.
	 */
	public Map/* <IJavaScriptElement, String> */getSimilarElementsToNewNames() {
		return fPreloadedElementToName;
	}

	/**
	 * @return the map of similarly named elements (IJavaScriptElement -> Boolean if selected) This
	 * map is live. Callers may change the selection status of the elements;
	 * they may not change the key set.
	 */
	public Map/* <IJavaScriptElement, Boolean> */getSimilarElementsToSelection() {
		return fPreloadedElementToSelection;
	}

	/**
	 * Resets the element maps back to the original status. This affects the
	 * maps returned in {@link #getSimilarElementsToNewNames() } and
	 * {@link #getSimilarElementsToSelection() }. All new names are reset to
	 * the calculated ones and every element gets selected.
	 */
	public void resetSelectedSimilarElements() {
		Assert.isNotNull(fPreloadedElementToName);
		for (Iterator iter= fPreloadedElementToNameDefault.keySet().iterator(); iter.hasNext();) {
			final IJavaScriptElement element= (IJavaScriptElement) iter.next();
			fPreloadedElementToName.put(element, fPreloadedElementToNameDefault.get(element));
			fPreloadedElementToSelection.put(element, Boolean.TRUE);
		}
	}

	/**
	 * @return true iff the "update similarly named elements" flag is set AND the
	 * search yielded some elements to be renamed.
	 */
	public boolean hasSimilarElementsToRename() {
		if (!fUpdateSimilarElements)
			return false;
		if (fPreloadedElementToName == null)
			return false;
		if (fPreloadedElementToName.size() == 0)
			return false;
		return true;
	}
}
