// Copyright 2019 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/virtualization/tests/fake_scenic.h"

#include <fuchsia/ui/gfx/cpp/fidl.h>
#include <fuchsia/ui/scenic/cpp/fidl.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/fit/defer.h>
#include <lib/fostr/fidl/fuchsia/ui/gfx/formatting.h>
#include <lib/fostr/fidl/fuchsia/ui/scenic/formatting.h>
#include <lib/syslog/cpp/macros.h>
#include <string.h>
#include <zircon/errors.h>

#include <cstdint>
#include <fstream>
#include <iostream>

// If true, print to log files received Session commands.
constexpr bool kTraceCommands = false;

using fuchsia::ui::input::KeyboardEventPhase;
using fuchsia::ui::scenic::Command;
using fuchsia::ui::scenic::Event;
using fuchsia::ui::scenic::Scenic;
using fuchsia::ui::scenic::Session;
using fuchsia::ui::scenic::SessionListener;
using GfxCommand = fuchsia::ui::gfx::Command;
using fuchsia::ui::gfx::ResourceArgs;

FakeSession::FakeSession(fidl::InterfaceRequest<Session> request,
                         fidl::InterfaceHandle<SessionListener> listener)
    : binding_(this, std::move(request)) {
  listener_.Bind(std::move(listener));
}

void FakeSession::Present(uint64_t /*presentation_time*/,
                          std::vector<::zx::event> /*acquire_fences*/,
                          std::vector<::zx::event> /*release_fences*/, PresentCallback callback) {
  callback({});
}

void FakeSession::HandleGfxCommand(GfxCommand cmd) {
  switch (cmd.Which()) {
    case GfxCommand::Tag::kCreateResource:
      HandleGfxCreateResource(std::move(cmd.create_resource()));
      break;
    case GfxCommand::Tag::kReleaseResource:
      HandleGfxReleaseResource(cmd.release_resource());
      break;
    case GfxCommand::Tag::kSetEventMask:
      HandleSetEventMask(cmd.set_event_mask());
      break;

    default:
      break;
  }
}

void FakeSession::HandleCreateView(uint32_t id) {
  // When a View is created, we need to send a "ViewProperties" describing
  // how large the view is.
  fuchsia::ui::gfx::Event response;
  auto& changed_event = response.view_properties_changed();
  changed_event.view_id = id;
  changed_event.properties.bounding_box.min = {0.0F, 0.0F, 0.0F};
  changed_event.properties.bounding_box.max = {kScreenWidthPixels, kScreenHeightPixels, 1.0F};
  SendGfxEvent(std::move(response));
}

void FakeSession::HandleGfxCreateResource(fuchsia::ui::gfx::CreateResourceCmd cmd) {
  const uint32_t id = cmd.id;
  const ResourceArgs::Tag type = cmd.resource.Which();

  // Track the resource, ensuring another resource with the same
  // ID doesn't already exist.
  auto [_, inserted] = resources_.insert({id, std::move(cmd)});
  FX_CHECK(inserted) << "Resource ID " << id << " already used by another resource.";

  // If the resource is a View, we need to send information to the user
  // about it.
  if (type == ResourceArgs::Tag::kView || type == ResourceArgs::Tag::kView3) {
    HandleCreateView(id);
  }
}

void FakeSession::HandleGfxReleaseResource(const fuchsia::ui::gfx::ReleaseResourceCmd& cmd) {
  auto it = resources_.find(cmd.id);
  FX_CHECK(it != resources_.end()) << "Attempting to release unknown resource ID " << cmd.id;
  resources_.erase(it);
}

void FakeSession::HandleSetEventMask(const fuchsia::ui::gfx::SetEventMaskCmd& cmd) {
  // Ensure the request is asking about a resource the client has installed.
  FX_CHECK(resources_.find(cmd.id) != resources_.end()) << "Unknown resource ID " << cmd.id;

  // Send scaling factors client should apply when generating textures.
  //
  // Clients refuse to start rendering until they have this information.
  if (cmd.event_mask & fuchsia::ui::gfx::kMetricsEventMask) {
    fuchsia::ui::gfx::Event response;
    auto& metrics = response.metrics();
    metrics.metrics = {/*scale_x=*/1.0F, /*scale_y=*/1.0F, /*scale_z=*/1.0F};
    metrics.node_id = cmd.id;
    SendGfxEvent(std::move(response));
  }
}

