////////////////////////////////////////////////////////////////////////////////
//                                                                             /
// 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.                                            /
//                                                                             /
////////////////////////////////////////////////////////////////////////////////
#include "CCommon.h"
#include "CMenuMain.h"
#include "CMenuOpen.h"
#include "CMenuStreams.h"

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CContext::CContext(const tXCHAR *i_pConfigPath)
    : m_pBaical(NULL)
    , m_iSubscriber(NULL)
    , m_pElActiveStream(NULL)
    , m_szNewStreams(0)
    , m_bError(FALSE)     
    , m_pMenu(NULL)
    , m_uiUpdateIntervalMs(1)
    , m_uiUpdateTimeStamp(GetTickCount())
    , m_bExit(FALSE)
{
    memset(m_pMenus, 0, sizeof(m_pMenus));

    if (!CFSYS::File_Exists(i_pConfigPath))
    {
        m_cCon.WriteText(IConsole::eWhite,
                         IConsole::eRed, 0, 
                         m_cCon.GetWidth(), 
                         TM("Error: configuration file isn't specified or exists, example: CBaical Baical.xml\n"));
        m_bError = TRUE;
    }

    if (!m_bError)
    {
        CBaical::eError l_eError = CBaical::eErrorNone;
        CWString        l_cCrashPath;
        CFSYS::GetUserDirectory(&l_cCrashPath);
        l_cCrashPath.Append(1, TM("/Baical/CrashDumps/"));

        m_pBaical = new CBaical(i_pConfigPath, l_cCrashPath.Get(), CBaical::eModeCLI);
        if (    (NULL == m_pBaical)
             || (!m_pBaical->Get_Initialized(l_eError))
           )
        {
            m_cCon.WriteText(IConsole::eWhite, 
                             IConsole::eRed, 0, 
                             m_cCon.GetWidth(), 
                             TM("Error: Baical is not initialized, error = %d\n"), (int)l_eError);
            m_bError = TRUE;
        }
    }

    if (!m_bError)
    {
        m_cCon.SetTextAttr(IConsole::eGreen, IConsole::eBlack);
        m_cCon.Clear();
        m_cCon.SetCursor(0,0);

        m_pBaical->Query_Interface(Bk::eInterfaceStreams, (void*&)m_iSubscriber);

        m_pMenus[CContext::eMenuMain]      = new CMenuMain(this);
        m_pMenus[CContext::eMenuStreams]   = new CMenuStreams(this);
        m_pMenus[CContext::eMenuOpen]      = new CMenuOpen(this);

        m_pMenu = m_pMenus[CContext::eMenuMain];
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CContext::~CContext()
{
    for (int l_iI = 0; l_iI < eMenuMax; l_iI++)
    {
        if (m_pMenus[l_iI])
        {
            delete m_pMenus[l_iI];
            m_pMenus[l_iI] = NULL;
        }
    }

    m_cStreams.Clear(TRUE);

    SAFE_RELEASE(m_iSubscriber);

    if (m_pBaical)
    {
        delete m_pBaical;
        m_pBaical = NULL;
    }
    m_szNewStreams = 0;

    m_cCon.SetTextAttr(IConsole::eWhite, IConsole::eBlack);

    if (!m_bError)
    {
        m_cCon.Clear();
        m_cCon.SetCursor(0,0);
    }

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int CContext::Execute()
{
    if (m_bError)
    {
        return -1;
    }
                       
    Bk::IStreamEx      *l_pExtra  = NULL;
    Bk::IStorageReader *l_pReader = NULL;
    tUINT32             l_dwWait  = 100;
    IConsole::sInput    l_stInput = {};

    while (!m_bExit)
    {
        if (Bk::eOk == m_iSubscriber->Pull(l_pReader, l_pExtra, l_dwWait))
        {
            AddStream(l_pReader, l_pExtra);
            l_pReader, l_pExtra = NULL;
        }

        if (    (m_uiUpdateIntervalMs)
             && (m_uiUpdateIntervalMs <= CTicks::Difference(GetTickCount(), m_uiUpdateTimeStamp))
           )
        {
            m_uiUpdateIntervalMs = 0;
            m_pMenu->Redraw();
        }

        l_dwWait = 0;

        if (m_cCon.GetInput(l_stInput))
        {

            if (    (IConsole::eKey == l_stInput.eEvent)
                 && (l_stInput.stKey.bDown)
               )
            {
                while (l_stInput.stKey.wCount--)
                {
                    m_pMenu->ProcessKey(l_stInput.stKey.wKey);
                }
            }
            else if (IConsole::eSize == l_stInput.eEvent)
            {
                //to resize ...
            }
        }
        else
        {
            l_dwWait = 25;
        }
    }

    return 0;
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CContext::AddStream(Bk::IStorageReader *i_pReader, Bk::IStreamEx *i_pExtra)
{
    m_cStreams.Add_After(m_cStreams.Get_Last(), new stStream(i_pReader, i_pExtra));
    m_szNewStreams ++;
    m_pMenus[CContext::eMenuStreams]->SetItemsCount(m_cStreams.Count());

    if (m_pMenu == m_pMenus[CContext::eMenuStreams])
    {
        m_pMenu->Redraw();
    }
}


