#include "AbsFSController.h"
#include "ZZ_Math_HDRONLY.h"
CAbsFSController::CAbsFSController(QObject* parent /*= nullptr*/)
{
	m_iFlagInit = 0;
#ifdef _DEBUG
	m_qstrWaveLengthPath = "E:/WorkSpace/TowerOptoSifAndSpectral/Data/WaveLengthInfo.txt";
#else
	m_qstrWaveLengthPath = "/home/data/Data/WaveLengthInfo.txt";
#endif // DEBUG
}

CAbsFSController::~CAbsFSController()
{
}

void CAbsFSController::SetContext(OneFSContext struFSParam)
{
	m_struFSParam = struFSParam;
}

int CAbsFSController::Initialize()
{
	using namespace ZZ_MISCDEF::IRIS;

	m_iFlagInit = 0;

	switch (m_struFSParam.ucDeviceModel)
	{
	case DeviceModel::FLAME:
		m_pFSCtrl = new OceanOptics_lib;
		if (m_pFSCtrl->Initialize(false, m_struFSParam.strInterface, m_struFSParam.strSN) != 0)
		{
			//qDebug() << "Flame Not Opened";
			printf("Flame Not Opened");
			return 1;
		}
		GetDarkPixelIndices();
		break;
	case DeviceModel::OSIFAlpha:
		m_pFSCtrl = new OceanOptics_lib;
		if (m_pFSCtrl->Initialize(false, m_struFSParam.strInterface, m_struFSParam.strSN) != 0)
		{
			qDebug() << "OSIFAlpha Not Opened";
			return 2;
		}
		break;
	case DeviceModel::OSIFBeta:
		m_pFSCtrl = new OceanOptics_lib;
		if (m_pFSCtrl->Initialize(false, m_struFSParam.strInterface, m_struFSParam.strSN) != 0)
		{
			qDebug() << "OSIFBeta Not Opened";
			return 2;
		}
		break;
	case DeviceModel::ISIF:
		m_pFSCtrl = new ZZ_ATPControl_Serial_Qt;
		//m_pFSCtrl->Initialize(false, m_struFSParam.strInterface, NULL);
		if (m_pFSCtrl->Initialize(false, m_struFSParam.strInterface, m_struFSParam.strSN) != 0)
		{
			qDebug() << "ISIF Not Opened";
			return 3;
		}
		break;
	case DeviceModel::IS1:
		m_pFSCtrl = new ZZ_ATPControl_Serial_Qt;
		//m_pFSCtrl->Initialize(false, m_struFSParam.strInterface, NULL);
		if (m_pFSCtrl->Initialize(false, m_struFSParam.strInterface, m_struFSParam.strSN) != 0)
		{
			//qDebug() << "IS1 Not Opened";
			printf("IS1 Not Opened");
			return 3;
		}
		break;
	case DeviceModel::IS2:
		m_pFSCtrl = new ZZ_ATPControl_Serial_Qt;
		//m_pFSCtrl->Initialize(false, m_struFSParam.strInterface, NULL);
		if (m_pFSCtrl->Initialize(false, m_struFSParam.strInterface, m_struFSParam.strSN) != 0)
		{
			qDebug() << "IS2 Not Opened";
			return 3;
		}
		break;

	case DeviceModel::IS11:
		m_pFSCtrl = new IS11_Ctrl_Qt;
		//m_pFSCtrl->Initialize(false, m_struFSParam.strInterface, NULL);
		if (m_pFSCtrl->Initialize(false, m_struFSParam.strInterface, m_struFSParam.strSN) != 0)
		{
			qDebug() << "IS11 Not Opened";
			return 3;
		}
		break;

	default:
		break;
	}

	int iRes = m_pFSCtrl->GetDeviceAttribute(m_struDeviceAttr);
	if (iRes != 0)
	{
		qDebug() << "GetDeviceAttribute Failed" << iRes;
		printf("GetDeviceAttribute Failed");
		return 4;
	}
	else//mark by zz
	{
		if (m_struFSParam.ucDeviceModel== DeviceModel::IS2)
		{
			m_struDeviceAttr.iMinIntegrationTimeInMS = 10;
		}
	}

	iRes = m_pFSCtrl->SetDeviceTemperature(0);
	if (iRes != 0)
	{
		qDebug() << "SetDeviceTemperature Failed" << iRes;
		//return 5;
	}
	m_iFlagInit = 1;
	return 0;
}

int CAbsFSController::Initialize_Self()
{
	return 0;
}

int CAbsFSController::SetExposureTime(int iMilliSec)
{
	return m_pFSCtrl->SetExposureTime(iMilliSec);
}

int CAbsFSController::GetExposureTime(int& iMilliSec)
{
	return m_pFSCtrl->GetExposureTime(iMilliSec);
}

