/*
 * Copyright 2009 Funambol, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License i<s distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id$ */

#include "Logger/LoggerMacroses.h"
#include <wbxml.h>
#include <wbxml_errors.h>
#include <wbxml_mem.h>

#include "Event.h"
#include "identifiers.h"
#include "hash.h"
#include "lock.h"
#include "Starter.h"
#include "SyncCall.h"
#include "WBXMLUtils.h"

#include "daemon/INotificationCenter.h"
#include "DaemonDM/branding.h"
#include "executionqueue/ICommand.h"
#include "executionqueue/IExecutionQueue.h"
#include "NotificationListener/SessionInfo.h"
#include "NotificationListener/DMSessionRequestCommand.h"

#include "serverexchange/commands/AccessConfigCommand.h"
#include "serverexchange/commands/AdjustDurationCommand.h"
#include "serverexchange/commands/DevDetailCommand.h"
#include "serverexchange/commands/SEMNetworkEntranceCommand.h"
#include "serverexchange/commands/ServerPollingInfoCommand.h"
#include "serverexchange/firmware/FirmwareManager.h"
#include "serverexchange/BasicCommandsSink.h"
#include "serverexchange/CommandStorage.h"
#include "serverexchange/ConnectionInfo.h"
#include "serverexchange/DRMDConnection.h"
#include "serverexchange/ResponseProcessor.h"
#include "serverexchange/ServerExchangeManager.h"
#include "serverexchange/WIBConnector.h"
#include "serverexchange/wrappers/SAlertCommand.h"
#include "serverexchange/wrappers/SCommandFactory.h"
#include "SEMConfig.h"
#include "UserAgentFormatter.h"


using namespace NS_DM_Client;
using namespace NS_DM_Client::NS_Common;
using namespace NS_DM_Client::NS_Communication;
using namespace NS_DM_Client::NS_NotificationListener;
using namespace NS_DM_Client::NS_SyncMLCommand;


static const char * c_LogName = "ServerExchangeManager";


ServerExchangeManager::ServerExchangeManager() :
    m_haveBMProcessed(false),
    m_multipleBootstrap(false),
    m_enteredNetwork(false),
    m_startOnLAN(false),
    m_startedOnLAN(false),
    m_threadRunning(false),
    m_useShortTimeout(false),

    m_pWIBConnector(NULL),
    m_pWIBThread(NULL),
    m_wibCipherHeaderPresent(false),
    m_wibPlainBootstrap(false),
    m_wibRetriesCount(-1),
    m_wibRetryInterval(-1),
    m_wibServerPort(0),

    m_connectionDelay(0),

    m_pDefaultConnection(NULL),
    m_pFirmwareManager(NULL),
    m_pProfileHolder(NULL),
    m_pSyncCall(NULL),
    m_evRunComplete(false)
{
GDLDEBUG("Enter");

    terminate = false;

GDLDEBUG("Leave");
}


ServerExchangeManager::~ServerExchangeManager()
{
GDLDEBUG("Enter");

    m_pDefaultConnection = NULL;
    SAFE_DELETE(m_pWIBConnector);
    SAFE_DELETE(m_pWIBThread);

    stopConnections();
    m_connInfoList.clear();

    SAFE_DELETE(m_pFirmwareManager);

GDLDEBUG("Leave");
}


void ServerExchangeManager::AddCommand(NS_SyncMLCommand::SCommandPtr ptrCommand, const char *connid)
{
GDLDEBUG("Enter");

    Lock lock(m_csAddCommand);

    GDLDEBUG("add command [serverID='%s'] %d", connid, m_connections.size());
    Connections::iterator iconnection = m_connections.find(connid);
    if (iconnection != m_connections.end() && iconnection->second)
        iconnection->second->AddCommand(ptrCommand, NULL);
    else
    {
        GDLERROR("no available connection '%s' to add command to", connid);
    }

GDLDEBUG("Leave");
}


void ServerExchangeManager::AddCommands(NS_SyncMLCommand::SCommandsArray &commands, const char *connid)
{
GDLDEBUG("Enter");

    Lock lock(m_csAddCommand);

    GDLDEBUG("add commands [serverID='%s']", connid);
    Connections::iterator iconnection = m_connections.find(connid);
    if (iconnection != m_connections.end() && iconnection->second)
        iconnection->second->AddCommands(commands, NULL);
    else
    {
        GDLERROR("no available connection '%s' to add commands to", connid);
    }

GDLDEBUG("Leave");
}


