////////////////////////////////////////////////////////////////////////////////
//                                                                             /
// 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_TRACE_H
#define BK_STREAM_TRACE_H

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/// <summary> Processor class </summary>
class CTrace
    : public CStream
{
    Bk::ITraceReader *m_iTrace; //trace reader interface
    tUINT64 m_qwPos; //last processed trace index
public:
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    CTrace(Bk::IStorageReader *i_iReader, Bk::IStreamEx *i_iExtra)
        : CStream(i_iReader, i_iExtra)
        , m_qwPos(0ull)
    {
        if (Bk::eOk != m_iReader->Query_Interface(Bk::eInterfaceTraceReader, (void*&)m_iTrace))
        {
            //Error: Can't retrieve interface of telemetry, something wrong with storage reader!;
        }
    }

    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    virtual ~CTrace()
    {
        SAFE_RELEASE(m_iTrace);
    }

    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    virtual CStream::eResult Process()
    {
        tUINT64 qwCount = 0ull;
        tUINT64 qwStartPos = m_qwPos;
        tBOOL bIsOnLine = FALSE;
        CStream::eResult eResult = CStream::eDone;
        Bk::stTrace stTrace = {};
        //trace text formatting is most expensive operation, so use it only when trace text message is REQUIRED for trace item processing,
        //otherwise we advise to disable it.
        const tBOOL bFormatText = FALSE; 

        //get current amount of traces in the stream, this is maximum amount of traces available for the time being
        m_iTrace->Get_Count(&qwCount);

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

        while (m_qwPos < qwCount)
        {
            if (Bk::eOk == m_iTrace->Get_Trace(m_qwPos, &stTrace, bFormatText))
            {
                //here you can process trace message, all trace fields are described inside file <PAPI_Storage_Trace.h>, please take a look
                //to description for stTrace structure.
                //N.B.: If (FALSE == bFormatText) then stTrace.pText will have NULL value.
                 
                //Example of time formatting:
                // SYSTEMTIME stSystemTime = {};
                // FILETIME stFileTime = {};
                // UINT64 l_qwTime = stTrace.qwTime;          //getting raw trace 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++;

            //we recommend to proceed trace items by bunches and let other stream be processed by main plugin thread. This is just simplest
            //example how to interrupt processing loop after 1000 iterations. 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) > 1000)
            {
                break;
            }
        }

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

        return eResult;
    }
};

#endif //BK_STREAM_TRACE_H