// This file is a part of the xMule Project.
//
// Copyright (c) 2004 Theodore R. Smith (hopeseekr@xmule.ws / http://www.xmule.ws/)
// DSA-1024 Fingerprint: 10A0 6372 9092 85A2 BB7F 907B CB8B 654B E33B F1ED
//
// Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.xmule-project.net )
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
// 
// This program 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 General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#ifdef PRECOMP
#	include "xmule-headers.h"
#else
#	include "ClientList.h"
#	include "ColorFrameCtrl.h"
#	include "DownloadQueue.h"
#include "ListenSocket.h"                   // CListenSocket - audited 5 Nov 2004
#	include "muuli_wdr.h"
#include "Preferences.h"                    // CPreferences::GetStatsColor
#include "ServerList.h"                     // Need for CServerList - audited 5 Nov 2004
#include "SharedFileList.h"                 // Needed for CSharedFileList
#include "sockets.h"                        // Needed for CServerConnect - audited 5 Nov 2004
#	include "StatisticsDlg.h"
#	include "UploadQueue.h"
#	include "xmule.h"
#endif

#include <DynPrefs/DynPrefs.h>              // Needed for DynamicPreferences

#include <map>                              // std::map
#include <wx/settings.h>
#include <wx/sizer.h>                       // Needed for wxSizer
#include <wx/stattext.h>                    // wxStaticText

#define ID_EXPORT_HTML 20001

// CStatisticsDlg dialog

BEGIN_EVENT_TABLE(CStatisticsDlg, wxPanel)
EVT_MENU(ID_EXPORT_HTML, CStatisticsDlg::ExportHTMLEvent)
END_EVENT_TABLE()

//IMPLEMENT_DYNAMIC(CStatisticsDlg, CDialog)
    CStatisticsDlg::CStatisticsDlg(wxWindow *pParent /*=NULL*/

)
    : wxPanel(pParent, CStatisticsDlg::IDD) /*, m_DownloadOMeter( _I_DO_NOTHING_HERE_ ),m_Statistics(4),m_UploadOMeter(3)*/
{
    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWFRAME));
    wxSizer *content = statsDlg(this, TRUE);
    content->Show(this, TRUE);
    m_DownloadOMeter = (COScopeCtrl *) FindWindowByName("dloadScope");
    m_UploadOMeter = (COScopeCtrl *) FindWindowByName("uloadScope");
    m_Statistics = (COScopeCtrl *) FindWindowByName("otherScope");
    stattree = wxStaticCast(FindWindowByName("statTree"), wxTreeCtrl);
#if 0
    COScopeCtrl *tmp = new COScopeCtrl(3, this);
    testSizer->Add(tmp, 1, wxGROW |wxALL |wxALIGN_CENTRE |wxLEFT, 5);
    testSizer->Layout();
    m_DownloadOMeter = *tmp;

    // let's play around a bit
    // can't. preferences are created later
    m_DownloadOMeter->SetRange(0, theApp.dynprefs->Get<long>("capacities-download") + 4, 0);
    m_DownloadOMeter->SetRange(0, theApp.dynprefs->Get<long>("capacities-download") + 4, 1);
    m_DownloadOMeter->SetRange(0, theApp.dynprefs->Get<long>("capacities-download") + 4, 2);
    m_DownloadOMeter->SetYUnits(GetResString(IDS_KBYTESEC));
#endif

    maxDownavg = 0.0;
}

CStatisticsDlg::~CStatisticsDlg()
{
}

