// Copyright 2019 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 "stream_protocol.h"

#include <utility>

#include <fbl/auto_lock.h>

#include "processing_node.h"
#include "src/lib/syslog/cpp/logger.h"

namespace camera {

constexpr auto kTag = "camera_controller";

StreamImpl::StreamImpl(async_dispatcher_t* dispatcher, ProcessNode* output_node)
    : dispatcher_(dispatcher), binding_(this), output_node_(*output_node) {}

zx_status_t StreamImpl::Attach(zx::channel channel, fit::function<void(void)> disconnect_handler) {
  FX_DCHECK(!binding_.is_bound());
  disconnect_handler_ = std::move(disconnect_handler);
  binding_.set_error_handler([this](zx_status_t status) {
    Shutdown(status);
    disconnect_handler_();
  });

  zx_status_t status = binding_.Bind(std::move(channel));
  if (status != ZX_OK) {
    FX_PLOGST(ERROR, kTag, status);
    return status;
  }
  return ZX_OK;
}

void StreamImpl::FrameReady(const frame_available_info_t* info) {
  // This method is invoked by the ISP in its own thread, so the event must be marshalled to the
  // binding's thread.
  async::PostTask(dispatcher_, [this, info = *info]() {
    fuchsia::camera2::FrameAvailableInfo frame_info;
    frame_info.frame_status = fuchsia::camera2::FrameStatus::OK;
    frame_info.buffer_id = info.buffer_id;
    frame_info.metadata.set_image_format_index(info.metadata.image_format_index);
    frame_info.metadata.set_timestamp(info.metadata.timestamp);
    binding_.events().OnFrameAvailable(std::move(frame_info));
  });
}

void StreamImpl::Shutdown(zx_status_t status) {
  // Close the connection if it's open.
  if (binding_.is_bound()) {
    binding_.Close(status);
  }

  // Stop streaming if its started
  if (started_) {
    Stop();
  }
}

void StreamImpl::Stop() {
  if (!started_) {
    Shutdown(ZX_ERR_BAD_STATE);
    return;
  }

  output_node_.OnStopStreaming();
  started_ = false;
}

void StreamImpl::Start() {
  if (started_) {
    Shutdown(ZX_ERR_BAD_STATE);
    return;
  }
  output_node_.OnStartStreaming();
  started_ = true;
}

void StreamImpl::ReleaseFrame(uint32_t buffer_id) { output_node_.OnReleaseFrame(buffer_id); }

void StreamImpl::AcknowledgeFrameError() {
  FX_LOGST(ERROR, kTag) << __PRETTY_FUNCTION__ << " not implemented";
  Shutdown(ZX_ERR_UNAVAILABLE);
}

void StreamImpl::SetRegionOfInterest(float /*x_min*/, float /*y_min*/, float /*x_max*/,
                                     float /*y_max*/, SetRegionOfInterestCallback /*callback*/) {
  FX_LOGST(ERROR, kTag) << __PRETTY_FUNCTION__ << " not implemented";
  Shutdown(ZX_ERR_UNAVAILABLE);
}

void StreamImpl::SetImageFormat(uint32_t /*image_format_index*/,
                                SetImageFormatCallback /*callback*/) {
  FX_LOGST(ERROR, kTag) << __PRETTY_FUNCTION__ << " not implemented";
  Shutdown(ZX_ERR_UNAVAILABLE);
}

void StreamImpl::GetImageFormats(GetImageFormatsCallback /*callback*/) {
  FX_LOGST(ERROR, kTag) << __PRETTY_FUNCTION__ << " not implemented";
  Shutdown(ZX_ERR_UNAVAILABLE);
}

}  // namespace camera
