/**
 * @file TriggerEngine.cpp
 * @brief Hub-side trigger FSM implementation (web client semantics).
 */

#include "TriggerEngine.h"
#include "AdvancedErrorManagement.h"

namespace StreamHub {

TriggerEngine::TriggerEngine()
    : epoch_(0u),
      state_(kTrigIdle),
      stopped_(false),
      prevValue_(0.0),
      prevValid_(false),
      trigTime_(0.0),
      firedPreSec_(0.0),
      firedPostSec_(0.0),
      firedValid_(false) {
}

void TriggerEngine::SetConfig(const TriggerConfig &cfg) {
    (void) mutex_.FastLock();
    config_ = cfg;
    /* Clamp to web UI bounds */
    if (config_.windowSec < 1.0e-4) { config_.windowSec = 1.0e-4; }
    if (config_.windowSec > 10.0)   { config_.windowSec = 10.0; }
    if (config_.prePercent < 0.0)   { config_.prePercent = 0.0; }
    if (config_.prePercent > 100.0) { config_.prePercent = 100.0; }
    epoch_++;
    prevValid_ = false;
    prevValue_ = 0.0;
    mutex_.FastUnLock();
}

TriggerConfig TriggerEngine::GetConfig() const {
    (void) mutex_.FastLock();
    TriggerConfig ret = config_;
    mutex_.FastUnLock();
    return ret;
}

uint32 TriggerEngine::GetConfigEpoch() const {
    (void) mutex_.FastLock();
    uint32 ret = epoch_;
    mutex_.FastUnLock();
    return ret;
}

void TriggerEngine::Arm() {
    (void) mutex_.FastLock();
    state_     = kTrigArmed;
    prevValid_ = false;
    prevValue_ = 0.0;
    mutex_.FastUnLock();
}

void TriggerEngine::Disarm() {
    (void) mutex_.FastLock();
    state_      = kTrigIdle;
    stopped_    = false;
    prevValid_  = false;
    prevValue_  = 0.0;
    firedValid_ = false;
    mutex_.FastUnLock();
}

void TriggerEngine::SetStopped(bool stopped) {
    (void) mutex_.FastLock();
    stopped_ = stopped;
    mutex_.FastUnLock();
}

bool TriggerEngine::GetStopped() const {
    (void) mutex_.FastLock();
    bool ret = stopped_;
    mutex_.FastUnLock();
    return ret;
}

void TriggerEngine::CheckSample(float64 t, float64 v) {
    (void) mutex_.FastLock();

    if (state_ != kTrigArmed) {
        mutex_.FastUnLock();
        return;
    }
    if (!prevValid_) {
        prevValue_ = v;
        prevValid_ = true;
        mutex_.FastUnLock();
        return;
    }

    const float64 thr = config_.threshold;
    const bool up   = (prevValue_ < thr) && (v >= thr);
    const bool down = (prevValue_ > thr) && (v <= thr);
    prevValue_ = v;

    bool fired = false;
    switch (config_.edge) {
        case kEdgeRising:  fired = up;          break;
        case kEdgeFalling: fired = down;        break;
        case kEdgeBoth:    fired = (up || down); break;
        default: break;
    }

    if (fired) {
        state_        = kTrigCollecting;
        trigTime_     = t;
        /* Latch the window at fire time so later config edits do not
         * affect this capture (web client snap._preS/_postS). */
        firedPreSec_  = config_.windowSec * config_.prePercent / 100.0;
        firedPostSec_ = config_.windowSec - firedPreSec_;
        firedValid_   = true;
        REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information,
                            "TriggerEngine: fired at t=%.6f (pre=%.4fs post=%.4fs)",
                            t, firedPreSec_, firedPostSec_);
    }

    mutex_.FastUnLock();
}

TrigState TriggerEngine::GetState() const {
    (void) mutex_.FastLock();
    TrigState ret = state_;
    mutex_.FastUnLock();
    return ret;
}

bool TriggerEngine::GetFiredWindow(float64 &trigTime, float64 &preSec,
                                   float64 &postSec) const {
    (void) mutex_.FastLock();
    const bool ok = firedValid_;
    if (ok) {
        trigTime = trigTime_;
        preSec   = firedPreSec_;
        postSec  = firedPostSec_;
    }
    mutex_.FastUnLock();
    return ok;
}

void TriggerEngine::MarkTriggered() {
    (void) mutex_.FastLock();
    if (state_ == kTrigCollecting) {
        state_ = kTrigTriggered;
    }
    mutex_.FastUnLock();
}

} /* namespace StreamHub */
