// Copyright (c) 2014, 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 dart_style.src.formatter_options;

import 'dart:convert';
import 'dart:io';

import 'source_code.dart';

/// Global options that affect how the formatter produces and uses its outputs.
class FormatterOptions {
  /// The [OutputReporter] used to show the formatting results.
  final OutputReporter reporter;

  /// The number of spaces of indentation to prefix the output with.
  final int indent;

  /// The number of columns that formatted output should be constrained to fit
  /// within.
  final int pageWidth;

  /// Whether symlinks should be traversed when formatting a directory.
  final bool followLinks;

  FormatterOptions(this.reporter,
      {this.indent: 0, this.pageWidth: 80, this.followLinks: false});
}

/// How the formatter reports the results it produces.
abstract class OutputReporter {
  /// Prints only the names of files whose contents are different from their
  /// formatted version.
  static final dryRun = new _DryRunReporter();

  /// Prints the formatted results of each file to stdout.
  static final print = new _PrintReporter();

  /// Prints the formatted result and selection info of each file to stdout as
  /// a JSON map.
  static final printJson = new _PrintJsonReporter();

  /// Overwrites each file with its formatted result.
  static final overwrite = new _OverwriteReporter();

  /// Describe the directory whose contents are about to be processed.
  void showDirectory(String path) {}

  /// Describe the symlink at [path] that wasn't followed.
  void showSkippedLink(String path) {}

  /// Describe the hidden [path] that wasn't processed.
  void showHiddenPath(String path) {}

  /// Called when [file] is about to be formatted.
  void beforeFile(File file, String label) {}

  /// Describe the processed file at [path] whose formatted result is [output].
  ///
  /// If the contents of the file are the same as the formatted output,
  /// [changed] will be false.
  void afterFile(File file, String label, SourceCode output, {bool changed});
}

/// Prints only the names of files whose contents are different from their
/// formatted version.
class _DryRunReporter extends OutputReporter {
  void afterFile(File file, String label, SourceCode output, {bool changed}) {
    // Only show the changed files.
    if (changed) print(label);
  }
}

/// Prints the formatted results of each file to stdout.
class _PrintReporter extends OutputReporter {
  void showDirectory(String path) {
    print("Formatting directory $path:");
  }

  void showSkippedLink(String path) {
    print("Skipping link $path");
  }

  void showHiddenPath(String path) {
    print("Skipping hidden path $path");
  }

  void afterFile(File file, String label, SourceCode output, {bool changed}) {
    // Don't add an extra newline.
    stdout.write(output.text);
  }
}

/// Prints the formatted result and selection info of each file to stdout as a
/// JSON map.
class _PrintJsonReporter extends OutputReporter {
  void afterFile(File file, String label, SourceCode output, {bool changed}) {
    // TODO(rnystrom): Put an empty selection in here to remain compatible with
    // the old formatter. Since there's no way to pass a selection on the
    // command line, this will never be used, which is why it's hard-coded to
    // -1, -1. If we add support for passing in a selection, put the real
    // result here.
    print(JSON.encode({
      "path": label,
      "source": output.text,
      "selection": {
        "offset": output.selectionStart != null ? output.selectionStart : -1,
        "length": output.selectionLength != null ? output.selectionLength : -1
      }
    }));
  }
}

/// Overwrites each file with its formatted result.
class _OverwriteReporter extends _PrintReporter {
  void afterFile(File file, String label, SourceCode output, {bool changed}) {
    if (changed) {
      file.writeAsStringSync(output.text);
      print("Formatted $label");
    } else {
      print("Unchanged $label");
    }
  }
}

/// A decorating reporter that reports how long it took for format each file.
class ProfileReporter implements OutputReporter {
  final OutputReporter _inner;

  /// The files that have been started but have not completed yet.
  ///
  /// Maps a file label to the time that it started being formatted.
  final Map<String, DateTime> _ongoing = {};

  /// The elapsed time it took to format each completed file.
  final Map<String, Duration> _elapsed = {};

  /// The number of files that completed so fast that they aren't worth
  /// tracking.
  int _elided = 0;

  ProfileReporter(this._inner);

  /// Show the times for the slowest files to format.
  void showProfile() {
    // Everything should be done.
    assert(_ongoing.isEmpty);

    var files = _elapsed.keys.toList();
    files.sort((a, b) => _elapsed[b].compareTo(_elapsed[a]));

    for (var file in files) {
      print("${_elapsed[file]}: $file");
    }

    if (_elided >= 1) {
      var s = _elided > 1 ? 's' : '';
      print("...$_elided more file$s each took less than 10ms.");
    }
  }

  /// Describe the directory whose contents are about to be processed.
  void showDirectory(String path) {
    _inner.showDirectory(path);
  }

  /// Describe the symlink at [path] that wasn't followed.
  void showSkippedLink(String path) {
    _inner.showSkippedLink(path);
  }

  /// Describe the hidden [path] that wasn't processed.
  void showHiddenPath(String path) {
    _inner.showHiddenPath(path);
  }

  /// Called when [file] is about to be formatted.
  void beforeFile(File file, String label) {
    _inner.beforeFile(file, label);

    _ongoing[label] = new DateTime.now();
  }

  /// Describe the processed file at [path] whose formatted result is [output].
  ///
  /// If the contents of the file are the same as the formatted output,
  /// [changed] will be false.
  void afterFile(File file, String label, SourceCode output, {bool changed}) {
    var elapsed = new DateTime.now().difference(_ongoing.remove(label));
    if (elapsed.inMilliseconds >= 10) {
      _elapsed[label] = elapsed;
    } else {
      _elided++;
    }

    _inner.afterFile(file, label, output, changed: changed);
  }
}
