// Copyright (c) 2015, 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 analyzer.src.task.options;

import 'dart:collection';

import 'package:analyzer/analyzer.dart';
import 'package:analyzer/plugin/options.dart';
import 'package:analyzer/source/analysis_options_provider.dart';
import 'package:analyzer/source/error_processor.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_general.dart';
import 'package:analyzer/src/task/general.dart';
import 'package:analyzer/src/task/strong/info.dart';
import 'package:analyzer/task/general.dart';
import 'package:analyzer/task/model.dart';
import 'package:source_span/source_span.dart';
import 'package:yaml/yaml.dart';

/// The errors produced while parsing `.analysis_options` files.
///
/// The list will be empty if there were no errors, but will not be `null`.
final ListResultDescriptor<AnalysisError> ANALYSIS_OPTIONS_ERRORS =
    new ListResultDescriptor<AnalysisError>(
        'ANALYSIS_OPTIONS_ERRORS', AnalysisError.NO_ERRORS);

final _OptionsProcessor _processor = new _OptionsProcessor();

void applyToAnalysisOptions(
    AnalysisOptionsImpl options, Map<String, Object> optionMap) {
  _processor.applyToAnalysisOptions(options, optionMap);
}

/// Configure this [context] based on configuration details specified in
/// the given [options].  If [options] is `null`, default values are applied.
void configureContextOptions(
        AnalysisContext context, Map<String, Object> options) =>
    _processor.configure(context, options);

/// `analyzer` analysis options constants.
class AnalyzerOptions {
  static const String analyzer = 'analyzer';
  static const String enableAsync = 'enableAsync';
  static const String enableGenericMethods = 'enableGenericMethods';
  static const String enableSuperMixins = 'enableSuperMixins';
  static const String enableConditionalDirectives =
      "enableConditionalDirectives";
  static const String errors = 'errors';
  static const String exclude = 'exclude';
  static const String language = 'language';
  static const String plugins = 'plugins';
  static const String strong_mode = 'strong-mode';

  /// Ways to say `ignore`.
  static const List<String> ignoreSynonyms = const ['ignore', 'false'];

  /// Valid error `severity`s.
  static final List<String> severities =
      new List.unmodifiable(severityMap.keys);

  /// Ways to say `include`.
  static const List<String> includeSynonyms = const ['include', 'true'];

  /// Ways to say `true` or `false`.
  static const List<String> trueOrFalse = const ['true', 'false'];

  /// Supported top-level `analyzer` options.
  static const List<String> topLevel = const [
    errors,
    exclude,
    language,
    plugins,
    strong_mode
  ];

  /// Supported `analyzer` language configuration options.
  static const List<String> languageOptions = const [
    enableAsync,
    enableGenericMethods,
    enableSuperMixins,
    enableConditionalDirectives,
  ];
}

/// Validates `analyzer` options.
class AnalyzerOptionsValidator extends CompositeValidator {
  AnalyzerOptionsValidator()
      : super([
          new TopLevelAnalyzerOptionsValidator(),
          new StrongModeOptionValueValidator(),
          new ErrorFilterOptionValidator(),
          new LanguageOptionValidator()
        ]);
}

/// Convenience class for composing validators.
class CompositeValidator extends OptionsValidator {
  final List<OptionsValidator> validators;
  CompositeValidator(this.validators);

  @override
  void validate(ErrorReporter reporter, Map<String, YamlNode> options) =>
      validators.forEach((v) => v.validate(reporter, options));
}

/// Builds error reports with value proposals.
class ErrorBuilder {
  String proposal;
  AnalysisOptionsWarningCode code;

  /// Create a builder for the given [supportedOptions].
  ErrorBuilder(List<String> supportedOptions) {
    assert(supportedOptions != null && !supportedOptions.isEmpty);
    if (supportedOptions.length > 1) {
      proposal = StringUtilities.printListOfQuotedNames(supportedOptions);
      code = pluralProposalCode;
    } else {
      proposal = "'${supportedOptions.join()}'";
      code = singularProposalCode;
    }
  }
  AnalysisOptionsWarningCode get pluralProposalCode =>
      AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUES;

  AnalysisOptionsWarningCode get singularProposalCode =>
      AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUE;

  /// Report an unsupported [node] value, defined in the given [scopeName].
  void reportError(ErrorReporter reporter, String scopeName, YamlNode node) {
    reporter
        .reportErrorForSpan(code, node.span, [scopeName, node.value, proposal]);
  }
}

/// Validates `analyzer` error filter options.
class ErrorFilterOptionValidator extends OptionsValidator {
  /// Legal values.
  static final List<String> legalValues =
      new List.from(AnalyzerOptions.ignoreSynonyms)
        ..addAll(AnalyzerOptions.includeSynonyms)
        ..addAll(AnalyzerOptions.severities);

