#ifndef SENSE_API_MANAGER_H
#define SENSE_API_MANAGER_H

#include <config.h>
#include <memory>
#include <vector>
#include <string>
#include <optional>
#include <functional>
#include <componentThread.h>
#include <asynchronousLoop.h>
#include <senseApis/senseApiLib.h>
#include <user/deviceAttachmentSpec.h>

namespace smo {
namespace sense_api {

class SenseApiManager
{
public:
    static SenseApiManager& getInstance()
    {
        static SenseApiManager instance;
        return instance;
    }

	void initialize(void)
	{};
	void finalize(void)
	{};

    SenseApiLib& loadSenseApiLib(
		const std::string& libraryPath,
		const std::shared_ptr<ComponentThread>& componentThread);

    std::optional<std::shared_ptr<SenseApiLib>> getSenseApiLib(
        const std::string& libraryPath);
    std::optional<std::shared_ptr<SenseApiLib>> getSenseApiLibByApiName(
        const std::string& apiName);
    void unloadSenseApiLib(const std::string& libraryPath);

    void initializeSenseApiLib(SenseApiLib& lib);
    void finalizeSenseApiLib(SenseApiLib& lib);

    void loadAllSenseApiLibsFromOptions(
		const std::shared_ptr<ComponentThread>& componentThread);

    void unloadAllSenseApiLibs(void);
    void initializeAllSenseApiLibs(void);
    void finalizeAllSenseApiLibs(void);

	typedef sal_mlo_attachDeviceReqCbFn attachSenseDeviceReqCbFn;
	typedef sal_mlo_detachDeviceReqCbFn detachSenseDeviceReqCbFn;

	void attachSenseDeviceReq(
        const std::shared_ptr<device::DeviceAttachmentSpec>& spec,
        attachSenseDeviceReqCbFn cb);
    void detachSenseDeviceReq(
        const std::shared_ptr<device::DeviceAttachmentSpec>& spec,
        detachSenseDeviceReqCbFn cb);

	typedef std::function<void(AsynchronousLoop &results)>
		attachAllSenseDevicesFromSpecsReqCbFn;
	typedef std::function<void(AsynchronousLoop &results)>
		detachAllSenseDevicesReqCbFn;

	void attachAllSenseDevicesFromSpecsReq(
		attachAllSenseDevicesFromSpecsReqCbFn cb);
	void detachAllSenseDevicesReq(
		detachAllSenseDevicesReqCbFn cb);

    std::string stringifyLibs() const;

private:
    SenseApiManager() = default;
    ~SenseApiManager() = default;

    SenseApiManager(const SenseApiManager&) = delete;
    SenseApiManager& operator=(const SenseApiManager&) = delete;

    std::vector<std::shared_ptr<SenseApiLib>> senseApiLibs;

	class AttachSenseDeviceReq;
	class DetachSenseDeviceReq;
	class AttachAllSenseDevicesFromSpecsReq;
	class DetachAllSenseDevicesReq;

public:
    static std::optional<std::string> searchForLibInSmoSearchPaths(
        const std::string& libraryPath);
};

} // namespace sense_api
} // namespace smo

#endif // SENSE_API_MANAGER_H
