// 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/lib/ui/compositing/scene_host.h"

#include <lib/ui/scenic/cpp/view_token_pair.h>
#include <lib/zx/eventpair.h>
#include <third_party/tonic/dart_args.h>
#include <third_party/tonic/dart_binding_macros.h>
#include <third_party/tonic/logging/dart_invoke.h>

#include "flutter/flow/view_holder.h"
#include "flutter/fml/thread_local.h"
#include "flutter/lib/ui/ui_dart_state.h"
#include "third_party/dart/runtime/include/dart_api.h"

namespace {

struct SceneHostBindingKey {
  std::string isolate_service_id;
  zx_koid_t koid;

  SceneHostBindingKey(const zx_koid_t koid,
                      const std::string isolate_service_id) {
    this->koid = koid;
    this->isolate_service_id = isolate_service_id;
  }

  bool operator==(const SceneHostBindingKey& other) const {
    return isolate_service_id == other.isolate_service_id && koid == other.koid;
  }
};

struct SceneHostBindingKeyHasher {
  std::size_t operator()(const SceneHostBindingKey& key) const {
    std::size_t koid_hash = std::hash<zx_koid_t>()(key.koid);
    std::size_t isolate_hash = std::hash<std::string>()(key.isolate_service_id);
    return koid_hash ^ isolate_hash;
  }
};

using SceneHostBindings = std::unordered_map<SceneHostBindingKey,
                                             flutter::SceneHost*,
                                             SceneHostBindingKeyHasher>;

static SceneHostBindings scene_host_bindings;

void SceneHost_constructor(Dart_NativeArguments args) {
  flutter::UIDartState::ThrowIfUIOperationsProhibited();
  tonic::DartCallConstructor(&flutter::SceneHost::Create, args);
}

flutter::SceneHost* GetSceneHost(scenic::ResourceId id,
                                 std::string isolate_service_id) {
  auto binding =
      scene_host_bindings.find(SceneHostBindingKey(id, isolate_service_id));
  if (binding == scene_host_bindings.end()) {
    return nullptr;
  } else {
    return binding->second;
  }
}

flutter::SceneHost* GetSceneHostForCurrentIsolate(scenic::ResourceId id) {
  auto isolate = Dart_CurrentIsolate();
  if (!isolate) {
    return nullptr;
  } else {
    std::string isolate_service_id = Dart_IsolateServiceId(isolate);
    return GetSceneHost(id, isolate_service_id);
  }
}

void InvokeDartClosure(const tonic::DartPersistentValue& closure) {
  auto dart_state = closure.dart_state().lock();
  if (!dart_state) {
    return;
  }

  tonic::DartState::Scope scope(dart_state);
  auto dart_handle = closure.value();

  FML_DCHECK(dart_handle && !Dart_IsNull(dart_handle) &&
             Dart_IsClosure(dart_handle));
  tonic::DartInvoke(dart_handle, {});
}

template <typename T>
void InvokeDartFunction(const tonic::DartPersistentValue& function, T& arg) {
  auto dart_state = function.dart_state().lock();
  if (!dart_state) {
    return;
  }

  tonic::DartState::Scope scope(dart_state);
  auto dart_handle = function.value();

  FML_DCHECK(dart_handle && !Dart_IsNull(dart_handle) &&
             Dart_IsClosure(dart_handle));
  tonic::DartInvoke(dart_handle, {tonic::ToDart(arg)});
}

zx_koid_t GetKoid(zx_handle_t handle) {
  zx_info_handle_basic_t info;
  zx_status_t status = zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info,
                                          sizeof(info), nullptr, nullptr);
  return status == ZX_OK ? info.koid : ZX_KOID_INVALID;
}

}  // namespace

