// $Header: https://oberon.oapd.inaf.it/shins/trunk/shins/src/tiptilt_ctrl/bcu/Interface/Sharknir/Bcu/ServiceFactory.cpp 3851 2022-03-10 14:05:11Z depa $
#include "tiptilt_ctrl/bcu/Interface/Sharknir/Bcu/DeviceFactoryImpl.h"
#include "tiptilt_ctrl/bcu/Interface/Sharknir/Bcu/OverallDiagnosticRecordRingBuffer.h"
#include "tiptilt_ctrl/bcu/Interface/Sharknir/Bcu/PropertyName.h"
#include "tiptilt_ctrl/bcu/Interface/Sharknir/Bcu/ServiceWorker.h"
#include "tiptilt_ctrl/bcu/Interface/Sharknir/Bcu/TaNDiagnosticsDispatcherFactory.h"
#include "tiptilt_ctrl/bcu/Interface/Sharknir/Bcu/ThreadedDiagnosticsCollector.h"

#include <Basda/Basdard.h>
#include <Basda/ServiceState.h>

#include "tiptilt_ctrl/bcu/util/ClockPtr.h"
#include "tiptilt_ctrl/bcu/util/NiceClock.h"

#include <boost/make_shared.hpp>


#undef LOG_NAME
#define LOG_NAME "BcuServiceFactory"

using namespace Sharknir::Bcu;
using Sharknir::Bcu::PropertyName;
using boost::make_shared;
using std::string;


namespace Sharknir { namespace Bcu {


class ServiceFactory
{
public:
    ServiceFactory(const Nice::JointPtr& config) :
        config_(config)
    {
    }

    OverallDiagnosticRecordBufferPtr buildDiagnosticRecordRingBuffer()
    {
       const size_t RING_BUFFER_SIZE = 10*1000;
       const size_t RECORD_OUT_OF_ORDER_RANGE = 100;
       const OverallDiagnosticRecordRingBufferPtr ring = make_shared<OverallDiagnosticRecordRingBuffer>(
                       RING_BUFFER_SIZE, RECORD_OUT_OF_ORDER_RANGE);
       assert(isThreadSafe(*ring));
       return ring;
    }

    void assertPropertyExistance(const string& propertyName)
    {
        SHARKNIR_PRECONDITION(config_->exist(propertyName),
            string("The property ") + propertyName + " exists.");
    }

    ServiceWorkerPtr buildServiceWorker()
    {
        Sharknir::Bcu::DeviceFactoryImplPtr deviceFactory(new Sharknir::Bcu::DeviceFactoryImpl(config_));
        OverallDiagnosticRecordBufferPtr diagBuffer = buildDiagnosticRecordRingBuffer();

        string propertyName = PropertyName::diagnosticsDestinationUdpPort();
        assertPropertyExistance(propertyName);
        DiagnosticsDispatcherFactoryPtr slopeBcuDispatcherFactory(new
            TaNDiagnosticsDispatcherFactory(config_->node(propertyName)->leaf(), diagBuffer));

        // propertyName= PropertyName::asmDiagnosticsReceiptionUdpPort();
        // assertPropertyExistance(propertyName);
        // DiagnosticsDispatcherFactoryPtr asmBcuDispatcherFactory(
        //     new TaNDiagnosticsDispatcherFactory(
        //      config_->node(propertyName)->leaf(), diagBuffer));

        // ActiveDiagnosticsCollectorPtr activeDispatcher(
        //     new ThreadedDiagnosticsCollector(slopeBcuDispatcherFactory,
        //             asmBcuDispatcherFactory));
        ActiveDiagnosticsCollectorPtr activeDispatcher(new
            ThreadedDiagnosticsCollector(slopeBcuDispatcherFactory));

        // TODO 2013-07-18 check for alive active dispatcher in service worker
        Sharknir::util::ClockPtr clock(new Sharknir::util::NiceClock());
        ServiceWorkerPtr worker= new Sharknir::Bcu::ServiceWorker(config_, diagBuffer, clock);
        worker->setDeviceFactory(deviceFactory);
        worker->setActiveDiagnosticsCollector(activeDispatcher);
        worker->setMaxNumOfTolerableCommunicationGlitches(1);

        return worker;
    }
private:
    Nice::JointPtr config_;
};

}
}

extern "C" void instantService(const Nice::JointPtr& config)
{
    std::string name= config->getAtNode<std::map<std::string, std::string> > ("LOAD")["NAME"];

    N_LOG("Creating BCU service " << name);

    ServiceFactory factory(config);
    Basda::Basdard::addWorker(name, factory.buildServiceWorker());

    Nice::Application::distribute(config);
}

