/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016 Raytrix GmbH. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/************************************************************************/
/*  This example demonstrates:                                          */
/*      - Working with a camera.                                        */
/*      - Calculating refocus image                                     */
/*      - Displaying result                                             */
/************************************************************************/

// This class was heavily modified from RX example camera
#include "RxReader.h"





RxReader::~RxReader() {

}

RxReader::RxReader(string raysFile) {

	this->raysFile = raysFile;

	// Strip out file path into a file name
	string outputFile = raysFile;
	outputFile = outputFile.substr(3);
	for (int i = 0; i < outputFile.length(); i++) {
		if (outputFile[i] == '\\')
			outputFile[i] = '-';
	}
	outputFile = "E:\\" + outputFile;

	bValidCamera = false;
	bSimCamera = false;
	bWriteImages = false;
	bPaused = false;
	imageUpdated = false;
	bFinished = false;
	gain = 0.0;
	dFocus = 0.5;
	frameCounter = 0;
	displayType = RAW;
	lastFrameCount = 0;

	imageFormat.m_iHeight = 5120;
	imageFormat.m_iWidth = 5120;
	imageFormat.m_eDataType = Rx::Interop::Runtime28::EDataType::UByte;
	imageFormat.m_ePixelType = Rx::Interop::Runtime28::EPixelType::Lum;

	int uID = 0;

	try
	{

		_sleep(100);

		// Authenticate MGPU runtime
		printf("Authenticate LFR...\n");
		Rx::LFR::CLightFieldRuntime::Authenticate();

		// Enumerate all CUDA devices at the beginning
		Rx::LFR::CCuda::EnumerateCudaDevices();

		// Iterate over all available Cuda devices
		printf("Listing Cuda devices...\n");
		for (int iIdx = 0; iIdx < Rx::LFR::CCuda::GetDeviceCount(); iIdx++)
		{
			const Rx::LFR::CCudaDevice& xCuda = Rx::LFR::CCuda::GetDevice(iIdx);

			xCuda.GetParams().GetValue(Rx::LFR::Params::ECudaDevice::Name, sxName);

			xCuda.GetParams().GetValue(Rx::LFR::Params::ECudaDevice::ClockFrequencyMHz, dClockMHz);

			xCuda.GetParams().GetValue(Rx::LFR::Params::ECudaDevice::TotalGlobalMemoryMB, dGlobalMemMB);

			printf("%d: %s, Clock: %.0f MHz, Memory: %.0f MB\n", iIdx, sxName.ToCString(), dClockMHz, dGlobalMemMB);
		}

		
		std::cout << "Loading " << raysFile << "..." << std::endl;
		seqReader.Open(raysFile.c_str(), 100);
		seqReader.StartReading(readImage);
		imgProc.setCameraCalibration(uID, readImage.GetCalibration());


		// Apply the camera uID and calibration to image processor
		std::cout << "Setting up processor...";
		imgProc.setImageFormat(imageFormat);
		imgProc.setVideoOutputFile(outputFile);
		imgProc.initCudaWithImage(); // Slow!!
		_sleep(2000);

		std::cout << "Ready." << std::endl;


	}
	catch (Rx::CRxException& ex)
	{
		printf("Exception occured:\n%s\n\n", ex.ToString(true).ToCString());
		printf("Press any key to end program...\n");
		_getch();
	}
	catch (Rx::IException31& ex)
	{
		printf("Exception occured:\n%s\n\n", ex.GetMessageText());
		printf("Press any key to end program...\n");
		_getch();
	}
}


int RxReader::start() {


	seqReader.ReadFrame(readImage);

	imgProc.start();

	// Start the image processing thread
	startThread();

	return 0;

}

int RxReader::pause() {
	bPaused = true;
	cout << "paused" << endl;
	return 0;
}

int RxReader::unPause() {
	bPaused = false;
	cout << "unpaused" << endl;
	return 0;
}

bool RxReader::isPaused() {
	return bPaused;
}

int RxReader::stop() {

	// Stop thread
	stopThread();


	imgProc.stop();

	printf("done.\n");

	// Finalize Cuda and the runtime
	Rx::LFR::CLightFieldRuntime::End();

	return 0;

}


void RxReader::setDisplayType(RxProcessor::IMAGE_DISPLAY_TYPE t) {
	imgProc.setDisplayType(t);
}

void RxReader::threadedFunction() {

	while (this->isThreadRunning())
	{

		if (bPaused) {
			sleep(1000);
			continue;
		}

		if (seqReader.GetFrameIndex() >= seqReader.GetFrameCount()) {
			bFinished = imgProc.queueSize() == 0;
			if (bFinished)
				break;
			else {
				sleep(100);
				continue;
			}
		}
		// Read image from sequence queue
		seqReader.ReadFrame(readImage);
		imgProc.addImage(readImage);

	}

}
