//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.

#include "stdafx.h"
#include "emule.h"
#include "emuleDlg.h"
#include "opcodes.h"
#include "mdump.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

const static UINT UWM_ARE_YOU_EMULE=RegisterWindowMessage(_T(EMULE_GUID));

// CemuleApp

BEGIN_MESSAGE_MAP(CemuleApp, CWinApp)
	ON_COMMAND(ID_HELP, OnHelp)
END_MESSAGE_MAP()


CemuleApp::CemuleApp(){

}



CemuleApp theApp;


// CemuleApp Initialisierung

BOOL CemuleApp::InitInstance()
{
#ifdef _DUMP
	MiniDumper dumper(CURRENT_VERSION_LONG);
#endif
  
	pendinglink = 0;
	if (ProcessCommandline())
		return false;
	// InitCommonControls() ist für Windows XP erforderlich, wenn ein Anwendungsmanifest
	// die Verwendung von ComCtl32.dll Version 6 oder höher zum Aktivieren
	// von visuellen Stilen angibt. Ansonsten treten beim Erstellen von Fenstern Fehler auf.
	InitCommonControls();

	CWinApp::InitInstance();

	if (!AfxSocketInit())
	{
		AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
		return FALSE;
	}

	AfxEnableControlContainer();
	AfxSocketInit();
	CemuleDlg dlg;
	emuledlg = &dlg;
	m_pMainWnd = &dlg;

	// create & initalize all the important stuff 
	glob_prefs = new CPreferences();

	// Change extension for help file
	CString strHelpFile = m_pszHelpFilePath;
	if (glob_prefs->GetLanguageID()==MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT)) {
		int pos=strHelpFile.ReverseFind('.');
		if (pos>0) strHelpFile=strHelpFile.Left(pos)+".de.chm";
	}
	strHelpFile.Replace(".HLP", ".chm");
	free((void*)m_pszHelpFilePath);
	m_pszHelpFilePath = _tcsdup(strHelpFile);

	// Barry - Auto-take ed2k links
	if (glob_prefs->AutoTakeED2KLinks())
		Ask4RegFix(false, true);

	clientlist = new CClientList();
	friendlist = new CFriendList();
	searchlist = new CSearchList();
	knownfiles = new CKnownFileList(glob_prefs->GetAppDir());
	serverlist = new CServerList(glob_prefs);
	serverconnect = new CServerConnect(serverlist,theApp.glob_prefs);
	sharedfiles = new CSharedFileList(glob_prefs,serverconnect,knownfiles);
	listensocket = new CListenSocket(glob_prefs);
	clientudp	= new CClientUDPSocket();
	clientcredits = new CClientCreditsList(glob_prefs);
	downloadqueue = new CDownloadQueue(glob_prefs,sharedfiles);	// bugfix - do this before creating the uploadqueue
	uploadqueue = new CUploadQueue(glob_prefs);

	// reset statistic values
	theApp.stat_sessionReceivedBytes=0;
	theApp.stat_sessionSentBytes=0;
	theApp.stat_reconnects=0;
	theApp.stat_transferStarttime=0;
	theApp.stat_serverConnectTime=0;

	INT_PTR nResponse = dlg.DoModal();

	::CloseHandle(m_hMutexOneInstance);

	return FALSE;
}

bool CemuleApp::ProcessCommandline(){
     HWND maininst = NULL;
     bool bAlreadyRunning;

     CCommandLineInfo cmdInfo;
     ParseCommandLine(cmdInfo);

     m_hMutexOneInstance = ::CreateMutex(NULL, FALSE,_T(EMULE_GUID));
     bAlreadyRunning = ( ::GetLastError() == ERROR_ALREADY_EXISTS ||::GetLastError() == ERROR_ACCESS_DENIED);
     if ( bAlreadyRunning ) EnumWindows(SearchEmuleWindow, (LPARAM)&maininst);

     if (cmdInfo.m_nShellCommand == CCommandLineInfo::FileOpen) {
		CString command = cmdInfo.m_strFileName;
		if (command.Find("://")>0) {
			sendstruct.cbData = command.GetLength()+1; 
			sendstruct.dwData = OP_ED2KLINK; 
			sendstruct.lpData = command.GetBuffer(); 
    		if (maininst){
      			SendMessage(maininst,WM_COPYDATA,(WPARAM)0,(LPARAM) (PCOPYDATASTRUCT) &sendstruct); 
      			return true; 
			} 
    		else 
      			pendinglink = new CString(command);
		} else {
			sendstruct.cbData = command.GetLength()+1; 
			sendstruct.dwData = OP_CLCOMMAND;
			sendstruct.lpData = command.GetBuffer(); 
    		if (maininst){
      			SendMessage(maininst,WM_COPYDATA,(WPARAM)0,(LPARAM) (PCOPYDATASTRUCT) &sendstruct); 
      			return true; 
			}
		}
     }
     return (maininst || bAlreadyRunning);
}

