// Copyright 2013 The Chromium 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 "device/gamepad/xbox_data_fetcher_mac.h"

#include <algorithm>
#include <cmath>
#include <limits>

#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/usb/IOUSBLib.h>
#include <IOKit/usb/USB.h>

#include "base/logging.h"
#include "base/mac/foundation_util.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"

namespace device {

namespace {

void CopyToUString(UChar* dest, size_t dest_length, base::string16 src) {
  static_assert(sizeof(base::string16::value_type) == sizeof(UChar),
                "Mismatched string16/WebUChar size.");

  const size_t str_to_copy = std::min(src.size(), dest_length - 1);
  src.copy(dest, str_to_copy);
  std::fill(dest + str_to_copy, dest + dest_length, 0);
}

}  // namespace

XboxDataFetcher::PendingController::PendingController(
    XboxDataFetcher* fetcher,
    std::unique_ptr<XboxControllerMac> controller)
    : fetcher(fetcher), controller(std::move(controller)) {}

XboxDataFetcher::PendingController::~PendingController() = default;

XboxDataFetcher::XboxDataFetcher() = default;

XboxDataFetcher::~XboxDataFetcher() {
  while (!controllers_.empty()) {
    RemoveController(*controllers_.begin());
  }
  UnregisterFromNotifications();
}

GamepadSource XboxDataFetcher::source() {
  return Factory::static_source();
}

void XboxDataFetcher::GetGamepadData(bool devices_changed_hint) {
  // This just loops through all the connected pads and "pings" them to indicate
  // that they're still active.
  for (auto* controller : controllers_) {
    GetPadState(controller->location_id());
  }
}

void XboxDataFetcher::PlayEffect(
    int source_id,
    mojom::GamepadHapticEffectType type,
    mojom::GamepadEffectParametersPtr params,
    mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback callback,
    scoped_refptr<base::SequencedTaskRunner> callback_runner) {
  XboxControllerMac* controller = ControllerForLocation(source_id);
  if (!controller) {
    RunVibrationCallback(
        std::move(callback), std::move(callback_runner),
        mojom::GamepadHapticsResult::GamepadHapticsResultError);
    return;
  }

  controller->PlayEffect(type, std::move(params), std::move(callback),
                         std::move(callback_runner));
}

void XboxDataFetcher::ResetVibration(
    int source_id,
    mojom::GamepadHapticsManager::ResetVibrationActuatorCallback callback,
    scoped_refptr<base::SequencedTaskRunner> callback_runner) {
  XboxControllerMac* controller = ControllerForLocation(source_id);
  if (!controller) {
    RunVibrationCallback(
        std::move(callback), std::move(callback_runner),
        mojom::GamepadHapticsResult::GamepadHapticsResultError);
    return;
  }

  controller->ResetVibration(std::move(callback), std::move(callback_runner));
}

void XboxDataFetcher::OnAddedToProvider() {
  RegisterForNotifications();
}

// static
void XboxDataFetcher::DeviceAdded(void* context, io_iterator_t iterator) {
  DCHECK(context);
  XboxDataFetcher* fetcher = static_cast<XboxDataFetcher*>(context);
  io_service_t ref;
  while ((ref = IOIteratorNext(iterator))) {
    base::mac::ScopedIOObject<io_service_t> scoped_ref(ref);
    fetcher->TryOpenDevice(ref);
  }
}

// static
void XboxDataFetcher::DeviceRemoved(void* context, io_iterator_t iterator) {
  DCHECK(context);
  XboxDataFetcher* fetcher = static_cast<XboxDataFetcher*>(context);
  io_service_t ref;
  while ((ref = IOIteratorNext(iterator))) {
    base::mac::ScopedIOObject<io_service_t> scoped_ref(ref);
    base::ScopedCFTypeRef<CFNumberRef> number(
        base::mac::CFCastStrict<CFNumberRef>(IORegistryEntryCreateCFProperty(
            ref, CFSTR(kUSBDevicePropertyLocationID), kCFAllocatorDefault,
            kNilOptions)));
    UInt32 location_id = 0;
    CFNumberGetValue(number, kCFNumberSInt32Type, &location_id);
    fetcher->RemoveControllerByLocationID(location_id);
  }
}

// static
void XboxDataFetcher::InterestCallback(void* context,
                                       io_service_t service,
                                       IOMessage message_type,
                                       void* message_argument) {
  if (message_type == kIOMessageServiceWasClosed) {
    PendingController* pending = static_cast<PendingController*>(context);
    pending->fetcher->PendingControllerBecameAvailable(service, pending);
  }
}

void XboxDataFetcher::PendingControllerBecameAvailable(
    io_service_t service,
    PendingController* pending) {
  // Destroying the PendingController object unregisters our interest
  // notification.
  for (auto it = pending_controllers_.begin(); it != pending_controllers_.end();
       ++it) {
    if (pending == it->get()) {
      pending_controllers_.erase(it);
      break;
    }
  }
  TryOpenDevice(service);
}

bool XboxDataFetcher::TryOpenDevice(io_service_t service) {
  auto pending = std::make_unique<PendingController>(
      this, std::make_unique<XboxControllerMac>(this));
  bool did_register_interest =
      RegisterForInterestNotifications(service, pending.get());

  auto* controller = pending->controller.get();
  XboxControllerMac::OpenDeviceResult result = controller->OpenDevice(service);
  if (result == XboxControllerMac::OpenDeviceResult::OPEN_SUCCEEDED) {
    AddController(pending->controller.release());
    return true;
  }

  if (did_register_interest &&
      result ==
          XboxControllerMac::OpenDeviceResult::OPEN_FAILED_EXCLUSIVE_ACCESS) {
    pending_controllers_.insert(std::move(pending));
  }
  return false;
}

bool XboxDataFetcher::RegisterForNotifications() {
  if (listening_)
    return true;
  if (port_ == nullptr)
    port_.reset(IONotificationPortCreate(kIOMasterPortDefault));
  if (!port_.is_valid())
    return false;
  source_ = IONotificationPortGetRunLoopSource(port_.get());
  if (!source_)
    return false;
  CFRunLoopAddSource(CFRunLoopGetCurrent(), source_, kCFRunLoopDefaultMode);

  listening_ = true;

  if (!RegisterForDeviceNotifications(
          XboxControllerMac::kVendorMicrosoft,
          XboxControllerMac::kProductXboxOneEliteController,
          &xbox_one_elite_device_added_iter_,
          &xbox_one_elite_device_removed_iter_))
    return false;

  if (!RegisterForDeviceNotifications(
          XboxControllerMac::kVendorMicrosoft,
          XboxControllerMac::kProductXboxOneController2013,
          &xbox_one_2013_device_added_iter_,
          &xbox_one_2013_device_removed_iter_))
    return false;

  if (!RegisterForDeviceNotifications(
          XboxControllerMac::kVendorMicrosoft,
          XboxControllerMac::kProductXboxOneController2015,
          &xbox_one_2015_device_added_iter_,
          &xbox_one_2015_device_removed_iter_))
    return false;

  if (!RegisterForDeviceNotifications(
          XboxControllerMac::kVendorMicrosoft,
          XboxControllerMac::kProductXboxOneSController,
          &xbox_one_s_device_added_iter_, &xbox_one_s_device_removed_iter_))
    return false;

  if (!RegisterForDeviceNotifications(
          XboxControllerMac::kVendorMicrosoft,
          XboxControllerMac::kProductXbox360Controller,
          &xbox_360_device_added_iter_, &xbox_360_device_removed_iter_))
    return false;

  return true;
}

bool XboxDataFetcher::RegisterForDeviceNotifications(
    int vendor_id,
    int product_id,
    base::mac::ScopedIOObject<io_iterator_t>* added_iter,
    base::mac::ScopedIOObject<io_iterator_t>* removed_iter) {
  base::ScopedCFTypeRef<CFNumberRef> vendor_cf(
      CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor_id));
  base::ScopedCFTypeRef<CFNumberRef> product_cf(
      CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product_id));
  base::ScopedCFTypeRef<CFMutableDictionaryRef> matching_dict(
      IOServiceMatching(kIOUSBDeviceClassName));
  if (!matching_dict)
    return false;
  CFDictionarySetValue(matching_dict, CFSTR(kUSBVendorID), vendor_cf);
  CFDictionarySetValue(matching_dict, CFSTR(kUSBProductID), product_cf);

  // IOServiceAddMatchingNotification() releases the dictionary when it's done.
  // Retain it before each call to IOServiceAddMatchingNotification to keep
  // things balanced.
  CFRetain(matching_dict);
  IOReturn ret;
  ret = IOServiceAddMatchingNotification(port_.get(), kIOFirstMatchNotification,
                                         matching_dict, DeviceAdded, this,
                                         added_iter->InitializeInto());
  if (ret != kIOReturnSuccess) {
    LOG(ERROR) << "Error listening for Xbox controller add events: " << ret;
    return false;
  }
  DeviceAdded(this, added_iter->get());

  CFRetain(matching_dict);
  ret = IOServiceAddMatchingNotification(port_.get(), kIOTerminatedNotification,
                                         matching_dict, DeviceRemoved, this,
                                         removed_iter->InitializeInto());
  if (ret != kIOReturnSuccess) {
    LOG(ERROR) << "Error listening for Xbox controller remove events: " << ret;
    return false;
  }
  DeviceRemoved(this, removed_iter->get());
  return true;
}

