content: /*******************************************************************************
   * Copyright (c) 2006, 2009 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.refactoring.code;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  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.IProgressMonitor;
  import org.eclipse.core.runtime.OperationCanceledException;
  import org.eclipse.core.runtime.SubProgressMonitor;
  import org.eclipse.jface.text.BadLocationException;
  import org.eclipse.jface.text.Document;
  import org.eclipse.jface.text.IDocument;
  import org.eclipse.ltk.core.refactoring.Change;
  import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
  import org.eclipse.ltk.core.refactoring.RefactoringStatus;
  import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
  import org.eclipse.ltk.core.refactoring.participants.ResourceChangeChecker;
  import org.eclipse.text.edits.MalformedTreeException;
  import org.eclipse.text.edits.MultiTextEdit;
  import org.eclipse.text.edits.TextEdit;
  import org.eclipse.text.edits.TextEditGroup;
  import org.eclipse.wst.jsdt.core.Flags;
  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.IJavaScriptProject;
  import org.eclipse.wst.jsdt.core.IFunction;
  import org.eclipse.wst.jsdt.core.IType;
  import org.eclipse.wst.jsdt.core.ITypeHierarchy;
  import org.eclipse.wst.jsdt.core.ITypeRoot;
  import org.eclipse.wst.jsdt.core.JavaScriptModelException;
  import org.eclipse.wst.jsdt.core.dom.AST;
  import org.eclipse.wst.jsdt.core.dom.ASTNode;
  import org.eclipse.wst.jsdt.core.dom.ASTParser;
  import org.eclipse.wst.jsdt.core.dom.Block;
  import org.eclipse.wst.jsdt.core.dom.BodyDeclaration;
  import org.eclipse.wst.jsdt.core.dom.JavaScriptUnit;
  import org.eclipse.wst.jsdt.core.dom.ExpressionStatement;
  import org.eclipse.wst.jsdt.core.dom.IBinding;
  import org.eclipse.wst.jsdt.core.dom.IFunctionBinding;
  import org.eclipse.wst.jsdt.core.dom.FunctionDeclaration;
  import org.eclipse.wst.jsdt.core.dom.FunctionInvocation;
  import org.eclipse.wst.jsdt.core.dom.Modifier;
  import org.eclipse.wst.jsdt.core.dom.SimpleName;
  import org.eclipse.wst.jsdt.core.dom.SingleVariableDeclaration;
  import org.eclipse.wst.jsdt.core.dom.rewrite.ASTRewrite;
  import org.eclipse.wst.jsdt.core.dom.rewrite.ImportRewrite;
  import org.eclipse.wst.jsdt.core.refactoring.descriptors.JavaScriptRefactoringDescriptor;
  import org.eclipse.wst.jsdt.internal.corext.dom.NodeFinder;
  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.RefactoringCoreMessages;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.base.JavaStatusContext;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.binary.StubCreator;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.CompilationUnitChange;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.util.RefactoringASTParser;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.util.TextChangeManager;
  import org.eclipse.wst.jsdt.internal.corext.util.Messages;
  import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
  import org.eclipse.wst.jsdt.internal.ui.viewsupport.BindingLabelProvider;
  import org.eclipse.wst.jsdt.ui.JavaScriptElementLabels;
  
  public class ReplaceInvocationsRefactoring extends ScriptableRefactoring {
  
  	private static final String ID_REPLACE_INVOCATIONS= "org.eclipse.wst.jsdt.ui.replace.invocations"; //$NON-NLS-1$
  	private static final String ATTRIBUTE_MODE= "mode"; //$NON-NLS-1$
  
  	public static class Mode {
  		private Mode() {
  		}
  		public static final Mode REPLACE_ALL= new Mode();
  		public static final Mode REPLACE_SINGLE= new Mode();
  	}
  
  	private final ITypeRoot fSelectionTypeRoot;
  	/**
  	 * only set if initial mode is REPLACE_SINGLE
  	 */
  	private final int fSelectionStart;
  	/**
  	 * only set if initial mode is REPLACE_SINGLE
  	 */
  	private final int fSelectionLength;
  	
  	private ASTNode fSelectionNode;
  	/**
  	 * only set after checkInitialConditions
  	 */
  	private IFunction fMethod;
  	
  	private String fBody;
  	private String[] fParameterNames;
  	
  	private SourceProvider fSourceProvider; // resolved once in checkInitialConditions
  	private TargetProvider fTargetProvider; // flexible
  	
  	private TextChangeManager fChangeManager;
  	private IFunctionBinding fMethodBinding;
  	
  	public ReplaceInvocationsRefactoring(ITypeRoot typeRoot, int offset, int length) {
  		fSelectionTypeRoot= typeRoot;
  		fSelectionStart= offset;
  		fSelectionLength= length;
  	}
  
  	public ReplaceInvocationsRefactoring(IFunction method) {
  		fMethod= method;
  		fSelectionTypeRoot= method.getTypeRoot();
  		fSelectionStart= -1;
  		fSelectionLength= -1;
  	}
  	
  	public String getName() {
  		return RefactoringCoreMessages.ReplaceInvocationsRefactoring_name;
  	}
  	
  	/**
  	 * Only to be called after {@link #checkInitialConditions(IProgressMonitor)}
  	 */
  	public boolean canReplaceSingle() {
  		return fSelectionNode instanceof FunctionInvocation;
  	}
  	
  	/**
  	 * Only to be called after {@link #checkInitialConditions(IProgressMonitor)}
  	 */
  	public RefactoringStatus setCurrentMode(Mode mode) throws JavaScriptModelException {
  		if (fTargetProvider.isSingle() == (mode == Mode.REPLACE_SINGLE))
  			return new RefactoringStatus();
  		Assert.isTrue(canReplaceSingle());
  		if (mode == Mode.REPLACE_SINGLE) {
  			fTargetProvider= TargetProvider.create((IJavaScriptUnit) fSelectionTypeRoot, (FunctionInvocation) fSelectionNode);
  		} else {
  			fTargetProvider= TargetProvider.create(fSourceProvider.getDeclaration());
  		}
  		return fTargetProvider.checkActivation();
  	}
  	
  	public void setBody(String body, String[] parameterNames) {
  		//TODO: validate parameter name count and body
  		fBody= body;
  		fParameterNames= parameterNames;
  	}
  	
  	public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
  		// TargetProvider must get an untampered AST with original invocation node
  		// SourceProvider must get a tweaked AST with method body / parameter names replaced
  		
  		RefactoringStatus result= new RefactoringStatus();
  		
  		if (fMethod == null) {
  			if (! (fSelectionTypeRoot instanceof IJavaScriptUnit))
  				return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ReplaceInvocationsRefactoring_cannot_replace_in_binary);
  			
  			IJavaScriptUnit cu= (IJavaScriptUnit) fSelectionTypeRoot;
  			JavaScriptUnit root= new RefactoringASTParser(AST.JLS3).parse(cu, true);
  			fSelectionNode= getTargetNode(cu, root, fSelectionStart, fSelectionLength);
  			if (fSelectionNode == null)
  				return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ReplaceInvocationsRefactoring_select_method_to_apply);
  			
  			if (fSelectionNode.getNodeType() == ASTNode.FUNCTION_DECLARATION) {
  				FunctionDeclaration methodDeclaration= (FunctionDeclaration) fSelectionNode;
  				fTargetProvider= TargetProvider.create(methodDeclaration);
  				fMethodBinding= methodDeclaration.resolveBinding();
  			} else {
  				FunctionInvocation methodInvocation= (FunctionInvocation) fSelectionNode;
  				fTargetProvider= TargetProvider.create(cu, methodInvocation);
  				fMethodBinding= methodInvocation.resolveMethodBinding();
  			}
  			if (fMethodBinding == null)
  				return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InlineMethodRefactoring_error_noMethodDeclaration);
  			fMethod= (IFunction) fMethodBinding.getJavaElement();
  			
  		} else {
  			ASTParser parser= ASTParser.newParser(AST.JLS3);
  			parser.setProject(fMethod.getJavaScriptProject());
  			IBinding[] bindings= parser.createBindings(new IJavaScriptElement[] { fMethod }, null);
  			fMethodBinding= (IFunctionBinding) bindings[0];
  			if (fMethodBinding == null)
  				return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InlineMethodRefactoring_error_noMethodDeclaration);
  			
  			fTargetProvider= TargetProvider.create(fMethodBinding);
  		}
  		
  		result.merge(fTargetProvider.checkActivation());
  		return result;
  	}
  	
  	private SourceProvider resolveSourceProvider(IFunctionBinding methodBinding, RefactoringStatus status) throws JavaScriptModelException {
  		final IFunction method= (IFunction) methodBinding.getJavaElement();
  		
  		ITypeRoot typeRoot;
  		IDocument source;
  		JavaScriptUnit methodDeclarationAstRoot;
  		
  		IJavaScriptUnit methodCu= (method).getJavaScriptUnit();
  		if (methodCu != null) {
  			typeRoot= methodCu;
  			ASTParser parser= ASTParser.newParser(AST.JLS3);
  			parser.setSource(methodCu);
  			parser.setFocalPosition(method.getNameRange().getOffset());
  			JavaScriptUnit compilationUnit= (JavaScriptUnit) parser.createAST(null);
  			FunctionDeclaration methodDecl= (FunctionDeclaration) NodeFinder.perform(compilationUnit, method.getNameRange()).getParent();
  			AST ast= compilationUnit.getAST();
  			ASTRewrite rewrite= ASTRewrite.create(ast);
  			Block newBody= ast.newBlock();
  			newBody.statements().add(rewrite.createStringPlaceholder(fBody, ASTNode.EMPTY_STATEMENT));
  			rewrite.replace(methodDecl.getBody(), newBody, null);
  			List parameters= methodDecl.parameters();
  			for (int i= 0; i < parameters.size(); i++) {
  				SingleVariableDeclaration parameter= (SingleVariableDeclaration) parameters.get(i);
  				rewrite.set(parameter.getName(), SimpleName.IDENTIFIER_PROPERTY, fParameterNames[i], null);
  			}
  			TextEdit textEdit= rewrite.rewriteAST();
  			Document document= new Document(methodCu.getBuffer().getContents());
  			try {
  				textEdit.apply(document);
  			} catch (MalformedTreeException e) {
  				JavaScriptPlugin.log(e);
  			} catch (BadLocationException e) {
  				JavaScriptPlugin.log(e);
  			}
  			source= document;
  			
  			methodDeclarationAstRoot= new RefactoringASTParser(AST.JLS3).parse(source.get(), methodCu, true, true, null);
  			
  		} else {
  			IClassFile classFile= method.getClassFile();
  			//TODO: use source if available?
  			StubCreator stubCreator= new StubCreator(true) {
  				protected void appendMethodBody(IFunction currentMethod) throws JavaScriptModelException {
  					if (currentMethod.equals(method)) {
  						fBuffer.append(fBody);
  					} else {
  						super.appendMethodBody(currentMethod);
  					}
  				}
  				/*
  				 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.binary.StubCreator#appendMethodParameterName(org.eclipse.wst.jsdt.core.IFunction, int)
  				 */
  				protected void appendMethodParameterName(IFunction currentMethod, int index) {
  					if (currentMethod.equals(method)) {
  						fBuffer.append(fParameterNames[index]);
  					} else {
  						super.appendMethodParameterName(currentMethod, index);
  					}
  				}
  			};
  			
  			String stub= stubCreator.createStub(classFile.getType(), null);
  			source= new Document(stub);
  			methodDeclarationAstRoot= new RefactoringASTParser(AST.JLS3).parse(stub, classFile, true, true, null);
  			typeRoot= classFile;
  		}
  		ASTNode node= methodDeclarationAstRoot.findDeclaringNode(methodBinding.getKey());
  		if (node instanceof FunctionDeclaration) {
  			return new SourceProvider(typeRoot, source, (FunctionDeclaration) node);
  		} else {
  			status.addFatalError(RefactoringCoreMessages.ReplaceInvocationsRefactoring_cannot_find_method_declaration);
  			return null;
  		}
  	}
  	
  	/**
  	 * @return an invocation or declaration node
  	 */
  	private static ASTNode getTargetNode(IJavaScriptUnit unit, JavaScriptUnit root, int offset, int length) {
  		ASTNode node= null;
  		try {
  			node= checkNode(NodeFinder.perform(root, offset, length, unit), unit);
  		} catch(JavaScriptModelException e) {
  			// Do nothing
  		}
  		if (node != null)
  			return node;
  		return checkNode(NodeFinder.perform(root, offset, length), unit);
  	}
  
  	private static ASTNode checkNode(ASTNode node, IJavaScriptUnit unit) {
  		if (node == null)
  			return null;
  		if (node.getNodeType() == ASTNode.SIMPLE_NAME) {
  			node= node.getParent();
  		} else if (node.getNodeType() == ASTNode.EXPRESSION_STATEMENT) {
  			node= ((ExpressionStatement)node).getExpression();
  		}
  		switch(node.getNodeType()) {
  			case ASTNode.FUNCTION_DECLARATION:
  			case ASTNode.FUNCTION_INVOCATION:
  // not yet...
  //			case ASTNode.SUPER_METHOD_INVOCATION:
  //			case ASTNode.CONSTRUCTOR_INVOCATION:
  				return node;
  		}
  		return null;
  	}
  	
  	public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException {
  		pm.beginTask("", 20); //$NON-NLS-1$
  		fChangeManager= new TextChangeManager();
  		RefactoringStatus result= new RefactoringStatus();
  		
  		fSourceProvider= resolveSourceProvider(fMethodBinding, result);
  		if (result.hasFatalError())
  			return result;
  		
  		result.merge(fSourceProvider.checkActivation());
  		if (result.hasFatalError())
  			return result;
  		
  		fSourceProvider.initialize();
  		fTargetProvider.initialize();
  		pm.setTaskName(RefactoringCoreMessages.InlineMethodRefactoring_searching);
  		RefactoringStatus searchStatus= new RefactoringStatus();
  		IJavaScriptUnit[] units= fTargetProvider.getAffectedCompilationUnits(searchStatus, new SubProgressMonitor(pm, 1));
  		if (searchStatus.hasFatalError()) {
  			result.merge(searchStatus);
  			return result;
  		}
  		IFile[] filesToBeModified= getFilesToBeModified(units);
  		result.merge(Checks.validateModifiesFiles(filesToBeModified, getValidationContext()));
  		if (result.hasFatalError())
  			return result;
  		result.merge(ResourceChangeChecker.checkFilesToBeChanged(filesToBeModified, new SubProgressMonitor(pm, 1)));
  		checkOverridden(result, new SubProgressMonitor(pm, 4));
  		IProgressMonitor sub= new SubProgressMonitor(pm, 15);
  		sub.beginTask("", units.length * 3); //$NON-NLS-1$
  		for (int c= 0; c < units.length; c++) {
  			IJavaScriptUnit unit= units[c];
  			sub.subTask(Messages.format(RefactoringCoreMessages.InlineMethodRefactoring_processing,  unit.getElementName())); 
  			CallInliner inliner= null;
  			try {
  				boolean added= false;
  				MultiTextEdit root= new MultiTextEdit();
  				CompilationUnitChange change= (CompilationUnitChange)fChangeManager.get(unit);
  				change.setEdit(root);
  				BodyDeclaration[] bodies= fTargetProvider.getAffectedBodyDeclarations(unit, new SubProgressMonitor(pm, 1));
  				if (bodies.length == 0)
  					continue;
  				inliner= new CallInliner(unit, (JavaScriptUnit) bodies[0].getRoot(), fSourceProvider);
  				for (int b= 0; b < bodies.length; b++) {
  					BodyDeclaration body= bodies[b];
  					inliner.initialize(body);
  					RefactoringStatus nestedInvocations= new RefactoringStatus();
  					ASTNode[] invocations= removeNestedCalls(nestedInvocations, unit, 
  						fTargetProvider.getInvocations(body, new SubProgressMonitor(sub, 2)));
  					for (int i= 0; i < invocations.length; i++) {
  						ASTNode invocation= invocations[i];
  						result.merge(inliner.initialize(invocation, fTargetProvider.getStatusSeverity()));
  						if (result.hasFatalError())
  							break;
  						if (result.getSeverity() < fTargetProvider.getStatusSeverity()) {
  							added= true;
  							TextEditGroup group= new TextEditGroup(RefactoringCoreMessages.InlineMethodRefactoring_edit_inline); 
  							change.addTextEditGroup(group);
  							result.merge(inliner.perform(group)); 
  						}
  					}
  					// do this after we have inlined the method calls. We still want
  					// to generate the modifications.
  					result.merge(nestedInvocations);
  				}
  				if (!added) {
  					fChangeManager.remove(unit);
  				} else {
  					root.addChild(inliner.getModifications());
  					ImportRewrite rewrite= inliner.getImportEdit();
  					if (rewrite.hasRecordedChanges()) {
  						TextEdit edit= rewrite.rewriteImports(null);
  						if (edit instanceof MultiTextEdit ? ((MultiTextEdit)edit).getChildrenSize() > 0 : true) {
  							root.addChild(edit);
  							change.addTextEditGroup(
  								new TextEditGroup(RefactoringCoreMessages.InlineMethodRefactoring_edit_import, new TextEdit[] {edit})); 
  						}
  					}
  				}
  			} finally {
  				if (inliner != null)
  					inliner.dispose();
  			}
  			sub.worked(1);
  			if (sub.isCanceled())
  				throw new OperationCanceledException();
  		}
  		result.merge(searchStatus);
  		sub.done();
  		pm.done();
  		return result;
  	}
  
  	public Change createChange(IProgressMonitor pm) throws CoreException {
  		// TODO: update for fSelectionStart == -1
  		final Map arguments= new HashMap();
  		String project= null;
  		IJavaScriptProject javaProject= fSelectionTypeRoot.getJavaScriptProject();
  		if (javaProject != null)
  			project= javaProject.getElementName();
  		final IFunctionBinding binding= fSourceProvider.getDeclaration().resolveBinding();
  		int flags= RefactoringDescriptor.STRUCTURAL_CHANGE | JavaScriptRefactoringDescriptor.JAR_REFACTORING | JavaScriptRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
  		if (!Modifier.isPrivate(binding.getModifiers()))
  			flags|= RefactoringDescriptor.MULTI_CHANGE;
  		final String description= Messages.format(RefactoringCoreMessages.ReplaceInvocationsRefactoring_descriptor_description_short, binding.getName());
  		final String header= Messages.format(RefactoringCoreMessages.ReplaceInvocationsRefactoring_descriptor_description, new String[] { BindingLabelProvider.getBindingLabel(binding, JavaScriptElementLabels.ALL_FULLY_QUALIFIED), BindingLabelProvider.getBindingLabel(binding.getDeclaringClass(), JavaScriptElementLabels.ALL_FULLY_QUALIFIED)});
  		final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header);
  		comment.addSetting(Messages.format(RefactoringCoreMessages.ReplaceInvocationsRefactoring_original_pattern, BindingLabelProvider.getBindingLabel(binding, JavaScriptElementLabels.ALL_FULLY_QUALIFIED)));
  		if (!fTargetProvider.isSingle())
  			comment.addSetting(RefactoringCoreMessages.ReplaceInvocationsRefactoring_replace_references);
  		final JDTRefactoringDescriptor descriptor= new JDTRefactoringDescriptor(ID_REPLACE_INVOCATIONS, project, description, comment.asString(), arguments, flags);
  		arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_INPUT, descriptor.elementToHandle(fSelectionTypeRoot));
  		arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_SELECTION, Integer.valueOf(fSelectionStart).toString() + " " + Integer.valueOf(fSelectionLength).toString()); //$NON-NLS-1$
  		arguments.put(ATTRIBUTE_MODE, Integer.valueOf(fTargetProvider.isSingle() ? 0 : 1).toString());
  		return new DynamicValidationRefactoringChange(descriptor, RefactoringCoreMessages.ReplaceInvocationsRefactoring_change_name, fChangeManager.getAllChanges());
  	}
  	
  	private IFile[] getFilesToBeModified(IJavaScriptUnit[] units) {
  		List result= new ArrayList(units.length + 1);
  		IFile file;
  		for (int i= 0; i < units.length; i++) {
  			file= getFile(units[i]);
  			if (file != null)
  				result.add(file);
  		}
  		return (IFile[])result.toArray(new IFile[result.size()]);
  	}
  	
  	private IFile getFile(IJavaScriptUnit unit) {
  		unit= unit.getPrimary();
  		IResource resource= unit.getResource();
  		if (resource != null && resource.getType() == IResource.FILE)
  			return (IFile)resource;
  		return null;
  	}
  	
  	private void checkOverridden(RefactoringStatus status, IProgressMonitor pm) throws JavaScriptModelException {
  		pm.beginTask("", 9); //$NON-NLS-1$
  		pm.setTaskName(RefactoringCoreMessages.InlineMethodRefactoring_checking_overridden); 
  		FunctionDeclaration decl= fSourceProvider.getDeclaration();
  		IFunction method= (IFunction) decl.resolveBinding().getJavaElement();
  		if (method == null || Flags.isPrivate(method.getFlags())) {
  			pm.worked(8);
  			return;
  		}
  		IType type= method.getDeclaringType();
  		ITypeHierarchy hierarchy= type.newTypeHierarchy(new SubProgressMonitor(pm, 6));
  		checkSubTypes(status, method, hierarchy.getAllSubtypes(type), new SubProgressMonitor(pm, 1));
  		checkSuperClasses(status, method, hierarchy.getAllSuperclasses(type), new SubProgressMonitor(pm, 1));
  		pm.setTaskName(""); //$NON-NLS-1$
  	}
  
  	private void checkSubTypes(RefactoringStatus result, IFunction method, IType[] types, IProgressMonitor pm) {
  		checkTypes(
  			result, method, types, 
  			RefactoringCoreMessages.InlineMethodRefactoring_checking_overridden_error,
  			pm);
  	}
  	
  	private void checkSuperClasses(RefactoringStatus result, IFunction method, IType[] types, IProgressMonitor pm) {
  		checkTypes(
  			result, method, types, 
  			RefactoringCoreMessages.InlineMethodRefactoring_checking_overrides_error,
  			pm);
  	}
  
  	private void checkTypes(RefactoringStatus result, IFunction method, IType[] types, String key, IProgressMonitor pm) {
  		pm.beginTask("", types.length); //$NON-NLS-1$
  		for (int i= 0; i < types.length; i++) {
  			pm.worked(1);
  			IFunction[] overridden= types[i].findMethods(method);
  			if (overridden != null && overridden.length > 0) {
  				result.addError(
  					Messages.format(key, types[i].getElementName()), 
  					JavaStatusContext.create(overridden[0]));
  			}
  		}
  	}
  	
  	private ASTNode[] removeNestedCalls(RefactoringStatus status, IJavaScriptUnit unit, ASTNode[] invocations) {
  		if (invocations.length <= 1)
  			return invocations;
  		ASTNode[] parents= new ASTNode[invocations.length];
  		for (int i= 0; i < invocations.length; i++) {
  			parents[i]= invocations[i].getParent();
  		}
  		for (int i= 0; i < invocations.length; i++) {
  			removeNestedCalls(status, unit, parents, invocations, i);
  		}
  		List result= new ArrayList();
  		for (int i= 0; i < invocations.length; i++) {
  			if (invocations[i] != null)
  				result.add(invocations[i]);
  		}
  		return (ASTNode[])result.toArray(new ASTNode[result.size()]);
  	}
  	
  	private void removeNestedCalls(RefactoringStatus status, IJavaScriptUnit unit, ASTNode[] parents, ASTNode[] invocations, int index) {
  		ASTNode invocation= invocations[index];
  		for (int i= 0; i < parents.length; i++) {
  			ASTNode parent= parents[i];
  			while (parent != null) {
  				if (parent == invocation) {
  					status.addError(RefactoringCoreMessages.InlineMethodRefactoring_nestedInvocation,  
  						JavaStatusContext.create(unit, parent));
  					invocations[index]= null;
  				}
  				parent= parent.getParent();
  			}
  		}
  	}
  
  	public RefactoringStatus initialize(final RefactoringArguments arguments) {
  		if (arguments instanceof JavaRefactoringArguments) {
  			final JavaRefactoringArguments generic= (JavaRefactoringArguments) arguments;
  			final String value= generic.getAttribute(ATTRIBUTE_MODE);
  			if (value != null && !"".equals(value)) {//$NON-NLS-1$
  				int mode= 0;
  				try {
  					mode= Integer.parseInt(value);
  				} catch (NumberFormatException exception) {
  					return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_MODE));
  				}
  				try {
  					setCurrentMode(mode == 1 ? Mode.REPLACE_ALL : Mode.REPLACE_SINGLE);
  				} catch (JavaScriptModelException exception) {
  					return RefactoringStatus.createFatalErrorStatus(exception.getLocalizedMessage());
  				}
  			}
  		} else
  			return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
  		return new RefactoringStatus();
  	}
  
  	public IFunction getMethod() {
  		return fMethod;
  	}
  
  }
  