// 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.completion.dart.cache;

import 'dart:async';
import 'dart:collection';

import 'package:analysis_server/src/protocol_server.dart'
    hide Element, ElementKind;
import 'package:analysis_server/src/services/completion/completion_manager.dart';
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
import 'package:analysis_server/src/services/completion/suggestion_builder.dart';
import 'package:analysis_server/src/services/search/search_engine.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/resolver.dart';
import 'package:analyzer/src/generated/source.dart';

/**
 * The `DartCompletionCache` contains cached information from a prior code
 * completion operation.
 */
class DartCompletionCache extends CompletionCache {
  /**
   * A hash of the import directives
   * or `null` if nothing has been cached.
   */
  String _importKey;

  /**
   * Type suggestions based upon imports,
   * or `null` if nothing has been cached.
   */
  List<CompletionSuggestion> importedTypeSuggestions;

  /**
   * Suggestions for methods and functions that have void return type,
   * or `null` if nothing has been cached.
   */
  List<CompletionSuggestion> importedVoidReturnSuggestions;

  /**
   * Other suggestions based upon imports,
   * or `null` if nothing has been cached.
   */
  List<CompletionSuggestion> otherImportedSuggestions;

  /**
   * Suggestions for constructors
   * or `null` if nothing has been cached.
   */
  List<CompletionSuggestion> importedConstructorSuggestions;

  /**
   * A collection of all imported completions
   * or `null` if nothing has been cached.
   */
  HashSet<String> _importedCompletions;

  /**
   * A map of simple identifier to imported class element
   * or `null` if nothing has been cached.
   */
  Map<String, ClassElement> importedClassMap;

  /**
   * The [ClassElement] for Object.
   */
  ClassElement _objectClassElement;

  DartCompletionCache(AnalysisContext context, Source source)
      : super(context, source);

  /**
   * Return a hash of the import directives for the cached import info
   * or `null` if nothing has been cached.
   */
  String get importKey => _importKey;

  /**
   * Return the [ClassElement] for Object.
   */
  ClassElement get objectClassElement {
    if (_objectClassElement == null) {
      Source coreUri = context.sourceFactory.forUri('dart:core');
      LibraryElement coreLib = context.getLibraryElement(coreUri);
      _objectClassElement = coreLib.getType('Object');
    }
    return _objectClassElement;
  }

  /**
   * Given a resolved compilation unit, compute suggestions based upon the
   * imports and other dart files (e.g. "part" files) in the library containing
   * the given compilation unit. The returned future completes when the cache
   * is populated.
   *
   * If [shouldWaitForLowPrioritySuggestions] is `true` then the returned
   * future will complete when the cache is fully populated. If `false`,
   * the returned future will complete sooner, but the cache will not include
   * the lower priority suggestions added as a result of a global search.
   * In this case, those lower priority suggestions will be added later
   * when the index has been updated and the global search completes.
   */
  Future<bool> computeImportInfo(CompilationUnit unit,
      SearchEngine searchEngine, bool shouldWaitForLowPrioritySuggestions) {
    importedTypeSuggestions = <CompletionSuggestion>[];
    otherImportedSuggestions = <CompletionSuggestion>[];
    importedConstructorSuggestions = <CompletionSuggestion>[];
    importedVoidReturnSuggestions = <CompletionSuggestion>[];
    importedClassMap = new Map<String, ClassElement>();
    _importedCompletions = new HashSet<String>();

    // Assert that the compilation unit is resolved
    // and represents the expected source
    assert(unit.element.source == source);

    // Exclude elements from local library
    // because they are provided by LocalReferenceContributor
    Set<LibraryElement> excludedLibs = new Set<LibraryElement>();
    excludedLibs.add(unit.element.enclosingElement);

    // Determine the compilation unit defining the library containing
    // this compilation unit
    List<Source> libraries = context.getLibrariesContaining(source);
    assert(libraries != null);
    Source libSource = libraries.length > 0 ? libraries[0] : null;
    Future<CompilationUnit> futureLibUnit = _computeLibUnit(libSource, unit);

    // Include implicitly imported dart:core elements
    _addDartCoreSuggestions();

    // Include explicitly imported and part elements
    Future futureImportsCached = futureLibUnit.then((CompilationUnit libUnit) {
      _addImportedElemSuggestions(libSource, libUnit, excludedLibs);
      // Don't wait for search of lower relevance results to complete.
      // Set key indicating results are ready, and lower relevance results
      // will be added to the cache when the search completes.
      _importKey = _computeImportKey(unit);
      return true;
    });

    // Add non-imported elements as low relevance
    // after the imported element suggestions have been added
    Future<bool> futureAllCached = futureImportsCached.then((_) {
      return searchEngine
          .searchTopLevelDeclarations('')
          .then((List<SearchMatch> matches) {
        _addNonImportedElementSuggestions(matches, excludedLibs);
        return true;
      });
    });

    return shouldWaitForLowPrioritySuggestions
        ? futureAllCached
        : futureImportsCached;
  }

