#include "stdafx.h"
#include "emule.h"
#include "MiniMule.h"
#include "preferences.h"
#include "UploadQueue.h"
#include "DownloadQueue.h"
#include "sockets.h"
#include "server.h"
#include "emuledlg.h"
#include "menuCmds.h"
#include "opcodes.h"
#include "WebServices.h"
#include "EmuleDLG.h"
#include "OtherFunctions.h"
#include "MuleSystrayDlg.h"
#include "PreferencesDlg.h" // gomez82 >>> NCFG - [NeoConfiguration] 
#include "Statistics.h"
#include ".\Neo\SysInfo\SystemInfo.h"
#include "Version.h" // gomez82 >>> NV - [NeoVersion]  

#define SNAPOFFSET	25

// these variables should have been defined in some standard header but is not
#define WS_EX_LAYERED 0x00080000 
//#define LWA_COLORKEY 1 // Use color as the transparency color.
//#define LWA_ALPHA    2 // Use bAlpha to determine the opacity of the layer

// Function pointer for lyering API in User32.dll
typedef BOOL (WINAPI *lpfnSetLayeredWindowAttributes)
            (HWND hWnd, COLORREF cr, BYTE bAlpha, DWORD dwFlags);

lpfnSetLayeredWindowAttributes g_pSetLayeredWindowAttributes;


IMPLEMENT_DYNAMIC(CMiniMule, CDialog)

CMiniMule::CMiniMule(CWnd* pParent /*=NULL*/)
: CDialog(IDD, pParent)
{
	m_bEasyMove = true;

	m_hCSConn = NULL;
	m_hCSCing = NULL;
	m_hCSDconn = NULL;
	manual = false;
	//m_nLastUpdate = ::GetTickCount() - SEC2MS(1);

	OSVERSIONINFO os = { sizeof(os) };
	GetVersionEx(&os);
	// use m_bWin2k before any call to the m_pSetLayeredWindowAttributes to make sure we are runninng Win2K
	m_bWin2K = ( VER_PLATFORM_WIN32_NT == os.dwPlatformId && os.dwMajorVersion >= 5 ); 
	if (!m_bWin2K)
		return;

    //  get the function from the user32.dll 
    HMODULE hUser32 = GetModuleHandle(_T("USER32.DLL"));
    g_pSetLayeredWindowAttributes = (lpfnSetLayeredWindowAttributes)
                        GetProcAddress(hUser32, "SetLayeredWindowAttributes");
}

CMiniMule::~CMiniMule()
{
	if(m_hCSConn)
		DestroyIcon(m_hCSConn);
	if(m_hCSCing)
		DestroyIcon(m_hCSCing);
	if(m_hCSDconn)
		DestroyIcon(m_hCSDconn);
	m_ctrlSpeedMeter.DestroyWindow();
}

void CMiniMule::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_MM_CONNSTATE, m_ctrlMMConnState);
}


BEGIN_MESSAGE_MAP(CMiniMule, CDialog)
//	ON_BN_CLICKED(IDC_MM_MENU, OnMenuButtonClicked)
	ON_WM_WINDOWPOSCHANGING()
	ON_WM_LBUTTONDOWN()
	ON_WM_CONTEXTMENU()
	ON_WM_CLOSE()
//	ON_WM_SHOWWINDOW()
END_MESSAGE_MAP()


BOOL CMiniMule::OnInitDialog()
{
	CDialog::OnInitDialog();

	InitWindowStyles(this);
	CString buffer = VERSION_MOD;	
	//CString buffer2;
	buffer += " ";
	buffer += (GetResString(IDS_X_MINIMULE));
	//buffer += "       ||       ";	
	//buffer2.Format("CPU: %3d%% Mem: %.2fMb",theApp.sysinfo->GetCpuUsage(), (double)(theApp.sysinfo->GetMemoryUsage()/1024));
	//buffer += buffer2;
	SetWindowText(buffer);
	m_hCSConn = theApp.LoadIcon(_T("CONNECT"), 32, 32);
	m_hCSCing = theApp.LoadIcon(_T("STOPCONNECTING"), 32, 32);
	m_hCSDconn = theApp.LoadIcon(_T("DISCONNECT"), 32, 32);
	RECT rect;
	UINT nPlaceholderID = IDC_SM_PLACEHOLDER;
	GetDlgItem(nPlaceholderID)->GetWindowRect(&rect);
	ScreenToClient(&rect);
	m_ctrlSpeedMeter.CreateEx(WS_EX_STATICEDGE, NULL, NULL, WS_CHILD | WS_VISIBLE, rect, this, 123, 0);
	SetSpeedMeterRange();
	m_ctrlSpeedMeter.EnableWindow(true);
	//RunMiniMule();
	MMUpdate();
	return true;
}

