/*
 *  Plugin of miranda IM(ICQ) for Communicating with users of the XFire Network. 
 *
 *  Copyright (C) 2010 by
 *          dufte <dufte@justmail.de>
 *
 *  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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 *
 *
 *  Miranda ICQ: the free icq client for MS Windows 
 *  Copyright (C) 2000-2008  Richard Hughes, Roland Rabien & Tristan Van de Vreede
 *
 */

#include "stdafx.h"
#include "baseProtocol.h"
#include "Xfire_gamelist.h"
#include "variables.h"
#include <string>
using std::string;

extern int foundgames;
extern HANDLE	 XFireAvatarFolder;
extern HANDLE	 XFireWorkingFolder;
extern INT_PTR StartGame(WPARAM wParam, LPARAM lParam,LPARAM fParam);
extern Xfire_gamelist xgamelist;

//versucht die * in den pfaden der ini mit dem korrekten eintrag zu ersetzen
BOOL CheckPath(char*ppath,char*pathwildcard=NULL)
{
	char* pos=0;
	char* pos2=0;

	pos = strchr(ppath,'*');
	if (pos)
	{	
		HANDLE fHandle;
		WIN32_FIND_DATAA wfd; 
		BOOL weiter=TRUE;

		if (pathwildcard)
		{
			strcpy_s(pathwildcard,XFIRE_MAX_STATIC_STRING_LEN,ppath);
		}

		pos++;
		*pos=0;
		pos++;
	
		//versuch die exe zu finden
		fHandle=FindFirstFileA(ppath,&wfd);  // . skippen
		FindNextFileA(fHandle,&wfd); // .. auch skippen

		while ((FindNextFileA(fHandle,&wfd)&&weiter==TRUE)) // erstes file
		{
			if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) // nur verzeichnisse sind interessant
			{
				char temp[XFIRE_MAX_STATIC_STRING_LEN];

				strcpy(temp,ppath);
				*(temp+strlen(temp)-1)=0;
				strcat(temp,wfd.cFileName);
				strcat(temp,"\\");
				strcat(temp,pos);

				if (GetFileAttributesA(temp)!=0xFFFFFFFF) { //exe vorhanden???? unt hint?
					//gefundenes in path kopieren
					FindClose(fHandle);
					strcpy(ppath,temp);
					return TRUE;
				}
			}
		}
		FindClose(fHandle);
	}
	else
	{
		if (GetFileAttributesA(ppath)!=0xFFFFFFFF) { //exe vorhanden???? unt hint?
		//gefundenes in path kopieren
			return TRUE;
		}
	}

	return FALSE;
}

INT_PTR CALLBACK DlgSearchDialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
		case WM_INITDIALOG:
		{
			TranslateDialogDefault(hwndDlg);
			return TRUE;
		}
	}

	return FALSE;
}

void ShowSearchDialog(LPVOID lparam)
{
	HWND* hwnd=(HWND*)lparam;
	HWND myhwnd=CreateDialog(hinstance,MAKEINTRESOURCE(IDD_SEARCHING),NULL,DlgSearchDialogProc);

	if (myhwnd==NULL)
		return;

	*hwnd=myhwnd;

	ShowWindow(myhwnd,SW_SHOW);

	//nachrichten schleife
	MSG msg;
   while (GetMessage(&msg,myhwnd,0,0))
   {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }
}

