// 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.

// @dart = 2.9

import 'dart:collection';
import 'package:kernel/core_types.dart';
import 'package:kernel/kernel.dart';
import 'constants.dart';
import 'kernel_helpers.dart';
import 'target.dart' show allowedNativeTest;

/// 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 NativeTypeSet {
  final CoreTypes coreTypes;
  final DevCompilerConstants constants;

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

  // Concrete native types.
  final _nativeTypes = HashSet<Class>.identity();
  final _pendingLibraries = HashSet<Library>.identity();

  NativeTypeSet(this.coreTypes, this.constants, Component component) {
    // First, core types:
    // TODO(vsm): If we're analyzing against the main SDK, those
    // types are not explicitly annotated.
    _extensibleTypes.add(coreTypes.objectClass);
    _addExtensionType(coreTypes.intClass, true);
    _addExtensionType(coreTypes.doubleClass, true);
    _addExtensionType(coreTypes.boolClass, true);
    _addExtensionType(coreTypes.stringClass, true);
    // Allow `Function.==` to be recognized as a symbolized member.
    _addExtensionType(coreTypes.functionClass, false);

    var sdk = coreTypes.index;
    _addExtensionTypes(sdk.getLibrary('dart:_interceptors'));
    _addExtensionTypes(sdk.getLibrary('dart:_native_typed_data'));

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

    // TODO(39612) Validate that after this point no types from the SDK are
    // added as native extensions (excluding types from dart:html and "friends"
    // listed below).

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

    // For testing purposes only, we add extension types outside the Dart SDK.
    // These are only allowed for native tests (see allowedNativeTest).
    for (var library in component.libraries) {
      if (allowedNativeTest(library.importUri)) {
        _addExtensionTypes(library);
      }
    }
  }

  void _addExtensionType(Class c, [bool mustBeNative = false]) {
    if (c == coreTypes.objectClass) return;
    if (_extensibleTypes.contains(c) || _nativeTypes.contains(c)) {
      return;
    }
    var isNative = mustBeNative || _isNative(c);
    if (isNative) {
      _nativeTypes.add(c);
    } else {
      _extensibleTypes.add(c);
    }
    for (var s in c.supers) {
      _addExtensionType(s.classNode);
    }
  }

  void _addExtensionTypesForLibrary(String library, List<String> classNames) {
    var sdk = coreTypes.index;
    for (var className in classNames) {
      _addExtensionType(sdk.getClass(library, className));
    }
  }

  void _addExtensionTypes(Library library) {
    for (var c in library.classes) {
      if (_isNative(c)) {
        _addExtensionType(c, true);
      }
    }
  }

  void _addPendingExtensionTypes(Library library) {
    _pendingLibraries.add(library);
  }

  bool _processPending(Class c) {
    var pending = _pendingLibraries;
    if (pending.isNotEmpty && pending.contains(c.enclosingLibrary)) {
      pending.forEach(_addExtensionTypes);
      pending.clear();
      return true;
    }
    return false;
  }

  bool isNativeClass(Class c) =>
      _nativeTypes.contains(c) ||
      _processPending(c) && _nativeTypes.contains(c);

  bool isNativeInterface(Class c) =>
      _extensibleTypes.contains(c) ||
      _processPending(c) && _extensibleTypes.contains(c);

  bool hasNativeSubtype(Class c) => isNativeInterface(c) || isNativeClass(c);

  /// 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(Class c) {
    if (c == coreTypes.objectClass) return ['Object'];

    for (var annotation in c.annotations) {
      var names = _getNativeAnnotationName(annotation);
      if (names != null) {
        // Omit the special name "!nonleaf" and any future dart2js hacks
        // starting with "!"
        return names.split(',').where((peer) => !peer.startsWith('!')).toList();
      }
    }
    return const [];
  }

  /// If this [annotation] is `@Native` or `@JsPeerInterface`, returns the "name"
  /// field (which is also the constructor parameter).
  String _getNativeAnnotationName(Expression annotation) {
    if (!_isNativeAnnotation(annotation)) return null;
    return constants.getFieldValueFromAnnotation(annotation, 'name') as String;
  }
}

/// Whether class [c] has any `@Native` or `@JsPeerInterface` annotations.
bool _isNative(Class c) => c.annotations.any(_isNativeAnnotation);

/// Whether this [annotation] is `@Native` or `@JsPeerInterface`.
bool _isNativeAnnotation(Expression annotation) {
  var c = getAnnotationClass(annotation);
  return c != null &&
      (c.name == 'Native' || c.name == 'JsPeerInterface') &&
      c.enclosingLibrary.importUri.scheme == 'dart';
}
