// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "topaz/runtime/dart_runner/service_isolate.h"

#include "third_party/dart/runtime/include/bin/dart_io_api.h"
#include "third_party/tonic/converter/dart_converter.h"
#include "third_party/tonic/dart_library_natives.h"
#include "third_party/tonic/dart_microtask_queue.h"
#include "third_party/tonic/dart_state.h"
#include "third_party/tonic/typed_data/uint8_list.h"
#include "topaz/runtime/dart/utils/inlines.h"

#include "topaz/runtime/dart_runner/builtin_libraries.h"
#include "topaz/runtime/dart_runner/dart_component_controller.h"
#include "topaz/runtime/dart_runner/logging.h"

namespace dart_runner {
namespace {

MappedResource mapped_isolate_snapshot_data;
MappedResource mapped_isolate_snapshot_instructions;
MappedResource mapped_shared_snapshot_data;
MappedResource mapped_shared_snapshot_instructions;
tonic::DartLibraryNatives* service_natives = nullptr;

Dart_NativeFunction GetNativeFunction(Dart_Handle name, int argument_count,
                                      bool* auto_setup_scope) {
  dart_utils::Check(service_natives, LOG_TAG);
  return service_natives->GetNativeFunction(name, argument_count,
                                            auto_setup_scope);
}

const uint8_t* GetSymbol(Dart_NativeFunction native_function) {
  dart_utils::Check(service_natives, LOG_TAG);
  return service_natives->GetSymbol(native_function);
}

#define SHUTDOWN_ON_ERROR(handle)           \
  if (Dart_IsError(handle)) {               \
    *error = strdup(Dart_GetError(handle)); \
    FX_LOG(ERROR, LOG_TAG, *error);         \
    Dart_ExitScope();                       \
    Dart_ShutdownIsolate();                 \
    return nullptr;                         \
  }

void NotifyServerState(Dart_NativeArguments args) {
  // NOP.
}

void Shutdown(Dart_NativeArguments args) {
  // NOP.
}

void EmbedderInformationCallback(Dart_EmbedderInformation* info) {
  info->version = DART_EMBEDDER_INFORMATION_CURRENT_VERSION;
  info->name = "dart_runner";
  info->current_rss = -1;
  info->max_rss = -1;

  zx_info_task_stats_t task_stats;
  zx_handle_t process = zx_process_self();
  zx_status_t status = zx_object_get_info(
      process, ZX_INFO_TASK_STATS, &task_stats, sizeof(task_stats), NULL, NULL);
  if (status == ZX_OK) {
    info->current_rss =
        task_stats.mem_private_bytes + task_stats.mem_shared_bytes;
  }
}

}  // namespace

Dart_Isolate CreateServiceIsolate(const char* uri, Dart_IsolateFlags* flags,
                                  char** error) {
  Dart_SetEmbedderInformationCallback(EmbedderInformationCallback);

#if defined(AOT_RUNTIME)
  // The VM service was compiled as a separate app.
  const char* snapshot_data_path =
      "pkg/data/vmservice_isolate_snapshot_data.bin";
  const char* snapshot_instructions_path =
      "pkg/data/vmservice_isolate_snapshot_instructions.bin";
#else
  // The VM service is embedded in the core snapshot.
  const char* snapshot_data_path = "pkg/data/isolate_core_snapshot_data.bin";
  const char* snapshot_instructions_path =
      "pkg/data/isolate_core_snapshot_instructions.bin";
#endif

  if (!MappedResource::LoadFromNamespace(nullptr, snapshot_data_path,
                                         mapped_isolate_snapshot_data)) {
    *error = strdup("Failed to load snapshot for service isolate");
    FX_LOG(ERROR, LOG_TAG, *error);
    return nullptr;
  }
  if (!MappedResource::LoadFromNamespace(nullptr, snapshot_instructions_path,
                                         mapped_isolate_snapshot_instructions,
                                         true /* executable */)) {
    *error = strdup("Failed to load snapshot for service isolate");
    FX_LOG(ERROR, LOG_TAG, *error);
    return nullptr;
  }

#if defined(AOT_RUNTIME)
  if (!MappedResource::LoadFromNamespace(
          nullptr, "pkg/data/vmservice_shared_snapshot_data.bin",
          mapped_shared_snapshot_data)) {
    *error = strdup("Failed to load snapshot for service isolate");
    FX_LOG(ERROR, LOG_TAG, *error);
    return nullptr;
  }
  if (!MappedResource::LoadFromNamespace(
          nullptr, "pkg/data/vmservice_shared_snapshot_instructions.bin",
          mapped_shared_snapshot_instructions, true /* executable */)) {
    *error = strdup("Failed to load snapshot for service isolate");
    FX_LOG(ERROR, LOG_TAG, *error);
    return nullptr;
  }
#endif

  auto state = new std::shared_ptr<tonic::DartState>(new tonic::DartState());
  Dart_Isolate isolate =
      Dart_CreateIsolate(uri, DART_VM_SERVICE_ISOLATE_NAME,
                         mapped_isolate_snapshot_data.address(),
                         mapped_isolate_snapshot_instructions.address(),
                         mapped_shared_snapshot_data.address(),
                         mapped_shared_snapshot_instructions.address(),
                         nullptr /* flags */, state, error);
  if (!isolate) {
    FX_LOGF(ERROR, LOG_TAG, "Dart_CreateIsolate failed: %s", *error);
    return nullptr;
  }

  state->get()->SetIsolate(isolate);

  // Setup native entries.
  service_natives = new tonic::DartLibraryNatives();
  service_natives->Register({
      {"VMServiceIO_NotifyServerState", NotifyServerState, 1, true},
      {"VMServiceIO_Shutdown", Shutdown, 0, true},
  });

  Dart_EnterScope();

  Dart_Handle library =
      Dart_LookupLibrary(Dart_NewStringFromCString("dart:vmservice_io"));
  SHUTDOWN_ON_ERROR(library);
  Dart_Handle result = Dart_SetRootLibrary(library);
  SHUTDOWN_ON_ERROR(result);
  result = Dart_SetNativeResolver(library, GetNativeFunction, GetSymbol);
  SHUTDOWN_ON_ERROR(result);

  // _ip = '127.0.0.1'
  result = Dart_SetField(library, Dart_NewStringFromCString("_ip"),
                         Dart_NewStringFromCString("127.0.0.1"));
  SHUTDOWN_ON_ERROR(result);

  // _port = 0
  result = Dart_SetField(library, Dart_NewStringFromCString("_port"),
                         Dart_NewInteger(0));
  SHUTDOWN_ON_ERROR(result);

  // _autoStart = true
  result = Dart_SetField(library, Dart_NewStringFromCString("_autoStart"),
                         Dart_NewBoolean(true));
  SHUTDOWN_ON_ERROR(result);

  // _originCheckDisabled = false
  result =
      Dart_SetField(library, Dart_NewStringFromCString("_originCheckDisabled"),
                    Dart_NewBoolean(false));
  SHUTDOWN_ON_ERROR(result);

  // _authCodesDisabled = false
  result =
      Dart_SetField(library, Dart_NewStringFromCString("_authCodesDisabled"),
                    Dart_NewBoolean(false));
  SHUTDOWN_ON_ERROR(result);

  InitBuiltinLibrariesForIsolate(std::string(uri), nullptr, fileno(stdout),
                                 fileno(stderr), nullptr, zx::channel(), true);

  // Make runnable.
  Dart_ExitScope();
  Dart_ExitIsolate();
  *error = Dart_IsolateMakeRunnable(isolate);
  if (*error != nullptr) {
    FX_LOG(ERROR, LOG_TAG, *error);
    Dart_EnterIsolate(isolate);
    Dart_ShutdownIsolate();
    return nullptr;
  }
  return isolate;
}  // namespace dart_runner

Dart_Handle GetVMServiceAssetsArchiveCallback() {
  MappedResource observatory_tar;
  if (!MappedResource::LoadFromNamespace(nullptr, "pkg/data/observatory.tar",
                                         observatory_tar)) {
    FX_LOG(ERROR, LOG_TAG, "Failed to load Observatory assets");
    return nullptr;
  }
  // TODO(rmacnak): Should we avoid copying the tar? Or does the service library
  // not hold onto it anyway?
  return tonic::DartConverter<tonic::Uint8List>::ToDart(
      reinterpret_cast<const uint8_t*>(observatory_tar.address()),
      observatory_tar.size());
}

}  // namespace dart_runner