bool XboxDataFetcher::RegisterForInterestNotifications(
    io_service_t service,
    PendingController* pending) {
  if (port_ == nullptr)
    port_.reset(IONotificationPortCreate(kIOMasterPortDefault));
  if (!port_.is_valid())
    return false;

  kern_return_t kr = IOServiceAddInterestNotification(
      port_.get(), service, kIOGeneralInterest, InterestCallback, pending,
      pending->notify.InitializeInto());
  return kr == KERN_SUCCESS;
}

void XboxDataFetcher::UnregisterFromNotifications() {
  if (!listening_)
    return;
  listening_ = false;
  if (source_)
    CFRunLoopSourceInvalidate(source_);
  port_.reset();
  pending_controllers_.clear();
}

XboxControllerMac* XboxDataFetcher::ControllerForLocation(UInt32 location_id) {
  for (std::set<XboxControllerMac*>::iterator i = controllers_.begin();
       i != controllers_.end(); ++i) {
    if ((*i)->location_id() == location_id)
      return *i;
  }
  return NULL;
}

void XboxDataFetcher::AddController(XboxControllerMac* controller) {
  DCHECK(!ControllerForLocation(controller->location_id()))
      << "Controller with location ID " << controller->location_id()
      << " already exists in the set of controllers.";
  PadState* state = GetPadState(controller->location_id());
  if (!state) {
    delete controller;
    return;  // No available slot for this device
  }

  controllers_.insert(controller);

  controller->SetLEDPattern((XboxControllerMac::LEDPattern)(
      XboxControllerMac::LED_FLASH_TOP_LEFT + controller->location_id()));

  CopyToUString(state->data.id, base::size(state->data.id),
                base::UTF8ToUTF16(controller->GetIdString()));
  CopyToUString(state->data.mapping, base::size(state->data.mapping),
                base::UTF8ToUTF16("standard"));

  state->data.connected = true;
  state->data.axes_length = 4;
  state->data.buttons_length = 17;
  state->data.timestamp = CurrentTimeInMicroseconds();
  state->mapper = 0;
  state->axis_mask = 0;
  state->button_mask = 0;

  // Assume all Xbox gamepads support vibration effects.
  state->data.vibration_actuator.type = GamepadHapticActuatorType::kDualRumble;
  state->data.vibration_actuator.not_null = true;
}