void CStatisticsDlg::Init()
{
    // called after preferences get initialised
    m_DownloadOMeter->SetBackgroundColor(RGB(0, 0, 64));
    m_DownloadOMeter->SetGridColor(RGB(192, 192, 255));
    m_DownloadOMeter->SetRange(0, theApp.dynprefs->Get<long>("capacities-download") + 4, 0);
    m_DownloadOMeter->SetRange(0, theApp.dynprefs->Get<long>("capacities-download") + 4, 1);
    m_DownloadOMeter->SetRange(0, theApp.dynprefs->Get<long>("capacities-download") + 4, 2);
    m_DownloadOMeter->SetPlotColor(RGB(0, 128, 0), 0);
    m_DownloadOMeter->SetPlotColor(RGB(0, 210, 0), 1);
    m_DownloadOMeter->SetPlotColor(RGB(128, 255, 128), 2);
    m_DownloadOMeter->SetYUnits(GetResString(IDS_KBYTESEC));
    m_UploadOMeter->SetBackgroundColor(RGB(0, 0, 64));
    m_UploadOMeter->SetGridColor(RGB(192, 192, 255));
    m_UploadOMeter->SetRange(0, theApp.dynprefs->Get<long>("capacities-upload") + 4, 0);
    m_UploadOMeter->SetRange(0, theApp.dynprefs->Get<long>("capacities-upload") + 4, 1);
    m_UploadOMeter->SetRange(0, theApp.dynprefs->Get<long>("capacities-upload") + 4, 2);
    m_UploadOMeter->SetPlotColor(RGB(140, 0, 0), 0);
    m_UploadOMeter->SetPlotColor(RGB(200, 0, 0), 1);
    m_UploadOMeter->SetPlotColor(RGB(255, 128, 128), 2);
    m_UploadOMeter->SetYUnits(GetResString(IDS_KBYTESEC));
    m_Statistics->SetBackgroundColor(RGB(0, 0, 64));
    m_Statistics->SetGridColor(RGB(192, 192, 255));
    m_Statistics->SetRanges(0, 100);
    // This does not work!
    //  m_Statistics->autofitYscale=true;
    m_Statistics->autofitYscale = false;
    m_Statistics->SetPlotColor(RGB(192, 0, 192), 0);
    m_Statistics->SetPlotColor(RGB(150, 150, 255), 1);
    m_Statistics->SetPlotColor(RGB(255, 192, 255), 2);
    m_Statistics->SetPlotColor(RGB(255, 255, 128), 3);
    m_Statistics->SetYUnits("");
    m_Statistics->SetXUnits(GetResString(IDS_TIME));
    // setup tree
    wxTreeItemId root = stattree->AddRoot(_("Statistics"));
    h_uptime = stattree->InsertItem(root, 0L, GetResString(IDS_FSTAT_WAITING));
    h_transfer = stattree->AppendItem(root, GetResString(IDS_FSTAT_TRANSFER));
    tran0 = stattree->AppendItem(h_transfer, GetResString(IDS_FSTAT_WAITING));
    h_upload = stattree->AppendItem(h_transfer, GetResString(IDS_TW_UPLOADS));
    up1 = stattree->AppendItem(h_upload, GetResString(IDS_FSTAT_WAITING));
    up2 = stattree->AppendItem(h_upload, GetResString(IDS_FSTAT_WAITING));
    up3 = stattree->AppendItem(h_upload, GetResString(IDS_FSTAT_WAITING));
    up4 = stattree->AppendItem(h_upload, GetResString(IDS_FSTAT_WAITING));
    up5 = stattree->AppendItem(h_upload, GetResString(IDS_FSTAT_WAITING));
    up6 = stattree->AppendItem(h_upload, GetResString(IDS_FSTAT_WAITING));
    up7 = stattree->AppendItem(h_upload, GetResString(IDS_FSTAT_WAITING));
    up8 = stattree->AppendItem(h_upload, GetResString(IDS_FSTAT_WAITING));
    up9 = stattree->AppendItem(h_upload, GetResString(IDS_FSTAT_WAITING));
    up10 = stattree->AppendItem(h_upload, GetResString(IDS_FSTAT_WAITING));
    h_download = stattree->AppendItem(h_transfer, GetResString(IDS_TW_DOWNLOADS));
    down1 = stattree->AppendItem(h_download, GetResString(IDS_FSTAT_WAITING));
    down2 = stattree->AppendItem(h_download, GetResString(IDS_FSTAT_WAITING));
    down3 = stattree->AppendItem(h_download, GetResString(IDS_FSTAT_WAITING));
    down4 = stattree->AppendItem(h_download, GetResString(IDS_FSTAT_WAITING));
    down5 = stattree->AppendItem(h_download, GetResString(IDS_FSTAT_WAITING));
    down6 = stattree->AppendItem(h_download, GetResString(IDS_FSTAT_WAITING));
    down7 = stattree->AppendItem(h_download, GetResString(IDS_FSTAT_WAITING));
    h_connection = stattree->AppendItem(root, GetResString(IDS_FSTAT_CONNECTION));
    con1 = stattree->AppendItem(h_connection, GetResString(IDS_FSTAT_WAITING));
    con2 = stattree->AppendItem(h_connection, GetResString(IDS_FSTAT_WAITING));
    con12 = stattree->AppendItem(h_connection, GetResString(IDS_FSTAT_WAITING));
    con13 = stattree->AppendItem(h_connection, GetResString(IDS_FSTAT_WAITING));
    con3 = stattree->AppendItem(h_connection, GetResString(IDS_FSTAT_WAITING));
    con4 = stattree->AppendItem(h_connection, GetResString(IDS_FSTAT_WAITING));
    con5 = stattree->AppendItem(h_connection, GetResString(IDS_FSTAT_WAITING));
    con6 = stattree->AppendItem(h_connection, GetResString(IDS_FSTAT_WAITING));
    con7 = stattree->AppendItem(h_connection, GetResString(IDS_FSTAT_WAITING));
    con8 = stattree->AppendItem(h_connection, GetResString(IDS_FSTAT_WAITING));
    con9 = stattree->AppendItem(h_connection, GetResString(IDS_FSTAT_WAITING));
    h_clients = stattree->AppendItem(root, GetResString(IDS_CLIENTS));
    cli1 = stattree->AppendItem(h_clients, GetResString(IDS_FSTAT_WAITING));
    cli_versions[0] = stattree->AppendItem(cli1, GetResString(IDS_FSTAT_WAITING));
    cli_versions[1] = stattree->AppendItem(cli1, GetResString(IDS_FSTAT_WAITING));
    cli_versions[2] = stattree->AppendItem(cli1, GetResString(IDS_FSTAT_WAITING));
    cli_versions[3] = stattree->AppendItem(cli1, GetResString(IDS_FSTAT_WAITING));
    cli8 = stattree->AppendItem(h_clients, GetResString(IDS_FSTAT_WAITING));
    //  cli10= stattree->AppendItem(h_clients,GetResString(IDS_FSTAT_WAITING));
    cli2 = stattree->AppendItem(h_clients, GetResString(IDS_FSTAT_WAITING));
    cli_versions[4] = stattree->AppendItem(cli2, GetResString(IDS_FSTAT_WAITING));
    cli_versions[5] = stattree->AppendItem(cli2, GetResString(IDS_FSTAT_WAITING));
    cli_versions[6] = stattree->AppendItem(cli2, GetResString(IDS_FSTAT_WAITING));
    cli_versions[7] = stattree->AppendItem(cli2, GetResString(IDS_FSTAT_WAITING));
    cli3 = stattree->AppendItem(h_clients, GetResString(IDS_FSTAT_WAITING));
    cli_versions[8] = stattree->AppendItem(cli3, GetResString(IDS_FSTAT_WAITING));
    cli_versions[9] = stattree->AppendItem(cli3, GetResString(IDS_FSTAT_WAITING));
    cli_versions[10] = stattree->AppendItem(cli3, GetResString(IDS_FSTAT_WAITING));
    cli_versions[11] = stattree->AppendItem(cli3, GetResString(IDS_FSTAT_WAITING));
    cli4 = stattree->AppendItem(h_clients, GetResString(IDS_FSTAT_WAITING));
    cli5 = stattree->AppendItem(h_clients, GetResString(IDS_FSTAT_WAITING));
    cli9 = stattree->AppendItem(h_clients, GetResString(IDS_FSTAT_WAITING));
    cli6 = stattree->AppendItem(h_clients, GetResString(IDS_FSTAT_WAITING));
    cli7 = stattree->AppendItem(h_clients, GetResString(IDS_STATS_FILTEREDCLIENTS));
    h_servers = stattree->AppendItem(root, GetResString(IDS_FSTAT_SERVERS));
    srv1 = stattree->AppendItem(h_servers, GetResString(IDS_FSTAT_WAITING));
    srv2 = stattree->AppendItem(h_servers, GetResString(IDS_FSTAT_WAITING));
    srv3 = stattree->AppendItem(h_servers, GetResString(IDS_FSTAT_WAITING));
    srv4 = stattree->AppendItem(h_servers, GetResString(IDS_FSTAT_WAITING));
    srv5 = stattree->AppendItem(h_servers, GetResString(IDS_FSTAT_WAITING));
    srv6 = stattree->AppendItem(h_servers, GetResString(IDS_FSTAT_WAITING));
    srv7 = stattree->AppendItem(h_servers, GetResString(IDS_FSTAT_WAITING));
    srv8 = stattree->AppendItem(h_servers, GetResString(IDS_FSTAT_WAITING));
    srv9 = stattree->AppendItem(h_servers, GetResString(IDS_FSTAT_WAITING));
    h_shared = stattree->AppendItem(root, GetResString(IDS_SHAREDFILES));
    shar1 = stattree->AppendItem(h_shared, GetResString(IDS_FSTAT_WAITING));
    shar2 = stattree->AppendItem(h_shared, GetResString(IDS_FSTAT_WAITING));
    shar3 = stattree->AppendItem(h_shared, GetResString(IDS_FSTAT_WAITING));
    stattree->Expand(root);
    stattree->Expand(h_uptime);
    //,TVE_EXPAND);:
    stattree->Expand(h_transfer);
    //,TVE_EXPAND);:
    stattree->Expand(h_connection);
    //,TVE_EXPAND);:
    stattree->Expand(h_clients);
    //,TVE_EXPAND);:
    stattree->Expand(h_servers);
    // ,TVE_EXPAND);:
    stattree->Expand(h_shared);
    //,TVE_EXPAND);:
    stattree->Expand(h_upload);
    //,TVE_EXPAND);:
    stattree->Expand(h_download);
    RepaintMeters();
    m_ilastMaxConnReached = 0;
    peakconnections = 0;
    totalconnectionchecks = 0;
    averageconnections = 0;
    activeconnections = 0;
    maxDown = 0;
}