IConnection * ServerExchangeManager::DefaultConnection()
{
GDLDEBUG("Enter");
GDLDEBUG("Leave");

    return m_pDefaultConnection;
}


void ServerExchangeManager::DefaultConnectionName(String &name)
{
GDLDEBUG("Enter");

    name = m_defaultAccountName;

GDLDEBUG("Leave");
}


FirmwareManager* ServerExchangeManager::GetFirmwareManager()
{
GDLDEBUG("Enter");

    if (!m_pFirmwareManager)
    {
        m_pFirmwareManager = new(std::nothrow) FirmwareManager(m_pProfileHolder);
    }

GDLDEBUG("Leave");

    return m_pFirmwareManager;
}


bool ServerExchangeManager::Init(const StringMap& settings, const String& loggerInstance, ProfileComponentsHolder& pch)
{
GDLDEBUG("Enter");

    m_pProfileHolder = &pch;
    m_serverPoller.SetProfile(pch);

    SEMConfig config;
    config(*this, settings);
    GetFirmwareManager();

GDLDEBUG("Leave");

    return true;
}


bool ServerExchangeManager::HasAccountFor(String &serverID)
{
GDLDEBUG("Enter");

    for (size_t i=0; i<m_connInfoList.size(); ++i)
        if (m_connInfoList[i].get() && serverID == m_connInfoList[i]->GetServerID())
            return true;

GDLDEBUG("Leave");

    return false;
}


void ServerExchangeManager::HandleNetworkEntrance(int homeNspID, const char* operatorName, bool startWIB)
{
GDLDEBUG("Enter");

    GDLDEBUG("HandleNetworkEntrance: operator name - '%s', connection delay - %d", operatorName, m_connectionDelay);

    Stop();
    m_enteredNetwork = true;
    
    m_evRunComplete.reset();
    Start();

    // here we sleep to get the ip & dns assigned
    sleep(m_connectionDelay);

    if (startWIB)
    {
        StartWIB();
    }
    m_evRunComplete.wait();

    startServerPoller();

GDLDEBUG("Leave");
}


void ServerExchangeManager::NotifyDiagnosticsReady(String &serverID, String &origID)
{
GDLDEBUG("Enter");

    GDLDEBUG("notify diagnostics ready to %s server", serverID.c_str());
    IConnection *pConnection = getConection(serverID);
    if (!pConnection)
    {
        GDLERROR("failed to start DRMD connection, serverID '%s'", serverID.c_str());
        return;
    }

    // TODO - pass Diagnostics node uri to alert
    pConnection->StartSession(SCommandFactory::CreateGenericAlert(NULL, DIAGNOSTICS_READY, 200));

GDLDEBUG("Leave");
}


void ServerExchangeManager::NotifyFWJobStatus(String &serverID, int result, ExecPtr &exec, const char *alertType)
{
GDLDEBUG("Enter");

    GDLDEBUG("notify fw status to server '%s'", serverID.c_str());
    IConnection *pConnection = getConection(serverID);
    if (pConnection)
    {
        GDLDEBUG("server - '%s', CommandStatus - %d, responseType - '%s'", serverID.c_str(), result, alertType);
        pConnection->StartSession(SCommandFactory::CreateAlertOnFWDownload(result, exec, alertType));
    }
    else
    {
        GDLERROR("failed to notify fw status to server '%s'", serverID.c_str());
    }

GDLDEBUG("Leave");
}


