#include "ProvisionHolder.h"
#include "daemon/INotification.h"
#include "ClientAdapter/ProvisionInfo.h"
#include "Message.h"
#include "ClientAdapter/ClientAdapterStub.h"

namespace NS_DM_Client
{
	const char* S_eventTypeDescription[] = 
	{
		"Start",
		"Processing",
		"End"
	};

	const char* S_commandSubTypeDescription[] = 
	{
		"Add",
		"Delete",
		"Replace",
		"Get",
		"Exec",
		"Atomic",
		"Sequence"
	};

	CommandType operator++(CommandType &command, int) 
	{
		return command = (CommandType)((int)command * 2);
	}

	EventType operator++(EventType &eventType, int) 
	{
		return eventType = (EventType)((int)eventType * 2);
	}

	//-------------------------------------------------------------------------------------------

	ProvisionSubscribersHolder::ProvisionSubscribersHolder(ClientAdapterStub& clientAdapterStub): 
	m_clientAdapterStub(clientAdapterStub), m_logger(NS_Logging::GetLogger(ClientAdapterStub::S_LoggerName))
	{

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

	void ProvisionSubscribersHolder::Clear()
	{
		m_registeredRequests.clear();
	}
	//-------------------------------------------------------------------------------------------

	void ProvisionSubscribersHolder::AddSubscriber(int msgId, const ProvisionInfoRequest& provision)
	{
		for (CommandType cmdType = e_Add; cmdType <= e_Sequence; cmdType++)
		{
			CommandType curCommand = (CommandType)(provision.m_commands & (int)cmdType);
			if (curCommand != cmdType)
				continue;

			for (EventType eventType = e_sessionStart; eventType <= e_sessionEnd; eventType++)
			{
				EventType curEvent = (EventType)(provision.m_events & (int)eventType);
				if (curEvent != eventType)
					continue;

				ProvisionInfo curProvision = {msgId, provision.m_monitorChildren, curCommand, curEvent};
				RegisteredRequests::iterator found = m_registeredRequests.find(provision.m_URI);
				if (found == m_registeredRequests.end())
				{
					Requests requests;
					requests.push_back(curProvision);
					m_registeredRequests[provision.m_URI] = requests;
				}
				else
				{
					found->second.push_back(curProvision);
				}
			}
		}
	}
	//-------------------------------------------------------------------------------------------

	void ProvisionSubscribersHolder::NotifySubscribers(const ProvisionInfoResponse& provision)
	{
		SortedURIs URIs;
		sortURIs(URIs, provision.m_URIs);

		SortedURIs::const_iterator end(URIs.end());
		for (SortedURIs::const_iterator iter = URIs.begin(); iter != end; ++iter)
		{
			RegisteredRequests::iterator found = m_registeredRequests.find(iter->first);
			Requests& requests = found->second;
			for (size_t i = 0; i != requests.size(); ++i)
			{
				ProvisionInfo curProvision = requests[i];
				if (curProvision.m_command == provision.m_command && curProvision.m_event == provision.m_event)
				{
					Message response;
					response.m_id = curProvision.m_msgId;
					response.m_type = e_notifyProvisioningUpdate;
					response.m_subType = e_none;
					String strProvision;
					ProvisionInfoResponse curProvisionResponse(iter->second, provision.m_command, provision.m_event, provision.m_statusCode);
					curProvisionResponse.Serialize(strProvision);
					if (!strProvision.empty())
					{
						StringToBytes(strProvision, response.m_data);
					}
					m_clientAdapterStub.sendResponse(response);
					LOG_DEBUG_(m_logger, "Response was sent");
				}
			}
		}
	}
	//-------------------------------------------------------------------------------------------

	void ProvisionSubscribersHolder::sortURIs(SortedURIs& sortedURIs, const StringArray& URIs)
	{
		RegisteredRequests::iterator end(m_registeredRequests.end());
		for (RegisteredRequests::iterator iter = m_registeredRequests.begin(); iter != end; ++iter)
		{
			for (size_t i = 0; i != URIs.size(); ++i)
			{
				String URI(URIs[i]);
				SortedURIs::iterator found = sortedURIs.find(URI);
				if (isParentNode(iter->first, URI))
				{
					if (!isMonitorChildren(iter) && iter->first != URI)
					{
						continue;
					}
					if (found != sortedURIs.end())
					{
						found->second.push_back(URI);
					}
					else
					{
						StringArray tmpURIs;
						tmpURIs.push_back(URI);
						sortedURIs[iter->first] = tmpURIs;
					}
				}
			}
		}
	}
	//-------------------------------------------------------------------------------------------

	bool ProvisionSubscribersHolder::isMonitorChildren(RegisteredRequests::iterator request)
	{
		Requests requests = request->second;
		for (size_t i = 0; i != requests.size(); ++i)
		{
			if (requests[i].m_monitorChildren)
			{
				return true;
			}
		}
		return false;
	}
	//-------------------------------------------------------------------------------------------

	bool ProvisionSubscribersHolder::isParentNode(const String& parent, const String& child)
	{
		size_t found = child.find(parent);
		return found == 0;
	}
	//-------------------------------------------------------------------------------------------
}