#include <cassert>
#include <config/xf-config.h>

#if (USE_XF_COMMON_DISPATCHER_CLASS != 0)
#if defined(XF_TRACE_EVENT_PUSH_POP) && (XF_TRACE_EVENT_PUSH_POP != 0)
    #include "trace/trace.h"
#endif // XF_TRACE_EVENT_PUSH_POP
#include "xf/interface/timeoutmanager.h"
#include "xf/interface/behavior.h"
#include "xf/interface/mutex.h"
#include "dispatcher.h"

using interface::XFTimeoutManager;      // Allows to use expression 'XFTimeoutManager' instead of 'interface::XFTimeoutManager'.
using interface::XFBehavior;            // Expression XFBehavior used in code below is in fact the XFBehavior interface class.
using Mutex = interface::XFMutex;       // Rename XFMutex interface class to Mutex for easier use.

// Implementation of the getInstance() method of the 'interface::XFDispatcher' class.
//
// Note: The implementation is done here because only in this file the real XFDispatcher
//       class is known (port specific class). An instance of the XFDispatcher class is
//       returned by the 'interface::XFDispatcher' class.
interface::XFDispatcher * interface::XFDispatcher::getInstance() {
    static ::XFDispatcher dispatcher;
    return &dispatcher;
}

XFDispatcher::XFDispatcher() {
    this->pMutex_ = interface::XFMutex::create();
}

XFDispatcher::~XFDispatcher() {

}

void XFDispatcher::dispatchEvent(const XFEvent *pEvent) const {
    XFBehavior::TerminateBehavior terminateBehavior;
    terminateBehavior = pEvent->getBehavior()->process(pEvent);
    if(terminateBehavior && pEvent->getBehavior()->deleteOnTerminate()) {
        delete pEvent->getBehavior();
        if(pEvent->deleteAfterConsume()) {
            delete pEvent;
        }
    }
}

void XFDispatcher::pushEvent(XFEvent *pEvent) {
    this->pMutex_->lock();
    events_.push(pEvent, false);
    this->pMutex_->unlock();
}

void XFDispatcher::scheduleTimeout(int timeoutId, int interval, interface::XFBehavior *pBehavior) {
    XFTimeoutManager::getInstance()->scheduleTimeout(timeoutId, interval, pBehavior);
}

void XFDispatcher::unscheduleTimeout(int timeoutId, interface::XFBehavior *pBehavior) {
    XFTimeoutManager::getInstance()->unscheduleTimeout(timeoutId, pBehavior);
}

void XFDispatcher::executeOnce() {
    if(!this->events_.empty()) {

        this->pMutex_->lock();
        const XFEvent *ev = this->events_.front();
        this->events_.pop();
        this->pMutex_->unlock();

        dispatchEvent(ev);
    }

}

int XFDispatcher::execute(const void *param) {
    (void) param;
    while(true){
        this->executeOnce();
    }
}


#endif // USE_XF_COMMON_DISPATCHER_CLASS
