#include "WindDataFileOperator.h"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <filesystem>



/*
* 风场数据格式说明
* 'LAMPWINDDASASET', Height , Width , TIMENUM ,// : int64_t
* 'GEOTRANSFORMER',ESPGCODE,T1,T2,T3,T4,T5,T6
* "WINUV" , TIMELB, UArr[HxWxN],Varr[HxWxN] // double
*/

#define LAMP_WIND_SIGNAL_NUM 15
#define LAMP_WIND_GEOTRANSFORMER_NUM 14
#define LAMP_WIND_WINUV_NUM 6

LAMPWindDataDLL DataFileInfo getDataFileInfo(const char* filepath)
{
    DataFileInfo info = { 0 }; 
    info.Height=-1;
    info.Width = -1;
    info.Num = -1;
    info.firstTimestamp = -1;
    info.lastTimestamp = -1;
    info.minLon=-1;
    info.maxLon=-1;
    info.minLat=-1;
    info.maxLat=-1;
    info.ESPGCODE = -1;
    info.T11=-1;
    info.T12=-1;
    info.T13=-1;
    info.T21=-1;
    info.T22=-1;
    info.T23=-1;
    info.fileSize = -1;


    std::ifstream file(filepath, std::ios::binary);

    if (!file.is_open()) {
        std::cerr << "无法打开文件: " << filepath << std::endl;
        return info;
    }


    // 获取文件大小
    file.seekg(0, std::ios::end);
    info.fileSize = file.tellg();
    file.seekg(0, std::ios::beg);

    const char Fileheader[LAMP_WIND_SIGNAL_NUM]={ 0x4C, 0x41, 0x4D ,0x50, 0x57, 0x49, 0x4E, 0x44, 0x44 ,0x41, 0x53 ,0x41 ,0x53, 0x45 ,0x54 }; // LAMPWINDDASASET
    const char GeoTransHeader[LAMP_WIND_GEOTRANSFORMER_NUM] = { 0x47 ,0x45 ,0x4F ,0x54 ,0x52 ,0x41 ,0x4E ,0x53 ,0x46 ,0x4F ,0x52 ,0x4D ,0x45 ,0x52 }; // GEOTRANSFORMER
	const char WindUVHeader[LAMP_WIND_WINUV_NUM] = { 0x57 ,0x49 ,0x4E ,0x44 ,0x55 ,0x56 }; // WINDUV


    char labelchar = '\0';

    for (int64_t i = 0; i < LAMP_WIND_SIGNAL_NUM; i++) { // 处理头文件
        file.read(reinterpret_cast<char*>(&labelchar), 1);
        if (labelchar != Fileheader[i]) {
            file.close();
            return info;
        }
    }

    // 读取基本维度信息
    file.read(reinterpret_cast<char*>(&info.Height), sizeof(int64_t)); // H
    file.read(reinterpret_cast<char*>(&info.Width), sizeof(int64_t)); // W
    file.read(reinterpret_cast<char*>(&info.Num), sizeof(int64_t)); // N
    
    if (info.Num == 0 || info.Height == 0 || info.Width == 0) {
        file.close();
        return info;
    }

    // 读取地理变换参数
    for (int64_t i = 0; i < LAMP_WIND_GEOTRANSFORMER_NUM; i++) { // 读取标识
        file.read(reinterpret_cast<char*>(&labelchar), 1);
        if (labelchar != GeoTransHeader[i]) {
            file.close();
            return info;
        }
    }

    // 读取数据
	file.read(reinterpret_cast<char*>(&info.ESPGCODE), sizeof(int64_t));
	file.read(reinterpret_cast<char*>(&info.T11), sizeof(double));
	file.read(reinterpret_cast<char*>(&info.T12), sizeof(double));
	file.read(reinterpret_cast<char*>(&info.T13), sizeof(double));
	file.read(reinterpret_cast<char*>(&info.T21), sizeof(double));
	file.read(reinterpret_cast<char*>(&info.T22), sizeof(double));
	file.read(reinterpret_cast<char*>(&info.T23), sizeof(double));

	// 计算经纬度范围（根据地理变换参数估算）
	info.minLon = info.T11;
	info.maxLon = info.T11 + info.Width * info.T12;
	info.minLat = info.T21 + info.Height * info.T23;
	info.maxLat = info.T21;


    // 从数据中抽取
    for (int64_t i = 0; i < LAMP_WIND_WINUV_NUM; i++) {
        file.read(reinterpret_cast<char*>(&labelchar), 1);
        if (labelchar != WindUVHeader[i]) {
            file.close();
            return info;
        }
    }

    std::vector<int64_t> timeArr(info.Num);
    for (int64_t t = 0; t < info.Num; t++) {
        file.read(reinterpret_cast<char*>(&timeArr[t]), sizeof(int64_t));
        int64_t datalen = int64_t(info.Height) * int64_t(info.Width) * 2 * sizeof(double);
        file.seekg(datalen, std::ios::cur);
        if (file.eof()) {
            if (t == info.Num - 1) { // 所有的数据都被处理
                break;
            }
            else {
                file.close();
                return info;
            }
            
        }
        else {}
    }
    std::vector<int64_t>::iterator minIter = std::min_element(timeArr.begin(),timeArr.end());
    std::vector<int64_t>::iterator maxIter = std::max_element(timeArr.begin(),timeArr.end());

    info.firstTimestamp = *minIter;
    info.lastTimestamp = *maxIter;

	file.close();
	return info;
}

