// Copyright 2017 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 "src/ui/examples/escher/common/demo_harness_fuchsia.h"

#include <lib/async/cpp/task.h>
#include <lib/async/default.h>
#include <lib/zx/time.h>

#include <memory>

#include <hid/usages.h>

#include "lib/vfs/cpp/pseudo_dir.h"
#include "src/ui/examples/escher/common/demo.h"
#include "src/ui/lib/escher/util/trace_macros.h"

// Directory provided by the "isolated-cache-storage" feature of the component sandbox.
static const char* kCacheDirectoryPath = "/cache";

namespace {

class DemoKeyDispatcher : public fuchsia::ui::input::InputDevice {
 public:
  using Callback = fit::function<void(std::string)>;

  DemoKeyDispatcher(Callback callback) : callback_(std::move(callback)) {}

 private:
  // |fuchsia::ui::input::InputDevice|
  void DispatchReport(fuchsia::ui::input::InputReport report) override {
    if (report.keyboard) {
      DispatchDelta(std::move(report.keyboard->pressed_keys));
    }
  }

  // Dispatch only keys that are newly pressed.
  void DispatchDelta(std::vector<uint32_t> pressed_keys) {
    for (uint32_t key : pressed_keys) {
      // Since this is a demo harness, we can assume a small number of pressed
      // keys. However, if this assumption breaks, we can switch to std::bitset.
      if (std::find(pressed_keys_.begin(), pressed_keys_.end(), key) == pressed_keys_.end()) {
        DispatchKey(key);
      }
    }
    pressed_keys_ = std::move(pressed_keys);
  }

  void DispatchKey(uint32_t hid) {
    if (hid >= HID_USAGE_KEY_A && hid <= HID_USAGE_KEY_Z) {
      callback_(std::string(1, 'A' + hid - HID_USAGE_KEY_A));
    } else if (hid >= HID_USAGE_KEY_1 && hid <= HID_USAGE_KEY_9) {
      callback_(std::string(1, '1' + hid - HID_USAGE_KEY_1));
    } else {
      switch (hid) {
        // Unlike ASCII, HID_USAGE_KEY_0 comes after 9.
        case HID_USAGE_KEY_0:
          callback_("0");
          break;
        case HID_USAGE_KEY_ENTER:
        case HID_USAGE_KEY_KP_ENTER:
          callback_("RETURN");
          break;
        case HID_USAGE_KEY_ESC:
          callback_("ESCAPE");
          break;
        case HID_USAGE_KEY_SPACE:
          callback_("SPACE");
          break;
        default:
          break;
      }
    }
  }

  Callback callback_;
  std::vector<uint32_t> pressed_keys_;
};

}  // namespace

// When running on Fuchsia, New() instantiates a DemoHarnessFuchsia.
std::unique_ptr<DemoHarness> DemoHarness::New(DemoHarness::WindowParams window_params,
                                              DemoHarness::InstanceParams instance_params) {
  auto harness = new DemoHarnessFuchsia(nullptr, window_params);
  harness->Init(std::move(instance_params));
  return std::unique_ptr<DemoHarness>(harness);
}

DemoHarnessFuchsia::DemoHarnessFuchsia(async::Loop* loop, WindowParams window_params)
    : DemoHarness(window_params),
      owned_loop_(loop ? nullptr : new async::Loop(&kAsyncLoopConfigAttachToCurrentThread)),
      loop_(loop ? loop : owned_loop_.get()),
      component_context_(sys::ComponentContext::CreateAndServeOutgoingDirectory()),
      input_reader_(this) {
  // Provide a PseudoDir where the demo can register debugging services.
  auto debug_dir = std::make_shared<vfs::PseudoDir>();
  component_context()->outgoing()->debug_dir()->AddSharedEntry("demo", debug_dir);
  filesystem_ = escher::HackFilesystem::New(debug_dir);

  // Synchronously create trace provider so that all subsequent traces are recorded.  This is
  // necessary e.g. if the system is already tracing when this app is launched, in order to not miss
  // trace events that occur during startup.
  bool already_started = false;
  trace::TraceProviderWithFdio::CreateSynchronously(loop_->dispatcher(), "Escher DemoHarness",
                                                    &trace_provider_, &already_started);
}

std::string DemoHarnessFuchsia::GetCacheDirectoryPath() { return kCacheDirectoryPath; }

void DemoHarnessFuchsia::InitWindowSystem() { input_reader_.Start(); }

vk::SurfaceKHR DemoHarnessFuchsia::CreateWindowAndSurface(const WindowParams& params) {
  VkImagePipeSurfaceCreateInfoFUCHSIA create_info = {
      .sType = VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA,
      .pNext = nullptr,
  };
  VkSurfaceKHR surface;
  VkResult err = vkCreateImagePipeSurfaceFUCHSIA(instance(), &create_info, nullptr, &surface);
  FX_CHECK(!err);
  return surface;
}

void DemoHarnessFuchsia::AppendPlatformSpecificInstanceExtensionNames(InstanceParams* params) {
  params->extension_names.insert(VK_KHR_SURFACE_EXTENSION_NAME);
  params->extension_names.insert(VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME);
  params->extension_names.insert(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME);
  params->extension_names.insert(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
  params->layer_names.insert("VK_LAYER_FUCHSIA_imagepipe_swapchain_fb");
}

void DemoHarnessFuchsia::AppendPlatformSpecificDeviceExtensionNames(std::set<std::string>* names) {
  names->insert(VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME);
}

void DemoHarnessFuchsia::ShutdownWindowSystem() {}

void DemoHarnessFuchsia::RunForPlatform(Demo* demo) {
  // We put in a delay so that tracing is ready to capture the first frame (otherwise we miss the
  // first frame and catch the second).
  async::PostDelayedTask(
      loop_->dispatcher(), [this, demo] { this->RenderFrameOrQuit(demo); }, zx::msec(1));
  loop_->Run();
}

void DemoHarnessFuchsia::RegisterDevice(
    fuchsia::ui::input::DeviceDescriptor descriptor,
    fidl::InterfaceRequest<fuchsia::ui::input::InputDevice> input_device) {
  if (descriptor.keyboard) {
    input_devices_.AddBinding(std::make_unique<DemoKeyDispatcher>([this](std::string key) {
                                this->HandleKeyPress(std::move(key));
                              }),
                              std::move(input_device));
  }
}

void DemoHarnessFuchsia::RenderFrameOrQuit(Demo* demo) {
  if (ShouldQuit()) {
    loop_->Quit();
    device().waitIdle();
  } else {
    MaybeDrawFrame();
    async::PostDelayedTask(
        loop_->dispatcher(), [this, demo] { this->RenderFrameOrQuit(demo); }, zx::msec(1));
  }
}
