/*
 * Copyright (C) 2009 - 2010 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */


#include "ClientAdapter/ClientAdapterStub.h"
#include "IFIFOWrapper.h"
#include "Logger/Logger.h"
#include "MessageDeserializer.h"
#include "MessageSerializer.h"
#include "common/Buffer.h"
#include "Message.h"
#include "GetCommand.h"
#include "SetCommand.h"
#include "SetMgmtTreeCommand.h"
#include "GetMgmtTreeCommand.h"
#include "Event.h"
#include "ManagementObjects/DevInfo.h"
#include "ManagementObjects/DevDetail.h"
#include "ManagementObjects/DMAcc.h"
#include "ManagementObjects/WiMAX.h"
#include "ManagementObjects/WiMAXSupp.h"
#include "ManagementObjects/WiMAX_Diagnostics.h"
#include "executionqueue/IExecutionQueue.h"
#include "RequestReceiverThread.h"
#include "RequestHandlingThread.h"
#include "CommonUtils.h"
#include "Utils.h"
#include "daemon/Configuration.h"
#include "daemon/Profile.h"
#include "NotificationStub.h"
#include "daemon/INotificationCenter.h"
#include "serverexchange/commands/ClientSessionCommand.h"
#include "serverexchange/commands/RequestFWUCommand.h"
#include "serverexchange/commands/HandleNetworkEntryCommand.h"
#include "serverexchange/commands/DRMDReadyNotificationCommand.h"
#include "DeviceAdapter/IDeviceAdapter.h"

static const char PARAMS_DELIMITER[] = "\n$DELIIM$\n";

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

namespace NS_DM_Client
{
	const unsigned long S_maxWaitForThreadFinished = 100000;
	//-------------------------------------------------------------------------------------------

