#include<iostream>
#include <QSettings>
#include <QCoreApplication>
#include <QFile>
#include <QTextStream>
#include<Eigen/Dense>
#include<complex>
#include<QDir>
#include <sstream>  
#include<fstream>
#include<iomanip>
#include<string>
#include<QDebug>

extern "C" {
	void  random_state_cpp(double** wf, int* n_wf, int* index)
	{
		char buf[10] = { 0 };
		itoa(*index, buf, 10);
		std::string RandomfileName = "wf_Matrix";
		RandomfileName.append(buf).append(".txt");
		std::ofstream file(RandomfileName);
		if (!file) {
			std::cerr << "Unable to open file " << RandomfileName << std::endl;
			return;
		}
		int iIndex = 0;
		for (size_t i = 0; i < 2 * (*n_wf); i += 2)
		{
			char buf[80] = { 0 };
			sprintf(buf, "%7d   %21.14e  %21.14e", iIndex++, *((*wf) + i), *((*wf) + i + 1));
			file << buf << std::endl; // 或者在行尾使用换行符，取决于你想要的格式  
		}
		file.close();
	}

	int __cdecl tbpm_accond2_(
		double* Bes, int* n_Bes, //Bes[n_Bes] REAL(KIND = 8)
		double* beta, double* mu,
		int* s_indptr, int* n_indptr,//s_indptr[n_indptr]
		int* s_indices, int* n_indices, //s_indices[n_indices]
		double* s_hop, int* n_hop, //s_hop[n_hop] COMPLEX(KIND = 8)
		double* H_rescale,
		double* s_dx, int* n_dx,//s_dx[n_dx]
		double* s_dy, int* n_dy,    //s_dy[n_dy]
		int* seed, int* n_timestep,
		int* n_ran_samples, int* nr_Fermi,
		double* Fermi_precision,
		char* output_filename,
		double* corr);

	void for_rtl_init_(int*, char**);

	int  for_rtl_finish_();
}

template<typename T>
int parseInputStr(QString str, T* dest) {
	int iIndex = 0;
	QString strTemp;
	for (size_t i = 0; i < str.size(); i++) {
		if (str.at(i) == '|') {
			dest[iIndex++] = strTemp.toDouble();
			strTemp.clear();
		}
		else {
			strTemp.append(str.at(i));
		}
	}
	if (!strTemp.isEmpty())
		dest[iIndex++] = strTemp.toDouble();
	return iIndex;
}


template<typename T>
int parseInputStr2(QString str, T* dest) {
	int iIndex = 0;
	QString strTemp;
	for (size_t i = 0; i < str.size(); i++) {
		if (str.at(i) == '|') {
			QString realStr, imgStr;
			for (size_t i = 0; i < strTemp.size(); i++) {
				if (strTemp.at(i) == '~') {
					imgStr = strTemp.mid(i + 1);
					break;
				}
				realStr.push_back(strTemp.at(i));
			}
			dest[2 * iIndex] = realStr.toDouble();
			dest[2 * iIndex + 1] = imgStr.toDouble();
			iIndex++;
			strTemp.clear();
		}
		else {
			strTemp.append(str.at(i));
		}
	}
	if (!strTemp.isEmpty()) {
		QString realStr, imgStr;
		for (size_t i = 0; i < strTemp.size(); i++) {
			if (strTemp.at(i) == '~') {
				imgStr = strTemp.mid(i + 1);
				break;
			}
			realStr.push_back(strTemp.at(i));
		}
		dest[2 * iIndex] = realStr.toDouble();
		dest[2 * iIndex + 1] = imgStr.toDouble();
		iIndex++;
	}
	return iIndex;
}

struct SPARSE_MATRIX_T {
	int* indptr;
	int* indices;
	double* values;
};




