//
// Created by matrixai on 4/2/24.
//

#include "FileUtil.h"

namespace ai_matrix
{
    FileUtil *FileUtil::ins = nullptr;
    FileUtil::GarbageCollector FileUtil::gc;
    std::mutex FileUtil::mx;

    FileUtil *FileUtil::getins()
    {
        //双层锁，确保线程安全
        if (ins == nullptr)
        {
            std::lock_guard<std::mutex> guard(mx); //防止异常发生不能解锁
            if (ins == nullptr)
            {
                ins = new FileUtil();
            }
        }
        return ins;
    }

    /**
    * 创建文件夹路径
    * inParam : std::string strDirPath   :文件夹路径
    * outParam: N/A
    * return  : true/false
    */
    bool FileUtil::createDirPath(std::string strDirPath)
    {
        if (strDirPath.back() != '/')
        {
            strDirPath += "/";
        }

        if (access(strDirPath.c_str(), F_OK) == 0)
        {
            return true;
        }

        std::string::size_type pos = strDirPath.find('/');
        while (pos != std::string::npos)
        {
            std::string strCur = strDirPath.substr(0, pos);
            if (!strCur.empty() && access(strCur.c_str(), F_OK) != 0)
            {
                if (mkdir(strCur.c_str(), 0755) != 0) //如果父目录不存在，会创建失败
                {
                    perror("mkdir fail");
                    return false;
                }

                if (chmod(strCur.c_str(), 0777) != 0)
                {
                    perror("chmod fail");
                }
            }
            pos = strDirPath.find('/', pos + 1);
        }
        return true;
    }

    std::string FileUtil::create_dir_name(std::string root, std::string name)
    {
        std::string dir_path = root + "/" + name;
        if (access(dir_path.c_str(), F_OK) != 0)
        {
            if (mkdir(dir_path.c_str(), 0755) != 0) //如果父目录不存在，会创建失败
            {
                perror("mkdir fail");
                return "";
            }
        }
        return dir_path;
    }

    std::string FileUtil::create_dir_date(std::string root)
    {
        time_t timep = time(NULL);
        struct tm *p = localtime(&timep);

        char tmp_date[20] = {0};
        sprintf(tmp_date, "%04d-%02d-%02d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday);

        std::string dir_path;

        dir_path = root + "/" + std::string(tmp_date); //创建日期目录
        if (access(dir_path.c_str(), F_OK) != 0)
        {
            if (mkdir(dir_path.c_str(), 0755) != 0) //如果父目录不存在，会创建失败
            {
                perror("mkdir fail");
                return "";
            }
        }

        return dir_path;
    }

    std::string FileUtil::create_dir_date_name_time(std::string root, std::string name)
    {
        time_t timep = time(NULL);
        struct tm *p = localtime(&timep);

        char tmp_date[20] = {0};
        sprintf(tmp_date, "%04d-%02d-%02d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday);

        char tmp_time[20] = {0};
        sprintf(tmp_time, "%02d-%02d-%02d", p->tm_hour, p->tm_min, p->tm_sec);

        std::string dir_path;

        dir_path = root + "/" + std::string(tmp_date); //创建日期目录
        if (access(dir_path.c_str(), F_OK) != 0)
        {
            if (mkdir(dir_path.c_str(), 0755) != 0) //如果父目录不存在，会创建失败
            {
                perror("mkdir fail");
                return "";
            }
        }

        dir_path = dir_path + "/" + name + "_" + std::string(tmp_time); //创建点云目录
        if (access(dir_path.c_str(), F_OK) != 0)
        {
            if (mkdir(dir_path.c_str(), 0755) != 0) //如果父目录不存在，会创建失败
            {
                perror("mkdir fail");
                return "";
            }
        }

        return dir_path;
    }

    std::string FileUtil::create_file_path(std::string root, std::string name, std::string suffix)
    {
        time_t timep = time(NULL);
        struct tm *p = localtime(&timep);

        char tmp_date[20] = {0};
        sprintf(tmp_date, "%04d-%02d-%02d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday);

        char tmp_time[20] = {0};
        sprintf(tmp_time, "%02d-%02d-%02d", p->tm_hour, p->tm_min, p->tm_sec);

        std::string file_path;

        file_path = root + "/" + std::string(tmp_date); //创建日期目录
        if (access(file_path.c_str(), F_OK) != 0)
        {
            if (mkdir(file_path.c_str(), 0755) != 0) //如果父目录不存在，会创建失败
            {
                perror("mkdir fail");
                return "";
            }
        }

        file_path = file_path + "/" + name + "_" + std::string(tmp_time) + suffix; //创建文件

        return file_path;
    }

/**
     * 拷贝文件
     * @param filePath 源文件位置
     * @param savePath 将要拷贝的新位置
     * @return
     */
    bool FileUtil::copyFile(std::string filePath, std::string savePath) {
        FILE *fp, *sp;
        fp = fopen(filePath.c_str(), "rb");
        sp = fopen(savePath.c_str(), "w+b");
        if (!fp) {
            return false;
        }
        void *buffer;
        while (!feof(fp)) {
            fread(&buffer, 1, 1, fp);
            fwrite(&buffer, 1, 1, sp);
        }
        fclose(fp);
        fclose(sp);
        return true;
    }

    /**
     * 读取json格式文件内容
     * inParam : std::string &strFilePath  :文件路径
     * outParam: Json::Value &jvFileInfo   :json格式内容
     * return  : true/false
     */
    bool FileUtil::readJsonInfo(Json::Value &jvFileInfo, std::string &strFilePath)
    {
        try {
            std::ifstream ifs(strFilePath.c_str(), std::ios::binary);
            if (!ifs.is_open())
            {
                return false;
            }
            Json::Reader reader;
            if (!reader.parse(ifs, jvFileInfo))
            {
                return false;
            }
        } catch (...) {
            return false;
        }
        return true;
    }

    /**
    * json格式内容写入文件
    * inParam : Json::Value &jvFileInfo   :json格式内容
              : std::string &strFilePath  :文件路径
    * outParam: N/A
    * return  : true/false
    */
    bool FileUtil::writeJsonInfo(Json::Value &jvFileInfo, std::string &strFilePath)
    {
        Json::StreamWriterBuilder jswBuilder;
        // 紧密型存储
        jswBuilder["indentation"] = "";
        std::string strFrameInfo = Json::writeString(jswBuilder, jvFileInfo);

        std::ofstream ofs(strFilePath.c_str());
        if (!ofs.is_open())
        {
//            LogWarn << "txt:" << strFilePath << " open fail";
            return false;
        }
        ofs.write(strFrameInfo.c_str(), strFrameInfo.length());
        ofs.close();
        return true;
    }
}
