// $Header: https://oberon.oapd.inaf.it/shins/trunk/shins/src/tiptilt_ctrl/bcu/Interface/Sharknir/Bcu/OverallDiagnosticRecordRingBuffer.h 1000 2018-10-31 13:28:26Z depa $
#pragma once

#include "tiptilt_ctrl/bcu/Interface/Sharknir/Bcu/OverallDiagnosticRecordBuffer.h"
#include "util/SharedPtr.h"

#include <Nice/Util/Exception.h>
#include <Nice/Time.h>
#include <Nice/Util/Sync.h>

#include <boost/circular_buffer.hpp>


namespace Sharknir { namespace Bcu {


class OverallDiagnosticRecordRingBuffer : public OverallDiagnosticRecordBuffer
{
public:
    OverallDiagnosticRecordRingBuffer(size_t capacity,
            size_t recordOutOfOrderRange);

    /** @note overridden */
    virtual size_t getCapacity();

    /** @note overridden */
    virtual size_t getSize();

    /** @note overridden */
    virtual size_t getNumOfDuplicatedSlopeRecords();

    /** @note overridden */
    virtual size_t getNumOfDuplicatedCcdRecords();

    /** @note overridden */
    virtual size_t getNumOfDuplicatedAsmRecords();

    /** @note overridden */
    virtual size_t getNumOfInsertedSlopeRecords();

    /** @note overridden */
    virtual size_t getNumOfInsertedCcdRecords();

    /** @note overridden */
    virtual size_t getNumOfInsertedAsmRecords();

    /** @note overridden */
    virtual FrameCounter getHighestReceivedFrameCounter();

    /** @note overridden */
    virtual size_t getNumOfLateSlopeRecords();

    /** @note overridden */
    virtual size_t getNumOfLateCcdRecords();

    /** @note overridden */
    virtual size_t getNumOfLateAsmRecords();

    /** @note overridden */
    virtual void clear();

    /** @note overridden */
    virtual void insertSlopeRecord(const FrameCounter frameCounter,
            const Basda::Microgate::ByteBufferPtr& buffer);

    /** @note overridden */
    virtual void insertCcdRecord(const FrameCounter frameCounter,
            const Basda::Microgate::ByteBufferPtr& buffer);

    /** @note overridden */
    virtual void insertAsmRecord(const FrameCounter frameCounter,
            const Basda::Microgate::ByteBufferPtr& buffer);

    /** @note overridden */
    virtual SeqOverallDiagnosticRecordPtr getPastOverallDiagnosticRecords(
            const size_t nMaxRecords);

    /** @note overridden */
    virtual SeqOverallDiagnosticRecordPtr getFutureOverallDiagnosticRecords(
            const size_t nMaxRecords, const Nice::Time& timeout);

    /** @note overridden */
    virtual SeqOverallDiagnosticRecordPtr getPastCcdOverallDiagnosticRecords(
            const size_t nMaxRecords);

    /** @note overridden */
    virtual SeqOverallDiagnosticRecordPtr getPastSlopeOverallDiagnosticRecords(
            const size_t nMaxRecords);

    /** @note overridden */
    virtual SeqOverallDiagnosticRecordPtr getFutureCcdOverallDiagnosticRecords(
            const size_t nMaxRecords, const Nice::Time& timeout);

    /** @note overridden */
    virtual SeqOverallDiagnosticRecordPtr getFutureSlopeOverallDiagnosticRecords(
            const size_t nMaxRecords, const Nice::Time& timeout);

private:
    struct ArrivalAlarm
    {
        ArrivalAlarm()
        {
            nFrameCounters= NULL;
            nSlopeRecords= NULL;
            nCcdRecords= NULL;
            nAsmRecords= NULL;
        }

        ~ArrivalAlarm()
        {
            free(nFrameCounters);
            free(nSlopeRecords);
            free(nCcdRecords);
            free(nAsmRecords);
        }

        size_t *nFrameCounters;
        size_t *nSlopeRecords;
        size_t *nCcdRecords;
        size_t *nAsmRecords;
    };
    SHARKNIR_DECLARE_BOOST_SP(ArrivalAlarm);
    typedef std::vector<ArrivalAlarmPtr> ArrivalAlarmContainer;

    struct FrameCounterMatch
    {
        FrameCounterMatch(const FrameCounter fc) :
            frameCounter_(fc)
        {
        }

        inline bool operator()(const OverallDiagnosticRecordPtr& record)
        {
            return static_cast<FrameCounter>(record->frameCounter) ==
                   frameCounter_;
        }
        FrameCounter frameCounter_;
    };


    size_t checkAndAdjustNumOfRequestedRecords(size_t nMaxRecords);
    void checkBuffer(const Basda::Microgate::ByteBufferPtr& buffer);

    void assignBuffer(Sharknir::Bcu::SeqByte& destinationRecordBuffer,
                      const Basda::Microgate::ByteBufferPtr sourceBuffer,
                      size_t& duplicatedReceivedRecordsCounter);

    void detectLateFrameCounter(const FrameCounter frameCounter,
            const std::string& recordTypeStr, size_t *lateRecordCounter);

    OverallDiagnosticRecordPtr findRecordFor(FrameCounter frameCounter);
    void registerArrivalAlarm(const ArrivalAlarmPtr&);
    void unregisterArrivalAlarm(const ArrivalAlarmPtr&);
    Nice::Time computeTimeoutIfAny(const Nice::Date& endTime,
            const Nice::Time& timeout);

    typedef std::vector<OverallDiagnosticRecordPtr>
        OverallDiagnosticRecordPtrContainer;
    inline SeqOverallDiagnosticRecordPtr reverseContainer(
        OverallDiagnosticRecordPtrContainer *sharedSeq);


    struct FrameCounterComparator
    {
        inline bool operator()(const OverallDiagnosticRecordPtr rec_1,
                const OverallDiagnosticRecordPtr rec_2)
        {
            return rec_1->frameCounter > rec_2->frameCounter;
        }
    };

    typedef boost::circular_buffer<OverallDiagnosticRecordPtr>
            CircularBufferType;
    CircularBufferType ring_;
    FrameCounter highestReceivedFrameCounter_;
    FrameCounter lastReceivedAsmRecordFrameCounter_;
    size_t asmRecordSkipCounter_;
    size_t delayLimitInFrameCounters_;
    size_t duplicatedSlopeRecordsReceivedCounter_;
    size_t duplicatedCcdRecordsReceivedCounter_;
    size_t duplicatedAsmRecordsReceivedCounter_;
    size_t asmRecordsInsertedCounter_;
    size_t ccdRecordsInsertedCounter_;
    size_t slopeRecordsInsertedCounter_;
    size_t lateAsmRecordCounter_;
    size_t lateSlopeRecordCounter_;
    size_t lateCcdRecordCounter_;
    ArrivalAlarmContainer arrivalCounters_;
    Nice::Monitor monitor_;
};

SHARKNIR_DECLARE_BOOST_SP(OverallDiagnosticRecordRingBuffer)


class OverallDiagnosticRecordRingBufferException : public Nice::Exception
{
};

inline bool isThreadSafe(const OverallDiagnosticRecordRingBuffer&)
{
    return true;
}

}
}

