// Copyright (c) 2019, 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 'dart:collection' show SplayTreeMap;

/// Assigns names from [nameSequence] to items using a naive algorithm.
///
/// Items are assigned the next available name in decreasing frequency
/// order. This allocation order is unstable in that small changes in the input
/// cause large changes in the output. To see this, consider a typical
/// distribution that has a 'tail' where large numbers of items occur two or
/// three times. If the small change causes one of the items that occurs twice
/// to occur four times, of then all the items that occur three times will be
/// assigned names that are 'shifted down' in the allocation order, as will many
/// of the items that occur twice.
///
/// See [semistableFrequencyAssignment] for meaning of parameters.
void naiveFrequencyAssignment(
  int items,
  Iterable<String> nameSequence,
  int Function(int) hashOf,
  int Function(int) countOf,
  void Function(int, String) assign,
) {
  Iterator<String> nameIterator = nameSequence.iterator..moveNext();

  for (int item = 0; item < items; item++) {
    assign(item, nameIterator.current);
    nameIterator.moveNext();
  }
}

/// Assigns names from [nameSequence] to items, trying to avoid the unstable
/// allocation of [naiveFrequencyAssignment] by assigning items to their
/// hashing-based 'preferred' slots if possible.
///
/// - [items]: number of items to be assigned names. Items are numbered from
///   zero. Items must be sorted in order of decreasing [countOf].
///
/// - [nameSequence]: Potentially unbounded sequence of valid names in
///   increasing size.
///
/// - [hashOf]: Function returning a stable hash code for item `i`.
///
/// - [countOf]: Function returning the frequency or number of occurrences of
///   item `i`.
///
/// - [assign]: Function to register the assignment of a name to item `i`.
void semistableFrequencyAssignment(
  int items,
  Iterable<String> nameSequence,
  int Function(int) hashOf,
  int Function(int) countOf,
  void Function(int, String) assign,
) {
  // Overallocate 3x the number of names so that the last pool is large enough
  // to substantially reduce collisions. Round up to the next power of two so
  // that slightly changing the number of items does not usually change the size
  // of the largest pool.
  int maxIndex = 1 << (items * 3).bitLength;
  List<String> names = nameSequence.take(maxIndex).toList(growable: false);
  List<_Pool> pools = _Pool.makePools(names);

  // First cohort with unassigned items.
  _Cohort? firstCohort = _Cohort.makeCohorts(items, countOf);

  for (var pool in pools) {
    // Completely allocate smaller pools before allocating larger
    // pools. Completely allocate each cohort in turn.

    // TODO(sra): If the next several cohorts all fit in the current pool, the
    // allocation will not change the bytes saved by minification.  Consider
    // allocating the preferred slot from several cohorts before allocating a
    // non-preferred slot. This should increase the number of items allocated to
    // their preferred slot.
    firstCohort = firstCohort?.skipEmpty();
    for (
      var startCohort = firstCohort;
      startCohort != null;
      startCohort = startCohort.next
    ) {
      if (pool.remaining == 0) break;

      // Pass 1: assign members of cohort their preferred slot if available.
      List<int> assigned = [];
      for (var item in startCohort.unassigned) {
        if (pool.remaining == 0) break;
        int hash = hashOf(item);
        int slot = hash % pool.size;
        if (pool.slotIsAvailable(slot)) {
          assign(item, pool.allocate(slot));
          assigned.add(item);
        }
      }
      startCohort.unassigned.removeAll(assigned);
      // Pass 2: assign members of cohort their second 'rehash' slot if
      // available, or the next available slot.
      assigned.clear();
      for (var item in startCohort.unassigned) {
        if (pool.remaining == 0) break;
        int hash = hashOf(item);
        int rehashSlot = (5 * hash + 7) % pool.size;
        int slot = pool.firstAvailableSlotFrom(rehashSlot);
        assign(item, pool.allocate(slot));
        assigned.add(item);
      }
      startCohort.unassigned.removeAll(assigned);
    }
  }

  // Perform naive assignment of any items left unassigned above (should be
  // none).
  for (var pool in pools) {
    while (pool.remaining > 0) {
      firstCohort = firstCohort?.skipEmpty();
      if (firstCohort == null) break;

      var item = firstCohort.unassigned.first;
      String name = pool.allocate(pool.firstAvailableSlot());
      assign(item, name);
      firstCohort.unassigned.remove(item);
    }
  }
}

/// A [_Pool] is a set of identifiers of the same length from which names are
/// allocated.
class _Pool {
  final List<String?> _names = [];

  // Keep the unused (available) slots in an ordered set for efficiently finding
  // the next available slot (i.e. linear rehash).  We are concerned about
  // efficiency because the smaller pools are completely allocated, making
  // worst-case linear rehashing quadratic. Using an ordered map brings this
  // down to O(N log N).
  //
  // We would prefer an ordered Set, but SplayTreeSet does not have methods to
  // find keys adjacent to a query key.
  final SplayTreeMap<int, bool> _availableSlots = SplayTreeMap();

  static List<_Pool> makePools(Iterable<String> names) {
    List<_Pool> pools = [];
    for (var name in names) {
      int length = name.length;
      while (pools.length < length) {
        pools.add(_Pool());
      }
      _Pool pool = pools[length - 1];
      pool._availableSlots[pool._names.length] = true;
      pool._names.add(name);
    }
    return pools;
  }

  int get size => _names.length;
  int get remaining => _availableSlots.length;

  bool slotIsAvailable(int slot) => _names[slot] != null;

  int firstAvailableSlot() => _availableSlots.keys.first;

  /// Returns [start] if slot [start] is free, otherwise returns the next
  /// available slot.
  int firstAvailableSlotFrom(int start) =>
      _availableSlots.firstKeyAfter(start - 1) ??
      _availableSlots.firstKeyAfter(-1) ??
      (throw StateError('No entries left in pool'));

  String allocate(int slot) {
    String name = _names[slot]!;
    _names[slot] = null;
    _availableSlots.remove(slot);
    return name;
  }

  @override
  String toString() => '_Pool(${_names.length}, ${_availableSlots.length})';
}

/// A [_Cohort] is a set of entities which occur with the same frequency. The
/// entities are identified by integers.
class _Cohort {
  _Cohort? next; // Next cohort in decreasing frequency.
  final int count; // This is the cohort of items occurring [count] times.
  Set<int> unassigned = {};

  _Cohort(this.count);

  _Cohort? skipEmpty() {
    _Cohort? cohort = this;
    while (cohort != null && cohort.remaining == 0) {
      cohort = cohort.next;
    }
    return cohort;
  }

  int get remaining => unassigned.length;

  static _Cohort? makeCohorts(int items, int Function(int) countOf) {
    // Build _Cohorts.
    _Cohort? first, current;
    int lastCount = -1;
    for (int item = 0; item < items; item++) {
      int count = countOf(item);
      if (count != lastCount) {
        lastCount = count;
        _Cohort next = _Cohort(count);
        if (current == null) {
          first = next;
        } else {
          current.next = next;
        }
        current = next;
      }
      current!.unassigned.add(item);
    }
    return first;
  }

  @override
  String toString() => '_Cohort($count, $remaining)';
}
