////////////////////////////////////////////////////////////////////////////////
//                                                                             /
// 2012-2019 (c) Baical                                                        /
//                                                                             /
// This library is free software; you can redistribute it and/or               /
// modify it under the terms of the GNU Lesser General Public                  /
// License as published by the Free Software Foundation; either                /
// version 3.0 of the License, or (at your option) any later version.          /
//                                                                             /
// This library is distributed in the hope that it will be useful,             /
// but WITHOUT ANY WARRANTY; without even the implied warranty of              /
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU           /
// Lesser General Public License for more details.                             /
//                                                                             /
// You should have received a copy of the GNU Lesser General Public            /
// License along with this library.                                            /
//                                                                             /
////////////////////////////////////////////////////////////////////////////////
#ifndef BK_STREAM_TELEMETRY_H
#define BK_STREAM_TELEMETRY_H

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/// <summary> Processor class </summary>
class CTelemetry
    : public CStream
{
    Bk::ITelemetryReader *m_iTelemetry; //telemetry reader interface
    tUINT64 m_qwPos; //last processed index
    Bk::stTelemetrySample *m_pBuffer; //buffer for samples to be processed
    tUINT32 m_dwMaxCount; //max count telemetry samples in the buffer
public:
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    CTelemetry(Bk::IStorageReader *i_iReader, Bk::IStreamEx *i_iExtra)
        : CStream(i_iReader, i_iExtra)
        , m_iTelemetry(NULL)
        , m_qwPos(0ull)
        , m_pBuffer(NULL)
        , m_dwMaxCount(64)
    {
        if (Bk::eOk != m_iReader->Query_Interface(Bk::eInterfaceTelemetryReader, (void*&)m_iTelemetry))
        {
            //Error: Can't retrieve interface of telemetry, something wrong with storage reader!;
        }

        m_pBuffer = (Bk::stTelemetrySample *)malloc(m_dwMaxCount * sizeof(Bk::stTelemetrySample));
    }

    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    virtual ~CTelemetry()
    {
        SAFE_RELEASE(m_iTelemetry);

        if (m_pBuffer)
        {
            free(m_pBuffer);
            m_pBuffer = NULL;
        }
    }

    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    virtual CStream::eResult Process()
    {
        Bk::stTelemetryInfo stInfo = {};
        tBOOL bIsOnLine = FALSE;
        CStream::eResult eResult = CStream::eDone;

        tUINT32 dwCount = 0;
        tUINT64 qwStartPos = m_qwPos;

        //get current telemetry channel state 
        m_iTelemetry->Get_Info(&stInfo);

        //we need to check is current stream is still active - if yes we may receive another telemetry samples later
        if (m_iExtra)
        {
            m_iExtra->Is_Active(&bIsOnLine);
        }

        while (m_qwPos < stInfo.qwSamples)
        {
            dwCount = 0;
            if (Bk::eOk == m_iTelemetry->Get_Samples(m_qwPos, m_pBuffer, m_dwMaxCount, &dwCount))
            {
                for (tUINT32 dwI = 0; dwI < dwCount; dwI++)
                {
                    //here you can process every sample, all sample's fields are described inside file <PAPI_Storage_Telemetry.h>, please 
                    //take a look to description for stTelemetrySample structure.
                    //m_pBuffer[dwI].bID - counter Id
                    //m_pBuffer[dwI].llValue - sample raw value
                    //m_pBuffer[dwI].qwTime - sample time

                    //Example of time formatting:
                    // SYSTEMTIME stSystemTime = {};
                    // FILETIME stFileTime = {};
                    // UINT64 l_qwTime = m_pBuffer[dwI].qwTime;   //getting raw time in 100ns intervals
                    // DWORD  l_dwReminder = l_qwTime % 10000ull; //calculate amount of nano and microseconds
                    // DWORD  l_dwNano = l_qwTime % 10ull;
                    // DWORD  l_dwMicro = l_dwReminder / 10u;
                    // 
                    // l_qwTime -= l_dwReminder;  
                    // l_qwTime += m_qwTime;  //adding stream time to calculate global time of trace item
                    // FileTimeToLocalFileTime((FILETIME*)&l_qwTime, &stFileTime);
                    // FileTimeToSystemTime(&stFileTime, &stSystemTime);
                    // 
                    // printf("Time : %02d.%02d.%04d %02d:%02d:%02d.%03d'%03d`%d\n", 
                    //        (DWORD)stSystemTime.wDay,
                    //        (DWORD)stSystemTime.wMonth,
                    //        (DWORD)stSystemTime.wYear,
                    //        (DWORD)stSystemTime.wHour,
                    //        (DWORD)stSystemTime.wMinute,
                    //        (DWORD)stSystemTime.wSecond,
                    //        (DWORD)stSystemTime.wMilliseconds,
                    //        (DWORD)l_dwMicro,
                    //        (DWORD)l_dwNano
                    //       );
                }
            }
            else //something is wrong !
            {
                break;
            }

            m_qwPos += dwCount;

            //we recommend to proceed telemetry samples by bunches and let other stream be processed by main plugin thread. This is just 
            //simplest example how to interrupt processing loop after 10000 samples processing. Please take in account that plugin thread
            //can process at the same time many different streams and scheduling is your responsibility.
            //N.B.: The golden rule is: do not block plugin thread inside CStream::Process() function call
            if ((m_qwPos - qwStartPos) > 10000)
            {
                break;
            }
        }

        if (bIsOnLine)
        {
            eResult = (m_qwPos == qwStartPos) ? CStream::eIdling : CStream::eProcessing;
        }
        else
        {
            eResult = (m_qwPos >= stInfo.qwSamples) ? CStream::eDone : CStream::eProcessing;
        }

        return eResult;
    }
};

#endif //BK_STREAM_TELEMETRY_H