// 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 operation.analysis;

import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/computer/computer_highlights.dart';
import 'package:analysis_server/src/computer/computer_navigation.dart';
import 'package:analysis_server/src/computer/computer_occurrences.dart';
import 'package:analysis_server/src/computer/computer_outline.dart';
import 'package:analysis_server/src/computer/computer_overrides.dart';
import 'package:analysis_server/src/operation/operation.dart';
import 'package:analysis_server/src/protocol_server.dart' as protocol;
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/html.dart';
import 'package:analyzer/src/generated/source.dart';


/**
 * Schedules sending notifications for the given [file] using the resolved
 * [resolvedDartUnit].
 */
void scheduleNotificationOperations(AnalysisServer server, String file,
    LineInfo lineInfo, AnalysisContext context, CompilationUnit parsedDartUnit,
    CompilationUnit resolvedDartUnit, List<AnalysisError> errors) {
  // Only send notifications if the current context is the preferred
  // context for the file.  This avoids redundant notification messages
  // being sent to the client (see dartbug.com/22210).
  // TODO(paulberry): note that there is a small risk that this will cause
  // notifications to be lost if the preferred context for a file changes
  // while analysis is in progress (e.g. because the client sent an
  // analysis.setAnalysisRoots message).
  if (server.getAnalysisContext(file) != context) {
    return;
  }
  // Dart
  CompilationUnit dartUnit =
      resolvedDartUnit != null ? resolvedDartUnit : parsedDartUnit;
  if (resolvedDartUnit != null) {
    if (server.hasAnalysisSubscription(
        protocol.AnalysisService.HIGHLIGHTS,
        file)) {
      server.scheduleOperation(
          new _DartHighlightsOperation(file, resolvedDartUnit));
    }
    if (server.hasAnalysisSubscription(
        protocol.AnalysisService.NAVIGATION,
        file)) {
      server.scheduleOperation(
          new _DartNavigationOperation(file, resolvedDartUnit));
    }
    if (server.hasAnalysisSubscription(
        protocol.AnalysisService.OCCURRENCES,
        file)) {
      server.scheduleOperation(
          new _DartOccurrencesOperation(file, resolvedDartUnit));
    }
    if (server.hasAnalysisSubscription(
        protocol.AnalysisService.OVERRIDES,
        file)) {
      server.scheduleOperation(
          new _DartOverridesOperation(file, resolvedDartUnit));
    }
  }
  if (dartUnit != null) {
    if (server.hasAnalysisSubscription(
        protocol.AnalysisService.OUTLINE,
        file)) {
      server.scheduleOperation(
          new _DartOutlineOperation(file, lineInfo, dartUnit));
    }
  }
  // errors
  if (server.shouldSendErrorsNotificationFor(file)) {
    server.scheduleOperation(
        new _NotificationErrorsOperation(file, lineInfo, errors));
  }
}


void sendAnalysisNotificationErrors(AnalysisServer server, String file,
    LineInfo lineInfo, List<AnalysisError> errors) {
  try {
    if (errors == null) {
      errors = <AnalysisError>[];
    }
    var serverErrors =
        protocol.doAnalysisError_listFromEngine(lineInfo, errors);
    var params = new protocol.AnalysisErrorsParams(file, serverErrors);
    server.sendNotification(params.toNotification());
  } catch (exception, stackTrace) {
    server.sendServerErrorNotification(exception, stackTrace);
  }
}


void sendAnalysisNotificationHighlights(AnalysisServer server, String file,
    CompilationUnit dartUnit) {
  try {
    var regions = new DartUnitHighlightsComputer(dartUnit).compute();
    var params = new protocol.AnalysisHighlightsParams(file, regions);
    server.sendNotification(params.toNotification());
  } catch (exception, stackTrace) {
    server.sendServerErrorNotification(exception, stackTrace);
  }
}


void sendAnalysisNotificationNavigation(AnalysisServer server, String file,
    CompilationUnit dartUnit) {
  try {
    var computer = new DartUnitNavigationComputer(dartUnit);
    computer.compute();
    var params = new protocol.AnalysisNavigationParams(
        file,
        computer.regions,
        computer.targets,
        computer.files);
    server.sendNotification(params.toNotification());
  } catch (exception, stackTrace) {
    server.sendServerErrorNotification(exception, stackTrace);
  }
}


