// Copyright (c) 2021, 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 'package:js_ast/src/precedence.dart' as js show PRIMARY;

import '../common_elements.dart' show JCommonElements;
import '../elements/entities.dart';
import '../js/js.dart' as js;
import '../serialization/serialization.dart';
import '../util/util.dart';
import '../js_emitter/model.dart' show Fragment;

import 'namer.dart';

// TODO(joshualitt): Figure out how to subsume more of the modular naming
// framework into this approach. For example, we are still creating ModularNames
// for the entity referenced in the DeferredHolderExpression.
enum DeferredHolderExpressionKind {
  globalObjectForStaticState,
  globalObjectForConstant,
  globalObjectForInterceptors,
  globalObjectForClass,
  globalObjectForMember,
}

/// A [DeferredHolderExpression] is a deferred JavaScript expression determined
/// by the finalization of holders. It is the injection point for data or
/// code to related to holders. The actual [Expression] contained within the
/// [DeferredHolderExpression] is determined by the
/// [DeferredHolderExpressionKind], eventually, most will be a [PropertyAccess]
/// but currently all are [VariableUse]s.
class DeferredHolderExpression extends js.DeferredExpression
    implements js.AstContainer {
  static const String tag = 'deferred-holder-expression';

  final DeferredHolderExpressionKind kind;
  final Object data;
  js.Expression _value;

  @override
  final js.JavaScriptNodeSourceInformation sourceInformation;

  DeferredHolderExpression(this.kind, this.data) : sourceInformation = null;
  DeferredHolderExpression._(
      this.kind, this.data, this._value, this.sourceInformation);

  factory DeferredHolderExpression.forInterceptors() {
    return DeferredHolderExpression(
        DeferredHolderExpressionKind.globalObjectForInterceptors, null);
  }

  factory DeferredHolderExpression.forStaticState() {
    return DeferredHolderExpression(
        DeferredHolderExpressionKind.globalObjectForStaticState, null);
  }

  factory DeferredHolderExpression.readFromDataSource(DataSource source) {
    source.begin(tag);
    var kind = source.readEnum(DeferredHolderExpressionKind.values);
    Object data;
    switch (kind) {
      case DeferredHolderExpressionKind.globalObjectForClass:
        data = source.readClass();
        break;
      case DeferredHolderExpressionKind.globalObjectForMember:
        data = source.readMember();
        break;
      case DeferredHolderExpressionKind.globalObjectForConstant:
        data = source.readConstant();
        break;
      case DeferredHolderExpressionKind.globalObjectForInterceptors:
      case DeferredHolderExpressionKind.globalObjectForStaticState:
        // no entity.
        break;
    }
    source.end(tag);
    return DeferredHolderExpression(kind, data);
  }

  void writeToDataSink(DataSink sink) {
    sink.begin(tag);
    sink.writeEnum(kind);
    switch (kind) {
      case DeferredHolderExpressionKind.globalObjectForClass:
        sink.writeClass(data);
        break;
      case DeferredHolderExpressionKind.globalObjectForMember:
        sink.writeMember(data);
        break;
      case DeferredHolderExpressionKind.globalObjectForConstant:
        sink.writeConstant(data);
        break;
      case DeferredHolderExpressionKind.globalObjectForInterceptors:
      case DeferredHolderExpressionKind.globalObjectForStaticState:
        // no entity.
        break;
    }
    sink.end(tag);
  }

  set value(js.Expression value) {
    assert(!isFinalized && value != null);
    _value = value;
  }

  @override
  js.Expression get value {
    assert(isFinalized, '$this is unassigned');
    return _value;
  }

  @override
  bool get isFinalized => _value != null;

  @override
  DeferredHolderExpression withSourceInformation(
      js.JavaScriptNodeSourceInformation newSourceInformation) {
    if (newSourceInformation == sourceInformation) return this;
    if (newSourceInformation == null) return this;
    return DeferredHolderExpression._(kind, data, _value, newSourceInformation);
  }

  @override
  int get precedenceLevel => _value?.precedenceLevel ?? js.PRIMARY;

  @override
  int get hashCode {
    return Hashing.objectsHash(kind, data);
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    return other is DeferredHolderExpression &&
        kind == other.kind &&
        data == other.data;
  }

  @override
  String toString() {
    StringBuffer sb = StringBuffer();
    sb.write('DeferredHolderExpression(kind=$kind,data=$data,');
    sb.write('value=$_value)');
    return sb.toString();
  }

  @override
  Iterable<js.Node> get containedNodes => isFinalized ? [_value] : const [];
}

