////////////////////////////////////////////////////////////////////////////////
//                                                                             /
// 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_MENUSTREAMS_H
#define BK_MENUSTREAMS_H

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class CMenuStreams
    : public CConsoleWnd
{
    CContext     *m_pContext;

public:
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CMenuStreams(CContext *i_pContext)
        : CConsoleWnd()  
        , m_pContext(i_pContext)
    {
        CConsoleWnd::sCfg l_cCfg = {};

        l_cCfg.pConsole      = &m_pContext->m_cCon;
        l_cCfg.szItemsCount  = 0;
        l_cCfg.uX            = 0;
        l_cCfg.uY            = 0;
        l_cCfg.uH            = m_pContext->m_cCon.GetHeight() - 1;
        l_cCfg.uW            = m_pContext->m_cCon.GetWidth();
        l_cCfg.pCaption      = TM("Streams");
        l_cCfg.eWindowBgColor= IConsole::eBlack;
        l_cCfg.eItemBgColor  = IConsole::eBlack;
        l_cCfg.eItemFgColor  = IConsole::eGreen;
        l_cCfg.eItemSlFgColor= IConsole::eBlue;
        l_cCfg.eItemSlBgColor= IConsole::eWhite;
        l_cCfg.uLinesPerItem = 5;

        CConsoleWnd::Init(l_cCfg);

        CConsoleWnd::PushHelpString(TM(" * Enter - view"), IConsole::eBlack, IConsole::eLightGreen);
        CConsoleWnd::PushHelpString(TM(" * Backspace - close stream (keep files)"), IConsole::eBlack, IConsole::eLightGreen);
        CConsoleWnd::PushHelpString(TM(" * Del - delete stream & files"), IConsole::eBlack, IConsole::eLightGreen);
    }             

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual size_t Print()
    {
        size_t l_szCount = 0;
        tBOOL  l_bError  = FALSE;

        if (m_bHelp)
        {
            return m_uH;
        }

        while (    (l_szCount < m_szItemsPerWnd)
                && ((tUINT64)l_szCount < m_qwItemsCount)
                && (FALSE == l_bError)
              )
        {
            if (l_szCount == m_szOffsetY)
            {
                l_bError = !PrintStream((size_t)(m_qwOffsetWnd + l_szCount), m_eItemSlFgColor, m_eItemSlBgColor);
            }
            else
            {
                l_bError = !PrintStream((size_t)(m_qwOffsetWnd + l_szCount), m_eItemFgColor, m_eItemBgColor);
            }
        
            l_szCount ++;
        }

        m_pContext->m_uiUpdateIntervalMs = 500;
        m_pContext->m_uiUpdateTimeStamp  = GetTickCount();

        return l_szCount * m_szLinesPerItem;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    tBOOL PrintStream(size_t i_szIndex, IConsole::eColor i_eFg, IConsole::eColor i_eBg)
    {
        tXCHAR              l_pIP[128]       = TM("");
        tUINT64             l_qwTime         = 0ull;
        tUINT32             l_uiYear         = 0;
        tUINT32             l_uiMonth        = 0;
        tUINT32             l_uiDay          = 0;
        tUINT32             l_uiHour         = 0;
        tUINT32             l_uiMinutes      = 0;
        tUINT32             l_uiSeconds      = 0;
        tUINT32             l_uiMilliseconds = 0;
        tUINT32             l_uiMicroseconds = 0;
        tUINT32             l_uiNanoseconds  = 0;
        const tXCHAR       *l_pType          = TM("Unknown");
        GUID                l_sGuidTl        = BK_READER_GUID_TELEMETRY;
        GUID                l_sGuidTr        = BK_READER_GUID_TRACE;
        Bk::IStorageReader *l_pReader        = m_pContext->m_cStreams[(tUINT32)i_szIndex]->pReader;
        Bk::stStorageInfo   l_sInfo          = {};
        
        if (!l_pReader)
        {
            return FALSE;
        }
        
        l_pReader->Get_Info(&l_sInfo);
        
        //i_pReader->Query_Interface(Bk::eInterfaceReader, (void *&)l_pReader);
        
        if (0 == memcmp(&l_sInfo.sType, &l_sGuidTl, sizeof(GUID)))
        {
            l_pType = TM("Telemetry");
        }
        else if (0 == memcmp(&l_sInfo.sType, &l_sGuidTr, sizeof(GUID)))
        {
            l_pType = TM("Trace");
        }
        
        if (!Print_SAddr((sockaddr*)&l_sInfo.sAddress, l_pIP, LENGTH(l_pIP)))
        {
            PStrCpy(l_pIP, LENGTH(l_pIP), TM("Unknown address format"));
        }
        
        l_qwTime = ((tUINT64)(l_sInfo.sProcess_Time.dwHighDateTime) << 32) + (tUINT64)l_sInfo.sProcess_Time.dwLowDateTime;
        
        UnpackLocalTime(l_qwTime, l_uiYear, l_uiMonth, l_uiDay, l_uiHour, l_uiMinutes, 
                        l_uiSeconds, l_uiMilliseconds, l_uiMicroseconds, l_uiNanoseconds);
        
        m_pContext->m_cCon.WriteTextO(i_eFg, i_eBg, m_uW, m_uW, m_szOffsetX, TM(" * Client: %s {%s}"), l_sInfo.pNode, l_pIP);
        m_pContext->m_cCon.WriteTextO(i_eFg, i_eBg, m_uW, m_uW, m_szOffsetX, TM("     Process: ID%d {%s} Time:%.4d.%.2d.%.2d %.2d:%.2d:%.2d"), 
               l_sInfo.dwProcess_ID,
               l_sInfo.pProcess_Name,
               l_uiYear, 
               l_uiMonth,
               l_uiDay,
               l_uiHour,
               l_uiMinutes,
               l_uiSeconds
              );
        
        l_qwTime = ((tUINT64)(l_sInfo.sStream_Time.dwHighDateTime) << 32) + (tUINT64)l_sInfo.sStream_Time.dwLowDateTime;
        
        UnpackLocalTime(l_qwTime, l_uiYear, l_uiMonth, l_uiDay, l_uiHour, l_uiMinutes, 
                        l_uiSeconds, l_uiMilliseconds, l_uiMicroseconds, l_uiNanoseconds);
        
        m_pContext->m_cCon.WriteTextO(i_eFg, i_eBg, m_uW, m_uW, m_szOffsetX, TM("     %s stream: {%s} Time:%.4d.%.2d.%.2d %.2d:%.2d:%.2d"),
               l_pType,
               l_sInfo.pStream_Name,
               l_uiYear, 
               l_uiMonth,
               l_uiDay,
               l_uiHour,
               l_uiMinutes,
               l_uiSeconds
              );
        
        if (l_pReader)
        {
            Bk::stStorageDesc l_cDesc = {};
            tXCHAR l_pDesc[128];
            l_cDesc.pText = l_pDesc;
            l_cDesc.szTextMax = LENGTH(l_pDesc);
            l_pReader->Get_Description(l_cDesc);
            m_pContext->m_cCon.WriteTextO(i_eFg, i_eBg, m_uW, m_uW, m_szOffsetX, TM("     Description: {%s}"), l_pDesc);
            
            tXCHAR *l_pPath = NULL;
            l_pReader->Get_Path(&l_pPath);
            if (l_pPath)
            {
                m_pContext->m_cCon.WriteTextO(i_eFg, i_eBg, m_uW, m_uW, m_szOffsetX, TM("     Path: {%s}"), l_pPath);
                free(l_pPath);
            }
        }
        return TRUE;
    }


    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual tBOOL ProcessKey(tUINT16 i_xChar)
    {
        if (m_bError)
        {
            return FALSE;
        }

        if (m_bHelp)
        {
            return CConsoleWnd::ProcessKey(i_xChar);
        }

        tBOOL l_bReturn = FALSE;

        if ((tUINT16)IConsole::eKeyEnter == i_xChar)
        {
            tUINT64             l_qwIndex   = m_qwOffsetWnd + m_szOffsetY;
            CContext::stStream *l_pStream   = m_pContext->m_cStreams[(tUINT32)l_qwIndex];
            Bk::stStorageInfo   l_sInfo     = {};

            m_pContext->m_pElActiveStream = m_pContext->m_cStreams.Get_ByIndex((tUINT32)l_qwIndex);
            
            if (    (l_pStream)
                 && (l_pStream->pReader)
               )
            {
                l_pStream->pReader->Get_Info(&l_sInfo);
            
                Bk::IViewer *l_iViewer = m_pContext->m_pBaical->Create_Viewer((WND_HANDLE)(&m_pContext->m_cCon),
                                                                              &l_sInfo.sType,
                                                                              l_pStream->pReader,
                                                                              l_pStream->pExtra,
                                                                              NULL);

                if (l_iViewer)
                {
                    l_iViewer->Show();
                    l_iViewer->Release();
                    l_iViewer = NULL;
                }

                m_pContext->m_uiUpdateIntervalMs = 1;
                m_pContext->m_uiUpdateTimeStamp  = GetTickCount();
            }

            l_bReturn = TRUE;
        }
        else if (    ((tUINT16)IConsole::eKeyDel == i_xChar)
                  || ((tUINT16)IConsole::eKeyBackSpace == i_xChar)
                )
        {
            size_t      l_szIndex = (size_t)m_qwOffsetWnd + m_szOffsetY;
            pAList_Cell l_pEl     = m_pContext->m_cStreams.Get_ByIndex((tUINT32)l_szIndex);
            tBOOL       l_bFiles  = ((tUINT16)IConsole::eKeyDel == i_xChar);

            if (l_pEl)
            {
                if (l_pEl == m_pContext->m_pElActiveStream)
                {
                    m_pContext->m_pElActiveStream = NULL;
                }

                pAList_Cell l_pElNext = m_pContext->m_cStreams.Get_Next(l_pEl);
                if (l_bFiles)
                {
                    CContext::stStream *l_pStream = m_pContext->m_cStreams.Get_Data(l_pEl);
                    l_pStream->pReader->Delete();
                }

                m_pContext->m_cStreams.Del(l_pEl, TRUE);
                m_pContext->m_uiUpdateIntervalMs = 1;
                m_pContext->m_uiUpdateTimeStamp  = GetTickCount();
                l_bReturn                        = TRUE;
                SetItemsCount((size_t)m_qwItemsCount - 1);

                if (!l_pElNext)
                {
                    if (m_qwOffsetWnd)
                    {
                        m_qwOffsetWnd --;
                    }
                    else if (m_szOffsetY)
                    {
                        m_szOffsetY--;
                    }
                }
            }
        }
        else if ((tUINT16)IConsole::eKeyEsc == i_xChar)
        {
            m_pContext->m_pMenu              = m_pContext->m_pMenus[CContext::eMenuMain];
            m_pContext->m_uiUpdateIntervalMs = 1;
            m_pContext->m_uiUpdateTimeStamp  = GetTickCount();
            l_bReturn                        = TRUE;
        }
        else
        {
            l_bReturn = CConsoleWnd::ProcessKey(i_xChar);
        }

        return l_bReturn;
    }

};


#endif //BK_MENUSTREAMS_H