  /// Pretty String listing legal values.
  static final String legalValueString =
      StringUtilities.printListOfQuotedNames(legalValues);

  /// Lazily populated set of error codes (hashed for speedy lookup).
  static HashSet<String> _errorCodes;

  /// Legal error code names.
  static Set<String> get errorCodes {
    if (_errorCodes == null) {
      _errorCodes = new HashSet<String>();
      // Engine codes.
      _errorCodes.addAll(ErrorCode.values.map((ErrorCode code) => code.name));
      // Strong-mode codes.
      _errorCodes.addAll(StaticInfo.names);
    }
    return _errorCodes;
  }

  @override
  void validate(ErrorReporter reporter, Map<String, YamlNode> options) {
    var analyzer = options[AnalyzerOptions.analyzer];
    if (analyzer is! YamlMap) {
      return;
    }

    var filters = analyzer[AnalyzerOptions.errors];
    if (filters is YamlMap) {
      String value;
      filters.nodes.forEach((k, v) {
        if (k is YamlScalar) {
          value = toUpperCase(k.value);
          if (!errorCodes.contains(value)) {
            reporter.reportErrorForSpan(
                AnalysisOptionsWarningCode.UNRECOGNIZED_ERROR_CODE,
                k.span,
                [k.value?.toString()]);
          }
        }
        if (v is YamlScalar) {
          value = toLowerCase(v.value);
          if (!legalValues.contains(value)) {
            reporter.reportErrorForSpan(
                AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUES,
                v.span, [
              AnalyzerOptions.errors,
              v.value?.toString(),
              legalValueString
            ]);
          }
        }
      });
    }
  }
}

/// A task that generates errors for an `.analysis_options` file.
class GenerateOptionsErrorsTask extends SourceBasedAnalysisTask {
  /// The name of the input whose value is the content of the file.
  static const String CONTENT_INPUT_NAME = 'CONTENT_INPUT_NAME';

  /// The task descriptor describing this kind of task.
  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
      'GenerateOptionsErrorsTask',
      createTask,
      buildInputs,
      <ResultDescriptor>[ANALYSIS_OPTIONS_ERRORS, LINE_INFO],
      suitabilityFor: suitabilityFor);

  final AnalysisOptionsProvider optionsProvider = new AnalysisOptionsProvider();

  GenerateOptionsErrorsTask(AnalysisContext context, AnalysisTarget target)
      : super(context, target);

  @override
  TaskDescriptor get descriptor => DESCRIPTOR;

  Source get source => target.source;

  @override
  void internalPerform() {
    String content = getRequiredInput(CONTENT_INPUT_NAME);

    List<AnalysisError> errors = <AnalysisError>[];

    try {
      Map<String, YamlNode> options =
          optionsProvider.getOptionsFromString(content);
      errors.addAll(_validate(options));
    } on OptionsFormatException catch (e) {
      SourceSpan span = e.span;
      var error = new AnalysisError(source, span.start.column + 1, span.length,
          AnalysisOptionsErrorCode.PARSE_ERROR, [e.message]);
      errors.add(error);
    }

    //
    // Record outputs.
    //
    outputs[ANALYSIS_OPTIONS_ERRORS] = errors;
    outputs[LINE_INFO] = computeLineInfo(content);
  }

  List<AnalysisError> _validate(Map<String, YamlNode> options) =>
      new OptionsFileValidator(source).validate(options);

  /// Return a map from the names of the inputs of this kind of task to the
  /// task input descriptors describing those inputs for a task with the
  /// given [target].
  static Map<String, TaskInput> buildInputs(Source source) =>
      <String, TaskInput>{CONTENT_INPUT_NAME: CONTENT.of(source)};

  /// Compute [LineInfo] for the given [content].
  static LineInfo computeLineInfo(String content) {
    List<int> lineStarts = StringUtilities.computeLineStarts(content);
    return new LineInfo(lineStarts);
  }

  /// Create a task based on the given [target] in the given [context].
  static GenerateOptionsErrorsTask createTask(
          AnalysisContext context, AnalysisTarget target) =>
      new GenerateOptionsErrorsTask(context, target);

  /**
   * Return an indication of how suitable this task is for the given [target].
   */
  static TaskSuitability suitabilityFor(AnalysisTarget target) {
    if (target is Source &&
        target.shortName == AnalysisEngine.ANALYSIS_OPTIONS_FILE) {
      return TaskSuitability.HIGHEST;
    }
    return TaskSuitability.NONE;
  }
}

/// Validates `analyzer` language configuration options.
class LanguageOptionValidator extends OptionsValidator {
  ErrorBuilder builder = new ErrorBuilder(AnalyzerOptions.languageOptions);
  ErrorBuilder trueOrFalseBuilder = new TrueOrFalseValueErrorBuilder();