void Scan4Games( LPVOID lparam  )
{
	int i=2;
	unsigned int i2=1;
	BOOL split=FALSE;
	int notfound=0;
	char* pos=0;
	char* pos2=0;
	char *cutforlaunch = 0;
	char temp[10]="";
	char inipath[XFIRE_MAX_STATIC_STRING_LEN]="";
	char ret[XFIRE_MAX_STATIC_STRING_LEN]="";
	char gamename[XFIRE_MAX_STATIC_STRING_LEN]="";
	char ret2[XFIRE_MAX_STATIC_STRING_LEN]="";
	char gamelist[XFIRE_MAX_STATIC_STRING_LEN]="";
	BOOL multiexe=FALSE;
	BOOL somethingfound=TRUE;
	int i3=0;
	DWORD gpps=1;
	DWORD last_gpps=0;
	static BOOL searching=FALSE;

	//ich suche schon,also raushier
	if (searching)
	{
		MSGBOX("Game searching is already running!");
		return;
	}
	if (xgamelist.Ingame())
	{
		MSGBOX("A game is currently running, please close the game.");
		return;
	}

	//gamelist blocken, damit nur 1 thread es ausf�hrt/nutzt
	xgamelist.Block(TRUE);

	searching=TRUE;

	//s�ubert die gameliste f�r eine neuauslesung
	xgamelist.clearGamelist();

	//pr�fe ob schon gescannt wurde, dann das aus der db nehmen, beschleunigt den start
	foundgames=db_get_w(NULL, protocolname, "foundgames",-1);

	//um bei einer neuen version einen rescan zuforcen, bei bestimmten wert found auf 0 resetten
	if (db_get_w(NULL, protocolname, "scanver",0)!=XFIRE_SCAN_VAL)
		foundgames=-1;

	BOOL loadgamesfromdb=FALSE;
	if (db_get_b(NULL,protocolname,"scanalways",0)==0)
		loadgamesfromdb=TRUE;
	else
	{
		if (db_get_b(NULL,protocolname,"scanalways",0)==2)
		{
			time_t zeit;
			struct tm *t;
			time(&zeit);
			t = localtime(&zeit);

			if (t!=NULL)
			{
				if (t->tm_yday!=db_get_w(NULL,protocolname,"scanalways_t",0))
				{
					db_set_w(NULL,protocolname,"scanalways_t",t->tm_yday);
				}
				else
					loadgamesfromdb=TRUE;
			}
		}
	}

	//spiele von db laden
	if (loadgamesfromdb)
		if (foundgames>0)
		{
			//spieliste einlesen
			xgamelist.readGamelist(foundgames);
			//men�punkte anlegen
			xgamelist.createStartmenu();

			//gamelist unblocken
			xgamelist.Block(FALSE);

			searching=FALSE;
			return;
		}
		else if (foundgames==0)
		{
			searching=FALSE;
			//dummymen� punkt entfernen
			//CallService(MS_CLIST_REMOVEMAINMENUITEM, ( WPARAM )dummymenu, 0 );	

			//gamelist unblocken
			xgamelist.Block(FALSE);

			return;
		}
		else
			foundgames=0;
	else
		foundgames=0;

	HWND hwnd=NULL;

	//suche dialog anzeigen
	if (!db_get_b(NULL,protocolname,"dontdissstatus",0))
	{
		mir_forkthread(ShowSearchDialog,&hwnd);
	}

	strcpy(inipath, XFireGetFoldersPath ("IniFile"));
	strcat(inipath,"xfire_games.ini");

	//erstmal db s�ubern
	xgamelist.clearDatabase();

	//maximal 200 notfounds, um die nicht belegten id's zu �berspringen
	while(notfound<200)
	{
		//2 gameids?
		if (split)
			mir_snprintf(temp, SIZEOF(temp), "%i_%i", i, i2);
		else
			mir_snprintf(temp, SIZEOF(temp), "%i", i);

		//MessageBox(0,temp,temp,0);

		//letztes ergeniss sichern
		last_gpps=gpps;

		//las ma mal suchen...
		gpps=xfire_GetPrivateProfileString(temp, "LongName", "", gamename, 255, inipath);

		char entrytype[100]="";
		if (gpps!=NULL) xfire_GetPrivateProfileString(temp, "SoftwareType", "", entrytype, 100, inipath);

		//kein eintrag? voicechat? musiapplicationen? schon in der gameliste?
		if (gpps!=NULL && strcmp(entrytype,"Music")!=0 && strcmp(entrytype,"VoiceChat")!=0  && !xgamelist.Gameinlist(i)) //was gefunden und noch nicht eintragen?
		{
			BOOL MatchExe=FALSE;
			//MatchExe Games in der automatischen Suche skippen
			if (xfire_GetPrivateProfileString(temp, "MatchExe", "", ret, 255, inipath))
				MatchExe=TRUE;

			//Registryschl�ssel auslesen und pfad auf exe pr�fen
			xfire_GetPrivateProfileString(temp, "LauncherDirKey", "", ret, 255, inipath);
			strcpy(ret2,ret);

			//ersten part des registry schl�ssel raustrennen
			pos=strchr(ret2,'\\');
			if (!MatchExe && pos!=0)
			{
				HKEY hkey,hsubk;

				*pos=0; //string trennen
				pos++;

				pos2=strrchr(pos,'\\'); //key trennen
				if (pos!=0)
				{
					*pos2=0;
					pos2++;

					//HKEY festlegen
					switch(*(ret2+6))
					{
					case 'L':
						hkey = HKEY_CLASSES_ROOT;
						break;
					case 'U':
						hkey = HKEY_CURRENT_USER;
						break;
					case 'O':
						hkey = HKEY_LOCAL_MACHINE;
						break;
					default: 
						hkey = NULL;
					}
				}
				else
					hkey = NULL;

				if (hkey) //nur wenn der key erkannt wurde
				{
					if (RegOpenKeyA(hkey,pos,&hsubk) == ERROR_SUCCESS) //key versuchen zu "�ffnen"
					{
						char path[XFIRE_MAX_STATIC_STRING_LEN]="";
						char path_r[XFIRE_MAX_STATIC_STRING_LEN]="";
						DWORD size=sizeof(path);
						
						//key lesen
						if (RegQueryValueExA(hsubk,pos2,NULL,NULL,(LPBYTE)path,&size)== ERROR_SUCCESS)
						{
							//zus�tzlichen pfad anh�ngen
							if (xfire_GetPrivateProfileString(temp, "LauncherDirAppend", "", ret2, 255, inipath))
							{
								if (*(path+strlen(path)-1)=='\\'&&*(ret2)=='\\')
									strcat(path,(ret2+1));
								else
									strcat(path,ret2);
							}

							if (xfire_GetPrivateProfileString(temp, "LauncherDirTruncAt", "", ret2, 255, inipath))
							{
								//m�gliches erstes anf�hrungszeichen entfernen
								if (*(path)=='"')
								{
									pos2=path;
									pos2++;

									strcpy(path,pos2);
								}
								
								//m�gliche weitere anf�hrungszeichen entfernen
								pos=strchr(path,'"');
								if (pos!=0)
									*pos=0;

								if (*(path+strlen(path)-1)!='\\')
									*(path+strlen(path)-strlen(ret2))=0;
							}

							if (*(path+strlen(path)-1)!='\\')
								strcat(path,"\\");


							//dateiname auslesen
							if (xfire_GetPrivateProfileString(temp, "InstallHint", "", ret2, 255, inipath))
							{
								char pathtemp[XFIRE_MAX_STATIC_STRING_LEN];
								strcpy(pathtemp,path);
								strcat(pathtemp,ret2);
								
								if (CheckPath(pathtemp))
								{
									if (xfire_GetPrivateProfileString(temp, "DetectExe", "", ret, 255, inipath))
									{
										cutforlaunch=path+strlen(path);
										strcpy(pathtemp,path);

										//wenn backslash bei detectexe, dann diesen skippen (eveonline bug)
										if (ret[0]=='\\')
										{
											strcat(pathtemp,(char*)&ret[1]);
										}
										else
										{
											strcat(pathtemp,ret);
										}

										if (CheckPath(pathtemp))
										{
											strcpy(path, pathtemp);
										}
										else
										{
											*(path)=0;
										}
									}
									else if (xfire_GetPrivateProfileString(temp, "LauncherExe", "", ret2, 255, inipath)) 
									{
										cutforlaunch=path+strlen(path);
										strcat(path,ret2);
									}
								}
								else
								{
									*(path)=0;
								}
							}
							else if (xfire_GetPrivateProfileString(temp, "DetectExe[0]", "", ret2, 255, inipath))
							{
								cutforlaunch=path+strlen(path);
								strcat(path,ret2);
								multiexe=TRUE;
								if (!CheckPath(path,path_r))
								{
									*(path)=0;
								}
							}
							else if (xfire_GetPrivateProfileString(temp, "DetectExe", "", ret2, 255, inipath))
							{
								cutforlaunch=path+strlen(path);

								//wenn backslash bei detectexe, dann diesen skippen (eveonline bug)
								if (ret2[0]=='\\')
								{
									strcat(path,(char*)&ret2[1]);
								}
								else
								{
									strcat(path,ret2);
								}

								if (!CheckPath(path,path_r))
								{
									*(path)=0;
								}
							}
							else if (xfire_GetPrivateProfileString(temp, "LauncherExe", "", ret2, 255, inipath)) 
							{
								cutforlaunch=path+strlen(path);
								strcat(path,ret2);
							}


							//pr�fe ob existent, dann ist das spiel installiert
							if (path[0]!=0 && GetFileAttributesA(path)!=0xFFFFFFFF)
							{
								Xfire_game* newgame=new Xfire_game();
								newgame->id=i;

								//8.3 pfade umwandeln
								//GetLongPathNameA(path,path,sizeof(path));

								//lowercase pfad
								for(unsigned int ii=0;ii<strlen(path);ii++)
									path[ii]=tolower(path[ii]);

								if (path_r[0]==0)
									newgame->setString(path,&newgame->path);
								else
								{
									//lowercase wildcard pfad
									for(unsigned int ii=0;ii<strlen(path_r);ii++)
										path_r[ii]=tolower(path_r[ii]);
									newgame->setString(path_r,&newgame->path);
								}

								//spiel mit mehreren exefiles
								if (multiexe)
								{
									multiexe=FALSE;
									for(int i=1;i<9;i++)
									{
										mir_snprintf(ret, SIZEOF(ret), "DetectExe[%d]", i);
										if (xfire_GetPrivateProfileString(temp, ret, "", ret2, 512, inipath))
										{
											char* pos=strrchr(path,'\\');
											if (pos!=0)
											{
												pos++;
												*pos=0;
											}		
											strcat(path,ret2);
											if (!CheckPath(path))
											{
												*(path)=0;
											}
											else
											{
												for(unsigned int i2=0;i2<strlen(path);i2++)
													path[i2]=tolower(path[i2]);
												
												char* mpathtemp=new char[strlen(path)+1];
												strcpy(mpathtemp,path);
												newgame->mpath.push_back(mpathtemp);
											}
										}
									}
								}

								//f�r launcherstring anpassen
								char* pos=strrchr(path,'\\');
								if (pos!=0)
								{
									pos++;
									*pos=0;
								}
								xfire_GetPrivateProfileString(temp, "LauncherExe", "", ret2, 255, inipath); // anf�gen
								if (cutforlaunch!=0) *cutforlaunch=0;

								//pfad aufbereiten
								char launchpath[XFIRE_MAX_STATIC_STRING_LEN]="";
								strcpy(launchpath,path);
								//letzten backslash entfernen
								if (launchpath[strlen(launchpath)-1]=='\\') launchpath[strlen(launchpath)-1]=0;

								strcat(path,ret2);

								newgame->setString(path,&newgame->launchparams);
								newgame->appendString(" ",&newgame->launchparams);

								xfire_GetPrivateProfileString(temp, "Launch", "", ret2, 512, inipath);
								str_replace(ret2,"%UA_LAUNCHER_EXE_DIR%",launchpath);
								str_replace(ret2,"%UA_LAUNCHER_EXE_PATH%",""); //erstmal unwichtige sachen entfernen
								//str_replace(ret2,"%UA_LAUNCHER_EXTRA_ARGS%",""); // - auch entfernen	
								str_replace(ret2,"%UA_LAUNCHER_LOGIN_ARGS%",""); // - auch entfernen	
								
								newgame->appendString(ret2,&newgame->launchparams);

								/*if (xfire_GetPrivateProfileString(temp, "LauncherLoginArgs", "", ret2, 512, inipath))
								{
									str_replace(xf[foundgames].launchparams,"%UA_LAUNCHER_LOGIN_ARGS%",ret2); // - auch entfernen	
								}
								else*/
								//	str_replace(xf[foundgames].launchparams,"%UA_LAUNCHER_LOGIN_ARGS%",""); // - auch entfernen	

								if (xfire_GetPrivateProfileString(temp, "LauncherPasswordArgs", "", ret2, 512, inipath))
									newgame->setString(ret2,&newgame->pwparams);
								
								if (xfire_GetPrivateProfileString(temp, "LauncherNetworkArgs", "", ret2, 512, inipath))
									newgame->setString(ret2,&newgame->networkparams);

								if (xfire_GetPrivateProfileString(temp, "CommandLineMustContain[0]", "", ret2, 512, inipath))
									newgame->setString(ret2,&newgame->mustcontain);

								if (xfire_GetPrivateProfileString(temp, "XUSERSendId", "", ret2, 512, inipath))
									newgame->send_gameid=atoi(ret2);

								if (xfire_GetPrivateProfileString(temp, "XUSERSetStatusMsg", "", ret2, 512, inipath))
									newgame->setstatusmsg=atoi(ret2);

								//launcherurl?
								if (xfire_GetPrivateProfileString(temp, "LauncherUrl", "", ret2, 512, inipath))
									newgame->setString(ret2,&newgame->launchparams);

								//soll alle string, welche nicht in der commandline eines spiels sein soll in einen string pakcen semikolon getrennt
								mir_snprintf(ret, SIZEOF(ret), "CommandLineMustNotContain[0]");
								int i=0;

								while(xfire_GetPrivateProfileString(temp, ret, "", ret2, 512, inipath))
								{
									if (!newgame->notcontain) newgame->setString("",&newgame->notcontain);
									if (i>0)
										newgame->appendString(";",&newgame->notcontain);
									newgame->appendString(ret2,&newgame->notcontain);

									i++;
									mir_snprintf(ret, SIZEOF(ret), "CommandLineMustNotContain[%d]", i);
								}

								newgame->setNameandIcon();

								strcat(gamelist,gamename);
								strcat(gamelist,", ");
								if (foundgames%2==1)
									strcat(gamelist,"\r\n");

								xgamelist.Addgame(newgame);
						
								foundgames++;

								split=FALSE;
							}
							
						}

						RegCloseKey(hsubk);
					}
				}

			}
			else if (!MatchExe && xfire_GetPrivateProfileString(temp, "LauncherDirDefault", "", ret2, 255, inipath))
			{
				if (xfire_GetPrivateProfileString(temp, "LauncherExe", "", ret, 255, inipath))
				{
					strcat(ret2,"\\");
					strcat(ret2,ret);
				}

				str_replace(ret2,"%WINDIR%",getenv("WINDIR"));
				str_replace(ret2,"%ProgramFiles%",getenv("ProgramFiles"));

				//pr�fe ob existent, dann ist das spiel installiert
				if (GetFileAttributesA(ret2)!=0xFFFFFFFF)
				{
					
					Xfire_game* newgame=new Xfire_game();

					newgame->id=i;
					
					//8.3 pfade umwandeln
					//GetLongPathNameA(ret2,ret2,sizeof(ret2));

					//lowercase pfad
					for(unsigned int i=0;i<strlen(ret2);i++)
						ret2[i]=tolower(ret2[i]);

					newgame->setString(ret2,&newgame->path);
					
					//launch parameterstring

					//pfad aufbereiten
					char launchpath[XFIRE_MAX_STATIC_STRING_LEN]="";
					strcpy(launchpath,ret2);
					if (strrchr(launchpath,'\\')!=0)
					{
						*(strrchr(launchpath,'\\'))=0;
					}

					newgame->setString(ret2,&newgame->launchparams);
					newgame->appendString(" ",&newgame->launchparams);

					xfire_GetPrivateProfileString(temp, "Launch", "", ret2, 512, inipath);

					str_replace(ret2,"%UA_LAUNCHER_EXE_DIR%",launchpath);

					str_replace(ret2,"%UA_LAUNCHER_EXE_PATH%",""); //unwichtige sachen entfernen
					//str_replace(ret2,"%UA_LAUNCHER_EXTRA_ARGS%",""); // - auch entfernen	
					str_replace(ret2,"%UA_LAUNCHER_LOGIN_ARGS%",""); // - auch entfernen

					newgame->appendString(ret2,&newgame->launchparams);

					if (xfire_GetPrivateProfileString(temp, "LauncherPasswordArgs", "", ret2, 512, inipath))
						newgame->setString(ret2,&newgame->pwparams);
					
					if (xfire_GetPrivateProfileString(temp, "LauncherNetworkArgs", "", ret2, 512, inipath))
						newgame->setString(ret2,&newgame->networkparams);

					if (xfire_GetPrivateProfileString(temp, "CommandLineMustContain[0]", "", ret2, 512, inipath))
						newgame->setString(ret2,&newgame->mustcontain);

					if (xfire_GetPrivateProfileString(temp, "XUSERSendId", "", ret2, 512, inipath))
						newgame->send_gameid=atoi(ret2);

					if (xfire_GetPrivateProfileString(temp, "XUSERSetStatusMsg", "", ret2, 512, inipath))
						newgame->setstatusmsg=atoi(ret2);

					//soll alle string, welche nicht in der commandline eines spiels sein soll in einen string pakcen semikolon getrennt
					mir_snprintf(ret, SIZEOF(ret), "CommandLineMustNotContain[0]");
					int i=0;

					while(xfire_GetPrivateProfileString(temp, ret, "", ret2, 512, inipath))
					{
						if (!newgame->notcontain) newgame->setString("",&newgame->notcontain);
						if (i>0)
							newgame->appendString(";",&newgame->notcontain);
						newgame->appendString(ret2,&newgame->notcontain);

						i++;
						mir_snprintf(ret, SIZEOF(ret), "CommandLineMustNotContain[%d]", i);
					}

					newgame->setNameandIcon();

					strcat(gamelist,gamename);
					strcat(gamelist,", ");
					if (foundgames%2==1)
						strcat(gamelist,"\r\n");

					xgamelist.Addgame(newgame);

					foundgames++;

					split=FALSE;
				}

			}

			if (split) 
				i2++;
			else
				i++;
			notfound=0;
		}
		else if (split==FALSE) // nichts gefunden, dann die 2. gameid probieren (games die zb �ber steam und normal installiert werden k�nnen, haben eine 2. id)
		{
			i2=1;
			split=TRUE;
		}
		else if (split==TRUE&&last_gpps!=NULL) // keine weiteren eintr�ge mit der 2. id gefunden, also wieder mit der normalen weitersuchen
		{
			split=FALSE;
			i++;
			i2=0;
		}
		else if (split==TRUE&&last_gpps==NULL) // �berhaupt nix gefunden, vllt nicht belegete id's, �berspringen und "notfound" hochsetzen
		{
			split=FALSE;
			i2=0;
			if (i==35) //gro�er sprung unbenutzer id's
				i+=4000;
			i++;
			notfound++;
		}
	}

	if (hwnd)SetDlgItemText(hwnd,IDC_CURRENTGAME,TranslateT("Write to database..."));
	
	//gefundene games in db eintragen
	xgamelist.writeDatabase();

	//scanversion setzen, um ungewollten rescan zu vermeiden
	db_set_w(NULL, protocolname, "scanver", XFIRE_SCAN_VAL);

	EndDialog(hwnd,0);

	if (!db_get_b(NULL,protocolname,"dontdisresults",0))
	{
		int p=strlen(gamelist)-2;
		if (p>-1)
			gamelist[p]=0; //letztes koma killen
		mir_snprintf(ret, SIZEOF(ret), Translate("Games found:%s%s"), "\r\n\r\n", gamelist);
		MSGBOX(ret);
	}

	searching=FALSE;

	xgamelist.createStartmenu();

	//gamelist unblocken
	xgamelist.Block(FALSE);
}