// 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 search.element_references;

import 'dart:async';

import 'package:analysis_server/src/collections.dart';
import 'package:analysis_server/src/protocol_server.dart'
    show SearchResult, newSearchResult_fromMatch;
import 'package:analysis_server/src/services/search/hierarchy.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/source.dart';

/**
 * A computer for `search.findElementReferences` request results.
 */
class ElementReferencesComputer {
  final SearchEngine searchEngine;

  ElementReferencesComputer(this.searchEngine);

  /**
   * Computes [SearchResult]s for [element] references.
   */
  Future<List<SearchResult>> compute(Element element, bool withPotential) {
    var futureGroup = new _ConcatFutureGroup<SearchResult>();
    // find element references
    futureGroup.add(_findElementsReferences(element));
    // add potential references
    if (withPotential && _isMemberElement(element)) {
      String name = element.displayName;
      var matchesFuture = searchEngine.searchMemberReferences(name);
      var resultsFuture = matchesFuture.then((List<SearchMatch> matches) {
        return matches.where((match) => !match.isResolved).map(toResult);
      });
      futureGroup.add(resultsFuture);
    }
    // merge results
    return futureGroup.future;
  }

  /**
   * Returns a [Future] completing with a [List] of references to [element] or
   * to the corresponding hierarchy [Element]s.
   */
  Future<List<SearchResult>> _findElementsReferences(Element element) {
    return _getRefElements(element).then((Iterable<Element> refElements) {
      var futureGroup = new _ConcatFutureGroup<SearchResult>();
      for (Element refElement in refElements) {
        // add declaration
        if (_isDeclarationInteresting(refElement)) {
          SearchResult searchResult = _newDeclarationResult(refElement);
          futureGroup.add(searchResult);
        }
        // do search
        futureGroup.add(_findSingleElementReferences(refElement));
      }
      return futureGroup.future;
    });
  }

  /**
   * Returns a [Future] completing with a [List] of references to [element].
   */
  Future<List<SearchResult>> _findSingleElementReferences(Element element) {
    Future<List<SearchMatch>> matchesFuture =
        searchEngine.searchReferences(element);
    return matchesFuture.then((List<SearchMatch> matches) {
      return matches.map(toResult).toList();
    });
  }

  /**
   * Returns a [Future] completing with [Element]s to search references to.
   *
   * If a [ClassMemberElement] is given, each corresponding [Element] in the
   * hierarchy is returned.
   *
   * Otherwise, only references to [element] should be searched.
   */
  Future<Iterable<Element>> _getRefElements(Element element) {
    if (element is ClassMemberElement) {
      return getHierarchyMembers(searchEngine, element);
    }
    return new Future.value([element]);
  }

  SearchResult _newDeclarationResult(Element refElement) {
    int nameOffset = refElement.nameOffset;
    int nameLength = refElement.nameLength;
    SearchMatch searchMatch = new SearchMatch(MatchKind.DECLARATION, refElement,
        new SourceRange(nameOffset, nameLength), true, false);
    return newSearchResult_fromMatch(searchMatch);
  }

  static SearchResult toResult(SearchMatch match) {
    return newSearchResult_fromMatch(match);
  }

  static bool _isDeclarationInteresting(Element element) {
    if (element is LabelElement) {
      return true;
    }
    if (element is LocalVariableElement) {
      return true;
    }
    if (element is ParameterElement) {
      return true;
    }
    if (element is PrefixElement) {
      return true;
    }
    if (element is PropertyInducingElement) {
      return !element.isSynthetic;
    }
    return false;
  }

  static bool _isMemberElement(Element element) {
    if (element is ConstructorElement) {
      return false;
    }
    return element.enclosingElement is ClassElement;
  }
}

/**
 * A collection of [Future]s that concats [List] results of added [Future]s into
 * a single [List].
 */
class _ConcatFutureGroup<E> {
  final List<Future<List<E>>> _futures = <Future<List<E>>>[];

  Future<List<E>> get future {
    return Future.wait(_futures).then(concatToList);
  }

  /**
   * Adds a [Future] or an [E] value to results.
   */
  void add(value) {
    if (value is Future) {
      _futures.add(value);
    } else {
      _futures.add(new Future.value(<E>[value]));
    }
  }
}
