/*
* $Header: https://svn.mpia.de/gulli/TwiceAsNice/branch/unstable/ln/ltcs/test/LbtoIIFSimulator/LbtoIIFInterfaceFactoryI.cc 14502 2017-07-17 08:46:15Z mathar $
*
* @since 2014-08-19
* @author kittmann
*/

#include <LbtoIIFInterfaceFactoryI.h>
#include <list>

lbto::DirtContainer lbto::FactoryI::s_dirts;

/*!*******************************
* Default ctor.
*/
lbto::FactoryI::FactoryI()
{
    m_debug = true; //by default enable the debug mode
}

/*!**************************
* @brief dtor.
* Does nothing
*/
lbto::FactoryI::~FactoryI()
{
}

/** @brief Creates or links an ICE proxy with the client connection.
* @param  _proxyName Proxy Identification. If two or more clients use the same name,
* both are linked to the same IIFServer object, sharing guide stars, target, etc.
* @param  _focalStation Instrument focal station
* @param _instrumentID Instrument ID
* @return The proxy pointer associated with this client.
*/
lbto::IIFServerPrx lbto::FactoryI::create(const std::string& _proxyName,
                                          const std::string& _focalStation,
                                          const std::string& _instrumentID,
                                          const Ice::Current& _c)
{
    // Get the Ice logger.
    Ice::Print info(_c.adapter->getCommunicator()->getLogger());
//    lbto::IIF *anIIF = NULL;

    /* convert to lower */
    std::string temp1 = _focalStation;
    transform(temp1.begin(), temp1.end(), temp1.begin(), (int (*)(int))tolower);

    /* convert to upper case */
    std::string temp2 = _instrumentID;
    transform(temp2.begin(), temp2.end(), temp2.begin(), (int (*)(int))toupper);
    std::string proxyDef = temp2 + " at " + temp1;

    // Get an IIFServerI pointer from the arbitrator. This will be linked with the proxy,
    // and attached to the communicator.
    lbto::IIFServerPtr iif = m_ar.getIIFServer(_proxyName,
                                               _c.adapter->getCommunicator());
    lbto::IIFServerPrx proxy;

    // Check if the proxy already exists for this adapter
    IceUtil::LockT < IceUtil::RecMutex > guard(__connMutex);
    if (_c.adapter->find(
            _c.adapter->getCommunicator()->stringToIdentity(_proxyName)) == 0)
    {
        // Does not exist, so make a new proxy.
        proxy = IIFServerPrx::uncheckedCast(
                _c.adapter->add(
                        (iif),
                        _c.adapter->getCommunicator()->stringToIdentity(
                                _proxyName)));
        s_dirts.m_objs.push_back(proxy);
        nameMap.erase(_proxyName);
        nameMap.insert(std::pair<std::string, std::string>(_proxyName, proxyDef));
        if (m_debug)
            info << proxy->ice_getIdentity().name << ":Created proxy for "
                    << nameMap[_proxyName];
    }
    else
    {
        // Already exists, so link the proxy with the adapter.
        proxy = IIFServerPrx::uncheckedCast(
                _c.adapter->createProxy(
                        _c.adapter->getCommunicator()->stringToIdentity(
                                _proxyName)));
        if (m_debug)
            info << proxy->ice_getIdentity().name << ":Linked proxy for "
                    << nameMap[_proxyName];
    }
    info.flush();
    m_c = _c;
    return proxy;
}

/** 
* @brief Releases the proxy object and removes the entry from the DirtContainer
* @param _prx the client proxy pointer
* @param _c
*/
void lbto::FactoryI::destroy(const lbto::IIFServerPrx& _prx,
                             const Ice::Current& _c)
{
    try
    {
        Ice::Print info(_c.adapter->getCommunicator()->getLogger());
        _c.adapter->remove(_prx->ice_getIdentity());
        for (std::list<lbto::IIFServerPrx>::iterator p = s_dirts.m_objs.begin();
                p != s_dirts.m_objs.end(); ++p)
        {
            if ((*p)->ice_getIdentity().name == _prx->ice_getIdentity().name)
            {
                s_dirts.m_objs.erase(p);
                m_ar.DeRegister(_prx->ice_getIdentity().name);
                nameMap.erase(_prx->ice_getIdentity().name);
                if (m_debug)
                    info << _prx->ice_getIdentity().name << ":Erased proxy";
                info.flush();

                /* perhaps the break should be removed to clear all (dupliated) proxies ? RJM 2017-01-17 */
                break;
            }
        }
    }
    catch (const Ice::ObjectAdapterDeactivatedException&)
    {
        // This method is called on shutdown of the server, in which
        // case this exception is expected.
    }
}

/** 
* @brief Releases the proxy object and removes the entry from the DirtContainer
* @param _proxyName the client proxy name
* @param _c
*/
void lbto::FactoryI::destroyProxy(const std::string& _proxyName,
                                  const Ice::Current& _c)
{
    Ice::Print info(_c.adapter->getCommunicator()->getLogger());
    for (std::list<lbto::IIFServerPrx>::iterator p = s_dirts.m_objs.begin();
            p != s_dirts.m_objs.end(); ++p)
    {
        if ((*p)->ice_getIdentity().name == _proxyName)
        {
            _c.adapter->remove((*p)->ice_getIdentity());
            s_dirts.m_objs.erase(p);
            m_ar.DeRegister(_proxyName);
            nameMap.erase(_proxyName);
            if (m_debug)
                info << _proxyName << ":Erased proxy";
            info.flush();
            break;
        }
    }
}

/** @brief Get the proxy definition.
* @return the proxy name.
*/
std::string lbto::FactoryI::getProxy(const std::string& _proxyName,
                                     const Ice::Current& _c)
{
    if (nameMap.count(_proxyName))
        return nameMap[_proxyName];
    else
        return "";
}

/** 
* @brief Get the proxy instrument.
* @return the proxy instrument
*/
std::string lbto::FactoryI::getProxyInstrument(const std::string& _proxyName,
                                               const Ice::Current& _c)
{
    if (nameMap.count(_proxyName))
    {
        std::string proxyDef = nameMap[_proxyName];
        return proxyDef.substr(0, proxyDef.find(" "));
    }
    else
        return "";
}

/**
* @brief Get the proxy focal station.
* @param _proxyName
* @param _c
* @return the proxy focal station
*/
std::string lbto::FactoryI::getProxyFocalStation(const std::string& _proxyName,
                                                 const Ice::Current& _c)
{
    if (nameMap.count(_proxyName))
    {
        std::string proxyDef = nameMap[_proxyName];
        return proxyDef.substr(proxyDef.find(" at ") + 4);
    }
    else
        return "";
}

/** 
* @brief Creates a list with all the current connections.
* @param _c
* @return the list of established connections
*/
std::string lbto::FactoryI::listConnections(const Ice::Current& _c)
{
    std::ostringstream tmp;
    IceUtil::LockT < IceUtil::RecMutex > guard(__connMutex);
    for (std::list<lbto::IIFServerPrx>::iterator p = s_dirts.m_objs.begin();
            p != s_dirts.m_objs.end(); ++p)
    {
        std::string name = (*p)->ice_getIdentity().name;
        tmp << name << " : " << nameMap[name] << std::endl;
    }
    return tmp.str();
}

/**
* @brief enable/disable debug mode.
* @param  b setting b to true, it will print out debug information in the syslog.
* @param _c
*/
void lbto::FactoryI::debugMode(bool b, const Ice::Current& _c)
{
    m_debug = b;
}
