// 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.intellij.codeInsight.generation;

import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.intention.AddAnnotationPsiFix;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static com.intellij.codeInsight.AnnotationUtil.CHECK_EXTERNAL;
import static com.intellij.codeInsight.AnnotationUtil.CHECK_TYPE;

/**
 * @author anna
 * @since 19-Aug-2008
 */
public interface OverrideImplementsAnnotationsHandler {
  ExtensionPointName<OverrideImplementsAnnotationsHandler> EP_NAME = ExtensionPointName.create("com.intellij.overrideImplementsAnnotationsHandler");

  /**
   * Returns annotations which should be copied from a source to an implementation (by default, no annotations are copied).
   */
  default String[] getAnnotations(@NotNull PsiFile file) {
    //noinspection deprecation
    return getAnnotations(file.getProject());
  }

  /**
   * @deprecated Use {@link #getAnnotations(PsiFile)}
   */
  @Deprecated
  String[] getAnnotations(Project project);

  @Deprecated
  @NotNull
  default String[] annotationsToRemove(Project project, @NotNull String fqName) {
    return ArrayUtil.EMPTY_STRING_ARRAY;
  }

  static void repeatAnnotationsFromSource(PsiModifierListOwner source, @Nullable PsiElement targetClass, PsiModifierListOwner target) {
    Module module = ModuleUtilCore.findModuleForPsiElement(targetClass != null ? targetClass : target);
    GlobalSearchScope moduleScope = module != null ? GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module) : null;
    Project project = target.getProject();
    JavaPsiFacade facade = JavaPsiFacade.getInstance(project);

    for (OverrideImplementsAnnotationsHandler each : Extensions.getExtensions(EP_NAME)) {
      for (String annotation : each.getAnnotations(target.getContainingFile())) {
        if (moduleScope != null && facade.findClass(annotation, moduleScope) == null) continue;

        int flags = CHECK_EXTERNAL | CHECK_TYPE;
        if (AnnotationUtil.isAnnotated(source, annotation, flags) && !AnnotationUtil.isAnnotated(target, annotation, flags)) {
          PsiModifierList modifierList = target.getModifierList();
          assert modifierList != null : target;
          PsiAnnotation srcAnnotation = AnnotationUtil.findAnnotation(source, annotation);
          PsiNameValuePair[] valuePairs = srcAnnotation != null ? srcAnnotation.getParameterList().getAttributes() 
                                                                : PsiNameValuePair.EMPTY_ARRAY;
          AddAnnotationPsiFix.addPhysicalAnnotation(annotation, valuePairs, modifierList);
        }
      }
    }
  }
}
@@ -2604,24 +2604,219 @@
 s)) %7B%0A      
+    each.transferToTarget(annotation, source, target);%0A        %7D%0A      %7D%0A    %7D%0A  %7D%0A%0A  default void transferToTarget(String annotation, PsiModifierListOwner source, PsiModifierListOwner target) %7B%0A
     PsiModif
@@ -2868,22 +2868,16 @@
 ();%0A    
-   
-   
 assert m
@@ -2906,22 +2906,16 @@
 target;%0A
-      
     PsiA
@@ -2991,22 +2991,16 @@
 ation);%0A
-      
     PsiN
@@ -3104,73 +3104,8 @@
 s() 
-%0A                                                                
 : Ps
@@ -3132,22 +3132,16 @@
 _ARRAY;%0A
-      
     AddA
@@ -3221,32 +3221,8 @@
 t);%0A
-        %7D%0A      %7D%0A    %7D%0A
   %7D%0A

allow override implementation handlers to customize result