//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-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.

// StatisticsDlg.cpp : implementation file
//
#include "stdafx.h"
#include "emule.h"
#include "StatisticsDlg.h"
#include "uploadqueue.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


// CStatisticsDlg dialog

IMPLEMENT_DYNAMIC(CStatisticsDlg, CDialog)
CStatisticsDlg::CStatisticsDlg(CWnd* pParent /*=NULL*/)
	: CResizableDialog(CStatisticsDlg::IDD, pParent) , m_DownloadOMeter( 3 ),m_Statistics(4),m_UploadOMeter(4)
{

}

CStatisticsDlg::~CStatisticsDlg()
{
}

void CStatisticsDlg::DoDataExchange(CDataExchange* pDX)
{
	CResizableDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CExoSliderDlg)
	DDX_Control(pDX, IDC_STATTREE, stattree);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CStatisticsDlg, CResizableDialog)
	//{{AFX_MSG_MAP(CStatisticsDlg)
	ON_WM_SHOWWINDOW()
	ON_WM_SIZE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()


// CStatisticsDlg message handlers

BOOL CStatisticsDlg::OnInitDialog(){

	CResizableDialog::OnInitDialog();
	EnableWindow( FALSE );

	Localize();

	// setup tree
	h_transfer= stattree.InsertItem(GetResString(IDS_FSTAT_TRANSFER));
	tran0= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_transfer);

	h_upload = stattree.InsertItem(GetResString(IDS_TW_UPLOADS), h_transfer);
	up1= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_upload);
	upFriendsAmount = stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_upload);
	up2= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_upload);
	up3= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_upload);
	up4= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_upload);
	up5= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_upload);
	up6= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_upload);
	uptotal = stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_upload);
	up7= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_upload);
	up8= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_upload);
	up9= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_upload);
	up10= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_upload);

	h_download = stattree.InsertItem(GetResString(IDS_TW_DOWNLOADS), h_transfer);
	down1= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_download);
	down2= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_download);
	down3= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_download);
	down4= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_download);
	down5= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_download);
	down6= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_download);
	down7= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_download);

	h_connection = stattree.InsertItem(GetResString(IDS_FSTAT_CONNECTION));
	con1= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_connection);
	con2= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_connection);
	con12= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_connection);
	con13= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_connection);
	con3= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_connection);
	con4= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_connection);
	con5= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_connection);
	con6= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_connection);
	con7= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_connection);
	con8= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_connection);
	con9= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_connection);

	h_clients = stattree.InsertItem(GetResString(IDS_CLIENTS));
	cli1= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_clients);
		cli_versions[0]= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),cli1);
		cli_versions[1]= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),cli1);
		cli_versions[2]= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),cli1);
		cli_versions[3]= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),cli1);

	cli2= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_clients);
		cli_versions[4]= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),cli2);
		cli_versions[5]= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),cli2);
		cli_versions[6]= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),cli2);
		cli_versions[7]= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),cli2);

	cli3= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_clients);
		cli_versions[8]= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),cli3);
		cli_versions[9]= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),cli3);
		cli_versions[10]= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),cli3);
		cli_versions[11]= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),cli3);

	cli4= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_clients);
	cli5= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_clients);
	cli6= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_clients);
	cli7= stattree.InsertItem(GetResString(IDS_STATS_FILTEREDCLIENTS),h_clients);


	h_servers = stattree.InsertItem(GetResString(IDS_FSTAT_SERVERS));
	srv1= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_servers);
	srv2= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_servers);
	srv3= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_servers);
	srv4= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_servers);
	srv5= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_servers);
	srv6= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_servers);
	srv7= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_servers);
	srv8= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_servers);
	srv9= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_servers);

	h_shared = stattree.InsertItem( GetResString(IDS_SHAREDFILES) );
	shar1= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_shared);
	shar2= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_shared);
	shar3= stattree.InsertItem(GetResString(IDS_FSTAT_WAITING),h_shared);

	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,TVE_EXPAND);

	// Setup download-scope
	CRect rect;
	GetDlgItem(IDC_SCOPE_D)->GetWindowRect(rect) ;
	ScreenToClient(rect) ;
	m_DownloadOMeter.Create(WS_VISIBLE | WS_CHILD, rect, this) ; 
	m_DownloadOMeter.SetRange(0, theApp.glob_prefs->GetMaxGraphDownloadRate()+4, 0) ;
	m_DownloadOMeter.SetRange(0, theApp.glob_prefs->GetMaxGraphDownloadRate()+4, 1) ;
	m_DownloadOMeter.SetRange(0, theApp.glob_prefs->GetMaxGraphDownloadRate()+4, 2) ;

	m_DownloadOMeter.SetYUnits(GetResString(IDS_KBYTESEC)) ;
	//m_DownloadOMeter.SetXUnits(GetResString(IDS_TIME));

	// Setup upload-scope
	GetDlgItem(IDC_SCOPE_U)->GetWindowRect(rect) ;
	ScreenToClient(rect) ;
	m_UploadOMeter.Create(WS_VISIBLE | WS_CHILD, rect, this) ; 
	m_UploadOMeter.SetRange(0, theApp.glob_prefs->GetMaxGraphUploadRate()+4, 0) ;
	m_UploadOMeter.SetRange(0, theApp.glob_prefs->GetMaxGraphUploadRate()+4, 1) ;
	m_UploadOMeter.SetRange(0, theApp.glob_prefs->GetMaxGraphUploadRate()+4, 2) ;
	m_UploadOMeter.SetRange(0, theApp.glob_prefs->GetMaxGraphUploadRate()+4, 3) ;
	m_UploadOMeter.SetYUnits(GetResString(IDS_KBYTESEC)) ;
	//m_UploadOMeter.SetXUnits(GetResString(IDS_TIME));

	// Setup additional graph-scope
	GetDlgItem(IDC_STATSSCOPE)->GetWindowRect(rect) ;
	ScreenToClient(rect) ;
	m_Statistics.Create(WS_VISIBLE | WS_CHILD, rect, this) ; 
	m_Statistics.SetRanges(0, theApp.glob_prefs->GetStatsMax()) ;
	m_Statistics.autofitYscale=false;

	AddAnchor(IDC_STATIC_LINE,CSize(50,50));
	AddAnchor(IDC_STATTREE,CSize(50,50) ,CSize(100,100));
	AddAnchor(m_UploadOMeter,CSize(50,0) ,CSize(100,50));
	AddAnchor(m_DownloadOMeter,CSize(0,0) ,CSize(50,50));
	AddAnchor(m_Statistics,CSize(0,50) ,CSize(50,100));

	
	AddAnchor(IDC_C0,CSize(0,50));
	AddAnchor(IDC_C0_2,CSize(0,50));
	AddAnchor(IDC_C0_3,CSize(0,50));
	AddAnchor(IDC_C1,CSize(50,50));
	AddAnchor(IDC_C1_2,CSize(50,50));
	AddAnchor(IDC_C1_3,CSize(50,50));

	AddAnchor(IDC_S1,CSize(0,100));
	AddAnchor(IDC_S2,CSize(0,100));
	AddAnchor(IDC_S3,CSize(0,100));
	AddAnchor(IDC_S0,CSize(0,100));

	AddAnchor(IDC_STATIC_D3,CSize(0,50));
	AddAnchor(IDC_STATIC_U,CSize(50,50));
	AddAnchor(IDC_STATIC_D,CSize(0,50));
	AddAnchor(IDC_STATIC_U2,CSize(50,50));
	AddAnchor(IDC_STATIC_U3,CSize(50,50));
	AddAnchor(IDC_STATIC_D2,CSize(0,50));
	AddAnchor(IDC_STATIC_S2,CSize(0,100));
	AddAnchor(IDC_STATIC_S0,CSize(0,100));
	AddAnchor(IDC_STATIC_S1,CSize(0,100));
	AddAnchor(IDC_STATIC_S3,CSize(0,100));

	AddAnchor(IDC_TIMEAVG1,CSize(0,50));
	AddAnchor(IDC_TIMEAVG2,CSize(50,50));
	RepaintMeters();
	AddAnchor(m_Led1[0],CSize(0,50));
	AddAnchor(m_Led1[1],CSize(0,50));
	AddAnchor(m_Led1[2],CSize(0,50));
	AddAnchor(m_Led2[0],CSize(50,50));
	AddAnchor(m_Led2[1],CSize(50,50));
	AddAnchor(m_Led2[2],CSize(50,50));
	AddAnchor(m_Led3[0],CSize(0,100));
	AddAnchor(m_Led3[1],CSize(0,100));
	AddAnchor(m_Led3[2],CSize(0,100));
	AddAnchor(m_Led3[3],CSize(0,100));

	m_Statistics.SetYUnits("") ;
	m_Statistics.SetXUnits(GetResString(IDS_TIME));

	RepaintMeters();
	m_Statistics.SetBackgroundColor(theApp.glob_prefs->GetStatsColor(0)) ;
	m_Statistics.SetGridColor(theApp.glob_prefs->GetStatsColor(1)) ;
	
	m_DownloadOMeter.InvalidateCtrl();
	m_UploadOMeter.InvalidateCtrl();
	m_Statistics.InvalidateCtrl();

	if (theApp.glob_prefs->GetStatsInterval()==0) GetDlgItem(IDC_STATTREE)->EnableWindow(false);

	UpdateData(FALSE);

	EnableWindow( TRUE );

	m_ilastMaxConnReached = 0;
	peakconnections = 0;
	totalconnectionchecks = 0;
	averageconnections = 0;
	activeconnections = 0;
	maxDown=0;
	maxDownavg=0;

	return true;
}

