/*!
    \file
    \copyright  (c) 2015 Jascha Wetzel. All rights reserved.
 */

#include "api/client.h"
#include "api/base.h"

#ifdef _WIN32
#include <Windows.h>
#elif defined(__APPLE__) || defined(__linux__)
#include <dlfcn.h>
#endif

#include <iostream>

namespace tfd {
namespace api {

static void* (*create_instance_ptr_)(unsigned int) = nullptr;

static void print_error()
{
#ifdef _WIN32

    LPVOID
        lpMsgBuf = nullptr;
    DWORD
        dw = GetLastError(),
        char_cnt = FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            nullptr, dw,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPTSTR)&lpMsgBuf,
            0, nullptr
        );
    if ( char_cnt > 0 )
        std::cerr << (const char*)lpMsgBuf;
    else
        std::cerr << "GetLastError " << dw;
    std::cerr << std::endl;
    LocalFree(lpMsgBuf);

#elif defined(__APPLE__) || defined(__linux__)

    std::cerr << dlerror() << std::endl;

#endif
}

bool load_library(const std::string& file_path)
{
    if ( !create_instance_ptr_ )
    {
#ifdef _WIN32

        auto lib = LoadLibraryA(file_path.c_str());
        if ( lib )
            *reinterpret_cast<FARPROC*>(&create_instance_ptr_) = GetProcAddress(lib, "create_instance");
        else
            print_error();

#elif defined(__APPLE__) || defined(__linux__)

        auto lib = dlopen(file_path.c_str(), RTLD_LOCAL);
        if ( lib )
            *reinterpret_cast<void**>(&create_instance_ptr_) = dlsym(lib, "create_instance");
        else
            print_error();

#else
#error unsupported platform
#endif
    }

    return create_instance_ptr_ != nullptr;
}

uint32_t get_server_version()
{
    auto server_version = api::create_shared_instance<api::ServerVersion>();
    if ( server_version )
        return server_version->version();
    return 0u;
}

void* create_instance(unsigned int iface)
{
    if ( create_instance_ptr_ )
        return create_instance_ptr_(iface);
    return nullptr;
}

} // namespace api
} // namespace tfd
