// Copyright (c) 2017, 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 'package:analyzer/dart/element/element.dart' as analyzer;
import 'package:analyzer/dart/element/type.dart' as analyzer;
import 'package:analyzer/error/error.dart' as analyzer;
import 'package:analyzer/exception/exception.dart' as analyzer;
import 'package:analyzer/source/error_processor.dart' as analyzer;
import 'package:analyzer/source/line_info.dart' as analyzer;
import 'package:analyzer/src/generated/engine.dart' as analyzer;
import 'package:analyzer/src/generated/source.dart' as analyzer;
import 'package:analyzer/src/generated/utilities_dart.dart' as analyzer;
import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_constants.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;

/**
 * An object used to convert between objects defined by the 'analyzer' package
 * and those defined by the plugin protocol.
 *
 * Clients may not extend, implement or mix-in this class.
 */
class AnalyzerConverter {
  /**
   * Convert the analysis [error] from the 'analyzer' package to an analysis
   * error defined by the plugin API. If a [lineInfo] is provided then the
   * error's location will have a start line and start column. If a [severity]
   * is provided, then it will override the severity defined by the error.
   */
  plugin.AnalysisError convertAnalysisError(analyzer.AnalysisError error,
      {analyzer.LineInfo lineInfo, analyzer.ErrorSeverity severity}) {
    analyzer.ErrorCode errorCode = error.errorCode;
    severity ??= errorCode.errorSeverity;
    int offset = error.offset;
    int startLine = -1;
    int startColumn = -1;
    if (lineInfo != null) {
      analyzer.CharacterLocation lineLocation = lineInfo.getLocation(offset);
      if (lineLocation != null) {
        startLine = lineLocation.lineNumber;
        startColumn = lineLocation.columnNumber;
      }
    }
    return new plugin.AnalysisError(
        convertErrorSeverity(severity),
        convertErrorType(errorCode.type),
        new plugin.Location(error.source.fullName, offset, error.length,
            startLine, startColumn),
        error.message,
        errorCode.name.toLowerCase(),
        correction: error.correction,
        hasFix: true);
  }

  /**
   * Convert the list of analysis [errors] from the 'analyzer' package to a list
   * of analysis errors defined by the plugin API. If a [lineInfo] is provided
   * then the resulting errors locations will have a start line and start column.
   * If an analysis [options] is provided then the severities of the errors will
   * be altered based on those options.
   */
  List<plugin.AnalysisError> convertAnalysisErrors(
      List<analyzer.AnalysisError> errors,
      {analyzer.LineInfo lineInfo,
      analyzer.AnalysisOptions options}) {
    List<plugin.AnalysisError> serverErrors = <plugin.AnalysisError>[];
    for (analyzer.AnalysisError error in errors) {
      analyzer.ErrorProcessor processor =
          analyzer.ErrorProcessor.getProcessor(options, error);
      if (processor != null) {
        analyzer.ErrorSeverity severity = processor.severity;
        // Errors with null severity are filtered out.
        if (severity != null) {
          // Specified severities override.
          serverErrors.add(convertAnalysisError(error,
              lineInfo: lineInfo, severity: severity));
        }
      } else {
        serverErrors.add(convertAnalysisError(error, lineInfo: lineInfo));
      }
    }
    return serverErrors;
  }

  /**
   * Convert the given [element] from the 'analyzer' package to an element
   * defined by the plugin API.
   */
  plugin.Element convertElement(analyzer.Element element) {
    plugin.ElementKind kind = _convertElementToElementKind(element);
    return new plugin.Element(
        kind,
        element.displayName,
        plugin.Element.makeFlags(
            isPrivate: element.isPrivate,
            isDeprecated: element.hasDeprecated,
            isAbstract: _isAbstract(element),
            isConst: _isConst(element),
            isFinal: _isFinal(element),
            isStatic: _isStatic(element)),
        location: _locationFromElement(element),
        typeParameters: _getTypeParametersString(element),
        parameters: _getParametersString(element),
        returnType: _getReturnTypeString(element));
  }

