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

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 =
      <LibraryEntity, LibraryContents>{};

  // 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, () => new 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<String, Holder> _holdersMap = <String, Holder>{};
  final Map<OutputUnit, LibrariesMap> _deferredLibrariesMap =
      <OutputUnit, LibrariesMap>{};

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

  Iterable<Holder> get holders => _holdersMap.values;
  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 = new LibrariesMap.main(_mainOutputUnit);
    } else {
      assert(!_deferredLibrariesMap.containsKey(outputUnit));
      String name = outputUnit.name;
      _deferredLibrariesMap[outputUnit] =
          new 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.
  }

  Holder registerHolder(String name,
      {bool isStaticStateHolder: false, bool isConstantsHolder: false}) {
    assert(_holdersMap[name] == null ||
        (_holdersMap[name].isStaticStateHolder == isStaticStateHolder &&
            _holdersMap[name].isConstantsHolder == isConstantsHolder));

    return _holdersMap.putIfAbsent(name, () {
      return new Holder(name, _holdersMap.length,
          isStaticStateHolder: isStaticStateHolder,
          isConstantsHolder: isConstantsHolder);
    });
  }
}
