#include <config.h>
#include <iostream>
#include <functional>
#include <componentThread.h>
#include <callback.h>
#include <deviceManager/deviceReattacher.h>
#include <deviceManager/deviceManager.h>

namespace smo {
namespace device {

static void reattachmentCb(AsynchronousLoop& results)
{
	if (results.nTotal == 0) { return; }

	std::cout << "DeviceReattacher: Successfully reattached "
		<< results.nSucceeded << " of " << results.nTotal << " devices"
		<< std::endl;
}

DeviceReattacher::DeviceReattacher(
	DeviceManager& parent, std::shared_ptr<ComponentThread> ioThread)
: parent(parent), ioThread(ioThread), shouldContinue(false),
timer(ioThread->getIoService())
{
}

void DeviceReattacher::start()
{
	shouldContinue.store(true);
	scheduleNextTimeout();
}

void DeviceReattacher::stop()
{
	shouldContinue.store(false);
	timer.cancel();
}

void DeviceReattacher::scheduleNextTimeout()
{
	if (!shouldContinue.load()) {
		return;
	}

	// Schedule the next timeout using the configured period
	timer.expires_from_now(
		boost::posix_time::milliseconds(
			CONFIG_MRNTT_DEVMGR_REATTACHER_PERIOD_MS));

	timer.async_wait(
		std::bind(&DeviceReattacher::onTimeout, this, std::placeholders::_1));
}

void DeviceReattacher::onTimeout(const boost::system::error_code& error)
{
	// Timer was cancelled, which is expected when stopping
	if (error == boost::asio::error::operation_aborted) {
		return;
	}

	if (error)
	{
		std::cerr << "DeviceReattacher: Timer error: " << error.message()
			<< std::endl;
		return;
	}

	if (!shouldContinue.load()) {
		return;
	}

	// Attempt to reattach all unattached devices from the known list
	parent.attachAllUnattachedDevicesFromKnownListReq(
		{ nullptr, reattachmentCb});

	// Schedule the next timeout
	scheduleNextTimeout();
}

} // namespace device
} // namespace smo