	ClientAdapterStub::ClientAdapterStub(NS_Daemon::Configuration& configuration): m_receiver(0),
		m_configuration(configuration), m_componentHolder(0), m_inFIFOWrapper(0), m_outFIFOWrapper(0),
		m_logger(NS_Logging::GetLogger("ClientAdapterStub"))
	{
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::Init()
	{
		NS_Daemon::Profile* profile = m_configuration.GetProfile(0); // use "0" profile as default one
		if (!profile)
		{
			LOG_ERROR_(m_logger, "No profiles are available");
			return false;
		}
		m_componentHolder = profile->GetComponentsHolder();
		m_notification = new NotificationStub(*this);
		INotificationCenter* notificationCenter = m_componentHolder->GetNotificationCenter();
		notificationCenter->Subscribe(m_notification);
		LOG_(m_logger, "Notification is created and registered in NotificationCenter");

		bool res = CreateFIFOWrapperEx(m_inFIFOWrapper, S_outFifoName, true, true, true);
		if (!res)
		{
			LOG_ERROR_(m_logger, "Failed to create incoming fifo wrapper \"%s\"", S_outFifoName.c_str());
			return false;
		}
		res = CreateFIFOWrapperEx(m_outFIFOWrapper, S_inFifoName, false, true, true);
		if (!res)
		{
			LOG_ERROR_(m_logger, "Failed to create outgoing fifo wrapper \"%s\"", S_inFifoName.c_str());
			return false;
		}

		return res;
	}
	//-------------------------------------------------------------------------------------------

	ClientAdapterStub::~ClientAdapterStub()
	{
		bool res = m_receiver->wait(S_maxWaitForThreadFinished);
		if (!res)
		{
			LOG_WARNING_(m_logger, "Failed to wait while receiver thread is finished");
		}

		m_outFIFOWrapper->Release();
		m_inFIFOWrapper->Release();

		delete m_receiver;
		delete m_notification;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::Start()
	{
		m_stopReceiving = false;
		m_receiver = new RequestReceiverThread(*this);
		m_receiver->start();
		return true;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::restartFifos()
	{
		m_inFIFOWrapper->Release();
		m_outFIFOWrapper->Release();

		bool res = CreateFIFOWrapperEx(m_inFIFOWrapper, S_outFifoName, true, true, true);
		if (!res)
		{
			LOG_ERROR_(m_logger, "Failed to create incoming fifo wrapper \"%s\"", S_outFifoName.c_str());
			return false;
		}
		res = CreateFIFOWrapperEx(m_outFIFOWrapper, S_inFifoName, false, true, true);
		if (!res)
		{
			LOG_ERROR_(m_logger, "Failed to create outgoing fifo wrapper \"%s\"", S_inFifoName.c_str());
			return false;
		}

		return true;
	}
	//-------------------------------------------------------------------------------------------

	void ClientAdapterStub::receiveRequest()
	{
		// receive request
		LOG_(m_logger, "Waiting for request from ClientAdapterProxy...");

		bool res = true;
		while (!m_stopReceiving)
		{
			if (!res)
			{
				restartFifos();
			}
			Message* request = new Message();
			res = receiveRequest(*request);
			if(res)
			{
				if ((request->m_type == e_status) && (request->m_subType == e_stopWaitingStatus))
				{
					delete request;
					m_stopReceiving = true;
					return;
				}

				// create thread for handling requests and sending responses
				// it'll be freed in thread's function with the request
				RequestHandlingThread* handlingThread = new RequestHandlingThread(request, this);
				handlingThread->start();
			}
			else
			{
				LOG_ERROR_(m_logger, "Failed to receive request");
				delete request;
			}
		}
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::receiveRequest(Message& request)
	{
		Buffer buffer;
		bool res = ReadMessageFromFIFO(m_inFIFOWrapper, buffer, m_logger, m_criticalSection);
		if (!res)
		{
			LOG_WARNING_(m_logger, "Failed to read message from fifo \"%s\"", S_inFifoName.c_str());
		}
		else
		{
			if (buffer.Size() == 0)
			{
				LOG_WARNING_(m_logger, "Receive empty buffer from fifo");
				return false;
			}
			LOG_(m_logger, "Received request: buffer.size = %d", buffer.Size());
			MessageDeserializer deserilizer;
			deserilizer(buffer.GetPointer(), buffer.Size(), request);
			LOG_(m_logger, "Message id = %d, type = '%s', subtype = '%s'", request.m_id, S_msgTypeDescription[request.m_type],
				S_msgSubTypeDescription[request.m_subType]);
		}
		return res;
	}
	//-------------------------------------------------------------------------------------------

	void ClientAdapterStub::handleRequest(const Message& request)
	{
		Message response;
		bool res = handleRequest(request, response);
		if (!res)
		{
			LOG_ERROR_(m_logger, "Failed to handle request. Sending response with failed status");
			response.m_type = e_status;
			response.m_subType = e_failedStatus;
		}
		// send response
		res = sendResponse(response);
		if (!res)
		{
			LOG_ERROR_(m_logger, "Failed to send response");
			return;
		}

		if (request.m_type == e_close)
		{
			Message responseStopWaiting;
			responseStopWaiting.m_type = e_status;
			responseStopWaiting.m_subType = e_stopWaitingStatus;
			res = sendResponse(response);
			if (!res)
			{
				LOG_ERROR_(m_logger, "Failed to send response");
				return;
			}
		}
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleRequest(const Message& request, Message& response)
	{
		bool res = false;
		response.m_id = request.m_id;
		switch (request.m_type)
		{
		case e_open:
			res = handleOpenType(response);
			break;
		case e_close:
			res = handleCloseType(response);
			break;
		case e_get:
			if (request.m_subType == e_EMSK)
				res = handleGetEMSKType(request, response);
			else
				res = handleGetType(request, response);
			break;
		case e_set:
			if (request.m_subType == e_clientProfileName)
				res = handleClientProfileNameType(request, response);
			else if (request.m_subType == e_EMSK)
				res = handleSetEMSKType(request, response);
			else if (request.m_subType == e_DeviceID)
				res = handleSetDeviceIDType(request, response);
			else
				res = handleSetType(request, response);
			break;
 		case e_clientProfiles:
 			res = handleClientProfilesType(request, response);
 			break;
		case e_startDMSession:
			res = handleStartDMSessionType(request, response);
			break;
		case e_notifyDMSession:
			res = handleDMSessionNotifType(request, response);
			break;
		case e_checkFirmwareUpdate:
			res = handleCheckFirmwareUpdateType(request, response);
			break;
		case e_notifyFirmwareUpdate:
			res = handleFirmwareUpdateNotifType(request, response);
			break;
		case e_notifyProvisioningUpdate:
			res = handleProvisioningUpdateNotifType(request, response);
			break;
		case e_networkEntry:
			res = handleNetworkEntry(request, response);
			break;
		case e_collectDRMD:
			res = handleCollectDRMD(request, response);
			break;
		case e_readyDRMD:
			res = handleDRMDReady(request, response);
			break;
		default:
			LOG_WARNING_(m_logger, "Unknown request type %d", request.m_type);
			break;
		}
		return res;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleSetEMSKType(const Message& request, Message& response)
	{
		IDeviceAdapter* deviceAdapter = m_componentHolder->GetDeviceAdapter();
		size_t size = request.m_data.size();
		response.m_type = e_status;
		response.m_subType = e_okStatus;
		if (size == 0)
		{
			LOG_WARNING_(m_logger, "Attempt to set empty EMSK");
			return true;
		}
		bool res = deviceAdapter->SetEMSK(&request.m_data[0], size);
		if (res)
		{
			LOG_(m_logger, "EMSK was set");
		}
		else
		{
			LOG_(m_logger, "Failed to set EMSK");
			response.m_subType = e_failedStatus;
		}
		return res;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleGetEMSKType(const Message& request, Message& response)
	{
		return false;
/*
		IDeviceAdapter* deviceAdapter = m_componentHolder->GetDeviceAdapter();
		void* EMSKBuffer = 0;
		size_t size;
		bool res = deviceAdapter->GetEMSK(EMSKBuffer, size);

		if (res)
		{
			LOG_(m_logger, "GetEMSK return buffer of size = %d", size);
			response.m_type = e_EMSK;
			response.m_subType = e_none;
			response.SetData(EMSKBuffer, size);
		}

		return res;
*/

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

	bool ClientAdapterStub::handleSetDeviceIDType(const Message& request, Message& response)
	{
		IDeviceAdapter* deviceAdapter = m_componentHolder->GetDeviceAdapter();
		size_t size = request.m_data.size();
		response.m_type = e_status;
		response.m_subType = e_okStatus;
		if (size == 0)
		{
			LOG_WARNING_(m_logger, "Attempt to set empty DeviceID");
			return true;
		}
		bool res = deviceAdapter->SetDeviceID(&request.m_data[0], size);
		if (res)
		{
			LOG_(m_logger, "DeviceID was set");
		}
		else
		{
			LOG_(m_logger, "Failed to set DeviceID");
			response.m_subType = e_failedStatus;
		}
		return res;
	}
	//-------------------------------------------------------------------------------------------


	bool ClientAdapterStub::handleOpenType(Message& response)
	{
		LOG_(m_logger, "Received \"open\" request");
		response.m_type = e_status;
		response.m_subType = e_okStatus;
		m_stopReceiving = false;
		LOG_(m_logger, "Created \"status\" response");
		return true;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleCloseType(Message& response)
	{
		LOG_(m_logger, "Received \"close\" request");
		response.m_type = e_status;
		response.m_subType = e_okStatus;
		LOG_(m_logger, "Created \"status\" response");
		return true;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleClientProfileNameType(const Message& request, Message& response)
	{
		String profileName;
		BytesToString(request.m_data, profileName);
		response.m_type = e_status;
		NS_Daemon::Profile* profile = m_configuration.GetProfile(profileName);
		if (!profile)
		{
			LOG_ERROR_(m_logger, "No profile with name \"%s\" is available", profileName.c_str());
			return false;
		}
		// unsubscribe notifications
		INotificationCenter* notificationCenter = m_componentHolder->GetNotificationCenter();
		notificationCenter->Unsubscribe(m_notification);

		m_componentHolder = profile->GetComponentsHolder();
		LOG_(m_logger, "New profile is active. ProfileName = \"%s\"", profileName.c_str());

		// subscribe again
		notificationCenter = m_componentHolder->GetNotificationCenter();
		notificationCenter->Subscribe(m_notification);
		LOG_(m_logger, "Notification was resubscribed");

		response.m_subType = e_okStatus;
		return true;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleClientProfilesType(const Message& request, Message& response)
	{
		LOG_(m_logger, "Received \"GetClientProfiles\" request");
		int profilesCount = m_configuration.GetProfilesCount();
		LOG_(m_logger, "There are %d profiles available in configuration", profilesCount);
		response.m_type = e_clientProfiles;
		response.m_subType = e_none;
		StringToBytes(ToString(profilesCount), response.m_data);
		LOG_(m_logger, "Created \"GetClientProfilesCount\" response");
		return true;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleStartDMSessionType(const Message& request, Message& response)
	{
		LOG_(m_logger, "Received \"CheckProvision\" request");
		m_notification->Add(e_startDMSession, request.m_id);
		LOG_(m_logger, "Notification is added");

		NS_Communication::ClientSessionCommand* command = new NS_Communication::ClientSessionCommand(m_componentHolder);
		if (!command)
		{
			LOG_ERROR_(m_logger, "Failed to create ClientSessionCommand");
			return false;
		}
		LOG_(m_logger, "ClientSessionCommand is created");

		bool res = m_componentHolder->GetExecutionQueue()->Add(*command);
		if (res)
		{
			LOG_(m_logger, "ClientSessionCommand is added to execution queue");
			response.m_type = e_status;
			response.m_subType = e_okStatus;
		}
		else
		{
			LOG_ERROR_(m_logger, "Failed to add ClientSessionCommand to queue");
		}

		return res;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleDMSessionNotifType(const Message& request, Message& response)
	{
		LOG_(m_logger, "Received \"NotifyProvision\" request");
		m_notification->Add(e_notifyDMSession, request.m_id);
		LOG_(m_logger, "Notification is added");
		response.m_type = e_status;
		response.m_subType = e_okStatus;
		return true;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleCheckFirmwareUpdateType(const Message& request, Message& response)
	{
		LOG_(m_logger, "Received \"CheckFirmware\" request");
		m_notification->Add(e_checkFirmwareUpdate, request.m_id);
		LOG_(m_logger, "Notification is added");

		NS_Communication::RequestFWUCommand* command = new NS_Communication::RequestFWUCommand(*m_componentHolder);
		if (!command)
		{
			LOG_ERROR_(m_logger, "Failed to create RequestFWUCommand");
			return false;
		}
		LOG_(m_logger, "RequestFWUCommand is created");

		bool res = m_componentHolder->GetExecutionQueue()->Add(*command);
		if (res)
		{
			LOG_(m_logger, "RequestFWUCommand is added to execution queue");
			response.m_type = e_status;
			response.m_subType = e_okStatus;
		}
		else
		{
			LOG_ERROR_(m_logger, "Failed to add RequestFWUCommand to queue");
		}

		return res;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleFirmwareUpdateNotifType(const Message& request, Message& response)
	{
		LOG_(m_logger, "Received \"NotifyFirmware\" request");
		m_notification->Add(e_notifyFirmwareUpdate, request.m_id);
		LOG_(m_logger, "Notification is added");

		response.m_type = e_status;
		response.m_subType = e_okStatus;
		return true;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleProvisioningUpdateNotifType(const Message& request, Message& response)
	{
		LOG_(m_logger, "Received \"ProvisioningUpdateNotif\" request");
		m_notification->Add(e_notifyProvisioningUpdate, request.m_id);
		LOG_(m_logger, "Notification is added");

		response.m_type = e_status;
		response.m_subType = e_okStatus;
		return true;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleCollectDRMD(const Message& request, Message& response)
	{
		LOG_(m_logger, "Received \"ProvisioningUpdateNotif\" request");
		m_notification->Add(e_collectDRMD, request.m_id);
		LOG_(m_logger, "Notification is added");

		response.m_type = e_status;
		response.m_subType = e_okStatus;
		return true;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleGetType(const Message& request, Message& response)
	{
		LOG_(m_logger, "Received \"get\" request");
		IMgmtObject* mgmtObject = getMgmtObject(request.m_subType);
		const String subType(S_msgSubTypeDescription[request.m_subType]);
		bool res = false;
		if (!mgmtObject)
		{
			LOG_(m_logger, "Management object wasn't define");
			res = handleGetUnknownSubType(request, response);
		}
		else
		{
			LOG_(m_logger, "Type of Management object: %s", S_msgSubTypeDescription[request.m_subType]);
			res = handleGetKnownMgmtObject(*mgmtObject, request, response);
			delete mgmtObject;
		}
		return res;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleSetType(const Message& request, Message& response)
	{
		LOG_(m_logger, "Received \"set\" request");
		IMgmtObject* mgmtObject = getMgmtObject(request.m_subType);
		bool res = false;
		if (!mgmtObject)
		{
			LOG_(m_logger, "Management object wasn't define");
			res = handleSetUnknownSubType(request, response);
		}
		else
		{
			LOG_(m_logger, "Type of Management object: %s", S_msgSubTypeDescription[request.m_subType]);
			res = handleSetKnownMgmtObject(*mgmtObject, request, response);
			delete mgmtObject;
		}

		return res;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleSetKnownMgmtObject(IMgmtObject& mgmtObject, const Message& request, Message& response)
	{
		String xmlData;
		BytesToString(request.m_data, xmlData);
		bool res = mgmtObject.Deserialize(xmlData);
		if (!res)
		{
			LOG_ERROR_(m_logger, "Failed to deserialize message with data = %s", xmlData.c_str());
			return false;
		}
		NS_Common::EventEx executionCompleted;
		bool executionResult;
		IMOTreeCommand* setCommand = new SetCommand(m_componentHolder, &mgmtObject, &executionCompleted, executionResult);
		if (!setCommand)
		{
			LOG_ERROR_(m_logger, "Failed to create SetCommand");
			return false;
		}
		const String subType(S_msgSubTypeDescription[request.m_subType]);
		LOG_(m_logger, "SetCommand for \"%s\" is created", subType.c_str());
		res = m_componentHolder->GetExecutionQueue()->Add(*setCommand);
		if (res)
		{
			LOG_(m_logger, "SetCommand is added to execution queue. Waiting for execution completes...");
			executionCompleted.wait();
			LOG_(m_logger, "Execution completed. Result = %d", executionResult);
			// create response - as status result
			response.m_type = e_status;
			response.m_subType = (executionResult? e_okStatus: e_failedStatus);
			LOG_(m_logger, "Response status on SetDevInfo is created");
		}
		return res;
	}	
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleSetUnknownSubType(const Message& request, Message& response)
	{
		NS_Common::EventEx executionCompleted;
		bool executionResult;
		String data;
		BytesToString(request.m_data, data);
		IMOTreeCommand* setMgmtTreeCommand = new SetMgmtTreeCommand(m_componentHolder, data, &executionCompleted, executionResult);
		if (!setMgmtTreeCommand)
		{
			LOG_ERROR_(m_logger, "Failed to create SetMgmtTreeCommand");
			return false;
		}
		LOG_(m_logger, "SetMgmtTreeCommand is created");
		bool res = m_componentHolder->GetExecutionQueue()->Add(*setMgmtTreeCommand);
		if (res)
		{
			LOG_(m_logger, "SetMgmtTreeCommand is added to execution queue. Waiting for execution completes...");
			executionCompleted.wait();
			LOG_(m_logger, "Execution completed. Result = %d", executionResult);
			// create response - as status result
			response.m_type = e_status;
			response.m_subType = (executionResult? e_okStatus: e_failedStatus);
			LOG_(m_logger, "Response status on SetMgmtTree is created");
		}
		return res;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleGetKnownMgmtObject(IMgmtObject& mgmtObject, const Message& request, Message& response)
	{
		NS_Common::EventEx executionCompleted;
		bool executionResult;
		IMOTreeCommand* getCommand = new GetCommand(m_componentHolder, &mgmtObject, &executionCompleted, executionResult);
		if (!getCommand)
		{
			LOG_ERROR_(m_logger, "Failed to create GetCommand");
			return false;
		}
		const String subType(S_msgSubTypeDescription[request.m_subType]);
		LOG_(m_logger, "GetCommand for \"%s\" is created", subType.c_str());

		bool res = m_componentHolder->GetExecutionQueue()->Add(*getCommand);
		if (res)
		{
			LOG_(m_logger, "GetCommand is added to execution queue. Waiting for execution completes...");
			executionCompleted.wait();
			LOG_(m_logger, "Execution completed. Result = %d", executionResult);
			// create response
			String dataXml;
			if (executionResult)
			{
				mgmtObject.Serialize(dataXml);
			}
			response.m_type = e_get;
			response.m_subType = request.m_subType;
			StringToBytes(dataXml, response.m_data);
			LOG_(m_logger, "Response on Get for \"%s\" is created, xmlData = %s", subType.c_str(), dataXml.c_str());
		}
		else
		{
			LOG_ERROR_(m_logger, "Failed to add command to queue");
		}
		return res;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::handleGetUnknownSubType(const Message& request, Message& response)
	{
		NS_Common::EventEx executionCompleted;
		bool executionResult;
		String mgmtTree;
		String uri;
		BytesToString(request.m_data, uri);
		IMOTreeCommand* getCommand = new GetMgmtTreeCommand(m_componentHolder, uri, mgmtTree, &executionCompleted, executionResult);
		if (!getCommand)
		{
			LOG_ERROR_(m_logger, "Failed to create GetMgmtTreeCommand");
			return false;
		}
		LOG_(m_logger, "GetMgmtTreeCommand is created");

		bool res = m_componentHolder->GetExecutionQueue()->Add(*getCommand);
		if (res)
		{
			LOG_(m_logger, "GetMgmtTreeCommand is added to execution queue. Waiting for execution completes...");
			executionCompleted.wait();
			LOG_(m_logger, "Execution completed. Result = %d", executionResult);
			// create response
			String dataXml;
			if (executionResult)
			{
				response.m_type = e_get;
				response.m_subType = request.m_subType;
				StringToBytes(mgmtTree, response.m_data);
			}
			else
			{
				response.m_type = e_status;
				response.m_subType = e_failedStatus;
			}
			LOG_(m_logger, "Response on Get for uri \"%s\" is created, mgmtTree = %s", uri.c_str(), mgmtTree.c_str());
		}
		else
		{
			LOG_ERROR_(m_logger, "Failed to add command to queue");
		}
		return res;
	}
	//-------------------------------------------------------------------------------------------

	IMgmtObject* ClientAdapterStub::getMgmtObject(size_t subType)
	{
		IMgmtObject* mgmtObject = 0;
		switch (subType)
		{
		case e_devInfo:
			mgmtObject = new DevInfo();
			break;
		case e_devDetail:
			mgmtObject = new DevDetail();
			break;
		case e_DMAcc:
			mgmtObject = new DMAcc();
			break;
		case e_WiMAX:
			mgmtObject = new WiMAX();
			break;
		case e_WiMAXSupp:
			mgmtObject = new WiMAXSupp();
			break;
		case e_WiMAX_Diagnostics:
			mgmtObject = new NS_DM_Diagnostics::WiMAX_Diagnostics();
			break;
		default:
			break;
		}
		return mgmtObject;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::sendResponse(const Message& response)
	{
		bool res = false;
		if (response.m_type != e_clientProfiles)
		{
			res = sendResponseHelper(response);
		}
		else
		{
			res = sendClientProfilesResponse(response);
		}
		return res;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::sendResponseHelper(const Message& message)
	{
		LOG_DEBUG_(m_logger, "Message id=%d, type='%s', sybtype='%s'", 
			message.m_id, S_msgTypeDescription[message.m_type], S_msgSubTypeDescription[message.m_subType]);
		MessageSerializer serializer;
		const MessageSerializer::PlainData& data = serializer(message);
		if (data.empty())
		{
			LOG_ERROR_(m_logger, "Failed to serialize message");
			return false;
		}
		bool res = (m_outFIFOWrapper->Write(&data[0], data.size()) == e_Ok);
		if (!res)
		{
			LOG_ERROR_(m_logger, "Failed to write to fifo");
			return res;
		}
		LOG_(m_logger, "Message was sent to fifo. Plain data size = %d", data.size());
		return res;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::sendClientProfilesResponse(const Message& response)
	{
		// send first response with profiles' count and then - responses with profiles' info
		bool res = sendResponseHelper(response);
		if (!res)
		{
			return res;
		}
		int profilesCount;
		if (response.m_data.size() != 0)
			memcpy(&profilesCount, &(response.m_data[0]), sizeof(int));
		LOG_(m_logger, "Response \"GetOperatorProfilesCount\" with profile's count was sent");
		for (int i = 0; i != profilesCount; ++i)
		{
			String profileInfo(m_configuration.GetProfile(i)->GetName() +
				S_profileInfoSeperator + m_configuration.GetProfile(i)->GetDescription());
			Message profileInfoResponse(0, e_clientProfileName, e_none, profileInfo);
			res = sendResponseHelper(profileInfoResponse);
			if (!res)
			{
				return res;
			}
			LOG_(m_logger, "Response \"GetOperatorProfilesCount\" with profile's info was sent");
		}

		return res;
	}
	//-------------------------------------------------------------------------------------------

	bool ClientAdapterStub::stopRequestReceiverThread()
	{
		m_outFIFOWrapper->Close();

		IFIFOWrapper* stopRequestFIFO;

		bool res = CreateFIFOWrapperEx(stopRequestFIFO, S_outFifoName, false, false, false);
		if (!res)
		{
			LOG_ERROR_(m_logger, "Failed to create stop request fifo wrapper \"%s\"", S_outFifoName.c_str());
			return false;
		}

		Message stopRequest;
		stopRequest.m_type = e_status;
		stopRequest.m_subType = e_stopWaitingStatus;

		MessageSerializer serializer;
		const MessageSerializer::PlainData& data = serializer(stopRequest);
		if (data.empty())
		{
			LOG_ERROR_(m_logger, "Failed to serialize message");
			return false;
		}
		res = (stopRequestFIFO->Write(&data[0], data.size()) == e_Ok);
		if (!res)
		{
			m_outFIFOWrapper->Close();			
			LOG_ERROR_(m_logger, "Failed to write to fifo");
		}
		stopRequestFIFO->Release();
		return res;
	}

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

	bool ClientAdapterStub::Stop()
	{
		m_stopReceiving = true;
		stopRequestReceiverThread();
		m_notification->Clear();
		return true;
	}

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

	bool ClientAdapterStub::handleNetworkEntry(const Message& request, Message& response)
	{
		int homeNspID = 0;
		String data;
		BytesToString(request.m_data, data);
		LOG_DEBUG_(m_logger, "Data: '%s'", data.c_str());

		String::size_type pos = data.find(PARAMS_DELIMITER);
		if (pos != String::npos)
		{
			homeNspID = atoi(data.c_str());
		}

		String operatorName;
		operatorName = data.c_str() + pos + strlen(PARAMS_DELIMITER);

		ICommand* cmd = new HandleNetworkEntryCommand(*m_componentHolder, homeNspID, operatorName.c_str());
		if (cmd)
		{
			if (!m_componentHolder->GetExecutionQueue()->Add(*cmd))
			{
				LOG_ERROR_(m_logger, "Failed to add command %p to Q", cmd);
				delete cmd;
				cmd = NULL;
			}
		}

		response.m_type = e_status;
		response.m_subType = (cmd != NULL) ? e_okStatus : e_failedStatus;
		return cmd != NULL;
	}

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

	bool ClientAdapterStub::handleDRMDReady(const Message& request, Message& response)
	{
		ICommand* cmd = new DRMDReadyNotificationCommand(m_componentHolder);
		if (cmd)
		{
			if (!m_componentHolder->GetExecutionQueue()->Add(*cmd))
			{
				LOG_ERROR_(m_logger, "Failed to add command %p to Q", cmd);
				delete cmd;
				cmd = NULL;
			}
		}

		response.m_type = e_status;
		response.m_subType = (cmd != NULL) ? e_okStatus : e_failedStatus;
		return cmd != NULL;
	}
}