void CStatisticsDlg::RepaintMeters()
{
    m_DownloadOMeter->SetBackgroundColor(theApp.glob_prefs->GetStatsColor(0));
    m_DownloadOMeter->SetGridColor(theApp.glob_prefs->GetStatsColor(1));
    m_DownloadOMeter->SetPlotColor(theApp.glob_prefs->GetStatsColor(4), 0);
    m_DownloadOMeter->SetPlotColor(theApp.glob_prefs->GetStatsColor(3), 1);
    m_DownloadOMeter->SetPlotColor(theApp.glob_prefs->GetStatsColor(2), 2);
    m_UploadOMeter->SetBackgroundColor(theApp.glob_prefs->GetStatsColor(0));
    m_UploadOMeter->SetGridColor(theApp.glob_prefs->GetStatsColor(1));
    m_UploadOMeter->SetPlotColor(theApp.glob_prefs->GetStatsColor(7), 0);
    m_UploadOMeter->SetPlotColor(theApp.glob_prefs->GetStatsColor(6), 1);
    m_UploadOMeter->SetPlotColor(theApp.glob_prefs->GetStatsColor(5), 2);
    m_Statistics->SetBackgroundColor(theApp.glob_prefs->GetStatsColor(0));
    m_Statistics->SetGridColor(theApp.glob_prefs->GetStatsColor(1));
    m_Statistics->SetPlotColor(theApp.glob_prefs->GetStatsColor(10), 0);
    m_Statistics->SetPlotColor(theApp.glob_prefs->GetStatsColor(8), 1);
    //m_Statistics.SetPlotColor( theApp.glob_prefs->GetStatsColor(10),2) ;
    m_Statistics->SetPlotColor(theApp.glob_prefs->GetStatsColor(9), 3);
    SetupLegend(IDC_C0_2, 0, 1);
    SetupLegend(IDC_C0_3, 1, 1);
    SetupLegend(IDC_C0, 2, 1);
    SetupLegend(IDC_C1_2, 0, 2);
    SetupLegend(IDC_C1_3, 1, 2);
    SetupLegend(IDC_C1, 2, 2);
    SetupLegend(IDC_S0, 1, 3);
    SetupLegend(IDC_S1, 0, 3);
    //SetupLegend( IDC_S2, 2 ,3);
    SetupLegend(IDC_S3, 3, 3);
}

void CStatisticsDlg::SetupLegend(int ResIdx, int ElmtIdx, int legendNr)
{
    //CRect Rect;
    //GetDlgItem( ResIdx )->GetWindowRect( Rect );
    //ScreenToClient( Rect );
    CColorFrameCtrl *ctrl = (CColorFrameCtrl *) FindWindow(ResIdx);
    if (ctrl == NULL)
    {
        printf("no control (%d)\n", ResIdx);
        exit(1);
    }
    if (legendNr == 1)
    {
        //m_Led1[ ElmtIdx ].Create( WS_VISIBLE | WS_CHILD, Rect, this );
        //m_Led1[ ElmtIdx ].SetBackgroundColor( m_DownloadOMeter.GetPlotColor( ElmtIdx ) );
        //m_Led1[ ElmtIdx ].SetFrameColor( RGB( 0x00, 0x00, 0x00 ) );
        ctrl->SetBackgroundColor((COLORREF) m_DownloadOMeter->GetPlotColor(ElmtIdx));
        ctrl->SetFrameColor((COLORREF) RGB(0, 0, 0));
    }
    else if(legendNr == 2)
    {
        //m_Led2[ ElmtIdx ].Create( WS_VISIBLE | WS_CHILD, Rect, this );
        //m_Led2[ ElmtIdx ].SetBackgroundColor( m_UploadOMeter.GetPlotColor( ElmtIdx ) );
        //m_Led2[ ElmtIdx ].SetFrameColor( RGB( 0x00, 0x00, 0x00 ) );
        ctrl->SetBackgroundColor((COLORREF) m_UploadOMeter->GetPlotColor(ElmtIdx));
        ctrl->SetFrameColor((COLORREF) RGB(0, 0, 0));
    }
    else if(legendNr == 3)
    {
        //m_Led3[ ElmtIdx ].Create( WS_VISIBLE | WS_CHILD, Rect, this );
        //m_Led3[ ElmtIdx ].SetBackgroundColor( m_Statistics.GetPlotColor( ElmtIdx ) );
        //m_Led3[ ElmtIdx ].SetFrameColor( RGB( 0x00, 0x00, 0x00 ) );
        ctrl->SetBackgroundColor((COLORREF) m_Statistics->GetPlotColor(ElmtIdx));
        ctrl->SetFrameColor((COLORREF) RGB(0, 0, 0));
    }
}

