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

import 'dart:io';

import 'package:pub_semver/pub_semver.dart';

import '../short/style_fix.dart';
import '../source_code.dart';
import 'output.dart';
import 'show.dart';
import 'summary.dart';

// Note: The following line of code is modified by tool/grind.dart.
const dartStyleVersion = '2.3.7';

/// Global options that affect how the formatter produces and uses its outputs.
class FormatterOptions {
  /// The language version formatted code should be parsed at or `null` if not
  /// specified.
  final Version? languageVersion;

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

  /// The style fixes to apply while formatting.
  final List<StyleFix> fixes;

  /// Which affected files should be shown.
  final Show show;

  /// Where formatted code should be output.
  final Output output;

  final Summary summary;

  /// Sets the exit code to 1 if any changes are made.
  final bool setExitIfChanged;

  /// Flags to enable experimental language features.
  ///
  /// See dart.dev/go/experiments for details.
  final List<String> experimentFlags;

  FormatterOptions(
      {this.languageVersion,
      this.indent = 0,
      this.pageWidth = 80,
      this.followLinks = false,
      Iterable<StyleFix>? fixes,
      this.show = Show.changed,
      this.output = Output.write,
      this.summary = Summary.none,
      this.setExitIfChanged = false,
      List<String>? experimentFlags})
      : fixes = [...?fixes],
        experimentFlags = [...?experimentFlags];

  /// Called when [file] is about to be formatted.
  ///
  /// If stdin is being formatted, then [file] is `null`.
  void beforeFile(File? file, String label) {
    summary.beforeFile(file, label);
  }

  /// Describe the processed file at [path] with formatted [result]s.
  ///
  /// If the contents of the file are the same as the formatted output,
  /// [changed] will be false.
  ///
  /// If stdin is being formatted, then [file] is `null`.
  void afterFile(File? file, String displayPath, SourceCode result,
      {required bool changed}) {
    summary.afterFile(this, file, displayPath, result, changed: changed);

    // Save the results to disc.
    var overwritten = false;
    if (changed) {
      overwritten = output.writeFile(file, displayPath, result);
    }

    // Show the user.
    if (show.file(displayPath, changed: changed, overwritten: overwritten)) {
      output.showFile(displayPath, result);
    }

    // Set the exit code.
    if (setExitIfChanged && changed) exitCode = 1;
  }

  /// Describes the directory whose contents are about to be processed.
  void showDirectory(String path) {
    if (output != Output.json) {
      show.directory(path);
    }
  }

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

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