int main(int argc, char* argv[]) {
	//保留下参数，进行校验
	QString curPath = QDir::currentPath();
	QString filepath = curPath.append("\\tbpm_sample\\tbpm.input");
	QSettings settings(filepath, QSettings::IniFormat);
	QFile file(filepath);
	if (!file.exists()){
		qDebug() << "file not exist!\n";
		return 1;
	}
	for_rtl_init_(&argc, argv);
	int* n_Bes = (int*)malloc(sizeof(int));
	double* beta = (double*)malloc(sizeof(double));
	double* mu = (double*)malloc(sizeof(double));
	int* n_indptr = (int*)malloc(sizeof(int));
	int* n_indices = (int*)malloc(sizeof(int));
	double* H_rescale = (double*)malloc(sizeof(double));
	int* n_dx = (int*)malloc(sizeof(int));
	int* n_dy = (int*)malloc(sizeof(int));
	int* seed = (int*)malloc(sizeof(int));
	int* n_ran_samples = (int*)malloc(sizeof(int));
	int* nr_Fermi = (int*)malloc(sizeof(int));
	double* Fermi_precision = (double*)malloc(sizeof(double));
	int* rank = (int*)malloc(sizeof(int));
	int* wfn_chk_step = (int*)malloc(sizeof(int));
	double* wfn_chk_thr = (double*)malloc(sizeof(double));
	int* n_hop = (int*)malloc(sizeof(int));
	int* n_timestep = (int*)malloc(sizeof(int));

	// 验证设置是否已写入
	*beta = settings.value("tbpm_accond/beta").toDouble();
	*mu = settings.value("tbpm_accond/mu").toDouble();
	*seed = settings.value("tbpm_accond/seed").toInt();
	*Fermi_precision = settings.value("tbpm_accond/Fermi_precision").toDouble();
	*n_ran_samples = settings.value("tbpm_accond/n_ran_samples").toDouble();
	*H_rescale = settings.value("tbpm_accond/H_rescale").toDouble();
	*nr_Fermi = settings.value("tbpm_accond/nr_Fermi").toDouble();
	*n_timestep = settings.value("tbpm_accond/n_timestep").toInt();

	QString out_fileName = settings.value("tbpm_accond/output_filename").toString();
	char output_filename[256] = { 0 };
	memcpy(output_filename, out_fileName.toStdString().c_str(), out_fileName.toStdString().length());

	*n_Bes = settings.value("tbpm_accond/nBes").toInt();
	double* Bes = (double*)malloc(*n_Bes * sizeof(double));//Bes[n_Bes] REAL(KIND = 8)
	QString value = settings.value("Bes").toString();
	int Ret = parseInputStr<double>(value, Bes);
	if (Ret != *n_Bes)
		printf("parse Bes arg error!\n");


	*n_indptr = settings.value("tbpm_accond/n_indptr").toInt();
	int* s_indptr = (int*)malloc((*n_indptr) * sizeof(int));//s_indptr[n_indptr]
	value = settings.value("s_indptr").toString();
	Ret = parseInputStr<int>(value, s_indptr);
	if (Ret != *n_indptr)
		printf("parse n_indptr arg error!\n");

	*n_indices = settings.value("tbpm_accond/n_indices").toInt();
	int* s_indices = (int*)malloc((*n_indices) * sizeof(int));//s_indices[n_indices]
	value = settings.value("s_indices").toString();
	Ret = parseInputStr<int>(value, s_indices);
	if (Ret != *n_indices)
		printf("parse s_indices arg error!\n");

	*n_dy = settings.value("tbpm_accond/n_dy").toInt();
	double* s_dy = (double*)malloc(*n_dy * sizeof(double)); //s_dy[n_dy]
	value = settings.value("n_dy").toString();
	Ret = parseInputStr<double>(value, s_dy);
	if (Ret != *n_dy)
		printf("parse n_dy arg error!\n");

	*n_dx = settings.value("tbpm_accond/n_dx").toInt();
	double* s_dx = (double*)malloc(*n_dx * sizeof(double)); //s_dy[n_dy]
	value = settings.value("n_dx").toString();
	Ret = parseInputStr<double>(value, s_dx);
	if (Ret != *n_dx)
		printf("parse s_dx arg error!\n");


	*n_hop = settings.value("tbpm_accond/n_hop").toInt();
	double* s_hop = (double*)malloc(2 * (*n_hop) * sizeof(double));//s_hop[n_hop] COMPLEX(KIND = 8)
	value = settings.value("s_hop").toString();
	Ret = parseInputStr2<double>(value, s_hop);
	if (Ret != *n_hop)
		printf("parse s_hop arg error!\n");

	//输出的信息
	double* corr = (double*)malloc(2 * 4 * (*n_timestep) * sizeof(double));//  COMPLEX(KIND = 8), INTENT(OUT), DIMENSION(4, n_timestep) ::corr
	//这个function完全可以调用！
	int result = tbpm_accond2_(Bes, n_Bes, beta, mu, s_indptr, n_indptr,
		s_indices, n_indices, s_hop, n_hop, H_rescale, s_dx, n_dx,
		s_dy, n_dy, seed, n_timestep, n_ran_samples, nr_Fermi,
		Fermi_precision, output_filename, corr);

	int io_status;
	io_status = for_rtl_finish_();
	return 1;
}