//
// Created by xueyimeng on 19-11-24.
//

#include "FileUtility.h"
#include "Utility.h"
//#include <filesystem> // C++17
#include <experimental/filesystem> // C++14
#include <iostream>
#include <fstream>
#include <glog/logging.h>

std::vector<std::string> FileUtility::ReadAllFiles(const std::string& parent_path, const std::string& filter) {
    std::vector<std::string> vec_filenames;
    if(!FileUtility::IsFolderExist(parent_path)) {
        LOG(ERROR) << "path " << parent_path << " do not exist!";
        return vec_filenames;
    }

#ifdef __linux__
    struct dirent *dirp;
    DIR* dir = opendir(parent_path.c_str());
    while ((dirp = readdir(dir)) != nullptr) {
        if (dirp->d_type == DT_REG) {
            // 文件
            std::string filename = dirp->d_name;
            int pos = filename.find_last_of(".");
            std::string ext = filename.substr(pos, filename.length()-pos);
            if(ext == filter) {
                std::string filepathname = parent_path + "/" + filename;
                vec_filenames.push_back(filepathname);
            }
        } else if (dirp->d_type == DT_DIR) {
            // 文件夹
            std::string sub_dirname = dirp->d_name;
            if(sub_dirname == "." || sub_dirname == "..") {
                continue;
            }
            std::string dir_name = parent_path + "/" + dirp->d_name + "/";
            std::vector<std::string> vec_pathnames = ReadAllFiles(dir_name, filter);
            if(!vec_pathnames.empty()) {
                vec_filenames.insert(vec_filenames.end(), vec_pathnames.begin(), vec_pathnames.end());
            }
        }
    }

    closedir(dir);
#endif
    return vec_filenames;
}

std::vector<std::string> FileUtility::ReadAllSubDir(const std::string& parent_path) {
    std::vector<std::string> vec_subpath;
    struct dirent *dirp;
#ifdef __linux__
    DIR* dir = opendir(parent_path.c_str());
    while ((dirp = readdir(dir)) != nullptr) {
        if (dirp->d_type == DT_DIR) {
            // 文件夹
            std::string path = dirp->d_name;
            if(path == "." || path == ".." || path == "tmp")
                continue;

            std::string fullpath = parent_path + "/" + path;
            vec_subpath.push_back(fullpath);
        } else if (dirp->d_type == DT_REG) {

        }
    }

    closedir(dir);
#endif
    return vec_subpath;
}

bool FileUtility::MakeDir(const std::string& path, int mode) {
    namespace fs = std::experimental::filesystem;
    return fs::create_directories(path);
}


bool FileUtility::IsFolderExist(const std::string &path)
{
#ifdef __linux__
    DIR *dp;
    if ((dp = opendir(path.c_str())) == NULL)
    {
        return false;
    }

    closedir(dp);
#endif
    return true;
}

bool FileUtility::IsDirectory(const std::string& path) {
    namespace fs = std::experimental::filesystem;
    std::error_code ec; // For using the non-throwing overloads of functions below.
    if (fs::is_directory(path, ec)) {
        return true;
    }
    return false;
}
//-1是存在
bool FileUtility::IsFileExist(const std::string& path)
{
#ifdef _WIN32
    return true;
#elif __linux__
    //for linux
    int ret = access(path.c_str(), F_OK);
    return 0 == ret;
#endif
    return true;
}

bool FileUtility::RemoveDir(const std::string& dir_to_remove) {
    if(!FileUtility::IsFolderExist(dir_to_remove))
        return false;

    namespace fs = std::experimental::filesystem;
    fs::remove_all(dir_to_remove);
    return true;
}

bool Parse(const std::map<std::string, std::string>& map_key_value, std::string key, std::string& value) {
    auto iter = map_key_value.find(key);
    if(iter == map_key_value.end()) {
        LOG(ERROR) << "failed to find keyword " << key;
        return false;
    }

    value = iter->second;
    return true;
}

bool FileUtility::LoadStationInfo(const std::string& station_filename, StationInfo& stationInfo) {
    std::ifstream ifs(station_filename.c_str());
    if(!ifs.is_open()) {
        LOG(ERROR) << "open " << station_filename << " failed!";
        return false;
    }

    char buf[1024];
    std::map<std::string, std::string> map_key_value;
    while(!ifs.eof()) {
        ifs.getline(buf, 1024);
        std::string line = buf;
        std::vector<std::string> vec_key_value;
        Utility::SplitString(line, vec_key_value,":");
        if(vec_key_value.size() != 2) {
            continue;
        }

        map_key_value[vec_key_value[0]] = vec_key_value[1];
    }

    std::string str_ref_lat, str_ref_lon, str_ref_height, str_srid;
    std::string str_utm_offset_x, str_utm_offset_y, str_utm_offset_z;

    if(!Parse(map_key_value, "LON_WGS84", str_ref_lon)) {
        return false;
    }

    if(!Parse(map_key_value, "LAT_WGS84", str_ref_lat)) {
        return false;
    }

    if(!Parse(map_key_value, "HIGH_WGS84", str_ref_height)) {
        return false;
    }

    if(!Parse(map_key_value, "SRID", str_srid)) {
        return false;
    }

    if(!Parse(map_key_value, "E0_PROJECT", str_utm_offset_x)) {
        return false;
    }

    if(!Parse(map_key_value, "N0_PROJECT", str_utm_offset_y)) {
        return false;
    }

    if(!Parse(map_key_value, "H0_PROJECT", str_utm_offset_z)) {
        return false;
    }

    stationInfo.ref_lat = std::atof(str_ref_lat.c_str());
    stationInfo.ref_lon = std::atof(str_ref_lon.c_str());
    stationInfo.ref_height = std::atof(str_ref_height.c_str());
    stationInfo.srid = std::atoi(str_srid.c_str())%100;
    stationInfo.utm_offset_x = std::atof(str_utm_offset_x.c_str());
    stationInfo.utm_offset_y = std::atof(str_utm_offset_y.c_str());
    stationInfo.utm_offset_z = std::atof(str_utm_offset_z.c_str());

    int srid = 31 + std::floor(stationInfo.ref_lon / 6.0);
    if(srid != stationInfo.srid)
    {
        LOG(ERROR) << "source and computed srid is not equal," <<  stationInfo.srid << " vs " <<srid;
        LOG(ERROR) << stationInfo.ref_lon << "," << stationInfo.ref_lat << "," << stationInfo.ref_height;
        return false;
    }
    return true;
}