#include "QSimulationLookTableDialog.h"
#include "ui_QSimulationLookTableDialog.h"
#include <QFileDialog>
#include <QMessageBox>

#include "SatelliteOribtModel.h"
#include "SARSimulationTaskSetting.h"
#include "ImageOperatorBase.h"
#include "FileOperator.h"
#include "BaseConstVariable.h"
#include "GPUTool.cuh"
#include "LookTableSimulationComputer.cuh"
#include <QDebug>

#include "ImageShowDialogClass.h"
#include "QToolProcessBarDialog.h"

QSimulationLookTableDialog::QSimulationLookTableDialog(QWidget *parent)
	: QDialog(parent),ui(new Ui::QSimulationLookTableDialogClass)
{
	ui->setupUi(this);
	connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(onaccepted()));
	connect(ui->buttonBox, SIGNAL(rejected()), this, SLOT(onrejected()));
	connect(ui->pushButtonDEM, SIGNAL(clicked(bool)), this, SLOT(onpushButtonDEMClicked(bool)));
	connect(ui->pushButtonOrbitModel, SIGNAL(clicked(bool)), this, SLOT(onpushButtonOrbitModelClicked(bool)));
	connect(ui->pushButtonOutDir, SIGNAL(clicked(bool)), this, SLOT(onpushButtonOutDirClicked(bool)));
	connect(ui->pushButtonSataSetting, SIGNAL(clicked(bool)), this, SLOT(onpushButtonSataSettingClicked(bool)));



}

QSimulationLookTableDialog::~QSimulationLookTableDialog()
{

}

void QSimulationLookTableDialog::onrejected()
{
	this->close();
}

void QSimulationLookTableDialog::onpushButtonOrbitModelClicked(bool)
{
	// 调用文件选择对话框并选择一个 .tif 文件
	QString fileName = QFileDialog::getOpenFileName(this,
		u8"GPS Orbit Model xml",          // 对话框标题
		"",                        // 初始目录，可以设置为路径
		u8"xml Files (*.xml)"); // 文件类型过滤器

	if (!fileName.isEmpty()) {
		this->ui->OrbitModelPathLineEdit->setText(fileName);
	}
	else {
		QMessageBox::information(this, u8"没有选择文件", u8"没有选择任何文件");
	}
}

void QSimulationLookTableDialog::onpushButtonSataSettingClicked(bool)
{
	// 调用文件选择对话框并选择一个 .tif 文件
	QString fileName = QFileDialog::getOpenFileName(this,
		u8"Satellite Params setting xml",          // 对话框标题
		"",                        // 初始目录，可以设置为路径
		u8"xml Files (*.xml)"); // 文件类型过滤器

	if (!fileName.isEmpty()) {
		this->ui->SateSettingLineEdit->setText(fileName);
	}
	else {
		QMessageBox::information(this, u8"没有选择文件", u8"没有选择任何文件");
	}
}

void QSimulationLookTableDialog::onpushButtonDEMClicked(bool)
{
	// 调用文件选择对话框并选择一个 .tif 文件
	QString fileName = QFileDialog::getOpenFileName(this,
		u8"DEM Raster Select",          // 对话框标题
		"",                        // 初始目录，可以设置为路径
		u8"tiff Files (*.tiff);;tif Files (*.tif);;dat Files (*.dat);;All Files (*.*)"); // 文件类型过滤器

	if (!fileName.isEmpty()) {
		this->ui->DEMLineEdit->setText(fileName);
	}
	else {
		QMessageBox::information(this, u8"没有选择文件", u8"没有选择任何文件");
	}
}

void QSimulationLookTableDialog::onpushButtonOutDirClicked(bool)
{
	// 调用文件选择对话框并选择一个 .tif 文件
	QString fileName = QFileDialog::getExistingDirectory(this,
		u8"DEM Raster Select",          // 对话框标题
		""                       // 初始目录，可以设置为路径
		);
	if (!fileName.isEmpty()) {
		this->ui->outDirLineEdit->setText(fileName);
	}
	else {
		QMessageBox::information(this, u8"没有选择文件", u8"没有选择任何文件");
	}
}

