// Copyright (c) 2016, 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 analysis_server.src.single_context_manager;

import 'dart:async';
import 'dart:core';
import 'dart:math' as math;

import 'package:analysis_server/src/context_manager.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/plugin/resolver_provider.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/util/glob.dart';
import 'package:path/path.dart' as path;
import 'package:watcher/watcher.dart';

/**
 * Implementation of [ContextManager] that supports only one [AnalysisContext].
 * So, sources from all analysis roots are added to this single context. All
 * features that could otherwise cause creating additional contexts, such as
 * presence of `pubspec.yaml` or `.packages` files, or analysis options files
 * are ignored.
 */
class SingleContextManager implements ContextManager {
  /**
   * The [ResourceProvider] using which paths are converted into [Resource]s.
   */
  final ResourceProvider resourceProvider;

  /**
   * The context used to work with file system paths.
   */
  path.Context pathContext;

  /**
   * The manager used to access the SDK that should be associated with a
   * particular context.
   */
  final DartSdkManager sdkManager;

  /**
   * A function that will return a [UriResolver] that can be used to resolve
   * `package:` URIs.
   */
  final ResolverProvider packageResolverProvider;

  /**
   * A list of the globs used to determine which files should be analyzed.
   */
  final List<Glob> analyzedFilesGlobs;

  /**
   * The default options used to create new analysis contexts.
   */
  final AnalysisOptionsImpl defaultContextOptions;

  /**
   * The list of included paths (folders and files) most recently passed to
   * [setRoots].
   */
  List<String> includedPaths = <String>[];

  /**
   * The list of excluded paths (folders and files) most recently passed to
   * [setRoots].
   */
  List<String> excludedPaths = <String>[];

  /**
   * The map of package roots most recently passed to [setRoots].
   */
  Map<String, String> packageRoots = <String, String>{};

  /**
   * Same as [packageRoots], except that source folders have been normalized
   * and non-folders have been removed.
   */
  Map<String, String> normalizedPackageRoots = <String, String>{};

  @override
  ContextManagerCallbacks callbacks;

  /**
   * The analysis driver which analyses everything.
   */
  AnalysisDriver analysisDriver;

  /**
   * The context in which everything is being analyzed.
   */
  AnalysisContext context;

  /**
   * The folder associated with the context.
   */
  Folder contextFolder;

  /**
   * The current watch subscriptions.
   */
  Map<String, StreamSubscription<WatchEvent>> watchSubscriptions =
      new Map<String, StreamSubscription<WatchEvent>>();

  /**
   * The [packageResolverProvider] must not be `null`.
   */
  SingleContextManager(
      this.resourceProvider,
      this.sdkManager,
      this.packageResolverProvider,
      this.analyzedFilesGlobs,
      this.defaultContextOptions) {
    pathContext = resourceProvider.pathContext;
  }

  @override
  Iterable<AnalysisContext> get analysisContexts =>
      context == null ? <AnalysisContext>[] : <AnalysisContext>[context];

  @override
  Map<Folder, AnalysisDriver> get driverMap => {contextFolder: analysisDriver};

  @override
  Map<Folder, AnalysisContext> get folderMap => {contextFolder: context};

  @override
  List<AnalysisContext> contextsInAnalysisRoot(Folder analysisRoot) {
    if (context == null || !includedPaths.contains(analysisRoot.path)) {
      return <AnalysisContext>[];
    }
    return <AnalysisContext>[context];
  }

  @override
  AnalysisContext getContextFor(String path) {
    if (context == null) {
      return null;
    } else if (_isContainedIn(includedPaths, path)) {
      return context;
    }
    return null;
  }

  @override
  AnalysisDriver getDriverFor(String path) {
    throw new UnimplementedError(
        'Unexpected invocation of getDriverFor in SingleContextManager');
  }

  @override
  List<AnalysisDriver> getDriversInAnalysisRoot(Folder analysisRoot) {
    throw new UnimplementedError(
        'Unexpected invocation of getDriversInAnalysisRoot in SingleContextManager');
  }

  @override
  bool isIgnored(String path) {
    return !_isContainedIn(includedPaths, path) || _isExcludedPath(path);
  }

  @override
  bool isInAnalysisRoot(String path) {
    return _isContainedIn(includedPaths, path) &&
        !_isContainedIn(excludedPaths, path);
  }

  @override
  void refresh(List<Resource> roots) {
    if (context != null) {
      callbacks.removeContext(contextFolder, null);
      context.dispose();
      context = null;
      contextFolder = null;
      _cancelCurrentWatchSubscriptions();
      setRoots(includedPaths, excludedPaths, packageRoots);
    }
  }