  /**
   * Return `true` if the import information is cached for the given
   * compilation unit.
   */
  bool isImportInfoCached(CompilationUnit unit) =>
      _importKey != null && _importKey == _computeImportKey(unit);

  /**
   * Add constructor suggestions for the given class.
   */
  void _addConstructorSuggestions(
      ClassElement classElem, int relevance, Source importForSource) {
    String className = classElem.name;
    for (ConstructorElement constructor in classElem.constructors) {
      if (!constructor.isPrivate) {
        CompletionSuggestion suggestion = createSuggestion(constructor,
            relevance: relevance, importForSource: importForSource);
        if (suggestion != null) {
          String name = suggestion.completion;
          name = name.length > 0 ? '$className.$name' : className;
          suggestion.completion = name;
          suggestion.selectionOffset = suggestion.completion.length;
          importedConstructorSuggestions.add(suggestion);
        }
      }
    }
  }

  /**
   * Add suggestions for implicitly imported elements in dart:core.
   */
  void _addDartCoreSuggestions() {
    Source coreUri = context.sourceFactory.forUri('dart:core');
    LibraryElement coreLib = context.getLibraryElement(coreUri);
    if (coreLib == null) {
      // If the core library has not been analyzed yet, then we cannot add any
      // suggestions from it.
      return;
    }
    Namespace coreNamespace =
        new NamespaceBuilder().createPublicNamespaceForLibrary(coreLib);
    coreNamespace.definedNames.forEach((String name, Element elem) {
      if (elem is ClassElement) {
        importedClassMap[name] = elem;
      }
      _addSuggestion(elem, DART_RELEVANCE_DEFAULT);
    });
  }

  /**
   * Add suggestions for explicitly imported and part elements in the given
   * library. Add libraries that should not have their elements suggested
   * even as low priority to [excludedLibs].
   */
  void _addImportedElemSuggestions(Source libSource, CompilationUnit libUnit,
      Set<LibraryElement> excludedLibs) {
    if (libUnit != null) {
      libUnit.directives.forEach((Directive directive) {
        if (directive is ImportDirective) {
          ImportElement importElem = directive.element;
          if (importElem != null && importElem.importedLibrary != null) {
            if (directive.prefix == null) {
              Namespace importNamespace = new NamespaceBuilder()
                  .createImportNamespaceForDirective(importElem);
              // Include top level elements
              importNamespace.definedNames.forEach((String name, Element elem) {
                if (elem is ClassElement) {
                  importedClassMap[name] = elem;
                }
                _addSuggestion(elem, DART_RELEVANCE_DEFAULT);
              });
            } else {
              // Exclude elements from prefixed imports
              // because they are provided by PrefixedElementContributor
              // Suggested by LibraryPrefixContributor
              // _addLibraryPrefixSuggestion(importElem);
              // excludedLibs.add(importElem.importedLibrary);
            }
          }
        } else if (directive is PartDirective) {
          CompilationUnitElement partElem = directive.element;
          if (partElem != null && partElem.source != source) {
            partElem.accept(new _NonLocalElementCacheVisitor(this));
          }
        }
      });
      if (libSource != source) {
        libUnit.element.accept(new _NonLocalElementCacheVisitor(this));
      }
    }
  }