BOOL CALLBACK CemuleApp::SearchEmuleWindow(HWND hWnd, LPARAM lParam){
	DWORD dwMsgResult;
	LRESULT res = ::SendMessageTimeout(hWnd,UWM_ARE_YOU_EMULE,0, 0,SMTO_BLOCK |SMTO_ABORTIFHUNG,10000,&dwMsgResult);
	if(res == 0)
		return TRUE;
	if(dwMsgResult == UWM_ARE_YOU_EMULE){ 
		HWND * target = (HWND *)lParam;
		*target = hWnd;
		return FALSE; 
	} 
	return TRUE; 
} 


void CemuleApp::UpdateReceivedBytes(int32 bytesToAdd) {
	SetTimeOnTransfer();
	stat_sessionReceivedBytes+=bytesToAdd;
}
void CemuleApp::UpdateSentBytes(int32 bytesToAdd) {
	SetTimeOnTransfer();
	stat_sessionSentBytes+=bytesToAdd;
}
void CemuleApp::SetTimeOnTransfer() {
	if (stat_transferStarttime>0) return;
	
	stat_transferStarttime=GetTickCount();
}

CString CemuleApp::StripInvalidFilenameChars(CString strText, bool bKeepSpaces)
{
	LPTSTR pszBuffer = strText.GetBuffer();
	LPTSTR pszSource = pszBuffer;
	LPTSTR pszDest = pszBuffer;

	while (*pszSource != '\0')
	{
		if (!((*pszSource <= 31 && *pszSource >= 0)	|| // lots of invalid chars for filenames in windows :=)
			*pszSource == '\"' || *pszSource == '*' || *pszSource == '<'  || *pszSource == '>' ||
			*pszSource == '?'  || *pszSource == '|' || *pszSource == '\\' || *pszSource == '/' || 
			*pszSource == ':') )
		{
			if (!bKeepSpaces && *pszSource == ' ')
				*pszDest = '.';
			*pszDest = *pszSource;
			pszDest++;
		}
		pszSource++;
	}
	*pszDest = '\0';
	strText.ReleaseBuffer();
	return strText;
}

CString CemuleApp::CreateED2kLink( CAbstractFile* f )
{
	CString strLink;
	strLink.Format("ed2k://|file|%s|%d|%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x|/",
		StripInvalidFilenameChars(f->GetFileName(), false),	// spaces to dots
		f->GetFileSize(),
		f->GetFileHash()[0],f->GetFileHash()[1],f->GetFileHash()[2],f->GetFileHash()[3],f->GetFileHash()[4],f->GetFileHash()[5],f->GetFileHash()[6],f->GetFileHash()[7],
		f->GetFileHash()[8],f->GetFileHash()[9],f->GetFileHash()[10],f->GetFileHash()[11],f->GetFileHash()[12],f->GetFileHash()[13],f->GetFileHash()[14],f->GetFileHash()[15]);
	return strLink;
}

CString CemuleApp::CreateED2kSourceLink( CAbstractFile* f )
{
	if (!serverconnect->IsConnected() || serverconnect->IsLowID()){
		emuledlg->AddLogLine(true,GetResString(IDS_SOURCELINKFAILED));
		return CString("");
	}
	uint32 dwID = serverconnect->GetClientID();
	CString strLink;
	strLink.Format("ed2k://|file|%s|%d|%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x|/|sources,%i.%i.%i.%i:%i|/",
		StripInvalidFilenameChars(f->GetFileName(), false),	// spaces to dots
		f->GetFileSize(),
		f->GetFileHash()[0],f->GetFileHash()[1],f->GetFileHash()[2],f->GetFileHash()[3],f->GetFileHash()[4],f->GetFileHash()[5],f->GetFileHash()[6],f->GetFileHash()[7],
		f->GetFileHash()[8],f->GetFileHash()[9],f->GetFileHash()[10],f->GetFileHash()[11],f->GetFileHash()[12],f->GetFileHash()[13],f->GetFileHash()[14],f->GetFileHash()[15],
		(uint8)dwID,(uint8)(dwID>>8),(uint8)(dwID>>16),(uint8)(dwID>>24), glob_prefs->GetPort());
	return strLink;
}




CString CemuleApp::CreateHTMLED2kLink( CAbstractFile* f )
{
	CString strCode = "<a href=\"" + CreateED2kLink(f) + "\">" + StripInvalidFilenameChars(f->GetFileName(), true) + "</a>";
	return strCode;
}

