// Copyright 2020 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/input/drivers/virtio/cpp/input_mouse.h"

#include <lib/ddk/debug.h>
#include <zircon/status.h>

#include <fbl/algorithm.h>
#include <virtio/input.h>

namespace virtio {

namespace {

constexpr uint16_t kKeyCodeBtnLeft = 0x110;    // BTN_LEFT
constexpr uint16_t kKeyCodeBtnRight = 0x111;   // BTN_RIGHT
constexpr uint16_t kKeyCodeBtnMiddle = 0x112;  // BTN_MIDDLE

constexpr int64_t kRangeMin = -32767;
constexpr int64_t kRangeMax = 32767;
constexpr fuchsia_input::wire::Axis kMouseRange = {
    .range = {.min = kRangeMin, .max = kRangeMax},
    .unit =
        {
            .type = fuchsia_input::wire::UnitType::kNone,
            .exponent = 0,
        },
};

}  // namespace

void MouseReport::ToFidlInputReport(
    fidl::WireTableBuilder<::fuchsia_input_report::wire::InputReport>& input_report,
    fidl::AnyArena& allocator) const {
  fidl::VectorView<uint8_t> pressed_buttons(allocator, kMaxButtonCount);
  size_t idx = 0;
  for (uint8_t i = 0; i < kMaxButtonCount; i++) {
    if (buttons[i]) {
      pressed_buttons[idx++] = i + 1;
    }
  }
  pressed_buttons.set_size(idx);

  auto mouse_rpt = fuchsia_input_report::wire::MouseInputReport::Builder(allocator);
  mouse_rpt.pressed_buttons(pressed_buttons);
  mouse_rpt.movement_x(rel_x);
  mouse_rpt.movement_y(rel_y);
  mouse_rpt.scroll_v(rel_wheel);

  input_report.event_time(event_time.get()).mouse(mouse_rpt.Build());
}

fuchsia_input_report::wire::DeviceDescriptor HidMouse::GetDescriptor(fidl::AnyArena& allocator) {
  auto device_info = fuchsia_input_report::wire::DeviceInformation::Builder(allocator);
  device_info.vendor_id(static_cast<uint32_t>(fuchsia_input_report::wire::VendorId::kGoogle));
  device_info.product_id(
      static_cast<uint32_t>(fuchsia_input_report::wire::VendorGoogleProductId::kVirtioMouse));

  if (!product_name_.empty()) {
    device_info.product_name(allocator, std::string_view(product_name_));
  }
  if (!serial_number_.empty()) {
    device_info.serial_number(allocator, std::string_view(serial_number_));
  }

  const auto input =
      fuchsia_input_report::wire::MouseInputDescriptor::Builder(allocator)
          .buttons({allocator,
                    {MouseReport::ButtonIndex::kLeft, MouseReport::ButtonIndex::kRight,
                     MouseReport::ButtonIndex::kMid}})
          .movement_x(kMouseRange)
          .movement_y(kMouseRange)
          .scroll_v(kMouseRange)
          .Build();

  const auto mouse =
      fuchsia_input_report::wire::MouseDescriptor::Builder(allocator).input(input).Build();

  return fuchsia_input_report::wire::DeviceDescriptor::Builder(allocator)
      .device_information(device_info.Build())
      .mouse(mouse)
      .Build();
}

void HidMouse::ReceiveKeyEvent(virtio_input_event_t* event) {
  ZX_DEBUG_ASSERT(event->type == VIRTIO_INPUT_EV_KEY);
  uint16_t key_code = event->code;
  uint32_t status = event->value;

  uint8_t button_idx = 0;
  switch (key_code) {
    case kKeyCodeBtnLeft:
      button_idx = MouseReport::ButtonIndex::kLeft;
      break;
    case kKeyCodeBtnRight:
      button_idx = MouseReport::ButtonIndex::kRight;
      break;
    case kKeyCodeBtnMiddle:
      button_idx = MouseReport::ButtonIndex::kMid;
      break;
    default:
      zxlogf(ERROR, "%s: key code %u not supported!", __func__, key_code);
      return;
  }

  report_.buttons[button_idx - 1] = status == VIRTIO_INPUT_EV_KEY_PRESSED;
}

void HidMouse::ReceiveRelEvent(virtio_input_event_t* event) {
  ZX_DEBUG_ASSERT(event->type == VIRTIO_INPUT_EV_REL);
  switch (event->code) {
    case VIRTIO_INPUT_EV_REL_X:
      report_.rel_x = static_cast<int16_t>(event->value);
      break;
    case VIRTIO_INPUT_EV_REL_Y:
      report_.rel_y = static_cast<int16_t>(event->value);
      break;
    case VIRTIO_INPUT_EV_REL_HWHEEL:
      // TODO(65215): Support horizontal wheel scrolling.
      break;
    case VIRTIO_INPUT_EV_REL_WHEEL:
      report_.rel_wheel = static_cast<int16_t>(event->value);
      break;
    default:
      zxlogf(ERROR, "%s: event code %u not supported!", __func__, event->code);
      return;
  }
}

void HidMouse::ReceiveEvent(virtio_input_event_t* event) {
  switch (event->type) {
    case VIRTIO_INPUT_EV_KEY:
      ReceiveKeyEvent(event);
      break;
    case VIRTIO_INPUT_EV_REL:
      ReceiveRelEvent(event);
      break;
    case VIRTIO_INPUT_EV_SYN:
      // EV_SYN events will be handled by InputDevice directly after calling
      // |ReceiveEvent|, so we ignore the SYN event here.
      break;
    default:
      zxlogf(ERROR, "%s: unsupported event type %u!", __func__, event->type);
      break;
  }
}

}  // namespace virtio
