#ifndef DEVICEMANAGER_H
#define DEVICEMANAGER_H

#include <vector>
#include <string>
#include <memory>
#include <opts.h>
#include <utility>
#include <iostream>
#include <user/senseApiDesc.h>
#include <user/deviceAttachmentSpec.h>
#include <deviceManager/device.h>
#include <deviceManager/deviceRole.h>
#include <deviceManager/deviceReattacher.h>
#include <marionette/marionetteThread.h>
#include <spinscale/multiOperationResultSet.h>
#include <spinscale/co/coQutex.h>
#include <spinscale/sharedResourceGroup.h>

namespace smo {
namespace device {

class DeviceReattacher;

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

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

	void initializeDeviceReattacher();
	void finalizeDeviceReattacher();

	std::string readDapSpecFile(const std::string& filename);
	void collateAllDapSpecs(void);
	void parseAllDapSpecs(void);

	static const std::string stringifyDeviceSpecs(void);

	mrntt::MrnttViralPostingInvoker<std::shared_ptr<DeviceRole>>
	newDeviceAttachmentSpecIndCReq(const DeviceAttachmentSpec &spec);

	mrntt::MrnttViralPostingInvoker<void>
	removeDeviceAttachmentSpecCReq(const DeviceAttachmentSpec &spec);

	mrntt::MrnttViralPostingInvoker<void>
	attachStimBuffDeviceCReq(
		const std::shared_ptr<DeviceAttachmentSpec>& spec);

	mrntt::MrnttViralPostingInvoker<void>
	detachStimBuffDeviceCReq(
		const std::shared_ptr<DeviceAttachmentSpec>& spec);

	mrntt::MrnttViralPostingInvoker<void>
	attachAllUnattachedDevicesFromKnownListCReq();

	mrntt::MrnttViralPostingInvoker<void>
	attachAllUnattachedDevicesFromCmdlineCReq();

	mrntt::MrnttViralPostingInvoker<void>
	detachAllAttachedDeviceRolesCReq();

private:
	DeviceManager()
	: s("DeviceManager")
	{}

	~DeviceManager();
	DeviceManager(const DeviceManager&) = delete;
	DeviceManager& operator=(const DeviceManager&) = delete;

	mrntt::MrnttViralPostingInvoker<sscl::MultiOperationResultSetWithException>
	attachAllUnattachedDevicesFromCReq(
		const std::shared_ptr<std::vector<DeviceAttachmentSpec>> &specs);

public:
	struct Resources
	{
		std::vector<std::shared_ptr<DeviceAttachmentSpec>> deviceAttachmentSpecs;
		std::vector<std::shared_ptr<Device>> devices;
		std::vector<std::shared_ptr<DeviceRole>> attachedDeviceRoles;
		std::vector<DeviceAttachmentSpec> commandLineDASpecs;
		std::string allDapSpecs;
	};
	sscl::SharedResourceGroup<sscl::co::CoQutex, Resources> s;

private:
	std::unique_ptr<DeviceReattacher> deviceReattacher;
};

} // namespace device
} // namespace smo

#endif // DEVICEMANAGER_H