  @override
  void validate(ErrorReporter reporter, Map<String, YamlNode> options) {
    var analyzer = options[AnalyzerOptions.analyzer];
    if (analyzer is! YamlMap) {
      return;
    }

    var language = analyzer[AnalyzerOptions.language];
    if (language is YamlMap) {
      language.nodes.forEach((k, v) {
        String key, value;
        bool validKey = false;
        if (k is YamlScalar) {
          key = k.value?.toString();
          if (!AnalyzerOptions.languageOptions.contains(key)) {
            builder.reportError(reporter, AnalyzerOptions.language, k);
          } else {
            // If we have a valid key, go on and check the value.
            validKey = true;
          }
        }
        if (validKey && v is YamlScalar) {
          value = toLowerCase(v.value);
          if (!AnalyzerOptions.trueOrFalse.contains(value)) {
            trueOrFalseBuilder.reportError(reporter, key, v);
          }
        }
      });
    }
  }
}

/// Validates `linter` top-level options.
/// TODO(pq): move into `linter` package and plugin.
class LinterOptionsValidator extends TopLevelOptionValidator {
  LinterOptionsValidator() : super('linter', const ['rules']);
}

/// Validates options defined in an `.analysis_options` file.
class OptionsFileValidator {
  // TODO(pq): move to an extension point.
  final List<OptionsValidator> _validators = [
    new AnalyzerOptionsValidator(),
    new LinterOptionsValidator()
  ];

  final Source source;
  OptionsFileValidator(this.source) {
    _validators.addAll(AnalysisEngine.instance.optionsPlugin.optionsValidators);
  }

  List<AnalysisError> validate(Map<String, YamlNode> options) {
    RecordingErrorListener recorder = new RecordingErrorListener();
    ErrorReporter reporter = new ErrorReporter(recorder, source);
    _validators.forEach((OptionsValidator v) => v.validate(reporter, options));
    return recorder.errors;
  }
}

/// Validates `analyzer` strong-mode value configuration options.
class StrongModeOptionValueValidator extends OptionsValidator {
  ErrorBuilder trueOrFalseBuilder = new TrueOrFalseValueErrorBuilder();

  @override
  void validate(ErrorReporter reporter, Map<String, YamlNode> options) {
    var analyzer = options[AnalyzerOptions.analyzer];
    if (analyzer is! YamlMap) {
      return;
    }

    var v = analyzer.nodes[AnalyzerOptions.strong_mode];
    if (v is YamlScalar) {
      var value = toLowerCase(v.value);
      if (!AnalyzerOptions.trueOrFalse.contains(value)) {
        trueOrFalseBuilder.reportError(
            reporter, AnalyzerOptions.strong_mode, v);
      }
    }
  }
}

/// Validates `analyzer` top-level options.
class TopLevelAnalyzerOptionsValidator extends TopLevelOptionValidator {
  TopLevelAnalyzerOptionsValidator()
      : super(AnalyzerOptions.analyzer, AnalyzerOptions.topLevel);
}

/// Validates top-level options. For example,
///     plugin:
///       top-level-option: true
class TopLevelOptionValidator extends OptionsValidator {
  final String pluginName;
  final List<String> supportedOptions;
  String _valueProposal;
  AnalysisOptionsWarningCode _warningCode;
  TopLevelOptionValidator(this.pluginName, this.supportedOptions) {
    assert(supportedOptions != null && !supportedOptions.isEmpty);
    if (supportedOptions.length > 1) {
      _valueProposal = StringUtilities.printListOfQuotedNames(supportedOptions);
      _warningCode =
          AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUES;
    } else {
      _valueProposal = "'${supportedOptions.join()}'";
      _warningCode =
          AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUE;
    }
  }

  @override
  void validate(ErrorReporter reporter, Map<String, YamlNode> options) {
    YamlNode node = options[pluginName];
    if (node is YamlMap) {
      node.nodes.forEach((k, v) {
        if (k is YamlScalar) {
          if (!supportedOptions.contains(k.value)) {
            reporter.reportErrorForSpan(
                _warningCode, k.span, [pluginName, k.value, _valueProposal]);
          }
        }
        //TODO(pq): consider an error if the node is not a Scalar.
      });
    }
  }
}

/// An error-builder that knows about `true` and `false` legal values.
class TrueOrFalseValueErrorBuilder extends ErrorBuilder {
  TrueOrFalseValueErrorBuilder() : super(AnalyzerOptions.trueOrFalse);
  @override
  AnalysisOptionsWarningCode get pluralProposalCode =>
      AnalysisOptionsWarningCode.UNSUPPORTED_VALUE;
}

