#include "LAMPScatterS1B.h"
#include <flann/flann.hpp>
#include <QDebug>

LAMPScatterS1BRCSDataNode::LAMPScatterS1BRCSDataNode(QString PolarName, double AzAngle, double IncAngle, std::shared_ptr<double> freqs, std::shared_ptr<double> InRCSPoints, long freqnumber)
{
    this->PolarName = PolarName;
    this->FreqPointNumber = freqnumber;
    this->FreqPoints = freqs;
    this->RCSPoints = InRCSPoints;
    this->AzAngle = AzAngle;
    this->IncAngle = IncAngle;
}

LAMPScatterS1BRCSDataNode::~LAMPScatterS1BRCSDataNode()
{
}

long LAMPScatterS1BRCSDataNode::getFreqPointNumber()
{
    return this->FreqPointNumber;
}

std::shared_ptr<double> LAMPScatterS1BRCSDataNode::getFreqPoints()
{
    return this->FreqPoints;
}

std::shared_ptr<double> LAMPScatterS1BRCSDataNode::getRCSPoints()
{
    return this->RCSPoints;
}

QString LAMPScatterS1BRCSDataNode::getPolarName()
{
    return this->PolarName;
}

double LAMPScatterS1BRCSDataNode::getAzAngle()
{
    return this->AzAngle;
}

double LAMPScatterS1BRCSDataNode::getIncAngle()
{
    return this->IncAngle;
}

 
 

LAMPScatterS1BPolarKdTree::LAMPScatterS1BPolarKdTree(std::vector<std::shared_ptr<LAMPScatterS1BRCSDataNode>> inDatalist)
{
    this->KdtreeFlannDatasetPtr = nullptr;
    this->kdtreeIndexPtr = nullptr;
    this->datalist = std::vector<std::shared_ptr< LAMPScatterS1BRCSDataNode >>(inDatalist.size());
    for (long i = 0; i < inDatalist.size(); i++) {
        this->datalist[i] = inDatalist[i];
    }

   this->dataset= std::vector<std::vector<double>>(this->datalist.size(), std::vector<double>(2));
    for (size_t i = 0; i < this->datalist.size(); ++i) {
        dataset[i][0] = static_cast<double>(this->datalist[i]->getAzAngle());
        dataset[i][1] = static_cast<double>(this->datalist[i]->getIncAngle());
    }

    // 构建KDtree
    this->KdtreeFlannDatasetPtr = std::make_shared < flann::Matrix<double>>(&(this->dataset)[0][0], this->dataset.size(), this->dataset[0].size());
    this->kdtreeIndexPtr = std::make_shared<flann::Index<flann::L2<double>>>(*(this->KdtreeFlannDatasetPtr.get()), flann::KDTreeSingleIndexParams(1));
    this->kdtreeIndexPtr->buildIndex();
 

}

LAMPScatterS1BPolarKdTree::~LAMPScatterS1BPolarKdTree()
{
    this->datalist.clear();
    std::vector<std::shared_ptr< LAMPScatterS1BRCSDataNode >>().swap(this->datalist);
}

QVector<std::shared_ptr< LAMPScatterS1BRCSDataNode >> LAMPScatterS1BPolarKdTree::search(double sAzAngle, double sIncAngle, long sPointNumber)
{

    // 查询点
    std::vector<double> queryPoint = { sAzAngle, sIncAngle };
    flann::Matrix<double> query(&queryPoint[0], 1, queryPoint.size());

    // 存储结果索引和距离
    std::vector<int> indices(sPointNumber);
    std::vector<double> dists(sPointNumber);

    // 确保 indices 和 dists 是 flann::Matrix 类型
    flann::Matrix<int> flannIndices(&indices[0], sPointNumber, 1);
    flann::Matrix<double> flannDists(&dists[0], sPointNumber, 1);

    // 执行最近邻搜索
    int result = this->kdtreeIndexPtr->knnSearch(query, flannIndices, flannDists, sPointNumber, flann::FLANN_CHECKS_AUTOTUNED);


    if (result > 0) {

        QVector<std::shared_ptr< LAMPScatterS1BRCSDataNode >> searchResults(sPointNumber);
        for(long i=0;i< sPointNumber;i++){
            searchResults[i] = datalist[indices[0]];
        }
        return searchResults;
    }
    else {
        return QVector<std::shared_ptr< LAMPScatterS1BRCSDataNode >>(0);
    }
}