void sendAnalysisNotificationOccurrences(AnalysisServer server, String file,
    CompilationUnit dartUnit) {
  try {
    var occurrences = new DartUnitOccurrencesComputer(dartUnit).compute();
    var params = new protocol.AnalysisOccurrencesParams(file, occurrences);
    server.sendNotification(params.toNotification());
  } catch (exception, stackTrace) {
    server.sendServerErrorNotification(exception, stackTrace);
  }
}


void sendAnalysisNotificationOutline(AnalysisServer server, String file,
    LineInfo lineInfo, CompilationUnit dartUnit) {
  try {
    var computer = new DartUnitOutlineComputer(file, lineInfo, dartUnit);
    var outline = computer.compute();
    var params = new protocol.AnalysisOutlineParams(file, outline);
    server.sendNotification(params.toNotification());
  } catch (exception, stackTrace) {
    server.sendServerErrorNotification(exception, stackTrace);
  }
}


void sendAnalysisNotificationOverrides(AnalysisServer server, String file,
    CompilationUnit dartUnit) {
  try {
    var overrides = new DartUnitOverridesComputer(dartUnit).compute();
    var params = new protocol.AnalysisOverridesParams(file, overrides);
    server.sendNotification(params.toNotification());
  } catch (exception, stackTrace) {
    server.sendServerErrorNotification(exception, stackTrace);
  }
}


/**
 * Instances of [PerformAnalysisOperation] perform a single analysis task.
 */
class PerformAnalysisOperation extends ServerOperation {
  static const int IDLE_CACHE_SIZE = AnalysisOptionsImpl.DEFAULT_CACHE_SIZE;
  static const int WORKING_CACHE_SIZE = 512;

  final AnalysisContext context;
  final bool isContinue;

  PerformAnalysisOperation(this.context, this.isContinue);

  @override
  ServerOperationPriority get priority {
    if (_isPriorityContext) {
      if (isContinue) {
        return ServerOperationPriority.PRIORITY_ANALYSIS_CONTINUE;
      } else {
        return ServerOperationPriority.PRIORITY_ANALYSIS;
      }
    } else {
      if (isContinue) {
        return ServerOperationPriority.ANALYSIS_CONTINUE;
      } else {
        return ServerOperationPriority.ANALYSIS;
      }
    }
  }

  bool get _isPriorityContext =>
      context is InternalAnalysisContext &&
          (context as InternalAnalysisContext).prioritySources.isNotEmpty;

  @override
  void perform(AnalysisServer server) {
    //
    // TODO(brianwilkerson) Add an optional function-valued parameter to
    // performAnalysisTask that will be called when the task has been computed
    // but before it is performed and send notification in the function:
    //
    // AnalysisResult result = context.performAnalysisTask((taskDescription) {
    //   sendStatusNotification(context.toString(), taskDescription);
    // });
    if (!isContinue) {
      _setCacheSize(WORKING_CACHE_SIZE);
    }
    // prepare results
    AnalysisResult result = context.performAnalysisTask();
    List<ChangeNotice> notices = result.changeNotices;
    if (notices == null) {
      _setCacheSize(IDLE_CACHE_SIZE);
      server.sendContextAnalysisDoneNotifications(
          context,
          AnalysisDoneReason.COMPLETE);
      return;
    }
    // process results
    _sendNotices(server, notices);
    _updateIndex(server, notices);
    // continue analysis
    server.addOperation(new PerformAnalysisOperation(context, true));
  }

  /**
   * Send the information in the given list of notices back to the client.
   */
  void _sendNotices(AnalysisServer server, List<ChangeNotice> notices) {
    for (int i = 0; i < notices.length; i++) {
      ChangeNotice notice = notices[i];
      Source source = notice.source;
      String file = source.fullName;
      // Dart
      CompilationUnit parsedDartUnit = notice.parsedDartUnit;
      CompilationUnit resolvedDartUnit = notice.resolvedDartUnit;
      scheduleNotificationOperations(
          server,
          file,
          notice.lineInfo,
          context,
          parsedDartUnit,
          resolvedDartUnit,
          notice.errors);
      // done
      server.fileAnalyzed(notice);
    }
  }

  void _setCacheSize(int cacheSize) {
    AnalysisOptionsImpl options =
        new AnalysisOptionsImpl.con1(context.analysisOptions);
    options.cacheSize = cacheSize;
    context.analysisOptions = options;
  }

