// Copyright 2020 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/lib/fake_camera/fake_camera_impl.h"

#include <lib/async-loop/default.h>
#include <lib/async/cpp/task.h>
#include <lib/fit/function.h>
#include <lib/syslog/cpp/macros.h>
#include <zircon/errors.h>

#include "src/camera/lib/fake_stream/fake_stream_impl.h"

namespace camera {

fpromise::result<std::unique_ptr<FakeCamera>, zx_status_t> FakeCamera::Create(
    std::string identifier, std::vector<FakeConfiguration> configurations) {
  auto result = FakeCameraImpl::Create(std::move(identifier), std::move(configurations));
  if (result.is_error()) {
    return fpromise::error(result.error());
  }
  return fpromise::ok(result.take_value());
}

FakeCameraImpl::FakeCameraImpl() : loop_(&kAsyncLoopConfigNoAttachToCurrentThread) {}

FakeCameraImpl::~FakeCameraImpl() {
  async::PostTask(loop_.dispatcher(), fit::bind_member(this, &FakeCameraImpl::OnDestruction));
  loop_.Quit();
  loop_.JoinThreads();
}

static zx_status_t Validate(const std::vector<FakeConfiguration>& configurations) {
  zx_status_t status = ZX_OK;

  if (configurations.empty()) {
    status = ZX_ERR_INVALID_ARGS;
    FX_PLOGS(DEBUG, status) << "Configurations must not be empty.";
  }

  for (const auto& configuration : configurations) {
    if (configuration.empty()) {
      status = ZX_ERR_INVALID_ARGS;
      FX_PLOGS(DEBUG, status) << "Configuration must not be empty.";
    }
    for (const auto& stream : configuration) {
      if (!stream) {
        status = ZX_ERR_INVALID_ARGS;
        FX_PLOGS(DEBUG, status) << "Stream must be non-null.";
      }
    }
  }

  return status;
}

fpromise::result<std::unique_ptr<FakeCameraImpl>, zx_status_t> FakeCameraImpl::Create(
    std::string identifier, std::vector<FakeConfiguration> configurations) {
  auto camera = std::make_unique<FakeCameraImpl>();

  zx_status_t status = Validate(configurations);
  if (status != ZX_OK) {
    FX_PLOGS(DEBUG, status) << "Configurations failed validation.";
    return fpromise::error(status);
  }

  camera->identifier_ = std::move(identifier);
  camera->configurations_ = std::move(configurations);

  for (auto& configuration : camera->configurations_) {
    fuchsia::camera3::Configuration real_configuration;
    for (auto& stream : configuration) {
      auto stream_impl = reinterpret_cast<FakeStreamImpl*>(stream.get());
      real_configuration.streams.push_back(stream_impl->properties_);
    }
    camera->real_configurations_.push_back(std::move(real_configuration));
  }

  ZX_ASSERT(camera->loop_.StartThread("Fake Camera Loop") == ZX_OK);

  return fpromise::ok(std::move(camera));
}

fidl::InterfaceRequestHandler<fuchsia::camera3::Device> FakeCameraImpl::GetHandler() {
  return fit::bind_member(this, &FakeCameraImpl::OnNewRequest);
}

void FakeCameraImpl::SetHardwareMuteState(bool muted) { bindings_.CloseAll(ZX_ERR_NOT_SUPPORTED); }

void FakeCameraImpl::OnNewRequest(fidl::InterfaceRequest<fuchsia::camera3::Device> request) {
  if (bindings_.size() > 0) {
    request.Close(ZX_ERR_ALREADY_BOUND);
    return;
  }

  bindings_.AddBinding(this, std::move(request), loop_.dispatcher());
}

void FakeCameraImpl::OnDestruction() { bindings_.CloseAll(ZX_ERR_IO_NOT_PRESENT); }

template <class T>
void FakeCameraImpl::SetDisconnectErrorHandler(fidl::InterfacePtr<T>& p) {
  p.set_error_handler([this](zx_status_t status) {
    FX_PLOGS(ERROR, status) << "Dependent component disconnected.";
    bindings_.CloseAll(ZX_ERR_INTERNAL);
  });
}

void FakeCameraImpl::GetIdentifier(GetIdentifierCallback callback) { callback(identifier_); }

void FakeCameraImpl::GetConfigurations(GetConfigurationsCallback callback) {
  callback(real_configurations_);
}

void FakeCameraImpl::WatchCurrentConfiguration(WatchCurrentConfigurationCallback callback) {
  bindings_.CloseAll(ZX_ERR_NOT_SUPPORTED);
}

void FakeCameraImpl::SetCurrentConfiguration(uint32_t index) {
  bindings_.CloseAll(ZX_ERR_NOT_SUPPORTED);
}

void FakeCameraImpl::WatchMuteState(WatchMuteStateCallback callback) {
  bindings_.CloseAll(ZX_ERR_NOT_SUPPORTED);
}

void FakeCameraImpl::SetSoftwareMuteState(bool muted, SetSoftwareMuteStateCallback callback) {
  bindings_.CloseAll(ZX_ERR_NOT_SUPPORTED);
}

void FakeCameraImpl::ConnectToStream(uint32_t index,
                                     fidl::InterfaceRequest<fuchsia::camera3::Stream> request) {
  configurations_[current_configuration_index_][index]->GetHandler()(std::move(request));
}

void FakeCameraImpl::Rebind(fidl::InterfaceRequest<Device> request) {
  bindings_.CloseAll(ZX_ERR_NOT_SUPPORTED);
}

}  // namespace camera