int LAMPScatterS1BDataset::OpenFile(QString s1bfilepath)
{
    int ncid;
    if (nc_open(s1bfilepath.toLocal8Bit().constData(), NC_NOWRITE, &ncid)) {
        qCritical() << "Failed to open NetCDF file";
        return 1;
    }

    int FreqVarid   ;    
    int PolVarid    ;    
    int AzVarid     ;    
    int IncVarid    ;
    int RCSVarid    ;
    if (nc_inq_varid(ncid, "Freq", &FreqVarid)
        || nc_inq_varid(ncid, "Pol", &PolVarid)
        || nc_inq_varid(ncid, "Az", &AzVarid)
        || nc_inq_varid(ncid, "Inc", &IncVarid)
        || nc_inq_varid(ncid, "RCS", &RCSVarid)
        ) {
        qDebug() << "Failed to get variable  ";
        qDebug() << "Freq:\t" << FreqVarid << "\tPol:\t" << PolVarid << "\tAz:\t" << AzVarid << "\tInc:\t" << IncVarid << "\RCS:\t" << RCSVarid;
        nc_close(ncid);
        return 1;
    }
    
    qDebug() << "[VarID]\t Freq:\t" << FreqVarid << "\tPol:\t" << PolVarid << "\tAz:\t" << AzVarid << "\tInc:\t" << IncVarid << "\RCS:\t" << RCSVarid;



    // 检查变量维度
    int Freqndims   ; 
    int Polndims    ;
    int Azndims     ;
    int Incndims    ;
    int RCSndims    ;
    if (   nc_inq_varndims(ncid, FreqVarid , &Freqndims)
        || nc_inq_varndims(ncid, PolVarid  , &Polndims )
        || nc_inq_varndims(ncid, AzVarid   , &Azndims  )
        || nc_inq_varndims(ncid, IncVarid  , &Incndims )
        || nc_inq_varndims(ncid, RCSVarid  , &RCSndims )
        ) {
        qDebug() << "Failed to get number of dimensions for variable";
        qDebug() << "[Dimensions]\t Freq:\t" << Freqndims 
                                << "\tPol:\t"<< Polndims  
                                << "\tAz:\t" << Azndims   
                                << "\tInc:\t"<< Incndims  
                                << "\RCS:\t" << RCSndims     ;

        nc_close(ncid);
        return 1;
    }
    qDebug() << "[Dimensions]\t Freq:\t" << Freqndims
        << "\tPol:\t" << Polndims
        << "\tAz:\t" << Azndims
        << "\tInc:\t" << Incndims
        << "\RCS:\t" << RCSndims;



    // 获取 点数据数量

    std::vector<int> Freqdimids (Freqndims  );
    std::vector<int> Poldimids  (Polndims   );
    std::vector<int> Azdimids   (Azndims    );
    std::vector<int> Incdimids  (Incndims   );
    std::vector<int> RCSdimids  (RCSndims   );

    if (   nc_inq_vardimid(ncid, FreqVarid ,  Freqdimids.data())
        || nc_inq_vardimid(ncid, PolVarid  ,  Poldimids .data())
        || nc_inq_vardimid(ncid, AzVarid   ,  Azdimids  .data())
        || nc_inq_vardimid(ncid, IncVarid  ,  Incdimids .data())
        || nc_inq_vardimid(ncid, RCSVarid  ,  RCSdimids .data())
        ) {
        qDebug() << "Failed to get dimension IDs for variable";
        qDebug() << "[Dimensions IDs]\t Freq:\t" << Freqdimids.size()
                                << "\tPol:\t"<< Poldimids .size()
                                << "\tAz:\t" << Azdimids  .size()
                                << "\tInc:\t"<< Incdimids .size()
                                << "\RCS:\t" << RCSdimids .size()      ;
        nc_close(ncid);
        return 1;
    }
    qDebug() << "[Dimensions IDs]\t Freq:\t" << Freqdimids.size()
        << "\tPol:\t" << Poldimids.size()
        << "\tAz:\t" << Azdimids.size()
        << "\tInc:\t" << Incdimids.size()
        << "\RCS:\t" << RCSdimids.size();


    std::vector<int> Freqdimsize(Freqndims);
    std::vector<int> Poldimsizes(Polndims);
    std::vector<int> Azdimsize  (Azndims);
    std::vector<int> Incdimsize (Incndims);
    std::vector<int> RCSdimsize (RCSndims);



    for (long i = 0; i < Freqdimids.size(); i++) {
        size_t datalen_temp;
        if (nc_inq_dimlen(ncid, Freqdimids[i], &datalen_temp)) {
            qDebug() << "Failed to get Freqdimsize  for variable";
        }
        else {
            Freqdimsize[i] = datalen_temp;
        }
        
    }

    for (long i = 0; i < Poldimids.size(); i++) {
        size_t datalen_temp;
        if (nc_inq_dimlen(ncid, Poldimids[i], &datalen_temp)) {
            qDebug() << "Failed to get Poldimids  for variable";
        }
        else {
            Poldimsizes[i] = datalen_temp;
        }
    }

    for (long i = 0; i < Azdimids.size(); i++) {
        size_t datalen_temp;
        if (nc_inq_dimlen(ncid, Azdimids[i], &datalen_temp)) {
            qDebug() << "Failed to get Azdimids  for variable";
        }
        else {
            Azdimsize[i] = datalen_temp;
        }
    }

    for (long i = 0; i < Incdimids.size(); i++) {
        size_t datalen_temp;
        if (nc_inq_dimlen(ncid, Incdimids[i], &datalen_temp)) {
            qDebug() << "Failed to get Incdimids  for variable";
        }
        else {
            Incdimsize[i] = datalen_temp;
        }
    }

    for (long i = 0; i < RCSdimids.size(); i++) {
        size_t datalen_temp;
        if (nc_inq_dimlen(ncid, RCSdimids[i], &datalen_temp)) {
            qDebug() << "Failed to get RCSdimids  for variable";
        }
        else {
            RCSdimsize[i] = datalen_temp;
        }
    }

    long Freq_datalen =1;
    long Pol_datalen  =1;
    long Az_datalen   =1;
    long Inc_datalen  =1;
    long RCS_datalen  =1;


    for (long i = 0; i < Freqdimsize.size(); i++) {
        Freq_datalen = Freq_datalen * Freqdimsize[i];
    }

    for (long i = 0; i < Poldimsizes.size(); i++) {
        Pol_datalen = Pol_datalen * Poldimsizes[i];
    }

    for (long i = 0; i < Azdimsize.size(); i++) {
        Az_datalen = Az_datalen * Azdimsize[i];
    }

    for (long i = 0; i < Incdimsize.size(); i++) {
        Inc_datalen = Inc_datalen * Incdimsize[i];
    }

    for (long i = 0; i < RCSdimsize.size(); i++) {
        RCS_datalen = RCS_datalen * RCSdimsize[i];
    }

    qDebug() << "[Data Size]\t Freq:\t" << Freq_datalen
        << "\tPol:\t" << Pol_datalen
        << "\tAz:\t" << Az_datalen
        << "\tInc:\t" << Inc_datalen
        << "\RCS:\t" << RCS_datalen;

    // 读取数据
    std::vector<float> pol_data    (Pol_datalen);
    std::vector<float> inc_data    (Inc_datalen);
    std::vector<float> az_data     (Az_datalen    );
    std::vector<float> freq_data   (Freq_datalen);
    std::vector<double> rcs_data    (RCS_datalen);

	if (   nc_get_var_float(ncid, FreqVarid,    freq_data.data())
		//|| nc_get_var_float(ncid, PolVarid,     pol_data.data())
		//|| nc_get_var_float(ncid, AzVarid,      az_data.data())
		//|| nc_get_var_float(ncid, IncVarid,     inc_data.data())
		//|| nc_get_var_double(ncid, RCSVarid,    rcs_data.data())
        ) {
        qDebug() << "reading Data for variable";
        qDebug() << "[Data size ]\t Freq:\t" <<     pol_data   .size()
                                << "\tPol:\t" <<    inc_data   .size()
                                << "\tAz:\t" <<     az_data    .size()
                                << "\tInc:\t" <<    freq_data  .size()
                                << "\RCS:\t" <<     rcs_data   .size();
        nc_close(ncid);
        return 1;
    }

    qDebug() << "[Data size ]\t Freq:\t" << pol_data.size()
        << "\tPol:\t" << inc_data.size()
        << "\tAz:\t" << az_data.size()
        << "\tInc:\t" << freq_data.size()
        << "\RCS:\t" << rcs_data.size();


    // 读取Pol的属性
    QMap<QString, QString> polnamedict = ReadPolAttribution(ncid, PolVarid);
    if (polnamedict.count()==0) {
        qDebug() << "Failed to get attribution Number for variable Pol ";
        nc_close(ncid);
        return 1;
    }
    nc_close(ncid);


	// 创建节点
	for (long PolId = 0; PolId < Pol_datalen; PolId++) { // Polar
		QString polkey = QString("label_Pol_%1").arg(PolId+1);
		QString polname = polnamedict[polkey];
		std::vector<std::shared_ptr< LAMPScatterS1BRCSDataNode >> nodes(0);
		for (long Azid = 0; Azid < Az_datalen; Azid++) { // Az
			for (long Incid = 0; Incid < Inc_datalen; Incid++) { // Inc

				std::shared_ptr<double> freqs(new double[Freq_datalen], LAMPScatterS1BdelArrPtr);
				std::shared_ptr<double> RCSData(new double[Freq_datalen], LAMPScatterS1BdelArrPtr);
                double Azvalue = az_data[Azid];
                double Incvalue = inc_data[Azid];
				for (long freqID = 0; freqID < Freq_datalen; freqID++) { // Freq

					freqs.get()[freqID] = freq_data[freqID];
					RCSData.get()[freqID] = rcs_data[PolId * Az_datalen * Inc_datalen * Freq_datalen +
						Azid * Inc_datalen * Freq_datalen +
						Incid * Freq_datalen +
						freqID
					];
				}

                std::shared_ptr<LAMPScatterS1BRCSDataNode> node(new LAMPScatterS1BRCSDataNode(polname, Azvalue, Incvalue, freqs, RCSData, Freq_datalen));
                nodes.push_back(node);
			}
		}

        std::shared_ptr< LAMPScatterS1BPolarKdTree> treetemp(new LAMPScatterS1BPolarKdTree(nodes));
        polarRCSTree.insert(polname, treetemp); // KDTree
	}

    this->FreqPointNumber= Freq_datalen;
    this->polNumber= Pol_datalen;
    this->AzNumber = Az_datalen;
    this->IncNumber = Inc_datalen;

	std::vector<float>().swap(pol_data);
	std::vector<float>().swap(inc_data);
	std::vector<float>().swap(az_data);
	std::vector<float>().swap(freq_data);
	std::vector<double>().swap(rcs_data);
      
	std::vector<int>().swap(Freqdimids);
	std::vector<int>().swap(Poldimids);
	std::vector<int>().swap(Azdimids);
	std::vector<int>().swap(Incdimids);
	std::vector<int>().swap(RCSdimids);
      
    std::vector<int>().swap(Freqdimsize);
    std::vector<int>().swap(Poldimsizes);
    std::vector<int>().swap(Azdimsize);
    std::vector<int>().swap(Incdimsize);
    std::vector<int>().swap(RCSdimsize);


    return 0;


}

