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

library services.src.index.index_contributor;

import 'dart:collection' show Queue;

import 'package:analysis_server/analysis/index_core.dart';
import 'package:analysis_server/src/services/correction/namespace.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analysis_server/src/services/index/index_store.dart';
import 'package:analysis_server/src/services/index/indexable_element.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/generated/source.dart';

/**
 * An [IndexContributor] that contributes relationships for Dart files.
 */
class DartIndexContributor extends IndexContributor {
  @override
  void contributeTo(IndexStore store, AnalysisContext context, Object object) {
    if (store is InternalIndexStore && object is CompilationUnit) {
      _IndexContributor contributor = new _IndexContributor(store);
      object.accept(contributor);
    }
  }
}

/**
 * Visits a resolved AST and adds relationships into [InternalIndexStore].
 */
class _IndexContributor extends GeneralizingAstVisitor {
  final InternalIndexStore _store;

  LibraryElement _libraryElement;

  Map<ImportElement, Set<Element>> _importElementsMap = {};

  /**
   * A stack whose top element (the element with the largest index) is an
   * element representing the inner-most enclosing scope.
   */
  Queue<Element> _elementStack = new Queue();

  _IndexContributor(this._store);

  /**
   * Enter a new scope represented by the given [Element].
   */
  void enterScope(Element element) {
    _elementStack.addFirst(element);
  }

  /**
   * Return the inner-most enclosing [Element], wrapped as an indexable object,
   * or `null` if there is no enclosing element.
   */
  IndexableElement peekElement() {
    for (Element element in _elementStack) {
      if (element != null) {
        return new IndexableElement(element);
      }
    }
    return null;
  }

  /**
   * Record the given relationship between the given [Element] and
   * [LocationImpl].
   */
  void recordRelationshipElement(
      Element element, RelationshipImpl relationship, LocationImpl location) {
    if (element != null && location != null) {
      _store.recordRelationship(
          new IndexableElement(element), relationship, location);
    }
  }

  /**
   * Record the given relationship between the given [IndexableObject] and
   * [LocationImpl].
   */
  void recordRelationshipIndexable(IndexableObject indexable,
      RelationshipImpl relationship, LocationImpl location) {
    if (indexable != null && location != null) {
      _store.recordRelationship(indexable, relationship, location);
    }
  }

  @override
  visitAssignmentExpression(AssignmentExpression node) {
    _recordOperatorReference(node.operator, node.bestElement);
    super.visitAssignmentExpression(node);
  }

  @override
  visitBinaryExpression(BinaryExpression node) {
    _recordOperatorReference(node.operator, node.bestElement);
    super.visitBinaryExpression(node);
  }

  @override
  visitClassDeclaration(ClassDeclaration node) {
    ClassElement element = node.element;
    enterScope(element);
    try {
      _recordTopLevelElementDefinition(element);
      _recordHasAncestor(element);
      {
        ExtendsClause extendsClause = node.extendsClause;
        if (extendsClause != null) {
          TypeName superclassNode = extendsClause.superclass;
          _recordSuperType(superclassNode, IndexConstants.IS_EXTENDED_BY);
        } else {
          InterfaceType superType = element.supertype;
          if (superType != null) {
            ClassElement objectElement = superType.element;
            recordRelationshipElement(
                objectElement,
                IndexConstants.IS_EXTENDED_BY,
                _createLocationForOffset(node.name.offset, 0));
          }
        }
      }
      {
        WithClause withClause = node.withClause;
        if (withClause != null) {
          for (TypeName mixinNode in withClause.mixinTypes) {
            _recordSuperType(mixinNode, IndexConstants.IS_MIXED_IN_BY);
          }
        }
      }
      {
        ImplementsClause implementsClause = node.implementsClause;
        if (implementsClause != null) {
          for (TypeName interfaceNode in implementsClause.interfaces) {
            _recordSuperType(interfaceNode, IndexConstants.IS_IMPLEMENTED_BY);
          }
        }
      }
      super.visitClassDeclaration(node);
    } finally {
      _exitScope();
    }
  }

