// Copyright (c) 2014, 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 '../common/elements.dart' show CommonElements, ElementEnvironment;
import '../elements/entities.dart';
import '../elements/types.dart';
import '../js_backend/native_data.dart' show NativeData;
import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter;
import '../options.dart';
import '../universe/use.dart' show TypeUse;
import '../universe/world_impact.dart'
    show WorldImpact, WorldImpactBuilder, WorldImpactBuilderImpl;
import 'behavior.dart';
import 'resolver.dart' show NativeClassFinder;

abstract class NativeEnqueuer {
  final Set<ClassEntity> _registeredClasses = {};
  final Set<ClassEntity> _unusedClasses = {};

  /// Returns whether native classes are being used.
  bool get hasInstantiatedNativeClasses => !_registeredClasses.isEmpty;

  /// Log message reported if all native types are used.
  String _allUsedMessage;

  final CompilerOptions _options;
  final ElementEnvironment _elementEnvironment;
  final DartTypes _dartTypes;
  final CommonElements _commonElements;

  /// Subclasses of [NativeEnqueuerBase] are constructed by the backend.
  NativeEnqueuer(this._options, this._elementEnvironment, this._commonElements,
      this._dartTypes);

  bool get enableLiveTypeAnalysis => _options.enableNativeLiveTypeAnalysis;

  /// Called when a [type] has been instantiated natively.
  void onInstantiatedType(InterfaceType type) {
    if (_unusedClasses.remove(type.element)) {
      _registeredClasses.add(type.element);
    }
  }

  /// Initial entry point to native enqueuer.
  WorldImpact processNativeClasses(Iterable<Uri> libraries);

  /// Register [classes] as natively instantiated in [impactBuilder].
  void _registerTypeUses(
      WorldImpactBuilder impactBuilder, Set<ClassEntity> classes, cause) {
    for (ClassEntity cls in classes) {
      if (!_unusedClasses.contains(cls)) {
        // No need to add [classElement] to [impactBuilder]: it has already been
        // instantiated and we don't track origins of native instantiations
        // precisely.
        continue;
      }
      impactBuilder.registerTypeUse(
          TypeUse.nativeInstantiation(_elementEnvironment.getRawType(cls)));
    }
  }

  /// Registers the [nativeBehavior]. Adds the liveness of its instantiated
  /// types to the world.
  void registerNativeBehavior(
      WorldImpactBuilder impactBuilder, NativeBehavior nativeBehavior, cause) {
    _processNativeBehavior(impactBuilder, nativeBehavior, cause);
  }

  void _processNativeBehavior(
      WorldImpactBuilder impactBuilder, NativeBehavior behavior, cause) {
    void registerInstantiation(InterfaceType type) {
      impactBuilder.registerTypeUse(TypeUse.nativeInstantiation(type));
    }

    int unusedBefore = _unusedClasses.length;
    Set<ClassEntity> matchingClasses = {};
    for (var type in behavior.typesInstantiated) {
      if (type is SpecialType) {
        if (type == SpecialType.JsObject) {
          registerInstantiation(_commonElements.objectType);
        }
        continue;
      }
      if (type is InterfaceType) {
        if (type == _commonElements.numType) {
          registerInstantiation(_commonElements.doubleType);
          registerInstantiation(_commonElements.intType);
        } else if (type == _commonElements.intType ||
            type == _commonElements.doubleType ||
            type == _commonElements.stringType ||
            type == _commonElements.nullType ||
            type == _commonElements.boolType ||
            _dartTypes.isSubtype(type,
                _elementEnvironment.getRawType(_commonElements.jsArrayClass))) {
          registerInstantiation(type);
        } else if (_dartTypes.isSubtype(
            type,
            _elementEnvironment
                .getRawType(_commonElements.jsLegacyJavaScriptObjectClass))) {
          matchingClasses.add(type.element);
        }
        // TODO(johnniwinther): Improve spec string precision to handle type
        // arguments and implements relations that preserve generics. Currently
        // we cannot distinguish between `List`, `List<dynamic>`, and
        // `List<int>` and take all to mean `List<E>`; in effect not including
        // any native subclasses of generic classes.
        // TODO(johnniwinther,sra): Find and replace uses of `List` with the
        // actual implementation classes such as `JSArray` et al.
        matchingClasses
            .addAll(_findUnusedClassesMatching((ClassEntity nativeClass) {
          InterfaceType nativeType =
              _elementEnvironment.getRawType(nativeClass);
          InterfaceType specType = _elementEnvironment.getRawType(type.element);
          return _dartTypes.isSubtype(nativeType, specType);
        }));
      } else if (type is DynamicType) {
        matchingClasses.addAll(_unusedClasses);
      } else {
        assert(type is VoidType, '$type was ${type.runtimeType}');
      }
    }
    if (matchingClasses.isNotEmpty && _registeredClasses.isEmpty) {
      matchingClasses.addAll(_onFirstNativeClass(impactBuilder));
    }
    _registerTypeUses(impactBuilder, matchingClasses, cause);

    // Give an info so that library developers can compile with -v to find why
    // all the native classes are included.
    if (unusedBefore > 0 && unusedBefore == matchingClasses.length) {
      _allUsedMessage ??= 'All native types marked as used due to $cause.';
    }
  }

  Iterable<ClassEntity> _findUnusedClassesMatching(
      bool predicate(ClassEntity classElement)) {
    return _unusedClasses.where(predicate);
  }

  Iterable<ClassEntity> _onFirstNativeClass(WorldImpactBuilder impactBuilder) {
    return _findNativeExceptions();
  }