void CStatisticsDlg::SetCurrentRate(float uploadrate, float downloadrate)
{
    // Update scaling of the active connections graph
    static uint32_t savedMaxConns;
    if (savedMaxConns != theApp.dynprefs->Get<long>("max-connections"))
    {
        savedMaxConns = theApp.dynprefs->Get<long>("max-connections");
        unsigned x = 1, by = 1;
        unsigned max = 100;
        if (savedMaxConns < max)
        {
            x = max / savedMaxConns;
            if (max < (x *savedMaxConns))
            x--;
            max = max / x;
        }
        else
        {
            by = (savedMaxConns + max - 1) / max;
            if ((by *max) < savedMaxConns)
            by++;
            max = max *by;
        }
        wxString txt = wxString::Format(GetResString(IDS_ST_ACTIVEC), x, by);
        wxStaticCast(wxWindow::FindWindowById(ID_ACTIVEC), wxStaticText)->SetLabel(txt);
        m_Statistics->SetRange(0, max, 1);
    }
    double m_dPlotDataUp[ 3 ];
    double m_dPlotDataDown[ 3 ];
    int myStats[6];
    // current rate
    m_dPlotDataDown[2] = downloadrate;
    m_dPlotDataUp[2] = uploadrate;
    if (maxDown < downloadrate) maxDown = downloadrate;
    // Websever [kuchin]
//    UpDown* updown = new UpDown();
//    updown->upload = uploadrate;
//    updown->download = downloadrate;
//    theApp.webserver->AddStatsLine(updown);
    // averages
    m_dPlotDataDown[0] = GetAvgDownloadRate(AVG_SESSION);
    m_dPlotDataUp[0] = GetAvgUploadRate(AVG_SESSION);
    m_dPlotDataDown[1] = GetAvgDownloadRate(AVG_TIME);
    m_dPlotDataUp[1] = GetAvgUploadRate(AVG_TIME);
    // show
    m_DownloadOMeter->AppendPoints(m_dPlotDataDown);
    m_UploadOMeter->AppendPoints(m_dPlotDataUp);
    // get Partialfiles summary
    activeconnections = theApp.listensocket->GetOpenSockets();
    theApp.downloadqueue->GetDownloadStats(myStats);
    m_dPlotDataMore[0] = theApp.uploadqueue->GetUploadQueueLength();
    //myStats[0];:
    m_dPlotDataMore[1] = activeconnections;
    //theApp.uploadqueue->GetWaitingUserCount();:
    m_dPlotDataMore[2] = 0;
    m_dPlotDataMore[3] = myStats[1];
    //for (int i=0;i<4;i++) if (m_dPlotDataMore[i]>theApp.glob_prefs->GetStatsMax()) {resize=true;theApp.glob_prefs->GetStatsMax()=(int)m_dPlotDataMore[i];}
    //if (resize) m_Statistics.SetRanges(0, theApp.glob_prefs->GetStatsMax()+15) ;
    m_Statistics->AppendPoints(m_dPlotDataMore);
}

void CStatisticsDlg::UpdateConnectionsStatus()
{
    if (peakconnections < activeconnections)
    peakconnections = activeconnections;
    if (theApp.serverconnect->IsConnected())
    {
        totalconnectionchecks++;
        float percent;
        percent = (float)((float)(totalconnectionchecks - 1) / (float) totalconnectionchecks);
        if (percent > .99)
        percent = (float) .99;
        averageconnections = (averageconnections *percent) + (float)((float) activeconnections * (float)(1 - percent));
    }
}

float CStatisticsDlg::GetMaxConperFiveModifier()
{
    //This is a alpha test.. Will clean up for b version.
    float SpikeSize = theApp.listensocket->GetOpenSockets() - averageconnections;
    if (SpikeSize < 1)
    return 1;
    float SpikeTolerance = 25.0 * static_cast<float>(theApp.dynprefs->Get<long>("max-per-5")) / 10.0;
    if (SpikeSize > SpikeTolerance)
    return 0;
    float Modifier = (1 - (SpikeSize/SpikeTolerance));
    return Modifier;
}

void CStatisticsDlg::RecordRate()
{
    if (theApp.stat_transferStarttime == 0) return;
    // every second
    downrateHistory.push_front(theApp.stat_sessionReceivedBytes);
    uprateHistory.push_front(theApp.stat_sessionSentBytes);
    // limit to maxmins
    while ((int) downrateHistory.size() > (int)(theApp.dynprefs->Get<long>("graph-average") * 60)) downrateHistory.pop_back();
    while ((int) uprateHistory.size() > (int)(theApp.dynprefs->Get<long>("graph-average") * 60)) uprateHistory.pop_back();
}