void XboxDataFetcher::RemoveController(XboxControllerMac* controller) {
  controllers_.erase(controller);
  delete controller;
}

void XboxDataFetcher::RemoveControllerByLocationID(uint32_t location_id) {
  XboxControllerMac* controller = NULL;
  for (std::set<XboxControllerMac*>::iterator i = controllers_.begin();
       i != controllers_.end(); ++i) {
    if ((*i)->location_id() == location_id) {
      controller = *i;
      break;
    }
  }
  if (controller)
    RemoveController(controller);
}

void XboxDataFetcher::XboxControllerGotData(
    XboxControllerMac* controller,
    const XboxControllerMac::Data& data) {
  PadState* state = GetPadState(controller->location_id());
  if (!state)
    return;  // No available slot for this device

  Gamepad& pad = state->data;

  for (size_t i = 0; i < 6; i++) {
    pad.buttons[i].pressed = data.buttons[i];
    pad.buttons[i].value = data.buttons[i] ? 1.0f : 0.0f;
  }
  pad.buttons[6].pressed = data.triggers[0] > kDefaultButtonPressedThreshold;
  pad.buttons[6].value = data.triggers[0];
  pad.buttons[7].pressed = data.triggers[1] > kDefaultButtonPressedThreshold;
  pad.buttons[7].value = data.triggers[1];
  for (size_t i = 8; i < 16; i++) {
    pad.buttons[i].pressed = data.buttons[i - 2];
    pad.buttons[i].value = data.buttons[i - 2] ? 1.0f : 0.0f;
  }
  if (controller->GetControllerType() ==
      XboxControllerMac::XBOX_360_CONTROLLER) {
    pad.buttons[16].pressed = data.buttons[14];
    pad.buttons[16].value = data.buttons[14] ? 1.0f : 0.0f;
  }
  for (size_t i = 0; i < base::size(data.axes); i++) {
    pad.axes[i] = data.axes[i];
  }

  pad.timestamp = CurrentTimeInMicroseconds();
}

void XboxDataFetcher::XboxControllerGotGuideData(XboxControllerMac* controller,
                                                 bool guide) {
  PadState* state = GetPadState(controller->location_id());
  if (!state)
    return;  // No available slot for this device

  Gamepad& pad = state->data;

  pad.buttons[16].pressed = guide;
  pad.buttons[16].value = guide ? 1.0f : 0.0f;

  pad.timestamp = CurrentTimeInMicroseconds();
}

void XboxDataFetcher::XboxControllerError(XboxControllerMac* controller) {
  RemoveController(controller);
}

}  // namespace device
