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

/**
 * This could be an abstract class but we use it as a stub for the dart_backend.
 */
class NativeEnqueuer {
  /// Called when a [type] has been instantiated natively.
  void onInstantiatedType(InterfaceType type) {}

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

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

  /// Returns whether native classes are being used.
  bool get hasInstantiatedNativeClasses => false;

  /// Emits a summary information using the [log] function.
  void logSummary(void log(String message)) {}
}

abstract class NativeEnqueuerBase implements NativeEnqueuer {
  final Set<ClassEntity> _registeredClasses = new Set<ClassEntity>();
  final Set<ClassEntity> _unusedClasses = new Set<ClassEntity>();

  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.
  NativeEnqueuerBase(this._options, this._elementEnvironment,
      this._commonElements, this._dartTypes);

  bool get enableLiveTypeAnalysis => _options.enableNativeLiveTypeAnalysis;

  void onInstantiatedType(InterfaceType type) {
    if (_unusedClasses.remove(type.element)) {
      _registeredClasses.add(type.element);
    }
  }

  /// 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(
          new TypeUse.nativeInstantiation(_elementEnvironment.getRawType(cls)));
    }
  }

  void registerNativeBehavior(
      WorldImpactBuilder impactBuilder, NativeBehavior nativeBehavior, cause) {
    _processNativeBehavior(impactBuilder, nativeBehavior, cause);
  }

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

    int unusedBefore = _unusedClasses.length;
    Set<ClassEntity> matchingClasses = new Set<ClassEntity>();
    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);
        }
        // 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.getThisType(nativeClass);
          InterfaceType specType =
              _elementEnvironment.getThisType(type.element);
          return _dartTypes.isSubtype(nativeType, specType);
        }));
      } else if (type.isDynamic) {
        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;
    });
  }

  void logSummary(void log(String message)) {
    if (_allUsedMessage != null) {
      log(_allUsedMessage);
    }
  }
}

class NativeResolutionEnqueuer extends NativeEnqueuerBase {
  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 = new Set<ClassEntity>();

  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;

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

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

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

  final Set<ClassEntity> _doneAddSubtypes = new Set<ClassEntity>();

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

  WorldImpact processNativeClasses(Iterable<LibraryEntity> libraries) {
    WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();
    _unusedClasses.addAll(_nativeClasses);

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

    // HACK HACK - add all the resolved classes.
    Set<ClassEntity> matchingClasses = new Set<ClassEntity>();
    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;
  }

  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.putIfAbsent(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.putIfAbsent(superclass, () => <ClassEntity>[]);
    directSubtypes.add(cls);
  }

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