#include <sys/stat.h>
#ifndef _WIN32

#include <FileIO/FileIO.hpp>
#include <Utilities/Utilities.hpp>

FileIO::~FileIO()
{
    if (fd != -1)
    {
        ::close(fd);
    }
}

bool FileIO::create(std::string path)
{
#ifdef DEBUG_BUILD
    if (fd != -1)
    {
        crash("FileIO::create called when a file is already open!");
    }
#endif

    fd = ::open(path.c_str(), O_CREAT | O_EXCL | O_RDWR, 0600);
    if (fd == -1)
    {
        return false;
    }

    return true;
}

bool FileIO::open(std::string path)
{
#ifdef DEBUG_BUILD
    if (fd != -1)
    {
        crash("FileIO::open called when a file is already open!");
    }
#endif

    fd = ::open(path.c_str(), O_RDWR);
    if (fd == -1)
    {
        return false;
    }

    return true;
}

bool FileIO::lock()
{
#ifdef DEBUG_BUILD
    if (fd == -1)
    {
        crash("FileIO::lock called but no file is open!");
    }
#endif

    struct flock fl{};
    fl.l_type = F_WRLCK;
    fl.l_whence = SEEK_SET;
    fl.l_start = 0;
    fl.l_len = 0;
    fl.l_pid = getpid();

    return fcntl(fd, F_SETLK, &fl) != -1;
}

void FileIO::close()
{
    if (fd != -1)
    {
        ::close(fd);
    }

    fd = -1;
}

bool FileIO::read(size_t offset, void *data, size_t size)
{
    if (pread(fd, data, size, offset) != size)
    {
        return false;
    }

    return true;
}

bool FileIO::write(size_t offset, const void *data, size_t size)
{
    if (pwrite(fd, data, size, offset) != size)
    {
        return false;
    }

    return true;
}

bool FileIO::sync()
{
    return fsync(fd) == 0;
}

bool FileIO::isOpen()
{
    return fd != -1;
}

size_t FileIO::size()
{
    struct stat st{};
    if (fstat(fd, &st) != 0)
    {
        return 0;
    }

    return st.st_size;
}

#endif