void CStatisticsDlg::SetupLegend( int ResIdx, int ElmtIdx, int legendNr){
	CRect Rect;

	GetDlgItem( ResIdx )->GetWindowRect( Rect );
	ScreenToClient( Rect );
	
	if (legendNr==1){
		if (!m_Led1[ ElmtIdx ]) 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 ) );
	} else if (legendNr==2) {
		if (!m_Led2[ ElmtIdx ]) 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 ) );
	} else if (legendNr==3){
		if (!m_Led3[ ElmtIdx ]) 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 ) );
	}
}

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) ;
    // friends line
	m_UploadOMeter.SetPlotColor( theApp.glob_prefs->GetStatsColor(13) ,3) ;

	m_Statistics.SetBackgroundColor(theApp.glob_prefs->GetStatsColor(0)) ;
	m_Statistics.SetGridColor(theApp.glob_prefs->GetStatsColor(1)) ;
	m_Statistics.SetPlotColor( theApp.glob_prefs->GetStatsColor(8),0) ;
	m_Statistics.SetPlotColor( theApp.glob_prefs->GetStatsColor(10),1) ;
	m_Statistics.SetPlotColor( theApp.glob_prefs->GetStatsColor(9),2) ;
	m_Statistics.SetPlotColor( theApp.glob_prefs->GetStatsColor(11),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, 0 ,3);
	SetupLegend( IDC_S1, 1 ,3);
	SetupLegend( IDC_S2, 2 ,3);
	SetupLegend( IDC_S3, 3 ,3);
}