int CAbsFSController::SingleShot(DataFrame& struSingleFrame)
{
	using namespace ZZ_MISCDEF::IRIS;

	


	int iRes = m_pFSCtrl->SingleShot(m_struSingleFrame);
	if (iRes != 0)
	{
		//qDebug() << "Err. SingleShot";
		printf("Err. SingleShot");
		return 1;
	}

	if (m_struFSParam.ucDeviceModel == DeviceModel::FLAME)
	{
		int iRes = m_pFSCtrl->SingleShot(m_struSingleFrame);
		if (iRes != 0)
		{
			//qDebug() << "Err. SingleShot";
			printf("Err. SingleShot");
			return 1;
		}
	}

	if (m_struFSParam.ucDeviceModel == DeviceModel::ISIF)
	{
		float fTemp;
		m_pFSCtrl->GetDeviceTemperature(fTemp);
		m_struSingleFrame.fTemperature = fTemp;
	}
	else if (m_struFSParam.ucDeviceModel == DeviceModel::IS2)
	{
		float fTemp;
		m_pFSCtrl->GetDeviceTemperature(fTemp);
		m_struSingleFrame.fTemperature = fTemp;
	}
	else if (m_struFSParam.ucDeviceModel == DeviceModel::IS1)
	{
		m_struSingleFrame.fTemperature = 1000;
	}
	else if (m_struFSParam.ucDeviceModel == DeviceModel::FLAME)
	{
		m_struSingleFrame.fTemperature = 1000;
	}

	QDateTime qdtTime = QDateTime::currentDateTime();
	m_struSingleFrame.dTimes = qdtTime.toMSecsSinceEpoch();

	struSingleFrame = m_struSingleFrame;
	return 0;
}

int CAbsFSController::PerformAutoExposure()
{

	qDebug() << "--------------------------Starting PerformAutoExposure";
	using namespace ZZ_MATH;
	float fPredictedExposureTime;
	int iDeviceDepth = (int)m_struFSParam.lDepth;

	qDebug() << "MAX---Min" << m_struFSParam.fMaxFactor << "---" << m_struFSParam.fMinFactor ;

	bool bFlagIsOverTrying = false;
	bool bFlagIsLowerMinExposureTime = false;
	bool bFlagIsOverMaxExposureTime = false;
	bool bFlagIsAutoExposureOK = false;
	bool bFlagIsAutoExposureFailed = false;

	bool bIsValueOverflow = false;
	bool bIsLastValueOverflow = false;

	int  iExposureTime = 0;
	float  fTempExposureTime = 0;
	double fLastExposureTime = 0.1;
	int    iRepeatCount = 0;


	while (!bFlagIsAutoExposureOK && !bFlagIsAutoExposureFailed)
	{
		DataFrame dfTemp;

		if (iRepeatCount++ > 30)
		{
			bFlagIsAutoExposureFailed = true;
			bFlagIsOverTrying = true;
			break;
		}

		m_pFSCtrl->GetExposureTime(iExposureTime);
		qDebug() << "Current ExpTime:" << iExposureTime;
		fTempExposureTime = iExposureTime;

		int iRes = m_pFSCtrl->SingleShot(dfTemp);
		if (iRes != 0)
		{
			//qDebug() << "Err:PerformAutoExposure Failed.Exit Code:2";
			printf("Err:PerformAutoExposure Failed,SingleShot Failed.Exit Code:2");
			return 2;
		}

		HeapSort(dfTemp.lData, m_struDeviceAttr.iPixels);

		double dSum = 0;
		int iCount = m_struDeviceAttr.iPixels / 200;
		for (int i = 0; i < iCount; i++)
		{
			dSum += dfTemp.lData[i];
		}
		double dTemp = dSum / iCount;

		qDebug() << "Avg " << dTemp ;

		if (dTemp >= iDeviceDepth * 0.99)
		{
			bIsValueOverflow = true;
			if (!bIsLastValueOverflow)
			{
				iExposureTime = (float)(fLastExposureTime + iExposureTime) / 2;
			}
			else
			{
				iExposureTime = iExposureTime / 2;
			}
		}

		else if (iDeviceDepth * m_struFSParam.fMaxFactor >= dTemp && dTemp >= iDeviceDepth * m_struFSParam.fMinFactor)
		{
			qDebug() << "trace bFlagIsAutoExposureOK =1 " << iExposureTime;
			bFlagIsAutoExposureOK = 1;
		}
		else if (dTemp > iDeviceDepth * m_struFSParam.fMaxFactor)
		{
			bIsValueOverflow = true;
			if (!bIsLastValueOverflow)
			{
				iExposureTime = (float)(fLastExposureTime + iExposureTime) / 2;
			}
			else
			{
				iExposureTime = iExposureTime * 3 / 4;
			}
		}
		else if (dTemp < iDeviceDepth * m_struFSParam.fMinFactor)
		{
			bIsValueOverflow = false;
			if (bIsLastValueOverflow)
			{
				iExposureTime = (float)(fLastExposureTime + iExposureTime) / 2;
			}
			else
			{
				double dFactor;
				dFactor = dTemp / (iDeviceDepth * m_struFSParam.fMaxFactor);
				iExposureTime = (float)(iExposureTime / dFactor);
			}

		}
		bIsLastValueOverflow = bIsValueOverflow;
		fLastExposureTime = fTempExposureTime;



		if (iExposureTime <= m_struDeviceAttr.iMinIntegrationTimeInMS)
		{
			bFlagIsAutoExposureOK = false;
			bFlagIsAutoExposureFailed = true;
			bFlagIsLowerMinExposureTime = true;

			iRes = m_pFSCtrl->SetExposureTime(m_struDeviceAttr.iMinIntegrationTimeInMS);
			if (iRes != 0)
			{
				//qDebug() << "Err:PerformAutoExposure Failed.Exit Code:3" ;
				printf("Err:PerformAutoExposure Failed,SetExposureTime Failed.Exit Code:2");
				return 3;
			}
			else
			{
				qDebug() << "Warning:PerformAutoExposure lower than min integration time.Will be limited to " << m_struDeviceAttr.iMinIntegrationTimeInMS << "MS";
			}

			break;
		}

		if (iExposureTime > m_struDeviceAttr.iMaxIntegrationTimeInMS - 1)
		{
			bFlagIsAutoExposureOK = false;
			bFlagIsAutoExposureFailed = true;
			bFlagIsOverMaxExposureTime = true;

			iRes = m_pFSCtrl->SetExposureTime(m_struDeviceAttr.iMaxIntegrationTimeInMS - 1);
			if (iRes != 0)
			{
				//qDebug() << "Err:PerformAutoExposure Failed.Exit Code:3";
				printf("Err:PerformAutoExposure Failed,SetExposureTime Failed.Exit Code:3");
				return 3;
			}
			else
			{
				qDebug() << "Warning:PerformAutoExposure exceed max integration time.Will be limited to " << m_struDeviceAttr.iMaxIntegrationTimeInMS - 1 << "MS";
			}

			break;
		}

		iRes = m_pFSCtrl->SetExposureTime((int)iExposureTime);
		if (iRes != 0)
		{
			//qDebug() << "Err:PerformAutoExposure Failed.Exit Code:4" ;
			printf("Err:PerformAutoExposure Failed,SetExposureTime Failed.Exit Code:4");
			return 3;
		}
		else
		{
			qDebug() << "Success:PerformAutoExposure. Value" << iExposureTime ;
		}
	}

	fPredictedExposureTime = iExposureTime;
	qDebug() << "--------------------------Stop PerformAutoExposure";

	return 0;
}

