// Copyright 2013 The Flutter 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 "flutter/runtime/dart_service_isolate.h"

#include <string.h>
#include <algorithm>

#include "flutter/fml/logging.h"
#include "flutter/runtime/embedder_resources.h"
#include "third_party/dart/runtime/include/dart_api.h"
#include "third_party/tonic/converter/dart_converter.h"
#include "third_party/tonic/dart_library_natives.h"
#include "third_party/tonic/logging/dart_error.h"

#define RETURN_ERROR_HANDLE(handle) \
  if (Dart_IsError(handle)) {       \
    return handle;                  \
  }

#define SHUTDOWN_ON_ERROR(handle)           \
  if (Dart_IsError(handle)) {               \
    *error = strdup(Dart_GetError(handle)); \
    Dart_ExitScope();                       \
    Dart_ShutdownIsolate();                 \
    return false;                           \
  }

namespace flutter {
namespace {

static Dart_LibraryTagHandler g_embedder_tag_handler;
static tonic::DartLibraryNatives* g_natives;
static std::string g_observatory_uri;

Dart_NativeFunction GetNativeFunction(Dart_Handle name,
                                      int argument_count,
                                      bool* auto_setup_scope) {
  FML_CHECK(g_natives);
  return g_natives->GetNativeFunction(name, argument_count, auto_setup_scope);
}

const uint8_t* GetSymbol(Dart_NativeFunction native_function) {
  FML_CHECK(g_natives);
  return g_natives->GetSymbol(native_function);
}

}  // namespace

std::mutex DartServiceIsolate::callbacks_mutex_;

std::set<std::unique_ptr<DartServiceIsolate::ObservatoryServerStateCallback>>
    DartServiceIsolate::callbacks_;

void DartServiceIsolate::NotifyServerState(Dart_NativeArguments args) {
  Dart_Handle exception = nullptr;
  std::string uri =
      tonic::DartConverter<std::string>::FromArguments(args, 0, exception);

  if (exception) {
    return;
  }

  g_observatory_uri = uri;

  // Collect callbacks to fire in a separate collection and invoke them outside
  // the lock.
  std::vector<DartServiceIsolate::ObservatoryServerStateCallback>
      callbacks_to_fire;
  {
    std::scoped_lock lock(callbacks_mutex_);
    for (auto& callback : callbacks_) {
      callbacks_to_fire.push_back(*callback.get());
    }
  }

  for (auto callback_to_fire : callbacks_to_fire) {
    callback_to_fire(uri);
  }
}

DartServiceIsolate::CallbackHandle DartServiceIsolate::AddServerStatusCallback(
    const DartServiceIsolate::ObservatoryServerStateCallback& callback) {
  if (!callback) {
    return 0;
  }

  auto callback_pointer =
      std::make_unique<DartServiceIsolate::ObservatoryServerStateCallback>(
          callback);

  auto handle = reinterpret_cast<CallbackHandle>(callback_pointer.get());

  {
    std::scoped_lock lock(callbacks_mutex_);
    callbacks_.insert(std::move(callback_pointer));
  }

  if (!g_observatory_uri.empty()) {
    callback(g_observatory_uri);
  }

  return handle;
}

bool DartServiceIsolate::RemoveServerStatusCallback(
    CallbackHandle callback_handle) {
  std::scoped_lock lock(callbacks_mutex_);
  auto found = std::find_if(
      callbacks_.begin(), callbacks_.end(),
      [callback_handle](const auto& item) {
        return reinterpret_cast<CallbackHandle>(item.get()) == callback_handle;
      });

  if (found == callbacks_.end()) {
    return false;
  }

  callbacks_.erase(found);
  return true;
}

void DartServiceIsolate::Shutdown(Dart_NativeArguments args) {
  // NO-OP.
}

bool DartServiceIsolate::Startup(std::string server_ip,
                                 intptr_t server_port,
                                 Dart_LibraryTagHandler embedder_tag_handler,
                                 bool disable_origin_check,
                                 bool disable_service_auth_codes,
                                 char** error) {
  Dart_Isolate isolate = Dart_CurrentIsolate();
  FML_CHECK(isolate);

  // Remember the embedder's library tag handler.
  g_embedder_tag_handler = embedder_tag_handler;
  FML_CHECK(g_embedder_tag_handler);

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

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

  // Make runnable.
  Dart_ExitScope();
  Dart_ExitIsolate();
  *error = Dart_IsolateMakeRunnable(isolate);
  if (*error) {
    Dart_EnterIsolate(isolate);
    Dart_ShutdownIsolate();
    return false;
  }
  Dart_EnterIsolate(isolate);
  Dart_EnterScope();

  library = Dart_RootLibrary();
  SHUTDOWN_ON_ERROR(library);

  // Set the HTTP server's ip.
  result = Dart_SetField(library, Dart_NewStringFromCString("_ip"),
                         Dart_NewStringFromCString(server_ip.c_str()));
  SHUTDOWN_ON_ERROR(result);
  // If we have a port specified, start the server immediately.
  bool auto_start = server_port >= 0;
  if (server_port < 0) {
    // Adjust server_port to port 0 which will result in the first available
    // port when the HTTP server is started.
    server_port = 0;
  }
  // Set the HTTP's servers port.
  result = Dart_SetField(library, Dart_NewStringFromCString("_port"),
                         Dart_NewInteger(server_port));
  SHUTDOWN_ON_ERROR(result);
  result = Dart_SetField(library, Dart_NewStringFromCString("_autoStart"),
                         Dart_NewBoolean(auto_start));
  SHUTDOWN_ON_ERROR(result);
  result =
      Dart_SetField(library, Dart_NewStringFromCString("_originCheckDisabled"),
                    Dart_NewBoolean(disable_origin_check));
  SHUTDOWN_ON_ERROR(result);
  result =
      Dart_SetField(library, Dart_NewStringFromCString("_authCodesDisabled"),
                    Dart_NewBoolean(disable_service_auth_codes));
  SHUTDOWN_ON_ERROR(result);
  return true;
}

}  // namespace flutter
