// 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 "button_checker.h"

#include <fcntl.h>
#include <lib/fdio/fdio.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/channel.h>
#include <unistd.h>

#include <cstring>
#include <filesystem>
#include <iostream>
#include <string>

#include <fbl/unique_fd.h>

constexpr auto kDevicePath = "/dev/class/input";
constexpr auto kTag = "button_checker";

std::unique_ptr<ButtonChecker> ButtonChecker::Create() {
  auto checker = std::make_unique<ButtonChecker>();

  std::error_code ec{};
  auto it = std::filesystem::directory_iterator(kDevicePath, ec);
  if (ec) {
    FX_LOGST(ERROR, kTag) << "Unable to open " << kDevicePath << ": " << ec.message();
    return nullptr;
  }
  for (const auto& entry : it) {
    auto device = BindDevice(entry.path());
    hid::ReportField mute_field{};
    if (device && !GetMuteFieldForDevice(device, &mute_field)) {
      checker->devices_.push_back(std::make_pair(std::move(device), std::move(mute_field)));
    }
  }

  if (checker->devices_.size() == 0) {
    FX_LOGST(WARNING, kTag) << "Zero devices were bound from " << kDevicePath;
    return nullptr;
  }

  return checker;
}

ButtonChecker::ButtonState ButtonChecker::GetMuteState() {
  auto state = ButtonState::UNKNOWN;
  for (auto& device : devices_) {
    // Get the report for the mute field.
    zx_status_t status_return = ZX_OK;
    std::vector<uint8_t> report;
    zx_status_t status = device.first->GetReport(fuchsia::hardware::input::ReportType::INPUT,
                                                 device.second.report_id, &status_return, &report);
    if (status != ZX_OK) {
      FX_PLOGST(ERROR, kTag, status);
      return ButtonState::UNKNOWN;
    }
    if (status_return != ZX_OK) {
      FX_PLOGST(ERROR, kTag, status_return);
      return ButtonState::UNKNOWN;
    }

    // Extract the value from the report.
    double field_value = 0.0;
    if (!hid::ExtractAsUnit(report.data(), report.size(), device.second.attr, &field_value)) {
      FX_LOGST(ERROR, kTag) << "Failed to extract HID field value";
      return ButtonState::UNKNOWN;
    }
    ButtonState state_for_device = field_value > 0 ? ButtonState::DOWN : ButtonState::UP;

    // Make sure that devices don't have conflicting states.
    if (state != ButtonState::UNKNOWN && state != state_for_device) {
      FX_LOGST(ERROR, kTag) << "Conflicting states reported by different devices";
      return ButtonState::UNKNOWN;
    }
    state = state_for_device;
  }

  return state;
}

fuchsia::hardware::input::DeviceSyncPtr ButtonChecker::BindDevice(const std::string& path) {
  // Open the device.
  int result = open(path.c_str(), O_RDONLY);
  if (result < 0) {
    FX_LOGST(ERROR, kTag) << "Error accessing " << path;
    return nullptr;
  }
  fbl::unique_fd fd(result);

  // Get a channel to its services.
  zx::channel channel;
  zx_status_t status = fdio_get_service_handle(fd.get(), channel.reset_and_get_address());
  if (status != ZX_OK) {
    FX_PLOGST(ERROR, kTag, status) << "Error getting channel from device " << path;
    return nullptr;
  }

  // Bind to the channel.
  fuchsia::hardware::input::DeviceSyncPtr device;
  device.Bind(std::move(channel));

  return device;
}

bool ButtonChecker::GetMuteFieldForDevice(fuchsia::hardware::input::DeviceSyncPtr& device,
                                          hid::ReportField* mute_field_out) {
  FX_CHECK(mute_field_out);
  auto kMuteButtonUsage =
      hid::USAGE(hid::usage::Page::kTelephony, hid::usage::Telephony::kPhoneMute);

  // Get the report descriptor.
  std::vector<uint8_t> desc;
  zx_status_t status = device->GetReportDesc(&desc);
  if (status != ZX_OK) {
    FX_PLOGST(ERROR, kTag, status);
    return true;
  }

  // Parse the descriptor.
  hid::DeviceDescriptor* device_descriptor_ptr = nullptr;
  auto parse_result = hid::ParseReportDescriptor(desc.data(), desc.size(), &device_descriptor_ptr);
  if (parse_result != hid::kParseOk) {
    FX_LOGST(ERROR, kTag) << "HID Parse Failure: " << parse_result;
    return true;
  }
  std::unique_ptr<hid::DeviceDescriptor, decltype(&hid::FreeDeviceDescriptor)> device_descriptor(
      device_descriptor_ptr, &hid::FreeDeviceDescriptor);

  // Loop over the descriptor reports and their fields.
  bool found_mute_field = false;
  for (size_t report_index = 0; report_index < device_descriptor->rep_count; ++report_index) {
    const auto& report_descriptor = device_descriptor->report[report_index];
    for (size_t field_index = 0; field_index < report_descriptor.input_count; ++field_index) {
      const auto& input_field = report_descriptor.input_fields[field_index];

      // If the report desc is for the mute button, save out the field metadata.
      if (input_field.attr.usage == kMuteButtonUsage) {
        if (found_mute_field && memcmp(mute_field_out, &input_field, sizeof(input_field)) != 0) {
          FX_LOGST(ERROR, kTag) << "Multiple mute fields found in same device";
          return true;
        }
        *mute_field_out = input_field;
        found_mute_field = true;
      }
    }
  }

  return !found_mute_field;
}

bool VerifyDeviceUnmuted(bool consider_unknown_as_unmuted) {
  auto state = ButtonChecker::ButtonState::UNKNOWN;
  auto checker = ButtonChecker::Create();
  if (checker) {
    state = checker->GetMuteState();
  }
  if (state == ButtonChecker::ButtonState::UP) {
    return true;
  }
  if (state == ButtonChecker::ButtonState::UNKNOWN) {
    std::cerr << "**************************************************\n"
                 "* WARNING: DEVICE MUTE STATE UNKNOWN. CAMERA MAY *\n"
                 "*          NOT OPERATE AND TESTS MAY BE SKIPPED! *\n"
                 "**************************************************\n";
    std::cerr.flush();
    return consider_unknown_as_unmuted;
  }
  FX_DCHECK(state == ButtonChecker::ButtonState::DOWN);
  std::cerr << "**********************************************\n"
               "* WARNING: DEVICE IS MUTED. CAMERA WILL NOT  *\n"
               "*          OPERATE AND TESTS MAY BE SKIPPED! *\n"
               "**********************************************\n";
  std::cerr.flush();
  return false;
}
