#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 "ClientAdapter/ProvisionInfo.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 "serverexchange/commands/StartBootstrapCommand.h"
#include "serverexchange/commands/TriggerDRMDCollectingCommand.h"
#include "ProfileActivationStatusCommand.h"
#include "ProfileActivationStatusByServerIDCommand.h"
#include "DeviceAdapter/IDeviceAdapter.h"
#include "UIRequestHandler.h"
#include "treemanager/ChangePasswordCommand.h"
#include "treemanager/ChangePasswordByServerIDCommand.h"

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

static const char c_SubscribeUserInterfaceConfParam[]   = "SubscribeUserInterface";

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

namespace NS_DM_Client
{
    const unsigned long S_maxWaitForThreadFinished = 100000;
    const char* ClientAdapterStub::S_LoggerName("ClientAdapterStub");

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

    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(S_LoggerName)), m_uiRequestHandler(0)
    {
    }
    //-------------------------------------------------------------------------------------------

    bool ClientAdapterStub::Init(const StringMap& settings)
    {
        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(std::nothrow) NotificationStub(*this);
        if(m_notification == NULL) LOG_WARNING_(m_logger, "new NotificationStub");

        INotificationCenter* notificationCenter = m_componentHolder->GetNotificationCenter();
        notificationCenter->Subscribe(m_notification);
        LOG_INFO_(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;
        }

        if (needUserInterfaceSubscriber(settings))
        {
            m_uiRequestHandler = new(std::nothrow) UIRequestHandler(*this);
            if(m_uiRequestHandler == NULL) LOG_WARNING_(m_logger, "new UIRequestHandler");
        }
        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;
        delete m_uiRequestHandler;
    }
    //-------------------------------------------------------------------------------------------

    bool ClientAdapterStub::Start()
    {
        m_stopReceiving = false;
        m_receiver = new(std::nothrow) RequestReceiverThread(*this);
        if(m_receiver == NULL) LOG_WARNING_(m_logger, "new RequestReceiverThread");

        m_receiver->start();
        return true;
    }
    //-------------------------------------------------------------------------------------------

    bool ClientAdapterStub::needUserInterfaceSubscriber(const StringMap& settings)
    {
        const char* subscribeUIParam = (const_cast<StringMap&>(settings).get(c_SubscribeUserInterfaceConfParam)).c_str();
        if (subscribeUIParam && (strlen(subscribeUIParam) >= 1) && subscribeUIParam[0] == '1')
        {
            return true;
        }
        return false;
    }

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

    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_INFO_(m_logger, "Waiting for request from ClientAdapterProxy...");

        bool res = true;
        while (!m_stopReceiving)
        {
            if (!res)
            {
                restartFifos();
            }
            Message* request = new(std::nothrow) Message();
            if(request == NULL) LOG_WARNING_(m_logger, "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
                RequestHandlingThread* handlingThread = new(std::nothrow) RequestHandlingThread(request, this);
                if (handlingThread)
                {
                    handlingThread->start();
                }
                else
                {
                    LOG_ERROR_(m_logger, "Failed to create handling thread for request");
                    delete request;                 
                }
            }
            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(responseStopWaiting);
            if (!res)
            {
                LOG_ERROR_(m_logger, "Failed to send e_stopWaitingStatus response");
                return;
            }
        }
    }
    //-------------------------------------------------------------------------------------------

    bool ClientAdapterStub::handleRequest(const Message& request, Message& response)
    {
        bool res = false;
        LOG_DEBUG_(m_logger, "Request type %d", request.m_type);

        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 if (request.m_subType == e_manufacturer)
                res = handleSetManufacturerType(request, response);
            else if (request.m_subType == e_model)
                res = handleSetModelType(request, response);
            else
                res = handleSetType(request, response);
            break;
        case e_clientProfiles:
            res = handleClientProfilesType(request, response);
            break;
        case e_profileActivationStatus:
            res = handleProfileActivationStatusType(request, response);
            break;
        case e_profileActivationStatusByServerID:
            res = handleProfileActivationStatusByServerIDType(request, response);
            break;      
        case e_startDMSession:
            res = handleStartDMSessionType(request, response);
            break;
        case e_startBootstrap:
            res = handleStartBootstrapType(request, response);
            break;
        case e_startDRMD:
            res = handleStartDRMDType(request, response);
            break;
        case e_changePassword:
            res = handleChangePasswordType(request, response);
            break;
        case e_changePasswordByServerID:
            res = handleChangePasswordByServerIDType(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_unsubscribeFirmwareUpdate):
            res = handleUnsubscribeNotifType(request, response);
            break;
        case (e_unsubscribeDMSession):
            res = handleUnsubscribeNotifType(request, response);
            break;
        case e_notifyProvisioningUpdate:
            res = handleProvisioningUpdateNotifType(request, response);
            break;
        case e_unsubscribeProvisioningUpdate:
            res = handleUnsubscribeProvisioningType(request, response);
            break;
        case e_confirmationRequired:
            res = handleConfirmationRequiredType(request, response);
            break;
        case e_confirmationResponse:
            res = handleConfirmationResponseType(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((char*)&request.m_data[0]);
        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::handleSetManufacturerType(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 device manufacturer");
            return true;
        }

        bool res = deviceAdapter->SetManufacturer((char*)&request.m_data[0]);
        if (res)
        {
            LOG_(m_logger, "Device manufacturer was set");
        }
        else
        {
            LOG_(m_logger, "Failed to set device manufacturer");
            response.m_subType = e_failedStatus;
        }
        return res;
    }

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

    bool ClientAdapterStub::handleSetModelType(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 device model");
            return true;
        }

        bool res = deviceAdapter->SetModel((char*)&request.m_data[0]);
        if (res)
        {
            LOG_(m_logger, "Device model was set");
        }
        else
        {
            LOG_(m_logger, "Failed to set device model");
            response.m_subType = e_failedStatus;
        }
        return res;
    }

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

    bool ClientAdapterStub::handleOpenType(Message& response)
    {
        LOG_(m_logger, "Received \"open\" request");
        m_notification->Clear();
        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");
        m_notification->Clear();
        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::handleProfileActivationStatusType(const Message& request, Message& response)
    {
        LOG_(m_logger, "Received \"ProfileActivationStatus\" request");
        //m_notification->Add(e_startDMSession, request.m_id);
        //LOG_(m_logger, "Notification is added");

        NS_Common::EventEx executionCompleted;
        ResultSink resultSink;
        ProfileActivationStatusCommand* command = new(std::nothrow) ProfileActivationStatusCommand(*m_componentHolder, resultSink, &executionCompleted);
        if (!command)
        {
            LOG_ERROR_(m_logger, "Failed to create ProfileActivationStatusCommand");
            return false;
        }
        bool res = m_componentHolder->GetExecutionQueue()->Add(*command);
        if (res)
        {
            LOG_(m_logger, "ProfileActivationStatusCommand is added to execution queue. Waiting for execution completes...");
            executionCompleted.wait();
            LOG_(m_logger, "Execution completed. ResultSink = %d", resultSink.GetResult());
            // create response - as status result
            response.m_type = e_profileActivationStatus;
            response.m_subType = e_none;
            StringToBytes(ToString(resultSink.GetResult()), response.m_data);
        }
        else
        {
            LOG_ERROR_(m_logger, "Failed to add ClientSessionCommand to queue");
            delete command;
        }

        return res;
    }

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

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

        String serverID;
        BytesToString(request.m_data, serverID);

        NS_Common::EventEx executionCompleted;
        ResultSink resultSink;
        //ProfileActivationStatusCommand* command = new ProfileActivationStatusCommand(*m_componentHolder, resultSink, &executionCompleted);
        ProfileActivationStatusByServerIDCommand* command = new(std::nothrow) ProfileActivationStatusByServerIDCommand(*m_componentHolder, resultSink, &executionCompleted, serverID);
        if (!command)
        {
            LOG_ERROR_(m_logger, "Failed to create ProfileActivationStatusByServerIDCommand");
            return false;
        }
        bool res = m_componentHolder->GetExecutionQueue()->Add(*command);
        if (res)
        {
            LOG_(m_logger, "ProfileActivationStatusByServerIDCommand is added to execution queue. Waiting for execution completes...");
            executionCompleted.wait();
            LOG_(m_logger, "Execution completed. ResultSink = %d", resultSink.GetResult());
            // create response - as status result
            response.m_type = e_profileActivationStatusByServerID;
            response.m_subType = e_none;
            StringToBytes(ToString(resultSink.GetResult()), response.m_data);
        }
        else
        {
            LOG_ERROR_(m_logger, "Failed to add ClientSessionCommand to queue");
            delete command;
        }

        return res;
    }

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

    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");

        String alertMessage;
        BytesToString(request.m_data, alertMessage);