LAMPWindDataDLL int32_t get_WindDataFileTimeArr(const char* filepath, DataFileInfo info, int64_t* outtimeArr)
{

    if (info.Num <= 0 || outtimeArr == nullptr) {
        return -1;
    }

    std::ifstream file(filepath, std::ios::binary);
    if (!file.is_open()) {
        return -2;
    }


    int64_t offset = LAMP_WIND_SIGNAL_NUM  // LAMPWINDDASASET
                    + 3 * sizeof(int64_t)
                    + LAMP_WIND_GEOTRANSFORMER_NUM // GEOTRANSFORMER
                    + sizeof(int64_t)
                    + sizeof(double) * 6
                    + LAMP_WIND_WINUV_NUM; // WINUV

    
    file.seekg(offset, std::ios::beg);
    for (int64_t t = 0; t < info.Num; t++) {
        file.read(reinterpret_cast<char*>(&outtimeArr[t]), sizeof(int64_t));
        int64_t datalen = int64_t(info.Height) * int64_t(info.Width) * 2 * sizeof(double);
        file.seekg(datalen, std::ios::cur);
        if (file.eof()) {
            if (t == info.Num - 1) { // 所有的数据都被处理
                break;
            }
            else {
                file.close();
                return -1;
            }

        }
        else {}
    }

 
    file.close();
    return 0;
}

LAMPWindDataDLL int32_t Read_WindDataFile(const char* filepath, DataFileInfo info, int32_t timeID, double* UArr, double* VArr)
{
    if (timeID < 0 || timeID >= info.Num || UArr == nullptr || VArr == nullptr) {
        return -1;
    }

    std::ifstream file(filepath, std::ios::binary);
    if (!file.is_open()) {
        return -2; 
    }
    // 判断信息
    file.seekg(0, std::ios::end);
    int64_t fileSize = file.tellg();
    file.seekg(0, std::ios::beg);

    if (fileSize != info.fileSize) {
        file.close();
        return -3;
    }


    int64_t Headeroffset = LAMP_WIND_SIGNAL_NUM  // LAMPWINDDASASET
        + 3 * sizeof(int64_t)
        + LAMP_WIND_GEOTRANSFORMER_NUM // GEOTRANSFORMER
        + sizeof(int64_t)
        + sizeof(double) * 6
        + LAMP_WIND_WINUV_NUM; // WINUV
    
    int64_t U_block_len= int64_t(info.Height) * int64_t(info.Width)* sizeof(double);
    int64_t V_block_len= int64_t(info.Height) * int64_t(info.Width)* sizeof(double);

    int64_t datalen = sizeof(int64_t) // Time
                      + U_block_len
                      + V_block_len;

    int64_t dataOffset = timeID * datalen;
    int64_t sumOffset = Headeroffset + dataOffset;

    if(sumOffset+datalen<=fileSize){}
    else {
        file.close();
        return -4;
    }



    file.seekg(sumOffset, std::ios::beg);
    
    int64_t timeInt = 0;
    file.read(reinterpret_cast<char*>(&timeInt), sizeof(int64_t));
    file.read(reinterpret_cast<char*>(UArr), U_block_len);
    file.read(reinterpret_cast<char*>(VArr), V_block_len);

    file.close();

    return 0;
}

