/*
 * Copyright 2018 The Chromium OS 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 "cros-camera/udev_watcher.h"

#include <string>
#include <utility>

#include <libudev.h>

#include <base/threading/thread.h>
#include <base/threading/thread_task_runner_handle.h>

#include "cros-camera/common.h"
#include "cros-camera/future.h"

namespace cros {

UdevWatcher::Observer::~Observer() = default;

void UdevWatcher::Observer::OnDeviceAdded(ScopedUdevDevicePtr /*device*/) {}

void UdevWatcher::Observer::OnDeviceRemoved(ScopedUdevDevicePtr /*device*/) {}

UdevWatcher::UdevWatcher(Observer* observer, std::string subsystem)
    : observer_(observer),
      subsystem_(std::move(subsystem)),
      thread_("UdevWatcherThread") {}

UdevWatcher::~UdevWatcher() {
  if (!thread_.IsRunning()) {
    // No-op destructor if the watcher thread is not running. It could happen
    // if Start() failed or is not getting called at all.
    return;
  }
  // Post a task to reset FileDescriptorWatcher and explicitly call
  // Thread::Stop() to ensure it is completed before destroying fields.
  thread_.task_runner()->PostTask(
      FROM_HERE,
      base::BindOnce(&UdevWatcher::StopOnThread, base::Unretained(this)));
  thread_.Stop();
}

bool UdevWatcher::Start(
    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
  udev_.reset(udev_new());
  if (!udev_) {
    LOGF(ERROR) << "udev_new failed";
    return false;
  }

  mon_.reset(udev_monitor_new_from_netlink(udev_.get(), "udev"));
  if (!mon_) {
    LOGF(ERROR) << "udev_monitor_new_from_netlink failed";
    return false;
  }

  if (udev_monitor_filter_add_match_subsystem_devtype(
          mon_.get(), subsystem_.c_str(), nullptr) < 0) {
    LOGF(ERROR) << "udev_monitor_filter_add_match_subsystem_devtype failed";
    return false;
  }

  if (udev_monitor_enable_receiving(mon_.get()) < 0) {
    LOGF(ERROR) << "udev_monitor_enable_receiving failed";
    return false;
  }

  int fd = udev_monitor_get_fd(mon_.get());
  if (fd < 0) {
    LOGF(ERROR) << "udev_monitor_get_fd failed";
    return false;
  }

  if (!thread_.StartWithOptions(
          base::Thread::Options(base::MessagePumpType::IO, 0))) {
    LOGF(ERROR) << "thread start failed";
    return false;
  }

  callback_task_runner_ = task_runner;

  auto future = cros::Future<bool>::Create(nullptr);
  thread_.task_runner()->PostTask(
      FROM_HERE, base::Bind(&UdevWatcher::StartOnThread, base::Unretained(this),
                            fd, cros::GetFutureCallback(future)));
  return future->Get();
}

bool UdevWatcher::EnumerateExistingDevices() {
  DCHECK(callback_task_runner_) << "Start() shuold be called first";
  DCHECK(callback_task_runner_->BelongsToCurrentThread());

  ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev_.get()));
  if (!enumerate) {
    LOGF(ERROR) << "udev_enumerate_new failed";
    return false;
  }

  if (udev_enumerate_add_match_subsystem(enumerate.get(), subsystem_.c_str()) <
      0) {
    LOGF(ERROR) << "udev_enumerate_add_match_subsystem failed";
    return false;
  }

  if (udev_enumerate_scan_devices(enumerate.get()) < 0) {
    LOGF(ERROR) << "udev_enumerate_scan_devices failed";
    return false;
  }

  for (udev_list_entry* entry = udev_enumerate_get_list_entry(enumerate.get());
       entry != nullptr; entry = udev_list_entry_get_next(entry)) {
    // We simply ignore errors in some entries here, and keep enumerating.

    const char* name = udev_list_entry_get_name(entry);
    if (!name) {
      LOGF(WARNING) << "udev_list_entry_get_name failed";
      continue;
    }

    ScopedUdevDevicePtr dev(udev_device_new_from_syspath(udev_.get(), name));
    if (!dev) {
      LOGF(WARNING) << "udev_device_new_from_syspath failed";
      continue;
    }

    observer_->OnDeviceAdded(std::move(dev));
  }

  return true;
}

void UdevWatcher::StartOnThread(int fd, base::Callback<void(bool)> callback) {
  DCHECK(thread_.task_runner()->BelongsToCurrentThread());

  watcher_ = base::FileDescriptorWatcher::WatchReadable(
      fd,
      base::BindRepeating(&UdevWatcher::OnReadable, base::Unretained(this)));
  if (!watcher_) {
    LOGF(ERROR) << "Failed to start watching a file descriptor";
    callback.Run(false);
    return;
  }

  callback.Run(true);
}

void UdevWatcher::StopOnThread() {
  watcher_ = nullptr;
}

void UdevWatcher::OnReadable() {
  DCHECK(thread_.task_runner()->BelongsToCurrentThread());

  ScopedUdevDevicePtr dev(udev_monitor_receive_device(mon_.get()));
  if (!dev) {
    LOGF(ERROR) << "udev_monitor_receive_device failed";
    return;
  }

  const char* action = udev_device_get_action(dev.get());
  if (!action) {
    LOGF(ERROR) << "udev_device_get_action failed";
    return;
  }

  decltype(&Observer::OnDeviceAdded) callback;
  if (strcmp(action, "add") == 0) {
    callback = &Observer::OnDeviceAdded;
  } else if (strcmp(action, "remove") == 0) {
    callback = &Observer::OnDeviceRemoved;
  } else {
    NOTREACHED() << "Unexpected action " << action;
    return;
  }

  callback_task_runner_->PostTask(
      FROM_HERE, base::Bind(callback, base::Unretained(observer_),
                            base::Passed(std::move(dev))));
}

}  // namespace cros