void QSimulationLookTableDialog::LookTableSimualtionMainProcess(QString sateName, QString orbitpath, QString SatePath, QString DEMPath, QString outDirPath, bool gpuflag, bool looktableflag, bool checkBoxIncAngle, bool DopplerFlag)
{
	this->ui->progressBar->setMinimum(0);
	this->ui->progressBar->setMaximum(100);



	if (!isExists(orbitpath)) {
		qDebug() << "Orbit model file is not exist !!!";
		return;
	}
	if (!isExists(SatePath)) {
		qDebug() << "Satellite Model file is not exist !!!";
		return;
	}
	if (!isExists(DEMPath)) {
		qDebug() << "DEM file is not exist !!!";
		return;
	}





	// 读取轨道模型
	qDebug() << "load orbit model params from xml :" << orbitpath;
	PolyfitSatelliteOribtModel orbitmodel;
	orbitmodel.loadFromXml(orbitpath);

	// 轨道参数
	long double			OribtStartTime = orbitmodel.getOribtStartTime();
	std::vector<double> PolyfitPx = orbitmodel.getPolyfitPx();
	std::vector<double> PolyfitPy = orbitmodel.getPolyfitPy();
	std::vector<double> PolyfitPz = orbitmodel.getPolyfitPz();
	std::vector<double> PolyfitVx = orbitmodel.getPolyfitVx();
	std::vector<double> PolyfitVy = orbitmodel.getPolyfitVy();
	std::vector<double> PolyfitVz = orbitmodel.getPolyfitVz();


	// 参数模型
	qDebug() << "load simulation setting params from xml :" << orbitpath;
	std::shared_ptr<AbstractSARSatelliteModel> SARSetting = ReadSimulationSettingsXML(SatePath);

	// 多普勒参数
	double dopplerRefrenceTime = SARSetting->getDopplerParametersReferenceTime();
	std::vector<double> DopplerCentroidCoefficients = SARSetting->getDopplerCentroidCoefficients();
	std::vector<double> DopplerRateValuesCoefficient = SARSetting->getDopplerRateValuesCoefficients();

	// 仿真成像参数计算
	double startTime = SARSetting->getSARImageStartTime();
	double endTime = SARSetting->getSARImageStartTime();

	double PRF = SARSetting->getPRF();
	double Fs = SARSetting->getFs();
	double nearRange = SARSetting->getNearRange();
	double farRange = SARSetting->getFarRange();
	double lamda = SARSetting->getCenterLamda();
	// 输出结果处理
	QString outLookTablePath = "";
	QString outIncPath = "";
	gdalImage demimg(DEMPath);




	if (looktableflag || checkBoxIncAngle) {
		outLookTablePath = JoinPath(outDirPath, sateName + "_looktable.bin");

		this->ui->label_tip->setText(u8"look table create...");
		this->ui->progressBar->setValue(0);
		this->LookTableSimulationDopplerProcess(
			DEMPath, outLookTablePath,
			OribtStartTime,
			PolyfitPx, PolyfitPy, PolyfitPz,
			PolyfitVx, PolyfitVy, PolyfitVz,
			dopplerRefrenceTime,
			DopplerCentroidCoefficients,
			startTime,
			endTime,
			nearRange,
			farRange,
			PRF,
			Fs,
			lamda,
			gpuflag,
			looktableflag,
			checkBoxIncAngle
		);
	}

	
	if (checkBoxIncAngle) {
		this->ui->label_tip->setText(u8"sloper process...");
		this->ui->progressBar->setValue(0);
		outIncPath = JoinPath(outDirPath, sateName + "_incAngle.bin");



	}


}