  Iterable<ClassEntity> _findNativeExceptions() {
    return _findUnusedClassesMatching((ClassEntity classElement) {
      // TODO(sra): Annotate exception classes in dart:html.
      String name = classElement.name;
      if (name.contains('Exception')) return true;
      if (name.contains('Error')) return true;
      return false;
    });
  }

  /// Emits a summary information using the [log] function.
  void logSummary(void log(String message)) {
    if (_allUsedMessage != null) {
      log(_allUsedMessage);
    }
  }
}

class NativeResolutionEnqueuer extends NativeEnqueuer {
  final NativeClassFinder _nativeClassFinder;

  /// The set of all native classes.  Each native class is in [nativeClasses]
  /// and exactly one of [unusedClasses] and [registeredClasses].
  final Set<ClassEntity> _nativeClasses = {};

  NativeResolutionEnqueuer(
      CompilerOptions options,
      ElementEnvironment elementEnvironment,
      CommonElements commonElements,
      DartTypes dartTypes,
      this._nativeClassFinder)
      : super(options, elementEnvironment, commonElements, dartTypes);

  Iterable<ClassEntity> get nativeClassesForTesting => _nativeClasses;

  Iterable<ClassEntity> get registeredClassesForTesting => _registeredClasses;

  Iterable<ClassEntity> get liveNativeClasses => _registeredClasses;

  @override
  WorldImpact processNativeClasses(Iterable<Uri> libraries) {
    WorldImpactBuilderImpl impactBuilder = WorldImpactBuilderImpl();
    Iterable<ClassEntity> nativeClasses =
        _nativeClassFinder.computeNativeClasses(libraries);
    _nativeClasses.addAll(nativeClasses);
    _unusedClasses.addAll(nativeClasses);
    if (!enableLiveTypeAnalysis) {
      _registerTypeUses(impactBuilder, _nativeClasses, 'forced');
    }
    return impactBuilder;
  }

  @override
  void logSummary(void log(String message)) {
    super.logSummary(log);
    log('Resolved ${_registeredClasses.length} native elements used, '
        '${_unusedClasses.length} native elements dead.');
  }
}

class NativeCodegenEnqueuer extends NativeEnqueuer {
  final CodeEmitterTask _emitter;
  final Iterable<ClassEntity> _nativeClasses;
  final NativeData _nativeData;

  final Set<ClassEntity> _doneAddSubtypes = {};

  NativeCodegenEnqueuer(
      CompilerOptions options,
      ElementEnvironment elementEnvironment,
      CommonElements commonElements,
      DartTypes dartTypes,
      this._emitter,
      this._nativeClasses,
      this._nativeData)
      : super(options, elementEnvironment, commonElements, dartTypes);

  @override
  WorldImpact processNativeClasses(Iterable<Uri> libraries) {
    WorldImpactBuilderImpl impactBuilder = WorldImpactBuilderImpl();
    _unusedClasses.addAll(_nativeClasses);

    if (!enableLiveTypeAnalysis) {
      _registerTypeUses(impactBuilder, _nativeClasses, 'forced');
    }

    // HACK HACK - add all the resolved classes.
    Set<ClassEntity> matchingClasses = {};
    for (ClassEntity classElement in _nativeClasses) {
      if (_unusedClasses.contains(classElement)) {
        matchingClasses.add(classElement);
      }
    }
    if (matchingClasses.isNotEmpty && _registeredClasses.isEmpty) {
      matchingClasses.addAll(_onFirstNativeClass(impactBuilder));
    }
    _registerTypeUses(impactBuilder, matchingClasses, 'was resolved');
    return impactBuilder;
  }

  @override
  void _registerTypeUses(
      WorldImpactBuilder impactBuilder, Set<ClassEntity> classes, cause) {
    super._registerTypeUses(impactBuilder, classes, cause);

    for (ClassEntity classElement in classes) {
      // Add the information that this class is a subtype of its supertypes. The
      // code emitter and the ssa builder use that information.
      _addSubtypes(classElement, _emitter.nativeEmitter);
    }
  }

  void _addSubtypes(ClassEntity cls, NativeEmitter emitter) {
    if (!_nativeData.isNativeClass(cls)) return;
    if (_doneAddSubtypes.contains(cls)) return;
    _doneAddSubtypes.add(cls);

    // Walk the superclass chain since classes on the superclass chain might not
    // be instantiated (abstract or simply unused).
    _addSubtypes(_elementEnvironment.getSuperClass(cls), emitter);

    _elementEnvironment.forEachSupertype(cls, (InterfaceType type) {
      List<ClassEntity> subtypes =
          emitter.subtypes[type.element] ??= <ClassEntity>[];
      subtypes.add(cls);
    });

    // Skip through all the mixin applications in the super class
    // chain. That way, the direct subtypes set only contain the
    // natives classes.
    ClassEntity superclass = _elementEnvironment.getSuperClass(cls);
    while (superclass != null &&
        _elementEnvironment.isMixinApplication(superclass)) {
      assert(!_nativeData.isNativeClass(superclass));
      superclass = _elementEnvironment.getSuperClass(superclass);
    }

    List<ClassEntity> directSubtypes =
        emitter.directSubtypes[superclass] ??= <ClassEntity>[];
    directSubtypes.add(cls);
  }

  @override
  void logSummary(void log(String message)) {
    super.logSummary(log);
    log('Compiled ${_registeredClasses.length} native classes, '
        '${_unusedClasses.length} native classes omitted.');
  }
}
