/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "vsock_frame_provider.h"
#include <hardware/camera3.h>
#include <libyuv.h>
#include <cstring>
#define LOG_TAG "VsockFrameProvider"
#include <log/log.h>

namespace cuttlefish {

VsockFrameProvider::~VsockFrameProvider() { stop(); }

void VsockFrameProvider::start(
    std::shared_ptr<cuttlefish::VsockConnection> connection, uint32_t width,
    uint32_t height) {
  stop();
  running_ = true;
  connection_ = connection;
  reader_thread_ =
      std::thread([this, width, height] { VsockReadLoop(width, height); });
}

void VsockFrameProvider::stop() {
  running_ = false;
  jpeg_pending_ = false;
  if (reader_thread_.joinable()) {
    reader_thread_.join();
  }
  connection_ = nullptr;
}

bool VsockFrameProvider::waitYUVFrame(unsigned int max_wait_ms) {
  auto timeout = std::chrono::milliseconds(max_wait_ms);
  nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
  std::unique_lock<std::mutex> lock(frame_mutex_);
  return yuv_frame_updated_.wait_for(
      lock, timeout, [this, now] { return timestamp_.load() > now; });
}

void VsockFrameProvider::requestJpeg() {
  jpeg_pending_ = true;
  Json::Value message;
  message["event"] = "VIRTUAL_DEVICE_CAPTURE_IMAGE";
  if (connection_) {
    connection_->WriteMessage(message);
  }
}

void VsockFrameProvider::cancelJpegRequest() { jpeg_pending_ = false; }

bool VsockFrameProvider::copyYUVFrame(uint32_t w, uint32_t h, YCbCrLayout dst) {
  size_t y_size = w * h;
  size_t cbcr_size = (w / 2) * (h / 2);
  size_t total_size = y_size + 2 * cbcr_size;
  std::lock_guard<std::mutex> lock(frame_mutex_);
  if (frame_.size() < total_size) {
    ALOGE("%s: %zu is too little for %ux%u frame", __FUNCTION__, frame_.size(),
          w, h);
    return false;
  }
  if (dst.y == nullptr) {
    ALOGE("%s: Destination is nullptr!", __FUNCTION__);
    return false;
  }
  YCbCrLayout src{.y = static_cast<void*>(frame_.data()),
                  .cb = static_cast<void*>(frame_.data() + y_size),
                  .cr = static_cast<void*>(frame_.data() + y_size + cbcr_size),
                  .yStride = w,
                  .cStride = w / 2,
                  .chromaStep = 1};
  uint8_t* src_y = static_cast<uint8_t*>(src.y);
  uint8_t* dst_y = static_cast<uint8_t*>(dst.y);
  uint8_t* src_cb = static_cast<uint8_t*>(src.cb);
  uint8_t* dst_cb = static_cast<uint8_t*>(dst.cb);
  uint8_t* src_cr = static_cast<uint8_t*>(src.cr);
  uint8_t* dst_cr = static_cast<uint8_t*>(dst.cr);
  libyuv::CopyPlane(src_y, src.yStride, dst_y, dst.yStride, w, h);
  if (dst.chromaStep == 1) {
    // Planar
    libyuv::CopyPlane(src_cb, src.cStride, dst_cb, dst.cStride, w / 2, h / 2);
    libyuv::CopyPlane(src_cr, src.cStride, dst_cr, dst.cStride, w / 2, h / 2);
  } else if (dst.chromaStep == 2 && dst_cr - dst_cb == 1) {
    // Interleaved cb/cr planes starting with cb
    libyuv::MergeUVPlane(src_cb, src.cStride, src_cr, src.cStride, dst_cb,
                         dst.cStride, w / 2, h / 2);
  } else if (dst.chromaStep == 2 && dst_cb - dst_cr == 1) {
    // Interleaved cb/cr planes starting with cr
    libyuv::MergeUVPlane(src_cr, src.cStride, src_cb, src.cStride, dst_cr,
                         dst.cStride, w / 2, h / 2);
  } else {
    ALOGE("%s: Unsupported interleaved U/V layout", __FUNCTION__);
    return false;
  }
  return true;
}

bool VsockFrameProvider::copyJpegData(uint32_t size, void* dst) {
  std::lock_guard<std::mutex> lock(jpeg_mutex_);
  auto jpeg_header_offset = size - sizeof(struct camera3_jpeg_blob);
  if (cached_jpeg_.empty()) {
    ALOGE("%s: No source data", __FUNCTION__);
    return false;
  } else if (dst == nullptr) {
    ALOGE("%s: Destination is nullptr", __FUNCTION__);
    return false;
  } else if (jpeg_header_offset <= cached_jpeg_.size()) {
    ALOGE("%s: %ubyte target buffer too small", __FUNCTION__, size);
    return false;
  }
  std::memcpy(dst, cached_jpeg_.data(), cached_jpeg_.size());
  struct camera3_jpeg_blob* blob = reinterpret_cast<struct camera3_jpeg_blob*>(
      static_cast<char*>(dst) + jpeg_header_offset);
  blob->jpeg_blob_id = CAMERA3_JPEG_BLOB_ID;
  blob->jpeg_size = cached_jpeg_.size();
  cached_jpeg_.clear();
  return true;
}

bool VsockFrameProvider::isBlob(const std::vector<char>& blob) {
  bool is_png = blob.size() > 4 && (blob[0] & 0xff) == 0x89 &&
                (blob[1] & 0xff) == 0x50 && (blob[2] & 0xff) == 0x4e &&
                (blob[3] & 0xff) == 0x47;
  bool is_jpeg =
      blob.size() > 2 && (blob[0] & 0xff) == 0xff && (blob[1] & 0xff) == 0xd8;
  return is_png || is_jpeg;
}

bool VsockFrameProvider::framesizeMatches(uint32_t width, uint32_t height,
                                          const std::vector<char>& data) {
  return data.size() == 3 * width * height / 2;
}

void VsockFrameProvider::VsockReadLoop(uint32_t width, uint32_t height) {
  jpeg_pending_ = false;
  while (running_.load() && connection_->ReadMessage(next_frame_)) {
    if (framesizeMatches(width, height, next_frame_)) {
      std::lock_guard<std::mutex> lock(frame_mutex_);
      timestamp_ = systemTime();
      frame_.swap(next_frame_);
      yuv_frame_updated_.notify_one();
    } else if (isBlob(next_frame_)) {
      std::lock_guard<std::mutex> lock(jpeg_mutex_);
      bool was_pending = jpeg_pending_.exchange(false);
      if (was_pending) {
        cached_jpeg_.swap(next_frame_);
      }
    } else {
      ALOGE("%s: Unexpected data of %zu bytes", __FUNCTION__,
            next_frame_.size());
    }
  }
  if (!connection_->IsConnected()) {
    ALOGE("%s: Connection closed - exiting", __FUNCTION__);
    running_ = false;
  }
}

}  // namespace cuttlefish
