#include <xavia/sensorFactory.h>
#include <xavia/iSensor.h>
#include <xavia/iCamera.h>
#include <xavia/iImage.h>
#include <xavia/error.h>
#include <xavia/logs.h>

#include <iostream>
#include <fstream>
#include <chrono>
#include <thread>
#include <atomic>

namespace xsdk = xavia::sdk;

std::atomic<int> imageCount{0};

/* CAMERA IMAGE RECORDING EXAMPLE (BayerRG12bit packed)
 * 
 * This example demonstrates how to handle recording of images as 12 bit packed bayer
 * The steps are:
 * 1. Set up a callback function to handle incoming images.
 * 2. Configure the camera to output 12 bit packed images.
 * 3. Build the sensor and get the camera.
 * 4. Start the camera.
 * 5. Process images as they arrive in the callback.
 * 6. Stop the camera when done.
 */

void imageCallback(std::unique_ptr<xsdk::IImage> image)
{
  // step 5. Process incoming image
  ++imageCount;
  const auto& metadata = image->GetMetaData();
  const auto bytesPerPixel = image->GetPixelData().size() / (metadata.width * metadata.height);
  
  std::wcout << L"Image #" << metadata.frameNumber;
  
  // keep this function short. The below is only an example, we advise to put the
  // saveAsJpeg in a separate thread in production code.
  try
  {
    // the library will automatically convert to RGB8
    image->SaveAsJpeg(L"image_" + std::to_wstring(metadata.frameNumber) + L"_B12p.jpg", 90, false); // note for in manual: chromatic subsampling increases output speed by 60%. quality does not have a big impact on speed.
    std::wcout << L" - saved successfully." << std::endl;
  }
  catch(const std::exception& e)
  {
    std::wcerr << L" - ERROR! Failed to save image as jpeg: " << e.what() << std::endl;
  }
}

void errorCallback(const xsdk::Exception& ex)
{
  std::wcerr << L"Error: " << ex.what() << std::endl;
}

int main(int argc, char** argv)
{
  try
  {
    std::wcout << L"=== Camera recording BayerRG12 bit packed Example ===" << std::endl;

    // logging is not mandatory, but we need to convert to std::wcout.
    xsdk::SetLogCallBack([](const xsdk::Severity& sev, const std::wstring& msg)
                       { std::wcout << xsdk::GetLogTypeString(sev) << L": " << msg << std::endl; });
    xsdk::SetLogSeverity(xsdk::Severity::XM_INFO);
    
    xsdk::SensorFactory factory;
    factory.SetErrorCallback(errorCallback); // optional
    
    // step 1. Set up image callbacks
    // setting this callback is required to activate the camera part of the sdk.
    factory.SetImageCallback(imageCallback);

    // step 2. Configure the camera to output BayerRG12 bit packed images
    factory.SetImageOutputFormat(xavia::sdk::PixelFormat::BayerRG12packed);
    
    // step 3. Build the sensor and get the camera
    auto sensor = factory.Build();
    auto camera = sensor->GetCamera();
    
    // always check if the camera is available before trying to use it.
    // The camera may not be available due to various reasons.
    if (!camera)
    {
      std::wcerr << L"Camera not available" << std::endl;
      return EXIT_FAILURE;
    }
    std::wcout << L"Connected to Camera ID: " << camera->GetCameraIdW() << std::endl;

    // step 4. Start the camera
    camera->Start();

    std::this_thread::sleep_for(std::chrono::seconds(5));

    // step 6. Stop the camera
    camera->Stop();

    std::wcout << L"Total images received: " << imageCount << std::endl;
  }
  catch (const std::exception& ex)
  {
    std::wcerr << L"Exception: " << ex.what() << std::endl;
    return EXIT_FAILURE;
  }

  std::wcout << L"=== Camera recording BayerRG12 bit packed Example Completed ===" << std::endl;
  return EXIT_SUCCESS;
}
