#include <cassert>
#include "xf/timeout.h"
#include "xf/initialevent.h"
#include "xf/behavior.h"
#include "trace/trace.h"


XFBehavior::XFBehavior() {
    this->deleteOnTerminate_ = false;
}

XFBehavior::~XFBehavior() {
}

void XFBehavior::startBehavior() {
    GEN(XFInitialEvent());
}

/**
 * @brief Pushes the given event to the dispatcher.
 *
 * If the event has no behavior assigned, the behavior of this object is assigned.
 * @param pEvent Event to push to the dispatcher.
 */
void XFBehavior::pushEvent(XFEvent *pEvent) {
    if(pEvent->getBehavior()==nullptr) {
        pEvent->setBehavior(this);
    }
    this->getDispatcher()->pushEvent(pEvent);
}

bool XFBehavior::deleteOnTerminate() const {
    return this->deleteOnTerminate_;
}

void XFBehavior::setDeleteOnTerminate(bool deleteBehaviour) {
    this->deleteOnTerminate_ = deleteBehaviour;
}

const XFEvent *XFBehavior::getCurrentEvent() const {
    return this->pCurrentEvent_;
}

interface::XFDispatcher *XFBehavior::getDispatcher() {
    return interface::XFDispatcher::getInstance();
}

/**
 * @brief Returns a reference to the actually processed timeout.
 *
 * Will work only if the current event is of type IXFEvent::Timeout.
 *
 * @return Pointer to the currently processed timeout or nullptr if the current event is not a timeout.
 */
const XFTimeout *XFBehavior::getCurrentTimeout() {
    if(pCurrentEvent_->getEventType() == XFEvent::Timeout) {
        return (XFTimeout*) this->pCurrentEvent_;
    } else {
        return nullptr;
    }
}

void XFBehavior::setCurrentEvent(const XFEvent *pEvent) {
    this->pCurrentEvent_ = pEvent;
}

/**
 * @brief Processes the given event.
 *
 * The dispatcher calls this method every time a new event
 * or timeout arrives. The process method stores the actual
 * event using the #_pCurrentEvent and then calls
 * processEvent().
 *
 * In case you intend to call process() inside your state machine you
 * are doing something wrong! Call GEN() or pushEvent() instead!
 *
 * @param pEvent Event to process
 * @return if the behavior is terminated (basically a boolean)
 */
XFBehavior::TerminateBehavior XFBehavior::process(const XFEvent *pEvent) {
    this->setCurrentEvent(pEvent);

    // Get status of the event processing
    XFEventStatus status = XFEventStatus::Unknown;
    status = this->processEvent();

    // Check if event was consumed and if it should be deleted
    if(status == XFEventStatus::Consumed && pEvent->deleteAfterConsume()) {
        delete pEvent;
    }

    // Check if the behavior is terminated and return the result
    XFBehavior::TerminateBehavior terminateBehavior = false;
    if(status == XFEventStatus::Terminate) {
        terminateBehavior = true;
    }
    return terminateBehavior;
}