/// A [DeferredHolderParameter] is a deferred JavaScript expression determined
/// by the finalization of holders. It is the injection point for data or
/// code to related to holders. This class does not support serialization.
/// TODO(joshualitt): Today this exists just for the static state holder.
/// Ideally we'd be able to treat the static state holder like other holders.
class DeferredHolderParameter extends js.Expression implements js.Parameter {
  String _name;

  @override
  final bool allowRename = false;

  @override
  final js.JavaScriptNodeSourceInformation sourceInformation;

  DeferredHolderParameter() : sourceInformation = null;
  DeferredHolderParameter._(this._name, this.sourceInformation);

  set name(String name) {
    assert(!isFinalized && name != null);
    _name = name;
  }

  @override
  String get name {
    assert(isFinalized, '$this is unassigned');
    return _name;
  }

  @override
  bool get isFinalized => _name != null;

  @override
  DeferredHolderParameter withSourceInformation(
      js.JavaScriptNodeSourceInformation newSourceInformation) {
    if (newSourceInformation == sourceInformation) return this;
    if (newSourceInformation == null) return this;
    return DeferredHolderParameter._(_name, newSourceInformation);
  }

  @override
  int get precedenceLevel => js.PRIMARY;

  @override
  T accept<T>(js.NodeVisitor<T> visitor) => visitor.visitParameter(this);

  @override
  R accept1<R, A>(js.NodeVisitor1<R, A> visitor, A arg) =>
      visitor.visitParameter(this, arg);

  @override
  void visitChildren<T>(js.NodeVisitor<T> visitor) {}

  @override
  void visitChildren1<R, A>(js.NodeVisitor1<R, A> visitor, A arg) {}

  @override
  String toString() {
    StringBuffer sb = StringBuffer();
    sb.write('DeferredHolderParameter(name=$_name)');
    return sb.toString();
  }
}

enum DeferredHolderResourceKind {
  mainFragment,
  deferredFragment,
}

/// A [DeferredHolderResource] is a deferred JavaScript statement determined by
/// the finalization of holders. Each fragment contains one
/// [DeferredHolderResource]. The actual [Statement] contained with the
/// [DeferredHolderResource] will be determined by the
/// [DeferredHolderResourceKind]. These [Statement]s differ considerably
/// depending on where they are used in the AST. This class is created by the
/// fragment emitter so does not need to support serialization.
class DeferredHolderResource extends js.DeferredStatement
    implements js.AstContainer {
  DeferredHolderResourceKind kind;
  // Each resource has a distinct name.
  String name;
  List<Fragment> fragments;
  Map<Entity, List<js.Property>> holderCode;
  js.Statement _statement;

  @override
  final js.JavaScriptNodeSourceInformation sourceInformation;

  DeferredHolderResource(this.kind, this.name, this.fragments, this.holderCode)
      : sourceInformation = null;

  DeferredHolderResource._(this.kind, this.name, this.fragments,
      this.holderCode, this._statement, this.sourceInformation);

  bool get isMainFragment => kind == DeferredHolderResourceKind.mainFragment;

  set statement(js.Statement statement) {
    assert(!isFinalized && statement != null);
    _statement = statement;
  }

  @override
  js.Statement get statement {
    assert(isFinalized, 'DeferredHolderResource is unassigned');
    return _statement;
  }

  @override
  bool get isFinalized => _statement != null;

  @override
  DeferredHolderResource withSourceInformation(
      js.JavaScriptNodeSourceInformation newSourceInformation) {
    if (newSourceInformation == sourceInformation) return this;
    if (newSourceInformation == null) return this;
    return DeferredHolderResource._(kind, this.name, this.fragments, holderCode,
        _statement, newSourceInformation);
  }

  @override
  Iterable<js.Node> get containedNodes => isFinalized ? [_statement] : const [];

  @override
  void visitChildren<T>(js.NodeVisitor<T> visitor) {
    _statement?.accept<T>(visitor);
  }

  @override
  void visitChildren1<R, A>(js.NodeVisitor1<R, A> visitor, A arg) {
    _statement?.accept1<R, A>(visitor, arg);
  }
}

const String mainResourceName = 'MAIN';

abstract class DeferredHolderExpressionFinalizer {
  /// Collects DeferredHolderExpressions from the JavaScript
  /// AST [code] and associates it with [resourceName].
  void addCode(String resourceName, js.Node code);

