// Copyright (c) 2017, 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.

import 'dart:collection';

import 'package:analysis_server/protocol/protocol_generated.dart' as server;
import 'package:analysis_server/src/channel/channel.dart';
import 'package:analysis_server/src/plugin/result_collector.dart';
import 'package:analysis_server/src/plugin/result_converter.dart';
import 'package:analysis_server/src/plugin/result_merger.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_constants.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;

/**
 * The object used to coordinate the results of notifications from the analysis
 * server and multiple plugins.
 */
class NotificationManager {
  /**
   * The identifier used to identify results from the server.
   */
  static const String serverId = 'server';

  /**
   * The channel used to send notifications to the client.
   */
  final ServerCommunicationChannel channel;

  /**
   * The resource provider used to get the path context.
   */
  final ResourceProvider provider;

  /**
   * A list of the paths of files and directories that are included for analysis.
   */
  List<String> includedPaths = <String>[];

  /**
   * A list of the paths of files and directories that are excluded from
   * analysis.
   */
  List<String> excludedPaths = <String>[];

  /**
   * The current set of subscriptions to which the client has subscribed.
   */
  Map<server.AnalysisService, Set<String>> currentSubscriptions =
      <server.AnalysisService, Set<String>>{};

  /**
   * The collector being used to collect the analysis errors from the plugins.
   */
  ResultCollector<List<AnalysisError>> errors;

  /**
   * The collector being used to collect the folding regions from the plugins.
   */
  ResultCollector<List<FoldingRegion>> folding;

  /**
   * The collector being used to collect the highlight regions from the plugins.
   */
  ResultCollector<List<HighlightRegion>> highlights;

  /**
   * The collector being used to collect the navigation parameters from the
   * plugins.
   */
  ResultCollector<server.AnalysisNavigationParams> navigation;

  /**
   * The collector being used to collect the occurrences from the plugins.
   */
  ResultCollector<List<Occurrences>> occurrences;

  /**
   * The collector being used to collect the outlines from the plugins.
   */
  ResultCollector<List<Outline>> outlines;

  /**
   * The object used to convert results.
   */
  final ResultConverter converter = new ResultConverter();

  /**
   * The object used to merge results.
   */
  final ResultMerger merger = new ResultMerger();

  /**
   * Initialize a newly created notification manager.
   */
  NotificationManager(this.channel, this.provider) {
    errors = new ResultCollector<List<AnalysisError>>(serverId,
        predicate: _isIncluded);
    folding = new ResultCollector<List<FoldingRegion>>(serverId);
    highlights = new ResultCollector<List<HighlightRegion>>(serverId);
    navigation = new ResultCollector<server.AnalysisNavigationParams>(serverId);
    occurrences = new ResultCollector<List<Occurrences>>(serverId);
    outlines = new ResultCollector<List<Outline>>(serverId);
  }

  /**
   * Handle the given [notification] from the plugin with the given [pluginId].
   */
  void handlePluginNotification(
      String pluginId, plugin.Notification notification) {
    String event = notification.event;
    switch (event) {
      case plugin.ANALYSIS_NOTIFICATION_ERRORS:
        plugin.AnalysisErrorsParams params =
            new plugin.AnalysisErrorsParams.fromNotification(notification);
        recordAnalysisErrors(pluginId, params.file, params.errors);
        break;
      case plugin.ANALYSIS_NOTIFICATION_FOLDING:
        plugin.AnalysisFoldingParams params =
            new plugin.AnalysisFoldingParams.fromNotification(notification);
        recordFoldingRegions(pluginId, params.file, params.regions);
        break;
      case plugin.ANALYSIS_NOTIFICATION_HIGHLIGHTS:
        plugin.AnalysisHighlightsParams params =
            new plugin.AnalysisHighlightsParams.fromNotification(notification);
        recordHighlightRegions(pluginId, params.file, params.regions);
        break;
      case plugin.ANALYSIS_NOTIFICATION_NAVIGATION:
        plugin.AnalysisNavigationParams params =
            new plugin.AnalysisNavigationParams.fromNotification(notification);
        recordNavigationParams(pluginId, params.file,
            converter.convertAnalysisNavigationParams(params));
        break;
      case plugin.ANALYSIS_NOTIFICATION_OCCURRENCES:
        plugin.AnalysisOccurrencesParams params =
            new plugin.AnalysisOccurrencesParams.fromNotification(notification);
        recordOccurrences(pluginId, params.file, params.occurrences);
        break;
      case plugin.ANALYSIS_NOTIFICATION_OUTLINE:
        plugin.AnalysisOutlineParams params =
            new plugin.AnalysisOutlineParams.fromNotification(notification);
        recordOutlines(pluginId, params.file, params.outline);
        break;
      case plugin.PLUGIN_NOTIFICATION_ERROR:
        plugin.PluginErrorParams params =
            new plugin.PluginErrorParams.fromNotification(notification);
        // TODO(brianwilkerson) There is no indication for the client as to the
        // fact that the error came from a plugin, let alone which plugin it
        // came from. We should consider whether we really want to send them to
        // the client.
        channel.sendNotification(new server.ServerErrorParams(
                params.isFatal, params.message, params.stackTrace)
            .toNotification());
        break;
    }
  }