void CStatisticsDlg::ShowStatistics()
{
    wxString cbuffer;
    wxString cbuffer2;
    bool resize;
    DWORD running;
    int myStats[11];
    float DownAvgRate;
    resize = false;
    theApp.downloadqueue->GetDownloadStats(myStats);
    uint64_t DownOHTotal = theApp.downloadqueue->GetDownDataOverheadFileRequest() + theApp.downloadqueue->GetDownDataOverheadSourceExchange() + theApp.downloadqueue->GetDownDataOverheadServer() + theApp.downloadqueue->GetDownDataOverheadOther();
    uint64_t DownOHTotalPackets = theApp.downloadqueue->GetDownDataOverheadFileRequestPackets() + theApp.downloadqueue->GetDownDataOverheadSourceExchangePackets() + theApp.downloadqueue->GetDownDataOverheadServerPackets() + theApp.downloadqueue->GetDownDataOverheadOtherPackets();
    cbuffer.Printf("Uptime: ");
    stattree->SetItemText(h_uptime, cbuffer);
    cbuffer.Printf(GetResString(IDS_STATS_DDATA), CastItoXBytes(theApp.stat_sessionReceivedBytes) .GetData(), CastItoXBytes(theApp.stat_sessionReceivedBytes + theApp.glob_prefs->GetTotalDownloaded()) .GetData());
    stattree->SetItemText(down1, cbuffer);
    cbuffer.Printf(GetResString(IDS_TOVERHEAD), CastItoXBytes(DownOHTotal) .GetData(), CastItoIShort(DownOHTotalPackets) .GetData());
    stattree->SetItemText(down2, cbuffer);
    cbuffer.Printf(GetResString(IDS_FROVERHEAD), CastItoXBytes(theApp.downloadqueue->GetDownDataOverheadFileRequest()) .GetData(), CastItoIShort(theApp.downloadqueue->GetDownDataOverheadFileRequestPackets()) .GetData());
    stattree->SetItemText(down3, cbuffer);
    cbuffer.Printf(GetResString(IDS_SSOVERHEAD), CastItoXBytes(theApp.downloadqueue->GetDownDataOverheadSourceExchange()) .GetData(), CastItoIShort(theApp.downloadqueue->GetDownDataOverheadSourceExchangePackets()) .GetData());
    stattree->SetItemText(down4, cbuffer);
    cbuffer.Printf(GetResString(IDS_SOVERHEAD), CastItoXBytes(theApp.downloadqueue->GetDownDataOverheadServer()) .GetData(), CastItoIShort(theApp.downloadqueue->GetDownDataOverheadServerPackets()) .GetData());
    stattree->SetItemText(down5, cbuffer);
    cbuffer.Printf(GetResString(IDS_STATS_FOUNDSRC), myStats[0]);
    stattree->SetItemText(down6, cbuffer);
    cbuffer.Printf(GetResString(IDS_STATS_ACTDL), myStats[1]);
    stattree->SetItemText(down7, cbuffer);
    uint64_t UpOHTotal = theApp.uploadqueue->GetUpDataOverheadFileRequest() + theApp.uploadqueue->GetUpDataOverheadSourceExchange() + theApp.uploadqueue->GetUpDataOverheadServer() + theApp.uploadqueue->GetUpDataOverheadOther();
    uint64_t UpOHTotalPackets = theApp.uploadqueue->GetUpDataOverheadFileRequestPackets() + theApp.uploadqueue->GetUpDataOverheadSourceExchangePackets() + theApp.uploadqueue->GetUpDataOverheadServerPackets() + theApp.uploadqueue->GetUpDataOverheadOtherPackets();
    cbuffer.Printf(GetResString(IDS_STATS_UDATA), CastItoXBytes(theApp.stat_sessionSentBytes) .GetData(), CastItoXBytes(theApp.stat_sessionSentBytes + theApp.glob_prefs->GetTotalUploaded()) .GetData());
    stattree->SetItemText(up1, cbuffer);
    cbuffer.Printf(GetResString(IDS_TOVERHEAD), CastItoXBytes(UpOHTotal) .GetData(), CastItoIShort(UpOHTotalPackets) .GetData());
    stattree->SetItemText(up2, cbuffer);
    cbuffer.Printf(GetResString(IDS_FROVERHEAD), CastItoXBytes(theApp.uploadqueue->GetUpDataOverheadFileRequest()) .GetData(), CastItoIShort(theApp.uploadqueue->GetUpDataOverheadFileRequestPackets()) .GetData());
    stattree->SetItemText(up3, cbuffer);
    cbuffer.Printf(GetResString(IDS_SSOVERHEAD), CastItoXBytes(theApp.uploadqueue->GetUpDataOverheadSourceExchange()) .GetData(), CastItoIShort(theApp.uploadqueue->GetUpDataOverheadSourceExchangePackets()) .GetData());
    stattree->SetItemText(up4, cbuffer);
    cbuffer.Printf(GetResString(IDS_SOVERHEAD), CastItoXBytes(theApp.uploadqueue->GetUpDataOverheadServer()) .GetData(), CastItoIShort(theApp.uploadqueue->GetUpDataOverheadServerPackets()) .GetData());
    stattree->SetItemText(up5, cbuffer);
    cbuffer.Printf(GetResString(IDS_STATS_ACTUL), theApp.uploadqueue->GetUploadQueueLength());
    stattree->SetItemText(up6, cbuffer);
    cbuffer.Printf(GetResString(IDS_STATS_WAITINGUSERS), theApp.uploadqueue->GetWaitingUserCount());
    stattree->SetItemText(up7, cbuffer);
    cbuffer.Printf(GetResString(IDS_STATS_SUCCUPCOUNT), theApp.uploadqueue->GetSuccessfullUpCount());
    stattree->SetItemText(up8, cbuffer);
    cbuffer.Printf(GetResString(IDS_STATS_FAILUPCOUNT), theApp.uploadqueue->GetFailedUpCount());
    stattree->SetItemText(up9, cbuffer);
    running = theApp.uploadqueue->GetAverageUpTime();
    cbuffer.Printf(GetResString(IDS_STATS_AVEUPTIME), CastSecondsToHM(running) .GetData());
    stattree->SetItemText(up10, cbuffer);
    if (theApp.stat_transferStarttime > 0)
    {
        cbuffer.Printf(GetResString(IDS_STATS_AVGDL), GetAvgDownloadRate(AVG_SESSION));
        stattree->SetItemText(con1, cbuffer);
        cbuffer.Printf(GetResString(IDS_STATS_AVGUL), GetAvgUploadRate(AVG_SESSION));
        stattree->SetItemText(con2, cbuffer);
        DownAvgRate = GetAvgDownloadRate(AVG_SESSION);
        if (maxDownavg < DownAvgRate) maxDownavg = DownAvgRate;
        cbuffer.Printf(GetResString(IDS_STATS_MAXAVGDL), maxDownavg);
        stattree->SetItemText(con12, cbuffer);
        cbuffer.Printf(GetResString(IDS_STATS_MAXDL), maxDown);
        stattree->SetItemText(con13, cbuffer);
    }
    if (theApp.stat_reconnects > 0) cbuffer.Printf(GetResString(IDS_STATS_RECONNECTS), theApp.stat_reconnects - 1);
    else cbuffer.Printf(GetResString(IDS_STATS_RECONNECTS), 0);
    stattree->SetItemText(con3, cbuffer);
    if (theApp.stat_transferStarttime == 0) cbuffer.Printf(GetResString(IDS_STATS_WAITTRANSF));
    else
    {
        running = (GetTickCount() - theApp.stat_transferStarttime) /1000;
        cbuffer.Printf(GetResString(IDS_TRANSFERTIME), CastSecondsToHM(running) .GetData());
    }
    stattree->SetItemText(con4, cbuffer);
    if (theApp.Start_time > 0)
    {
        running = (GetTickCount() - theApp.Start_time) /1000;
        cbuffer.Printf("Uptime: %s", CastSecondsToHM(running) .GetData());
        stattree->SetItemText(h_uptime, cbuffer);
    }
    if (theApp.stat_serverConnectTime == 0) cbuffer.Printf(GetResString(IDS_STATS_WAITCONN));
    else
    {
        running = (GetTickCount() - theApp.stat_serverConnectTime) /1000;
        cbuffer.Printf(GetResString(IDS_STATS_CONNECTEDSINCE), CastSecondsToHM(running) .GetData());
    }
    stattree->SetItemText(con5, cbuffer);
    if (theApp.stat_sessionReceivedBytes > 0 &&theApp.stat_sessionSentBytes > 0)
    if (theApp.stat_sessionReceivedBytes < theApp.stat_sessionSentBytes)
    {
        cbuffer.Printf("%s %.2f : 1", GetResString(IDS_STATS_RATIO) .GetData(), (float) theApp.stat_sessionSentBytes/theApp.stat_sessionReceivedBytes);
        stattree->SetItemText(tran0, cbuffer);
    }
    else
    {
        cbuffer.Printf("%s 1 : %.2f", GetResString(IDS_STATS_RATIO) .GetData(), (float) theApp.stat_sessionReceivedBytes/theApp.stat_sessionSentBytes);
        stattree->SetItemText(tran0, cbuffer);
    }
    // shared files stats
    cbuffer.Printf(GetResString(IDS_SHAREDFILESCOUNT), theApp.sharedfiles->GetCount());
    stattree->SetItemText(shar1, cbuffer);
    uint64_t allsize = theApp.sharedfiles->GetDatasize();
    cbuffer.Printf(GetResString(IDS_SF_SIZE), CastItoXBytes(allsize) .GetData());
    stattree->SetItemText(shar2, cbuffer);
    if (theApp.sharedfiles->GetCount() != 0)
    cbuffer2.Printf("%s", CastItoXBytes((uint64_t) allsize/theApp.sharedfiles->GetCount()) .GetData());
    else
    {
        cbuffer2 = "-";
    }
    cbuffer.Printf(GetResString(IDS_SF_AVERAGESIZE), cbuffer2.GetData());
    stattree->SetItemText(shar3, cbuffer);
    // get clientversion-counts
    // statsclientstatus : original idea and code by xrmb
    std::map<uint16_t, uint32_t> clientVersionEDonkey;
    std::map<uint16_t, uint32_t> clientVersionEDonkeyHybrid;
    std::map<uint8_t, uint32_t> clientVersionEMule;

    uint32_t totalclient;
    theApp.clientlist->GetStatistics(totalclient, myStats, &clientVersionEDonkey, &clientVersionEDonkeyHybrid, &clientVersionEMule);
    totalclient -= myStats[0];
    if (!totalclient)
    totalclient = 1;
    cbuffer.Printf(_("eMule: %i (%1.1f%%)"), myStats[2], (double) 100 *myStats[2]/totalclient);
    stattree->SetItemText(cli1, cbuffer);
    //	cbuffer.Printf(_("LMule: %i (%1.1f%%)"),myStats[8],(double)100*myStats[8]/totalclient);stattree->SetItemText(cli10, cbuffer);
    cbuffer.Printf(_("xMule: %i (%1.1f%%)"), myStats[6], (double) 100 *myStats[6]/totalclient);
    stattree->SetItemText(cli8, cbuffer);
    cbuffer.Printf(_("eDonkeyHybrid: %i (%1.1f%%)"), myStats[4], (double) 100 *myStats[4]/totalclient);
    stattree->SetItemText(cli2, cbuffer);
    cbuffer.Printf(_("eDonkey: %i (%1.1f%%)"), myStats[1], (double) 100 *myStats[1]/totalclient);
    stattree->SetItemText(cli3, cbuffer);
    cbuffer.Printf(_("cDonkey: %i (%1.1f%%)"), myStats[5], (double) 100 *myStats[5]/totalclient);
    stattree->SetItemText(cli4, cbuffer);
    cbuffer.Printf(_("Old MLDonkey: %i (%1.1f%%)"), myStats[3], (double) 100 *myStats[3]/totalclient);
    stattree->SetItemText(cli5, cbuffer);
    cbuffer.Printf(_("New MLDonkey: %i (%1.1f%%)"), myStats[7], (double) 100 *myStats[7]/totalclient);
    stattree->SetItemText(cli9, cbuffer);
    cbuffer.Printf(GetResString(IDS_STATS_UNKNOWNCLIENT) .GetData(), myStats[0]);
    stattree->SetItemText(cli6, cbuffer);
    cbuffer.Printf(GetResString(IDS_STATS_FILTEREDCLIENTS) .GetData(), theApp.stat_filteredclients);
    stattree->SetItemText(cli7, cbuffer);
    //if (stattree->GetItemState(cli3, TVIS_EXPANDED)&&TVIS_EXPANDED == TVIS_EXPANDED ) {
    if (stattree->IsExpanded(cli3))
    {
        uint32_t totcnt = myStats[1];
        //--- find top 4 eDonkey client versions ---
        uint32_t currtop = 0;
        uint32_t lasttop = 0xFFFFFFFF;

        for (uint32_t i = 0; i < 4; ++i)
        {
            uint32_t topver = 0;
            uint32_t topcnt = 0;
            double topper = 0;

            std::map<uint16_t, uint32_t>::const_iterator it;
            it = clientVersionEDonkey.begin();

            while (it != clientVersionEDonkey.end())
            {
                const uint16_t ver(it->first);
                const uint32_t cnt(it->second);

                ++it;

                if (currtop < ver && (ver < lasttop && ver != 0x91))
                {
                    double percent = (double) cnt/totcnt;

                    if (lasttop == 0xFFFFFFFF && ((totcnt > 75 && ((cnt <= 2) || percent < 0.01)) || (totcnt > 50 && cnt <= 1)))
                    {
                        continue;
                    }

                    topper = percent;
                    topver = ver;
                    topcnt = cnt;
                    currtop = ver;
                }
            }

            lasttop = currtop;
            currtop = 0;

            if (topcnt)
            {
                cbuffer.Printf("v%i: %i (%1.1f%%)", topver, topcnt, topper * 100);
            }
            else
            {
                cbuffer = "";
            }

            stattree->SetItemText(cli_versions[i + 8], cbuffer);
        }
    }
    //if (stattree->GetItemState(cli2, TVIS_EXPANDED)&&TVIS_EXPANDED == TVIS_EXPANDED ) {
    if (stattree->IsExpanded(cli2))
    {
        uint32_t totcnt = myStats[4];
        //--- find top 4 eDonkey Hybrid client versions ---
        uint32_t currtop = 0;
        uint32_t lasttop = 0xFFFFFFFF;
        for (uint32_t i = 0; i < 4; ++i)
        {
            uint32_t topver = 0;
            uint32_t topcnt = 0;
            double topper = 0;

            std::map<uint16_t, uint32_t>::const_iterator it;
            it = clientVersionEDonkeyHybrid.begin();

            while (it != clientVersionEDonkeyHybrid.end())
            {
                const uint16_t ver(it->first);
                const uint32_t cnt(it->second);

                ++it;

                if (currtop < ver && ver < lasttop && ver != 0x91)
                {
                    double percent = (double) cnt/totcnt;

                    if (lasttop == 0xFFFFFFFF && ((totcnt > 75 && ((cnt <= 2) || percent < 0.01)) || (totcnt > 50 && cnt <= 1)))
                    {

                        continue;
                    }

                    topper = percent;
                    topver = ver;
                    topcnt = cnt;
                    currtop = ver;
                }
            }

            lasttop = currtop;
            currtop = 0;

            if (topcnt)
            {
                cbuffer.Printf("v%i: %i (%1.1f%%)", topver, topcnt, topper * 100);
            }
            else
            {
                cbuffer = "";
            }

            stattree->SetItemText(cli_versions[i + 4], cbuffer);
        }
    }
    //if (stattree->GetItemState(cli1, TVIS_EXPANDED)&&TVIS_EXPANDED == TVIS_EXPANDED ) {
    if (stattree->IsExpanded(cli1))
    {
        uint32_t totcnt = myStats[2];
        //--- find top 4 eMule client versions ---
        uint32_t currtop = 0;
        uint32_t lasttop = 0xFFFFFFFF;

        for (uint32_t i = 0 ; i < 4 ; i++)
        {
            uint32_t topver = 0;
            uint32_t topcnt = 0;
            double topper = 0;

            std::map<uint8_t, uint32_t>::const_iterator it;
            it = clientVersionEMule.begin();

            while (it != clientVersionEMule.end())
            {
                const uint8_t ver(it->first);
                const uint32_t cnt(it->second);

                ++it;

                if (currtop < ver && ver < lasttop)
                {
                    double percent = (double) cnt/totcnt;

                    if (lasttop == 0xFFFFFFFF && ((totcnt > 75 && ((cnt <= 2) || percent < 0.01)) || (totcnt > 50 && cnt <= 1)))
                    {
                        continue;
                    }

                    topper = percent;
                    topver = ver;
                    topcnt = cnt;
                    currtop = ver;
                }
            }

            lasttop = currtop;
            currtop = 0;

            if (topcnt)
            {
                cbuffer.Printf("v0.%02X: %i (%1.1f%%)", topver, topcnt, topper *100);
            }
            else
            {
                cbuffer = "";
            }

            stattree->SetItemText(cli_versions[i], cbuffer);
        }
        // xrmb
    }
    // get serverstats
    uint32_t servtotal;
    uint32_t servfail;
    uint32_t servuser;
    uint32_t servfile;
    uint32_t servtuser;
    uint32_t servtfile;
    float servocc;
    theApp.serverlist->GetStatus(servtotal, servfail, servuser, servfile, servtuser, servtfile, servocc);
    cbuffer.Printf("%s: %i", GetResString(IDS_SF_WORKING) .GetData(), servtotal - servfail);
    stattree->SetItemText(srv1, cbuffer);
    cbuffer.Printf("%s: %i", GetResString(IDS_SF_FAIL) .GetData(), servfail);
    stattree->SetItemText(srv2, cbuffer);
    cbuffer.Printf("%s: %i", GetResString(IDS_SF_TOTAL) .GetData(), servtotal);
    stattree->SetItemText(srv3, cbuffer);
    cbuffer.Printf("%s: %i", GetResString(IDS_SF_DELCOUNT) .GetData(), theApp.serverlist->GetDeletedServerCount());
    stattree->SetItemText(srv4, cbuffer);
    cbuffer.Printf("%s: %i", GetResString(IDS_SF_WUSER) .GetData(), servuser);
    stattree->SetItemText(srv5, cbuffer);
    cbuffer.Printf("%s: %i", GetResString(IDS_SF_WFILE) .GetData(), servfile);
    stattree->SetItemText(srv6, cbuffer);
    cbuffer.Printf("%s: %i", GetResString(IDS_SF_USER) .GetData(), servtuser);
    stattree->SetItemText(srv7, cbuffer);
    cbuffer.Printf("%s: %i", GetResString(IDS_SF_FILE) .GetData(), servtfile);
    stattree->SetItemText(srv8, cbuffer);
    cbuffer.Printf("%s: %i", GetResString(IDS_SF_ACTIVECON) .GetData(), activeconnections);
    stattree->SetItemText(con6, cbuffer);
    cbuffer.Printf(GetResString(IDS_SF_SRVOCC), servocc);
    stattree->SetItemText(srv9, cbuffer);
    uint32_t m_itemp = theApp.listensocket->GetMaxConnectionReached();
    if (m_itemp != m_ilastMaxConnReached)
    {
        char osDate[60];
        //_strtime( osTime );
        //_strdate( osDate );
        time_t mytime = time(NULL);
        struct tm *now = localtime( &mytime);
        strftime(osDate, sizeof(osDate) - 1, "%d.%m.%Y %H:%M:%S", now);
        cbuffer.Printf("%s: %i : %s", GetResString(IDS_SF_MAXCONLIMITREACHED) .GetData(), m_itemp, osDate);
        stattree->SetItemText(con7, cbuffer);
        m_ilastMaxConnReached = m_itemp;
    }
    else if(m_itemp == 0)
    {
        cbuffer.Printf("%s: %i", GetResString(IDS_SF_MAXCONLIMITREACHED) .GetData(), m_itemp);
        stattree->SetItemText(con7, cbuffer);
    }
    if (theApp.serverconnect->IsConnected())
    {
        cbuffer.Printf("%s: %i", GetResString(IDS_SF_AVGCON) .GetData(), (int) averageconnections);
        stattree->SetItemText(con8, cbuffer);
    }
    else
    {
        stattree->SetItemText(con8, GetResString(IDS_STATS_WAITCONN));
    }
    cbuffer.Printf("%s: %i", GetResString(IDS_SF_PEAKCON) .GetData(), peakconnections);
    stattree->SetItemText(con9, cbuffer);
}