  @override
  void setRoots(List<String> includedPaths, List<String> excludedPaths,
      Map<String, String> packageRoots) {
    includedPaths = _nonOverlappingPaths(includedPaths);
    excludedPaths = _nonOverlappingPaths(excludedPaths);
    this.packageRoots = packageRoots;
    _updateNormalizedPackageRoots();
    // Update context path.
    {
      String contextPath = _commonPrefix(includedPaths);
      Folder contextFolder = resourceProvider.getFolder(contextPath);
      if (contextFolder != this.contextFolder) {
        if (context != null) {
          callbacks.moveContext(this.contextFolder, contextFolder);
        }
        this.contextFolder = contextFolder;
      }
    }
    // Start new watchers and cancel old ones.
    {
      Map<String, StreamSubscription<WatchEvent>> newSubscriptions =
          new Map<String, StreamSubscription<WatchEvent>>();
      for (String includedPath in includedPaths) {
        Resource resource = resourceProvider.getResource(includedPath);
        if (resource is Folder) {
          // Extract the existing subscription or create a new one.
          StreamSubscription<WatchEvent> subscription =
              watchSubscriptions.remove(includedPath);
          if (subscription == null) {
            subscription = resource.changes.listen(_handleWatchEvent);
          }
          // Remember the subscription.
          newSubscriptions[includedPath] = subscription;
        }
        _cancelCurrentWatchSubscriptions();
        this.watchSubscriptions = newSubscriptions;
      }
    }
    // Create or update the analysis context.
    if (context == null) {
      context = callbacks.addContext(contextFolder, defaultContextOptions);
      ChangeSet changeSet =
          _buildChangeSet(added: _includedFiles(includedPaths, excludedPaths));
      callbacks.applyChangesToContext(contextFolder, changeSet);
    } else {
      // TODO(brianwilkerson) Optimize this.
      List<File> oldFiles =
          _includedFiles(this.includedPaths, this.excludedPaths);
      List<File> newFiles = _includedFiles(includedPaths, excludedPaths);
      ChangeSet changeSet = _buildChangeSet(
          added: _diff(newFiles, oldFiles), removed: _diff(oldFiles, newFiles));
      callbacks.applyChangesToContext(contextFolder, changeSet);
    }
    this.includedPaths = includedPaths;
    this.excludedPaths = excludedPaths;
  }

  /**
   * Recursively add the given [resource] (if it's a file) or its children (if
   * it's a folder) to the [addedFiles].
   */
  void _addFilesInResource(
      List<File> addedFiles, Resource resource, List<String> excludedPaths) {
    if (_isImplicitlyExcludedResource(resource)) {
      return;
    }
    String path = resource.path;
    if (_isEqualOrWithinAny(excludedPaths, path)) {
      return;
    }
    if (resource is File) {
      if (_matchesAnyAnalyzedFilesGlob(path) && resource.exists) {
        addedFiles.add(resource);
      }
    } else if (resource is Folder) {
      for (Resource child in _getChildrenSafe(resource)) {
        _addFilesInResource(addedFiles, child, excludedPaths);
      }
    }
  }

  ChangeSet _buildChangeSet({List<File> added, List<File> removed}) {
    ChangeSet changeSet = new ChangeSet();
    if (added != null) {
      for (File file in added) {
        Source source = createSourceInContext(context, file);
        changeSet.addedSource(source);
      }
    }
    if (removed != null) {
      for (File file in removed) {
        Source source = createSourceInContext(context, file);
        changeSet.removedSource(source);
      }
    }
    return changeSet;
  }

  void _cancelCurrentWatchSubscriptions() {
    for (StreamSubscription<WatchEvent> subscription
        in watchSubscriptions.values) {
      subscription.cancel();
    }
    watchSubscriptions.clear();
  }

  String _commonPrefix(List<String> paths) {
    if (paths.isEmpty) {
      return '';
    }
    List<String> left = pathContext.split(paths[0]);
    int count = left.length;
    for (int i = 1; i < paths.length; i++) {
      List<String> right = pathContext.split(paths[i]);
      count = _commonComponents(left, count, right);
    }
    return pathContext.joinAll(left.sublist(0, count));
  }

  List<Resource> _existingResources(List<String> pathList) {
    List<Resource> resources = <Resource>[];
    for (String path in pathList) {
      Resource resource = resourceProvider.getResource(path);
      if (resource is Folder) {
        resources.add(resource);
      } else if (!resource.exists) {
        // Non-existent resources are ignored.  TODO(paulberry): we should set
        // up a watcher to ensure that if the resource appears later, we will
        // begin analyzing it.
      } else if (resource is File) {
        resources.add(resource);
      } else {
        throw new UnimplementedError('$path is not a folder. '
            'Only support for file and folder analysis is implemented.');
      }
    }
    return resources;
  }

  void _handleWatchEvent(WatchEvent event) {
    String path = event.path;
    // Ignore if excluded.
    if (_isExcludedPath(path)) {
      return;
    }
    // Ignore if not in a root.
    if (!_isContainedIn(includedPaths, path)) {
      return;
    }
    // Handle the change.
    switch (event.type) {
      case ChangeType.ADD:
        Resource resource = resourceProvider.getResource(path);
        if (resource is File) {
          if (_matchesAnyAnalyzedFilesGlob(path)) {
            callbacks.applyChangesToContext(
                contextFolder, _buildChangeSet(added: <File>[resource]));
          }
        }
        break;
      case ChangeType.REMOVE:
        List<Source> sources = context.getSourcesWithFullName(path);
        if (!sources.isEmpty) {
          ChangeSet changeSet = new ChangeSet();
          sources.forEach(changeSet.removedSource);
          callbacks.applyChangesToContext(contextFolder, changeSet);
        }
        break;
      case ChangeType.MODIFY:
        List<Source> sources = context.getSourcesWithFullName(path);
        if (!sources.isEmpty) {
          ChangeSet changeSet = new ChangeSet();
          sources.forEach(changeSet.changedSource);
          callbacks.applyChangesToContext(contextFolder, changeSet);
        }
        break;
    }
  }