LAMPWindDataDLL int32_t Write_WindDataFile(const char* filepath, DataFileInfo info, int64_t timeInt,int32_t timeID, double* UArr, double* VArr)
{
    const char Fileheader[LAMP_WIND_SIGNAL_NUM] = { 0x4C, 0x41, 0x4D ,0x50, 0x57, 0x49, 0x4E, 0x44, 0x44 ,0x41, 0x53 ,0x41 ,0x53, 0x45 ,0x54 }; // LAMPWINDDASASET
    const char GeoTransHeader[LAMP_WIND_GEOTRANSFORMER_NUM] = { 0x47 ,0x45 ,0x4F ,0x54 ,0x52 ,0x41 ,0x4E ,0x53 ,0x46 ,0x4F ,0x52 ,0x4D ,0x45 ,0x52 }; // GEOTRANSFORMER
    const char WindUVHeader[LAMP_WIND_WINUV_NUM] = { 0x57 ,0x49 ,0x4E ,0x44 ,0x55 ,0x56 }; // WINDUV



    if (timeID < 0 || timeID >= info.Num || UArr == nullptr || VArr == nullptr) {
        return -1;
    }

    // 判断文件是否存在
    if (! std::filesystem::exists(filepath)) { // 文件不存在
        std::fstream file(filepath, std::ios::binary | std::ios::in | std::ios::out);
        if (!file.is_open()) { // 如果文件不存在，创建新文件并写入完整结构
            file.open(filepath, std::ios::binary | std::ios::out);
            if (!file.is_open()) {
                return -2;
            }

            // 写入文件头
            for (int64_t i = 0; i < LAMP_WIND_SIGNAL_NUM; i++) {
                file.write(reinterpret_cast<const char*>(&Fileheader[i]), sizeof(char));
            }

            // 写入文件信息
            file.write(reinterpret_cast<const char*>(&info.Height), sizeof(int64_t)); // H
            file.write(reinterpret_cast<const char*>(&info.Width), sizeof(int64_t)); // W
            file.write(reinterpret_cast<const char*>(&info.Num), sizeof(int64_t)); // N

            // 写入地理变换参数
            for (int64_t i = 0; i < LAMP_WIND_GEOTRANSFORMER_NUM; i++) {
                file.write(reinterpret_cast<const char*>(&GeoTransHeader[i]), sizeof(char));
            }

            file.write(reinterpret_cast<const char*>(&info.ESPGCODE), sizeof(int64_t));
            file.write(reinterpret_cast<const char*>(&info.T11), sizeof(double));
            file.write(reinterpret_cast<const char*>(&info.T12), sizeof(double));
            file.write(reinterpret_cast<const char*>(&info.T13), sizeof(double));
            file.write(reinterpret_cast<const char*>(&info.T21), sizeof(double));
            file.write(reinterpret_cast<const char*>(&info.T22), sizeof(double));
            file.write(reinterpret_cast<const char*>(&info.T23), sizeof(double));

            // 写入风场数据标签
            for (int64_t i = 0; i < LAMP_WIND_WINUV_NUM; i++) {
                file.write(reinterpret_cast<const char*>(&WindUVHeader[i]), sizeof(char));
            }

            // 写入风场块
            std::vector<double> blockData(info.Width);
            for (int64_t i = 0; i < info.Width; i++) {
                blockData[i] = 0;
            }

            for (int64_t tid = 0; tid < info.Num; tid++) {
                int64_t timeValue = 0;
                if (tid == timeID) { // 
                    timeValue = timeInt;
                    file.write(reinterpret_cast<const char*>(&timeValue), sizeof(int64_t));
                    file.write(reinterpret_cast<const char*>(UArr), info.Height*info.Width * sizeof(double));
                    file.write(reinterpret_cast<const char*>(VArr), info.Height*info.Width * sizeof(double));
                    timeValue = 0;
                }
                else {
                    file.write(reinterpret_cast<const char*>(&timeValue), sizeof(int64_t));
                    for (int64_t i = 0; i < info.Height; i++) { // U 
                        file.write(reinterpret_cast<const char*>(blockData.data()), info.Width*sizeof(double));
                    }
                    for (int64_t i = 0; i < info.Height; i++) { // V 
                        file.write(reinterpret_cast<const char*>(blockData.data()), info.Width*sizeof(double));
                    }
                }
            }
            file.close();
        }
    }
    else {
        std::fstream file(filepath, std::ios::binary | std::ios::in | std::ios::out);

        // 计算数据维度
        int64_t Headeroffset = LAMP_WIND_SIGNAL_NUM  // LAMPWINDDASASET
            + 3 * sizeof(int64_t)
            + LAMP_WIND_GEOTRANSFORMER_NUM // GEOTRANSFORMER
            + sizeof(int64_t)
            + sizeof(double) * 6
            + LAMP_WIND_WINUV_NUM; // WINUV


        file.seekp(LAMP_WIND_SIGNAL_NUM, std::ios::beg);
        int64_t height = 0;
        int64_t width = 0;
        int64_t num = 0;
        file.read(reinterpret_cast<char*>(&height), sizeof(int64_t));
        file.read(reinterpret_cast<char*>(&width), sizeof(int64_t));
        file.read(reinterpret_cast<char*>(&num), sizeof(int64_t));

        if (info.Width != width || info.Height != height||info.Num<num) {
            return -3;
        }
        if (info.Num > num) { // 修改长度
            int64_t offset = LAMP_WIND_SIGNAL_NUM +2 * sizeof(int64_t);
            file.seekg(offset, std::ios::beg);
            file.write(reinterpret_cast<char*>(&info.Num), sizeof(int64_t)); // 修改长度

            offset = LAMP_WIND_SIGNAL_NUM  // LAMPWINDDASASET
                + 3 * sizeof(int64_t)
                + LAMP_WIND_GEOTRANSFORMER_NUM // GEOTRANSFORMER
                + sizeof(int64_t)
                + sizeof(double) * 6
                + LAMP_WIND_WINUV_NUM
                + int64_t(sizeof(int64_t) + int64_t(info.Width) * int64_t(info.Height) * sizeof(double) * 2) * num;

            file.seekg(offset, std::ios::beg);// 移动到 [n-1]  >>|<<[n] 块
            // 结果补零
            std::vector<double> blockData(info.Width);
            for (int64_t i = 0; i < info.Width; i++) {
                blockData[i] = 0;
            }
            for (int64_t tid = num; tid < info.Num; tid++) {
                int64_t timeValue = 0;
                if (tid == timeID) { // 
                    timeValue = timeInt;
                    file.write(reinterpret_cast<const char*>(&timeValue), sizeof(int64_t));
                    file.write(reinterpret_cast<const char*>(UArr), info.Height * info.Width * sizeof(double));
                    file.write(reinterpret_cast<const char*>(VArr), info.Height * info.Width * sizeof(double));
                    timeValue = 0;
                }
                else {
                    file.write(reinterpret_cast<const char*>(&timeValue), sizeof(int64_t));
                    for (int64_t i = 0; i < info.Height; i++) { // U 
                        file.write(reinterpret_cast<const char*>(blockData.data()), info.Width * sizeof(double));
                    }
                    for (int64_t i = 0; i < info.Height; i++) { // V 
                        file.write(reinterpret_cast<const char*>(blockData.data()), info.Width * sizeof(double));
                    }
                }
            }
        }
        else {}

        // 移动到制定为
        int64_t writeoffset = LAMP_WIND_SIGNAL_NUM  // LAMPWINDDASASET
            + 3 * sizeof(int64_t)
            + LAMP_WIND_GEOTRANSFORMER_NUM // GEOTRANSFORMER
            + sizeof(int64_t)
            + sizeof(double) * 6
            + LAMP_WIND_WINUV_NUM
            + int64_t(sizeof(int64_t) + int64_t(info.Width) * int64_t(info.Height) * sizeof(double) * 2) * timeID;
        
        file.seekg(writeoffset, std::ios::beg);

        file.write(reinterpret_cast<const char*>(&timeInt), sizeof(int64_t));
        file.write(reinterpret_cast<const char*>(UArr), int64_t(info.Width)* int64_t(info.Height) * sizeof(double));
        file.write(reinterpret_cast<const char*>(VArr), int64_t(info.Width)* int64_t(info.Height) * sizeof(double));

        file.close();
    }

    
    return 0;
}