  /// Performs analysis on all collected DeferredHolderExpression nodes
  /// finalizes the values to expressions to access the holders.
  void finalize();

  /// The below registration functions are for use only by the visitor.
  void registerDeferredHolderExpression(
      String resourceName, DeferredHolderExpression node);
  void registerDeferredHolderResource(DeferredHolderResource node);
  void registerDeferredHolderParameter(DeferredHolderParameter node);
}

/// An abstraction representing a [Holder] object, which will contain some
/// portion of the programs code.
class Holder {
  final String name;
  final Map<String, int> refCountPerResource = {};
  final Map<String, List<js.Property>> propertiesPerResource = {};
  int _index;
  int _hashCode;

  Holder(this.name);

  int refCount(String resource) => refCountPerResource[resource];

  void registerUse(String resource) {
    refCountPerResource.update(resource, (count) => count + 1,
        ifAbsent: () => 0);
  }

  void registerUpdate(String resource, List<js.Property> properties) {
    (propertiesPerResource[resource] ??= []).addAll(properties);
    registerUse(resource);
  }

  int get index {
    assert(_index != null);
    return _index;
  }

  set index(int newIndex) {
    assert(_index == null);
    _index = newIndex;
  }

  @override
  bool operator ==(that) {
    return that is Holder && name == that.name;
  }

  @override
  int get hashCode {
    return _hashCode ??= Hashing.objectsHash(name);
  }
}

