#include "windowspath.hpp"

#if defined(_WIN32) || defined(__WINDOWS__)

#include <cstring>

#define FAR
#define NEAR

#include <shlobj.h>
#include <shlwapi.h>
#include <winreg.h>

#undef NEAR
#undef FAR

#include <boost/locale.hpp>
namespace bconv = boost::locale::conv;

#include <components/debug/debuglog.hpp>

/**
 * \namespace Files
 */
namespace Files
{

WindowsPath::WindowsPath(const std::string& application_name)
    : mName(application_name)
{
    std::error_code ec;
    current_path(getLocalPath(), ec);
    if (ec.value() != 0)
        Log(Debug::Warning) << "Error " << ec.value() << " when changing current directory";
}

std::filesystem::path WindowsPath::getUserConfigPath() const
{
    std::filesystem::path userPath = std::filesystem::current_path();

    WCHAR path[MAX_PATH + 1] = {};

    if(SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, nullptr, 0, path)))
    {
        userPath = std::filesystem::path(path);
    }

    return userPath / "My Games" / mName;
}

std::filesystem::path WindowsPath::getUserDataPath() const
{
    // Have some chaos, windows people!
    return getUserConfigPath();
}

std::filesystem::path WindowsPath::getGlobalConfigPath() const
{
    std::filesystem::path globalPath = std::filesystem::current_path();

    WCHAR path[MAX_PATH + 1] = {};

    if(SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_PROGRAM_FILES | CSIDL_FLAG_CREATE, nullptr, 0, path)))
    {
        globalPath = std::filesystem::path(path);
    }

    return globalPath / mName;
}

std::filesystem::path WindowsPath::getLocalPath() const
{
    std::filesystem::path localPath = std::filesystem::current_path();

    WCHAR path[MAX_PATH + 1] = {};

    if (GetModuleFileNameW(nullptr, path, MAX_PATH + 1) > 0)
    {
        localPath = std::filesystem::path(path).parent_path();
    }

    // lookup exe path
    return localPath;
}

std::filesystem::path WindowsPath::getGlobalDataPath() const
{
    return getGlobalConfigPath();
}

std::filesystem::path WindowsPath::getCachePath() const
{
    return getUserConfigPath() / "cache";
}

std::filesystem::path WindowsPath::getInstallPath() const
{
    std::filesystem::path installPath{};

    if (HKEY hKey; RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Bethesda Softworks\\Morrowind", 0, KEY_READ | KEY_WOW64_32KEY, &hKey) == ERROR_SUCCESS)
    {
        //Key existed, let's try to read the install dir
        std::array<wchar_t, 512> buf{};
        DWORD len = buf.size() * sizeof(wchar_t);

        if (RegQueryValueExW(hKey, L"Installed Path", nullptr, nullptr, reinterpret_cast<LPBYTE>(buf.data()), &len) == ERROR_SUCCESS)
        {
            installPath = std::filesystem::path (buf.data());
        }
        RegCloseKey(hKey);
    }

    return installPath;
}

} /* namespace Files */

#endif /* defined(_WIN32) || defined(__WINDOWS__) */