//
// Created by Ht on 9/16/20.
//

#ifndef JVDALUNIT_LFILEUTILS_H
#define JVDALUNIT_LFILEUTILS_H

#include <qlibc/FileUtils.h>
#ifdef WIN32
#include <direct.h>
#include <io.h>
#else
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include <iostream>
#include <qlibc/qlibc.h>
#include <string>
using namespace std;

namespace jedge{
    class JE_API LFileUtils: FileUtils {
    public:
        /**创建多级目录
         *
         * @param dirName
         * @return
         */
        static  bool createDirs(const std::string& dirName){

            uint32_t beginCmpPath = 0;
            uint32_t endCmpPath = 0;

            std::string fullPath = "";

            QLog("path = %s\n", dirName.c_str());

            if('/' != dirName[0]){ //Relative path
                //get current path
                fullPath = SystemUtil::getCurrentPath();

                beginCmpPath = fullPath.size();

                QLog("current Path: %s\n", fullPath.c_str());
                fullPath = fullPath + "/" + dirName;
            }else{
                //Absolute path
                fullPath = dirName;
                beginCmpPath = 1;
            }

            if (fullPath[fullPath.size() - 1] != '/'){
                fullPath += "/";
            }

            endCmpPath = fullPath.size();
            //create dirs;
            for(uint32_t i = beginCmpPath; i < endCmpPath ; i++ ){
                if('/' == fullPath[i]){
                    std::string curPath = fullPath.substr(0, i);
                    if(access(curPath.c_str(), F_OK) != 0){
//                        if (mkdir(curPath.c_str(), S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH) != 0 ){
                        if ( mkdir(curPath.c_str(), S_IRWXG | S_IRWXU | S_IRWXO ) == 0 ){
                             chmod(curPath.c_str(),0777);
                        }else{
                             QLog("mkdir(%s) failed(%s)\n", curPath.c_str(), strerror(errno));
                             return false;
                        }
                    }
                }
            }

            return true;
        }
        //创建单级目录
        static bool makeDir(string &dir){
            if (0 != access(dir.c_str(), 0))
            {
#ifdef WIN32
                if (0 != mkdir(dir.c_str())){
                // balabala，创建失败！
                return false;
                }
#else
                if( mkdir(dir.c_str(),S_IRWXG | S_IRWXU | S_IRWXO ) != 0){
                    QLog("make directory(%s) failed! error:%s",dir.c_str(),strerror(errno));
                    return false;
                }
#endif
            }
            return true;
        }
        /**删除rootPath下的dirName指定的目录，支持多级目录
         * @param dirName
         * @param rootPath 参数必须是绝对路径
         * @return
         */
        static  bool removeDirs(const  string &rootPath,const std::string& dirName){
            QLog("dirName = %s\n", dirName.c_str());

            uint32_t beginCmpPath = 0;
            uint32_t endCmpPath = 0;

            std::string fullPath = rootPath;
            beginCmpPath = fullPath.size();

            if('/' != dirName[0]){
                fullPath = fullPath + "/" + dirName;
            }else{
                fullPath = fullPath + dirName;
            }

            if (fullPath[fullPath.size() - 1] != '/'){
                fullPath += "/";
            }
            QLog("fullPath Path: %s\n", fullPath.c_str());
            endCmpPath = fullPath.size();

            for(uint32_t i = endCmpPath; i >  beginCmpPath+1 ; i-- ){
                if('/' == fullPath[i]){
                    std::string curPath = fullPath.substr(0, i);
                    if ( remove(curPath.c_str()) == 0 ){
                        QLog("remove(%s) succeded\n", curPath.c_str());
                    }else{
                        QLog("remove(%s) failed(%s)\n", curPath.c_str(), strerror(errno));
                        return false;
                    }
                }
            }

            return true;
        }
        //清空dir下，指定以ext结尾的文件
        static bool emptyDir(const string& dir, const string& ext){
            vector<std::string> deviceFiles;
            int filecnt = FileUtils::listFiles(dir, ext, deviceFiles);
            for( int i = 0 ; i < filecnt ; i++ ){
                std::string filePath = deviceFiles.at(i);
                if( FileUtils::fileExists(filePath) )
                    LFileUtils::deleFile(filePath);

            }
            return true;
        }
        //删除单级目录
        static  bool removeDir(string &dir){
            bool  ret ;
            ret = remove(dir.c_str());
            if( ret != 0){
                QLog("remove directory(%s) failed! error:%s",dir.c_str(),strerror(errno));
                return false;
            }
            return  true;
        }
        //删除文件
        static bool deleFile(string& fileName){
            int ret = remove(fileName.c_str());
            if( ret != 0 ){
                QLog("delete (%s) failed(%s)\n", fileName.c_str(), strerror(errno));
                return false;
            }
            return true;

        }
        /**清空指定文件夹下的所有文件
         *
         * @param destDir 需清空文件夹的相对路径
         * @return
         */
#ifdef WIN32
        static int emptyDir(string destDir)
        {

            DIR *dp;
            struct dirent *entry;
            struct stat statbuf;
            string curPath = SystemUtil::getCurrentPath();
            if ((dp = opendir(destDir.c_str())) == NULL)
            {
                fprintf(stderr, "cannot open directory: %s\n", destDir.c_str());
                return -1;
            }
            chdir (destDir.c_str());
            while ((entry = readdir(dp)) != NULL)
            {
                lstat(entry->d_name, &statbuf);
                if (S_ISREG(statbuf.st_mode))
                {
                    remove(entry->d_name);
                }
            }
            //返回到当前工作路径
            opendir(curPath.c_str());
            return 0;
        }
#endif
        static  unsigned short crc16 (unsigned char *pD, int len)
        {

            static unsigned short poly[2]={0, 0xa001};              //0x8005 <==> 0xa001
            unsigned short crc = 0xffff;
            //unsigned char ds;
            int i,j;

            for(j=len; j>0; j--)
            {
                unsigned char ds = *pD++;
                for(i=0; i<8; i++)
                {
                    crc = (crc >> 1) ^ poly[(crc ^ ds ) & 1];
                    ds = ds >> 1;
                }
            }

            return crc;
        }
    };
}

#endif //JVDALUNIT_LFILEUTILS_H
