// Copyright (c) 2016, 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.

import 'dart:collection';
import 'package:analyzer/dart/element/element.dart'
    show ClassElement, CompilationUnitElement, Element;
import 'package:analyzer/dart/element/type.dart' show DartType, InterfaceType;
import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
import 'element_helpers.dart' show getAnnotationName, isBuiltinAnnotation;

/// Contains information about native JS types (those types provided by the
/// implementation) that are also provided by the Dart SDK.
///
/// For types provided by JavaScript, it is important that we don't add methods
/// directly to those types. Instead, we must call through a special set of
/// JS Symbol names, that are used for the "Dart extensions". For example:
///
///     // Dart
///     Iterable iter = myList;
///     print(iter.first);
///
///     // JS
///     let iter =  myLib.myList;
///     core.print(iter[dartx.first]);
///
/// This will provide the [Iterable.first] property, without needing to add
/// `first` to the `Array.prototype`.
class ExtensionTypeSet {
  final AnalysisContext _context;

  // Abstract types that may be implemented by both native and non-native
  // classes.
  final _extensibleTypes = HashSet<ClassElement>();

  // Concrete native types.
  final _nativeTypes = HashSet<ClassElement>();
  final _pendingLibraries = HashSet<String>();

  ExtensionTypeSet(this._context) {
    // TODO(vsm): Eventually, we want to make this extensible - i.e., find
    // annotations in user code as well.  It would need to be summarized in
    // the element model - not searched this way on every compile.  To make this
    // a little more efficient now, we do this in two phases.

    // First, core types:
    // TODO(vsm): If we're analyzing against the main SDK, those
    // types are not explicitly annotated.
    var types = _context.typeProvider;
    _extensibleTypes.add(types.objectType.element);
    _addExtensionType(types.intType, true);
    _addExtensionType(types.doubleType, true);
    _addExtensionType(types.boolType, true);
    _addExtensionType(types.stringType, true);
    _addExtensionTypes('dart:_interceptors');
    _addExtensionTypes('dart:_native_typed_data');

    // These are used natively by dart:html but also not annotated.
    _addExtensionTypesForLibrary('dart:core', ['Comparable', 'Map']);
    _addExtensionTypesForLibrary('dart:collection', ['ListMixin']);
    _addExtensionTypesForLibrary('dart:math', ['Rectangle']);

    // Second, html types - these are only searched if we use dart:html, etc.:
    _addPendingExtensionTypes('dart:html');
    _addPendingExtensionTypes('dart:indexed_db');
    _addPendingExtensionTypes('dart:svg');
    _addPendingExtensionTypes('dart:web_audio');
    _addPendingExtensionTypes('dart:web_gl');
    _addPendingExtensionTypes('dart:web_sql');
  }

  void _visitCompilationUnit(CompilationUnitElement unit) {
    unit.types.forEach(_visitClass);
  }

  void _visitClass(ClassElement element) {
    if (_isNative(element)) {
      _addExtensionType(element.type, true);
    }
  }

  bool _isNative(ClassElement element) {
    for (var metadata in element.metadata) {
      var e = metadata.element?.enclosingElement;
      if (e.name == 'Native' || e.name == 'JsPeerInterface') {
        if (e.source.isInSystemLibrary) return true;
      }
    }
    return false;
  }

  void _addExtensionType(InterfaceType t, [bool mustBeNative = false]) {
    if (t.isObject) return;
    var element = t.element;
    if (_extensibleTypes.contains(element) || _nativeTypes.contains(element)) {
      return;
    }
    bool isNative = mustBeNative || _isNative(element);
    if (isNative) {
      _nativeTypes.add(element);
    } else {
      _extensibleTypes.add(element);
    }
    element.interfaces.forEach(_addExtensionType);
    element.mixins.forEach(_addExtensionType);
    var supertype = element.supertype;
    if (supertype != null) _addExtensionType(element.supertype);
  }

  void _addExtensionTypesForLibrary(String libraryUri, List<String> typeNames) {
    var sourceFactory = _context.sourceFactory.forUri(libraryUri);
    var library = _context.computeLibraryElement(sourceFactory);
    for (var typeName in typeNames) {
      _addExtensionType(library.getType(typeName).type);
    }
  }

  void _addExtensionTypes(String libraryUri) {
    var sourceFactory = _context.sourceFactory.forUri(libraryUri);
    var library = _context.computeLibraryElement(sourceFactory);
    _visitCompilationUnit(library.definingCompilationUnit);
    library.parts.forEach(_visitCompilationUnit);
  }

  void _addPendingExtensionTypes(String libraryUri) {
    _pendingLibraries.add(libraryUri);
  }

  bool _processPending(Element element) {
    if (_pendingLibraries.isEmpty) return false;
    if (element is ClassElement) {
      var uri = element.library.source.uri.toString();
      if (_pendingLibraries.contains(uri)) {
        // Load all pending libraries
        _pendingLibraries.forEach(_addExtensionTypes);
        _pendingLibraries.clear();
        return true;
      }
    }
    return false;
  }

  bool _setContains(HashSet<ClassElement> set, Element element) {
    return set.contains(element) ||
        _processPending(element) && set.contains(element);
  }

  bool isNativeClass(Element element) => _setContains(_nativeTypes, element);

  bool isNativeInterface(Element element) =>
      _setContains(_extensibleTypes, element);

  bool hasNativeSubtype(DartType type) =>
      isNativeInterface(type.element) || isNativeClass(type.element);

  /// Gets the JS peer for this Dart type if any, otherwise null.
  ///
  /// For example for dart:_interceptors `JSArray` this will return "Array",
  /// referring to the JavaScript built-in `Array` type.
  List<String> getNativePeers(ClassElement classElem) {
    if (classElem.type.isObject) return ['Object'];
    var names = getAnnotationName(
        classElem,
        (a) =>
            isBuiltinAnnotation(a, '_js_helper', 'JsPeerInterface') ||
            isBuiltinAnnotation(a, '_js_helper', 'Native'));
    if (names == null) return [];

    // Omit the special name "!nonleaf" and any future hacks starting with "!"
    return names.split(',').where((peer) => !peer.startsWith("!")).toList();
  }
}
