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

library dart2js.js_emitter.metadata_collector;

import 'package:js_ast/src/precedence.dart' as js_precedence;

import '../common.dart';
import '../common_elements.dart' show JElementEnvironment;
import '../constants/values.dart';
import '../deferred_load.dart' show OutputUnit;
import '../elements/entities.dart' show FunctionEntity;

import '../elements/entities.dart';
import '../elements/types.dart';
import '../js/js.dart' as jsAst;
import '../js/js.dart' show js;
import '../js_backend/runtime_types_new.dart' show RecipeEncoder;
import '../js_model/type_recipe.dart' show TypeExpressionRecipe;
import '../options.dart';

import 'code_emitter_task.dart' show Emitter;

/// Represents an entry's position in one of the global metadata arrays.
///
/// [_rc] is used to count the number of references of the token in the
/// ast for a program.
/// [value] is the actual position, once they have been finalized.
abstract class _MetadataEntry extends jsAst.DeferredNumber
    implements Comparable, jsAst.ReferenceCountedAstNode {
  jsAst.Expression get entry;
  @override
  int get value;
  int get _rc;

  // Mark this entry as seen. On the first time this is seen, the visitor
  // will be applied to the [entry] to also mark potential [_MetadataEntry]
  // instances in the [entry] as seen.
  @override
  void markSeen(jsAst.TokenCounter visitor);
}

class BoundMetadataEntry extends _MetadataEntry {
  int _value = -1;
  @override
  int _rc = 0;
  @override
  final jsAst.Expression entry;

  BoundMetadataEntry(this.entry);

  @override
  bool get isFinalized => _value != -1;

  finalize(int value) {
    assert(!isFinalized);
    _value = value;
  }

  @override
  int get value {
    assert(isFinalized);
    return _value;
  }

  bool get isUsed => _rc > 0;

  @override
  void markSeen(jsAst.BaseVisitor visitor) {
    _rc++;
    if (_rc == 1) entry.accept(visitor);
  }

  @override
  int compareTo(covariant _MetadataEntry other) => other._rc - this._rc;

  @override
  String toString() => 'BoundMetadataEntry($hashCode,rc=$_rc,_value=$_value)';
}

class _MetadataList extends jsAst.DeferredExpression {
  jsAst.Expression _value;

  void setExpression(jsAst.Expression value) {
    assert(_value == null);
    assert(value.precedenceLevel == this.precedenceLevel);
    _value = value;
  }

  @override
  jsAst.Expression get value {
    assert(_value != null);
    return _value;
  }

  @override
  int get precedenceLevel => js_precedence.PRIMARY;
}

class MetadataCollector implements jsAst.TokenFinalizer {
  final CompilerOptions _options;
  final DiagnosticReporter reporter;
  final Emitter _emitter;
  final RecipeEncoder _rtiRecipeEncoder;
  final JElementEnvironment _elementEnvironment;

  /// A map with a token per output unit for a list of expressions that
  /// represent metadata, parameter names and type variable types.
  Map<OutputUnit, _MetadataList> _metadataTokens =
      new Map<OutputUnit, _MetadataList>();

  jsAst.Expression getMetadataForOutputUnit(OutputUnit outputUnit) {
    return _metadataTokens.putIfAbsent(outputUnit, () => new _MetadataList());
  }

  /// A map used to canonicalize the entries of metadata.
  Map<OutputUnit, Map<String, BoundMetadataEntry>> _metadataMap =
      <OutputUnit, Map<String, BoundMetadataEntry>>{};

  /// A map with a token for a lists of JS expressions, one token for each
  /// output unit. Once finalized, the entries represent types including
  /// function types and typedefs.
  Map<OutputUnit, _MetadataList> _typesTokens =
      new Map<OutputUnit, _MetadataList>();

  jsAst.Expression getTypesForOutputUnit(OutputUnit outputUnit) {
    return _typesTokens.putIfAbsent(outputUnit, () => new _MetadataList());
  }

  /// A map used to canonicalize the entries of types.
  Map<OutputUnit, Map<DartType, BoundMetadataEntry>> _typesMap =
      <OutputUnit, Map<DartType, BoundMetadataEntry>>{};

