content: /*******************************************************************************
   * Copyright (c) 2000, 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.ui.text.correction;
  
  import java.util.List;
  
  import org.eclipse.core.runtime.CoreException;
  import org.eclipse.swt.graphics.Image;
  import org.eclipse.wst.jsdt.core.IJavaScriptProject;
  import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
  import org.eclipse.wst.jsdt.core.dom.AST;
  import org.eclipse.wst.jsdt.core.dom.ASTNode;
  import org.eclipse.wst.jsdt.core.dom.AnonymousClassDeclaration;
  import org.eclipse.wst.jsdt.core.dom.ClassInstanceCreation;
  import org.eclipse.wst.jsdt.core.dom.Expression;
  import org.eclipse.wst.jsdt.core.dom.ExpressionStatement;
  import org.eclipse.wst.jsdt.core.dom.FunctionInvocation;
  import org.eclipse.wst.jsdt.core.dom.IBinding;
  import org.eclipse.wst.jsdt.core.dom.ITypeBinding;
  import org.eclipse.wst.jsdt.core.dom.Modifier;
  import org.eclipse.wst.jsdt.core.dom.Name;
  import org.eclipse.wst.jsdt.core.dom.SimpleName;
  import org.eclipse.wst.jsdt.core.dom.SingleVariableDeclaration;
  import org.eclipse.wst.jsdt.core.dom.SuperMethodInvocation;
  import org.eclipse.wst.jsdt.core.dom.Type;
  import org.eclipse.wst.jsdt.core.dom.rewrite.ASTRewrite;
  import org.eclipse.wst.jsdt.internal.corext.codemanipulation.StubUtility;
  import org.eclipse.wst.jsdt.internal.corext.dom.ASTNodes;
  import org.eclipse.wst.jsdt.internal.corext.dom.Bindings;
  
  public class NewMethodCompletionProposal extends AbstractMethodCompletionProposal {
  
  	private static final String KEY_NAME= "name"; //$NON-NLS-1$
  	private static final String KEY_TYPE= "type"; //$NON-NLS-1$
  
  	private List fArguments;
  
  	//	invocationNode is FunctionInvocation, ConstructorInvocation, SuperConstructorInvocation, ClassInstanceCreation, SuperMethodInvocation
  	public NewMethodCompletionProposal(String label, IJavaScriptUnit targetCU, ASTNode invocationNode,  List arguments, ITypeBinding binding, int relevance, Image image) {
  		super(label, targetCU, invocationNode, binding, relevance, image);
  		fArguments= arguments;
  	}
  
  	private int evaluateModifiers(ASTNode targetTypeDecl) {
  		ASTNode invocationNode= getInvocationNode();
  		if (invocationNode instanceof FunctionInvocation) {
  			int modifiers= 0;
  			Expression expression= ((FunctionInvocation)invocationNode).getExpression();
  			if (expression != null) {
  				if (expression instanceof Name && ((Name) expression).resolveBinding().getKind() == IBinding.TYPE) {
  					modifiers |= Modifier.STATIC;
  				}
  			} else if (ASTResolving.isInStaticContext(invocationNode)) {
  				modifiers |= Modifier.STATIC;
  			}
  			ASTNode node= ASTResolving.findParentType(invocationNode);
  			if (targetTypeDecl.equals(node)) {
  				modifiers |= Modifier.PRIVATE;
  			} else if (node instanceof AnonymousClassDeclaration && ASTNodes.isParent(node, targetTypeDecl)) {
  				modifiers |= Modifier.PROTECTED;
  				if (ASTResolving.isInStaticContext(node)) {
  					modifiers |= Modifier.STATIC;
  				}
  			} else {
  				modifiers |= Modifier.PUBLIC;
  			}
  			return modifiers;
  		}
  		return Modifier.PUBLIC;
  	}
  	
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.ui.text.correction.AbstractMethodCompletionProposal#addNewModifiers(org.eclipse.wst.jsdt.core.dom.rewrite.ASTRewrite, java.util.List)
  	 */
  	protected void addNewModifiers(ASTRewrite rewrite, ASTNode targetTypeDecl, List modifiers) {
  		modifiers.addAll(rewrite.getAST().newModifiers(evaluateModifiers(targetTypeDecl)));
  		ModifierCorrectionSubProcessor.installLinkedVisibilityProposals(getLinkedProposalModel(), rewrite, modifiers, false);
  	}
  
  
  	/*(non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.ui.text.correction.AbstractMethodCompletionProposal#isConstructor()
  	 */
  	protected boolean isConstructor() {
  		ASTNode node= getInvocationNode();
  
  		return node.getNodeType() != ASTNode.FUNCTION_INVOCATION && node.getNodeType() != ASTNode.SUPER_METHOD_INVOCATION;
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.ui.text.correction.AbstractMethodCompletionProposal#getNewName(org.eclipse.wst.jsdt.core.dom.rewrite.ASTRewrite)
  	 */
  	protected SimpleName getNewName(ASTRewrite rewrite) {
  		ASTNode invocationNode= getInvocationNode();
  		String name;
  		if (invocationNode instanceof FunctionInvocation) {
  			name= ((FunctionInvocation)invocationNode).getName().getIdentifier();
  		} else if (invocationNode instanceof SuperMethodInvocation) {
  			name= ((SuperMethodInvocation)invocationNode).getName().getIdentifier();
  		} else {
  			name= getSenderBinding().getName(); // name of the class
  		}
  		AST ast= rewrite.getAST();
  		SimpleName newNameNode= ast.newSimpleName(name);
  		addLinkedPosition(rewrite.track(newNameNode), false, KEY_NAME);
  
  		ASTNode invocationName= getInvocationNameNode();
  		if (invocationName != null && invocationName.getAST() == ast) { // in the same CU
  			addLinkedPosition(rewrite.track(invocationName), true, KEY_NAME);
  		}
  		return newNameNode;
  	}
  
  	private ASTNode getInvocationNameNode() {
  		ASTNode node= getInvocationNode();
  		if (node instanceof FunctionInvocation) {
  			return ((FunctionInvocation)node).getName();
  		} else if (node instanceof SuperMethodInvocation) {
  			return ((SuperMethodInvocation)node).getName();
  		} else if (node instanceof ClassInstanceCreation) {
  			Type type= ((ClassInstanceCreation)node).getType();
  			return type;
  		}
  		return null;
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.ui.text.correction.AbstractMethodCompletionProposal#getNewMethodType(org.eclipse.wst.jsdt.core.dom.rewrite.ASTRewrite)
  	 */
  	protected Type getNewMethodType(ASTRewrite rewrite) throws CoreException {
  		ASTNode node= getInvocationNode();
  		AST ast= rewrite.getAST();
  
  		Type newTypeNode= null;
  		ITypeBinding[] otherProposals= null;
  
  		if (node.getParent() instanceof FunctionInvocation) {
  			FunctionInvocation parent= (FunctionInvocation) node.getParent();
  			if (parent.getExpression() == node) {
  				ITypeBinding[] bindings= ASTResolving.getQualifierGuess(node.getRoot(), parent.getName().getIdentifier(), parent.arguments(), getSenderBinding());
  				if (bindings.length > 0) {
  					newTypeNode= getImportRewrite().addImport(bindings[0], ast);
  					otherProposals= bindings;
  				}
  			}
  		}
  		if (newTypeNode == null) {
  			ITypeBinding binding= ASTResolving.guessBindingForReference(node);
  			if (binding != null) {
  				newTypeNode= getImportRewrite().addImport(binding, ast);
  			} else {
  				ASTNode parent= node.getParent();
  				if (parent instanceof ExpressionStatement) {
  					return null;
  				}
  				newTypeNode= ASTResolving.guessTypeForReference(ast, node);
  				if (newTypeNode == null) {
  					newTypeNode= ast.newSimpleType(ast.newSimpleName("Object")); //$NON-NLS-1$
  				}
  			}
  		}
  
  		addLinkedPosition(rewrite.track(newTypeNode), false, KEY_TYPE);
  		if (otherProposals != null) {
  			for (int i= 0; i < otherProposals.length; i++) {
  				addLinkedPositionProposal(KEY_TYPE, otherProposals[i]);
  			}
  		}
  
  		return newTypeNode;
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.ui.text.correction.AbstractMethodCompletionProposal#addNewParameters(org.eclipse.wst.jsdt.core.dom.rewrite.ASTRewrite, java.util.List, java.util.List)
  	 */
  	protected void addNewParameters(ASTRewrite rewrite, List takenNames, List params) throws CoreException {
  		AST ast= rewrite.getAST();
  
  		List arguments= fArguments;
  
  		for (int i= 0; i < arguments.size(); i++) {
  			Expression elem= (Expression) arguments.get(i);
  			SingleVariableDeclaration param= ast.newSingleVariableDeclaration();
  
  			// argument type
  			String argTypeKey= "arg_type_" + i; //$NON-NLS-1$
  			Type type= evaluateParameterType(ast, elem, argTypeKey);
  			param.setType(type);
  
  			// argument name
  			String argNameKey= "arg_name_" + i; //$NON-NLS-1$
  			String name= evaluateParameterName(takenNames, elem, type, argNameKey);
  			param.setName(ast.newSimpleName(name));
  
  			params.add(param);
  
  			addLinkedPosition(rewrite.track(param.getType()), false, argTypeKey);
  			addLinkedPosition(rewrite.track(param.getName()), false, argNameKey);
  		}
  	}
  
  	private Type evaluateParameterType(AST ast, Expression elem, String key) throws CoreException {
  		ITypeBinding binding= Bindings.normalizeTypeBinding(elem.resolveTypeBinding());
  		if (binding != null) {
  			ITypeBinding[] typeProposals= ASTResolving.getRelaxingTypes(ast, binding);
  			for (int i= 0; i < typeProposals.length; i++) {
  				addLinkedPositionProposal(key, typeProposals[i]);
  			}
  			return getImportRewrite().addImport(binding, ast);
  		}
  		return ast.newSimpleType(ast.newSimpleName("Object")); //$NON-NLS-1$
  	}
  
  	private String evaluateParameterName(List takenNames, Expression argNode, Type type, String key) {
  		IJavaScriptProject project= getCompilationUnit().getJavaScriptProject();
  		String[] names= StubUtility.getVariableNameSuggestions(StubUtility.PARAMETER, project, type, argNode, takenNames);
  		for (int i= 0; i < names.length; i++) {
  			addLinkedPositionProposal(key, names[i], null);
  		}
  		String favourite= names[0];
  		takenNames.add(favourite);
  		return favourite;
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.ui.text.correction.AbstractMethodCompletionProposal#addNewExceptions(org.eclipse.wst.jsdt.core.dom.rewrite.ASTRewrite, java.util.List)
  	 */
  	protected void addNewExceptions(ASTRewrite rewrite, List exceptions) throws CoreException {
  	}
  }
  