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

#ifndef RUNTIME_VM_SERVICE_ISOLATE_H_
#define RUNTIME_VM_SERVICE_ISOLATE_H_

#include "include/dart_api.h"

#include "vm/allocation.h"
#include "vm/object.h"
#include "vm/os_thread.h"

namespace dart {

class Isolate;
class ObjectPointerVisitor;
class SendPort;

class ServiceIsolate : public AllStatic {
#if !defined(PRODUCT)

 public:
  static const char* kName;

  static bool Exists();
  static bool IsRunning();
  static bool IsServiceIsolate(const Isolate* isolate);
  static bool IsServiceIsolateDescendant(Isolate* isolate);
  static Dart_Port Port();
  static void WaitForServiceIsolateStartup();

  // Returns `true` if the request was successfully sent.  If it was, the
  // [reply_port] will receive a Dart_TypedData_kUint8 response json.
  //
  // If sending the rpc failed and [error] is not `nullptr` then [error] might
  // be set to a string containing the reason for the failure. If so, the
  // caller is responsible for free()ing the error.
  static bool SendServiceRpc(uint8_t* request_json,
                             intptr_t request_json_length,
                             Dart_Port reply_port,
                             char** error);

  static void Run();
  static bool SendIsolateStartupMessage();
  static bool SendIsolateShutdownMessage();
  static bool SendServiceControlMessage(Thread* thread,
                                        Dart_Port port_id,
                                        intptr_t code,
                                        const char* name);
  static void SendServiceExitMessage();
  static void Shutdown();

  static void BootVmServiceLibrary();

  static void RegisterRunningIsolates(
      const GrowableArray<Dart_Port>& isolate_ports,
      const GrowableArray<const String*>& isolate_names,
      const GrowableArray<bool>& isolate_is_system);

  static void RequestServerInfo(const SendPort& sp);
  static void ControlWebServer(const SendPort& sp,
                               bool enable,
                               const Bool& silenceOutput);

  static void SetServerAddress(const char* address);

  // Returns the server's web address or nullptr if none is running.
  static const char* server_address() { return server_address_; }

  static void VisitObjectPointers(ObjectPointerVisitor* visitor);

 private:
  static void KillServiceIsolate();

 protected:
  static void SetServicePort(Dart_Port port);
  static void SetServiceIsolate(Isolate* isolate);
  static void FinishedExiting();
  static void FinishedInitializing();
  static void InitializingFailed(char* error);
  static void MaybeMakeServiceIsolate(Isolate* isolate);
  static Dart_IsolateGroupCreateCallback create_group_callback() {
    return create_group_callback_;
  }

  static Dart_IsolateGroupCreateCallback create_group_callback_;
  static Monitor* monitor_;
  enum State {
    kStopped,
    kStarting,
    kStarted,
    kStopping,
  };
  static State state_;
  static Isolate* isolate_;
  static Dart_Port port_;
  static Dart_Port origin_;
  static char* server_address_;

  // If starting the service-isolate failed, this error might provide the reason
  // for the failure.
  static char* startup_failure_reason_;
#else

 public:
  static bool Exists() { return false; }
  static bool IsRunning() { return false; }
  static bool IsServiceIsolate(const Isolate* isolate) { return false; }
  static bool IsServiceIsolateDescendant(Isolate* isolate) { return false; }
  static void Run() {}
  static bool SendIsolateStartupMessage() { return false; }
  static bool SendIsolateShutdownMessage() { return false; }
  static void SendServiceExitMessage() {}
  static void Shutdown() {}
  static void RegisterRunningIsolate(Isolate* isolate) {}
  static void VisitObjectPointers(ObjectPointerVisitor* visitor) {}

 protected:
  static void SetServiceIsolate(Isolate* isolate) { UNREACHABLE(); }
#endif  // !defined(PRODUCT)

  friend class Dart;
  friend class Isolate;
  friend class RunServiceTask;
  friend class ServiceIsolateNatives;
};

}  // namespace dart

#endif  // RUNTIME_VM_SERVICE_ISOLATE_H_
