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

import 'package:args/args.dart';
import 'package:args/command_runner.dart';

import 'entrypoint.dart';
import 'log.dart' as log;
import 'global_packages.dart';
import 'system_cache.dart';

/// The base class for commands for the pub executable.
///
/// A command may either be a "leaf" command or it may be a parent for a set
/// of subcommands. Only leaf commands are ever actually invoked. If a command
/// has subcommands, then one of those must always be chosen.
abstract class PubCommand extends Command {
  SystemCache get cache {
    if (_cache == null) _cache = new SystemCache(isOffline: isOffline);
    return _cache;
  }

  SystemCache _cache;

  GlobalPackages get globals {
    if (_globals == null) {
      _globals = new GlobalPackages(cache);
    }
    return _globals;
  }

  GlobalPackages _globals;

  /// Gets the [Entrypoint] package for the current working directory.
  ///
  /// This will load the pubspec and fail with an error if the current directory
  /// is not a package.
  Entrypoint get entrypoint {
    // Lazy load it.
    if (_entrypoint == null) {
      _entrypoint = new Entrypoint('.', cache);
    }
    return _entrypoint;
  }

  Entrypoint _entrypoint;

  /// The URL for web documentation for this command.
  String get docUrl => null;

  /// Override this and return `false` to disallow trailing options from being
  /// parsed after a non-option argument is parsed.
  bool get allowTrailingOptions => true;

  ArgParser get argParser {
    // Lazily initialize the parser because the superclass constructor requires
    // it but we want to initialize it based on [allowTrailingOptions].
    if (_argParser == null) {
      _argParser = new ArgParser(allowTrailingOptions: allowTrailingOptions);
    }
    return _argParser;
  }

  ArgParser _argParser;

  /// Override this to use offline-only sources instead of hitting the network.
  ///
  /// This will only be called before the [SystemCache] is created. After that,
  /// it has no effect. This only needs to be set in leaf commands.
  bool get isOffline => false;

  String get usageFooter {
    if (docUrl == null) return null;
    return "See $docUrl for detailed documentation.";
  }

  void printUsage() {
    log.message(usage);
  }

  /// Parses a user-supplied integer [intString] named [name].
  ///
  /// If the parsing fails, prints a usage message and exits.
  int parseInt(String intString, String name) {
    try {
      return int.parse(intString);
    } on FormatException catch (_) {
      usageException('Could not parse $name "$intString".');
      return null;
    }
  }
}