// Copyright (c) 2012, 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 hosted_source;

import 'dart:async';
import 'dart:io' as io;
import 'dart:json' as json;
import 'dart:uri';

// TODO(nweiz): Make this import better.
import '../../pkg/http/lib/http.dart' as http;
import '../../pkg/pathos/lib/path.dart' as path;

import 'http.dart';
import 'io.dart';
import 'log.dart' as log;
import 'package.dart';
import 'pubspec.dart';
import 'source.dart';
import 'source_registry.dart';
import 'utils.dart';
import 'version.dart';

/// A package source that installs packages from a package hosting site that
/// uses the same API as pub.dartlang.org.
class HostedSource extends Source {
  final name = "hosted";
  final shouldCache = true;

  /// Downloads a list of all versions of a package that are available from the
  /// site.
  Future<List<Version>> getVersions(String name, description) {
    var url = _makeUrl(description,
        (server, package) => "$server/packages/$package.json");

    log.io("Get versions from $url.");
    return httpClient.read(url).then((body) {
      var doc = json.parse(body);
      return doc['versions']
          .map((version) => new Version.parse(version))
          .toList();
    }).catchError((ex) {
      var parsed = _parseDescription(description);
      _throwFriendlyError(ex, parsed.first, parsed.last);
    });
  }

  /// Downloads and parses the pubspec for a specific version of a package that
  /// is available from the site.
  Future<Pubspec> describe(PackageId id) {
    var url = _makeVersionUrl(id, (server, package, version) =>
        "$server/packages/$package/versions/$version.yaml");

    log.io("Describe package at $url.");
    return httpClient.read(url).then((yaml) {
      return new Pubspec.parse(null, yaml, systemCache.sources);
    }).catchError((ex) {
      var parsed = _parseDescription(id.description);
      _throwFriendlyError(ex, id, parsed.last);
    });
  }

  /// Downloads a package from the site and unpacks it.
  Future<bool> install(PackageId id, String destPath) {
    return defer(() {
      var url = _makeVersionUrl(id, (server, package, version) =>
          "$server/packages/$package/versions/$version.tar.gz");
      log.io("Install package from $url.");

      log.message('Downloading $id...');

      // Download and extract the archive to a temp directory.
      var tempDir = systemCache.createTempDir();
      return httpClient.send(new http.Request("GET", url))
          .then((response) => response.stream)
          .then((stream) {
        return timeout(extractTarGz(stream, tempDir), HTTP_TIMEOUT,
            'fetching URL "$url"');
      }).then((_) {
        // Now that the install has succeeded, move it to the real location in
        // the cache. This ensures that we don't leave half-busted ghost
        // directories in the user's pub cache if an install fails.
        renameDir(tempDir, destPath);
        return true;
      });
    });
  }

  /// The system cache directory for the hosted source contains subdirectories
  /// for each separate repository URL that's used on the system. Each of these
  /// subdirectories then contains a subdirectory for each package installed
  /// from that site.
  Future<String> systemCacheDirectory(PackageId id) {
    var parsed = _parseDescription(id.description);
    var url = _getSourceDirectory(parsed.last);
    var urlDir = replace(url, new RegExp(r'[<>:"\\/|?*%]'), (match) {
      return '%${match[0].codeUnitAt(0)}';
    });

    return new Future.immediate(
        path.join(systemCacheRoot, urlDir, "${parsed.first}-${id.version}"));
  }

  String packageName(description) => _parseDescription(description).first;

  bool descriptionsEqual(description1, description2) =>
      _parseDescription(description1) == _parseDescription(description2);

  /// Ensures that [description] is a valid hosted package description.
  ///
  /// There are two valid formats. A plain string refers to a package with the
  /// given name from the default host, while a map with keys "name" and "url"
  /// refers to a package with the given name from the host at the given URL.
  dynamic parseDescription(String containingPath, description,
                           {bool fromLockFile: false}) {
    _parseDescription(description);
    return description;
  }

  Future<List<Package>> getCachedPackages() {
    return defer(() {
      var cacheDir = path.join(systemCacheRoot, 
                               _getSourceDirectory(_defaultUrl)); 
      if (!dirExists(cacheDir)) return [];
    
      return listDir(path.join(cacheDir)).then((entries) {
        return entries.map((entry) => 
          new Package.load(null, entry, systemCache.sources));
      });  
    });
  }
  
  /// When an error occurs trying to read something about [package] from [url],
  /// this tries to translate into a more user friendly error message. Always
  /// throws an error, either the original one or a better one.
  void _throwFriendlyError(AsyncError asyncError, package, url) {
    if (asyncError.error is PubHttpException &&
        asyncError.error.response.statusCode == 404) {
      throw 'Could not find package "$package" at $url.';
    }

    if (asyncError.error is TimeoutException) {
      throw 'Timed out trying to find package "$package" at $url.';
    }

    if (asyncError.error is io.SocketIOException) {
      throw 'Got socket error trying to find package "$package" at $url.\n'
          '${asyncError.error.osError}';
    }

    // Otherwise re-throw the original exception.
    throw asyncError;
  }

}

/// The URL of the default package repository.
final _defaultUrl = "https://pub.dartlang.org";

String _getSourceDirectory(String url) {
  return url.replaceAll(new RegExp(r"^https?://"), "");
}

/// Parses [description] into its server and package name components, then
/// converts that to a Uri given [pattern]. Ensures the package name is
/// properly URL encoded.
Uri _makeUrl(description, String pattern(String server, String package)) {
  var parsed = _parseDescription(description);
  var server = parsed.last;
  var package = encodeUriComponent(parsed.first);
  return new Uri(pattern(server, package));
}

/// Parses [id] into its server, package name, and version components, then
/// converts that to a Uri given [pattern]. Ensures the package name is
/// properly URL encoded.
Uri _makeVersionUrl(PackageId id,
    String pattern(String server, String package, String version)) {
  var parsed = _parseDescription(id.description);
  var server = parsed.last;
  var package = encodeUriComponent(parsed.first);
  var version = encodeUriComponent(id.version.toString());
  return new Uri(pattern(server, package, version));
}

/// Parses the description for a package.
///
/// If the package parses correctly, this returns a (name, url) pair. If not,
/// this throws a descriptive FormatException.
Pair<String, String> _parseDescription(description) {
  if (description is String) {
    return new Pair<String, String>(description, _defaultUrl);
  }

  if (description is! Map) {
    throw new FormatException(
        "The description must be a package name or map.");
  }

  if (!description.containsKey("name")) {
    throw new FormatException(
    "The description map must contain a 'name' key.");
  }

  var name = description["name"];
  if (name is! String) {
    throw new FormatException("The 'name' key must have a string value.");
  }

  var url = description.containsKey("url") ? description["url"] : _defaultUrl;
  return new Pair<String, String>(name, url);
}