/// [DeferredHolderExpressionFinalizerImpl] finalizes
/// [DeferredHolderExpression]s, [DeferredHolderParameter]s,
/// [DeferredHolderResource]s, [DeferredHolderResourceExpression]s.
class DeferredHolderExpressionFinalizerImpl
    implements DeferredHolderExpressionFinalizer {
  _DeferredHolderExpressionCollectorVisitor _visitor;
  final Map<String, List<DeferredHolderExpression>> holderReferences = {};
  final List<DeferredHolderParameter> holderParameters = [];
  final List<DeferredHolderResource> holderResources = [];
  final Map<String, Set<Holder>> holdersPerResource = {};
  final Map<String, Holder> holderMap = {};
  final JCommonElements _commonElements;
  DeferredHolderResource mainHolderResource;

  DeferredHolderExpressionFinalizerImpl(this._commonElements) {
    _visitor = _DeferredHolderExpressionCollectorVisitor(this);
  }

  @override
  void addCode(String resourceName, js.Node code) {
    _visitor.setResourceNameAndVisit(resourceName, code);
  }

  final List<String> userGlobalObjects =
      List.from(Namer.reservedGlobalObjectNames)
        ..remove('C')
        ..remove('H')
        ..remove('J')
        ..remove('P')
        ..remove('W');

  /// Returns the [reservedGlobalObjectNames] for [library].
  String globalObjectNameForLibrary(LibraryEntity library) {
    if (library == _commonElements.interceptorsLibrary)
      return globalObjectNameForInterceptors();
    Uri uri = library.canonicalUri;
    if (uri.scheme == 'dart') {
      if (uri.path == 'html') return 'W';
      if (uri.path.startsWith('_')) return 'H';
      return 'P';
    }
    return userGlobalObjects[library.name.hashCode % userGlobalObjects.length];
  }

  /// Returns true if [element] is stored in the static state holder
  /// ([staticStateHolder]).  We intend to store only mutable static state
  /// there, whereas constants are stored in 'C'. Functions, accessors,
  /// classes, etc. are stored in one of the other objects in
  /// [reservedGlobalObjectNames].
  bool _isPropertyOfStaticStateHolder(MemberEntity element) {
    // TODO(ahe): Make sure this method's documentation is always true and
    // remove the word "intend".
    return element.isField;
  }

  String globalObjectNameForMember(MemberEntity entity) {
    if (_isPropertyOfStaticStateHolder(entity)) {
      return globalObjectNameForStaticState();
    } else {
      return globalObjectNameForLibrary(entity.library);
    }
  }

  String globalObjectNameForClass(ClassEntity entity) {
    return globalObjectNameForLibrary(entity.library);
  }

  final Holder globalObjectForStaticState =
      Holder(globalObjectNameForStaticState());

  static String globalObjectNameForInterceptors() => 'J';

  static String globalObjectNameForStaticState() => r'$';

  String globalObjectNameForConstants() => 'C';

  String globalObjectNameForEntity(Entity entity) {
    if (entity is MemberEntity) {
      return globalObjectNameForMember(entity);
    } else if (entity is ClassEntity) {
      return globalObjectNameForLibrary(entity.library);
    } else {
      assert(entity is LibraryEntity);
      return globalObjectNameForLibrary(entity);
    }
  }

  Holder holderNameToHolder(String holderKey) {
    if (holderKey == globalObjectNameForStaticState()) {
      return globalObjectForStaticState;
    } else {
      return holderMap[holderKey];
    }
  }

  Holder globalObjectForEntity(Entity entity) {
    return holderNameToHolder(globalObjectNameForEntity(entity));
  }

  /// Registers a [holder] use within a given [resource], if [properties] are
  /// provided then it is assumed this is an update to a holder.
  void registerHolderUseOrUpdate(String resourceName, String holderName,
      {List<js.Property> properties}) {
    // For simplicity, we don't currently track the static state holder per
    // resource.
    if (holderName == globalObjectNameForStaticState()) return;
    Holder holder = holderMap[holderName] ??= Holder(holderName);
    if (properties == null) {
      holder.registerUse(resourceName);
    } else {
      holder.registerUpdate(resourceName, properties);
    }
    (holdersPerResource[resourceName] ??= {}).add(holder);
  }

  /// Returns a key to a global object for a given [Object] based on the
  /// [DeferredHolderExpressionKind].
  String kindToHolderName(DeferredHolderExpressionKind kind, Object data) {
    switch (kind) {
      case DeferredHolderExpressionKind.globalObjectForInterceptors:
        return globalObjectNameForInterceptors();
      case DeferredHolderExpressionKind.globalObjectForClass:
        return globalObjectNameForClass(data);
      case DeferredHolderExpressionKind.globalObjectForMember:
        return globalObjectNameForMember(data);
      case DeferredHolderExpressionKind.globalObjectForConstant:
        return globalObjectNameForConstants();
      case DeferredHolderExpressionKind.globalObjectForStaticState:
        return globalObjectNameForStaticState();
    }
    throw UnsupportedError("Unreachable");
  }

  /// Returns a global object for a given [Object] based on the
  /// [DeferredHolderExpressionKind].
  Holder kindToHolder(DeferredHolderExpressionKind kind, Object data) {
    return holderNameToHolder(kindToHolderName(kind, data));
  }

  /// Finalizes [DeferredHolderParameter]s.
  void finalizeParameters() {
    for (var parameter in holderParameters) {
      if (parameter.isFinalized) continue;
      parameter.name = globalObjectNameForStaticState();
    }
  }

  /// Finalizes all of the [DeferredHolderExpression]s associated with a
  /// [DeferredHolderResource].
  void finalizeReferences(DeferredHolderResource resource) {
    if (!holderReferences.containsKey(resource.name)) return;
    for (var reference in holderReferences[resource.name]) {
      if (reference.isFinalized) continue;
      String holder = kindToHolder(reference.kind, reference.data).name;
      js.Expression value = js.VariableUse(holder);
      reference.value =
          value.withSourceInformation(reference.sourceInformation);
    }
  }

  /// Registers all of the holders used in the entire program.
  void registerHolders() {
    // Register all holders used in all [DeferredHolderResource]s.
    for (var resource in holderResources) {
      resource.holderCode.forEach((entity, properties) {
        String holderName = globalObjectNameForEntity(entity);
        registerHolderUseOrUpdate(resource.name, holderName,
            properties: properties);
      });
    }

    // Register all holders used in [DeferredHolderReference]s.
    holderReferences.forEach((resource, references) {
      for (var reference in references) {
        String holderName = kindToHolderName(reference.kind, reference.data);
        registerHolderUseOrUpdate(resource, holderName);
      }
    });
  }

  /// Returns an [Iterable<Holder>] containing all of the holders used within a
  /// given [DeferredHolderResource]except the static state holder (if any).
  Iterable<Holder> nonStaticStateHolders(DeferredHolderResource resource) {
    return holdersPerResource[resource.name] ?? [];
  }

  /// Returns an [Iterable<Holder>] containing all of the holders used within a
  /// given [DeferredHolderResource] except the static state holder.
  Iterable<Holder> get allNonStaticStateHolders {
    return holderMap.values;
  }

  /// Generates code to declare holders for a given [resourceName].
  HolderInitCode declareHolders(String resourceName, Iterable<Holder> holders,
      {bool initializeEmptyHolders = false}) {
    // Create holder initialization code. If there are no properties
    // associated with a given holder in this specific [DeferredHolderResource]
    // then it will be omitted. However, in some cases, i.e. the main output
    // unit, we still want to declare the holder with an empty object literal
    // which will be filled in later by another [DeferredHolderResource], i.e.
    // in a specific deferred fragment. The generated code looks like this:
    //
    //    {
    //      var H = {...}, ..., G = {...};
    //    }

    List<Holder> activeHolders = [];
    List<js.VariableInitialization> holderInitializations = [];
    for (var holder in holders) {
      var holderName = holder.name;
      List<js.Property> properties =
          holder.propertiesPerResource[resourceName] ?? [];
      if (properties.isEmpty) {
        holderInitializations.add(js.VariableInitialization(
            js.VariableDeclaration(holderName, allowRename: false),
            initializeEmptyHolders ? js.ObjectInitializer(properties) : null));
      } else {
        activeHolders.add(holder);
        holderInitializations.add(js.VariableInitialization(
            js.VariableDeclaration(holderName, allowRename: false),
            js.ObjectInitializer(properties)));
      }
    }

    // Create statement to initialize holders.
    var initStatement = js.ExpressionStatement(
        js.VariableDeclarationList(holderInitializations, indentSplits: false));
    return HolderInitCode(holders, activeHolders, initStatement);
  }

  /// Finalizes [resource] to code that updates holders. [resource] must be in
  /// the AST of a deferred fragment.
  void updateHolders(DeferredHolderResource resource) {
    final holderCode =
        declareHolders(resource.name, nonStaticStateHolders(resource));

    // Set names if necessary on deferred holders list.
    js.Expression deferredHoldersList = js.ArrayInitializer(holderCode
        .activeHolders
        .map((holder) => js.js("#", holder.name))
        .toList(growable: false));
    js.Statement setNames = js.js.statement(
        'hunkHelpers.setFunctionNamesIfNecessary(#deferredHoldersList)',
        {'deferredHoldersList': deferredHoldersList});

    // Update holder assignments.
    List<js.Statement> updateHolderAssignments = [
      if (holderCode.allHolders.isNotEmpty) holderCode.statement,
      setNames
    ];
    for (var holder in holderCode.allHolders) {
      var holderName = holder.name;
      var holderIndex = js.number(holder.index);
      if (holderCode.activeHolders.contains(holder)) {
        updateHolderAssignments.add(js.js.statement(
            '#holder = hunkHelpers.updateHolder(holdersList[#index], #holder)',
            {'index': holderIndex, 'holder': js.VariableUse(holderName)}));
      } else {
        // TODO(sra): Change declaration followed by assignments to declarations
        // with initialization.
        updateHolderAssignments.add(js.js.statement(
            '#holder = holdersList[#index]',
            {'index': holderIndex, 'holder': js.VariableUse(holderName)}));
      }
    }

    // Create a single block of all statements.
    resource.statement = js.Block(updateHolderAssignments);
  }

  /// Declares all holders in the [DeferredHolderResource] representing the main
  /// fragment.
  void declareHoldersInMainResource() {
    // Declare holders in main output unit.
    var holders = allNonStaticStateHolders;
    var holderCode = declareHolders(mainHolderResource.name, holders,
        initializeEmptyHolders: true);

    // Create holder uses and init holder indices.
    List<js.VariableUse> holderUses = [];
    int i = 0;
    for (var holder in holders) {
      holder.index = i++;
      holderUses.add(js.VariableUse(holder.name));
    }

    // Create holders array statement.
    //    {
    //      var holders = [ H, ..., G ];
    //    }
    var holderArray =
        js.js.statement('var holders = #', js.ArrayInitializer(holderUses));

    mainHolderResource.statement =
        js.Block([holderCode.statement, holderArray]);
  }

  /// Allocates all [DeferredHolderResource]s and finalizes the associated
  /// [DeferredHolderExpression]s.
  void allocateResourcesAndFinalizeReferences() {
    // First finalize all holders in the main output unit.
    declareHoldersInMainResource();

    // Next finalize all [DeferredHolderResource]s.
    for (var resource in holderResources) {
      switch (resource.kind) {
        case DeferredHolderResourceKind.mainFragment:
          // There should only be one main resource and at this point it
          // should have already been finalized.
          assert(mainHolderResource == resource && resource.isFinalized);
          break;
        case DeferredHolderResourceKind.deferredFragment:
          updateHolders(resource);
          break;
      }
      finalizeReferences(resource);
    }
  }

  @override
  void finalize() {
    registerHolders();
    finalizeParameters();
    allocateResourcesAndFinalizeReferences();
  }

  @override
  void registerDeferredHolderExpression(
      String resourceName, DeferredHolderExpression node) {
    (holderReferences[resourceName] ??= []).add(node);
  }

  @override
  void registerDeferredHolderResource(DeferredHolderResource node) {
    if (node.isMainFragment) {
      assert(mainHolderResource == null);
      mainHolderResource = node;
    }
    holderResources.add(node);
  }

  @override
  void registerDeferredHolderParameter(DeferredHolderParameter node) {
    holderParameters.add(node);
  }
}