void CStatisticsDlg::SetCurrentRate(float uploadrate, float downloadrate, float uploadtonetworkrate) {
	double m_dPlotDataUp[ 4 ];
	double m_dPlotDataDown[ 3 ];
	int myStats[6];

	// current rate
	m_dPlotDataDown[2]=downloadrate;
	m_dPlotDataUp[2]=uploadrate;

    // current rate to network (friends excluded)
	m_dPlotDataUp[3]=uploadtonetworkrate;

	if (maxDown<downloadrate) maxDown=downloadrate;
	
	// 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();
//	UpdateConnectionsStatus();

	theApp.downloadqueue->GetDownloadStats(myStats);
	m_dPlotDataMore[0]=(activeconnections/3);//myStats[0];
	m_dPlotDataMore[1]=theApp.uploadqueue->GetActiveUploadsCount();
	m_dPlotDataMore[2]=theApp.uploadqueue->GetUploadQueueLength();
	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*(float)theApp.glob_prefs->GetMaxConperFive()/(float)10;
	if ( SpikeSize > SpikeTolerance )
		return 0;
	float Modifier = (1-(SpikeSize/SpikeTolerance));
	return Modifier;
}

void CStatisticsDlg::RecordRate() {
	
	if (theApp.stat_transferStarttime==0) return;

	// every second
    rateHistoryTicks.push_front(::GetTickCount());
	downrateHistory.push_front(theApp.stat_sessionReceivedBytes);
	uprateHistory.push_front(theApp.stat_sessionSentBytes);
    uprateHistoryFriends.push_front(theApp.stat_sessionSentBytesToFriend);
	
	// limit to maxmins 
    while (rateHistoryTicks.size() > 0 && rateHistoryTicks.front()-rateHistoryTicks.back() > (DWORD)(theApp.glob_prefs->GetStatsAverageMinutes()*60*1000)) {
        rateHistoryTicks.pop_back();
        downrateHistory.pop_back();
        uprateHistory.pop_back();
        uprateHistoryFriends.pop_back();
    }

}

