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

// @dart = 2.10

part of dart2js.js_emitter.program_builder;

class LibraryContents {
  final List<ClassEntity> classes = [];
  final List<MemberEntity> members = [];
  final List<ClassEntity> classTypes = [];
}

/// Maps [LibraryEntity]s to their classes, members, and class types.
///
/// Fundamentally, this class nicely encapsulates a
/// `Map<LibraryEntity, Tuple<classes, members, class types>>`.
///
/// where both classes and class types are lists of [ClassEntity] and
/// members is a list of [MemberEntity].
///
/// There exists exactly one instance per [OutputUnit].
class LibrariesMap {
  final Map<LibraryEntity, LibraryContents> _mapping = {};

  // It is very common to access the same library multiple times in a row, so
  // we cache the last access.
  LibraryEntity _lastLibrary;
  LibraryContents _lastMapping;

  /// A unique name representing this instance.
  final String name;
  final OutputUnit outputUnit;

  LibrariesMap.main(this.outputUnit) : name = "";

  LibrariesMap.deferred(this.outputUnit, this.name) {
    assert(name != "");
  }

  LibraryContents _getMapping(LibraryEntity library) {
    if (_lastLibrary != library) {
      _lastLibrary = library;
      _lastMapping = _mapping.putIfAbsent(library, () => LibraryContents());
    }
    return _lastMapping;
  }

  void addClass(LibraryEntity library, ClassEntity element) {
    _getMapping(library).classes.add(element);
  }

  void addClassType(LibraryEntity library, ClassEntity element) {
    _getMapping(library).classTypes.add(element);
  }

  void addMember(LibraryEntity library, MemberEntity element) {
    _getMapping(library).members.add(element);
  }

  int get length => _mapping.length;

  void forEach(
      void f(LibraryEntity library, List<ClassEntity> classes,
          List<MemberEntity> members, List<ClassEntity> classTypeData)) {
    _mapping.forEach((LibraryEntity library, LibraryContents mapping) {
      f(library, mapping.classes, mapping.members, mapping.classTypes);
    });
  }
}

/// Keeps track of all elements and holders.
///
/// This class assigns each registered element to its [LibrariesMap] (which are
/// in bijection with [OutputUnit]s).
///
/// Registered holders are assigned a name.
class Registry {
  final OutputUnit _mainOutputUnit;
  final Sorter _sorter;
  final Map<OutputUnit, LibrariesMap> _deferredLibrariesMap = {};

  /// Cache for the last seen output unit.
  OutputUnit _lastOutputUnit;
  LibrariesMap _lastLibrariesMap;

  Iterable<LibrariesMap> get deferredLibrariesMap =>
      _deferredLibrariesMap.values;

  // Add one for the main libraries map.
  int get librariesMapCount => _deferredLibrariesMap.length + 1;

  LibrariesMap mainLibrariesMap;

  Registry(this._mainOutputUnit, this._sorter);

  LibrariesMap _mapUnitToLibrariesMap(OutputUnit targetUnit) {
    if (targetUnit == _lastOutputUnit) return _lastLibrariesMap;

    LibrariesMap result = (targetUnit == _mainOutputUnit)
        ? mainLibrariesMap
        : _deferredLibrariesMap[targetUnit];

    assert(result != null);
    _lastOutputUnit = targetUnit;
    _lastLibrariesMap = result;
    return result;
  }

  void registerOutputUnit(OutputUnit outputUnit) {
    if (outputUnit == _mainOutputUnit) {
      assert(mainLibrariesMap == null);
      mainLibrariesMap = LibrariesMap.main(_mainOutputUnit);
    } else {
      assert(!_deferredLibrariesMap.containsKey(outputUnit));
      String name = outputUnit.name;
      _deferredLibrariesMap[outputUnit] =
          LibrariesMap.deferred(outputUnit, name);
    }
  }

  /// Adds all elements to their respective libraries in the correct
  /// libraries map.
  void registerClasses(OutputUnit outputUnit, Iterable<ClassEntity> elements) {
    LibrariesMap targetLibrariesMap = _mapUnitToLibrariesMap(outputUnit);
    for (ClassEntity element in _sorter.sortClasses(elements)) {
      targetLibrariesMap.addClass(element.library, element);
    }
  }

  /// Adds all elements to their respective libraries in the correct
  /// libraries map.
  void registerClassTypes(
      OutputUnit outputUnit, Iterable<ClassEntity> elements) {
    LibrariesMap targetLibrariesMap = _mapUnitToLibrariesMap(outputUnit);
    for (ClassEntity element in _sorter.sortClasses(elements)) {
      targetLibrariesMap.addClassType(element.library, element);
    }
  }

  /// Adds all elements to their respective libraries in the correct
  /// libraries map.
  void registerMembers(OutputUnit outputUnit, Iterable<MemberEntity> elements) {
    LibrariesMap targetLibrariesMap = _mapUnitToLibrariesMap(outputUnit);
    for (MemberEntity element in _sorter.sortMembers(elements)) {
      targetLibrariesMap.addMember(element.library, element);
    }
  }

  void registerConstant(OutputUnit outputUnit, ConstantValue constantValue) {
    // Ignore for now.
  }
}