  MetadataCollector(this._options, this.reporter, this._emitter,
      this._rtiRecipeEncoder, this._elementEnvironment);

  List<jsAst.DeferredNumber> reifyDefaultArguments(
      FunctionEntity function, OutputUnit outputUnit) {
    // TODO(sra): These are stored on the InstanceMethod or StaticDartMethod.
    List<jsAst.DeferredNumber> defaultValues = <jsAst.DeferredNumber>[];
    _elementEnvironment.forEachParameter(function,
        (_, String name, ConstantValue constant) {
      if (constant == null) return;
      jsAst.Expression expression = _emitter.constantReference(constant);
      defaultValues.add(_addGlobalMetadata(expression, outputUnit));
    });
    return defaultValues;
  }

  jsAst.Expression reifyType(DartType type, OutputUnit outputUnit) {
    return addTypeInOutputUnit(type, outputUnit);
  }

  jsAst.Expression reifyName(String name, OutputUnit outputUnit) {
    return _addGlobalMetadata(js.string(name), outputUnit);
  }

  jsAst.Expression reifyExpression(
      jsAst.Expression expression, OutputUnit outputUnit) {
    return _addGlobalMetadata(expression, outputUnit);
  }

  _MetadataEntry _addGlobalMetadata(jsAst.Node node, OutputUnit outputUnit) {
    String nameToKey(jsAst.Name name) => "${name.key}";
    String printed = jsAst.prettyPrint(node,
        enableMinification: _options.enableMinification,
        renamerForNames: nameToKey);
    _metadataMap[outputUnit] ??= new Map<String, BoundMetadataEntry>();
    return _metadataMap[outputUnit].putIfAbsent(printed, () {
      return new BoundMetadataEntry(node);
    });
  }

  jsAst.Expression _computeTypeRepresentationNewRti(DartType type) {
    return _rtiRecipeEncoder.encodeGroundRecipe(
        _emitter, TypeExpressionRecipe(type));
  }

  jsAst.Expression addTypeInOutputUnit(DartType type, OutputUnit outputUnit) {
    _typesMap[outputUnit] ??= new Map<DartType, BoundMetadataEntry>();
    return _typesMap[outputUnit].putIfAbsent(type, () {
      return new BoundMetadataEntry(_computeTypeRepresentationNewRti(type));
    });
  }

  @override
  void finalizeTokens() {
    void countTokensInTypes(Iterable<BoundMetadataEntry> entries) {
      jsAst.TokenCounter counter = new jsAst.TokenCounter();
      entries
          .where((BoundMetadataEntry e) => e._rc > 0)
          .map((BoundMetadataEntry e) => e.entry)
          .forEach(counter.countTokens);
    }

    jsAst.ArrayInitializer finalizeMap(Map<dynamic, BoundMetadataEntry> map) {
      bool isUsed(BoundMetadataEntry entry) => entry.isUsed;
      List<BoundMetadataEntry> entries = map.values.where(isUsed).toList();
      entries.sort();

      // TODO(herhut): Bucket entries by index length and use a stable
      //               distribution within buckets.
      int count = 0;
      for (BoundMetadataEntry entry in entries) {
        entry.finalize(count++);
      }

      List<jsAst.Node> values =
          entries.map((BoundMetadataEntry e) => e.entry).toList();

      return new jsAst.ArrayInitializer(values);
    }

    _metadataTokens.forEach((OutputUnit outputUnit, _MetadataList token) {
      Map metadataMap = _metadataMap[outputUnit];
      if (metadataMap != null) {
        token.setExpression(finalizeMap(metadataMap));
      } else {
        token.setExpression(new jsAst.ArrayInitializer([]));
      }
    });

    _typesTokens.forEach((OutputUnit outputUnit, _MetadataList token) {
      Map typesMap = _typesMap[outputUnit];
      if (typesMap != null) {
        countTokensInTypes(typesMap.values);
        token.setExpression(finalizeMap(typesMap));
      } else {
        token.setExpression(new jsAst.ArrayInitializer([]));
      }
    });
  }
}
