#include "jes/Path.h"
#include "jes/FileReader.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>

namespace jes
{
    Path::Path(const char * path)
    {
        m_path = path;
        clean();
    }

    Path::Path(const std::string & path)
    {
        m_path = path;
        clean();
    }

    PathRef Path::dirname()
    {
        if (m_path.size() == 0)
            return new Path("");
        size_t i = m_path.size() - 1;
        while (m_path[i] == '/')
        {
            if (i == 0)
                return new Path("/");
            i--;
        }
        while (m_path[i] != '/')
        {
            if (i == 0)
                return new Path(".");
            i--;
        }
        while (m_path[i] == '/')
        {
            if (i == 0)
                return new Path("/");
            i--;
        }
        return new Path(std::string(m_path, 0, i + 1));
    }

    PathRef Path::ext(const std::string & new_ext)
    {
        if (m_path.size() == 0)
            return new Path("");
        size_t i = m_path.size() - 1;
        while (m_path[i] != '.')
        {
            if ((i == 0) || (m_path[i] == '/'))
            {
                i = m_path.size();
                break;
            }
            i--;
        }
        if (new_ext.size() == 0)
        {
            return new Path(std::string(m_path, 0, i));
        }
        else if (new_ext[0] == '.')
        {
            return new Path(std::string(m_path, 0, i) + new_ext);
        }
        else
        {
            return new Path(std::string(m_path, 0, i) + "." + new_ext);
        }
    }

    PathRef Path::join(const Path & other)
    {
        if (m_path.size() > 0 && *m_path.rbegin() == '/')
            return new Path(m_path + other.m_path);
        else
            return new Path(m_path + '/' + other.m_path);
    }

    bool Path::exists()
    {
        struct stat st;
        return stat(m_path.c_str(), &st) == 0;
    }

    std::vector<std::string> Path::dir_entries()
    {
        std::vector<std::string> rv;
        DIR * dir = opendir(m_path.c_str());
        if (dir != NULL)
        {
            for (;;)
            {
                struct dirent * de = readdir(dir);
                if (de == NULL)
                    break;
                rv.push_back(std::string(de->d_name));
            }
            closedir(dir);
        }
        return rv;
    }

    bool Path::read(uint8_t ** buf, size_t * size)
    {
        return FileReader::load(m_path.c_str(), buf, size);
    }

    void Path::clean()
    {
        for (char & c : m_path)
        {
            if (c == '\\')
                c = '/';
        }
    }
}