void QSimulationLookTableDialog::LookTableSimulationDopplerProcess(QString DEMPath, QString outLookTablePath, long double OribtStartTime, std::vector<double> PolyfitPx, std::vector<double> PolyfitPy, std::vector<double> PolyfitPz, std::vector<double> PolyfitVx, std::vector<double> PolyfitVy, std::vector<double> PolyfitVz, double dopplerRefrenceTime, std::vector<double> DopplerCentroidCoefficients, double starttime, double endtime, double nearRange, double farRange, double PRF, double Fs, double lamda, bool gpuflag, bool looktableflag, bool incflag)
{
	qDebug() << "generate look table ";
	qDebug() << "DEMPath\t" << DEMPath;
	qDebug() << "outLookTablePath\t" << outLookTablePath;


	gdalImage demimg(DEMPath);
	gdalImage outLookTable = CreategdalImage( // 创建查找表
		outLookTablePath,
		demimg.height, demimg.width, 2,
		demimg.gt,
		demimg.projection,
		true,
		true,
		true
	);


	starttime = starttime - OribtStartTime; // 处理坐标时间
	endtime = endtime - OribtStartTime;

	// 轨道模型
	double Xp0 = 0, Yp0 = 0, Zp0 = 0, Xv0 = 0, Yv0 = 0, Zv0 = 0;
	double Xp1 = 0, Yp1 = 0, Zp1 = 0, Xv1 = 0, Yv1 = 0, Zv1 = 0;
	double Xp2 = 0, Yp2 = 0, Zp2 = 0, Xv2 = 0, Yv2 = 0, Zv2 = 0;
	double Xp3 = 0, Yp3 = 0, Zp3 = 0, Xv3 = 0, Yv3 = 0, Zv3 = 0;
	double Xp4 = 0, Yp4 = 0, Zp4 = 0, Xv4 = 0, Yv4 = 0, Zv4 = 0;
	double Xp5 = 0, Yp5 = 0, Zp5 = 0, Xv5 = 0, Yv5 = 0, Zv5 = 0;
	int degree = PolyfitPx.size();
	switch (degree) {
	case(6):
		Xp5 = PolyfitPx[5];
		Yp5 = PolyfitPy[5];
		Zp5 = PolyfitPz[5];
		Xv5 = PolyfitVx[5];
		Yv5 = PolyfitVy[5];
		Zv5 = PolyfitVz[5];
	case(5):
		Xp4 = PolyfitPx[4];
		Yp4 = PolyfitPy[4];
		Zp4 = PolyfitPz[4];
		Xv4 = PolyfitVx[4];
		Yv4 = PolyfitVy[4];
		Zv4 = PolyfitVz[4];
	case(4):
		Xp3 = PolyfitPx[3];
		Yp3 = PolyfitPy[3];
		Zp3 = PolyfitPz[3];
		Xv3 = PolyfitVx[3];
		Yv3 = PolyfitVy[3];
		Zv3 = PolyfitVz[3];
	case(3):
		Xp2 = PolyfitPx[2];
		Yp2 = PolyfitPy[2];
		Zp2 = PolyfitPz[2];
		Xv2 = PolyfitVx[2];
		Yv2 = PolyfitVy[2];
		Zv2 = PolyfitVz[2];
	case(2):
		Xp1 = PolyfitPx[1];
		Yp1 = PolyfitPy[1];
		Zp1 = PolyfitPz[1];
		Xv1 = PolyfitVx[1];
		Yv1 = PolyfitVy[1];
		Zv1 = PolyfitVz[1];
	case(1):
		Xp0 = PolyfitPx[0];
		Yp0 = PolyfitPy[0];
		Zp0 = PolyfitPz[0];
		Xv0 = PolyfitVx[0];
		Yv0 = PolyfitVy[0];
		Zv0 = PolyfitVz[0];
	default:
		break;
	}

	// 多普勒参数
	double r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0;
	degree = DopplerCentroidCoefficients.size();
	switch (degree)
	{
	case(5):
		r4 = DopplerCentroidCoefficients[4];
	case(4):
		r3 = DopplerCentroidCoefficients[3];
	case(3):
		r2 = DopplerCentroidCoefficients[2];
	case(2):
		r1 = DopplerCentroidCoefficients[1];
	case(1):
		r0 = DopplerCentroidCoefficients[0];
	default:
		break;
	}



	// 处理分块
	long GPUMemoryline = floor((Memory1MB * 2.0 / 8.0 / 3.0 / demimg.width * 2000));//2GB
	GPUMemoryline = GPUMemoryline < 1 ? 1 : GPUMemoryline;

	// 内存预分配

	// 
	std::shared_ptr<float> host_Rid((float*)mallocCUDAHost(sizeof(float) * GPUMemoryline * demimg.width), FreeCUDAHost);
	std::shared_ptr<float> host_Cid((float*)mallocCUDAHost(sizeof(float) * GPUMemoryline * demimg.width), FreeCUDAHost);

	std::shared_ptr<float> device_Rid((float*)mallocCUDADevice(sizeof(float) * GPUMemoryline * demimg.width), FreeCUDADevice);
	std::shared_ptr<float> device_Cid((float*)mallocCUDADevice(sizeof(float) * GPUMemoryline * demimg.width), FreeCUDADevice);

	// 
	std::shared_ptr<double> host_demX((double*)mallocCUDAHost(sizeof(double) * GPUMemoryline * demimg.width), FreeCUDAHost);
	std::shared_ptr<double> host_demY((double*)mallocCUDAHost(sizeof(double) * GPUMemoryline * demimg.width), FreeCUDAHost);
	std::shared_ptr<double> host_demZ((double*)mallocCUDAHost(sizeof(double) * GPUMemoryline * demimg.width), FreeCUDAHost);

	std::shared_ptr<double> device_demX((double*)mallocCUDADevice(sizeof(double) * GPUMemoryline * demimg.width), FreeCUDADevice);
	std::shared_ptr<double> device_demY((double*)mallocCUDADevice(sizeof(double) * GPUMemoryline * demimg.width), FreeCUDADevice);
	std::shared_ptr<double> device_demZ((double*)mallocCUDADevice(sizeof(double) * GPUMemoryline * demimg.width), FreeCUDADevice);

	//
	//std::shared_ptr<ImageShowDialogClass> datashowptr(new ImageShowDialogClass);

	// 处理复制结果

	long rowcount = GPUMemoryline;
	long colcount = demimg.width;

	//rowcount = 1;
	//colcount = 1;
	//long testRid = demimg.height / 2;
	//long testCid = demimg.width / 2;
	
	double fact_lamda = 1 / lamda;
	for (long rid = 0; rid < demimg.height; rid = rid + GPUMemoryline) {
		qDebug() << "computer read file : " << rid << "~" << rowcount + rid << "\t:" << demimg.height;
		//double* tmep = new double[rowcount * colcount];
		std::shared_ptr<double> demX = readDataArr<double>(demimg, rid, 0, rowcount, colcount, 1, GDALREADARRCOPYMETHOD::VARIABLEMETHOD);// 行列数修改
		std::shared_ptr<double> demY = readDataArr<double>(demimg, rid, 0, rowcount, colcount, 2, GDALREADARRCOPYMETHOD::VARIABLEMETHOD);
		std::shared_ptr<double> demZ = readDataArr<double>(demimg, rid, 0, rowcount, colcount, 3, GDALREADARRCOPYMETHOD::VARIABLEMETHOD);




		//std::shared_ptr<double> demX = readDataArr<double>(demimg, rid, testCid, rowcount, colcount, 1, GDALREADARRCOPYMETHOD::VARIABLEMETHOD);// 行列数修改
		//std::shared_ptr<double> demY = readDataArr<double>(demimg, rid, testCid, rowcount, colcount, 2, GDALREADARRCOPYMETHOD::VARIABLEMETHOD);
		//std::shared_ptr<double> demZ = readDataArr<double>(demimg, rid, testCid, rowcount, colcount, 3, GDALREADARRCOPYMETHOD::VARIABLEMETHOD);

		//demX.get()[0]=-1407793.922129;
		//demY.get()[0]=5465044.940211;
		//demZ.get()[0]=2963219.736386;
		// 数据复制
		memcpy(host_demX.get(), demX.get(), sizeof(double) * rowcount * colcount);
		memcpy(host_demY.get(), demY.get(), sizeof(double) * rowcount * colcount);
		memcpy(host_demZ.get(), demZ.get(), sizeof(double) * rowcount * colcount);

		//内存->GPU
		HostToDevice(host_demX.get(), device_demX.get(), sizeof(double) * GPUMemoryline * demimg.width);
		HostToDevice(host_demY.get(), device_demY.get(), sizeof(double) * GPUMemoryline * demimg.width);
		HostToDevice(host_demZ.get(), device_demZ.get(), sizeof(double) * GPUMemoryline * demimg.width);

		qDebug() << "GPU computer start: " << rid << "~" << rowcount + rid << "\t:" << demimg.height;
		RDProcess_dopplerGPU(
			device_demX.get(), device_demY.get(), device_demZ.get(),
			device_Rid.get(), device_Cid.get(),
			rowcount, colcount,
			starttime, nearRange, farRange,
			PRF, Fs,
			fact_lamda,
			Xp0, Yp0, Zp0, Xv0, Yv0, Zv0,
			Xp1, Yp1, Zp1, Xv1, Yv1, Zv1,
			Xp2, Yp2, Zp2, Xv2, Yv2, Zv2,
			Xp3, Yp3, Zp3, Xv3, Yv3, Zv3,
			Xp4, Yp4, Zp4, Xv4, Yv4, Zv4,
			Xp5, Yp5, Zp5, Xv5, Yv5, Zv5,
			dopplerRefrenceTime, r0, r1, r2, r3, r4);


		// GPU -> 内存
		DeviceToHost(host_Rid.get(), device_Rid.get(), sizeof(float) * GPUMemoryline * demimg.width);
		DeviceToHost(host_Cid.get(), device_Cid.get(), sizeof(float) * GPUMemoryline * demimg.width);
		qDebug() << "GPU computer finished!!: " << rid << "~" << rowcount + rid << "\t:" << demimg.height;
		//exit(-1);
		// 数据存储
		outLookTable.saveImage(host_Rid, rid, 0, rowcount, colcount, 1);
		outLookTable.saveImage(host_Cid, rid, 0, rowcount, colcount, 2);

		//datashowptr->load_double_data(host_Rid.get(), rowcount, colcount, QString("host_Rid"));
		//datashowptr->exec();

		qDebug() << "GPU computer result write finished: " << rid << "~" << rowcount + rid << "\t:" << demimg.height;
		
		this->ui->progressBar->setValue(floor(100.0*(rowcount + rid)/ demimg.height));
	}

	qDebug() << "look table computed finished!!!";
	this->ui->progressBar->setValue(100);
}

