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

import 'dart:async';

import 'package:analysis_server/analysis/index_core.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analysis_server/src/services/index/store/split_store.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';

/**
 * A local implementation of [Index].
 */
class LocalIndex extends Index {
  /**
   * The index contributors used by this index.
   */
  List<IndexContributor> contributors = <IndexContributor>[];

  SplitIndexStore _store;

  LocalIndex(NodeManager nodeManager) {
    // TODO(scheglov) get IndexObjectManager(s) as a parameter
    _store = new SplitIndexStore(
        nodeManager, <IndexObjectManager>[new DartUnitIndexObjectManager()]);
  }

  @override
  String get statistics => _store.statistics;

  @override
  void clear() {
    _store.clear();
  }

  /**
   * Returns all relations with [Element]s with the given [name].
   */
  Future<Map<List<String>, List<InspectLocation>>> findElementsByName(
      String name) {
    return _store.inspect_getElementRelations(name);
  }

  /**
   * Returns a `Future<List<Location>>` that completes with the list of
   * [LocationImpl]s of the given [relationship] with the given [indexable].
   *
   * For example, if the [indexable] represents a function element and the
   * [relationship] is the `is-invoked-by` relationship, then the locations
   * will be all of the places where the function is invoked.
   */
  @override
  Future<List<LocationImpl>> getRelationships(
      IndexableObject indexable, RelationshipImpl relationship) {
    return _store.getRelationships(indexable, relationship);
  }

  @override
  List<Element> getTopLevelDeclarations(ElementNameFilter nameFilter) {
    return _store.getTopLevelDeclarations(nameFilter);
  }

  @override
  void index(AnalysisContext context, Object object) {
    // about to index
    bool mayIndex = _store.aboutToIndex(context, object);
    if (!mayIndex) {
      return;
    }
    // do index
    try {
      for (IndexContributor contributor in contributors) {
        contributor.contributeTo(_store, context, object);
      }
      _store.doneIndex();
    } catch (e) {
      _store.cancelIndex();
      rethrow;
    }
  }

  @override
  void recordRelationship(
      IndexableObject indexable, Relationship relationship, Location location) {
    _store.recordRelationship(indexable, relationship, location);
  }

  @override
  void removeContext(AnalysisContext context) {
    _store.removeContext(context);
  }

  @override
  void removeSource(AnalysisContext context, Source source) {
    _store.removeSource(context, source);
  }

  @override
  void removeSources(AnalysisContext context, SourceContainer container) {
    _store.removeSources(context, container);
  }

  @override
  void run() {
    // NO-OP for the local index
  }

  @override
  void stop() {
    // NO-OP for the local index
  }
}