std::complex<double> LAMPScatterS1BDataset::getRCSData(QString polarName, double AzAngle, double IncAngle, double FreqId)
{
    return std::complex<double>();
}

QMap<QString, QString> LAMPScatterS1BDataset::ReadPolAttribution(int ncid, int pol_varid)
{

    int num_atts;
    if (nc_inq_varnatts(ncid, pol_varid, &num_atts)) {
        return QMap<QString, QString>();
    }
    if (num_atts == 0) {
        return QMap<QString, QString>();
    }
    else {
        QMap<QString, QString> result;
        qDebug() << "Attributes for Pol:" ;
        for (int i = 0; i < num_atts; ++i) {
            char att_name[NC_MAX_NAME + 1];
            if (nc_inq_attname(ncid, pol_varid, i, att_name)) {
                qDebug() << "Error getting attribute name";

            }
           
            // 获取属性类型和长度
            nc_type xtype;
            size_t len;
            if (nc_inq_att(ncid, pol_varid, att_name, &xtype, &len)) {
                qDebug() << "Error getting attribute type and length";

            }
 
            // 根据属性类型读取属性值
            switch (xtype) {
            case NC_CHAR: {
                std::vector<char> att_value(len + 1); // +1 for null terminator
                if (nc_get_att_text(ncid, pol_varid, att_name, att_value.data())) {
                    qDebug() << "Error reading text attribute";
                }
                
                qDebug() << "Attribute Name: " << att_name << ", Type: NC_CHAR, Value: " << att_value.data();
                result.insert(QString(att_name), QString(att_value.data()));
                break;
            }
            default:
                qDebug() << "Attribute Name: " << att_name << ", Type: Unknown";
                break;
            }
        }
        return result;
    }
}