  @override
  visitClassTypeAlias(ClassTypeAlias node) {
    ClassElement element = node.element;
    enterScope(element);
    try {
      _recordTopLevelElementDefinition(element);
      _recordHasAncestor(element);
      {
        TypeName superclassNode = node.superclass;
        if (superclassNode != null) {
          _recordSuperType(superclassNode, IndexConstants.IS_EXTENDED_BY);
        }
      }
      {
        WithClause withClause = node.withClause;
        if (withClause != null) {
          for (TypeName mixinNode in withClause.mixinTypes) {
            _recordSuperType(mixinNode, IndexConstants.IS_MIXED_IN_BY);
          }
        }
      }
      {
        ImplementsClause implementsClause = node.implementsClause;
        if (implementsClause != null) {
          for (TypeName interfaceNode in implementsClause.interfaces) {
            _recordSuperType(interfaceNode, IndexConstants.IS_IMPLEMENTED_BY);
          }
        }
      }
      super.visitClassTypeAlias(node);
    } finally {
      _exitScope();
    }
  }

  @override
  visitCompilationUnit(CompilationUnit node) {
    CompilationUnitElement unitElement = node.element;
    if (unitElement != null) {
      _elementStack.add(unitElement);
      _libraryElement = unitElement.enclosingElement;
      if (_libraryElement != null) {
        super.visitCompilationUnit(node);
      }
    }
  }

  @override
  visitConstructorDeclaration(ConstructorDeclaration node) {
    ConstructorElement element = node.element;
    enterScope(element);
    try {
      super.visitConstructorDeclaration(node);
    } finally {
      _exitScope();
    }
  }