void ServerExchangeManager::ProcessBootstrapMessage(const char *bsm, uint length)
{
GDLDEBUG("Enter");

    if (!m_multipleBootstrap && m_haveBMProcessed)
    {
        GDLINFO("bootstrap message already processed; skip request");
        return;
    }

    char *xml = NULL;
    int status = WBXMLUtils::Parse(bsm, length, &xml);
    if (status)
    {
        GDLERROR("error '#%d' while converting wbxml of bootstrap to syncml", status);
        GDLERROR("error text:'%s'", wbxml_errors_string((WBXMLError)status));
    }
    else
    {
        // response processor should process message
        GDLDEBUG("process bootstrap message:\n%s", xml);

        ConnectionInfo info;
        BasicCommandsSink bcs(info);
        ResponseProcessor rp(info, &bcs, m_pProfileHolder);
        ResponseProcessor::ProcessingStatus status = rp.Process(xml, true);

        m_haveBMProcessed = (ResponseProcessor::PS_Successful == status);
        if (m_haveBMProcessed)
            bcs.Wait();

        wbxml_free(xml);

        if (m_haveBMProcessed)
        {
            m_evRunComplete.reset();
            Restart();
            m_evRunComplete.wait();
            
            SessionInfo si;
            si.serverInitiated = false;
            ICommand *cmd = new(std::nothrow) DMSessionRequestCommand(si, false, *m_pProfileHolder,
                                                        NS_Logging::GetLogger(c_LogName));
            if(cmd == (ICommand*)NULL)
            {
                GDLWARN("new DMSessionRequestCommand");
            }
            IExecutionQueue* exq = m_pProfileHolder->GetExecutionQueue();
            if (!exq->Add(*cmd))
            {
                GDLDEBUG("Failed to add DMSessionRequestCommand command to Q");
                delete cmd;
            }
            
            startServerPoller();
        }
    }

GDLDEBUG("Leave");
}


void ServerExchangeManager::RequestFWUpdate(bool userInitiated, const char *fumouri, int data)
{
GDLDEBUG("Enter");

    if (m_pDefaultConnection)
    {
        m_pDefaultConnection->RequestFWUpdate(userInitiated, fumouri, data);
    }

GDLDEBUG("Leave");
}


void ServerExchangeManager::RequestSessionStart(const NS_NotificationListener::SessionInfo& sessionInfo)
{
GDLDEBUG("Enter");

    const String &serverid = sessionInfo.serverID;
    GDLDEBUG("requested session start for server '%s'", serverid.c_str());
    IConnection *pConnection = getConection(serverid);
    if (pConnection)
        pConnection->RequestSessionStart(sessionInfo);
    else
        GDLERROR("failed to get connection for server '%s'", serverid.c_str());

GDLDEBUG("Leave");
}


void ServerExchangeManager::Restart()
{
GDLDEBUG("Enter");

    GDLDEBUG("~ restart");
    stopConnections();

    m_connInfoList.clear();
    m_startedOnLAN = false;

    Start();

GDLDEBUG("Leave");
}


void ServerExchangeManager::Release()
{
GDLDEBUG("Enter");
GDLDEBUG("Leave");
}


void ServerExchangeManager::SetConnectionsInfo(ConnInfoList &c)
{
GDLDEBUG("Enter");

    GDLDEBUG("Set ConnectionsInfo {%d}", c.size());
    m_connInfoList = c;
    GDLDEBUG("  def account name '%s', start: %d", m_defaultAccountName.c_str(), m_startOnLAN);

    for (size_t i=0; i<m_connInfoList.size(); ++i)
    {
        if (!m_connInfoList[i])
        {
            GDLERROR("passed NULL instead of ConnectionInfo instance");
            continue;
        }

        ConnectionInfo &info = *m_connInfoList[i];
        info.acconfig.setUserAgent(m_settings.UserAgentName.c_str());
        info.settings = m_settings;
        info.devinf = m_ptrDevInfo;
            
        if (m_ptrDevInfo.get())
            info.acconfig.setUserAgent(UserAgentFormatter::GetUserAgent(m_pProfileHolder, cApplicationVendor, cApplicationVersion));

        GDLDEBUG("  has connection info for '%s'", info.GetServerID());
        if (m_drmdAccountName == info.GetServerID())
        {
            GDLDEBUG("  found DRMD account config '%s', server id '%s'", info.accname.c_str(), info.GetServerID());
            configureDRMDAccount(info);
        }
    }

    if (m_pSyncCall)
        m_pSyncCall->Notify();

GDLDEBUG("Leave");
}


void ServerExchangeManager::SetDevInfo(Funambol::DevInf &devInf)
{
GDLDEBUG("Enter");

    GDLDEBUG("Set DevInfo");
    m_ptrDevInfo.reset(devInf.clone());

    if (m_pSyncCall)
        m_pSyncCall->Notify();

GDLDEBUG("Leave");
}