LOG_DEBUG_(m_logger, "alertMessage %s", alertMessage.c_str());
        NS_Communication::ClientSessionCommand* command = new(std::nothrow) NS_Communication::ClientSessionCommand(*m_componentHolder->GetServerExchangeManager(), alertMessage);
        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");
            delete command;

        }

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

    bool ClientAdapterStub::handleStartBootstrapType(const Message& request, Message& response)
    {
        LOG_(m_logger, "Received \"StartBootstrap\" request");

        NS_Communication::StartBootstrapCommand* command = new(std::nothrow) NS_Communication::StartBootstrapCommand(*m_componentHolder->GetServerExchangeManager());
        if (!command)
        {
            LOG_ERROR_(m_logger, "Failed to create StartBootstrapCommand");
            return false;
        }
        LOG_(m_logger, "StartBootstrapCommand is created");

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

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

    bool ClientAdapterStub::handleStartDRMDType(const Message& request, Message& response)
    {
        LOG_(m_logger, "Received \"StartDRMD\" request");

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

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

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

    bool ClientAdapterStub::handleChangePasswordType(const Message& request, Message& response)
    {
        LOG_(m_logger, "Received \"ChangePassword\" request");

        NS_Common::EventEx executionCompleted;
        bool executionResult;
        String oldPassword, newPassword, data;
        BytesToString(request.m_data, data);
        DeserializePasswords(data, oldPassword, newPassword);
        ChangePasswordCommand* command = new(std::nothrow) ChangePasswordCommand(*m_componentHolder, oldPassword, newPassword, executionCompleted, executionResult);
        if (!command)
        {
            LOG_ERROR_(m_logger, "Failed to create ChangePasswordCommand");
            return false;
        }
        LOG_(m_logger, "ChangePasswordCommand is created");

        bool res = m_componentHolder->GetExecutionQueue()->Add(*command);
        if (res)
        {
            LOG_(m_logger, "ChangePasswordCommand is added to execution queue");
            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 ChangePasswordCommand is created");
        }
        else
        {
            LOG_ERROR_(m_logger, "Failed to add ChangePasswordCommand to queue");
            delete command;
        }

        return res;
    }

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

    bool ClientAdapterStub::handleChangePasswordByServerIDType(const Message& request, Message& response)
    {
        LOG_(m_logger, "Received \"ChangePasswordByServerID\" request");

        NS_Common::EventEx executionCompleted;
        bool executionResult;
        String serverID, oldPassword, newPassword, data;
        BytesToString(request.m_data, data);
        DeserializePasswordsAndServerID(data, serverID, oldPassword, newPassword);
        ChangePasswordByServerIDCommand* command = new(std::nothrow) ChangePasswordByServerIDCommand(*m_componentHolder, oldPassword, newPassword, executionCompleted, executionResult, serverID);
        if (!command)
        {
            LOG_ERROR_(m_logger, "Failed to create ChangePasswordByServerIDCommand");
            return false;
        }
        LOG_(m_logger, "ChangePasswordByServerIDCommand is created");

        bool res = m_componentHolder->GetExecutionQueue()->Add(*command);
        if (res)
        {
            LOG_(m_logger, "ChangePasswordByServerIDCommand is added to execution queue");
            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 ChangePasswordByServerIDCommand is created");
        }
        else
        {
            LOG_ERROR_(m_logger, "Failed to add ChangePasswordByServerIDCommand to queue");
            delete command;
        }

        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(std::nothrow) NS_Communication::RequestFWUCommand(*m_componentHolder->GetServerExchangeManager());
        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");
            delete command;
        }

        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 \"ProvisionUpdateNotif\" request");
        ProvisionInfoRequest provisionInfo;
        String strData;
        BytesToString(request.m_data, strData);
        bool res = provisionInfo.Deserialize(strData);
        if (res)
        {
            LOG_(m_logger, "ProvisionInfoRequest was deserialised. Provision info: uri = %s, monitorChildren = %d, commands = %d, events = %d", 
                provisionInfo.m_URI.c_str(), provisionInfo.m_monitorChildren, provisionInfo.m_commands, provisionInfo.m_events);
        }
        else
        {
            LOG_ERROR_(m_logger, "Failed to deserialize ProvisionInfoRequest");
            return false;
        }
        // register each command - one command / one notification
        m_notification->AddProvisioningUpdateType(request.m_id, provisionInfo);
        LOG_(m_logger, "Notification \"ProvisionInfoRequest\" is added");

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

    bool ClientAdapterStub::handleUnsubscribeProvisioningType(const Message& request, Message& response)
    {
        LOG_(m_logger, "Received \"UnsubscribeProvisioningType\" request");
        m_notification->DeleteProvisioningUpdateType();
        LOG_(m_logger, "Notification \"Provisioning\" was unsubscribed");

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

    bool ClientAdapterStub::handleUnsubscribeNotifType(const Message& request, Message& response)
    {
        LOG_(m_logger, "Received \"UnsubscribeNotifType\" request");
        m_notification->Delete((MsgType)request.m_type);
        LOG_(m_logger, "Notification \"%s\" was unsubscribed", S_msgTypeDescription[request.m_type]);

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

    bool ClientAdapterStub::handleConfirmationRequiredType(const Message& request, Message& response)
    {
        LOG_(m_logger, "Received \"ConfirmationRequired\" request");
        m_notification->Add(e_confirmationRequired, request.m_id);

        response.m_type = e_status;
        response.m_subType = e_okStatus;
        LOG_(m_logger, "Notification \"ConfirmationRequired\" is added");
        return true;
    }
    //-------------------------------------------------------------------------------------------

    bool ClientAdapterStub::handleConfirmationResponseType(const Message& request, Message& response)
    {
        LOG_(m_logger, "Received \"ConfirmationResponse\" request");
        if (m_uiRequestHandler)
        {
            String strData;
            BytesToString(request.m_data, strData);
            m_uiRequestHandler->NotifyResponse(strData);
            LOG_(m_logger, "UIRequestHandler was notified about response. Message = \"%s\"", strData.c_str());
        }

        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(std::nothrow) 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");
        }
        else
        {
            delete setCommand;
        }
        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(std::nothrow) 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");
        }
        else
        {
            delete setMgmtTreeCommand;
        }
        return res;
    }
    //-------------------------------------------------------------------------------------------

    bool ClientAdapterStub::handleGetKnownMgmtObject(IMgmtObject& mgmtObject, const Message& request, Message& response)
    {
        NS_Common::EventEx executionCompleted;
        bool executionResult;
        IMOTreeCommand* getCommand = new(std::nothrow) 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");
            delete getCommand;
        }
        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(std::nothrow) 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");
            delete getCommand;
        }
        return res;
    }
    //-------------------------------------------------------------------------------------------

    IMgmtObject* ClientAdapterStub::getMgmtObject(size_t subType)
    {
        IMgmtObject* mgmtObject = NULL;
        switch (subType)
        {
        case e_devInfo:
            mgmtObject = new(std::nothrow) DevInfo();
            if(mgmtObject == NULL) LOG_WARNING_(m_logger, "new DevInfo");
            break;
        case e_devDetail:
            mgmtObject = new(std::nothrow) DevDetail();
            if(mgmtObject == NULL) LOG_WARNING_(m_logger, "new DevDetail");
            break;
        case e_DMAcc:
            mgmtObject = new(std::nothrow) DMAcc();
            if(mgmtObject == NULL) LOG_WARNING_(m_logger, "new DMAcc");
            break;
        case e_WiMAX:
            mgmtObject = new(std::nothrow) WiMAX();
            if(mgmtObject == NULL) LOG_WARNING_(m_logger, "new WiMAX");
            break;
        case e_WiMAXSupp:
            mgmtObject = new(std::nothrow) WiMAXSupp();
            if(mgmtObject == NULL) LOG_WARNING_(m_logger, "new WiMAXSupp");
            break;
        case e_WiMAX_Diagnostics:
            mgmtObject = new(std::nothrow) NS_DM_Diagnostics::WiMAX_Diagnostics();
            if(mgmtObject == NULL) LOG_WARNING_(m_logger, "new 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', subtype='%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;
        }
        String strProfileCount;
        BytesToString(response.m_data, strProfileCount);
        int profilesCount = atoi(strProfileCount.c_str());
        LOG_(m_logger, "Response \"GetOperatorProfilesCount\" with profile's count was sent");
        for (int i = 0; i != profilesCount; ++i)
        {
            String profileInfo;
            SerializeOperatorProfile(m_configuration.GetProfile(i)->GetName(), m_configuration.GetProfile(i)->GetType(), 
                m_configuration.GetProfile(i)->GetDescription(), profileInfo);
            Message profileInfoResponse(response.m_id, e_clientProfiles, e_none, profileInfo);
            res = sendResponseHelper(profileInfoResponse);
            if (!res)
            {
                return res;
            }
            LOG_(m_logger, "Response \"GetOperatorProfilesCount\" with profile's info was sent");
        }

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

    void ClientAdapterStub::sendConfirmationRequest(const String& message)
    {
        m_notification->ConfirmationRequired(message);
    }
    //-------------------------------------------------------------------------------------------

    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();
        if (m_uiRequestHandler)
        {
            m_uiRequestHandler->NotifyClientStopping();
        }
        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(std::nothrow) 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;
            }
        }
        else
        {
            LOG_WARNING_(m_logger, "new HandleNetworkEntryCommand");
        }

        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(std::nothrow) 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;
            }
        }
        else
        {
            LOG_WARNING_(m_logger, "new DRMDReadyNotificationCommand");
        }

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