void QSimulationLookTableDialog::LocalIncidenceAngleSimulationCompter(QString DEMPath, QString LookTablePath, QString outIncPath, long double OribtStartTime, std::vector<double> PolyfitPx, std::vector<double> PolyfitPy, std::vector<double> PolyfitPz, std::vector<double> PolyfitVx, std::vector<double> PolyfitVy, std::vector<double> PolyfitVz, double starttime, double endtime, double nearRange, double farRange, double PRF, double Fs)
{
	//gdalImage outInc = CreategdalImageDouble(
//	outIncPath,
//	demimg.height, demimg.width, 1,
//	demimg.gt,
//	demimg.projection,
//	true,
//	true,
//	true
//);
}

void QSimulationLookTableDialog::onaccepted()
{
	QString orbitpath = this->ui->OrbitModelPathLineEdit->text();
	QString SatePath = this->ui->SateSettingLineEdit->text();
	QString DEMPath = this->ui->DEMLineEdit->text();
	QString outDirPath = this->ui->outDirLineEdit->text();

	//double gridX = this->ui->doubleSpinBoxGridX->value();
	//double gridY = this->ui->doubleSpinBoxGridY->value();

	bool gpuflag = this->ui->radioButtonGPU->isChecked();
	bool looktableflag = this->ui->LookTableCheck->isChecked();
	bool checkBoxIncAngle = this->ui->checkBoxIncAngle->isChecked();
	bool BoxDopplerFlag = this->ui->checkBoxDoppler->isChecked();
	QString simulationName = this->ui->lineEditLookName->text();
	this->LookTableSimualtionMainProcess(
		simulationName,
		orbitpath, SatePath, DEMPath, outDirPath,
		gpuflag, looktableflag, checkBoxIncAngle, BoxDopplerFlag
	);


	QMessageBox::information(this, u8"info", u8"completed!!!");

}
