#include "stdafx.h"
#include "emule.h"
#include "MiniMule.h"
#include "preferences.h"
#include "UploadQueue.h"
#include "DownloadQueue.h"
#include "ServerConnect.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 "Neo/CP/PreferencesDlg.h" // NEO: NCFG - [NeoConfiguration] <-- Xanatos --
#include "Statistics.h"
#include "Neo/SysInfo/SystemInfo.h" // NEO: SI - [SysInfo] <-- Xanatos --
#include "Neo/NeoVersion.h" // NEO: NV - [NeoVersion]  <-- Xanatos --
#include "Neo/Functions.h"
#include "Neo/BandwidthControl/BandwidthControl.h"
#include "ListenSocket.h"
#include "SharedFileList.h"
#ifdef VOODOO // NEO: VOODOO - [UniversalPartfileInterface] -- Xanatos -->
#include "Neo/voodoo.h"
#endif // VOODOO // NEO: VOODOO END <-- Xanatos --
#include "MemDC.h"

#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_hCSConn = NULL;
	//m_hCSCing = NULL;
	//m_hCSDconn = NULL;
	manual = false;

	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()
{
	m_Back.DeleteObject();
	//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);
}

BEGIN_MESSAGE_MAP(CMiniMule, CDialog)
	ON_WM_WINDOWPOSCHANGING()
	ON_WM_LBUTTONDOWN()
	ON_WM_CONTEXTMENU()
	ON_WM_CLOSE()
	ON_WM_DESTROY()
	ON_WM_ERASEBKGND()
	ON_WM_PAINT()
//	ON_WM_SHOWWINDOW()
END_MESSAGE_MAP()

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

	LoadWindowRect(_T("MiniMule"), TRUE);

	InitWindowStyles(this);
	CString buffer = MOD_VERSION;	
	buffer += " ";
	buffer += (GetResString(IDS_X_MINIMULE));
	SetWindowText(buffer);

	m_Back.Attach(theApp.LoadImage(_T("MMBACK"),_T("JPG")));
	//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 = {269,5,383,90};
	m_ctrlSpeedMeter.CreateEx(WS_EX_STATICEDGE, NULL, NULL, WS_CHILD | WS_VISIBLE, rect, this, 123, 0);
	SetSpeedMeterRange();
	m_ctrlSpeedMeter.EnableWindow(true);

	m_rcText.SetRect(5,5,264,90);

	m_crTextColor = ::GetSysColor(COLOR_WINDOWTEXT);
	theApp.LoadSkinColorAlt(_T("MiniMuleLv"), _T("MMLv"), m_crTextColor);

	MMUpdate();
	return true;
}

void CMiniMule::OnDestroy() 
{
	SaveWindowRect(_T("MiniMule"), FALSE);
	CDialog::OnDestroy();
}

void CMiniMule::OnSysColorChange()
{
	m_Back.DeleteObject();
	//if(m_hCSConn)
	//	DestroyIcon(m_hCSConn);
	//if(m_hCSCing)
	//	DestroyIcon(m_hCSCing);
	//if(m_hCSDconn)
	//	DestroyIcon(m_hCSDconn);

	m_Back.Attach(theApp.LoadImage(_T("MMBACK"),_T("JPG")));
	//m_hCSConn = theApp.LoadIcon(_T("CONNECT"), 32, 32);
	//m_hCSCing = theApp.LoadIcon(_T("STOPCONNECTING"), 32, 32);
	//m_hCSDconn = theApp.LoadIcon(_T("DISCONNECT"), 32, 32);

	m_crTextColor = ::GetSysColor(COLOR_WINDOWTEXT);
	theApp.LoadSkinColorAlt(_T("MiniMuleLv"), _T("MMLv"), m_crTextColor);
}

