#include "Header_Files/calibration.h"

CalibrationAlgorithm::CalibrationAlgorithm()
{

}

CalibrationAlgorithm::~CalibrationAlgorithm()
{

}

void CalibrationAlgorithm::readAndResample_StandardLightFile(QString filePath, int integratingSphereDetectorValue, DeviceAttribute deviceAttribute, DeviceInfo deviceInfo)
{

	QFile file(filePath);
	if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
	{
		std::cout << "文件不存在！" << std::endl;

		return;
	}

	//读取标准灯数据
	int lineCount = 0;
	while (!file.atEnd())
	{
		QByteArray tmp = file.readLine();
		lineCount++;
	}
	double * StandardLightWavelength_tmp = new double[lineCount - 1];
	double * StandardLightData_tmp = new double[lineCount - 1];


	file.seek(0);
	for (size_t i = 0; i < lineCount; i++)
	{
		QByteArray line = file.readLine();
		QString str(line);
		//cout << str.section('\t', 1).trimmed().toStdString() << endl;

		if (i == 0)
		{
			QString first = str.section('\t', 0, 0);
			m_dStandardLightDataBase = first.toDouble();
		}
		else
		{
			QString first = str.section('\t', 0, 0);
			QString second = str.section('\t', 1, 1);
			StandardLightWavelength_tmp[i - 1] = first.toDouble();
			StandardLightData_tmp[i - 1] = second.toDouble();

			//if (i== lineCount-1)//查看最后一行数据是否正确
			//{
			//	double xx = first.toDouble();
			//	double yy = second.toDouble();
			//	std::cout << "xx：" << xx <<std::endl;
			//	std::cout << "yy：" << yy << std::endl;
			//}
		}
	}



	//截取标准灯数据的有效段
	int startPos, endPos;
	int buffer = 3;//需要考虑标准灯原始文件的行数
	//QString biaozhundengfanwei = QString::number(StandardLightWavelength_tmp[0]) + "--" + QString::number(StandardLightWavelength_tmp[lineCount - 2]);

	if (deviceAttribute.fWaveLengthInNM[0] < StandardLightWavelength_tmp[0])//标准灯文件范围未包含光谱仪最小波长
	{
		startPos = 0;
	}
	else
	{
		for (size_t i = 0; i < lineCount - 1; i++)
		{
			if (deviceAttribute.fWaveLengthInNM[0] < StandardLightWavelength_tmp[i])
			{
				startPos = i - buffer;

				break;
			}
		}
	}

	if (deviceAttribute.fWaveLengthInNM[deviceAttribute.iPixels - 1] > StandardLightWavelength_tmp[lineCount - 2])//标准灯文件范围未包含光谱仪最大波长
	{
		endPos = lineCount - 2;
	}
	else
	{
		for (size_t i = 0; i < lineCount - 1; i++)
		{
			if (deviceAttribute.fWaveLengthInNM[deviceAttribute.iPixels - 1] < StandardLightWavelength_tmp[i])
			{
				endPos = i + buffer;//??

				break;
			}
		}
	}

	m_dStandardLightWavelength = new double[endPos - startPos];
	m_dStandardLightData = new double[endPos - startPos];

	for (size_t i = 0; i < endPos - startPos; i++)
	{
		m_dStandardLightWavelength[i] = StandardLightWavelength_tmp[i + startPos];
		m_dStandardLightData[i] = StandardLightData_tmp[i + startPos];
	}



	//将截断标准灯数据输出到csv
	QFileInfo fileInfo(filePath);
	QString standardLightFileFolder = fileInfo.path();
	QString standardLightFileName = fileInfo.fileName();

	QDateTime curDateTime = QDateTime::currentDateTime();
	QString currentTime = curDateTime.toString("yyyy_MM_dd_hh_mm_ss");

	QString tmp = standardLightFileFolder + "/" + currentTime + "_" + QString::fromStdString(deviceInfo.strSN) +"_"+ standardLightFileName + "_truncation.csv";

	std::ofstream outfile1(tmp.toStdString().c_str());

	for (size_t i = 0; i < endPos - startPos; i++)
	{
		if (i == 0)
		{
			outfile1 << m_dStandardLightDataBase << std::endl;
		}

		outfile1 << m_dStandardLightWavelength[i] << "," << m_dStandardLightData[i] << std::endl;
	}
	outfile1.close();



	//重采样标准灯数据
	Eigen::VectorXd vx = Eigen::VectorXd::Map(m_dStandardLightWavelength, endPos - startPos/*x_vec.size()*/);
	Eigen::VectorXd vy = Eigen::VectorXd::Map(m_dStandardLightData, endPos - startPos/*y_vec.size()*/);

	using namespace ZZ_MATH::SplineFit;
	SplineInterpolation m_sfLine(vx, vy);

	m_dStandardLightWavelengthResampled = new double[deviceAttribute.iPixels];
	m_dStandardLightDataResampled = new double[deviceAttribute.iPixels];

	double dTemp,scaleFactor;
    if(integratingSphereDetectorValue <= 0)
        scaleFactor=1;
    else
        scaleFactor=integratingSphereDetectorValue/m_dStandardLightDataBase;

	for (size_t i = 0; i < deviceAttribute.iPixels; i++)
	{
		if (deviceAttribute.fWaveLengthInNM[i] < StandardLightWavelength_tmp[0])//此波长 < 标准灯文件最小波长
		{
			dTemp = m_sfLine(StandardLightWavelength_tmp[0]);//???????????????
		}
		else if (StandardLightWavelength_tmp[lineCount - 2] < deviceAttribute.fWaveLengthInNM[i])//标准灯文件最大波长 < 此波长
		{
			dTemp = m_sfLine(StandardLightWavelength_tmp[lineCount - 2]);//???????????????
		}
		else
		{
			dTemp = m_sfLine(deviceAttribute.fWaveLengthInNM[i]);//?????
		}

		//double dTemp2 = m_sfLine(deviceAttribute.fWaveLengthInNM[i]);//外插结果，没有使用

		m_dStandardLightWavelengthResampled[i] = deviceAttribute.fWaveLengthInNM[i];
		m_dStandardLightDataResampled[i] = dTemp * scaleFactor;
    }


    //将重采样的标准灯数据输出到csv
    QString outputName = standardLightFileFolder + "/" + currentTime + "_" + QString::fromStdString(deviceInfo.strSN) + "_" + standardLightFileName + "_resample.csv";
    std::ofstream outfile2(outputName.toStdString().c_str());
    for (size_t i = 0; i < deviceAttribute.iPixels; i++)
    {
        if (i == 0)
        {
            outfile2 << m_dStandardLightDataBase << std::endl;
        }

        outfile2 << deviceAttribute.fWaveLengthInNM[i] << "," << m_dStandardLightDataResampled[i] << std::endl;
    }
	outfile2.close();
}