  @override
  visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
    SimpleIdentifier fieldName = node.fieldName;
    Expression expression = node.expression;
    // field reference is write here
    if (fieldName != null) {
      Element element = fieldName.staticElement;
      LocationImpl location = _createLocationForNode(fieldName);
      recordRelationshipElement(
          element, IndexConstants.IS_WRITTEN_BY, location);
    }
    // index expression
    if (expression != null) {
      expression.accept(this);
    }
  }

  @override
  visitConstructorName(ConstructorName node) {
    ConstructorElement element = node.staticElement;
    // in 'class B = A;' actually A constructors are invoked
    if (element != null &&
        element.isSynthetic &&
        element.redirectedConstructor != null) {
      element = element.redirectedConstructor;
    }
    // prepare location
    LocationImpl location;
    if (node.name != null) {
      int start = node.period.offset;
      int end = node.name.end;
      location = _createLocationForOffset(start, end - start);
    } else {
      int start = node.type.end;
      location = _createLocationForOffset(start, 0);
    }
    // record relationship
    recordRelationshipElement(
        element, IndexConstants.IS_REFERENCED_BY, location);
    super.visitConstructorName(node);
  }

  @override
  visitDeclaredIdentifier(DeclaredIdentifier node) {
    LocalVariableElement element = node.element;
    enterScope(element);
    try {
      super.visitDeclaredIdentifier(node);
    } finally {
      _exitScope();
    }
  }

  @override
  visitEnumDeclaration(EnumDeclaration node) {
    ClassElement element = node.element;
    enterScope(element);
    try {
      _recordTopLevelElementDefinition(element);
      super.visitEnumDeclaration(node);
    } finally {
      _exitScope();
    }
  }

  @override
  visitExportDirective(ExportDirective node) {
    ExportElement element = node.element;
    if (element != null) {
      LibraryElement expLibrary = element.exportedLibrary;
      _recordLibraryReference(node, expLibrary);
    }
    super.visitExportDirective(node);
  }

  @override
  visitFormalParameter(FormalParameter node) {
    ParameterElement element = node.element;
    enterScope(element);
    try {
      super.visitFormalParameter(node);
    } finally {
      _exitScope();
    }
  }

  @override
  visitFunctionDeclaration(FunctionDeclaration node) {
    Element element = node.element;
    _recordTopLevelElementDefinition(element);
    enterScope(element);
    try {
      super.visitFunctionDeclaration(node);
    } finally {
      _exitScope();
    }
  }

  @override
  visitFunctionTypeAlias(FunctionTypeAlias node) {
    Element element = node.element;
    _recordTopLevelElementDefinition(element);
    super.visitFunctionTypeAlias(node);
  }

  @override
  visitImportDirective(ImportDirective node) {
    ImportElement element = node.element;
    if (element != null) {
      LibraryElement impLibrary = element.importedLibrary;
      _recordLibraryReference(node, impLibrary);
    }
    super.visitImportDirective(node);
  }

  @override
  visitIndexExpression(IndexExpression node) {
    MethodElement element = node.bestElement;
    if (element is MethodElement) {
      Token operator = node.leftBracket;
      LocationImpl location =
          _createLocationForToken(operator, element != null);
      recordRelationshipElement(
          element, IndexConstants.IS_INVOKED_BY, location);
    }
    super.visitIndexExpression(node);
  }

  @override
  visitMethodDeclaration(MethodDeclaration node) {
    ExecutableElement element = node.element;
    enterScope(element);
    try {
      super.visitMethodDeclaration(node);
    } finally {
      _exitScope();
    }
  }

  @override
  visitMethodInvocation(MethodInvocation node) {
    SimpleIdentifier name = node.methodName;
    LocationImpl location = _createLocationForNode(name);
    // name invocation
    recordRelationshipIndexable(
        new IndexableName(name.name), IndexConstants.IS_INVOKED_BY, location);
    // element invocation
    Element element = name.bestElement;
    if (element is MethodElement ||
        element is PropertyAccessorElement ||
        element is FunctionElement ||
        element is VariableElement) {
      recordRelationshipElement(
          element, IndexConstants.IS_INVOKED_BY, location);
    }
    _recordImportElementReferenceWithoutPrefix(name);
    super.visitMethodInvocation(node);
  }

  @override
  visitPartDirective(PartDirective node) {
    Element element = node.element;
    LocationImpl location = _createLocationForNode(node.uri);
    recordRelationshipElement(
        element, IndexConstants.IS_REFERENCED_BY, location);
    super.visitPartDirective(node);
  }

  @override
  visitPartOfDirective(PartOfDirective node) {
    LocationImpl location = _createLocationForNode(node.libraryName);
    recordRelationshipElement(
        node.element, IndexConstants.IS_REFERENCED_BY, location);
  }

  @override
  visitPostfixExpression(PostfixExpression node) {
    _recordOperatorReference(node.operator, node.bestElement);
    super.visitPostfixExpression(node);
  }

  @override
  visitPrefixExpression(PrefixExpression node) {
    _recordOperatorReference(node.operator, node.bestElement);
    super.visitPrefixExpression(node);
  }

  @override
  visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) {
    ConstructorElement element = node.staticElement;
    LocationImpl location;
    if (node.constructorName != null) {
      int start = node.period.offset;
      int end = node.constructorName.end;
      location = _createLocationForOffset(start, end - start);
    } else {
      int start = node.thisKeyword.end;
      location = _createLocationForOffset(start, 0);
    }
    recordRelationshipElement(
        element, IndexConstants.IS_REFERENCED_BY, location);
    super.visitRedirectingConstructorInvocation(node);
  }

  @override
  visitSimpleIdentifier(SimpleIdentifier node) {
    IndexableName indexableName = new IndexableName(node.name);
    LocationImpl location = _createLocationForNode(node);
    if (location == null) {
      return;
    }
    // name in declaration
    if (node.inDeclarationContext()) {
      recordRelationshipIndexable(
          indexableName, IndexConstants.NAME_IS_DEFINED_BY, location);
      return;
    }
    // prepare information
    Element element = node.bestElement;
    // stop if already handled
    if (_isAlreadyHandledName(node)) {
      return;
    }
    // record name read/write
    if (element != null && element.enclosingElement is ClassElement ||
        element == null && location.isQualified) {
      bool inGetterContext = node.inGetterContext();
      bool inSetterContext = node.inSetterContext();
      if (inGetterContext && inSetterContext) {
        recordRelationshipIndexable(
            indexableName, IndexConstants.IS_READ_WRITTEN_BY, location);
      } else if (inGetterContext) {
        recordRelationshipIndexable(
            indexableName, IndexConstants.IS_READ_BY, location);
      } else if (inSetterContext) {
        recordRelationshipIndexable(
            indexableName, IndexConstants.IS_WRITTEN_BY, location);
      }
    }
    // this.field parameter
    if (element is FieldFormalParameterElement) {
      RelationshipImpl relationship = peekElement().element == element
          ? IndexConstants.IS_WRITTEN_BY
          : IndexConstants.IS_REFERENCED_BY;
      recordRelationshipElement(element.field, relationship, location);
      return;
    }
    // record specific relations
    if (element is ClassElement ||
        element is FunctionElement ||
        element is FunctionTypeAliasElement ||
        element is LabelElement ||
        element is MethodElement ||
        element is PropertyAccessorElement ||
        element is PropertyInducingElement ||
        element is TypeParameterElement) {
      recordRelationshipElement(
          element, IndexConstants.IS_REFERENCED_BY, location);
    } else if (element is PrefixElement) {
      recordRelationshipElement(
          element, IndexConstants.IS_REFERENCED_BY, location);
      _recordImportElementReferenceWithPrefix(node);
    } else if (element is ParameterElement || element is LocalVariableElement) {
      bool inGetterContext = node.inGetterContext();
      bool inSetterContext = node.inSetterContext();
      if (inGetterContext && inSetterContext) {
        recordRelationshipElement(
            element, IndexConstants.IS_READ_WRITTEN_BY, location);
      } else if (inGetterContext) {
        recordRelationshipElement(element, IndexConstants.IS_READ_BY, location);
      } else if (inSetterContext) {
        recordRelationshipElement(
            element, IndexConstants.IS_WRITTEN_BY, location);
      } else {
        recordRelationshipElement(
            element, IndexConstants.IS_REFERENCED_BY, location);
      }
    }
    _recordImportElementReferenceWithoutPrefix(node);
    super.visitSimpleIdentifier(node);
  }

  @override
  visitSuperConstructorInvocation(SuperConstructorInvocation node) {
    ConstructorElement element = node.staticElement;
    LocationImpl location;
    if (node.constructorName != null) {
      int start = node.period.offset;
      int end = node.constructorName.end;
      location = _createLocationForOffset(start, end - start);
    } else {
      int start = node.superKeyword.end;
      location = _createLocationForOffset(start, 0);
    }
    recordRelationshipElement(
        element, IndexConstants.IS_REFERENCED_BY, location);
    super.visitSuperConstructorInvocation(node);
  }

  @override
  visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
    VariableDeclarationList variables = node.variables;
    for (VariableDeclaration variableDeclaration in variables.variables) {
      Element element = variableDeclaration.element;
      _recordTopLevelElementDefinition(element);
    }
    super.visitTopLevelVariableDeclaration(node);
  }

  @override
  visitTypeParameter(TypeParameter node) {
    TypeParameterElement element = node.element;
    enterScope(element);
    try {
      super.visitTypeParameter(node);
    } finally {
      _exitScope();
    }
  }

  @override
  visitVariableDeclaration(VariableDeclaration node) {
    VariableElement element = node.element;
    // record declaration
    {
      SimpleIdentifier name = node.name;
      LocationImpl location = _createLocationForNode(name);
      location = _getLocationWithExpressionType(location, node.initializer);
      recordRelationshipElement(
          element, IndexConstants.NAME_IS_DEFINED_BY, location);
    }
    // visit
    enterScope(element);
    try {
      super.visitVariableDeclaration(node);
    } finally {
      _exitScope();
    }
  }

  @override
  visitVariableDeclarationList(VariableDeclarationList node) {
    NodeList<VariableDeclaration> variables = node.variables;
    if (variables != null) {
      // use first VariableDeclaration as Element for Location(s) in type
      {
        TypeName type = node.type;
        if (type != null) {
          for (VariableDeclaration variableDeclaration in variables) {
            enterScope(variableDeclaration.element);
            try {
              type.accept(this);
            } finally {
              _exitScope();
            }
            // only one iteration
            break;
          }
        }
      }
      // visit variables
      variables.accept(this);
    }
  }

  /**
   * @return the [LocationImpl] representing location of the [AstNode].
   */
  LocationImpl _createLocationForNode(AstNode node) {
    bool isQualified = _isQualifiedClassMemberAccess(node);
    bool isResolved = true;
    if (node is SimpleIdentifier) {
      isResolved = node.bestElement != null;
    }
    IndexableObject indexable = peekElement();
    return new LocationImpl(indexable, node.offset, node.length,
        isQualified: isQualified, isResolved: isResolved);
  }

  /**
   * [offset] - the offset of the location within [Source].
   * [length] - the length of the location.
   *
   * Returns the [LocationImpl] representing the given offset and length within the
   * inner-most [Element].
   */
  LocationImpl _createLocationForOffset(int offset, int length) {
    IndexableObject element = peekElement();
    return new LocationImpl(element, offset, length);
  }

  /**
   * @return the [LocationImpl] representing location of the [Token].
   */
  LocationImpl _createLocationForToken(Token token, bool isResolved) {
    IndexableObject element = peekElement();
    return new LocationImpl(element, token.offset, token.length,
        isQualified: true, isResolved: isResolved);
  }

  /**
   * Exit the current scope.
   */
  void _exitScope() {
    _elementStack.removeFirst();
  }

  /**
   * @return `true` if given node already indexed as more interesting reference, so it should
   *         not be indexed again.
   */
  bool _isAlreadyHandledName(SimpleIdentifier node) {
    AstNode parent = node.parent;
    if (parent is MethodInvocation) {
      return parent.methodName == node;
    }
    return false;
  }

  bool _isQualifiedClassMemberAccess(AstNode node) {
    if (node is SimpleIdentifier) {
      AstNode parent = node.parent;
      if (parent is PrefixedIdentifier && parent.identifier == node) {
        return parent.prefix.staticElement is! PrefixElement;
      }
      if (parent is PropertyAccess && parent.propertyName == node) {
        return parent.realTarget != null;
      }
      if (parent is MethodInvocation && parent.methodName == node) {
        Expression target = parent.realTarget;
        if (target is SimpleIdentifier &&
            target.staticElement is PrefixElement) {
          return false;
        }
        return target != null;
      }
    }
    return false;
  }

  void _recordHasAncestor(ClassElement element) {
    int offset = element.nameOffset;
    int length = element.nameLength;
    LocationImpl location = _createLocationForOffset(offset, length);
    _recordHasAncestor0(location, element, false, <ClassElement>[]);
  }

  void _recordHasAncestor0(LocationImpl location, ClassElement element,
      bool includeThis, List<ClassElement> visitedElements) {
    if (element == null) {
      return;
    }
    if (visitedElements.contains(element)) {
      return;
    }
    visitedElements.add(element);
    if (includeThis) {
      recordRelationshipElement(element, IndexConstants.HAS_ANCESTOR, location);
    }
    {
      InterfaceType superType = element.supertype;
      if (superType != null) {
        _recordHasAncestor0(location, superType.element, true, visitedElements);
      }
    }
    for (InterfaceType mixinType in element.mixins) {
      _recordHasAncestor0(location, mixinType.element, true, visitedElements);
    }
    for (InterfaceType implementedType in element.interfaces) {
      _recordHasAncestor0(
          location, implementedType.element, true, visitedElements);
    }
  }

  /**
   * Records [ImportElement] reference if given [SimpleIdentifier] references some
   * top-level element and not qualified with import prefix.
   */
  void _recordImportElementReferenceWithoutPrefix(SimpleIdentifier node) {
    if (_isIdentifierInImportCombinator(node)) {
      return;
    }
    if (_isIdentifierInPrefixedIdentifier(node)) {
      return;
    }
    Element element = node.staticElement;
    ImportElement importElement = internal_getImportElement(
        _libraryElement, null, element, _importElementsMap);
    if (importElement != null) {
      LocationImpl location = _createLocationForOffset(node.offset, 0);
      recordRelationshipElement(
          importElement, IndexConstants.IS_REFERENCED_BY, location);
    }
  }

  /**
   * Records [ImportElement] that declares given prefix and imports library with element used
   * with given prefix node.
   */
  void _recordImportElementReferenceWithPrefix(SimpleIdentifier prefixNode) {
    ImportElementInfo info = internal_getImportElementInfo(prefixNode);
    if (info != null) {
      int offset = prefixNode.offset;
      int length = info.periodEnd - offset;
      LocationImpl location = _createLocationForOffset(offset, length);
      recordRelationshipElement(
          info.element, IndexConstants.IS_REFERENCED_BY, location);
    }
  }

  /**
   * Records reference to defining [CompilationUnitElement] of the given
   * [LibraryElement].
   */
  void _recordLibraryReference(UriBasedDirective node, LibraryElement library) {
    if (library != null) {
      LocationImpl location = _createLocationForNode(node.uri);
      recordRelationshipElement(library.definingCompilationUnit,
          IndexConstants.IS_REFERENCED_BY, location);
    }
  }

  /**
   * Record reference to the given operator [Element] and name.
   */
  void _recordOperatorReference(Token operator, Element element) {
    // prepare location
    LocationImpl location = _createLocationForToken(operator, element != null);
    // record name reference
    {
      String name = operator.lexeme;
      if (name == "++") {
        name = "+";
      }
      if (name == "--") {
        name = "-";
      }
      if (StringUtilities.endsWithChar(name, 0x3D) && name != "==") {
        name = name.substring(0, name.length - 1);
      }
      IndexableName indexableName = new IndexableName(name);
      recordRelationshipIndexable(
          indexableName, IndexConstants.IS_INVOKED_BY, location);
    }
    // record element reference
    if (element != null) {
      recordRelationshipElement(
          element, IndexConstants.IS_INVOKED_BY, location);
    }
  }

  /**
   * Records a relation between [superNode] and its [Element].
   */
  void _recordSuperType(TypeName superNode, RelationshipImpl relationship) {
    if (superNode != null) {
      Identifier superName = superNode.name;
      if (superName != null) {
        Element superElement = superName.staticElement;
        recordRelationshipElement(
            superElement, relationship, _createLocationForNode(superNode));
      }
    }
  }

  /**
   * Records the [Element] definition in the library and universe.
   */
  void _recordTopLevelElementDefinition(Element element) {
    if (element != null) {
      IndexableElement indexable = new IndexableElement(element);
      int offset = element.nameOffset;
      int length = element.nameLength;
      LocationImpl location = new LocationImpl(indexable, offset, length);
      recordRelationshipElement(
          _libraryElement, IndexConstants.DEFINES, location);
      _store.recordTopLevelDeclaration(element);
    }
  }

  /**
   * If the given expression has resolved type, returns the new location with this type.
   *
   * [location] - the base location
   * [expression] - the expression assigned at the given location
   */
  static LocationImpl _getLocationWithExpressionType(
      LocationImpl location, Expression expression) {
    if (expression != null) {
      return new LocationWithData<DartType>(location, expression.bestType);
    }
    return location;
  }

  /**
   * @return `true` if given "node" is part of an import [Combinator].
   */
  static bool _isIdentifierInImportCombinator(SimpleIdentifier node) {
    AstNode parent = node.parent;
    return parent is Combinator;
  }

  /**
   * @return `true` if given "node" is part of [PrefixedIdentifier] "prefix.node".
   */
  static bool _isIdentifierInPrefixedIdentifier(SimpleIdentifier node) {
    AstNode parent = node.parent;
    return parent is PrefixedIdentifier && parent.identifier == node;
  }
}
