#include "NotificationStub.h"
#include "ClientAdapter/ClientAdapterStub.h"
#include "CommonUtils.h"
#include "ClientAdapter/INotificationUpdater.h"
#include "daemon/INotification.h"

#include "Logger/Logger.h"
#include "Logger/LoggerMacroses.h"
#include "Message.h"
#include "MessageSerializer.h"
#include "ClientAdapter/ProvisionInfo.h"
#include "common/Utils.h"

#include "common/lock.h"

using namespace NS_DM_Client::NS_Common;

namespace NS_DM_Client
{
	NotificationStub::NotificationStub(ClientAdapterStub& clientAdapterStub):
		m_clientAdapterStub(clientAdapterStub), m_provisionHolder(clientAdapterStub)
	{

	}
	//-------------------------------------------------------------------------------------------

	void NotificationStub::Add(MsgType notifType, size_t msgId)
	{
		Lock locker(m_containersSynch);

		RegisteredRequests::iterator found = m_registeredRequests.find(notifType);
		if (found == m_registeredRequests.end())
		{
			Requests requests;
			requests.push_back(msgId);
			m_registeredRequests[notifType] = requests;
		}
		else
		{
			found->second.push_back(msgId);
		}
	}
	//-------------------------------------------------------------------------------------------

	void NotificationStub::AddProvisioningUpdateType(size_t msgId, const ProvisionInfoRequest& provision)
	{
		Lock locker(m_containersSynch);

		m_provisionHolder.AddSubscriber(msgId, provision);
	}
	//-------------------------------------------------------------------------------------------

	void NotificationStub::DeleteProvisioningUpdateType()
	{
		Lock locker(m_containersSynch);

		m_provisionHolder.Clear();
	}
	//-------------------------------------------------------------------------------------------

	void NotificationStub::Delete(MsgType notifType)
	{
		Lock locker(m_containersSynch);

		RegisteredRequests::iterator found = m_registeredRequests.find(notifType);
		if (found != m_registeredRequests.end())
		{
			m_registeredRequests.erase(found);
		}
	}
	//-------------------------------------------------------------------------------------------

	void NotificationStub::Clear()
	{
		Lock locker(m_containersSynch);

		m_registeredRequests.clear();
		m_provisionHolder.Clear();
	}
	//-------------------------------------------------------------------------------------------

	void NotificationStub::sendResponse(MsgType msgType, MsgSubType subType, bool removeMsg, const String& data/* = ""*/)
	{
		NS_Logging::Logger& m_logger = NS_Logging::GetLogger("NotificationStub");
		LOG_DEBUG_(m_logger, "MsgType = %s, subtype = %s, removeMsg = %d, data = '%s'", 
			S_msgTypeDescription[msgType], S_msgSubTypeDescription[subType], removeMsg, data.c_str());

		Lock locker(m_containersSynch);

		RegisteredRequests::iterator found = m_registeredRequests.find(msgType);
		if (found == m_registeredRequests.end())
		{
			LOG_ERROR_(m_logger, "Msg is not found", msgType, subType, removeMsg, data.c_str());
			return;
		}

		Requests& requests = found->second;
		for (size_t i = 0; i != requests.size(); ++i)
		{
			Message response;
			response.m_id = requests[i];
			response.m_type = msgType;
			response.m_subType = subType;
			if (!data.empty())
			{
				StringToBytes(data, response.m_data);
			}
			if (removeMsg)
			{
				requests.erase(requests.begin() + i);
				--i;
			}
			LOG_DEBUG_(m_logger, "Sending response %d", i);
			m_clientAdapterStub.sendResponse(response);
		}
	}
	//-------------------------------------------------------------------------------------------

	void NotificationStub::ConfirmationRequired(const String& message)
	{
		sendResponse(e_confirmationRequired, e_none, false, message);
	}
	//-------------------------------------------------------------------------------------------

	void NotificationStub::NotifyDMSessionStatus(EventType eventType, Initiator initiator, NotificationStatus statusCode)
	{
		String data;
		SerializeDMSessionNotification(eventType, initiator, statusCode, data);
		sendResponse(e_notifyDMSession, e_none, false, data);
	}
	//-------------------------------------------------------------------------------------------

 	void NotificationStub::StartDMSessionStatus(bool isStarted)
 	{
		String data = isStarted? S_true: S_false;
		sendResponse(e_startDMSession, e_none, true, data);
	}
	//-------------------------------------------------------------------------------------------

	void NotificationStub::CheckFirmwareUpdateStatus(bool isNewFirmware)
	{
		String data = isNewFirmware? S_true: S_false;
		sendResponse(e_checkFirmwareUpdate, e_none, true, data);
	}
	//-------------------------------------------------------------------------------------------

	void NotificationStub::FirmwareInfo(const String& localpath, const String& filename, const int size)
	{
		String firmwareInfo;
		SerializeFirmwareInfo(localpath, filename, size, firmwareInfo);
		sendResponse(e_notifyFirmwareUpdate, e_FirmwareInfo, false, firmwareInfo);
	}
	//-------------------------------------------------------------------------------------------

	void NotificationStub::FirmwareUpdateStart(FirmwareUpdate::EnumFirmwareOperation fwo)
	{
		MsgSubType subType = s_mapFirmwareOperation(fwo);
		sendResponse(e_notifyFirmwareUpdate, subType, false, S_notificationStatusDescription[e_start]);
	}
	//-------------------------------------------------------------------------------------------

	void NotificationStub::FirmwareUpdateFinished(FirmwareUpdate::EnumFirmwareOperation fwo)
	{
		MsgSubType subType = s_mapFirmwareOperation(fwo);
		sendResponse(e_notifyFirmwareUpdate, subType, false, S_notificationStatusDescription[e_end]);
	}
	//-------------------------------------------------------------------------------------------

	MsgSubType NotificationStub::s_mapFirmwareOperation(FirmwareUpdate::EnumFirmwareOperation fwo)
	{
		MsgSubType subType = e_none;
		switch (fwo)
		{
		case FirmwareUpdate::e_Download:
			subType = e_FirmwareDownload;
			break;

		case FirmwareUpdate::e_Update:
			subType = e_FirmwareUpdate;
			break;

		case FirmwareUpdate::e_DownloadAndUpdate:
			subType = e_FirmwareDownloadAndUpdate;
			break;

		case FirmwareUpdate::e_Error:
			subType = e_none;
			break;
		}

		return subType;
	}
	//-------------------------------------------------------------------------------------------

	void NotificationStub::ProvisioningUpdate(const StringArray& URIs, CommandType command, EventType eventType, StatusCode resultCode)
	{
		if (URIs.empty())
			return;
		ProvisionInfoResponse provisionResponse(URIs, command, eventType, resultCode);

		Lock locker(m_containersSynch);
		m_provisionHolder.NotifySubscribers(provisionResponse);
	}
	//-------------------------------------------------------------------------------------------

	void NotificationStub::StartDRMDCollecting(int duration)
	{
		String data = ToString(duration);
		NS_Logging::Logger& m_logger = NS_Logging::GetLogger("NotificationStub");
		LOG_DEBUG_(m_logger, "Duration = '%s'", data.c_str());
		sendResponse(e_collectDRMD, e_none, false, data);
	}
	//-------------------------------------------------------------------------------------------

}

