// 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 pub.solver.dependency_queue;

import 'dart:async';
import 'dart:collection' show Queue;

import '../log.dart' as log;
import '../package.dart';
import 'backtracking_solver.dart';

/// A queue of one package's dependencies, ordered by how the solver should
/// traverse them.
///
/// It prefers locked versions so that they stay locked if possible. Then it
/// prefers a currently selected package so that it only has to consider a
/// single version.
///
/// After that, it orders the remaining packages by the number of versions they
/// have so that packages with fewer versions are solved first. (If two
/// packages have the same number of versions, they are sorted alphabetically
/// just to be deterministic.)
///
/// Critically, this queue will *not* sort the dependencies by number of
/// versions until actually needed. This ensures we don't do any network
/// requests until we actually need to. In particular, it means that solving
/// a package graph with an already up-to-date lockfile will do no network
/// requests.
class DependencyQueue {
  final BacktrackingSolver _solver;

  /// The dependencies for packages that have already been selected.
  final Queue<PackageDep> _presorted;

  /// The dependencies on the remaining packages.
  ///
  /// This is lazily sorted right before the first item is requested.
  final List<PackageDep> _remaining;

  bool _isSorted = false;

  /// Gets whether there are any dependencies left to iterate over.
  bool get isEmpty => _presorted.isEmpty && _remaining.isEmpty;

  /// The pending [Future] while the remaining dependencies are being sorted.
  ///
  /// This will only be non-null while a sort is in progress.
  Future _sortFuture;

  factory DependencyQueue(BacktrackingSolver solver,
      Iterable<PackageDep> deps) {
    // Separate out the presorted ones.
    var presorted = <PackageDep>[];
    var remaining = <PackageDep>[];

    for (var dep in deps) {
      // Selected or locked packages come first.
      if (solver.getSelected(dep.name) != null ||
          solver.getLocked(dep.name) != null) {
        presorted.add(dep);
      } else {
        remaining.add(dep);
      }
    }

    return new DependencyQueue._(solver, new Queue<PackageDep>.from(presorted),
        remaining);
  }

  DependencyQueue._(this._solver, this._presorted, this._remaining);

  /// Emits the next dependency in priority order.
  ///
  /// It is an error to call this if [isEmpty] returns `true`. Note that this
  /// function is *not* re-entrant. You should only advance after the previous
  /// advance has completed.
  Future<PackageDep> advance() {
    // Emit the sorted ones first.
    if (_presorted.isNotEmpty) {
      return new Future.value(_presorted.removeFirst());
    }

    // Sort the remaining packages when we need the first one.
    if (!_isSorted) return _sort().then((_) => _remaining.removeAt(0));

    return new Future.value(_remaining.removeAt(0));
  }

  /// Sorts the unselected packages by number of versions and name.
  Future _sort() {
    // Sorting is not re-entrant.
    assert(_sortFuture == null);

    _sortFuture = Future.wait(_remaining.map(_getNumVersions)).then((versions) {
      _sortFuture = null;

      // Map deps to the number of versions they have.
      var versionMap = new Map.fromIterables(_remaining, versions);

      // Sort in best-first order to minimize backtracking.
      _remaining.sort((a, b) {
        // Traverse into packages with fewer versions since they will lead to
        // less backtracking.
        if (versionMap[a] != versionMap[b]) {
          return versionMap[a].compareTo(versionMap[b]);
        }

        // Otherwise, just sort by name so that it's deterministic.
        return a.name.compareTo(b.name);
      });

      _isSorted = true;
    });

    return _sortFuture;
  }

  /// Given a dependency, returns a future that completes to the number of
  /// versions available for it.
  Future<int> _getNumVersions(PackageDep dep) {
    // There is only ever one version of the root package.
    if (dep.isRoot) {
      return new Future.value(1);
    }

    return _solver.cache.getVersions(dep.toRef()).then((versions) {
      return versions.length;
    }).catchError((error, trace) {
      // If it fails for any reason, just treat that as no versions. This
      // will sort this reference higher so that we can traverse into it
      // and report the error more properly.
      log.solver("Could not get versions for $dep:\n$error\n\n$trace");
      return 0;
    });
  }
}
