// 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/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.LineInfo_Location 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.LineInfo_Location 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);
  }
}
