// Copyright 2016 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/camera/camera_manager/camera_manager_impl.h"

#include <ddk/debug.h>
#include <ddk/driver.h>
#include <fbl/unique_fd.h>
#include <fcntl.h>

#include <string>

namespace camera {

static const char* kCameraDevicePath = "/dev/class/camera";

CameraManagerImpl::CameraManagerImpl(async::Loop* loop) {
  // Step #0: Try to connect to /dev/test/virtual_camera
  FXL_LOG(INFO) << "Adding tests camera devices";
  int open_result = open("/dev/test", O_DIRECTORY | O_RDONLY);
  if (open_result >= 0) {
    fbl::unique_fd dir_fd(open_result);
    OnDeviceFound(open_result, "/dev/test/virtual_camera");
  } else {
    FXL_LOG(INFO) << "/dev/test is not available (" << open_result << ")";
  }

  // Step #1: Begin monitoring for plug/unplug events for pluggable cameras
  bool idle_seen = false;
  device_watcher_ = fsl::DeviceWatcher::CreateWithIdleCallback(
      kCameraDevicePath,
      // Function to be called when adding a camera:
      fbl::BindMember(this, &CameraManagerImpl::OnDeviceFound),
      // Function to be called when all existing devices have been found:
      // This function captures the local variable idle_seen
      // because it will only be called while we are in this constructor.
      [&idle_seen] { idle_seen = true; });
  if (device_watcher_ == nullptr) {
    FXL_LOG(ERROR) << " failed to create DeviceWatcher.";
    return;
  }
  // Now we need to wait until:
  // #1 we have received the IDLE notification, indicating that all the devices
  // that were plugged in have been added, and
  // #2 all of those devices have finished gathering information from their
  // drivers.
  // We do this by spinning the async loop one event at a time until the devices
  // all report in.  VideoDeviceClients are guaranteed to either gather all the
  // necessary information, or time out (or error out), so we know that this
  // loop will finish.
  zx_status_t status;
  while (!idle_seen || !inactive_devices_.empty()) {
    status = loop->Run(zx::time::infinite(), true);
    if (status != ZX_OK) {
      return;
    }
  }

  // Now bind our context, and publish the public service:
  // Note that CreateFromStartupInfo must be called after we do our looping
  // above, or the request for the CameraManager may fail.
  // TODO(CAM-18):  Change the interface to encourage dynamic detections by the
  // application, and we won't have to do this.
  context_ = component::StartupContext::CreateFromStartupInfo();
  context_->outgoing().AddPublicService(bindings_.GetHandler(this));
}

// The dispatcher loop should be shut down when this destructor is called.
// No further messages should be handled after this destructor is called.
CameraManagerImpl::~CameraManagerImpl() {
  // Stop monitoring plug/unplug events.  We are shutting down and
  // no longer care about devices coming and going.
  device_watcher_ = nullptr;
  // In case we just discovered any new devices:
  inactive_devices_.clear();
  // Shut down each currently active device in the system.
  active_devices_.clear();
}

void CameraManagerImpl::OnDeviceFound(int dir_fd, std::string filename) {
  auto video_device = VideoDeviceClient::Create(dir_fd, filename);
  if (video_device) {
    AddDevice(std::move(video_device));
  } else {
    // If we can't create the device, drop it.
    FXL_LOG(ERROR) << "Failed to create device " << filename;
  }
}

void CameraManagerImpl::AddDevice(
    std::unique_ptr<VideoDeviceClient> video_device) {
  // Initially add the device to the inactive devices until we get all
  // the information we need from it.
  inactive_devices_.push_back(std::move(video_device));
  inactive_devices_.back()->Startup(
      [this, id = inactive_devices_.back()->id()](zx_status_t status) {
        OnDeviceStartupComplete(id, status);
      });
}

void CameraManagerImpl::OnDeviceStartupComplete(uint64_t camera_id,
                                                zx_status_t status) {
  for (auto iter = inactive_devices_.begin(); iter != inactive_devices_.end();
       iter++) {
    if ((*iter)->id() == camera_id) {
      // Now that we found the device, either put it in the active list,
      // or shut it down, depending on the status.
      if (status == ZX_OK) {
        // We put the newly active device in the front of active_devices_,
        // but it doesn't really matter what order the devices are stored in.
        active_devices_.splice(active_devices_.begin(), inactive_devices_,
                               iter);
      } else {
        inactive_devices_.erase(iter);
      }
      break;
    }
  }
}

void CameraManagerImpl::GetDevices(GetDevicesCallback callback) {
  fidl::VectorPtr<fuchsia::camera::DeviceInfo> device_descriptions;
  for (auto& device : active_devices_) {
    device_descriptions.push_back(device->GetDeviceInfo());
  }
  callback(std::move(device_descriptions));
}

void CameraManagerImpl::GetFormats(uint64_t camera_id, uint32_t index,
                                   GetFormatsCallback callback) {
  const std::vector<fuchsia::camera::VideoFormat>* formats;
  for (auto& device : active_devices_) {
    if (device->id() == camera_id) {
      formats = device->GetFormats();
      break;
    }
  }

  size_t min_index =
      std::max((size_t)0, std::min((size_t)index, formats->size() - 1));
  size_t max_index =
      std::min(min_index + fuchsia::camera::MAX_FORMATS_PER_RESPONSE - 1,
               formats->size() - 1);

  callback(std::vector<fuchsia::camera::VideoFormat>(
               &(*formats)[min_index], &(*formats)[max_index + 1]),
           formats->size());
}

void CameraManagerImpl::CreateStream(
    fuchsia::camera::VideoStream request,
    fuchsia::sysmem::BufferCollectionInfo buffer_collection,
    fidl::InterfaceRequest<fuchsia::camera::Stream> stream,
    zx::eventpair client_token) {
  for (auto& device : active_devices_) {
    if (device->id() == request.camera_id) {
      device->CreateStream(std::move(buffer_collection), request.format.rate,
                           std::move(stream), std::move(client_token));
      break;
    }
  }
}

}  // namespace camera