  List<File> _includedFiles(
      List<String> includedPaths, List<String> excludedPaths) {
    List<Resource> includedResources = _existingResources(includedPaths);
    List<File> includedFiles = <File>[];
    for (Resource resource in includedResources) {
      _addFilesInResource(includedFiles, resource, excludedPaths);
    }
    return includedFiles;
  }

  bool _isContainedIn(List<String> pathList, String path) {
    for (String pathInList in pathList) {
      if (_isEqualOrWithin(pathInList, path)) {
        return true;
      }
    }
    return false;
  }

  bool _isEqualOrWithin(String parent, String child) {
    return child == parent || pathContext.isWithin(parent, child);
  }

  bool _isEqualOrWithinAny(List<String> parents, String child) {
    for (String parent in parents) {
      if (_isEqualOrWithin(parent, child)) {
        return true;
      }
    }
    return false;
  }

  /**
   * Return `true` if the given [path] should be excluded, using explicit
   * or implicit rules.
   */
  bool _isExcludedPath(String path) {
    List<String> parts = resourceProvider.pathContext.split(path);
    // Implicit rules.
    for (String part in parts) {
      if (part.startsWith('.')) {
        return true;
      }
    }
    // Explicitly excluded paths.
    if (_isEqualOrWithinAny(excludedPaths, path)) {
      return true;
    }
    // OK
    return false;
  }

  /**
   * Return `true` if the given [resource] and children should be excluded
   * because of some implicit exclusion rules, e.g. `.name`.
   */
  bool _isImplicitlyExcludedResource(Resource resource) {
    String shortName = resource.shortName;
    if (shortName.startsWith('.')) {
      return true;
    }
    return false;
  }

  /**
   * Return `true` if the given [path] matches one of the [analyzedFilesGlobs].
   */
  bool _matchesAnyAnalyzedFilesGlob(String path) {
    for (Glob glob in analyzedFilesGlobs) {
      if (glob.matches(path)) {
        return true;
      }
    }
    return false;
  }

  /**
   * Return a list consisting of the elements from [pathList] that describe the
   * minimal set of directories that include everything in the original list of
   * paths and nothing more. In particular:
   *
   *  * if a path is in the input list multiple times it will appear at most
   *    once in the output list, and
   *  * if a directory D and a subdirectory of it are both in the input list
   *    then only the directory D will be in the output list.
   *
   * The original list is not modified.
   */
  List<String> _nonOverlappingPaths(List<String> pathList) {
    List<String> sortedPaths = new List<String>.from(pathList);
    sortedPaths.sort((a, b) => a.length - b.length);
    int pathCount = sortedPaths.length;
    for (int i = pathCount - 1; i > 0; i--) {
      String path = sortedPaths[i];
      for (int j = 0; j < i; j++) {
        if (_isEqualOrWithin(path, sortedPaths[j])) {
          sortedPaths.removeAt(i);
          break;
        }
      }
    }
    return sortedPaths;
  }

  /**
   *  Normalize all package root sources by mapping them to folders on the
   * filesystem.  Ignore any package root sources that aren't folders.
   */
  void _updateNormalizedPackageRoots() {
    normalizedPackageRoots = <String, String>{};
    packageRoots.forEach((String sourcePath, String targetPath) {
      Resource resource = resourceProvider.getResource(sourcePath);
      if (resource is Folder) {
        normalizedPackageRoots[resource.path] = targetPath;
      }
    });
  }

  /**
   * Create and return a source representing the given [file] within the given
   * [context].
   */
  static Source createSourceInContext(AnalysisContext context, File file) {
    // TODO(brianwilkerson) Optimize this, by allowing support for source
    // factories to restore URI's from a file path rather than a source.
    Source source = file.createSource();
    if (context == null) {
      return source;
    }
    Uri uri = context.sourceFactory.restoreUri(source);
    return file.createSource(uri);
  }

  static int _commonComponents(
      List<String> left, int count, List<String> right) {
    int max = math.min(count, right.length);
    for (int i = 0; i < max; i++) {
      if (left[i] != right[i]) {
        return i;
      }
    }
    return max;
  }

  /**
   * Return a list of all the files in the [left] that are not in the [right].
   */
  static List<File> _diff(List<File> left, List<File> right) {
    List<File> diff = new List.from(left);
    for (File file in right) {
      diff.remove(file);
    }
    return diff;
  }

  static List<Resource> _getChildrenSafe(Folder folder) {
    try {
      return folder.getChildren();
    } on FileSystemException {
      // The folder either doesn't exist or cannot be read.
      // Either way, there are no children.
      return const <Resource>[];
    }
  }
}