bool CemuleApp::CopyTextToClipboard( CString strText )
{
	//allocate global memory & lock it
	HGLOBAL hGlobal = GlobalAlloc(GHND|GMEM_SHARE,strText.GetLength() + 1);
	if(hGlobal == NULL)
		return false;

	PTSTR pGlobal = static_cast<PTSTR>(GlobalLock(hGlobal));
	if( pGlobal == NULL )
		return false;

	//copy the text
	strcpy(pGlobal,(LPCTSTR)strText);

	GlobalUnlock(hGlobal);

	//Open the Clipboard and insert the handle into the global memory
	if( OpenClipboard(NULL) == NULL )
		return false;

	if(!EmptyClipboard())
		return false;

	if( SetClipboardData(CF_TEXT,hGlobal) == NULL )
		return false;

	CloseClipboard();

	return true;
}


void CemuleApp::OnlineSig() // Added By Bouc7 
{ 
	if (!theApp.glob_prefs->IsOnlineSignatureEnabled()) return;

    char* fullpath = new char[strlen(glob_prefs->GetAppDir())+MAX_PATH]; 
    sprintf(fullpath,"%sonlinesig.dat",glob_prefs->GetAppDir()); 
    CFile file; 
    if (!file.Open(fullpath,CFile::modeCreate|CFile::modeReadWrite)){ 
		theApp.emuledlg->AddLogLine(true,GetResString(IDS_ERROR_SAVEFILE)+CString(" OnlineSig.dat"));
    } 
    char buffer[20]; 
    if (serverconnect->IsConnected()) 
    { 
      file.Write("1",1); 
      file.Write("|",1); 
      file.Write(serverconnect->GetCurrentServer()->GetListName(),strlen(serverconnect->GetCurrentServer()->GetListName())); 
      // Not : file.Write(serverconnect->GetCurrentServer()->GetListName(),strlen(serverconnect->GetCurrentServer()- >GetRealName())); 

      file.Write("|",1); 
      file.Write(serverconnect->GetCurrentServer()->GetFullIP(),strlen(serverconnect->GetCurrentServer()->GetFullIP())); 
      file.Write("|",1); 
      itoa(serverconnect->GetCurrentServer()->GetPort(),buffer,10); 
      file.Write(buffer,strlen(buffer)); 
    } 
    else 
      file.Write("0",1); 

    file.Write("\n",1); 
    sprintf(buffer,"%.1f",(float)downloadqueue->GetDatarate()/1024); 
    file.Write(buffer,strlen(buffer)); 
    file.Write("|",1); 
    sprintf(buffer,"%.1f",(float)uploadqueue->GetDatarate()/1024); 
    file.Write(buffer,strlen(buffer)); 
    file.Write("|",1); 
    itoa(uploadqueue->GetWaitingUserCount(),buffer,10); 
    file.Write(buffer,strlen(buffer)); 

    file.Close(); 
    delete[] fullpath; 
    
} //End Added By Bouc7

// Added by Tarod to Jigle Fakechecking [DeltaHF's original code]
void CemuleApp::Action(CKnownFile* knownfile, CPartFile* partfile, CSearchFile* searchfile)
{
	char str_filesize[34]; // max. is 33 bytes
	uchar* hash_id;
	uint32 filesize;

	CString commandbuffer = "http://jigle.com/search?p=ed2k%3A#filesize%3A#hashid&ma=1&d=1&a=0&l=10&t=7&x=&sl=1&su=&kw=0&v=0";

	if (knownfile != NULL) {
		hash_id = knownfile->GetFileHash();
		filesize = knownfile->GetFileSize();
	} else if (searchfile != NULL) {
		hash_id = searchfile->GetFileHash();
		filesize = searchfile->GetIntTagValue(FT_FILESIZE);
	} else if (partfile != NULL) {	
		hash_id = partfile->GetFileHash();
		filesize = partfile->GetFileSize();
	}

	// Convert hash to hexadecimal text and add it to the URL
	commandbuffer.Replace("#hashid", EncodeBase16(hash_id, 16));

	// Add file size to the URL
	_ultoa((unsigned long)filesize, str_filesize, 10);
	commandbuffer.Replace("#filesize", str_filesize);

	// Start Application
	ShellExecute(NULL, NULL, commandbuffer, NULL, theApp.glob_prefs->GetAppDir(), SW_SHOWDEFAULT);
	theApp.emuledlg->AddLogLine(false,"Command: %s", commandbuffer);
}

void CemuleApp::OnHelp() {
	// lets just open the helpfile by associated program, instead of more windows-dependency :)
	CFileFind ff;
	if (ff.FindFile(m_pszHelpFilePath, 0)) ShellOpenFile(m_pszHelpFilePath); else AfxMessageBox(GetResString(IDS_ERR_NOHELP), MB_OK | MB_ICONERROR);
	ff.Close();
}
