// Copyright (c) 2015, 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.

/// A programmatic API for reflecting on Pub's cache directory.
library pub_cache;

import 'dart:io';

import 'package:path/path.dart' as path;
import 'package:pub_semver/pub_semver.dart';
import 'package:yaml/yaml.dart' as yaml;

import 'src/impl.dart';

/// A programmatic API for reflecting on Pub's cache directory.
class PubCache {
  /// Return the location of Pub's package cache.
  static Directory getSystemCacheLocation() {
    Map env = Platform.environment;

    if (env.containsKey('PUB_CACHE')) {
      return new Directory(env['PUB_CACHE']);
    } else if (Platform.operatingSystem == 'windows') {
      return new Directory(path.join(env['APPDATA'], 'Pub', 'Cache'));
    } else {
      return new Directory('${env['HOME']}/.pub-cache');
    }
  }

  // The location of the pub cache.
  final Directory location;

  List<Application> _applications;
  List<PackageRef> _packageRefs;

  /// Create a pubcache instance. [dir] defaults to the default platform pub
  /// cache location.
  PubCache([Directory dir]) :
      location = dir == null ? getSystemCacheLocation() : dir {
    _parse();
  }

  /// Return the contents of `bin/` - the scripts for the activated applications.
  List<File> getBinScripts() {
    Directory dir = _getSubDir(location, 'bin');
    return dir.existsSync() ? dir.listSync() : [];
  }

  /// Return applications that have been installed via `pub global activate`.
  List<Application> getGlobalApplications() => _applications;

  /// Get all the packages and their versions that have been installed into the
  /// cache.
  List<PackageRef> getPackageRefs() => _packageRefs;

  /// Return the list of package names (not versions) that are available in the
  /// cache.
  List<String> getCachedPackages() =>
      new Set.from(getPackageRefs().map((p) => p.name)).toList();

  /// Return all available cached versions for a given package.
  List<PackageRef> getAllPackageVersions(String packageName) =>
      getPackageRefs().where((p) => p.name == packageName).toList();

  /// Return the most recent verison of the given package contained in the
  /// cache. This method will prefer to return only release verions. If
  /// [includePreRelease] is true, then the very latest verision will be
  /// returned, include pre-release versions.
  PackageRef getLatestVersion(String packageName, {bool includePreRelease: false}) {
    List<PackageRef> refs = getAllPackageVersions(packageName);

    if (refs.isEmpty) return null;
    if (refs.length == 1) return refs.first;

    PackageRef latest = refs.first;

    if (includePreRelease) {
      for (int i = 1; i < refs.length; i++) {
        if (refs[i].version > latest.version) latest = refs[i];
      }
    } else {
      List<Version> versions = refs.map((ref) => ref.version).toList();
      Version latestVersion = Version.primary(versions);
      for (PackageRef ref in refs) {
        if (ref.version == latestVersion) latest = ref;
      }
    }

    return latest;
  }

  void _parse() {
    // Read the activated applications.
    _applications = [];

    Directory globalPackagesDir = _getSubDir(location, 'global_packages');
    if (globalPackagesDir.existsSync()) {
      _applications = globalPackagesDir
          .listSync()
          .where((item) => item is Directory)
          .map((dir) => new Application._(this, dir))
          .toList();
    }

    // Scan hosted packages - just pub.dartlang.org for now.
    _packageRefs = [];

    Directory dartlangDir = new Directory(
        path.join(location.path, 'hosted', 'pub.dartlang.org'));
    if (dartlangDir.existsSync()) {
      _packageRefs = dartlangDir.listSync()
          .where((dir) => dir is Directory)
          .map((dir) => new DirectoryPackageRef('hosted', dir))
          .toList();
    }

    // Scan for git packages (ignore the git/cache directory).
    // ace-a1a140cc933e7d44d2955a6d6033308754bb9235
    Directory gitDir = new Directory(path.join(location.path, 'git'));
    if (gitDir.existsSync()) {
      Iterable gitRefs = gitDir.listSync()
          .where((dir) => dir is Directory && path.basename(dir.path) != 'cache')
          .map((dir) => new GitDirectoryPackageRef(dir));
      _packageRefs.addAll(gitRefs);
    }
  }

  Directory _getSubDir(Directory dir, String name) =>
      new Directory(path.join(dir.path, name));
}

/// A Dart application; a package with an entry-point, available via `pub global
/// activate`.
class Application {
  final PubCache _cache;
  final Directory _dir;

  List<PackageRef> _packageRefs;

  Application._(this._cache, this._dir);

  /// The name of the defining package.
  String get name => path.basename(_dir.path);

  /// The version of the application and of the defining package.
  Version get version {
    PackageRef ref = getDefiningPackageRef();
    return ref == null ? Version.none : ref.version;
  }

  /// Return the reference to the defining package. This is the package that
  /// defines the application.
  PackageRef getDefiningPackageRef() {
    for (PackageRef ref in getPackageRefs()) {
      if (ref.name == name) return ref;
    }
    return null;
  }

  /// Return all the package references for the application. This includes the
  /// defining package as well as the direct and transitive dependencies.
  List<PackageRef> getPackageRefs() {
    if (_packageRefs == null) _parsePubspecLock();
    return _packageRefs;
  }

  String toString() => '${name} ${version}';

  void _parsePubspecLock() {
    File pubspecLock = new File(path.join(_dir.path, 'pubspec.lock'));
    Map doc = yaml.loadYaml(pubspecLock.readAsStringSync());
    Map packages = doc['packages'];
    _packageRefs = packages.keys.map((key) {
      Map m = packages[key];
      String source = m['source'];
      if (source == 'git') {
        return new PackageRefImpl.git(key, m['version'], m['description'], (curRef) {
          for (PackageRef ref in _cache.getPackageRefs()) {
            if (ref == curRef) return ref.resolve();
          }
          return null;
        });
      } else if (source == 'hosted') {
        return new PackageRefImpl.hosted(key, m['version'], (curRef) {
          for (PackageRef ref in _cache.getPackageRefs()) {
            if (ref == curRef) return ref.resolve();
          }
          return null;
        });
      } else if (source == 'path') {
        return new PackageRefImpl.path(key, m['version'], m['description']);
      } else {
        return new PackageRefImpl(source, key, m['version']);
      }
    }).toList();
  }
}

/// A package reference, including the package name and version. This package
/// reference can be resolved to the actual package on disk.
abstract class PackageRef {
  /// The type of the package reference. Valid types include `hosted` and `git`.
  String get sourceType;
  /// The name of the package.
  String get name;
  /// The version of the package.
  Version get version;

  /// Resolve the package reference into the actual package, including the
  /// location on disk.
  Package resolve();

  bool operator ==(other) {
    return this.sourceType == other.sourceType
        && this.name == other.name
        && this.version == other.version;
  }

  String toString() => '${name} ${version}';
}

/// A representation of a package, including the name, version, and location on
/// disk.
class Package {
  final Directory location;
  final String name;
  final Version version;

  Package(this.location, this.name, this.version);

  String toString() => '${name} ${version}';
}