  void _updateIndex(AnalysisServer server, List<ChangeNotice> notices) {
    Index index = server.index;
    if (index == null) {
      return;
    }
    for (ChangeNotice notice in notices) {
      String file = notice.source.fullName;
      // Dart
      try {
        CompilationUnit dartUnit = notice.resolvedDartUnit;
        if (dartUnit != null) {
          server.addOperation(new _DartIndexOperation(context, file, dartUnit));
        }
      } catch (exception, stackTrace) {
        server.sendServerErrorNotification(exception, stackTrace);
      }
      // HTML
      try {
        HtmlUnit htmlUnit = notice.resolvedHtmlUnit;
        if (htmlUnit != null) {
          server.addOperation(new _HtmlIndexOperation(context, file, htmlUnit));
        }
      } catch (exception, stackTrace) {
        server.sendServerErrorNotification(exception, stackTrace);
      }
    }
  }
}


class _DartHighlightsOperation extends _DartNotificationOperation {
  _DartHighlightsOperation(String file, CompilationUnit unit)
      : super(file, unit);

  @override
  void perform(AnalysisServer server) {
    sendAnalysisNotificationHighlights(server, file, unit);
  }
}


class _DartIndexOperation extends _SingleFileOperation {
  final AnalysisContext context;
  final CompilationUnit unit;

  _DartIndexOperation(this.context, String file, this.unit) : super(file);

  @override
  ServerOperationPriority get priority {
    return ServerOperationPriority.ANALYSIS_INDEX;
  }

  @override
  void perform(AnalysisServer server) {
    Index index = server.index;
    index.indexUnit(context, unit);
  }
}


class _DartNavigationOperation extends _DartNotificationOperation {
  _DartNavigationOperation(String file, CompilationUnit unit)
      : super(file, unit);

  @override
  void perform(AnalysisServer server) {
    sendAnalysisNotificationNavigation(server, file, unit);
  }
}


abstract class _DartNotificationOperation extends _SingleFileOperation {
  final CompilationUnit unit;

  _DartNotificationOperation(String file, this.unit) : super(file);

  @override
  ServerOperationPriority get priority {
    return ServerOperationPriority.ANALYSIS_NOTIFICATION;
  }
}


class _DartOccurrencesOperation extends _DartNotificationOperation {
  _DartOccurrencesOperation(String file, CompilationUnit unit)
      : super(file, unit);

  @override
  void perform(AnalysisServer server) {
    sendAnalysisNotificationOccurrences(server, file, unit);
  }
}


class _DartOutlineOperation extends _DartNotificationOperation {
  final LineInfo lineInfo;

  _DartOutlineOperation(String file, this.lineInfo, CompilationUnit unit)
      : super(file, unit);

  @override
  void perform(AnalysisServer server) {
    sendAnalysisNotificationOutline(server, file, lineInfo, unit);
  }
}


class _DartOverridesOperation extends _DartNotificationOperation {
  _DartOverridesOperation(String file, CompilationUnit unit)
      : super(file, unit);

  @override
  void perform(AnalysisServer server) {
    sendAnalysisNotificationOverrides(server, file, unit);
  }
}


class _HtmlIndexOperation extends _SingleFileOperation {
  final AnalysisContext context;
  final HtmlUnit unit;

  _HtmlIndexOperation(this.context, String file, this.unit) : super(file);

  @override
  ServerOperationPriority get priority {
    return ServerOperationPriority.ANALYSIS_INDEX;
  }

  @override
  void perform(AnalysisServer server) {
    Index index = server.index;
    index.indexHtmlUnit(context, unit);
  }
}


class _NotificationErrorsOperation extends _SingleFileOperation {
  final LineInfo lineInfo;
  final List<AnalysisError> errors;

  _NotificationErrorsOperation(String file, this.lineInfo, this.errors)
      : super(file);

  @override
  ServerOperationPriority get priority {
    return ServerOperationPriority.ANALYSIS_NOTIFICATION;
  }

  @override
  void perform(AnalysisServer server) {
    sendAnalysisNotificationErrors(server, file, lineInfo, errors);
  }
}


abstract class _SingleFileOperation extends SourceSensitiveOperation {
  final String file;

  _SingleFileOperation(this.file);

  @override
  bool shouldBeDiscardedOnSourceChange(Source source) {
    return source.fullName == file;
  }
}