void CMiniMule::RunMiniMule(bool resetMiniMule)
{
	//if (::GetTickCount() - m_nLastUpdate < SEC2MS(1))
	//	return;
	//m_nLastUpdate = ::GetTickCount();

	reset = resetMiniMule;
	MMUpdate();
}

void CMiniMule::MMUpdate()
{
	//Retrieve the current datarates
	const float upratekb = (float)theApp.uploadqueue->GetDatarate() / 1024;
	const float downratekb = (float)theApp.downloadqueue->GetDatarate() / 1024;
	SetSpeedMeterValues((int)upratekb, (int)downratekb);

	if (!(theApp.emuledlg->IsRunning() || IsWindowVisible()))
		return;

	static uint8 Transparency = 0;
	if(Transparency != thePrefs.GetMiniMuleTransparency()){
		Transparency = thePrefs.GetMiniMuleTransparency();
		SetTransparent(255 - Transparency);
	}

	if (reset)
		SetSpeedMeterRange();

	TCHAR buffer3[256];
	CString buffer;
	CString buffer2;

	buffer = VERSION_MOD;
	buffer += _T(" ");
	buffer += (GetResString(IDS_X_MINIMULE));
	buffer += _T("  ||  ");	
	buffer2.Format(_T("CPU: %3d%% Mem: %.2fMb"),theApp.sysinfo->GetCpuUsage(), (double)(theApp.sysinfo->GetMemoryUsage()/1024));
	buffer += buffer2;
	SetWindowText(buffer);

	CDownloadQueue::SDownloadStats myStats;
	theApp.downloadqueue->GetDownloadSourcesStats(myStats);

	if (theApp.serverconnect->IsConnected())
		m_ctrlMMConnState.SetIcon(m_hCSDconn);
	else if (theApp.serverconnect->IsConnecting())
		m_ctrlMMConnState.SetIcon(m_hCSCing);
	else
		m_ctrlMMConnState.SetIcon(m_hCSConn);
	if (theApp.serverconnect->IsConnected())
	{ 
		buffer.Format(_T("%u"),theApp.serverconnect->GetClientID());
		if (theApp.serverconnect->IsLowID()) buffer2 = GetResString(IDS_IDLOW);
		else buffer2 = GetResString(IDS_IDHIGH);
		GetDlgItem(IDC_MM_SERVER)->SetWindowText(theApp.serverconnect->GetCurrentServer()->GetListName());
		GetDlgItem(IDC_MM_ID)->SetWindowText(buffer + _T(" [") + buffer2 + _T("]"));
	} else {
		GetDlgItem(IDC_MM_SERVER)->SetWindowText(GetResString(IDS_NOTCONNECTED));
		GetDlgItem(IDC_MM_ID)->SetWindowText(GetResString(IDS_NOTCONNECTED));
	}
	buffer.Format( GetResString( IDS_X_MM_ACTDL ) , myStats.a[1] );
	GetDlgItem(IDC_MM_DLCOUNT)->SetWindowText(buffer);
	buffer.Format(GetResString(IDS_X_MM_ACTUP),theApp.uploadqueue->GetUploadQueueLength());
	GetDlgItem(IDC_MM_ULCOUNT)->SetWindowText(buffer);

	//Retrieve the current datarates
	float lastuprateoverheadkb = ((float)theStats.GetUpDatarateOverhead() /*+ (float)theApp.uploadqueue->GetDatarate()*/)/1024;
	float lastdownrateoverheadkb = ((float)theStats.GetDownDatarateOverhead() /*+ (float)theApp.downloadqueue->GetDatarate()*/)/1024;
	if( thePrefs.ShowOverhead() )
		_stprintf(buffer3,GetResString(IDS_UPDOWN), upratekb, lastuprateoverheadkb, downratekb, lastdownrateoverheadkb);
	else
		_stprintf(buffer3,GetResString(IDS_UPDOWNSMALL), upratekb, downratekb);
	GetDlgItem(IDC_MM_ULDL)->SetWindowText(buffer3);

#ifdef _DEBUG_NEO // gomez82 >>> ND - [NeoDebug]
 #ifdef NEO_SS // gomez82 >>> NSS - [NeoSourceStorage]
	_stprintf(buffer3,_T("Fails O: %u/%u, S: %u/%u, E: %u "),thePrefs.m_iOfficialFails,thePrefs.m_iOfficialReasks,thePrefs.m_iStorageFails,thePrefs.m_iStorageReasks, thePrefs.m_iElseFails);
 #endif // gomez82 >>>_SS // gomez82 >>> NSS END
#else
	uint64 ulReceived = theStats.sessionReceivedBytes;
	uint64 ulSent = theStats.sessionSentBytes;
	uint64 ulCumReceived = thePrefs.GetTotalDownloaded() + ulReceived;
	uint64 ulCumSent = thePrefs.GetTotalUploaded() + ulSent;
	_stprintf(buffer3,GetResString(IDS_X_UPDOWN), CastItoXBytes(ulSent, false, false), CastItoXBytes(ulCumSent, false, false), CastItoXBytes(ulReceived, false, false), CastItoXBytes(ulCumReceived, false, false));
	//buffer.Format(GetResString(IDS_SF_TRANS));
	//buffer.AppendFormat(_T(" %s"),buffer3);
#endif //_DEBUG_NEO // gomez82 >>> ND END
	//Retrieve the transfer
	GetDlgItem(IDC_MM_ULDL_TRANSFER)->SetWindowText(buffer3);

}