namespace flutter {

IMPLEMENT_WRAPPERTYPEINFO(ui, SceneHost);

#define FOR_EACH_BINDING(V) \
  V(SceneHost, dispose)     \
  V(SceneHost, setProperties)

FOR_EACH_BINDING(DART_NATIVE_CALLBACK)

void SceneHost::RegisterNatives(tonic::DartLibraryNatives* natives) {
  natives->Register({{"SceneHost_constructor", SceneHost_constructor, 5, true},
                     FOR_EACH_BINDING(DART_REGISTER_NATIVE)});
}

fml::RefPtr<SceneHost> SceneHost::Create(
    fml::RefPtr<zircon::dart::Handle> viewHolderToken,
    Dart_Handle viewConnectedCallback,
    Dart_Handle viewDisconnectedCallback,
    Dart_Handle viewStateChangedCallback) {
  return fml::MakeRefCounted<SceneHost>(viewHolderToken, viewConnectedCallback,
                                        viewDisconnectedCallback,
                                        viewStateChangedCallback);
}

void SceneHost::OnViewConnected(scenic::ResourceId id) {
  auto* scene_host = GetSceneHostForCurrentIsolate(id);

  if (scene_host && !scene_host->view_connected_callback_.is_empty()) {
    InvokeDartClosure(scene_host->view_connected_callback_);
  }
}

void SceneHost::OnViewDisconnected(scenic::ResourceId id) {
  auto* scene_host = GetSceneHostForCurrentIsolate(id);

  if (scene_host && !scene_host->view_disconnected_callback_.is_empty()) {
    InvokeDartClosure(scene_host->view_disconnected_callback_);
  }
}

void SceneHost::OnViewStateChanged(scenic::ResourceId id, bool state) {
  auto* scene_host = GetSceneHostForCurrentIsolate(id);

  if (scene_host && !scene_host->view_state_changed_callback_.is_empty()) {
    InvokeDartFunction(scene_host->view_state_changed_callback_, state);
  }
}

SceneHost::SceneHost(fml::RefPtr<zircon::dart::Handle> viewHolderToken,
                     Dart_Handle viewConnectedCallback,
                     Dart_Handle viewDisconnectedCallback,
                     Dart_Handle viewStateChangedCallback)
    : raster_task_runner_(
          UIDartState::Current()->GetTaskRunners().GetRasterTaskRunner()),
      koid_(GetKoid(viewHolderToken->handle())) {
  auto dart_state = UIDartState::Current();
  isolate_service_id_ = Dart_IsolateServiceId(Dart_CurrentIsolate());

  // Initialize callbacks it they are non-null in Dart.
  if (!Dart_IsNull(viewConnectedCallback)) {
    view_connected_callback_.Set(dart_state, viewConnectedCallback);
  }
  if (!Dart_IsNull(viewDisconnectedCallback)) {
    view_disconnected_callback_.Set(dart_state, viewDisconnectedCallback);
  }
  if (!Dart_IsNull(viewStateChangedCallback)) {
    view_state_changed_callback_.Set(dart_state, viewStateChangedCallback);
  }

  // This callback will be posted as a task  when the |scenic::ViewHolder|
  // resource is created and given an id by the raster thread.
  auto bind_callback = [scene_host = this,
                        isolate_service_id =
                            isolate_service_id_](scenic::ResourceId id) {
    const auto key = SceneHostBindingKey(id, isolate_service_id);
    scene_host_bindings.emplace(std::make_pair(key, scene_host));
  };

  // Pass the raw handle to the raster thread; destroying a
  // |zircon::dart::Handle| on that thread can cause a race condition.
  raster_task_runner_->PostTask(
      [id = koid_,
       ui_task_runner =
           UIDartState::Current()->GetTaskRunners().GetUITaskRunner(),
       raw_handle = viewHolderToken->ReleaseHandle(), bind_callback]() {
        flutter::ViewHolder::Create(
            id, std::move(ui_task_runner),
            scenic::ToViewHolderToken(zx::eventpair(raw_handle)),
            std::move(bind_callback));
      });
}

SceneHost::~SceneHost() {
  scene_host_bindings.erase(SceneHostBindingKey(koid_, isolate_service_id_));

  raster_task_runner_->PostTask(
      [id = koid_]() { flutter::ViewHolder::Destroy(id); });
}

void SceneHost::dispose() {
  ClearDartWrapper();
}

void SceneHost::setProperties(double width,
                              double height,
                              double insetTop,
                              double insetRight,
                              double insetBottom,
                              double insetLeft,
                              bool focusable) {
  raster_task_runner_->PostTask([id = koid_, width, height, insetTop,
                                 insetRight, insetBottom, insetLeft,
                                 focusable]() {
    auto* view_holder = flutter::ViewHolder::FromId(id);
    FML_DCHECK(view_holder);

    view_holder->SetProperties(width, height, insetTop, insetRight, insetBottom,
                               insetLeft, focusable);
  });
}

}  // namespace flutter