void CStatisticsDlg::ShowStatistics() {
	CString cbuffer;
	CString cbuffer2;
	bool resize;
	DWORD running;
	int myStats[10];
	float DownAvgRate;

	resize=false;
	theApp.downloadqueue->GetDownloadStats(myStats);

	uint64 DownOHTotal = theApp.downloadqueue->GetDownDataOverheadFileRequest() + theApp.downloadqueue->GetDownDataOverheadSourceExchange() + theApp.downloadqueue->GetDownDataOverheadServer() + theApp.downloadqueue->GetDownDataOverheadOther();
	uint64 DownOHTotalPackets = theApp.downloadqueue->GetDownDataOverheadFileRequestPackets() + theApp.downloadqueue->GetDownDataOverheadSourceExchangePackets() + theApp.downloadqueue->GetDownDataOverheadServerPackets() + theApp.downloadqueue->GetDownDataOverheadOtherPackets();
	cbuffer.Format(GetResString(IDS_STATS_DDATA),CastItoXBytes( theApp.stat_sessionReceivedBytes),	CastItoXBytes( theApp.stat_sessionReceivedBytes+theApp.glob_prefs->GetTotalDownloaded()));
	stattree.SetItemText(down1, cbuffer);
	cbuffer.Format(GetResString(IDS_TOVERHEAD),	CastItoXBytes(DownOHTotal), CastItoIShort(DownOHTotalPackets));
	stattree.SetItemText(down2, cbuffer);
	cbuffer.Format(GetResString(IDS_FROVERHEAD), CastItoXBytes( theApp.downloadqueue->GetDownDataOverheadFileRequest()), CastItoIShort(theApp.downloadqueue->GetDownDataOverheadFileRequestPackets()));
	stattree.SetItemText(down3, cbuffer);
	cbuffer.Format(GetResString(IDS_SSOVERHEAD), CastItoXBytes( theApp.downloadqueue->GetDownDataOverheadSourceExchange()), CastItoIShort(theApp.downloadqueue->GetDownDataOverheadSourceExchangePackets()) );
	stattree.SetItemText(down4, cbuffer);
	cbuffer.Format(GetResString(IDS_SOVERHEAD), CastItoXBytes( theApp.downloadqueue->GetDownDataOverheadServer()), CastItoIShort(theApp.downloadqueue->GetDownDataOverheadServerPackets()));
	stattree.SetItemText(down5, cbuffer);
	cbuffer.Format(GetResString(IDS_STATS_FOUNDSRC),myStats[0]);
	stattree.SetItemText(down6, cbuffer);
    cbuffer.Format(GetResString(IDS_STATS_ACTDL),myStats[1]);
	stattree.SetItemText(down7, cbuffer);
	uint64 UpOHTotal = theApp.uploadqueue->GetUpDataOverheadFileRequest() + theApp.uploadqueue->GetUpDataOverheadSourceExchange() + theApp.uploadqueue->GetUpDataOverheadServer() + theApp.uploadqueue->GetUpDataOverheadOther();
	uint64 UpOHTotalPackets = theApp.uploadqueue->GetUpDataOverheadFileRequestPackets() + theApp.uploadqueue->GetUpDataOverheadSourceExchangePackets() + theApp.uploadqueue->GetUpDataOverheadServerPackets() + theApp.uploadqueue->GetUpDataOverheadOtherPackets();
	cbuffer.Format(GetResString(IDS_STATS_UDATA),CastItoXBytes( theApp.stat_sessionSentBytes),CastItoXBytes( theApp.stat_sessionSentBytes+theApp.glob_prefs->GetTotalUploaded()));
	stattree.SetItemText(up1, cbuffer);

	cbuffer.Format(GetResString(IDS_STATS_UDATA_FRIENDS),CastItoXBytes( theApp.stat_sessionSentBytesToFriend));
    stattree.SetItemText(upFriendsAmount, cbuffer);

    cbuffer.Format(GetResString(IDS_TOVERHEAD), CastItoXBytes( UpOHTotal), CastItoIShort(UpOHTotalPackets));
	stattree.SetItemText(up2, cbuffer);
	cbuffer.Format(GetResString(IDS_FROVERHEAD), CastItoXBytes( theApp.uploadqueue->GetUpDataOverheadFileRequest()), CastItoIShort(theApp.uploadqueue->GetUpDataOverheadFileRequestPackets()));
	stattree.SetItemText(up3, cbuffer);
	cbuffer.Format(GetResString(IDS_SSOVERHEAD), CastItoXBytes( theApp.uploadqueue->GetUpDataOverheadSourceExchange()), CastItoIShort(theApp.uploadqueue->GetUpDataOverheadSourceExchangePackets()));
	stattree.SetItemText(up4, cbuffer);
	cbuffer.Format(GetResString(IDS_SOVERHEAD), CastItoXBytes( theApp.uploadqueue->GetUpDataOverheadServer()), CastItoIShort(theApp.uploadqueue->GetUpDataOverheadServerPackets()));
	stattree.SetItemText(up5, cbuffer);
	cbuffer.Format(GetResString(IDS_STATS_TOTALUL),theApp.uploadqueue->GetUploadQueueLength());
	stattree.SetItemText(uptotal, cbuffer);
	cbuffer.Format(GetResString(IDS_STATS_ACTUL),theApp.uploadqueue->GetActiveUploadsCount());
	stattree.SetItemText(up6, cbuffer);
	cbuffer.Format(GetResString(IDS_STATS_WAITINGUSERS),theApp.uploadqueue->GetWaitingUserCount());
	stattree.SetItemText(up7, cbuffer);
	cbuffer.Format(GetResString(IDS_STATS_SUCCUPCOUNT),theApp.uploadqueue->GetSuccessfullUpCount());
	stattree.SetItemText(up8, cbuffer);
	cbuffer.Format(GetResString(IDS_STATS_FAILUPCOUNT),theApp.uploadqueue->GetFailedUpCount());
	stattree.SetItemText(up9, cbuffer);
	running=theApp.uploadqueue->GetAverageUpTime();
	cbuffer.Format(GetResString(IDS_STATS_AVEUPTIME),CastSecondsToHM(running));
	stattree.SetItemText(up10, cbuffer);

	if (theApp.stat_transferStarttime>0) {
		cbuffer.Format(GetResString(IDS_STATS_AVGDL),GetAvgDownloadRate(AVG_SESSION));
		stattree.SetItemText(con1, cbuffer);

		cbuffer.Format(GetResString(IDS_STATS_AVGUL),GetAvgUploadRate(AVG_SESSION));
		stattree.SetItemText(con2, cbuffer);

		DownAvgRate=GetAvgDownloadRate(AVG_SESSION);
		if (maxDownavg<DownAvgRate) maxDownavg=DownAvgRate;
		cbuffer.Format(GetResString(IDS_STATS_MAXAVGDL),maxDownavg);
		stattree.SetItemText(con12, cbuffer);
		cbuffer.Format(GetResString(IDS_STATS_MAXDL),maxDown);
		stattree.SetItemText(con13, cbuffer);
	}
	if (theApp.stat_reconnects>0) cbuffer.Format(GetResString(IDS_STATS_RECONNECTS),theApp.stat_reconnects-1);
		else cbuffer.Format(GetResString(IDS_STATS_RECONNECTS),0);
	stattree.SetItemText(con3, cbuffer);

	if (theApp.stat_transferStarttime==0) cbuffer.Format(GetResString(IDS_STATS_WAITTRANSF)); else {
		running=(GetTickCount()-theApp.stat_transferStarttime)/1000;
		cbuffer.Format(GetResString(IDS_TRANSFERTIME),CastSecondsToHM(running));
	}
	stattree.SetItemText(con4, cbuffer);

	if (theApp.stat_serverConnectTime==0) cbuffer.Format(GetResString(IDS_STATS_WAITCONN)); else {
		running=(GetTickCount()-theApp.stat_serverConnectTime)/1000;
		cbuffer.Format(GetResString(IDS_STATS_CONNECTEDSINCE),CastSecondsToHM(running));
	}
	stattree.SetItemText(con5, cbuffer);

	if (theApp.stat_sessionReceivedBytes>0 && theApp.stat_sessionSentBytes>0 )
		if (theApp.stat_sessionReceivedBytes<theApp.stat_sessionSentBytes) {
			cbuffer.Format("%s %.2f : 1",GetResString(IDS_STATS_RATIO),(float)theApp.stat_sessionSentBytes/theApp.stat_sessionReceivedBytes);
			stattree.SetItemText(tran0, cbuffer);
		} else {
			cbuffer.Format("%s 1 : %.2f",GetResString(IDS_STATS_RATIO),(float)theApp.stat_sessionReceivedBytes/theApp.stat_sessionSentBytes);
			stattree.SetItemText(tran0, cbuffer);
		}

	// shared files stats
	cbuffer.Format(GetResString(IDS_SHAREDFILESCOUNT),theApp.sharedfiles->GetCount());stattree.SetItemText(shar1, cbuffer);

	uint64 allsize=theApp.sharedfiles->GetDatasize();
	cbuffer.Format(GetResString(IDS_SF_SIZE),CastItoXBytes(allsize));stattree.SetItemText(shar2, cbuffer);
	
	if(theApp.sharedfiles->GetCount() != 0)
		cbuffer2.Format( "%s", CastItoXBytes((uint64)allsize/theApp.sharedfiles->GetCount()));
	else {
		cbuffer2 = "-";
	}
	cbuffer.Format(GetResString(IDS_SF_AVERAGESIZE),cbuffer2);
	stattree.SetItemText(shar3, cbuffer);
	// get clientversion-counts

	// statsclientstatus : original idea and code by xrmb
	
	CMap<uint8, uint8, uint32, uint32> clientStatus;
	CMap<uint16, uint16, uint32, uint32> clientVersionEDonkey;
	CMap<uint16, uint16, uint32, uint32> clientVersionEDonkeyHybrid;
	CMap<uint8, uint8, uint32, uint32> clientVersionEMule;
	uint32 totalclient;
	theApp.clientlist->GetStatistics(totalclient, myStats, &clientStatus, &clientVersionEDonkey, &clientVersionEDonkeyHybrid, &clientVersionEMule);
	totalclient -= myStats[0];
	if( !totalclient )
		totalclient = 1;
	cbuffer.Format("eMule: %i (%1.1f%%)",myStats[2],(double)100*myStats[2]/totalclient);stattree.SetItemText(cli1, cbuffer);
	cbuffer.Format("eDonkeyHybrid: %i (%1.1f%%)",myStats[4],(double)100*myStats[4]/totalclient);stattree.SetItemText(cli2, cbuffer);
	cbuffer.Format("eDonkey: %i (%1.1f%%)",myStats[1],(double)100*myStats[1]/totalclient);stattree.SetItemText(cli3, cbuffer);
	cbuffer.Format("cDonkey: %i (%1.1f%%)",myStats[5],(double)100*myStats[5]/totalclient);stattree.SetItemText(cli4, cbuffer);
	cbuffer.Format("Old MLDonkey: %i (%1.1f%%)",myStats[3],(double)100*myStats[3]/totalclient);stattree.SetItemText(cli5, cbuffer);
	cbuffer.Format(GetResString(IDS_STATS_UNKNOWNCLIENT),myStats[0]);stattree.SetItemText(cli6, cbuffer);
	cbuffer.Format(GetResString(IDS_STATS_FILTEREDCLIENTS),theApp.stat_filteredclients);stattree.SetItemText(cli7, cbuffer);
	
	if (stattree.GetItemState(cli3, TVIS_EXPANDED)&&TVIS_EXPANDED == TVIS_EXPANDED ) {

		uint32 totcnt = myStats[1];

		//--- find top 4 eDonkey client versions ---
		uint32	currtop = 0;
		uint32	lasttop = 0xFFFFFFFF;
		for(uint32 i=0; i<4; i++)
		{
			POSITION pos=clientVersionEDonkey.GetStartPosition();
			uint32 topver=0;
			uint32 topcnt=0;
			double topper=0;
			while(pos)
			{
				uint16	ver;
				uint32	cnt;
				clientVersionEDonkey.GetNextAssoc(pos, ver, cnt);
				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.Format("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 ) {

		uint32 totcnt = myStats[4];

		//--- find top 4 eDonkey client versions ---
		uint32	currtop = 0;
		uint32	lasttop = 0xFFFFFFFF;
		for(uint32 i=0; i<4; i++)
		{
			POSITION pos=clientVersionEDonkeyHybrid.GetStartPosition();
			uint32 topver=0;
			uint32 topcnt=0;
			double topper=0;
			while(pos)
			{
				uint16	ver;
				uint32	cnt;
				clientVersionEDonkeyHybrid.GetNextAssoc(pos, ver, cnt);
				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.Format("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 ) {
		uint32 totcnt = myStats[2];

		//--- find top 4 eMule client versions ---
		uint32	currtop = 0;
		uint32	lasttop = 0xFFFFFFFF;
		for(uint32 i=0; i<4; i++)
		{
			POSITION pos=clientVersionEMule.GetStartPosition();
			uint32 topver=0;
			uint32 topcnt=0;
			double topper=0;
			while(pos)
			{
				uint8	ver;
				uint32	cnt;
				clientVersionEMule.GetNextAssoc(pos, ver, cnt);
				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.Format("v0.%02X: %i (%1.1f%%)", topver, topcnt, topper*100);
			else
				cbuffer="";

			stattree.SetItemText(cli_versions[i], cbuffer);
		}
		// xrmb
	}

	// get serverstats
	uint32 servtotal;
	uint32 servfail;
	uint32 servuser;
	uint32 servfile;
	uint32 servtuser;
	uint32 servtfile;
	float servocc;
	theApp.serverlist->GetStatus( servtotal, servfail, servuser, servfile, servtuser, servtfile,servocc);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_WORKING),servtotal-servfail);stattree.SetItemText(srv1, cbuffer);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_FAIL),servfail);stattree.SetItemText(srv2, cbuffer);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_TOTAL),servtotal);stattree.SetItemText(srv3, cbuffer);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_DELCOUNT),theApp.serverlist->GetDeletedServerCount());stattree.SetItemText(srv4, cbuffer);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_WUSER),servuser);stattree.SetItemText(srv5, cbuffer);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_WFILE),servfile);stattree.SetItemText(srv6, cbuffer);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_USER),servtuser);stattree.SetItemText(srv7, cbuffer);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_FILE),servtfile);stattree.SetItemText(srv8, cbuffer);
	cbuffer.Format("%s: %i",GetResString(IDS_SF_ACTIVECON),activeconnections);stattree.SetItemText(con6, cbuffer);
	cbuffer.Format(GetResString(IDS_SF_SRVOCC),servocc);stattree.SetItemText(srv9, cbuffer);
	uint32 m_itemp = theApp.listensocket->GetMaxConnectionReached();
	if( m_itemp != m_ilastMaxConnReached ){
		char osDate[30],osTime[30];
		_strtime( osTime );
		_strdate( osDate );
		cbuffer.Format("%s: %i : %s %s",GetResString(IDS_SF_MAXCONLIMITREACHED),m_itemp,osDate,osTime);stattree.SetItemText(con7, cbuffer);
		m_ilastMaxConnReached = m_itemp;
	}
	else if( m_itemp == 0 ){
		cbuffer.Format("%s: %i",GetResString(IDS_SF_MAXCONLIMITREACHED),m_itemp);stattree.SetItemText(con7, cbuffer);}

	if(theApp.serverconnect->IsConnected()){
		cbuffer.Format("%s: %i",GetResString(IDS_SF_AVGCON),(int)averageconnections);stattree.SetItemText(con8, cbuffer);
	}
	else{
		stattree.SetItemText(con8, GetResString(IDS_STATS_WAITCONN));
	}
	cbuffer.Format("%s: %i",GetResString(IDS_SF_PEAKCON),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)*1000 / (GetTickCount()-theApp.stat_transferStarttime) / 1024;
	} else {
		if (downrateHistory.size()==0) return 0;

		return (float)((float)(downrateHistory.front()-downrateHistory.back())*1000/(rateHistoryTicks.front()-rateHistoryTicks.back())/1024);
	}
}

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)*1000 / (GetTickCount()-theApp.stat_transferStarttime) / 1024 +
               (float)(theApp.stat_sessionSentBytesToFriend)*1000 / (GetTickCount()-theApp.stat_transferStarttime) / 1024;
	} else  {
		if (uprateHistory.size()==0) return 0;

		return (float)((float)(uprateHistory.front()-uprateHistory.back())*1000/(rateHistoryTicks.front()-rateHistoryTicks.back())/1024) +
               (float)((float)(uprateHistoryFriends.front()-uprateHistoryFriends.back())*1000/(rateHistoryTicks.front()-rateHistoryTicks.back())/1024);
	}
}