float CStatisticsDlg::GetAvgDownloadRate(int averageType)
{
    if (averageType == AVG_SESSION)
    {
        if (theApp.stat_transferStarttime == 0) return 0;
        DWORD running = (GetTickCount() - theApp.stat_transferStarttime) /1000;
        if (running < 5) return 0;
        return(float)(theApp.stat_sessionReceivedBytes/1024) / running;
    }
    else
    {
        if (downrateHistory.size() == 0) return 0;
        uint64_t sum;
        sum = downrateHistory.front();
        if ((int) downrateHistory.size() >= (int)theApp.dynprefs->Get<long>("graph-average") * 60) sum -= downrateHistory.back();
        return (float)(sum/1024) / downrateHistory.size();
    }
}

float CStatisticsDlg::GetAvgUploadRate(int averageType)
{
    if (averageType == AVG_SESSION)
    {
        if (theApp.stat_transferStarttime == 0) return 0;
        DWORD running = (GetTickCount() - theApp.stat_transferStarttime) /1000;
        if (running < 5) return 0;
        return(float)(theApp.stat_sessionSentBytes/1024) / running;
    }
    else
    {
        if (uprateHistory.size() == 0) return 0;
        uint64_t sum = uprateHistory.front();
        if ((int) uprateHistory.size() >= (int)(theApp.dynprefs->Get<long>("graph-average") * 60)) sum -= uprateHistory.back();
        return(float)(sum/1024) /uprateHistory.size();
    }
}

