/*
 * User: anna
 * Date: 21-Mar-2008
 */
package com.intellij.codeInsight.daemon.impl.quickfix;

import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class SurroundWithArrayFix extends PsiElementBaseIntentionAction {
  private final PsiMethodCallExpression myMethodCall;

  public SurroundWithArrayFix(final PsiMethodCallExpression methodCall) {
    myMethodCall = methodCall;
  }

  @NotNull
  public String getText() {
    return "Surround with array initialization";
  }

  @NotNull
  public String getFamilyName() {
    return getText();
  }

  public boolean isAvailable(@NotNull final Project project, final Editor editor, @Nullable final PsiElement element) {
    return myMethodCall != null && myMethodCall.isValid() && getExpression(element) != null;
 }

  @Nullable
  private PsiExpression getExpression(PsiElement element) {
    final PsiElement method = myMethodCall.getMethodExpression().resolve();
    if (method != null) {
      final PsiMethod psiMethod = (PsiMethod)method;
      final PsiParameter[] psiParameters = psiMethod.getParameterList().getParameters();
      final PsiExpressionList argumentList = myMethodCall.getArgumentList();
      int idx = 0;
      for (PsiExpression expression : argumentList.getExpressions()) {
        if (element != null && PsiTreeUtil.isAncestor(expression, element, false)) {
          if (psiParameters.length > idx) {
            final PsiType paramType = psiParameters[idx].getType();
            if (paramType instanceof PsiArrayType) {
              final PsiType expressionType = expression.getType();
              if (expressionType != null && expressionType.isAssignableFrom(((PsiArrayType)paramType).getComponentType())) {
                return expression;
              }
            }
          }
        }
        idx++;
      }
    }
    return null;
  }

  public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException {
    if (!CodeInsightUtilBase.prepareFileForWrite(file)) return;
    final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory();
    final PsiExpression expression = getExpression(file.findElementAt(editor.getCaretModel().getOffset()));
    assert expression != null;
    final PsiExpression toReplace = elementFactory.createExpressionFromText(getArrayCreation(expression), myMethodCall);
    JavaCodeStyleManager.getInstance(project).shortenClassReferences(expression.replace(toReplace));
  }

  @NonNls
  private static String getArrayCreation(@NotNull PsiExpression expression) {
    final PsiType expressionType = expression.getType();
    assert expressionType != null;
    return "new " + expressionType.getCanonicalText() + "[]{" + expression.getText()+ "}";
  }

  public boolean startInWriteAction() {
    return true;
  }
}
@@ -144,16 +144,67 @@
 ilBase;%0A
+import com.intellij.codeInsight.TargetElementUtil;%0A
 import c
@@ -662,16 +662,46 @@
 lable;%0A%0A
+import java.util.Collection;%0A%0A
 public c
@@ -1402,22 +1402,44 @@
  Psi
-Element method
+ReferenceExpression methodExpression
  = m
@@ -1471,16 +1471,64 @@
 ession()
+;%0A    final PsiElement method = methodExpression
 .resolve
@@ -1608,24 +1608,588 @@
 d)method;%0A  
+    return checkMethod(element, psiMethod);%0A    %7D else %7B%0A      final Collection%3CPsiElement%3E psiElements = TargetElementUtil.getInstance().getTargetCandidates(methodExpression);%0A      for (PsiElement psiElement : psiElements) %7B%0A        if (psiElement instanceof PsiMethod) %7B%0A          final PsiExpression expression = checkMethod(element, (PsiMethod)psiElement);%0A          if (expression != null) return expression;%0A        %7D%0A      %7D%0A    %7D%0A    return null;%0A  %7D%0A%0A  @Nullable%0A  private PsiExpression checkMethod(final PsiElement element, final PsiMethod psiMethod) %7B%0A
     final Ps
@@ -2263,26 +2263,24 @@
 ters();%0A    
-  
 final PsiExp
@@ -2342,18 +2342,16 @@
 ();%0A    
-  
 int idx 
@@ -2355,26 +2355,24 @@
 dx = 0;%0A    
- 
- 
 for (PsiExpr
@@ -2420,26 +2420,24 @@
 ssions()) %7B%0A
-  
       if (el
@@ -2503,26 +2503,24 @@
 , false)) %7B%0A
-  
         if (
@@ -2551,34 +2551,32 @@
 dx) %7B%0A          
-  
 final PsiType pa
@@ -2621,26 +2621,24 @@
 ;%0A          
-  
 if (paramTyp
@@ -2670,34 +2670,32 @@
 ) %7B%0A            
- 
- 
 final PsiType ex
@@ -2723,34 +2723,32 @@
 sion.getType();%0A
-  
             if (
@@ -2864,26 +2864,24 @@
             
-  
 return expre
@@ -2891,24 +2891,8 @@
 on;%0A
-              %7D%0A
     
@@ -2921,24 +2921,30 @@
         %7D%0A  
+    %7D%0A
       idx++;
@@ -2944,24 +2944,16 @@
  idx++;%0A
-      %7D%0A
     %7D%0A  

enable surround with array initialization fix for ambigous method calls