// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.theoryinpractice.testng.inspection;

import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInspection.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.testng.annotations.DataProvider;

import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @author Dmitry Batkovich
 */
public class DuplicatedDataProviderNamesInspection extends AbstractBaseJavaLocalInspectionTool {
  private final static Logger LOG = Logger.getInstance(DuplicatedDataProviderNamesInspection.class);
  private final static String NAME_ATTRIBUTE = "name";

  @Nullable
  @Override
  public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) {
    final String dataProviderFqn = DataProvider.class.getCanonicalName();

    final MultiMap<String, PsiMethod> dataProvidersByName = new MultiMap<>();
    for (HierarchicalMethodSignature signature : aClass.getVisibleSignatures()) { //include only visible signatures to hide overridden methods
      PsiMethod method = signature.getMethod();
      final PsiAnnotation annotation = AnnotationUtil.findAnnotation(method, dataProviderFqn);
      if (annotation != null) {
        final PsiAnnotationMemberValue value = annotation.findAttributeValue(NAME_ATTRIBUTE);
        LOG.assertTrue(value != null);
        final String dataProviderName = PsiTreeUtil.isAncestor(annotation, value, false)
                                        ? AnnotationUtil.getStringAttributeValue(annotation, NAME_ATTRIBUTE)
                                        : method.getName();
        if (dataProviderName != null) {
          dataProvidersByName.putValue(dataProviderName, method);
        }
      }
    }

    final List<ProblemDescriptor> descriptors = new SmartList<>();
    for (Map.Entry<String, Collection<PsiMethod>> entry : dataProvidersByName.entrySet()) {
      if (entry.getValue().size() > 1) {
        for (PsiMethod method : entry.getValue()) {
          if (method.getContainingClass() != aClass) continue; //don't highlight methods in super class
          final String description = String.format("Data provider with name '%s' already exists in context", entry.getKey());
          final PsiAnnotation annotation = AnnotationUtil.findAnnotation(method, dataProviderFqn);
          LOG.assertTrue(annotation != null);
          final PsiAnnotationMemberValue nameElement = annotation.findAttributeValue(NAME_ATTRIBUTE);
          LOG.assertTrue(nameElement != null);
          PsiElement problemElement = PsiTreeUtil.isAncestor(aClass, nameElement, false) ? nameElement : method.getNameIdentifier();
          LOG.assertTrue(problemElement != null);
          descriptors.add(manager.createProblemDescriptor(problemElement, description, isOnTheFly, LocalQuickFix.EMPTY_ARRAY, ProblemHighlightType.ERROR));
        }
      }
    }
    return descriptors.isEmpty() ? null : descriptors.toArray(ProblemDescriptor.EMPTY_ARRAY);
  }
}

@@ -1683,30 +1683,19 @@
         
-LOG.assertTrue
+if 
 (value !
@@ -1701,26 +1701,28 @@
 != null)
-;%0A
+ %7B%0A 
         
 final St
@@ -1705,32 +1705,33 @@
 ull) %7B%0A         
+ 
 final String dat
@@ -1795,16 +1795,18 @@
  false)%0A
+  
         
@@ -1946,16 +1946,18 @@
         
+  
 : method
@@ -1972,24 +1972,26 @@
 ();%0A        
+ 
+ 
 if (dataProv
@@ -2002,32 +2002,34 @@
 Name != null) %7B%0A
+  
           dataPr
@@ -2078,16 +2078,28 @@
 ethod);%0A
+          %7D%0A
         

"name" attribute can be null