/* $Header: https://svn.mpia.de/gulli/TwiceAsNice/branch/unstable/TwiceAsNice/basda/src/Interface/Basda/ServiceWorkerInterface.cc 15824 2019-07-08 14:53:41Z briegel $
*/

#include "Basda/ServiceWorkerInterface.h"
//#include <Basda/ServiceWorkerReadWaitDataWithMultiCompletionProxy.hh>
#include <Basda/ServiceStateMachine.h>
#include <Nice/App/ConfigClient.h>
#include <Nice/Property/Joint.hh>
#include <Nice/Util/UUID.h>

Basda::ServiceWorkerInterfaceWatchdogListener::ServiceWorkerInterfaceWatchdogListener(const ServiceWorkerInterfacePtr & _if)
    : m_if(_if)
{
}

Basda::ServiceWorkerInterfaceWatchdogListener::~ServiceWorkerInterfaceWatchdogListener()
{

}

void Basda::ServiceWorkerInterfaceWatchdogListener::update(bool _reachable)
{
    Nice::JointPtrVector childs;
    m_if->config()->leafsWithBridgeType<Nice::PropertyBridgeReadWaitProxy>(childs, m_if->identity());
    for(Nice::JointPtrVector::iterator it = childs.begin(); it != childs.end(); it++)
    {
        if(_reachable)
        {
            (*it)->leaf()->getBridge<Nice::PropertyBridgeReadWaitProxy>(m_if->identity())->signal(Nice::OK);
        }
        else
        {
            (*it)->leaf()->getBridge<Nice::PropertyBridgeReadWaitProxy>(m_if->identity())->signal(Nice::UNSYNCHED);
        }
    }
}

std::map<std::string, Basda::ServiceWorkerInterfacePtr> Basda::ServiceWorkerInterface::s_inst;


Basda::ServiceWorkerInterface::ServiceWorkerInterface(const Nice::JointPtr & _config, const Nice::AppConfigClientPtr & _cc )
    : m_identity(Nice::generateUUID()), m_id( Nice::Date::now().toNanoSeconds()), m_config(_config), m_cc(_cc)
{
   m_config->leaf("STATE")->applyBridge(m_stateBridgeReadWaitProxy = new Nice::PropertyBridgeReadWaitProxy(m_id, m_identity.c_str()));
   if( m_config->exist("CMD"))
      m_config->leaf("CMD")->applyBridge(m_stopReadWaitProxy = 
             new Basda::ServiceWorkerReadWaitCompletionProxy(m_id, m_identity.c_str()));
     
     
   
}

void Basda::ServiceWorkerInterface::addListener()
{
    Nice::AppConfigClientPtr cc = Nice::AppConfigClient::getClientByNode(m_config);
    if(cc)
    {
        m_listener = new ServiceWorkerInterfaceWatchdogListener( this );
        cc->applyWatchdogListener( m_listener );
    }

}

void Basda::ServiceWorkerInterface::addAttribute(const Nice::JointPtr & _node)
{
    Nice::PropertyAttrMap amap = _node->leaf()->attributeMap();
    for(Nice::PropertyAttrMap::iterator it = amap.begin(); it != amap.end(); it++)
    {
        try
        {
            std::string::size_type firstPos = it->first.find_first_of('+');
            if(firstPos != std::string::npos)
            {
              _node->leaf(it->first.substr(0,firstPos))->applyAttribute(it->first.substr(firstPos+1), it->second);
            }
        }
        catch (const Nice::Exception & _e)
        {
            E_LOG(_e.what());
        }
        catch (...)
        {
            E_LOG("unknown error");
        }
    }
}

void Basda::ServiceWorkerInterface::abort()
{
     if( m_config->exist("CMD"))
          m_config->node("CMD")->set<Nice::Completion>(Nice::Completion::abort(), m_id);
}

bool Basda::ServiceWorkerInterface::stop(const Nice::Time & _timeout)
{
//    m_config->node("CMD")->set<Nice::Completion>(Nice::Completion::stop(), m_id);
//    U2_LOG("stop " << m_id);
    Nice::Completion c = Nice::Completion::stop();
    m_stopReadWaitProxy->set(c);
    if(_timeout > Nice::Time())
    {
      return m_stopReadWaitProxy->timedWait(_timeout);
    }
//    m_stopReadWaitProxy->wait();
//    U2_LOG("stop done");
    return true;
}


Basda::ServiceState Basda::ServiceWorkerInterface::state()
{
   return m_config->getAtNode<Basda::ServiceStateMachine>("STATE").now();
}

bool Basda::ServiceWorkerInterface::changeState ( Basda::ServiceState _state, const Nice::Time & _timeout)
{
    Basda::ServiceStateMachine state = m_config->getAtNode<Basda::ServiceStateMachine>("STATE");
    if(state.now() == _state) return true;
    state.setNext(_state);
    m_config->setAtNode<Basda::ServiceStateMachine>("STATE", state, m_id);
    bool result = waitForState(_state, _timeout);
    return result;
}

bool Basda::ServiceWorkerInterface::waitForState ( Basda::ServiceState _state, const Nice::Time & _timeout)
{
    Nice::Timer timer;
    timer.start(_timeout);
    while ( Basda::ServiceWorkerInterface::state() != _state )
    {
        if(_timeout == Nice::Time())
        {    
            m_stateBridgeReadWaitProxy->wait();
        }
        else
        {
            if(timer.elapsed()) return false;
            m_stateBridgeReadWaitProxy->timedWait(timer.now());
        }
    }
    return true;
}


bool Basda::ServiceWorkerInterface::waitForActiveState( const Nice::Time & _timeout)
{
    Nice::Timer timer;
    timer.start(_timeout);
    while (! ( Basda::ServiceWorkerInterface::state() == Basda::ONLINE || 
               Basda::ServiceWorkerInterface::state() == Basda::WORKING) )
    {
        if(_timeout == Nice::Time())
        {    
            m_stateBridgeReadWaitProxy->wait();
        }
        else
        {
            if(timer.elapsed()) return false;
            m_stateBridgeReadWaitProxy->timedWait(timer.now());
        }
    }
    return true;
}