void ServerExchangeManager::SetServerPollerInfo(bool pollingSupported, int pollingInterval, int pollingAttempts)
{
GDLDEBUG("Enter");

    if (m_pSyncCall)
        m_pSyncCall->Notify();

    GDLDEBUG("Set ServerPollerInfo {%s, %d, %d}", pollingSupported ? "true" : "false", pollingInterval, pollingAttempts);

    m_pollingInfo.pollingSupported = pollingSupported;
    m_pollingInfo.pollingInterval  = pollingInterval;
    m_pollingInfo.pollingAttempts  = pollingAttempts;

GDLDEBUG("Leave");
}


bool ServerExchangeManager::Start()
{
GDLDEBUG("Enter");

    GetFirmwareManager();
    Thread::start();

GDLDEBUG("Leave");
    return true;
}


void ServerExchangeManager::StartClientSession()
{
GDLDEBUG("Enter");

    GDLDEBUG("start client session");
    if (!m_pDefaultConnection)
    {
        m_pDefaultConnection = startConnection(m_defaultAccountName);
    }

    if (m_pDefaultConnection)
    {
        GDLDEBUG("default connection already created");
        m_pDefaultConnection->StartSession();
    }
    else
    {
        GDLERROR("default connection is null");
    }

GDLDEBUG("Leave");
}


void ServerExchangeManager::StartClientSession(NS_SyncMLCommand::SAlertCommandPtr ptrAlert)
{
GDLDEBUG("Enter");

    if(ptrAlert.get() == NULL)
    {
        GDLWARN("ptrAlert is NULL");
    }

    GDLDEBUG("start client session with custom alert");
    if (!m_pDefaultConnection)
    {
        m_pDefaultConnection = startConnection(m_defaultAccountName);
    }
    
    if (m_pDefaultConnection)
    {
        GDLDEBUG("default connection already created");
        m_pDefaultConnection->StartSession(ptrAlert);
    }
    else
    {
        GDLERROR("default connection is null");
    }

GDLDEBUG("Leave");
}


void ServerExchangeManager::StartWIB()
{
GDLDEBUG("Enter");

    // !!TODO: add lock for m_pWIBConnector

    SAFE_DELETE(m_pWIBConnector);
    m_pWIBConnector = new(std::nothrow) WIBConnector(*m_pProfileHolder,
        m_wibPlainBootstrap, (m_wibPlainBootstrap) ? m_wibCipherHeaderPresent : true,
        m_wibServiceDiscoveryTarget, m_wibDnsServer,
        m_wibServer, m_wibServerPort, m_wibRequestURI, 
        m_wibRetriesCount, m_wibRetryInterval);
    if (m_pWIBConnector != (WIBConnector*)NULL)
    {
        SAFE_DELETE(m_pWIBThread);
        m_pWIBThread = new(std::nothrow) Starter(*m_pWIBConnector);
        if (m_pWIBThread != (Starter*)NULL)
        {
            GDLDEBUG("WIB start");
            m_pWIBThread->start();
        }
        else
        {
            GDLWARN("new Starter");
        }
    }
    else
    {
        GDLWARN("new WIBConnector");
    }

GDLDEBUG("Leave");
}


bool ServerExchangeManager::Stop()
{
GDLDEBUG("Enter");

    GDLDEBUG("received Stop ...");
    
    m_evRunComplete.signal();
    m_serverPoller.Stop();
    if (m_threadRunning)
    {
        terminate = true;
        if (m_pSyncCall)
            m_pSyncCall->Notify();
        SAFE_DELETE(m_pSyncCall);

        GDLDEBUG("wait SEM to stop ...");
        wait();
        m_enteredNetwork = false;

        terminate = false;
    }

    stopConnections();
    m_connInfoList.clear();
    SAFE_DELETE(m_pFirmwareManager);
    GDLDEBUG("terminated.");

GDLDEBUG("Leave");
    return true;
}