/// Scans a JavaScript AST to collect all the [DeferredHolderExpression],
/// [DeferredHolderParameter], [DeferredHolderResource], and
/// [DeferredHolderResourceExpression] nodes.
///
/// The state is kept in the finalizer so that this scan could be extended to
/// look for other deferred expressions in one pass.
class _DeferredHolderExpressionCollectorVisitor extends js.BaseVisitor<void> {
  String resourceName;
  final DeferredHolderExpressionFinalizer _finalizer;

  _DeferredHolderExpressionCollectorVisitor(this._finalizer);

  void setResourceNameAndVisit(String resourceName, js.Node code) {
    this.resourceName = resourceName;
    code.accept(this);
    this.resourceName = null;
  }

  @override
  void visitNode(js.Node node) {
    assert(node is! DeferredHolderExpression);
    if (node is js.AstContainer) {
      for (js.Node element in node.containedNodes) {
        element.accept(this);
      }
    } else {
      super.visitNode(node);
    }
  }

  @override
  void visitDeferredExpression(js.DeferredExpression node) {
    if (node is DeferredHolderExpression) {
      assert(resourceName != null);
      _finalizer.registerDeferredHolderExpression(resourceName, node);
    } else {
      visitNode(node);
    }
  }

  @override
  void visitDeferredStatement(js.DeferredStatement node) {
    if (node is DeferredHolderResource) {
      _finalizer.registerDeferredHolderResource(node);
    } else {
      visitNode(node);
    }
  }