//void CMiniMule::OnShowWindow(BOOL bShow, UINT nStatus){
//	CSnapDialog::OnShowWindow(bShow,nStatus);
//}

void CMiniMule::OnClose(){
	if(!theApp.emuledlg->TrayIsVisible())
		theApp.emuledlg->ShowWindow(SW_SHOW);
	manual = false;
	CDialog::OnCancel();
}

void CMiniMule::OnWindowPosChanging( WINDOWPOS* wndPos )
{
	RECT rcScrn;
	SystemParametersInfo(SPI_GETWORKAREA, 0, &rcScrn, 0);

	// Snap X axis
	if (abs(wndPos->x - rcScrn.left) <= 15)
		wndPos->x = rcScrn.left;
	else if (abs(wndPos->x + wndPos->cx - rcScrn.right) <= SNAPOFFSET)
		wndPos->x = rcScrn.right - wndPos->cx;

	// Snap Y axis
	if (abs(wndPos->y - rcScrn.top) <= SNAPOFFSET)
		wndPos->y = rcScrn.top;
	else if (abs(wndPos->y + wndPos->cy - rcScrn.bottom) <= SNAPOFFSET)
		wndPos->y = rcScrn.bottom - wndPos->cy;
}

void CMiniMule::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
{
//	DoMenu(point);
	theApp.emuledlg->OnTrayRButtonUp(point);
}

void CMiniMule::OnLButtonDown(UINT nFlags, CPoint point)
{
    if (m_bEasyMove)
        PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x, point.y));	

    CDialog::OnLButtonDown(nFlags, point);
}

void CMiniMule::EnableEasyMove(bool pEnable)
{
    m_bEasyMove = pEnable;
}

bool CMiniMule::SetTransparent(BYTE bAlpha)
{
	static int preAlpha = thePrefs.GetMiniMuleTransparency();

	if (!m_bWin2K || (g_pSetLayeredWindowAttributes == NULL) || ((bAlpha == preAlpha) && !reset))
        return false;

	preAlpha = bAlpha;

    if (bAlpha < 255)
    {
        //  set layered style for the dialog
        SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
        
        //  call it with 255 as alpha - opacity
        g_pSetLayeredWindowAttributes(m_hWnd, 0, bAlpha, LWA_ALPHA);
    }
    else
    {
        SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);

        // Ask the window and its children to repaint
        ::RedrawWindow(m_hWnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);	//makes the flicker...
    }

    return true;
}

void CMiniMule::Show()
{
	if(!IsWindowVisible())
	{
//		m_nLastUpdate = 0;
		if (thePrefs.IsMiniMuleUpdate())
			RunMiniMule();
		else
			RunMiniMule(true);
		ShowWindow(SW_SHOW);
	}
}

void CMiniMule::Hide()
{
	ShowWindow(SW_HIDE);
}

/*void CMiniMule::OnMenuButtonClicked()
{
	CRect rectBn;
	CPoint thePoint;
	GetDlgItem(IDC_MM_MENU)->GetWindowRect(&rectBn);
	thePoint = rectBn.BottomRight();
	DoMenu(thePoint);
}

void CMiniMule::DoMenu(CPoint doWhere)
{
	theApp.emuledlg->OnTrayRButtonUp(doWhere);
}*/

void CMiniMule::SetSpeedMeterRange()
{
	int iMaxRange = thePrefs.GetMaxGraphDownloadRate();
	if (thePrefs.GetMaxGraphUploadRate(true) > iMaxRange)
		iMaxRange = thePrefs.GetMaxGraphUploadRate(true);
	UINT nLastMaxRange, nLastMinRange;
	m_ctrlSpeedMeter.GetRange(nLastMaxRange, nLastMinRange);
	if ((int)nLastMaxRange != iMaxRange)
		m_ctrlSpeedMeter.SetRange(0, iMaxRange, true);	
}