void ServerExchangeManager::run()
{
GDLDEBUG("Enter");

    Lock lock(m_csRun);

    GDLDEBUG("start SEM");
    m_threadRunning = true;

    do {
        if (m_enteredNetwork || m_haveBMProcessed)
        {
GDLDEBUG("Phase1");
            m_pSyncCall = new(std::nothrow) SyncCall(new(std::nothrow) DevDetailCommand(*m_pProfileHolder), m_pProfileHolder, false);
            if(m_pSyncCall == (SyncCall*)NULL)
            {
                GDLWARN("new SyncCall");
            }

            m_pSyncCall->Call();
            SAFE_DELETE(m_pSyncCall);

            if (terminate) break;

            m_pSyncCall = new(std::nothrow) SyncCall(
                new(std::nothrow) ServerPollingInfoCommand(m_pProfileHolder,
                    m_serverPoller.URIPollingSupported,
                    m_serverPoller.URIPollingInterval,
                    m_serverPoller.URIPollingAttempts), 
                m_pProfileHolder, false);
            if(m_pSyncCall == (SyncCall*)NULL)
            {
                GDLWARN("new SyncCall");
            }

            m_pSyncCall->Call();
            SAFE_DELETE(m_pSyncCall);

            if (terminate) break;

            m_pSyncCall = new(std::nothrow) SyncCall(new(std::nothrow) DMAccountCommand(*m_pProfileHolder), m_pProfileHolder, false);

            if(m_pSyncCall == (SyncCall*)NULL)
            {
                GDLWARN("new SyncCall");
            }

            m_pSyncCall->Call();
            SAFE_DELETE(m_pSyncCall);

            if (terminate) break;
        }

        if (m_startOnLAN && !m_startedOnLAN)
        {
            GDLDEBUG("init network entrance");
            ICommand *pNetworEntryCmd = new(std::nothrow) SEMNetworkEntranceCommand(*m_pProfileHolder->GetServerExchangeManager(), 0, NULL, false);
            if(pNetworEntryCmd == (ICommand*)NULL)
            {
                GDLWARN("new SEMNetworkEntranceCommand");
            }

            const bool commandAdded = m_pProfileHolder->GetExecutionQueue()->Add(*pNetworEntryCmd);
            m_startedOnLAN = commandAdded;
            if (!commandAdded)
            {
                delete pNetworEntryCmd;
            }
        }
    } while(false);

    m_threadRunning = false;
    GDLDEBUG("finished SEM");
    GDLDEBUG("");
    m_evRunComplete.signal();

GDLDEBUG("Leave");
}


void ServerExchangeManager::configureDRMDAccount(ConnectionInfo &ci)
{
GDLDEBUG("Enter");

    // set DRMD specific values
    const char *serverID = ci.GetServerID();
    
    String deviceID;
    FStringBuffer serialNumber;
    if (m_pProfileHolder->GetDeviceAdapter()->GetDeviceID(deviceID))
    {
        if (deviceID[0])
        {
            serialNumber.append(deviceID.c_str());
            serialNumber.upperCase();
        }
        else
        {
            GDLERROR("Received empty DeviceID");
            return;
        }
    }
    else
    {
        GDLERROR("Failed to receive DeviceID from the DeviceAdapter");
        return;
    }

    // client name
    ci.acconfig.setUsername(deviceID.c_str());
    GDLDEBUG("drmd username %s", deviceID.c_str());

    // client password
    const char * clientpass = NS_Common::calculateF(serialNumber.c_str(), serverID, m_OEMSharedKey.c_str());
    if (clientpass)
    {
        GDLDEBUG("drmd clientpass %s", clientpass);
        ci.acconfig.setPassword(clientpass);
        SAFE_DELETE_ARR(clientpass);
    }
    else
    {
        GDLERROR("Received empty clientpass on '%s' '%s' '%s'", serialNumber.c_str(), serverID, m_OEMSharedKey.c_str());
        return;
    }

    // server password
    const char * serverpass = NS_Common::calculateF(serverID, serialNumber.c_str(), m_OEMSharedKey.c_str());
    if (serverpass)
    {
        GDLDEBUG("drmd serverpass %s", serverpass);
        ci.acconfig.setServerPWD(serverpass);
        SAFE_DELETE_ARR(serverpass);
    }
    else
    {
        GDLERROR("Received empty serverpass on '%s' '%s' '%s'", serverID, serialNumber.c_str(), m_OEMSharedKey.c_str());
        return;
    }

    ci.settings.UseWBXML = false;
    
    String diagDuration("./WiMAX_Diagnostics/Start/Duration"); // TODO - create a conf parameter ?
    ICommand *cmd = new(std::nothrow) AdjustDurationCommand(m_pProfileHolder, diagDuration);
    if(cmd == (ICommand*)NULL)
    {
        GDLWARN("new AdjustDurationCommand");
    }

    if (!m_pProfileHolder->GetExecutionQueue()->Add(*cmd))
    {
        delete cmd;
    }

GDLDEBUG("Leave");
}