  @override
  void visitParameter(js.Parameter node) {
    if (node is DeferredHolderParameter) {
      _finalizer.registerDeferredHolderParameter(node);
    } else {
      visitNode(node);
    }
  }
}

class HolderInitCode {
  final Iterable<Holder> allHolders;
  final List<Holder> activeHolders;
  final js.Statement statement;
  HolderInitCode(this.allHolders, this.activeHolders, this.statement);
}

/// All of the code below this point is legacy code.

/// [DeferredHolderExpressionFinalizerImpl] finalizes
/// [DeferredHolderExpression]s, [DeferredHolderParameter]s,
/// [DeferredHolderResource]s, [DeferredHolderResourceExpression]s.
class LegacyDeferredHolderExpressionFinalizerImpl
    implements DeferredHolderExpressionFinalizer {
  _DeferredHolderExpressionCollectorVisitor _visitor;
  final List<DeferredHolderExpression> holderReferences = [];
  final List<DeferredHolderParameter> holderParameters = [];
  final List<DeferredHolderResource> holderResources = [];
  final Set<String> _uniqueHolders = {};
  final List<String> _holders = [];
  final Map<Entity, String> _entityMap = {};
  final JCommonElements _commonElements;

  LegacyDeferredHolderExpressionFinalizerImpl(this._commonElements) {
    _visitor = _DeferredHolderExpressionCollectorVisitor(this);
  }

  @override
  void addCode(String resourceName, js.Node code) {
    _visitor.setResourceNameAndVisit(resourceName, code);
  }

  final List<String> userGlobalObjects =
      new List.from(Namer.reservedGlobalObjectNames)
        ..remove('C')
        ..remove('H')
        ..remove('J')
        ..remove('P')
        ..remove('W');

  /// Returns the [reservedGlobalObjectNames] for [library].
  String globalObjectForLibrary(LibraryEntity library) {
    if (library == _commonElements.interceptorsLibrary) return 'J';
    Uri uri = library.canonicalUri;
    if (uri.scheme == 'dart') {
      if (uri.path == 'html') return 'W';
      if (uri.path.startsWith('_')) return 'H';
      return 'P';
    }
    return userGlobalObjects[library.name.hashCode % userGlobalObjects.length];
  }

  /// Returns true if [element] is stored in the static state holder
  /// ([staticStateHolder]).  We intend to store only mutable static state
  /// there, whereas constants are stored in 'C'. Functions, accessors,
  /// classes, etc. are stored in one of the other objects in
  /// [reservedGlobalObjectNames].
  bool _isPropertyOfStaticStateHolder(MemberEntity element) {
    // TODO(ahe): Make sure this method's documentation is always true and
    // remove the word "intend".
    return element.isField;
  }

  String globalObjectForMember(MemberEntity entity) {
    if (_isPropertyOfStaticStateHolder(entity)) {
      return globalObjectForStaticState();
    } else {
      return globalObjectForLibrary(entity.library);
    }
  }

  String globalObjectForClass(ClassEntity entity) {
    return globalObjectForLibrary(entity.library);
  }

  String globalObjectForInterceptors() => 'J';

  String globalObjectForStaticState() => r'$';

  String globalObjectForConstants() => 'C';

  String globalObjectForEntity(Entity entity) {
    if (entity is MemberEntity) {
      return globalObjectForMember(entity);
    } else if (entity is ClassEntity) {
      return globalObjectForLibrary(entity.library);
    } else {
      assert(entity is LibraryEntity);
      return globalObjectForLibrary(entity);
    }
  }

  /// Registers an [Entity] with a specific [holder].
  void registerHolderUse(String holder, Object data) {
    if (_uniqueHolders.add(holder)) _holders.add(holder);
    if (data != null && data is Entity) {
      assert(!_entityMap.containsKey(data) || _entityMap[data] == holder);
      _entityMap[data] = holder;
    }
  }

  /// Returns a global object for a given [Object] based on the
  /// [DeferredHolderExpressionKind].
  String kindToHolder(DeferredHolderExpressionKind kind, Object data) {
    switch (kind) {
      case DeferredHolderExpressionKind.globalObjectForInterceptors:
        return globalObjectForInterceptors();
      case DeferredHolderExpressionKind.globalObjectForClass:
        return globalObjectForClass(data);
      case DeferredHolderExpressionKind.globalObjectForMember:
        return globalObjectForMember(data);
      case DeferredHolderExpressionKind.globalObjectForConstant:
        return globalObjectForConstants();
      case DeferredHolderExpressionKind.globalObjectForStaticState:
        return globalObjectForStaticState();
    }
    throw UnsupportedError("Unreachable");
  }

  /// Finalizes [DeferredHolderExpression]s [DeferredHolderParameter]s.
  void finalizeReferences() {
    // Finalize [DeferredHolderExpression]s and registers holder usage.
    for (var reference in holderReferences) {
      if (reference.isFinalized) continue;
      Object data = reference.data;
      String holder = kindToHolder(reference.kind, data);
      js.Expression value = js.VariableUse(holder);
      registerHolderUse(holder, data);
      reference.value =
          value.withSourceInformation(reference.sourceInformation);
    }

    // Finalize [DeferredHolderParameter]s.
    for (var parameter in holderParameters) {
      if (parameter.isFinalized) continue;
      parameter.name = globalObjectForStaticState();
    }
  }

  /// Registers all of the holders used by a given [DeferredHolderResource].
  void registerHolders(DeferredHolderResource resource) {
    for (var entity in resource.holderCode.keys) {
      var holder = globalObjectForEntity(entity);
      registerHolderUse(holder, entity);
    }
  }

  /// Returns a [List<String>] containing all of the holders except the static
  /// state holder.
  List<String> get nonStaticStateHolders {
    return _holders
        .where((holder) => holder != globalObjectForStaticState())
        .toList(growable: false);
  }

  /// Generates code to declare holders.
  LegacyHolderCode declareHolders(DeferredHolderResource resource) {
    // Collect all holders except the static state holder. Then, create a map of
    // holder to list of properties which are associated with that holder, but
    // only with respect to a given [DeferredHolderResource]. Each fragment will
    // have its own [DeferredHolderResource] and associated code.
    Map<String, List<js.Property>> codePerHolder = {};
    final holders = nonStaticStateHolders;
    for (var holder in holders) {
      codePerHolder[holder] = [];
    }

    final holderCode = resource.holderCode;
    holderCode.forEach((entity, properties) {
      assert(_entityMap.containsKey(entity));
      var holder = _entityMap[entity];
      assert(codePerHolder.containsKey(holder));
      codePerHolder[holder].addAll(properties);
    });

    // Create holder initialization code based on the [codePerHolder]. If there
    // are no properties associated with a given holder in this specific
    // [DeferredHolderResource] then it will be omitted. However, in some cases,
    // i.e. the main output unit, we still want to declare the holder with an
    // empty object literal which will be filled in later by another
    // [DeferredHolderResource], i.e. in a specific deferred fragment.
    // The generated code looks like this:
    //
    //    {
    //      var H = {...}, ..., G = {...};
    //      var holders = [ H, ..., G ]; // Main unit only.
    //    }

    List<String> activeHolders = [];
    List<js.VariableInitialization> holderInitializations = [];
    for (var holder in holders) {
      List<js.Property> properties = codePerHolder[holder];
      if (properties.isEmpty) {
        holderInitializations.add(js.VariableInitialization(
            js.VariableDeclaration(holder, allowRename: false),
            resource.isMainFragment ? js.ObjectInitializer(properties) : null));
      } else {
        activeHolders.add(holder);
        holderInitializations.add(js.VariableInitialization(
            js.VariableDeclaration(holder, allowRename: false),
            js.ObjectInitializer(properties)));
      }
    }

    List<js.Statement> statements = [];
    statements.add(js.ExpressionStatement(js.VariableDeclarationList(
        holderInitializations,
        indentSplits: false)));
    if (resource.isMainFragment) {
      statements.add(js.js.statement(
          'var holders = #',
          js.ArrayInitializer(holders
              .map((holder) => js.VariableUse(holder))
              .toList(growable: false))));
    }
    return LegacyHolderCode(activeHolders, statements);
  }

  /// Finalizes [resource] to code that updates holders. [resource] must be in
  /// the AST of a deferred fragment.
  void updateHolders(DeferredHolderResource resource) {
    // Declare holders.
    final holderCode = declareHolders(resource);

    // Set names if necessary on deferred holders list.
    js.Expression deferredHoldersList = js.ArrayInitializer(holderCode
        .activeHolders
        .map((holder) => js.js("#", holder))
        .toList(growable: false));
    js.Statement setNames = js.js.statement(
        'hunkHelpers.setFunctionNamesIfNecessary(#deferredHoldersList)',
        {'deferredHoldersList': deferredHoldersList});

    // Update holder assignments.
    final holders = nonStaticStateHolders;
    List<js.Statement> updateHolderAssignments = [setNames];
    for (int i = 0; i < holders.length; i++) {
      var holder = holders[i];
      if (holderCode.activeHolders.contains(holder)) {
        updateHolderAssignments.add(js.js.statement(
            '#holder = hunkHelpers.updateHolder(holdersList[#index], #holder)',
            {'index': js.number(i), 'holder': js.VariableUse(holder)}));
      } else {
        // TODO(sra): Change declaration followed by assignments to declarations
        // with initialization.
        updateHolderAssignments.add(js.js.statement(
            '#holder = holdersList[#index]',
            {'index': js.number(i), 'holder': js.VariableUse(holder)}));
      }
    }

    // Create a single block of all statements.
    List<js.Statement> statements = holderCode.statements
        .followedBy(updateHolderAssignments)
        .toList(growable: false);
    resource.statement = js.Block(statements);
  }

  /// Allocates all [DeferredHolderResource]s and
  /// [DeferredHolderResourceExpression]s.
  void allocateResources() {
    // First ensure all holders used in all [DeferredHolderResource]s have been
    // allocated.
    for (var resource in holderResources) {
      registerHolders(resource);
    }
    _holders.sort();

    // Next finalize all [DeferredHolderResource]s.
    for (var resource in holderResources) {
      switch (resource.kind) {
        case DeferredHolderResourceKind.mainFragment:
          var holderCode = declareHolders(resource);
          resource.statement = js.Block(holderCode.statements);
          break;
        case DeferredHolderResourceKind.deferredFragment:
          updateHolders(resource);
          break;
      }
    }
  }

  @override
  void finalize() {
    finalizeReferences();
    allocateResources();
  }

  @override
  void registerDeferredHolderExpression(
      String resourceName, DeferredHolderExpression node) {
    holderReferences.add(node);
  }

  @override
  void registerDeferredHolderResource(DeferredHolderResource node) {
    holderResources.add(node);
  }

  @override
  void registerDeferredHolderParameter(DeferredHolderParameter node) {
    holderParameters.add(node);
  }
}

class LegacyHolderCode {
  final List<String> activeHolders;
  final List<js.Statement> statements;
  LegacyHolderCode(this.activeHolders, this.statements);
}