#if 0
void CStatisticsDlg::OnShowWindow(bool bShow, UINT nStatus)
{
}

void CStatisticsDlg::OnSize(UINT nType, int cx, int cy)
{
    CResizableDialog::OnSize(nType, cx, cy);
    // TODO: Add your message handler code here
    //this will cause COScopeCtrl::OnSizeCall
    CRect rc;
    GetDlgItem(IDC_UPLOAD)->GetWindowRect( &rc);
    ScreenToClient( &rc);
    m_DownloadOMeter.MoveWindow( &rc);
    //OnSize:
}

#endif

void CStatisticsDlg::ShowInterval()
{
    //EnableWindow( FALSE );
    int shownSecs = 319 * theApp.dynprefs->Get<long>("graph-delay");
    if (shownSecs == 0)
    {
        m_DownloadOMeter->SetXUnits(GetResString(IDS_STOPPED));
        m_UploadOMeter->SetXUnits(GetResString(IDS_STOPPED));
    }
    else
    {
        char buffer[50];
        wxString tmpstr = CastSecondsToHM(shownSecs);
        m_UploadOMeter->SetXUnits(tmpstr.GetData());
        m_DownloadOMeter->SetXUnits(tmpstr.GetData());
    }
    //UpdateData(FALSE);
    //EnableWindow( TRUE );
}

