#include "VrFileUtils.h"
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <fstream>
#include <sys/stat.h>
#include <cstdio>
#include <cstring>

#ifdef _WIN32
#include <Windows.h>
#include <direct.h> 
#include <io.h>
#else
#include <unistd.h>
#endif

bool CVrFileUtils::IsFileExist(const char* pFileName)
{
    std::ifstream in(pFileName);
    return in.good();
}

size_t CVrFileUtils::GetFileSize(const char* fileName)
{
    std::ifstream in(fileName);
    in.seekg(0, std::ios::end);
    size_t size = in.tellg();
    in.close();
    return (int)size;
}

bool CVrFileUtils::WriteFileData(const char* pFileName, const char* pData, const size_t nLen, bool isAppend)
{
    if(!pFileName || !pData)
        return false;
        
    bool bRet = false;
    std::ofstream fStream;
    std::ios_base::openmode nMode = std::ios::binary;
    if(isAppend)
    {
        nMode = nMode | std::ios::app;
    }

    fStream.open(pFileName, nMode);

    bRet = fStream.good();

    if(bRet)
    {
        fStream.write(pData, nLen);
        fStream.flush();
    }
    fStream.close();
#ifndef _WIN32
	sync();
#endif
    return bRet;
}

bool CVrFileUtils::ReadFileData(const char* pFileName, char* pData, size_t* pLen, const int nOffset)
{
    if(!pFileName)
        return false;

    int nFileSize = GetFileSize(pFileName);
    if(nOffset >= nFileSize)
    {
        return false;
    }
    
    if(nFileSize - nOffset < *pLen)
    {
        *pLen = nFileSize - nOffset;
    }

    std::ifstream iStream(pFileName, std::ios::binary);
    iStream.seekg(nOffset);
    iStream.read(pData, *pLen);
    iStream.close();
    return true;
}

bool CVrFileUtils::GetFileList(std::string& pDirPath, std::string exd, std::vector<std::string>& vetFiles)
{
#ifdef _WIN32
	//文件句柄
	intptr_t hFile = 0;
	//文件信息
	struct _finddata_t fileinfo;
	std::string pathName, exdName;

	if (0 != strcmp(exd.c_str(), ""))
	{
		exdName = "\\*." + exd;
	}
	else
	{
		exdName = "\\*";
	}

	if ((hFile = _findfirst(pathName.assign(pDirPath).append(exdName).c_str(), &fileinfo)) != -1)
	{
		do
		{
			//如果是文件夹中仍有文件夹,迭代之
			//如果不是,加入列表
			if ((fileinfo.attrib & _A_SUBDIR))
			{
                if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
                {
                    std::string sFilePath = pathName.assign(pDirPath).append("\\").append(fileinfo.name);
                    GetFileList(sFilePath, exd, vetFiles);
                }
					
			}
			else
			{
				if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
					vetFiles.push_back(pathName.assign(pDirPath).append("\\").append(fileinfo.name));
			}
		} while (_findnext(hFile, &fileinfo) == 0);
		_findclose(hFile);
	}
#endif
	return true;
}

/// 获取目录下所有目录
bool CVrFileUtils::GetDirList(std::string& pDirPath, std::vector<std::string>& vetFiles)
{
#if 0
    // 打开目录
    DIR* dir = opendir(pDirPath.c_str());
    if (dir == nullptr) {
        std::cerr << "Unable to open directory: " << pDirPath << std::endl;
        return false;
    }

    struct dirent* entry;
    while ((entry = readdir(dir)) != nullptr) {
        const std::string name = entry->d_name;

        // 排除 "." 和 ".."
        if (name != "." && name != "..") {
            const std::string full_path = pDirPath + "/" + name;
            struct stat info;
            if (stat(full_path.c_str(), &info) == 0) {
                if (S_ISDIR(info.st_mode)) {
                    subdirs.push_back(full_path);  // 如果是目录，则保存路径
                }
            }
        }
    }

    closedir(dir);  // 关闭目录流
#endif
    return true;
}

bool CVrFileUtils::ReNameFile(const char* oldName, const char* newName)
{
	if (!IsFileExist(oldName)) return false;
	return 0 == rename(oldName, newName);
}

bool CVrFileUtils::DeleteLocalFile(const char* sFileName)
{
	if (!IsFileExist(sFileName)) return false;
	return 0 == remove(sFileName);
}

/// 目录是否存在
bool CVrFileUtils::IsDirExist(const char* szDirectory)
{
	if (nullptr == szDirectory)
	{
		return false;
	}

	struct stat sStat;
	memset(&sStat, 0, sizeof(struct stat));
	if (0 != stat(szDirectory, &sStat))
		return false;
	return true;
}


bool _CreateDirs(const std::string& path) {
    // 检查目录是否已经存在
    struct stat info;
    if (stat(path.c_str(), &info) == 0 && (info.st_mode & S_IFDIR)) 
    {
        return true;
    }

    // 递归创建父目录
#ifdef _WIN32
    size_t pos = path.find_last_of('\\');
#else
    size_t pos = path.find_last_of('/');
#endif // _WIN32

    if (pos != std::string::npos) {
        std::string parent_path = path.substr(0, pos);
        if (!_CreateDirs(parent_path)) {
            return false;
        }
    }

    // 创建当前目录
#ifdef _WIN32
    int nMkdirRet = mkdir(path.c_str());
#else
    int nMkdirRet = mkdir(path.c_str(), 0777);
#endif // __WIN32
    if (nMkdirRet == -1) {
        perror("mkdir");
        return false;
    }
    return true;
}


bool _DeleteDirs(const std::string& path) 
{
    // 检查目录是否已经存在
    struct stat info;
    if (stat(path.c_str(), &info) == 0 && (info.st_mode & S_IFDIR))
    {
        std::cout << "Directory already exists: " << path << std::endl;
        return true;
    }
    int nRet = rmdir(path.c_str());
    return 0 == nRet;
}


/// 创建新的文件夹
bool CVrFileUtils::CreatNewDir(const char* szPath)
{
    return _CreateDirs(szPath);
}

/// 删除目录
bool CVrFileUtils::DeleteDir(const char* szDirPath)
{
	return _DeleteDirs(szDirPath);
}

/// 去除后缀获取文件名称
std::string CVrFileUtils::GetFileName(const std::string& filePath, bool bHasSuffix)
{
	// 获取最后一个斜杠或反斜杠的位置
	size_t slashIndex = filePath.find_last_of("/\\");

	// 获取文件名（包含扩展名）
	std::string fileName = (slashIndex != std::string::npos) ? filePath.substr(slashIndex + 1) : filePath;

    if(!bHasSuffix)
    {
        // 查找最后一个点的位置
        size_t dotIndex = fileName.find_last_of(".");

        // 去除扩展名
        if (dotIndex != std::string::npos) {
            fileName = fileName.substr(0, dotIndex);
        }
    }

	return fileName;
}

