#include "RxProcessor.h"

RxProcessor::RxProcessor() {
	iHandle = 0;
	uID = 0;
	pxImages = NULL;
	haveCameraCal = false;
	// Authenticate MGPU runtime
	printf("Authenticate LFR...\n");
	Rx::LFR::CLightFieldRuntime::Authenticate();
}

RxProcessor::~RxProcessor() {
	haveCameraCal = false;
}

RxProcessor::RxProcessor(unsigned int uID, Rx::LFR::CCalibration& xDefaultCalibration) {

	// Authenticate MGPU runtime
	printf("Authenticate LFR...\n");
	Rx::LFR::CLightFieldRuntime::Authenticate();

	this->uID = uID;
	setCameraCalibration(uID, xDefaultCalibration);

}

void RxProcessor::setCameraCalibration(unsigned int uID, Rx::LFR::CCalibration& xDefaultCalibration) {
	
	// For this example just work with one camera and one GPU
	xCudaCompute.SetCudaDevice(Rx::LFR::CCuda::GetDevice(uID));
	xCudaCompute.ApplyCalibration(xDefaultCalibration, true);
	xCudaCompute.GetParams().SetValue(Rx::LFR::Params::ECudaCompute::PreProc_DataType, (unsigned)Rx::Interop::Runtime28::EDataType::UByte);

	// Get the image access interface.
	pxImages = static_cast<Rx::LFR::ICudaDataImages*>(xCudaCompute.GetInterface(Rx::LFR::Interfaces::ECudaCompute::Images));

	haveCameraCal = true;

}

void RxProcessor::addImage(const Rx::CRxImage& xImage)
{

	try
	{

		Rx::CRxImage xCapturedImage1;
		// Make a copy of the provided image. We don't know if this image is reused by the camera SDK or by another handler
		xCapturedImage1.Create(&xImage);



		/************************************************************************/
		/* Write into buffer                                                    */
		/************************************************************************/
		if (!m_xImageBuffer.MoveIn(std::move(xCapturedImage1)))
		{
			// Buffer is full and overwrite is disabled
			// This is a lost frame
			std::cout << "imgProc: dropped Image!" << std::endl;
			return;
		}

	}
	catch (Rx::CRxException& ex)
	{
		printf("Exception occured:\n%s\n\n", ex.ToString(true).ToCString());
		printf("Press any key to end program...\n");
		_getch();
	}
}

int RxProcessor::start() {

	if (!haveCameraCal) {
		std::cout << "Can't start processor thread without calibration." << std::endl;
		return 1;
	}

	// load the window
	CLUViz::Tool::CreateViewImage(iHandle, 0, 0, 1000, 800, "RxProcessorView");

	// Start the image processing thread
	startThread();

	return 0;

}

int RxProcessor::stop() {

	// Finalize Cuda and the runtime
	Rx::LFR::CLightFieldRuntime::End();

	// Stop thread
	stopThread();

	return 0;

}

void RxProcessor::threadedFunction() {

	while (isThreadRunning())
	{

		// Wait for the image buffer to be not empty
		if (!m_xImageBuffer.WaitForNotEmpty(5))
		{
			continue;
		}

		// Check if a new image should be get from the image buffer or the previous image sould be updated
		if (!m_xImageBuffer.MoveOut(xCapturedImage))
		{
			{
				// Wait again! This functions says that it waits until a frame is available
				continue;
			}
		}

		totalFocusProc();


	}


}

void RxProcessor::totalFocusProc() {

	// Upload the image as the new raw image of all further CUDA computations
	//printf("Uploading image to Cuda compute instance...\n");
	xCudaCompute.UploadRawImage(xCapturedImage);

	// Pre-process raw light field image before calling any processing functions
	//printf("Pre-processing light field image...\n");
	xCudaCompute.Compute_PreProcess();
	xCudaCompute.Compute_TotalFocus();
	pxImages->Download(Rx::LFR::EImage::TotalFocus_View_Object_Pinhole, &xOutputImage);
	CLUViz::Tool::ViewSetImage(iHandle, &xOutputImage);

}

void RxProcessor::rawImageProc() {

	// Upload the image as the new raw image of all further CUDA computations
	//printf("Uploading image to Cuda compute instance...\n");
	xCudaCompute.UploadRawImage(xCapturedImage);

	// Pre-process raw light field image before calling any processing functions
	//printf("Pre-processing light field image...\n");
	xCudaCompute.Compute_PreProcess();
	pxImages->Download(Rx::LFR::EImage::Raw, &xOutputImage);
	CLUViz::Tool::ViewSetImage(iHandle, &xOutputImage);

}