void CStatisticsDlg::SetARange(bool SetDownload, int maxValue)
{
    if (SetDownload)
    {
        m_DownloadOMeter->SetRange(0, maxValue + 4, 0);
        m_DownloadOMeter->SetRange(0, maxValue + 4, 1);
        m_DownloadOMeter->SetRange(0, maxValue + 4, 2);
    }
    else
    {
        m_UploadOMeter->SetRange(0, maxValue + 4, 0);
        m_UploadOMeter->SetRange(0, maxValue + 4, 1);
        m_UploadOMeter->SetRange(0, maxValue + 4, 2);
    }
}

#if 0
void CStatisticsDlg::Localize()
{
    GetDlgItem(IDC_STATIC_D3)->SetWindowText(GetResString(IDS_ST_DOWNLOAD));
    GetDlgItem(IDC_STATIC_U)->SetWindowText(GetResString(IDS_ST_UPLOAD));
    GetDlgItem(IDC_STATIC_D)->SetWindowText(GetResString(IDS_ST_CURRENT));
    GetDlgItem(IDC_STATIC_U2)->SetWindowText(GetResString(IDS_ST_CURRENT));
    GetDlgItem(IDC_STATIC_D2)->SetWindowText(GetResString(IDS_ST_SESSION));
    GetDlgItem(IDC_STATIC_U3)->SetWindowText(GetResString(IDS_ST_SESSION));
    GetDlgItem(IDC_STATIC_S2)->SetWindowText(GetResString(IDS_ST_ACTIVED));
    GetDlgItem(IDC_STATIC_S0)->SetWindowText(GetResString(IDS_ST_ACTIVEC));
    GetDlgItem(IDC_STATIC_S1)->SetWindowText(GetResString(IDS_ST_ACTIVEU));
    GetDlgItem(IDC_STATIC_S3)->SetWindowText(GetResString(IDS_ST_WAITINGU));
    wxString value;
    value.Printf(" (%u mins)", theApp.glob_prefs->GetStatsAverageMinutes());
    GetDlgItem(IDC_TIMEAVG1)->SetWindowText(GetResString(IDS_AVG) + value);
    GetDlgItem(IDC_TIMEAVG2)->SetWindowText(GetResString(IDS_AVG) + value);
}

#endif

// the idea: we must dispatch this request to the main thread as web thread
// can't touch the GUI controls. Only allowed function is wxPostEvent which
// unfortunately just passes the event, so we must implement a wxCondition
// so we can wait until the main thread has processed the request and built
// a valid string for us.
wxString CStatisticsDlg::ExportHTML()
{
    // only one shall pass
    wxCriticalSectionLocker locker(exportCrit);
    // then lock the signalling mutex
    wxCondition myCond(exportMutex);
    exportCondition = &myCond;
    exportMutex.Lock();
    // post the message
    wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, ID_EXPORT_HTML);
    wxPostEvent(this, evt);
    // and wait until it is completed
    exportCondition->Wait();
    // and now we can return the string
    exportMutex.Unlock();
    printf("*** WEB THREAD: returning the value\n");
    return exportString;
}

void CStatisticsDlg::ExportHTMLEvent(wxCommandEvent &evt)
{
    int8_t ix;
    wxString temp;
    wxString text = "";
    wxTreeItemId item;
    // update it
    ShowStatistics();
    item = stattree->GetRootItem();
    text = stattree->GetItemText(item);
    while (item)
    {
        item = stattree->GetNextVisible(item);
        if (!item) break;
        //,TVE_EXPAND);:
        stattree->Expand(item);
        temp = "";
        for (ix = 0 ; ix < 3 * (int) stattree->GetItemData(item) ; ix++) temp += "&nbsp;";
        text += "<br>" + temp + stattree->GetItemText(item);
    }
    // set the string
    exportString = text;
    // and signal
    printf("** MAIN THREAD: Return value ready.\n");
    wxMutexLocker locker(exportMutex);
    exportCondition->Broadcast();
    printf("** MAIN THREAD: All done.\n");
}