int CAbsFSController::CheckAndAdjust_Fast()
{
	using namespace ZZ_MATH;

	int iExposureTime = 0;

	int iRes = m_pFSCtrl->GetExposureTime(iExposureTime);
	if (iRes != 0)
	{
		//qDebug() << "Err. SingleShot";
		printf("CheckAndAdjust_Fast,Err. SingleShot");
		return 1;
	}


	HeapSort(m_struSingleFrame.lData, m_struDeviceAttr.iPixels);

	double dSum = 0;
	int iCount = m_struDeviceAttr.iPixels / 200;
	for (int i = 0; i < iCount; i++)
	{
		dSum += m_struSingleFrame.lData[i];
	}
	double dTemp = dSum / iCount;


	if (dTemp >= m_struFSParam.lDepth * 0.99)
	{
		iExposureTime = iExposureTime / 2;
	}
	else
	{
		double dFactor;
		dFactor = dTemp / (float)(m_struFSParam.lDepth * m_struFSParam.fMaxFactor);
		iExposureTime = (float)(iExposureTime / dFactor);
	}

	return 0;
}

int CAbsFSController::GetDarkPixelIndices()
{
	m_vecDarkPixleIndices.clear();

	if (m_struFSParam.ucDeviceModel == DeviceModel::FLAME)
	{
		m_vecDarkPixleIndices = ((OceanOptics_lib*)m_pFSCtrl)->m_vecDarkPixels;
	}
	
	//////////////////////////////////////////////////////////////////////////debug only
	/*qDebug() << m_vecDarkPixleIndices.size();
	qDebug() << ((OceanOptics_lib*)m_pFSCtrl)->m_vecDarkPixels.size();
	for (int i=0;i< m_vecDarkPixleIndices.size();i++)
	{
		qDebug() << m_vecDarkPixleIndices[i];
	}*/
	
	//////////////////////////////////////////////////////////////////////////debug only
	return 0;
}

void CAbsFSController::GetDeviceAttr(DeviceAttribute& struDeviceAttr)
{
	struDeviceAttr = m_struDeviceAttr;
}

// int CAbsFSController::CreateWavelengthFile()
// {
// 	QDir qdirPath(qstrTemp);
// 	if (!qdirPath.exists())
// 	{
// 		bool bRes = qdirPath.mkdir(qstrTemp);
// 		if (!bRes)
// 		{
// 			qDebug() << "DataFileProcessor mkdir Failed.";
// 		}
// 	}
// 	m_qstrWaveLengthPath
// 	temp1 = "wavelength = ";
// 	file.Write(temp1, temp1.GetLength());
// 	file.Write("{", 1);
// 	return 0;
// }
