// Copyright (c) 2017, 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:io';

import 'package:io/io.dart';
import 'package:path/path.dart' as p;
import 'package:source_span/source_span.dart';
import 'package:yaml/yaml.dart';

/// User-provided settings for invoking an executable.
class ExecutableSettings {
  /// Additional arguments to pass to the executable.
  final List<String> arguments;

  /// The path to the executable on Linux.
  ///
  /// This may be an absolute path or a basename, in which case it will be
  /// looked up on the system path. It may not be relative.
  final String _linuxExecutable;

  /// The path to the executable on Mac OS.
  ///
  /// This may be an absolute path or a basename, in which case it will be
  /// looked up on the system path. It may not be relative.
  final String _macOSExecutable;

  /// The path to the executable on Windows.
  ///
  /// This may be an absolute path; a basename, in which case it will be looked
  /// up on the system path; or a relative path, in which case it will be looked
  /// up relative to the paths in the `LOCALAPPDATA`, `PROGRAMFILES`, and
  /// `PROGRAMFILES(X64)` environment variables.
  final String _windowsExecutable;

  /// The path to the executable for the current operating system.
  String get executable {
    if (Platform.isMacOS) return _macOSExecutable;
    if (!Platform.isWindows) return _linuxExecutable;
    if (p.isAbsolute(_windowsExecutable)) return _windowsExecutable;
    if (p.basename(_windowsExecutable) == _windowsExecutable) {
      return _windowsExecutable;
    }

    var prefixes = [
      Platform.environment['LOCALAPPDATA'],
      Platform.environment['PROGRAMFILES'],
      Platform.environment['PROGRAMFILES(X86)']
    ];

    for (var prefix in prefixes) {
      if (prefix == null) continue;

      var path = p.join(prefix, _windowsExecutable);
      if (new File(path).existsSync()) return path;
    }

    // If we can't find a path that works, return one that doesn't. This will
    // cause an "executable not found" error to surface.
    return p.join(
        prefixes.firstWhere((prefix) => prefix != null, orElse: () => '.'),
        _windowsExecutable);
  }

  /// Parses settings from a user-provided YAML mapping.
  factory ExecutableSettings.parse(YamlMap settings) {
    List<String> arguments;
    var argumentsNode = settings.nodes["arguments"];
    if (argumentsNode != null) {
      if (argumentsNode.value is String) {
        try {
          arguments = shellSplit(argumentsNode.value);
        } on FormatException catch (error) {
          throw new SourceSpanFormatException(
              error.message, argumentsNode.span);
        }
      } else {
        throw new SourceSpanFormatException(
            "Must be a string.", argumentsNode.span);
      }
    }

    String linuxExecutable;
    String macOSExecutable;
    String windowsExecutable;
    var executableNode = settings.nodes["executable"];
    if (executableNode != null) {
      if (executableNode.value is String) {
        // Don't check this on Windows because people may want to set relative
        // paths in their global config.
        if (!Platform.isWindows) _assertNotRelative(executableNode);

        linuxExecutable = executableNode.value;
        macOSExecutable = executableNode.value;
        windowsExecutable = executableNode.value;
      } else if (executableNode is YamlMap) {
        linuxExecutable = _getExecutable(executableNode.nodes["linux"]);
        macOSExecutable = _getExecutable(executableNode.nodes["mac_os"]);
        windowsExecutable = _getExecutable(executableNode.nodes["windows"],
            allowRelative: true);
      } else {
        throw new SourceSpanFormatException(
            "Must be a map or a string.", executableNode.span);
      }
    }

    return new ExecutableSettings(
        arguments: arguments,
        linuxExecutable: linuxExecutable,
        macOSExecutable: macOSExecutable,
        windowsExecutable: windowsExecutable);
  }

  /// Asserts that [executableNode] is a string or `null` and returns it.
  ///
  /// If [allowRelative] is `false` (the default), asserts that the value isn't
  /// a relative path.
  static String _getExecutable(YamlNode executableNode,
      {bool allowRelative: false}) {
    if (executableNode == null || executableNode.value == null) return null;
    if (executableNode.value is! String) {
      throw new SourceSpanFormatException(
          "Must be a string.", executableNode.span);
    }
    if (!allowRelative) _assertNotRelative(executableNode);
    return executableNode.value;
  }

  /// Throws a [SourceSpanFormatException] if [executableNode]'s value is a
  /// relative POSIX path that's not just a plain basename.
  ///
  /// We loop up basenames on the PATH and we can resolve absolute paths, but we
  /// have no way of interpreting relative paths.
  static void _assertNotRelative(YamlScalar executableNode) {
    var executable = executableNode.value as String;
    if (!p.posix.isRelative(executable)) return;
    if (p.posix.basename(executable) == executable) return;

    throw new SourceSpanFormatException(
        "Linux and Mac OS executables may not be relative paths.",
        executableNode.span);
  }

  ExecutableSettings(
      {Iterable<String> arguments,
      String linuxExecutable,
      String macOSExecutable,
      String windowsExecutable})
      : arguments =
            arguments == null ? const [] : new List.unmodifiable(arguments),
        _linuxExecutable = linuxExecutable,
        _macOSExecutable = macOSExecutable,
        _windowsExecutable = windowsExecutable;

  /// Merges [this] with [other], with [other]'s settings taking priority.
  ExecutableSettings merge(ExecutableSettings other) => new ExecutableSettings(
      arguments: arguments.toList()..addAll(other.arguments),
      linuxExecutable: other._linuxExecutable ?? _linuxExecutable,
      macOSExecutable: other._macOSExecutable ?? _macOSExecutable,
      windowsExecutable: other._windowsExecutable ?? _windowsExecutable);
}