void CStatisticsDlg::OnShowWindow(BOOL bShow,UINT nStatus){

}

void CStatisticsDlg::OnSize(UINT nType, int cx, int cy)
{
	CResizableDialog::OnSize(nType, cx, cy);
	ShowInterval();
}  //OnSize

void CStatisticsDlg::ShowInterval(){
	// Check if OScope already initialized
	if(m_DownloadOMeter.GetSafeHwnd() != NULL && m_UploadOMeter.GetSafeHwnd() != NULL){ 
		// Retrieve the size (in pixel) of the OScope
		CRect plotRect;
		m_UploadOMeter.GetPlotRect(plotRect);
		
		// Dynamic update of time scale [Maella]
		int shownSecs = plotRect.Width() * theApp.glob_prefs->GetTrafficOMeterInterval(); 
		if(shownSecs == 0){
			m_DownloadOMeter.SetXUnits(GetResString(IDS_STOPPED)); 
			m_UploadOMeter.SetXUnits(GetResString(IDS_STOPPED)); 
		} 
		else {
			const CString buffer = CastSecondsToHM(shownSecs);
			m_UploadOMeter.SetXUnits(buffer);
			m_DownloadOMeter.SetXUnits(buffer); 
		}
		UpdateData(FALSE);
	}
}

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);
	}
}

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_TOTALU));
	CString value;value.Format(" (%u %s)",theApp.glob_prefs->GetStatsAverageMinutes(),GetResString(IDS_MINS) );
	GetDlgItem(IDC_TIMEAVG1)->SetWindowText(GetResString(IDS_AVG) + value );
	GetDlgItem(IDC_TIMEAVG2)->SetWindowText(GetResString(IDS_AVG) + value);
}

