/*
 * 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 "hal_adapter/camera_hal_test_adapter.h"

#include <string>

#include "cros-camera/future.h"

namespace cros {

CameraHalTestAdapter::CameraHalTestAdapter(
    std::vector<camera_module_t*> camera_modules,
    CameraMojoChannelManager* mojo_manager,
    CameraActivityCallback activity_callback,
    bool enable_front,
    bool enable_back,
    bool enable_external)
    : CameraHalAdapter(camera_modules, mojo_manager, activity_callback),
      enable_front_(enable_front),
      enable_back_(enable_back),
      enable_external_(enable_external) {
  VLOGF_ENTER();
  LOGF(INFO) << "Filter options: enable_front=" << enable_front_
             << ", enable_back=" << enable_back_
             << ", enable_external=" << enable_external_;
}

int32_t CameraHalTestAdapter::OpenDevice(
    int32_t camera_id,
    mojom::Camera3DeviceOpsRequest device_ops_request,
    cros::mojom::CameraClientType camera_client_type) {
  VLOGF_ENTER();

  base::Optional<int> unremapped_id = GetUnRemappedCameraId(camera_id);
  if (!unremapped_id) {
    return -EINVAL;
  }
  LOGF(INFO) << "From remap camera id " << camera_id << " to "
             << *unremapped_id;
  return CameraHalAdapter::OpenDevice(
      *unremapped_id, std::move(device_ops_request), camera_client_type);
}

int32_t CameraHalTestAdapter::GetNumberOfCameras() {
  VLOGF_ENTER();

  return enable_camera_ids_.size();
}

int32_t CameraHalTestAdapter::GetCameraInfo(int32_t camera_id,
                                            mojom::CameraInfoPtr* camera_info) {
  VLOGF_ENTER();

  base::Optional<int> unremapped_id = GetUnRemappedCameraId(camera_id);
  if (!unremapped_id) {
    camera_info->reset();
    return -EINVAL;
  }
  LOGF(INFO) << "From remap camera id " << camera_id << " to "
             << *unremapped_id;
  int32_t ret = CameraHalAdapter::GetCameraInfo(*unremapped_id, camera_info);
  if (ret != 0) {
    return ret;
  }
  if ((*camera_info)->conflicting_devices) {
    std::vector<std::string> conflicting_devices;
    for (const std::string& id_str : *(*camera_info)->conflicting_devices) {
      base::Optional<int> remapped_id = GetRemappedCameraId(std::stoi(id_str));
      if (remapped_id) {
        conflicting_devices.push_back(std::to_string(*remapped_id));
      }
    }
    (*camera_info)->conflicting_devices = std::move(conflicting_devices);
  }
  return 0;
}

int32_t CameraHalTestAdapter::SetTorchMode(int32_t camera_id, bool enabled) {
  VLOGF_ENTER();

  base::Optional<int> unremapped_id = GetUnRemappedCameraId(camera_id);
  if (!unremapped_id) {
    return -EINVAL;
  }
  LOGF(INFO) << "From remap camera id " << camera_id << " to "
             << *unremapped_id;
  return CameraHalAdapter::SetTorchMode(*unremapped_id, enabled);
}

void CameraHalTestAdapter::StartOnThread(base::Callback<void(bool)> callback) {
  VLOGF_ENTER();

  auto future = cros::Future<bool>::Create(nullptr);
  CameraHalAdapter::StartOnThread(cros::GetFutureCallback(future));

  if (!future.get()) {
    callback.Run(false);
    return;
  }

  for (int cam_id = 0; cam_id < CameraHalAdapter::GetNumberOfCameras();
       cam_id++) {
    camera_module_t* m;
    int internal_id;
    std::tie(m, internal_id) = CameraHalAdapter::GetInternalModuleAndId(cam_id);

    camera_info_t info;
    int ret = m->get_camera_info(internal_id, &info);
    if (ret != 0) {
      LOGF(ERROR) << "Failed to get info of camera " << cam_id;
      callback.Run(false);
      return;
    }

    if ((info.facing == CAMERA_FACING_BACK && enable_back_) ||
        (info.facing == CAMERA_FACING_FRONT && enable_front_)) {
      LOGF(INFO) << "Remap camera id " << cam_id << "->"
                 << enable_camera_ids_.size();
      enable_camera_ids_.push_back(cam_id);
    } else {
      LOG(INFO) << "Filter out camera " << internal_id << " facing "
                << info.facing << " of module " << m->common.name;
    }
  }
  LOGF(INFO) << "Enable total " << enable_camera_ids_.size() << " cameras";
  callback.Run(true);
}

void CameraHalTestAdapter::NotifyCameraDeviceStatusChange(
    CameraModuleCallbacksDelegate* delegate,
    int camera_id,
    camera_device_status_t status) {
  VLOGF_ENTER();

  base::Optional<int> remapped_id = GetRemappedCameraId(camera_id);
  if (remapped_id) {
    LOGF(INFO) << "Remap external camera id " << camera_id << "->"
               << *remapped_id;
    CameraHalAdapter::NotifyCameraDeviceStatusChange(delegate, *remapped_id,
                                                     status);
  }
}

void CameraHalTestAdapter::NotifyTorchModeStatusChange(
    CameraModuleCallbacksDelegate* delegate,
    int camera_id,
    torch_mode_status_t status) {
  VLOGF_ENTER();

  base::Optional<int> remapped_id = GetRemappedCameraId(camera_id);
  if (remapped_id) {
    CameraHalAdapter::NotifyTorchModeStatusChange(delegate, *remapped_id,
                                                  status);
  }
}

base::Optional<int> CameraHalTestAdapter::GetUnRemappedCameraId(int camera_id) {
  if (camera_id < 0) {
    LOGF(ERROR) << "Invalid remapped camera id: " << camera_id;
    return {};
  }
  if (camera_id < enable_camera_ids_.size()) {
    return enable_camera_ids_[camera_id];
  } else if (enable_external_) {
    return camera_id - GetNumberOfCameras() +
           CameraHalAdapter::GetNumberOfCameras();
  } else {
    return {};
  }
}

base::Optional<int> CameraHalTestAdapter::GetRemappedCameraId(int camera_id) {
  if (camera_id < 0) {
    LOGF(ERROR) << "Invalid unremapped camera id: " << camera_id;
    return {};
  }
  if (camera_id < CameraHalAdapter::GetNumberOfCameras()) {
    auto it = std::find(enable_camera_ids_.begin(), enable_camera_ids_.end(),
                        camera_id);
    return it != enable_camera_ids_.end() ? it - enable_camera_ids_.begin()
                                          : base::Optional<int>{};
  } else if (enable_external_) {
    return camera_id - CameraHalAdapter::GetNumberOfCameras() +
           GetNumberOfCameras();
  } else {
    return {};
  }
}

}  // namespace cros