  /**
   * Convert the element [kind] from the 'analyzer' package to an element kind
   * defined by the plugin API.
   *
   * This method does not take into account that an instance of [ClassElement]
   * can be an enum and an instance of [FieldElement] can be an enum constant.
   * Use [_convertElementToElementKind] where possible.
   */
  plugin.ElementKind convertElementKind(analyzer.ElementKind kind) {
    if (kind == analyzer.ElementKind.CLASS) {
      return plugin.ElementKind.CLASS;
    } else if (kind == analyzer.ElementKind.COMPILATION_UNIT) {
      return plugin.ElementKind.COMPILATION_UNIT;
    } else if (kind == analyzer.ElementKind.CONSTRUCTOR) {
      return plugin.ElementKind.CONSTRUCTOR;
    } else if (kind == analyzer.ElementKind.FIELD) {
      return plugin.ElementKind.FIELD;
    } else if (kind == analyzer.ElementKind.FUNCTION) {
      return plugin.ElementKind.FUNCTION;
    } else if (kind == analyzer.ElementKind.FUNCTION_TYPE_ALIAS) {
      return plugin.ElementKind.FUNCTION_TYPE_ALIAS;
    } else if (kind == analyzer.ElementKind.GETTER) {
      return plugin.ElementKind.GETTER;
    } else if (kind == analyzer.ElementKind.LABEL) {
      return plugin.ElementKind.LABEL;
    } else if (kind == analyzer.ElementKind.LIBRARY) {
      return plugin.ElementKind.LIBRARY;
    } else if (kind == analyzer.ElementKind.LOCAL_VARIABLE) {
      return plugin.ElementKind.LOCAL_VARIABLE;
    } else if (kind == analyzer.ElementKind.METHOD) {
      return plugin.ElementKind.METHOD;
    } else if (kind == analyzer.ElementKind.PARAMETER) {
      return plugin.ElementKind.PARAMETER;
    } else if (kind == analyzer.ElementKind.PREFIX) {
      return plugin.ElementKind.PREFIX;
    } else if (kind == analyzer.ElementKind.SETTER) {
      return plugin.ElementKind.SETTER;
    } else if (kind == analyzer.ElementKind.TOP_LEVEL_VARIABLE) {
      return plugin.ElementKind.TOP_LEVEL_VARIABLE;
    } else if (kind == analyzer.ElementKind.TYPE_PARAMETER) {
      return plugin.ElementKind.TYPE_PARAMETER;
    }
    return plugin.ElementKind.UNKNOWN;
  }

  /**
   * Convert the error [severity] from the 'analyzer' package to an analysis
   * error severity defined by the plugin API.
   */
  plugin.AnalysisErrorSeverity convertErrorSeverity(
          analyzer.ErrorSeverity severity) =>
      new plugin.AnalysisErrorSeverity(severity.name);

  /**
   *Convert the error [type] from the 'analyzer' package to an analysis error
   * type defined by the plugin API.
   */
  plugin.AnalysisErrorType convertErrorType(analyzer.ErrorType type) =>
      new plugin.AnalysisErrorType(type.name);

  /**
   * Convert the element kind of the [element] from the 'analyzer' package to an
   * element kind defined by the plugin API.
   */
  plugin.ElementKind _convertElementToElementKind(analyzer.Element element) {
    if (element is analyzer.ClassElement && element.isEnum) {
      return plugin.ElementKind.ENUM;
    } else if (element is analyzer.FieldElement &&
        element.isEnumConstant &&
        // MyEnum.values and MyEnum.one.index return isEnumConstant = true
        // so these additional checks are necessary.
        // TODO(danrubel) MyEnum.values is constant, but is a list
        // so should it return isEnumConstant = true?
        // MyEnum.one.index is final but *not* constant
        // so should it return isEnumConstant = true?
        // Or should we return ElementKind.ENUM_CONSTANT here
        // in either or both of these cases?
        element.type != null &&
        element.type.element == element.enclosingElement) {
      return plugin.ElementKind.ENUM_CONSTANT;
    }
    return convertElementKind(element.kind);
  }

  /**
   * Return a textual representation of the parameters of the given [element],
   * or `null` if the element does not have any parameters.
   */
  String _getParametersString(analyzer.Element element) {
    // TODO(scheglov) expose the corresponding feature from ExecutableElement
    List<analyzer.ParameterElement> parameters;
    if (element is analyzer.ExecutableElement) {
      // valid getters don't have parameters
      if (element.kind == analyzer.ElementKind.GETTER &&
          element.parameters.isEmpty) {
        return null;
      }
      parameters = element.parameters;
    } else if (element is analyzer.FunctionTypeAliasElement) {
      parameters = element.parameters;
    } else {
      return null;
    }
    StringBuffer buffer = new StringBuffer();
    String closeOptionalString = '';
    buffer.write('(');
    for (int i = 0; i < parameters.length; i++) {
      analyzer.ParameterElement parameter = parameters[i];
      if (i > 0) {
        buffer.write(', ');
      }
      if (closeOptionalString.isEmpty) {
        if (parameter.isNamed) {
          buffer.write('{');
          closeOptionalString = '}';
        } else if (parameter.isOptionalPositional) {
          buffer.write('[');
          closeOptionalString = ']';
        }
      }
      parameter.appendToWithoutDelimiters(buffer);
    }
    buffer.write(closeOptionalString);
    buffer.write(')');
    return buffer.toString();
  }