void FakeSession::Enqueue(std::vector<fuchsia::ui::scenic::Command> cmds) {
  FX_CHECK(binding_.is_bound());

  for (auto& cmd : cmds) {
    if (kTraceCommands) {
      FX_LOGS(INFO) << "Received command: " << cmd;
    }
    if (cmd.is_gfx()) {
      HandleGfxCommand(std::move(cmd.gfx()));
    }
  }
}

void FakeSession::SendGfxEvent(fuchsia::ui::gfx::Event event) {
  fuchsia::ui::scenic::Event payload;
  payload.set_gfx(std::move(event));
  SendEvent(std::move(payload));
}

void FakeSession::SendEvent(Event event) {
  if (listener_.is_bound()) {
    std::vector<Event> events;
    events.push_back(std::move(event));
    listener_->OnScenicEvent(std::move(events));
  }
}

void FakeSession::NotImplemented_(const std::string& name) {}

std::vector<const fuchsia::ui::gfx::CreateResourceCmd*> FakeSession::FindResourceByType(
    ResourceArgs::Tag type) {
  std::vector<const fuchsia::ui::gfx::CreateResourceCmd*> results;
  for (const auto& item : resources_) {
    if (item.second.resource.Which() == type) {
      results.push_back(&item.second);
    }
  }
  return results;
}

zx_status_t FakeSession::CaptureScreenshot(Screenshot* output) {
  FX_CHECK(output != nullptr);

  // Fetch all memory objects. We assume that this corresponds to the
  // guest's framebuffer.
  std::vector<const fuchsia::ui::gfx::CreateResourceCmd*> resources =
      FindResourceByType(ResourceArgs::Tag::kMemory);
  if (resources.empty()) {
    FX_LOGS(ERROR) << "No frame buffer found.";
    return ZX_ERR_BAD_STATE;
  }
  if (resources.size() > 1) {
    FX_LOGS(ERROR) << "Multiple possible frame buffers found, which is not "
                      "supported by FakeScenic.";
    return ZX_ERR_BAD_STATE;
  }
  const fuchsia::ui::gfx::MemoryArgs& args = resources[0]->resource.memory();

  // Read from the VMO into memory.
  std::vector<std::byte> image(args.allocation_size);
  if (zx_status_t status = args.vmo.read(image.data(), 0, image.size()); status != ZX_OK) {
    return status;
  }

  // Pass data back to the user.
  output->data = std::move(image);
  output->height = kScreenHeightPixels;
  output->width = kScreenWidthPixels;
  return ZX_OK;
}

void FakeSession::set_error_handler(fit::function<void(zx_status_t)> error_handler) {
  binding_.set_error_handler(std::move(error_handler));
}

fidl::InterfaceRequestHandler<Scenic> FakeScenic::GetHandler() {
  return bindings_.GetHandler(this);
}

void FakeScenic::SendEvent(Event event) {
  if (session_.has_value()) {
    session_->SendEvent(std::move(event));
  }
}

void FakeScenic::SendKeyEvent(KeyboardEventHidUsage usage,
                              fuchsia::ui::input::KeyboardEventPhase phase) {
  Event event;
  auto& keyboard_event = event.input().keyboard();
  keyboard_event.device_id = 0;
  keyboard_event.phase = phase;
  keyboard_event.hid_usage = static_cast<uint16_t>(usage);
  keyboard_event.code_point = 0;
  SendEvent(std::move(event));
}

void FakeScenic::SendKeyPress(KeyboardEventHidUsage usage) {
  SendKeyEvent(usage, KeyboardEventPhase::PRESSED);
  SendKeyEvent(usage, KeyboardEventPhase::RELEASED);
}

zx_status_t FakeScenic::CaptureScreenshot(Screenshot* output) {
  if (!session_.has_value()) {
    return ZX_ERR_BAD_STATE;
  }

  return session_->CaptureScreenshot(output);
}

void FakeScenic::CreateSession(fidl::InterfaceRequest<Session> session_request,
                               fidl::InterfaceHandle<SessionListener> listener) {
  // Ensure we don't already have a session open.
  if (session_.has_value()) {
    FX_LOGS(WARNING) << "Attempt to create a second session on FakeScenic was rejected.";
    session_request.Close(ZX_ERR_NO_RESOURCES);
    return;
  }

  // Create a new session.
  session_.emplace(std::move(session_request), std::move(listener));
  session_->set_error_handler([this](zx_status_t /*error*/) { session_.reset(); });
}

void FakeScenic::NotImplemented_(const std::string& name) {}