bool ServerExchangeManager::isDRMDServer(const String &serverID)
{
GDLDEBUG("Enter");
GDLDEBUG("Leave");

    return (m_drmdAccountName == serverID);
}


void ServerExchangeManager::startServerPoller()
{
GDLDEBUG("Enter");

    GDLDEBUG("startServerPoller {%s, %d, %d}", 
        m_pollingInfo.pollingSupported ? "enabled" : "disabled", m_pollingInfo.pollingInterval, m_pollingInfo.pollingAttempts);
    m_serverPoller.Stop();

    if (m_pollingInfo.pollingInterval == -1)
    {
        m_serverPoller.SetPollingInterval(1);
        m_serverPoller.SetPollingAttempts(1);
        m_serverPoller.Start();
    }
    else if (m_pollingInfo.pollingInterval)
    {
        m_serverPoller.SetPollingInterval(m_useShortTimeout ? m_pollingInfo.pollingInterval : 60*m_pollingInfo.pollingInterval);
        if (m_pollingInfo.pollingAttempts > 0)
            m_serverPoller.SetPollingAttempts(m_pollingInfo.pollingAttempts+1);
        else
            m_serverPoller.SetPollingAttempts(m_pollingInfo.pollingAttempts);

        if (m_pollingInfo.pollingSupported && m_pollingInfo.pollingAttempts != 0)
        {
            m_serverPoller.Start();
        }
    }

GDLDEBUG("Leave");
}


IConnection * ServerExchangeManager::getConection(const String &serverID)
{
GDLDEBUG("Enter");

    IConnection *pConnection = NULL;
    Connections::iterator iconnection = m_connections.find(serverID);
    if (iconnection != m_connections.end())
    {   
        GDLDEBUG("found existing connection for server '%s'", serverID.c_str());
        pConnection = iconnection->second;
    }
    else
    {
        GDLDEBUG("start new connection for server '%s'", serverID.c_str());
        pConnection = startConnection(serverID);
    }

GDLDEBUG("Leave");
    return pConnection;
}


IConnection * ServerExchangeManager::startConnection(const String &serverid)
{
GDLDEBUG("Enter");

    GDLDEBUG("start connection for server '%s'", serverid.c_str());
    IConnection *pConnection = NULL;
    for (size_t i=0; i<m_connInfoList.size(); ++i)
    {
        if (!m_connInfoList[i])
        {
            GDLERROR("stored NULL instead of ConnectionInfo instance");
            continue;
        }

        ConnectionInfo &info = *m_connInfoList[i];
        GDLDEBUG(" here is server '%s'", info.GetServerID());
        if (serverid == info.GetServerID())
        {
            GDLDEBUG("found AccConfig for server '%s'", serverid.c_str());

            NS_Common::Event event;
            if (isDRMDServer(serverid))
             {
                GDLDEBUG("DRMDConnection");
                pConnection = new(std::nothrow) DRMDConnection(info, m_OEMSharedKey);
                if(pConnection == NULL)
                {
                    GDLWARN("new DRMDConnection");
                }
             }
            else
             {
                GDLDEBUG("Connection");
                pConnection = new(std::nothrow) Connection(info);
                if(pConnection == NULL)
                {
                    GDLWARN("new Connection");
                }
             }

            m_connections[info.GetServerID()] = pConnection;
            pConnection->SetPCH(*m_pProfileHolder);
            if (m_defaultAccountName == serverid)
              {
                m_pDefaultConnection = pConnection;
              }

            GDLDEBUG("[start connection ...");
            pConnection->Start(&event);
            event.wait();
            GDLDEBUG("connection started]");
            break;
        }
    }
    
    if (!pConnection)
        GDLERROR("  failed to start connection - no ConnectionInfo is assigned to serverID '%s'", serverid.c_str());

GDLDEBUG("Leave");
    return pConnection;
}


void ServerExchangeManager::stopConnections()
{
GDLDEBUG("Enter");

    GDLDEBUG("stop all connections");
    Connections::iterator iconnection = m_connections.begin();
    for (; iconnection != m_connections.end(); ++iconnection)
    {
        IConnection *pConnection = iconnection->second;
        pConnection->Stop();
        pConnection->Wait();
        delete pConnection;
    }
    m_connections.clear();
    m_pDefaultConnection = NULL;
    GDLDEBUG("connections stopped");

GDLDEBUG("Leave");
}