  /**
   * Record error information from the plugin with the given [pluginId] for the
   * file with the given [filePath].
   */
  void recordAnalysisErrors(
      String pluginId, String filePath, List<AnalysisError> errorData) {
    if (errors.isCollectingFor(filePath)) {
      errors.putResults(filePath, pluginId, errorData);
      List<List<AnalysisError>> unmergedErrors = errors.getResults(filePath);
      List<AnalysisError> mergedErrors =
          merger.mergeAnalysisErrors(unmergedErrors);
      channel.sendNotification(
          new server.AnalysisErrorsParams(filePath, mergedErrors)
              .toNotification());
    }
  }

  /**
   * Record folding information from the plugin with the given [pluginId] for
   * the file with the given [filePath].
   */
  void recordFoldingRegions(
      String pluginId, String filePath, List<FoldingRegion> foldingData) {
    if (folding.isCollectingFor(filePath)) {
      folding.putResults(filePath, pluginId, foldingData);
      List<List<FoldingRegion>> unmergedFolding = folding.getResults(filePath);
      List<FoldingRegion> mergedFolding =
          merger.mergeFoldingRegions(unmergedFolding);
      channel.sendNotification(
          new server.AnalysisFoldingParams(filePath, mergedFolding)
              .toNotification());
    }
  }

  /**
   * Record highlight information from the plugin with the given [pluginId] for
   * the file with the given [filePath].
   */
  void recordHighlightRegions(
      String pluginId, String filePath, List<HighlightRegion> highlightData) {
    if (highlights.isCollectingFor(filePath)) {
      highlights.putResults(filePath, pluginId, highlightData);
      List<List<HighlightRegion>> unmergedHighlights =
          highlights.getResults(filePath);
      List<HighlightRegion> mergedHighlights =
          merger.mergeHighlightRegions(unmergedHighlights);
      channel.sendNotification(
          new server.AnalysisHighlightsParams(filePath, mergedHighlights)
              .toNotification());
    }
  }

  /**
   * Record navigation information from the plugin with the given [pluginId] for
   * the file with the given [filePath].
   */
  void recordNavigationParams(String pluginId, String filePath,
      server.AnalysisNavigationParams navigationData) {
    if (navigation.isCollectingFor(filePath)) {
      navigation.putResults(filePath, pluginId, navigationData);
      List<server.AnalysisNavigationParams> unmergedNavigations =
          navigation.getResults(filePath);
      server.AnalysisNavigationParams mergedNavigations =
          merger.mergeNavigation(unmergedNavigations);
      channel.sendNotification(mergedNavigations.toNotification());
    }
  }