  /**
   * Add suggestions for all top level elements in the context
   * excluding those elemnents for which suggestions have already been added.
   */
  void _addNonImportedElementSuggestions(
      List<SearchMatch> matches, Set<LibraryElement> excludedLibs) {
    // Exclude internal Dart SDK libraries
    for (var lib in context.sourceFactory.dartSdk.sdkLibraries) {
      if (lib.isInternal) {
        Source libUri = context.sourceFactory.forUri(lib.shortName);
        if (libUri != null) {
          LibraryElement libElem = context.getLibraryElement(libUri);
          if (libElem != null) {
            excludedLibs.add(libElem);
          }
        }
      }
    }

    AnalysisContext sdkContext = context.sourceFactory.dartSdk.context;
    matches.forEach((SearchMatch match) {
      if (match.kind == MatchKind.DECLARATION) {
        Element element = match.element;
        if ((element.context == context || element.context == sdkContext) &&
            element.isPublic &&
            !excludedLibs.contains(element.library) &&
            !_importedCompletions.contains(element.displayName)) {
          _addSuggestion(element, DART_RELEVANCE_LOW, importForSource: source);
        }
      }
    });
  }

  /**
   * Add a suggestion for the given element.
   */
  void _addSuggestion(Element element, int relevance,
      {Source importForSource}) {
    if (element is ExecutableElement) {
      // Do not suggest operators or local functions
      if (element.isOperator) {
        return;
      }
      if (element is FunctionElement) {
        if (element.enclosingElement is! CompilationUnitElement) {
          return;
        }
      }
    }

    CompletionSuggestion suggestion = createSuggestion(element,
        relevance: relevance, importForSource: importForSource);

    if (suggestion != null) {
      if (element is ExecutableElement) {
        DartType returnType = element.returnType;
        if (returnType != null && returnType.isVoid) {
          importedVoidReturnSuggestions.add(suggestion);
        } else {
          otherImportedSuggestions.add(suggestion);
        }
      } else if (element is FunctionTypeAliasElement) {
        importedTypeSuggestions.add(suggestion);
      } else if (element is ClassElement) {
        importedTypeSuggestions.add(suggestion);
        _addConstructorSuggestions(element, relevance, importForSource);
      } else {
        otherImportedSuggestions.add(suggestion);
      }
      _importedCompletions.add(suggestion.completion);
    }
  }

  /**
   * Compute the hash of the imports for the given compilation unit.
   */
  String _computeImportKey(CompilationUnit unit) {
    StringBuffer sb = new StringBuffer();
    unit.directives.forEach((Directive directive) {
      sb.write(directive.toSource());
    });
    return sb.toString();
  }

  /**
   * Compute the library unit for the given library source,
   * where the [unit] is the resolved compilation unit associated with [source].
   */
  Future<CompilationUnit> _computeLibUnit(
      Source libSource, CompilationUnit unit) {
    // If the sources are the same then we already have the library unit
    if (libSource == source) {
      return new Future.value(unit);
    }
    // If [source] is a part, then compute the library unit
    if (libSource != null) {
      return context.computeResolvedCompilationUnitAsync(libSource, libSource);
    }
    return new Future.value(null);
  }
}

/**
 * A visitor for building suggestions based upon the elements defined by
 * a source file contained in the same library but not the same as
 * the source in which the completions are being requested.
 */
class _NonLocalElementCacheVisitor extends GeneralizingElementVisitor {
  final DartCompletionCache cache;

  _NonLocalElementCacheVisitor(this.cache);

  @override
  void visitClassElement(ClassElement element) {
    cache._addSuggestion(element, DART_RELEVANCE_DEFAULT);
  }

  @override
  void visitCompilationUnitElement(CompilationUnitElement element) {
    element.visitChildren(this);
  }

  @override
  void visitElement(Element element) {
    // ignored
  }

  @override
  void visitFunctionElement(FunctionElement element) {
    cache._addSuggestion(element, DART_RELEVANCE_DEFAULT);
  }

  @override
  void visitFunctionTypeAliasElement(FunctionTypeAliasElement element) {
    cache._addSuggestion(element, DART_RELEVANCE_DEFAULT);
  }

  @override
  void visitTopLevelVariableElement(TopLevelVariableElement element) {
    cache._addSuggestion(element, DART_RELEVANCE_DEFAULT);
  }
}
