// Copyright (c) 2016, 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:analyzer/src/generated/source.dart' show Source;
import 'package:analyzer/src/summary/package_bundle_reader.dart'
    show InSummarySource;
import 'package:args/args.dart' show ArgParser, ArgResults;
import 'package:args/command_runner.dart' show UsageException;
import 'package:path/path.dart' as path;

import '../analyzer/context.dart' show AnalyzerOptions, parseDeclaredVariables;
import 'compiler.dart' show BuildUnit, CompilerOptions, ModuleCompiler;
import 'module_builder.dart';

final ArgParser _argParser = () {
  var argParser = new ArgParser(allowTrailingOptions: true)
    ..addFlag('help', abbr: 'h', help: 'Display this message.')
    ..addOption('out',
        abbr: 'o', allowMultiple: true, help: 'Output file (required).')
    ..addOption('module-root',
        help: 'Root module directory.\n'
            'Generated module paths are relative to this root.')
    ..addOption('library-root',
        help: 'Root of source files.\n'
            'Generated library names are relative to this root.')
    ..addOption('build-root',
        help: 'Deprecated in favor of --library-root', hide: true);
  addModuleFormatOptions(argParser, allowMultiple: true);
  AnalyzerOptions.addArguments(argParser);
  CompilerOptions.addArguments(argParser);
  return argParser;
}();

/// Runs a single compile for dartdevc.
///
/// This handles argument parsing, usage, error handling.
/// See bin/dartdevc.dart for the actual entry point, which includes Bazel
/// worker support.
int compile(List<String> args, {void printFn(Object obj)}) {
  printFn ??= print;
  ArgResults argResults;
  var declaredVars = <String, String>{};
  try {
    argResults = _argParser.parse(parseDeclaredVariables(args, declaredVars));
  } on FormatException catch (error) {
    printFn('$error\n\n$_usageMessage');
    return 64;
  }
  try {
    _compile(argResults, declaredVars, printFn);
    return 0;
  } on UsageException catch (error) {
    // Incorrect usage, input file not found, etc.
    printFn(error);
    return 64;
  } on CompileErrorException catch (error) {
    // Code has error(s) and failed to compile.
    printFn(error);
    return 1;
  } catch (error, stackTrace) {
    // Anything else is likely a compiler bug.
    //
    // --unsafe-force-compile is a bit of a grey area, but it's nice not to
    // crash while compiling
    // (of course, output code may crash, if it had errors).
    //
    printFn('''
We're sorry, you've found a bug in our compiler.
You can report this bug at:
    https://github.com/dart-lang/sdk/issues/labels/area-dev-compiler
Please include the information below in your report, along with
any other information that may help us track it down. Thanks!
    dartdevc arguments: ${args.join(' ')}
    dart --version: ${Platform.version}
```
$error
$stackTrace
```''');
    return 70;
  }
}

bool _changed(List<int> list1, List<int> list2) {
  var length = list1.length;
  if (length != list2.length) return true;
  for (var i = 0; i < length; ++i) {
    if (list1[i] != list2[i]) return true;
  }
  return false;
}

void _compile(ArgResults argResults, Map<String, String> declaredVars,
    void printFn(Object obj)) {
  if (argResults['help']) {
    printFn(_usageMessage);
    return;
  }
  var compiler = new ModuleCompiler(
      new AnalyzerOptions.fromArguments(argResults, declaredVars));
  var compilerOpts = new CompilerOptions.fromArguments(argResults);
  var outPaths = argResults['out'] as List<String>;
  var moduleFormats = parseModuleFormatOption(argResults);
  bool singleOutFile = argResults['single-out-file'];
  if (singleOutFile) {
    for (var format in moduleFormats) {
      if (format != ModuleFormat.amd && format != ModuleFormat.legacy) {
        _usageException('Format $format cannot be combined with '
            'single-out-file. Only amd and legacy modes are supported.');
      }
    }
  }

  if (outPaths.isEmpty) {
    _usageException('Please include the output file location. For example:\n'
        '    -o PATH/TO/OUTPUT_FILE.js');
  } else if (outPaths.length != moduleFormats.length) {
    _usageException('Number of output files (${outPaths.length}) must match '
        'number of module formats (${moduleFormats.length}).');
  }

  // TODO(jmesserly): for now the first one is special. This will go away once
  // we've removed the "root" and "module name" variables.
  var firstOutPath = outPaths[0];

  var libraryRoot = argResults['library-root'] as String;
  libraryRoot ??= argResults['build-root'] as String;
  if (libraryRoot != null) {
    libraryRoot = path.absolute(libraryRoot);
  } else {
    libraryRoot = Directory.current.path;
  }
  var moduleRoot = argResults['module-root'] as String;
  String modulePath;
  if (moduleRoot != null) {
    moduleRoot = path.absolute(moduleRoot);
    if (!path.isWithin(moduleRoot, firstOutPath)) {
      _usageException('Output file $firstOutPath must be within the module '
          'root directory $moduleRoot');
    }
    modulePath =
        path.withoutExtension(path.relative(firstOutPath, from: moduleRoot));
  } else {
    moduleRoot = path.dirname(firstOutPath);
    modulePath = path.basenameWithoutExtension(firstOutPath);
  }

  var unit = new BuildUnit(modulePath, libraryRoot, argResults.rest,
      (source) => _moduleForLibrary(moduleRoot, source, compilerOpts));

  var module = compiler.compile(unit, compilerOpts);
  module.errors.forEach(printFn);

  if (!module.isValid) throw new CompileErrorException();

  // Write JS file, as well as source map and summary (if requested).
  for (var i = 0; i < outPaths.length; i++) {
    module.writeCodeSync(moduleFormats[i], outPaths[i],
        singleOutFile: singleOutFile);
  }
  if (module.summaryBytes != null) {
    var summaryPaths = compilerOpts.summaryOutPath != null
        ? [compilerOpts.summaryOutPath]
        : outPaths.map((p) =>
            '${path.withoutExtension(p)}.${compilerOpts.summaryExtension}');

    // place next to every compiled module
    for (var summaryPath in summaryPaths) {
      // Only overwrite if summary changed.  This plays better with timestamp
      // based build systems.
      var file = new File(summaryPath);
      if (!file.existsSync() ||
          _changed(file.readAsBytesSync(), module.summaryBytes)) {
        if (!file.parent.existsSync()) file.parent.createSync(recursive: true);
        file.writeAsBytesSync(module.summaryBytes);
      }
    }
  }
}

String _moduleForLibrary(
    String moduleRoot, Source source, CompilerOptions compilerOpts) {
  if (source is InSummarySource) {
    var summaryPath = source.summaryPath;
    var ext = '.${compilerOpts.summaryExtension}';
    if (path.isWithin(moduleRoot, summaryPath) && summaryPath.endsWith(ext)) {
      var buildUnitPath =
          summaryPath.substring(0, summaryPath.length - ext.length);
      return path.relative(buildUnitPath, from: moduleRoot);
    }

    _usageException('Imported file ${source.uri} is not within the module root '
        'directory $moduleRoot');
  }

  _usageException(
      'Imported file "${source.uri}" was not found as a summary or source '
      'file. Please pass in either the summary or the source file '
      'for this import.');
  return null; // unreachable
}

final _usageMessage =
    'Dart Development Compiler compiles Dart into a JavaScript module.'
    '\n\n${_argParser.usage}';

void _usageException(String message) {
  throw new UsageException(message, _usageMessage);
}

/// Thrown when the input source code has errors.
class CompileErrorException implements Exception {
  toString() => '\nPlease fix all errors before compiling (warnings are okay).';
}
