/**
 * @file TimeArrayGAM.cpp
 * @brief Source file for class TimeArrayGAM
 * @date 19/05/2026
 * @author Martino Ferrari
 */

#define DLL_API

#include "AdvancedErrorManagement.h"
#include "TimeArrayGAM.h"

namespace MARTe {

TimeArrayGAM::TimeArrayGAM() :
        GAM(),
        samplingRate(1000000.0),
        anchorIsFirst(true),
        nElements(0u),
        inputTime(NULL_PTR(uint32 *)),
        outputBuf(NULL_PTR(uint64 *)) {
}

TimeArrayGAM::~TimeArrayGAM() {
}

bool TimeArrayGAM::Initialise(StructuredDataI &data) {
    bool ok = GAM::Initialise(data);
    if (ok) {
        if (!data.Read("SamplingRate", samplingRate) || samplingRate <= 0.0) {
            REPORT_ERROR(ErrorManagement::InitialisationError,
                         "TimeArrayGAM: SamplingRate > 0 is required.");
            ok = false;
        }
    }
    if (ok) {
        StreamString anchor;
        (void) data.Read("Anchor", anchor);
        if (anchor.Size() == 0u || anchor == "FirstSample") {
            anchorIsFirst = true;   /* default */
        }
        else if (anchor == "LastSample") {
            anchorIsFirst = false;
        }
        else {
            REPORT_ERROR(ErrorManagement::InitialisationError,
                         "TimeArrayGAM: Anchor must be 'FirstSample' or 'LastSample'.");
            ok = false;
        }
    }
    return ok;
}

bool TimeArrayGAM::Setup() {
    bool ok = (GetNumberOfInputSignals() == 1u) && (GetNumberOfOutputSignals() == 1u);
    if (!ok) {
        REPORT_ERROR(ErrorManagement::InitialisationError,
                     "TimeArrayGAM: exactly one input and one output signal are required.");
        return false;
    }

    inputTime = reinterpret_cast<uint32 *>(GetInputSignalMemory(0u));
    outputBuf = reinterpret_cast<uint64 *>(GetOutputSignalMemory(0u));
    ok = (inputTime != NULL_PTR(uint32 *)) && (outputBuf != NULL_PTR(uint64 *));
    if (!ok) {
        REPORT_ERROR(ErrorManagement::InitialisationError,
                     "TimeArrayGAM: failed to resolve signal memory.");
        return false;
    }

    uint32 sz = 0u;
    ok = GetSignalByteSize(OutputSignals, 0u, sz);
    if (ok) {
        nElements = sz / static_cast<uint32>(sizeof(uint64));
        ok = (nElements > 0u);
    }
    if (!ok) {
        REPORT_ERROR(ErrorManagement::InitialisationError,
                     "TimeArrayGAM: output signal must be a non-empty uint64 array.");
    }
    return ok;
}

bool TimeArrayGAM::Execute() {
    /* Period in nanoseconds — uint64 preserves sub-microsecond resolution
     * even at sampling rates > 1 MHz where the µs period would be < 1. */
    uint64 periodNs  = static_cast<uint64>(1000000000.0 / samplingRate + 0.5);
    /* Input is uint32 microseconds (LinuxTimer); convert to nanoseconds. */
    uint64 anchorNs  = static_cast<uint64>(*inputTime) * 1000u;

    if (anchorIsFirst) {
        /* out[k] = anchorNs + k * periodNs */
        for (uint32 k = 0u; k < nElements; k++) {
            outputBuf[k] = anchorNs + static_cast<uint64>(k) * periodNs;
        }
    }
    else {
        /* out[k] = anchorNs - (N-1-k) * periodNs */
        for (uint32 k = 0u; k < nElements; k++) {
            outputBuf[k] = anchorNs - static_cast<uint64>(nElements - 1u - k) * periodNs;
        }
    }
    return true;
}

CLASS_REGISTER(TimeArrayGAM, "1.0")

} /* namespace MARTe */