CString FormatLabel(CString buffer, CDownloadQueue::SDownloadStats& myStats)
{
	buffer.Replace(_T("%n"),_T("\n"));

	if(buffer.Find(_T("%us")) != -1)
		buffer.Replace(_T("%us"),StrLine(_T("%.2f"), theApp.bandwidthControl->GetCurrDataUpload()));
	if(buffer.Find(_T("%ds")) != -1)
		buffer.Replace(_T("%ds"),StrLine(_T("%.2f"), theApp.bandwidthControl->GetCurrDataDownload()));

#ifdef VOODOO // NEO: VOODOO - [UniversalPartfileInterface] -- Xanatos -->
	if(buffer.Find(_T("%vus")) != -1)
		buffer.Replace(_T("%vus"),StrLine(_T("%.2f"), (float)theApp.voodoo->GetUpDatarate()/1024));
	if(buffer.Find(_T("%vds")) != -1)
		buffer.Replace(_T("%vds"),StrLine(_T("%.2f"), (float)theApp.voodoo->GetDownDatarate()/1024));
#endif // VOODOO // NEO: VOODOO END <-- Xanatos --

	if(buffer.Find(_T("%uo")) != -1)
		buffer.Replace(_T("%uo"),StrLine(_T("%.2f"), theApp.bandwidthControl->GetCurrUpload()));
	if(buffer.Find(_T("%do")) != -1)
		buffer.Replace(_T("%do"),StrLine(_T("%.2f"), theApp.bandwidthControl->GetCurrDownload()));

	if(buffer.Find(_T("%ts")) != -1)
		buffer.Replace(_T("%ts"),StrLine(_T("%i"), theApp.sharedfiles->GetCount));
	if(buffer.Find(_T("%td")) != -1)
		buffer.Replace(_T("%td"),StrLine(_T("%i"), theApp.downloadqueue->GetFileCount()));

	if(buffer.Find(_T("%au")) != -1)
		buffer.Replace(_T("%au"),StrLine(_T("%i"),theApp.uploadqueue->GetUploadQueueLength()));
	if(buffer.Find(_T("%ad")) != -1)
		buffer.Replace(_T("%ad"),StrLine(_T("%i"),myStats.a[1]));
	if(buffer.Find(_T("%ac")) != -1)
		buffer.Replace(_T("%ac"),StrLine(_T("%i"),theApp.listensocket->GetOpenSockets()));

	if (theApp.serverconnect->IsConnected())
	{ 
		if(buffer.Find(_T("%sn")) != -1)
			buffer.Replace(_T("%sn"),theApp.serverconnect->GetCurrentServer()->GetListName());
	} else {
		if(buffer.Find(_T("%sn")) != -1)
			buffer.Replace(_T("%sn"),GetResString(IDS_NOTCONNECTED));
	}
	if(buffer.Find(_T("%id")) != -1)
		buffer.Replace(_T("%id"),StrLine(_T("%u"), theApp.GetID()));
	if(buffer.Find(_T("%ip")) != -1)
		buffer.Replace(_T("%ip"),ipstr(theApp.GetPublicIP()));
	if(buffer.Find(_T("%fw")) != -1)
		buffer.Replace(_T("%fw"), GetResString(theApp.IsFirewalled() ? IDS_IDLOW : IDS_IDHIGH));

	if(buffer.Find(_T("%ua")) != -1)
		buffer.Replace(_T("%ua"),CastItoXBytes(theStats.sessionReceivedBytes, false, false));
	if(buffer.Find(_T("%da")) != -1)
		buffer.Replace(_T("%da"),CastItoXBytes(theStats.sessionSentBytes, false, false));

	return buffer;
}

void CMiniMule::MMUpdate(BOOL reset)
{
	//Retrieve the current datarates
	SetSpeedMeterValues(theApp.uploadqueue->GetDatarate()/1024, theApp.downloadqueue->GetDatarate()/1024);

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

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

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

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

	m_Label = FormatLabel(thePrefs.GetMiniMuleLabel(),myStats);

}

//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)
{
	theApp.emuledlg->OnTrayRButtonUp(point);
}

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

bool CMiniMule::SetTransparent(BYTE bAlpha, BOOL reset)
{
	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())
	{
		if (thePrefs.IsMiniMuleUpdate())
			MMUpdate();
		else
			MMUpdate(true);
		ShowWindow(SW_SHOW);
		::SetWindowPos(m_hWnd,thePrefs.IsMiniMuleOnTop() ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
	}
}

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

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

BOOL CMiniMule::OnEraseBkgnd(CDC* pDC) 
{	
	if(m_Back.m_hObject == NULL || !thePrefs.UseMiniMuleBackground())
		return CDialog::OnEraseBkgnd(pDC);

	RECT rect;
	GetClientRect(&rect);
	
	BITMAP bmpInfo;
	CDC dcMemory;

	m_Back.GetBitmap(&bmpInfo);
	dcMemory.CreateCompatibleDC(pDC);
	CBitmap* pOldBitmap = dcMemory.SelectObject(&m_Back);
	pDC->BitBlt(0,0, bmpInfo.bmWidth, bmpInfo.bmHeight, &dcMemory, 0, 0, SRCCOPY);
	dcMemory.SelectObject(pOldBitmap);

	//if (theApp.IsConnected())
	//	::DrawIconEx(pDC->m_hDC, 2, 0, m_hCSDconn, 32, 32, 0, NULL, DI_NORMAL);
	//else if (theApp.IsFirewalled())
	//	::DrawIconEx(pDC->m_hDC, 2, 0, m_hCSCing, 32, 32, 0, NULL, DI_NORMAL);
	//else
	//	::DrawIconEx(pDC->m_hDC, 2, 0, m_hCSConn, 32, 32, 0, NULL, DI_NORMAL);

	return FALSE;
}

void CMiniMule::OnPaint()
{
	CPaintDC dc(this); // device context for painting
	CDC * pDC   = CDC::FromHandle(dc);
	int nSavedDC = pDC->SaveDC();

	// Draw Text
	CFont *pOldFont;
	pOldFont=pDC->SelectObject(&theApp.m_fontLog);
	pDC->SetBkMode(TRANSPARENT);
	pDC->SetTextColor(m_crTextColor);
	pDC->DrawText(m_Label,-1,m_rcText,DT_CENTER | DT_VCENTER | DT_WORDBREAK);
	pDC->SelectObject(pOldFont);

	pDC->RestoreDC(nSavedDC);
}