  /**
   * Record occurrences information from the plugin with the given [pluginId]
   * for the file with the given [filePath].
   */
  void recordOccurrences(
      String pluginId, String filePath, List<Occurrences> occurrencesData) {
    if (occurrences.isCollectingFor(filePath)) {
      occurrences.putResults(filePath, pluginId, occurrencesData);
      List<List<Occurrences>> unmergedOccurrences =
          occurrences.getResults(filePath);
      List<Occurrences> mergedOccurrences =
          merger.mergeOccurrences(unmergedOccurrences);
      channel.sendNotification(
          new server.AnalysisOccurrencesParams(filePath, mergedOccurrences)
              .toNotification());
    }
  }

  /**
   * Record outline information from the plugin with the given [pluginId] for
   * the file with the given [filePath].
   */
  void recordOutlines(
      String pluginId, String filePath, List<Outline> outlineData) {
    if (outlines.isCollectingFor(filePath)) {
      outlines.putResults(filePath, pluginId, outlineData);
      List<List<Outline>> unmergedOutlines = outlines.getResults(filePath);
      List<Outline> mergedOutlines = merger.mergeOutline(unmergedOutlines);
      channel.sendNotification(new server.AnalysisOutlineParams(
              filePath, server.FileKind.LIBRARY, mergedOutlines[0])
          .toNotification());
    }
  }

  /**
   * Set the lists of [included] and [excluded] files.
   */
  void setAnalysisRoots(List<String> included, List<String> excluded) {
    includedPaths = included;
    excludedPaths = excluded;
  }

  /**
   * Set the current subscriptions to the given set of [newSubscriptions].
   */
  void setSubscriptions(
      Map<server.AnalysisService, Set<String>> newSubscriptions) {
    /**
     * Return the collector associated with the given service, or `null` if the
     * service is not handled by this manager.
     */
    ResultCollector collectorFor(server.AnalysisService service) {
      switch (service) {
        case server.AnalysisService.FOLDING:
          return folding;
        case server.AnalysisService.HIGHLIGHTS:
          return highlights;
        case server.AnalysisService.NAVIGATION:
          return navigation;
        case server.AnalysisService.OCCURRENCES:
          return occurrences;
        case server.AnalysisService.OUTLINE:
          return outlines;
      }
      return null;
    }

    Set<server.AnalysisService> services =
        new HashSet<server.AnalysisService>();
    services.addAll(currentSubscriptions.keys);
    services.addAll(newSubscriptions.keys);
    services.forEach((server.AnalysisService service) {
      ResultCollector collector = collectorFor(service);
      if (collector != null) {
        Set<String> currentPaths = currentSubscriptions[service];
        Set<String> newPaths = newSubscriptions[service];
        if (currentPaths == null) {
          if (newPaths == null) {
            // This should not happen.
            return;
          }
          // All of the [newPaths] need to be added.
          newPaths.forEach((String filePath) {
            collector.startCollectingFor(filePath);
          });
        } else if (newPaths == null) {
          // All of the [currentPaths] need to be removed.
          currentPaths.forEach((String filePath) {
            collector.stopCollectingFor(filePath);
          });
        } else {
          // Compute the difference of the two sets.
          newPaths.forEach((String filePath) {
            if (!currentPaths.contains(filePath)) {
              collector.startCollectingFor(filePath);
            }
          });
          currentPaths.forEach((String filePath) {
            if (!newPaths.contains(filePath)) {
              collector.stopCollectingFor(filePath);
            }
          });
        }
      }
    });
    currentSubscriptions = newSubscriptions;
  }

  /**
   * Return `true` if errors should be collected for the file with the given
   * [path] (because it is being analyzed).
   */
  bool _isIncluded(String path) {
    bool isIncluded() {
      for (String includedPath in includedPaths) {
        if (provider.pathContext.isWithin(includedPath, path) ||
            provider.pathContext.equals(includedPath, path)) {
          return true;
        }
      }
      return false;
    }

    bool isExcluded() {
      for (String excludedPath in excludedPaths) {
        if (provider.pathContext.isWithin(excludedPath, path)) {
          return true;
        }
      }
      return false;
    }

    // TODO(brianwilkerson) Return false if error notifications are globally
    // disabled.
    return isIncluded() && !isExcluded();
  }
}
