//
// Created by Krad on 2021/10/12.
//
#include "ShimLib/ShimLib.h"
#include "DeviceManager.h"
#include "../event/EventCenter.h"
#include <QVariant>
#include <QTimerEvent>
#include <QDate>
#include <QDateTime>
#include <qdebug.h>
#include "appvals/AppGlobalValues.h"
#define TRIGGER_EVENT EventCenter::Default()->triggerEvent

#define THROW_ERROR(errormsg)\
TRIGGER_EVENT(GUIEvents::GUIErrorRaise, nullptr, (QObject*)&errormsg);


const char* getStatusString(int status)
{
	switch (status) {
	case SCANNING:
		return "SCANNING";
	case READY:
		return "Ready";
	case BUSY:
		return "BUSY";
	case ERROR:
		return "ERROR";
	}
	return "";
}


std::string getJsonFromPatInf(QObject* obj)
{
	return ((QString*)obj)->toStdString();
}

void ErrorCallback(const char* msg)
{
    DeviceManager::Default()->emitErrorCallback(msg);
}

void DeviceManager::emitErrorCallback(const char *msg) {
    this->setErrorOccurred(true);
    printf("Error Callback , message:%s\r\n", msg);
    QString m(msg);
    emit raiseGlobalError( m);
}


void DeviceManager::initDevice() {
	InitLib(ErrorCallback);

	deviceInfTimerID = startTimer(1000);

	// empty scan
	connect(EventCenter::Default(), &EventCenter::RequestEmptyScan, [=](QObject* sender, QObject* detail) {
		std::string json = getJsonFromPatInf(detail);
		//        qDebug()<<json.c_str();
		//        void * jss = malloc(json.size());
		//        memcpy(jss,json.c_str(),json.size());
		//        processScan((char*)jss,true);
		processScan(json.c_str(), true);
		});
	// Patient scan
	connect(EventCenter::Default(), &EventCenter::RequestPatientScan, [=](QObject* sender, QObject* detail) {
		std::string json = getJsonFromPatInf(detail);
		qDebug() << json.c_str();
		if (!json.empty())
		{
			//            void * jss = malloc(json.size());
			//            memcpy(jss,json.c_str(),json.size());
			//            processScan((char*)jss);
			processScan(json.c_str());
		}
		});
	// stop
	connect(EventCenter::Default(), &EventCenter::RequestStop, [=]() {
		qDebug() << "GetStatus";
		StatusInfo inf = GetStatus();
		qDebug() << "Stop request status, status:%s" << getStatusString(inf.status);

		// check device status=========================================
		//device is ready return
		if (inf.status != SCANNING) {
            //double check
            QThread::msleep(100);
            inf = GetStatus();
            if (inf.status != SCANNING){
                TRIGGER_EVENT(GUIEvents::ResponseStop, nullptr, nullptr);
                return;
            }
		}
		//        if (inf.status == BUSY) {
		//            QString msg("Device is busy, Stop operation fail!");
		//            THROW_ERROR(msg);
		//            return;
		//        };
		AppGlobalValues::setInProcessing(true);
		TRIGGER_EVENT(GUIEvents::InvokeOperationStart, nullptr, nullptr);
		//ScanControl fail
		qDebug() << "Request stop!";
		if (timerID != -1)killTimer(timerID);
		if (ScanControl(STOP)) {
			qDebug() << "Stop fail!";
			QString msg("Stop operation fail!");
			THROW_ERROR(msg);
			qDebug() << "Error thrown!";
			lastStatus = -1;
			previewing = false;
			QString s("%1  %2");
			s = s.arg(QDateTime::currentDateTime().toString("yyyy/MM/dd HH:mm:ss"), msg);
			TRIGGER_EVENT(GUIEvents::GlobalBannerMessage, nullptr, (QObject*)&msg);
			return;
		}
		lastStatus = -1;
		previewing = false;
		QString s("%1  %2");
		s = s.arg(QDateTime::currentDateTime().toString("yyyy/MM/dd HH:mm:ss"), ("Scan Stopped!"));
		TRIGGER_EVENT(GUIEvents::GlobalBannerMessage, nullptr, (QObject*)&s);
		TRIGGER_EVENT(GUIEvents::InvokeOperationEnd, nullptr, nullptr);
		TRIGGER_EVENT(GUIEvents::ResponseStop, nullptr, nullptr);
		AppGlobalValues::setInProcessing(false);
		});

	// preview
	connect(EventCenter::Default(), &EventCenter::RequestPreviewScan, [=]() {
		// check device status=========================================
		qDebug() << "GetStatus";
		StatusInfo inf = GetStatus();
		qDebug() << "PreviewScan request status, status:" << getStatusString(inf.status);
		if (inf.status == READY)
		{
			AppGlobalValues::setInProcessing(true);
			TRIGGER_EVENT(GUIEvents::InvokeOperationStart, nullptr, nullptr);
			//ScanControl
			qDebug() << "Request preview!";
			if (!ScanControl(PREVIEW_SCAN))
			{
				qDebug() << "Preview success!";
				lastStatus = SCANNING;
				previewing = true;
				//                timerID = startTimer(500);
				TRIGGER_EVENT(GUIEvents::ResponsePreview, nullptr, nullptr);
				TRIGGER_EVENT(GUIEvents::InvokeOperationEnd, nullptr, nullptr);
				QString s("Device Previewing!");
				TRIGGER_EVENT(GUIEvents::GlobalBannerMessage, nullptr, (QObject*)&s);
				return;
			}
		}
		qDebug() << "Preview fail!";
		QString msg(inf.status != READY ? "Can't start preview,Device is not ready!" : "Start preview operation fail!");
		THROW_ERROR(msg);
		qDebug() << "Error thrown!";
		});

	previewDataCaller = QThread::create([=]() {
		while (!endLoop)
		{
			if (!previewing) {
				QThread::sleep(3);
				continue;
			}
			// check device status=========================================
			qDebug() << "GetStatus";
			StatusInfo inf = GetStatus();
			qDebug() << "GetPreviewData request status, status:" << getStatusString(inf.status);
			// device is preview scanning, try get preview data
			if (inf.status == SCANNING) {
				qDebug() << "Preview data reader read start!";
				const char* data = GetPreviewData();
				if (!data)continue;
				qDebug() << "Preview data reader read end!";
				QByteArray bytes = QByteArray::fromRawData(data, 140 * 140);
				//double check
				if (!previewing) {
					qDebug() << "Preview data reader long sleep!";
					QThread::sleep(3);
					continue;
				}
				qDebug() << "Preview data response event start!";
				TRIGGER_EVENT(GUIEvents::ResponsePreviewData, nullptr, (QObject*)(&bytes));
				qDebug() << "Preview data response event end!";
			}
			QThread::msleep(100);
		}
		});
	previewDataCaller->start();


}