void CalibrationAlgorithm::produceCalfile(QString calFilePath, DeviceAttribute deviceAttribute, DataFrame integratingSphereData, DataFrame darkData)
{
	using namespace ZZ_MISCDEF;//ZZ_U32

	int errorCode;
	size_t writeCounter;

	double* m_gain = new double[deviceAttribute.iPixels];//double*
	double* m_offset = new double[deviceAttribute.iPixels];//double*

	for (size_t i = 0; i < deviceAttribute.iPixels; i++)
	{
		if (integratingSphereData.lData[i] - darkData.lData[i] == 0)//如果分母为零
		{
			m_gain[i] = 0;
		}
		else
		{
			m_gain[i] = m_dStandardLightDataResampled[i] / (integratingSphereData.lData[i] - darkData.lData[i]);
		}

		m_offset[i] = 0;
	}

	//写入到二进制文件
	FILE * calFileHandle = fopen(calFilePath.toStdString().c_str(), "wb");

	writeCounter = fwrite(&integratingSphereData.usExposureTimeInMS,sizeof(ZZ_U32), 1, calFileHandle);//曝光时间
	writeCounter = fwrite(&integratingSphereData.fTemperature, sizeof(float), 1, calFileHandle);//温度
	writeCounter = fwrite(&deviceAttribute.iPixels, sizeof(int), 1, calFileHandle);//波长数
	writeCounter = fwrite(&deviceAttribute.fWaveLengthInNM, sizeof(float), deviceAttribute.iPixels, calFileHandle);//波长
	writeCounter = fwrite(m_gain, sizeof(double), deviceAttribute.iPixels, calFileHandle);//gain
	writeCounter = fwrite(m_offset, sizeof(double), deviceAttribute.iPixels, calFileHandle);//offset

	fclose(calFileHandle);


	//写入到CSV文件
	QString calFile_csv = calFilePath.split(".")[0] + ".csv";
	std::ofstream outfile(calFile_csv.toStdString().c_str());
	for (int i = 0; i < deviceAttribute.iPixels; i++)
	{
        if (i==0)
        {
            outfile << integratingSphereData.usExposureTimeInMS << std::endl;
        }

		outfile << deviceAttribute.fWaveLengthInNM[i] << "," << m_gain[i] << std::endl;
	}
	outfile.close();

    //输出定标文件时，直接写结构体
    using namespace ZZ_MISCDEF::ZZ_DATAFILE;//tagCalibrationFrame
    tagCalibrationFrame calibrationFrame;

    calibrationFrame.uiExposureTimeInMS = integratingSphereData.usExposureTimeInMS;
    calibrationFrame.fTemperature = integratingSphereData.fTemperature;
    calibrationFrame.iPixels = deviceAttribute.iPixels;

    for (size_t i = 0; i < deviceAttribute.iPixels; i++)
    {
        calibrationFrame.fWaveLength[i] = deviceAttribute.fWaveLengthInNM[i];
        calibrationFrame.dCal_Gain[i] = m_gain[i];
    }

    QStringList tmp = calFilePath.split('.');
    QString calFilePath2 = tmp[0] + "_structure." + tmp[1];

    FILE * calFileHandle2 = fopen(calFilePath2.toStdString().c_str(), "wb");

    writeCounter = fwrite(&calibrationFrame,sizeof(tagCalibrationFrame), 1, calFileHandle2);

    fclose(calFileHandle2);


	delete[] m_gain;
    delete[] m_offset;
}
