/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * User: anna
 * Date: 04-Feb-2009
 */
package com.intellij.refactoring.replaceConstructorWithBuilder;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.util.PropertyUtil;
import com.intellij.refactoring.util.RefactoringUtil;

import java.util.Map;

public class ParameterData {
  private final String myName;
  private final String myParameterName;
  private final PsiType myType;
  private String myFieldName;
  private String mySetterName;
  private String myDefaultValue;
  private boolean myInsertSetter = true;
  private static final Logger LOG = Logger.getInstance("#" + ParameterData.class.getName());

  public ParameterData(String name, String parameterName, PsiType type) {
    myName = name;
    myParameterName = parameterName;
    myType = type;
  }

  public static void createFromConstructor(final PsiMethod constructor, final Map<String, ParameterData> result) {

    for (PsiParameter parameter : constructor.getParameterList().getParameters()) {
      initParameterData(parameter, result);
    }

    final PsiMethod chainedConstructor = RefactoringUtil.getChainedConstructor(constructor);
    if (chainedConstructor != null) {
      final PsiCodeBlock constructorBody = constructor.getBody();
      LOG.assertTrue(constructorBody != null);
      final PsiStatement thisStatement = constructorBody.getStatements()[0];
      final PsiExpression thisExpression = ((PsiExpressionStatement)thisStatement).getExpression();
      final PsiExpression[] args = ((PsiMethodCallExpression)thisExpression).getArgumentList().getExpressions();
      int i = 0;
      for (final PsiParameter parameter : chainedConstructor.getParameterList().getParameters()) {
        if (!parameter.isVarArgs()) {
          final PsiExpression arg = args[i];
          final ParameterData parameterData = initParameterData(parameter, result);
          if (!(arg instanceof PsiReferenceExpression && ((PsiReferenceExpression)arg).resolve() instanceof PsiParameter)) {
            parameterData.setDefaultValue(arg.getText());
          }
          i++;
        }
      }
    }
  }

  private static ParameterData initParameterData(PsiParameter parameter, Map<String, ParameterData> result) {
    JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(parameter.getProject());
    final String paramName = parameter.getName();
    final String pureParamName = styleManager.variableNameToPropertyName(paramName, VariableKind.PARAMETER);

    ParameterData parameterData = result.get(pureParamName);
    if (parameterData == null) {
      parameterData = new ParameterData(pureParamName, paramName, parameter.getType());

      parameterData.setFieldName(styleManager.suggestVariableName(VariableKind.FIELD, pureParamName, null, parameter.getType()).names[0]);
      parameterData.setSetterName(PropertyUtil.suggestSetterName(pureParamName));

      result.put(pureParamName, parameterData);
    }

    return parameterData;
  }

  public PsiType getType() {
    return myType;
  }

  public String getFieldName() {
    return myFieldName;
  }

  public String getSetterName() {
    return mySetterName;
  }

  public String getParamName() {
    return myParameterName;
  }

  public String getDefaultValue() {
    return myDefaultValue;
  }

  public boolean isInsertSetter() {
    return myInsertSetter;
  }

  public void setFieldName(String fieldName) {
    myFieldName = fieldName;
  }

  public void setSetterName(String setterName) {
    mySetterName = setterName;
  }

  public void setDefaultValue(String defaultValue) {
    myDefaultValue = defaultValue;
  }

  public void setInsertSetter(boolean insertSetter) {
    myInsertSetter = insertSetter;
  }
}
@@ -745,24 +745,68 @@
 tic.Logger;%0A
+import com.intellij.openapi.util.Comparing;%0A
 import com.i
@@ -820,16 +820,16 @@
 .psi.*;%0A
-
 import c
@@ -1078,39 +1078,8 @@
 a %7B%0A
-  private final String myName;%0A
   pr
@@ -1409,21 +1409,8 @@
 ing 
-name, String 
 para
@@ -1440,27 +1440,8 @@
 ) %7B%0A
-    myName = name;%0A
     
@@ -3168,24 +3168,68 @@
 ARAMETER);%0A%0A
+    String uniqueParamName = pureParamName;%0A
     Paramete
@@ -3261,19 +3261,21 @@
 ult.get(
-pur
+uniqu
 eParamNa
@@ -3284,17 +3284,35 @@
 );%0A    i
-f
+nt i = 0;%0A    while
  (parame
@@ -3319,17 +3319,17 @@
 terData 
-=
+!
 = null) 
@@ -3332,24 +3332,277 @@
 ll) %7B%0A      
+if (!Comparing.equal(parameter.getType(), parameterData.getType())) %7B%0A        uniqueParamName = pureParamName + i++;%0A        parameterData = result.get(uniqueParamName);%0A      %7D else %7B%0A        break;%0A      %7D%0A    %7D%0A    if (parameterData == null) %7B%0A      
 parameterDat
@@ -3623,31 +3623,16 @@
 terData(
-pureParamName, 
 paramNam
@@ -3743,19 +3743,21 @@
 .FIELD, 
-pur
+uniqu
 eParamNa
@@ -3863,19 +3863,21 @@
 terName(
-pur
+uniqu
 eParamNa
@@ -3900,19 +3900,21 @@
 ult.put(
-pur
+uniqu
 eParamNa

replace constructor with builder: check that names corresponding to different params (with different types) would get different names