// 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:collection';

import 'package:analyzer/error/error.dart';
import 'package:analyzer/source/error_processor.dart' show ErrorProcessor;
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisOptions;
import 'package:path/path.dart' as path;

class ErrorCollector {
  final bool _replCompile;
  final AnalysisOptions _options;
  SplayTreeMap<AnalysisError, String> _errors;

  ErrorCollector(this._options, this._replCompile) {
    _errors = SplayTreeMap<AnalysisError, String>(_compareErrors);
  }

  bool get hasFatalErrors => _errors.keys.any(_isFatalError);

  Iterable<String> get formattedErrors => _errors.values;

  void add(LineInfo lineInfo, AnalysisError error) {
    if (_shouldIgnoreError(error)) return;

    // Skip hints, some like TODOs are not useful.
    if (_errorSeverity(error).ordinal <= ErrorSeverity.INFO.ordinal) return;

    _errors[error] = _formatError(lineInfo, error);
  }

  void addAll(LineInfo lineInfo, Iterable<AnalysisError> errors) {
    for (var e in errors) add(lineInfo, e);
  }

  ErrorSeverity _errorSeverity(AnalysisError error) {
    var errorCode = error.errorCode;
    if (errorCode == StrongModeCode.TOP_LEVEL_FUNCTION_LITERAL_BLOCK ||
        errorCode == StrongModeCode.TOP_LEVEL_INSTANCE_GETTER ||
        errorCode == StrongModeCode.TOP_LEVEL_INSTANCE_METHOD) {
      // These are normally hints, but they should be errors when running DDC, so
      // that users won't be surprised by behavioral differences between DDC and
      // dart2js.
      return ErrorSeverity.ERROR;
    }

    // TODO(jmesserly): remove support for customizing error levels via
    // analysis_options from DDC. (it won't work with --kernel).
    return ErrorProcessor.getProcessor(_options, error)?.severity ??
        errorCode.errorSeverity;
  }

  String _formatError(LineInfo lineInfo, AnalysisError error) {
    var location = lineInfo.getLocation(error.offset);

    // [warning] 'foo' is not a... (/Users/.../tmp/foo.dart, line 1, col 2)
    return (StringBuffer()
          ..write('[${_errorSeverity(error).displayName}] ')
          ..write(error.message)
          ..write(' (${path.prettyUri(error.source.uri)}')
          ..write(
              ', line ${location.lineNumber}, col ${location.columnNumber})'))
        .toString();
  }

  bool _shouldIgnoreError(AnalysisError error) {
    var uri = error.source.uri;
    if (uri.scheme != 'dart') return false;
    var sdkLib = uri.pathSegments[0];
    if (sdkLib == 'html' || sdkLib == 'svg' || sdkLib == '_interceptors') {
      var c = error.errorCode;
      return c == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1 ||
          c == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2 ||
          c == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS;
    }
    return false;
  }

  int _compareErrors(AnalysisError error1, AnalysisError error2) {
    // severity
    int compare = _errorSeverity(error2).compareTo(_errorSeverity(error1));
    if (compare != 0) return compare;

    // path
    compare = Comparable.compare(error1.source.fullName.toLowerCase(),
        error2.source.fullName.toLowerCase());
    if (compare != 0) return compare;

    // offset
    compare = error1.offset - error2.offset;
    if (compare != 0) return compare;

    // compare message, in worst case.
    return error1.message.compareTo(error2.message);
  }

  bool _isFatalError(AnalysisError e) {
    if (_errorSeverity(e) != ErrorSeverity.ERROR) return false;

    // These errors are not fatal in the REPL compile mode as we
    // allow access to private members across library boundaries
    // and those accesses will show up as undefined members unless
    // additional analyzer changes are made to support them.
    // TODO(jacobr): consider checking that the identifier name
    // referenced by the error is private.
    return !_replCompile ||
        (e.errorCode != StaticTypeWarningCode.UNDEFINED_GETTER &&
            e.errorCode != StaticTypeWarningCode.UNDEFINED_SETTER &&
            e.errorCode != StaticTypeWarningCode.UNDEFINED_METHOD);
  }
}

const invalidImportDartMirrors = StrongModeCode(
    ErrorType.COMPILE_TIME_ERROR,
    'IMPORT_DART_MIRRORS',
    'Cannot import "dart:mirrors" in web applications (https://goo.gl/R1anEs).');

const invalidJSInteger = StrongModeCode(
    ErrorType.COMPILE_TIME_ERROR,
    'INVALID_JS_INTEGER',
    "The integer literal '{0}' can't be represented exactly in JavaScript. "
    "The nearest value that can be represented exactly is '{1}'.");
