
#include "FileSys.h"

#include "Log.h"
#include "MapConfig.h"
#include "Utils.h"

extern "C" {
#include "xxtea.h"
}

#include <dirent.h>  //windows开发工具没有这个头文件
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <cstdlib>
#include <iostream>
#include <ostream>
#include <string>
#include <vector>
#include <memory>

using namespace std;
using namespace jf;

std::string FileSys::key = "jfx2020!";

std::vector<string> FileSys::GetAllFiles(const string& indir) {
    std::vector<string> ret;
    DIR* dir;
    struct dirent* ptr;
    int i = 0;
    dir = opendir(indir.c_str());
    if (!dir) {
        // jf_log_error("cannot find dir {}", indir.c_str());
        return {};
    }
    while ((ptr = readdir(dir)) != NULL) {
        printf("d_name : %s\n", ptr->d_name);
        ret.push_back(ptr->d_name);
    }
//    delete ptr;
    return ret;
}

bool FileSys::Read(const std::string& f, std::string& is, bool encrypt) {
    // jf_log_info("[FileSys::Read] load file {0}", f);
    if (!Exist(f)) {
        // jf_log_error("[FileSys::Read] file {0} cannot found", f);
        return false;
    }
    std::ifstream in(f.c_str(), ios::binary);
    string str((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
    if (encrypt) {
        size_t outlen;
        void* outdata = xxtea_decrypt(str.data(), str.length(), key.data(), &outlen);
        std::stringstream ss;
        ss.write((char*)outdata, outlen);
        is = ss.str();
        free(outdata);
    } else {
        is = str;
    }
    return in.good();
}

void FileSys::AppendSlow(const std::string& f, const std::string& content) {
#ifndef ANDROID
    std::string p = MapConfig::GetProjectDir() + f;
    // jf_log_info("[FileSys::Save] Save file {}", p);
    std::ofstream of;
    of.open(f.c_str(), iostream::app);
    of << content;
    of.close();
#endif
}

void FileSys::Save(const std::string& f, const std::string& content, bool encrypt) {
    // jf_log_info("[FileSys::Save] Save file {}", f);
    std::ofstream of;
    of.open(f.c_str(), ios::binary);
    if (encrypt) {
        size_t outlen;
        void* outdata = xxtea_encrypt(content.data(), content.length(), key.data(), &outlen);
        std::stringstream outss;
        outss.write((char*)outdata, outlen);
        of << outss.rdbuf();
        free(outdata);
    } else {
        of << content;
    }
    of.close();
    return;
}

void FileSys::CleanDir(const std::string& dir) {
    DIR* theFolder = opendir(dir.c_str());
    if (!theFolder) {
        return;
    }
    struct dirent* next_file;
    char filepath[1024];

    while ((next_file = readdir(theFolder)) != NULL) {
        sprintf(filepath, "%s/%s", dir.c_str(), next_file->d_name);
        remove(filepath);
    }
    closedir(theFolder);
}

void FileSys::MkDir(const std::string& dir) {
    std::string command = std::string("mkdir ") + dir;
    const int dir_err = system(command.c_str());
}

void FileSys::Remove(const std::string& path) {
    std::string command = std::string("rm -rf ") + path;
    const int dir_err = system(command.c_str());
    if (-1 == dir_err) {
        printf("Error creating directory!n");
    }
}

bool FileSys::FileNameEndWith(const std::string& fileName, const std::string& ext) { return jf::Utils::EndsWith(fileName, ext); }

std::string FileSys::ChoosePath(const std::vector<std::string>& dirs, const std::string& subPath) {
    for (auto& dir : dirs) {
        std::string fullPath = dir + subPath;
        if (Exist(fullPath)) {
            return fullPath;
        }
    }

    // jf_log_error("assert false : cannot find file in any dirs: {}", subPath);
    return "";
}

bool FileSys::Exist(const std::string& fullPath) {
    struct stat buffer;
    return (stat(fullPath.c_str(), &buffer) == 0);
}