class _OptionsProcessor {
  static final Map<String, Object> defaults = {'analyzer': {}};

  /**
   * Apply the options in the given [optionMap] to the given analysis [options].
   */
  void applyToAnalysisOptions(
      AnalysisOptionsImpl options, Map<String, Object> optionMap) {
    if (optionMap == null) {
      return;
    }
    var analyzer = optionMap[AnalyzerOptions.analyzer];
    if (analyzer is! Map) {
      return;
    }
    // Process strong mode option.
    var strongMode = analyzer[AnalyzerOptions.strong_mode];
    if (strongMode is bool) {
      options.strongMode = strongMode;
    }
    // Process language options.
    var language = analyzer[AnalyzerOptions.language];
    _applyLanguageOptions(options, language);
  }

  /// Configure [context] based on the given [options] (which can be `null`
  /// to restore [defaults]).
  void configure(AnalysisContext context, Map<String, Object> options) {
    if (options == null) {
      options = defaults;
    }

    var analyzer = options[AnalyzerOptions.analyzer];
    if (analyzer is! Map) {
      return;
    }

    // Set strong mode (default is false).
    var strongMode = analyzer[AnalyzerOptions.strong_mode];
    setStrongMode(context, strongMode);

    // Set filters.
    var filters = analyzer[AnalyzerOptions.errors];
    setProcessors(context, filters);

    // Process language options.
    var language = analyzer[AnalyzerOptions.language];
    setLanguageOptions(context, language);
  }

  void setLanguageOption(
      AnalysisContext context, Object feature, Object value) {
    if (feature == AnalyzerOptions.enableAsync) {
      if (isFalse(value)) {
        AnalysisOptionsImpl options =
            new AnalysisOptionsImpl.from(context.analysisOptions);
        options.enableAsync = false;
        context.analysisOptions = options;
      }
    }
    if (feature == AnalyzerOptions.enableSuperMixins) {
      if (isTrue(value)) {
        AnalysisOptionsImpl options =
            new AnalysisOptionsImpl.from(context.analysisOptions);
        options.enableSuperMixins = true;
        context.analysisOptions = options;
      }
    }
    if (feature == AnalyzerOptions.enableGenericMethods) {
      if (isTrue(value)) {
        AnalysisOptionsImpl options =
            new AnalysisOptionsImpl.from(context.analysisOptions);
        options.enableGenericMethods = true;
        context.analysisOptions = options;
      }
    }
    if (feature == AnalyzerOptions.enableConditionalDirectives) {
      if (isTrue(value)) {
        AnalysisOptionsImpl options =
            new AnalysisOptionsImpl.from(context.analysisOptions);
        options.enableConditionalDirectives = true;
        context.analysisOptions = options;
      }
    }
  }

  void setLanguageOptions(AnalysisContext context, Object configs) {
    if (configs is YamlMap) {
      configs.nodes.forEach((k, v) {
        if (k is YamlScalar && v is YamlScalar) {
          String feature = k.value?.toString();
          setLanguageOption(context, feature, v.value);
        }
      });
    } else if (configs is Map) {
      configs.forEach((k, v) => setLanguageOption(context, k, v));
    }
  }

  void setProcessors(AnalysisContext context, Object codes) {
    ErrorConfig config = new ErrorConfig(codes);
    context.setConfigurationData(
        CONFIGURED_ERROR_PROCESSORS, config.processors);
  }

  void setStrongMode(AnalysisContext context, Object strongMode) {
    bool strong = strongMode is bool ? strongMode : false;
    if (context.analysisOptions.strongMode != strong) {
      AnalysisOptionsImpl options =
          new AnalysisOptionsImpl.from(context.analysisOptions);
      options.strongMode = strong;
      context.analysisOptions = options;
    }
  }

  void _applyLanguageOption(
      AnalysisOptionsImpl options, Object feature, Object value) {
    bool boolValue = toBool(value);
    if (boolValue != null) {
      if (feature == AnalyzerOptions.enableAsync) {
        options.enableAsync = boolValue;
      }
      if (feature == AnalyzerOptions.enableSuperMixins) {
        options.enableSuperMixins = boolValue;
      }
      if (feature == AnalyzerOptions.enableGenericMethods) {
        options.enableGenericMethods = boolValue;
      }
    }
  }

  void _applyLanguageOptions(AnalysisOptionsImpl options, Object configs) {
    if (configs is YamlMap) {
      configs.nodes.forEach((key, value) {
        if (key is YamlScalar && value is YamlScalar) {
          String feature = key.value?.toString();
          _applyLanguageOption(options, feature, value.value);
        }
      });
    } else if (configs is Map) {
      configs
          .forEach((key, value) => _applyLanguageOption(options, key, value));
    }
  }
}