  /**
   * Return a textual representation of the return type of the given [element],
   * or `null` if the element does not have a return type.
   */
  String _getReturnTypeString(analyzer.Element element) {
    if (element is analyzer.ExecutableElement) {
      if (element.kind == analyzer.ElementKind.SETTER) {
        return null;
      }
      return element.returnType?.toString();
    } else if (element is analyzer.VariableElement) {
      analyzer.DartType type = element.type;
      return type != null ? type.displayName : 'dynamic';
    } else if (element is analyzer.FunctionTypeAliasElement) {
      return element.returnType.toString();
    }
    return null;
  }

  /**
   * Return a textual representation of the type parameters of the given
   * [element], or `null` if the element does not have type parameters.
   */
  String _getTypeParametersString(analyzer.Element element) {
    if (element is analyzer.TypeParameterizedElement) {
      List<analyzer.TypeParameterElement> typeParameters =
          element.typeParameters;
      if (typeParameters == null || typeParameters.isEmpty) {
        return null;
      }
      return '<${typeParameters.join(', ')}>';
    }
    return null;
  }

  /**
   * Return the compilation unit containing the given [element].
   */
  analyzer.CompilationUnitElement _getUnitElement(analyzer.Element element) {
    if (element is analyzer.CompilationUnitElement) {
      return element;
    }
    if (element?.enclosingElement is analyzer.LibraryElement) {
      element = element.enclosingElement;
    }
    if (element is analyzer.LibraryElement) {
      return element.definingCompilationUnit;
    }
    for (; element != null; element = element.enclosingElement) {
      if (element is analyzer.CompilationUnitElement) {
        return element;
      }
    }
    return null;
  }

  bool _isAbstract(analyzer.Element element) {
    // TODO(scheglov) add isAbstract to Element API
    if (element is analyzer.ClassElement) {
      return element.isAbstract;
    } else if (element is analyzer.MethodElement) {
      return element.isAbstract;
    } else if (element is analyzer.PropertyAccessorElement) {
      return element.isAbstract;
    }
    return false;
  }

  bool _isConst(analyzer.Element element) {
    // TODO(scheglov) add isConst to Element API
    if (element is analyzer.ConstructorElement) {
      return element.isConst;
    } else if (element is analyzer.VariableElement) {
      return element.isConst;
    }
    return false;
  }

  bool _isFinal(analyzer.Element element) {
    // TODO(scheglov) add isFinal to Element API
    if (element is analyzer.VariableElement) {
      return element.isFinal;
    }
    return false;
  }

  bool _isStatic(analyzer.Element element) {
    // TODO(scheglov) add isStatic to Element API
    if (element is analyzer.ExecutableElement) {
      return element.isStatic;
    } else if (element is analyzer.PropertyInducingElement) {
      return element.isStatic;
    }
    return false;
  }

  /**
   * Create and return a location within the given [unitElement] at the given
   * [range].
   */
  plugin.Location _locationForArgs(
      analyzer.CompilationUnitElement unitElement, analyzer.SourceRange range) {
    int startLine = 0;
    int startColumn = 0;
    try {
      analyzer.LineInfo lineInfo = unitElement.lineInfo;
      if (lineInfo != null) {
        analyzer.CharacterLocation offsetLocation =
            lineInfo.getLocation(range.offset);
        startLine = offsetLocation.lineNumber;
        startColumn = offsetLocation.columnNumber;
      }
    } on analyzer.AnalysisException {
      // Ignore exceptions
    }
    return new plugin.Location(unitElement.source.fullName, range.offset,
        range.length, startLine, startColumn);
  }

  /**
   * Create a location based on an the given [element].
   */
  plugin.Location _locationFromElement(analyzer.Element element) {
    if (element == null || element.source == null) {
      return null;
    }
    int offset = element.nameOffset;
    int length = element.nameLength;
    if (element is analyzer.CompilationUnitElement ||
        (element is analyzer.LibraryElement && offset < 0)) {
      offset = 0;
      length = 0;
    }
    analyzer.CompilationUnitElement unitElement = _getUnitElement(element);
    analyzer.SourceRange range = new analyzer.SourceRange(offset, length);
    return _locationForArgs(unitElement, range);
  }
}
