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

part of dart.developer;

/// Service protocol is the protocol that a client like the Observatory
/// could use to access the services provided by the Dart VM for
/// debugging and inspecting Dart programs. This class encapsulates the
/// version number and Uri for accessing this service.
class ServiceProtocolInfo {
  /// The major version of the protocol. If the running Dart environment does
  /// not support the service protocol, this is 0.
  final int majorVersion = _getServiceMajorVersion();

  /// The minor version of the protocol. If the running Dart environment does
  /// not support the service protocol, this is 0.
  final int minorVersion = _getServiceMinorVersion();

  /// The Uri to connect to the debugger client hosted by the service. If the
  /// web server is not running, this will be null.
  final Uri? serverUri;

  /// The Uri to connect to the service via web socket. If the web server is
  /// not running, this will be null.
  Uri? get serverWebSocketUri {
    Uri? uri = serverUri;
    if (uri != null) {
      final pathSegments = <String>[];
      if (uri.pathSegments.isNotEmpty) {
        pathSegments.addAll(uri.pathSegments.where(
          // Strip out the empty string that appears at the end of path segments.
          // Empty string elements will result in an extra '/' being added to the
          // URI.
          (s) => s.isNotEmpty,
        ));
      }
      pathSegments.add('ws');
      uri = uri.replace(scheme: 'ws', pathSegments: pathSegments);
    }
    return uri;
  }

  ServiceProtocolInfo(this.serverUri);

  String toString() {
    if (serverUri != null) {
      return 'Dart VM Service Protocol v$majorVersion.$minorVersion '
          'listening on $serverUri';
    } else {
      return 'Dart VM Service Protocol v$majorVersion.$minorVersion';
    }
  }
}

/// Access information about the service protocol and control the web server
/// that provides access to the services provided by the Dart VM for
/// debugging and inspecting Dart programs.
class Service {
  /// Get information about the service protocol (version number and
  /// Uri to access the service).
  static Future<ServiceProtocolInfo> getInfo() async {
    // Port to receive response from service isolate.
    final RawReceivePort receivePort =
        new RawReceivePort(null, 'Service.getInfo');
    final Completer<String?> completer = new Completer<String?>();
    receivePort.handler = (String? uriString) => completer.complete(uriString);
    // Request the information from the service isolate.
    _getServerInfo(receivePort.sendPort);
    // Await the response from the service isolate.
    String? uriString = await completer.future;
    Uri? uri = uriString == null ? null : Uri.parse(uriString);
    // Close the port.
    receivePort.close();
    return new ServiceProtocolInfo(uri);
  }

  /// Control the web server that the service protocol is accessed through.
  /// [enable] is used as a toggle to enable or disable the web server
  /// servicing requests. If [silenceOutput] is provided and is true,
  /// the server will not output information to the console.
  static Future<ServiceProtocolInfo> controlWebServer(
      {bool enable = false, bool? silenceOutput}) async {
    // TODO: When NNBD is complete, delete the following line.
    ArgumentError.checkNotNull(enable, 'enable');
    // Port to receive response from service isolate.
    final RawReceivePort receivePort =
        new RawReceivePort(null, 'Service.controlWebServer');
    final Completer<String?> completer = new Completer<String?>();
    receivePort.handler = (String? uriString) => completer.complete(uriString);
    // Request the information from the service isolate.
    _webServerControl(receivePort.sendPort, enable, silenceOutput);
    // Await the response from the service isolate.
    String? uriString = await completer.future;
    Uri? uri = uriString == null ? null : Uri.parse(uriString);
    // Close the port.
    receivePort.close();
    return new ServiceProtocolInfo(uri);
  }

  /// Returns a [String] token representing the ID of [isolate].
  ///
  /// Returns null if the running Dart environment does not support the service
  /// protocol.
  static String? getIsolateID(Isolate isolate) {
    // TODO: When NNBD is complete, delete the following line.
    ArgumentError.checkNotNull(isolate, 'isolate');
    return _getIsolateIDFromSendPort(isolate.controlPort);
  }
}

/// [sendPort] will receive a Uri or null.
external void _getServerInfo(SendPort sendPort);

/// [sendPort] will receive a Uri or null.
external void _webServerControl(
    SendPort sendPort, bool enable, bool? silenceOutput);

/// Returns the major version of the service protocol.
external int _getServiceMajorVersion();

/// Returns the minor version of the service protocol.
external int _getServiceMinorVersion();

/// Returns the service id for the isolate that owns [sendPort].
external String? _getIsolateIDFromSendPort(SendPort sendPort);