void DeviceManager::timerEvent(QTimerEvent* event) {
	if (event->timerId() == deviceInfTimerID) {
		QString temp = QString(GetDeviceInfo(MEAN_TEMPERATURE));
		TRIGGER_EVENT(GUIEvents::ResponseDeviceTemperature, nullptr, (QObject*)&temp);
		return;
	}
	//scanning progress timer
	{
		//error exit,  callback error
		if (errorOccurred)
		{
			//            qDebug() << "Error occurred, exit progress timer";
			//            QString msg("Error occurred, exit current operation!");
			//            THROW_ERROR(msg);
			goto exitTimer;
		}
		// previewing exit
		if (previewing)
		{
			QString msg("Device is previewing, exit current operation!");
			THROW_ERROR(msg);
			goto exitTimer;
		}
		else {
			// check device status=========================================
			qDebug() << "GetStatus";
			StatusInfo inf = GetStatus();
			qDebug() << "Scanning request status, status:" << getStatusString(inf.status);
			//设备正常扫描中
			if (inf.status == SCANNING) {
				lastStatus = SCANNING;
				//normal scan
				QVariant var(inf.progress);
				qDebug() << "Normal scan, invoke InvokeOperationProgress:" << inf.progress;
				TRIGGER_EVENT(GUIEvents::InvokeOperationProgress, nullptr, (QObject*)&var);
				return;
			}
			else {
				//未发生错误并且，之前状态是扫描，代表正常扫描完成
				if (lastStatus == SCANNING) {
					qDebug() << "Scan finished";
					QVariant var(true);
					qDebug() << "InvokeOperationEnd";

					TRIGGER_EVENT(GUIEvents::InvokeOperationEnd, nullptr, (QObject*)&var);
					AppGlobalValues::setInProcessing(false);
					lastStatus = -1;
					previewing = false;
					QString s("%1  %2");
					s = s.arg(QDateTime::currentDateTime().toString("yyyy/MM/dd HH:mm:ss")).arg("Scan finished");
					TRIGGER_EVENT(GUIEvents::GlobalBannerMessage, nullptr, (QObject*)&s);
				}
				//一般不会出现其他情况
				else {
					QString msg("Unknown error in scanning progress timer");
					THROW_ERROR(msg);
				}
			}
		}
	exitTimer:
		qDebug() << "Scanning progress Timer exit";
		killTimer(timerID);
		timerID = -1;
		lastStatus = -1;
		previewing = false;
		return;
	}



}

void DeviceManager::processScan(const char* json, bool empty) {
	//clear last error state first
	errorOccurred = false;
	// check device status=========================================
	qDebug() << "GetStatus";
	StatusInfo inf = GetStatus();
	qDebug() << "Scan start request status, status:" << getStatusString(inf.status);
	if (inf.status != READY) {
		QString errmsg("Device is not ready, start scan operation fail!status is %1");
		errmsg = errmsg.arg(getStatusString(inf.status));
		THROW_ERROR(errmsg);
		return;
	}
	static QString msg = "Start scan...";
	AppGlobalValues::setInProcessing(true);
	TRIGGER_EVENT(GUIEvents::InvokeOperationStart, nullptr, (QObject*)&msg);
	qDebug() << "SetScanInfo>>>>>>>>>>>>>>>>>>>>";
	int ret = SetScanInfo(json, empty ? 1 : 0);
	if (ret) {
		qDebug() << ">>>>>>>>>>>>>>>>>>>>SetScanInfo failed";
		QString errmsg("Transfer patient information fail!");
		qDebug() << "Error thrown";
		THROW_ERROR(errmsg);
		return;
	}
	qDebug() << ">>>>>>>>>>>>>>>>>>>>SetScanInfo success";
	//ScanControl fail
	qDebug() << "ScanControl start>>>>>>>>>>>>>>>>>>>>>";
	if (!ScanControl(SCAN)) {
		qDebug() << ">>>>>>>>>>>>>>>>>>>>>ScanControl success";
		//set current state
		lastStatus = SCANNING;
		previewing = false;
		qDebug() << "Start progress timer";
		timerID = startTimer(500);
		return;
	}
	QString errmsg("ScanControl start fail!");
	THROW_ERROR(errmsg);
	qDebug() << ">>>>>>>>>>>>>>>>>>>>>ScanControl failed";
}

void DeviceManager::close() {
    previewDataCaller->terminate();
    delete previewDataCaller;
}
