/*
	PluginFramework
	by John Ryland
	Copyright (c) 2023
*/

////////////////////////////////////////////////////////////////////////////////////
//	Library

#include "Library.h"

#ifdef _WIN32
#  define WIN32_LEAN_AND_MEAN
#  include <windows.h>
#else //UNIX
#  include <dlfcn.h>
#endif

namespace PluginFramework {

Library::Library(const char* fileName, Handle libraryHandle)
    : mLibraryHandle(libraryHandle)
    , mLibraryFileName(fileName)
{
}

Library::~Library()
{
    if (Loaded())
        Unload();
}

// static
LibraryPtr Library::Load(const char* libraryFileName)
{
#ifdef _WIN32
    void *osHandle = reinterpret_cast<void*>(LoadLibraryA(libraryFileName));
#else
    dlerror(); // clear errors
    void *osHandle = dlopen(libraryFileName, RTLD_NOW); // LAZY can help debug some issues - allows it to load
    if (!osHandle)
        printf("Error loading library %s:\n\n%s\n", libraryFileName, dlerror());
#endif
    return std::make_unique<Library>(libraryFileName, Handle{osHandle});
}

void Library::Unload()
{
#ifdef _WIN32
    FreeLibrary(HMODULE(mLibraryHandle.mOSHandle));
#else
    dlclose(mLibraryHandle.mOSHandle);
#endif
    mLibraryHandle.mOSHandle = nullptr;
}

bool Library::Loaded() const
{
    return mLibraryHandle.mOSHandle != nullptr;
}

std::string Library::FileName() const
{
    return mLibraryFileName;
}

void* Library::GetFunctionAddress(const char* functionName) const
{
    if (Loaded())
    {
#ifdef _WIN32
        return reinterpret_cast<void*>(GetProcAddress(HMODULE(mLibraryHandle.mOSHandle), LPCSTR(functionName)));
#else
        return dlsym(mLibraryHandle.mOSHandle, functionName);
#endif
    }
    return nullptr;
}

} // PluginFramework namespace
