// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// TODO(johnniwinther): Make this a separate library.
part of dart2js.kernel.element_map;

class KernelAnnotationProcessor implements AnnotationProcessor {
  final KernelToElementMapForImpactImpl elementMap;
  final NativeBasicDataBuilder _nativeBasicDataBuilder;

  KernelAnnotationProcessor(this.elementMap, this._nativeBasicDataBuilder);

  void extractNativeAnnotations(LibraryEntity library) {
    ElementEnvironment elementEnvironment = elementMap.elementEnvironment;
    CommonElements commonElements = elementMap.commonElements;

    elementEnvironment.forEachClass(library, (ClassEntity cls) {
      String annotationName;
      for (ConstantValue value in elementEnvironment.getClassMetadata(cls)) {
        String name = readAnnotationName(
            cls, value, commonElements.nativeAnnotationClass);
        if (annotationName == null) {
          annotationName = name;
        } else if (name != null) {
          failedAt(cls, 'Too many name annotations.');
        }
      }
      if (annotationName != null) {
        _nativeBasicDataBuilder.setNativeClassTagInfo(cls, annotationName);
      }
    });
  }

  String getJsInteropName(
      Spannable spannable, Iterable<ConstantValue> metadata) {
    CommonElements commonElements = elementMap.commonElements;
    String annotationName;
    for (ConstantValue value in metadata) {
      String name = readAnnotationName(
          spannable, value, commonElements.jsAnnotationClass,
          defaultValue: '');
      if (annotationName == null) {
        annotationName = name;
      } else if (name != null) {
        // TODO(johnniwinther): This should be an error, not a crash.
        failedAt(spannable, 'Too many name annotations.');
      }
    }
    return annotationName;
  }

  void checkFunctionParameters(FunctionEntity function) {
    if (function.parameterStructure.namedParameters.isNotEmpty) {
      elementMap.reporter.reportErrorMessage(
          function,
          MessageKind.JS_INTEROP_METHOD_WITH_NAMED_ARGUMENTS,
          {'method': function.name});
    }
  }

  void extractJsInteropAnnotations(LibraryEntity library) {
    DiagnosticReporter reporter = elementMap.reporter;
    ElementEnvironment elementEnvironment = elementMap.elementEnvironment;
    CommonElements commonElements = elementMap.commonElements;

    String libraryName = getJsInteropName(
        library, elementEnvironment.getLibraryMetadata(library));
    bool isJsLibrary = libraryName != null;

    elementEnvironment.forEachLibraryMember(library, (MemberEntity member) {
      if (member.isField) return;
      String memberName = getJsInteropName(
          library, elementEnvironment.getMemberMetadata(member));
      if (memberName != null) {
        _nativeBasicDataBuilder.markAsJsInteropMember(member, memberName);
        checkFunctionParameters(member);
      }
    });

    elementEnvironment.forEachClass(library, (ClassEntity cls) {
      Iterable<ConstantValue> metadata =
          elementEnvironment.getClassMetadata(cls);
      String className = getJsInteropName(cls, metadata);
      if (className != null) {
        bool isAnonymous = false;
        for (ConstantValue value in metadata) {
          if (isAnnotation(cls, value, commonElements.jsAnonymousClass)) {
            isAnonymous = true;
            break;
          }
        }
        // TODO(johnniwinther): Report an error if the class is anonymous but
        // has a non-empty name.
        _nativeBasicDataBuilder.markAsJsInteropClass(cls,
            name: className, isAnonymous: isAnonymous);
        // TODO(johnniwinther): When fasta supports library metadata, report
        // and error if [isJsLibrary] is false.
        // For now, assume the library is a js-interop library.
        isJsLibrary = true;

        bool implementsJsJavaScriptObjectClass = false;
        elementEnvironment.forEachSupertype(cls, (InterfaceType supertype) {
          if (supertype.element == commonElements.jsJavaScriptObjectClass) {
            implementsJsJavaScriptObjectClass = true;
          }
        });
        if (!implementsJsJavaScriptObjectClass) {
          reporter.reportErrorMessage(
              cls, MessageKind.JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS, {
            'cls': cls.name,
            'superclass': elementEnvironment.getSuperClass(cls).name
          });
        }

        elementEnvironment.forEachClassMember(cls,
            (ClassEntity declarer, MemberEntity member) {
          if (declarer != cls) return;
          if (member.isField) return;
          FunctionEntity function = member;

          String memberName = getJsInteropName(
              library, elementEnvironment.getMemberMetadata(function));
          if (memberName != null) {
            _nativeBasicDataBuilder.markAsJsInteropMember(function, memberName);
          }

          if (!function.isExternal &&
              !function.isAbstract &&
              !function.isConstructor &&
              !function.isStatic) {
            reporter.reportErrorMessage(
                function,
                MessageKind.JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER,
                {'cls': cls.name, 'member': member.name});
          }

          checkFunctionParameters(function);
        });
        elementEnvironment.forEachConstructor(cls,
            (ConstructorEntity constructor) {
          String memberName = getJsInteropName(
              library, elementEnvironment.getMemberMetadata(constructor));
          if (memberName != null) {
            _nativeBasicDataBuilder.markAsJsInteropMember(
                constructor, memberName);
          }

          if (constructor.isFactoryConstructor && isAnonymous) {
            if (constructor.parameterStructure.requiredParameters > 0) {
              reporter.reportErrorMessage(
                  constructor,
                  MessageKind
                      .JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS,
                  {'cls': cls.name});
            }
          } else {
            checkFunctionParameters(constructor);
          }
        });
      }
    });
    if (isJsLibrary) {
      // TODO(johnniwinther): Remove this when fasta supports library metadata.
      // For now, assume the empty name.
      libraryName ??= '';
      _nativeBasicDataBuilder.markAsJsInteropLibrary(library,
          name: libraryName);
    }
  }

  @override
  void processJsInteropAnnotations(
      NativeBasicData nativeBasicData, NativeDataBuilder nativeDataBuilder) {
    // Nothing to do; all is computed in [extractJsInteropAnnotations].
  }
}
