/* PROJECT:         ReactOS Downloader
 * LICENSE:         GPL - See COPYING in the top level directory
 * FILE:            base/applications/downloader/xml.c
 * PURPOSE:         Main program
 * PROGRAMMERS:     Maarten Bosma, Lester Kortenhoeven
 */

#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#include <tchar.h>
#include <stdio.h>
#include <shlwapi.h>
#include <shlobj.h>
#include "resources.h"
#include "structures.h"

HWND hwnd, hCategories, hApps, hDownloadButton, hUninstallButton, hUpdateButton, hHelpButton, hProfButton;
HBITMAP hLogo, hUnderline;
WCHAR* DescriptionHeadline = L"";
WCHAR* DescriptionText = L"";
WCHAR ApplicationText[700];

struct Category Root;
struct Application* SelectedApplication;

INT_PTR CALLBACK DownloadProc (HWND, UINT, WPARAM, LPARAM);
BOOL ProcessXML (const char* filename, struct Category* Root);
VOID FreeTree (struct Category* Node);
WCHAR Strings [STRING_COUNT][MAX_STRING_LENGHT];


BOOL
getUninstaller(WCHAR* RegName, WCHAR* Uninstaller) {

	const DWORD ArraySize = 200;

	HKEY hKey1;
	HKEY hKey2;
	DWORD Type = 0;
	DWORD Size = ArraySize;
	WCHAR Value[ArraySize];
	WCHAR KeyName[ArraySize];
	LONG i = 0;

	if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall",0,KEY_READ,&hKey1) == ERROR_SUCCESS) {
		while (RegEnumKeyExW(hKey1,i,KeyName,&Size,NULL,NULL,NULL,NULL) == ERROR_SUCCESS) {
			++i;
			RegOpenKeyExW(hKey1,KeyName,0,KEY_READ,&hKey2);
			Size = ArraySize;
			if (RegQueryValueExW(hKey2,L"DisplayName",0,&Type,(LPBYTE)Value,&Size) == ERROR_SUCCESS) {
				Size = ArraySize;
				if (StrCmpW(Value,RegName) == 0) {
					if (RegQueryValueExW(hKey2,L"UninstallString",0,&Type,(LPBYTE)Uninstaller,&Size) == ERROR_SUCCESS) {
						RegCloseKey(hKey2);
						RegCloseKey(hKey1);
						return TRUE;
					} else {
						RegCloseKey(hKey2);
						RegCloseKey(hKey1);
						return FALSE;
					}
				}
			}
			RegCloseKey(hKey2);
			Size = ArraySize;
		}
		RegCloseKey(hKey1);
	}
	return FALSE;
}

void
ShowMessage (WCHAR* title, WCHAR* message)
{
	DescriptionHeadline = title;
	DescriptionText = message;
	InvalidateRect(hwnd,NULL,TRUE);
	UpdateWindow(hwnd);
}

void
AddItems(HWND hwnd, struct Category* Category, struct Category* Parent)
{
	TV_INSERTSTRUCTW Insert;

	Insert.item.lParam = (UINT)Category;
	Insert.item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE;;
	Insert.item.pszText = Category->Name;
	Insert.item.cchTextMax = lstrlenW(Category->Name);
	Insert.item.iImage = Category->Icon;
	Insert.item.iSelectedImage = Category->Icon;
	Insert.hInsertAfter = TVI_LAST;
	Insert.hParent = Category->Parent ? Category->Parent->TreeviewItem : TVI_ROOT;

	Category->TreeviewItem = (HTREEITEM)SendMessage(hwnd, TVM_INSERTITEM, 0, (LPARAM)&Insert);

	if(Category->Next)
		AddItems (hwnd,Category->Next,Parent);

	if(Category->Children)
		AddItems (hwnd,Category->Children,Category);
}

void
CategoryChoosen(HWND hwnd, struct Category* Category)
{
	struct Application* CurrentApplication;
	TV_INSERTSTRUCTW Insert;
	SelectedApplication = NULL;

	if(Category->Children && !Category->Apps)
		ShowMessage(Category->Name, Strings[IDS_CHOOSE_SUB]);
	else if(!Category->Children && Category->Apps)
		ShowMessage(Category->Name, Strings[IDS_CHOOSE_APP]);
	else if(Category->Children && Category->Apps)
		ShowMessage(Category->Name, Strings[IDS_CHOOSE_BOTH]);
	else
		ShowMessage(Category->Name, Strings[IDS_NO_APPS]);

	(void)TreeView_DeleteItem(hwnd, TVI_ROOT);
	(void)TreeView_DeleteItem(hwnd, TVI_ROOT); // Delete twice to bypass bug in windows

	Insert.item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE;
	Insert.hInsertAfter = TVI_LAST;
	Insert.hParent = TVI_ROOT;

	CurrentApplication = Category->Apps;

	WCHAR Uninstaller[200];
	while(CurrentApplication)
	{
		Insert.item.lParam = (UINT)CurrentApplication;
		Insert.item.pszText = CurrentApplication->Name;
		Insert.item.cchTextMax = lstrlenW(CurrentApplication->Name);
		Insert.item.iImage = 10;
		if(StrCmpW(CurrentApplication->RegName,L"")) {
			if(getUninstaller(CurrentApplication->RegName, Uninstaller))
				Insert.item.iImage = 9;
		}
		SendMessage(hwnd, TVM_INSERTITEM, 0, (LPARAM)&Insert);
		CurrentApplication = CurrentApplication->Next;
	}
}

BOOL
SetupControls (HWND hwnd)
{
	TV_INSERTSTRUCTW Insert = {0};
	HIMAGELIST hImageList;
	HINSTANCE hInstance = GetModuleHandle(NULL);
	WCHAR Cats[MAX_STRING_LENGHT], Apps[MAX_STRING_LENGHT];
	TCHAR Buf[MAX_PATH];
	char Tmp[MAX_PATH];
	int i;

	// Getting downloader.xml path
	if(!GetSystemDirectory(Buf,sizeof(Buf)/sizeof(char))) return FALSE;
	lstrcat((LPTSTR)Buf, L"\\downloader.xml");
	for (i = 0; i < _tcslen(Buf) + 1; i++) Tmp[i] = Buf[i];

	// Parse the XML file
	if (!ProcessXML(Tmp, &Root))
		return FALSE;

	LoadStringW(hInstance, IDS_CATS_TITLE, Cats, MAX_STRING_LENGHT);
	LoadStringW(hInstance, IDS_APPS_TITLE, Apps, MAX_STRING_LENGHT);

	// Set up the controls
	hCategories = CreateWindowExW(0, WC_TREEVIEWW, Cats,
								  WS_CHILD|WS_VISIBLE|WS_BORDER|TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS|TVS_SHOWSELALWAYS,
								  0, 0, 0, 0, hwnd, NULL, hInstance, NULL);

	hApps = CreateWindowExW(0, WC_TREEVIEWW, Apps,
							WS_CHILD|WS_VISIBLE|WS_BORDER|TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS|TVS_SHOWSELALWAYS,
							0, 0, 0, 0, hwnd, NULL, hInstance, NULL);

	hLogo = LoadBitmap(GetModuleHandle(NULL),
					   MAKEINTRESOURCE(IDB_LOGO));
	hUnderline = LoadBitmap(GetModuleHandle(NULL),
							MAKEINTRESOURCE(IDB_UNDERLINE));

	hHelpButton = CreateWindowW(L"Button", L"",
								WS_CHILD | WS_VISIBLE | BS_ICON,
								550, 10, 40, 40,
								hwnd, 0, hInstance, NULL);
	hUpdateButton = CreateWindowW(L"Button", L"",
								  WS_CHILD | WS_VISIBLE | BS_ICON,
								  450, 10, 40, 40,
								  hwnd, 0, hInstance, NULL);
	hProfButton = CreateWindowW(L"Button", L"",
								WS_CHILD | WS_VISIBLE | BS_ICON,
								500, 10, 40, 40,
								hwnd, 0, hInstance, NULL);
	hDownloadButton = CreateWindowW(L"Button", L"",
									WS_CHILD | WS_VISIBLE | BS_BITMAP,
									330, 505, 140, 33,
									hwnd, 0, hInstance, NULL);
	hUninstallButton = CreateWindowW(L"Button", L"",
									 WS_CHILD | WS_VISIBLE | BS_BITMAP,
									 260, 505, 140, 33,
									 hwnd, 0, hInstance, NULL);

	SendMessageW(hProfButton,
				BM_SETIMAGE,
				(WPARAM)IMAGE_ICON,
				(LPARAM)(HANDLE)LoadIcon(hInstance,MAKEINTRESOURCE(IDI_PROF)));
	SendMessageW(hHelpButton,
				BM_SETIMAGE,
				(WPARAM)IMAGE_ICON,
				(LPARAM)(HANDLE)LoadIcon(hInstance, MAKEINTRESOURCE(IDI_HELP)));
	SendMessageW(hUpdateButton,
				BM_SETIMAGE,
				(WPARAM)IMAGE_ICON,
				(LPARAM)(HANDLE)LoadIcon(hInstance, MAKEINTRESOURCE(IDI_UPDATE)));
	SendMessageW(hDownloadButton,
				BM_SETIMAGE,
				(WPARAM)IMAGE_BITMAP,
				(LPARAM)(HANDLE)LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_DOWNLOAD)));
	SendMessageW(hUninstallButton,
				BM_SETIMAGE,
				(WPARAM)IMAGE_BITMAP,
				(LPARAM)(HANDLE)LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_UNINSTALL)));
	ShowWindow(hUninstallButton, SW_HIDE);

	// Set deflaut entry for hApps
	Insert.item.mask = TVIF_TEXT|TVIF_IMAGE;
	Insert.item.pszText = Strings[IDS_CHOOSE_CATEGORY];
	Insert.item.cchTextMax = lstrlenW(Strings[IDS_CHOOSE_CATEGORY]);
	Insert.item.iImage = 0;
	SendMessage(hApps, TVM_INSERTITEM, 0, (LPARAM)&Insert);

	// Create Tree Icons
	hImageList = ImageList_Create(16, 16, ILC_COLORDDB, 1, 1);
	SendMessageW(hCategories, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)(HIMAGELIST)hImageList);
	SendMessageW(hApps, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)(HIMAGELIST)hImageList);

	ImageList_Add(hImageList,
				  LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_0)), NULL);
	ImageList_Add(hImageList,
				  LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_1)), NULL);
	ImageList_Add(hImageList,
				  LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_2)), NULL);
	ImageList_Add(hImageList,
				  LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_3)), NULL);
	ImageList_Add(hImageList,
				  LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_4)), NULL);
	ImageList_Add(hImageList,
				  LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_5)), NULL);
	ImageList_Add(hImageList,
				  LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_6)), NULL);
	ImageList_Add(hImageList,
				  LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_7)), NULL);
	ImageList_Add(hImageList,
				  LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_8)), NULL);
	ImageList_Add(hImageList,
				  LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_9)), NULL);
	ImageList_Add(hImageList,
				  LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_10)), NULL);
	ImageList_Add(hImageList,
				  LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_11)), NULL);
	ImageList_Add(hImageList,
				  LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_12)), NULL);
	ImageList_Add(hImageList,
				  LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TREEVIEW_ICON_13)), NULL);

	// Fill the TreeViews
	AddItems (hCategories, Root.Children, NULL);

	return TRUE;
}

static void
ResizeControl (HWND hwnd, int x1, int y1, int x2, int y2)
{
	// Make resizing a little easier
	MoveWindow(hwnd, x1, y1, x2-x1, y2-y1, TRUE);
}

static void
DrawBitmap (HDC hdc, int x, int y, HBITMAP hBmp)
{
	BITMAP bm;
	HDC hdcMem = CreateCompatibleDC(hdc);

	SelectObject(hdcMem, hBmp);
	GetObject(hBmp, sizeof(bm), &bm);
	TransparentBlt(hdc, x, y, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, 0xFFFFFF);

	DeleteDC(hdcMem);
}

static void
DrawDescription (HDC hdc, RECT DescriptionRect)
{
	int i;
	HFONT Font;
	RECT Rect = {DescriptionRect.left+5, DescriptionRect.top+3, DescriptionRect.right-2, DescriptionRect.top+22};

	// Backgroud
	Rectangle(hdc, DescriptionRect.left, DescriptionRect.top, DescriptionRect.right, DescriptionRect.bottom);

	// Underline
	for (i=DescriptionRect.left+1;i<DescriptionRect.right-1;i++)
		DrawBitmap(hdc, i, DescriptionRect.top+22, hUnderline); // less code then stretching ;)

	// Headline
	Font = CreateFont(-16 , 0, 0, 0, FW_EXTRABOLD, FALSE, FALSE, FALSE, ANSI_CHARSET,
					  OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, L"Arial");
	SelectObject(hdc, Font);
	DrawTextW(hdc, DescriptionHeadline, lstrlenW(DescriptionHeadline), &Rect, DT_SINGLELINE|DT_NOPREFIX);
	DeleteObject(Font);

	// Description
	Font = CreateFont(-13 , 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
					  OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, L"Arial");
	SelectObject(hdc, Font);
	Rect.top += 50;
	Rect.bottom = DescriptionRect.bottom-2;
	DrawTextW(hdc, DescriptionText, lstrlenW(DescriptionText), &Rect, DT_WORDBREAK|DT_NOPREFIX); // ToDo: Call TabbedTextOut to draw a nice table
	DeleteObject(Font);

}

void showUninstaller() {
	int Split_Vertical = 200;
	RECT Rect;

    GetClientRect(hwnd,&Rect);
	ShowWindow(hUninstallButton,SW_SHOW);
	MoveWindow(hDownloadButton,(Split_Vertical+Rect.right-Rect.left)/2,Rect.bottom-Rect.top-45,140,35,TRUE);;
}

void hideUninstaller() {
	int Split_Vertical = 200;
	RECT Rect;

    GetClientRect(hwnd,&Rect);
	ShowWindow(hUninstallButton,SW_HIDE);
	MoveWindow(hDownloadButton,(Split_Vertical+Rect.right-Rect.left)/2-70,Rect.bottom-Rect.top-45,140,35,TRUE);
}

void startUninstaller(WCHAR* Uninstaller) {
	STARTUPINFOW si;
	PROCESS_INFORMATION pi;

	memset(&si, 0, sizeof(si));
	si.cb = sizeof(si);
	CreateProcessW(NULL,Uninstaller,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
	CloseHandle(pi.hThread);
	// WaitForSingleObject(pi.hProcess, INFINITE); // If you want to wait for the Unistaller
	CloseHandle(pi.hProcess);
    hideUninstaller();
}

BOOL
SaveSettings(HWND hwnd)
{
	HKEY hKey;
	TCHAR szBuf[MAX_PATH];

	if (RegOpenKey(HKEY_LOCAL_MACHINE,
                   TEXT("Software\\ReactOS\\Download!"),
                   &hKey) != ERROR_SUCCESS)
		return FALSE;

	SendMessage(GetDlgItem(hwnd, IDC_DOWNLOAD_FOLDER_EDIT), WM_GETTEXT, sizeof(szBuf)/sizeof(TCHAR), (LPARAM)szBuf);
	if (GetFileAttributes(szBuf) == 0xFFFFFFFF)
		if (!CreateDirectory((LPCTSTR)szBuf,NULL))
		{
			LoadString(GetModuleHandle(NULL), IDS_UNABLECREATE_FOLDER, szBuf, sizeof(szBuf) / sizeof(TCHAR));
			MessageBox(hwnd, (LPCTSTR)szBuf, NULL, MB_ICONSTOP);
			return FALSE;
		}
	if (RegSetValueEx(hKey,
					  L"DownloadFolder",
					  0,
					  REG_SZ,
					  (LPBYTE)szBuf,
					  (DWORD)(sizeof(szBuf) / sizeof(TCHAR))))
		return FALSE;

	SendMessage(GetDlgItem(hwnd, IDC_UPDATE_SERVER_EDIT), WM_GETTEXT, sizeof(szBuf)/sizeof(TCHAR), (LPARAM)szBuf);
	if (RegSetValueEx(hKey,
					  L"UpdateServer",
					  0,
					  REG_SZ,
					  (LPBYTE)szBuf,
					  (DWORD)(sizeof(szBuf) / sizeof(TCHAR))))
		return FALSE;

	DWORD dwValue;
	if (SendMessage(GetDlgItem(hwnd, IDC_DELINST_FILES_CHECKBOX), BM_GETCHECK, 0, 0) == BST_CHECKED)
		dwValue = 0x1;
	else
		dwValue = 0x0;
	if (RegSetValueEx(hKey,
					  L"DeleteInstaller",
					  0,
					  REG_DWORD,
					  (LPBYTE)&dwValue,
					  sizeof(DWORD)))
			return FALSE;

	RegCloseKey(hKey);

	return TRUE;
}

BOOL
InitProfDlg(HWND hwnd)
{
	HKEY hKey;
	TCHAR Buf[MAX_PATH];
	DWORD dwDisp, dwSize;

	if (RegOpenKey(HKEY_LOCAL_MACHINE,
                   TEXT("Software\\ReactOS\\Download!"),
                   &hKey) != ERROR_SUCCESS)
	{
		if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, L"Software\\ReactOS\\Download!",
						   0, NULL, REG_OPTION_NON_VOLATILE,
						   KEY_WRITE, NULL, &hKey, &dwDisp))
		{
			LoadString(GetModuleHandle(NULL), IDS_NOTCREATE_REGKEY, Buf, sizeof(Buf) / sizeof(TCHAR));
			MessageBox(hwnd, (LPCTSTR)Buf, NULL, MB_ICONSTOP);
			return FALSE;
		}
	}

	dwSize = MAX_PATH;
	if (RegQueryValueEx(hKey,
                        L"DownloadFolder",
                        NULL,
                        NULL,
                        (LPBYTE)&Buf,
                        &dwSize) == ERROR_SUCCESS)
	{
		SendMessage(GetDlgItem(hwnd, IDC_DOWNLOAD_FOLDER_EDIT), WM_SETTEXT, -1, (LPARAM)Buf);
	}
	else
	{
		if (!GetWindowsDirectory(Buf, sizeof(Buf) / sizeof(TCHAR))) return FALSE;

		TCHAR DPath[256];
		int i;
		for (i = 0; i < 4; i++)
		{
			if (i == 3)
			{
				DPath[i] = '\0';
				break;
			}
			DPath[i] = Buf[i];
		}
		LoadString(GetModuleHandle(NULL), IDS_DOWNLOAD_FOLDER, Buf, sizeof(Buf) / sizeof(TCHAR));
		lstrcat((LPTSTR)DPath, Buf);
		if (RegSetValueEx(hKey,
						  L"DownloadFolder",
						  0,
						  REG_SZ,
						  (LPBYTE)DPath,
						  (DWORD)(sizeof(DPath) / sizeof(TCHAR))))
			return FALSE;
		else
		{
			if (GetFileAttributes(DPath) == 0xFFFFFFFF)
				if (!CreateDirectory((LPCTSTR)DPath,NULL)) return FALSE;
			SendMessage(GetDlgItem(hwnd, IDC_DOWNLOAD_FOLDER_EDIT), WM_SETTEXT, -1, (LPARAM)DPath);
		}
	}

	dwSize = MAX_PATH;
	if (RegQueryValueEx(hKey,
                        L"UpdateServer",
                        NULL,
                        NULL,
                        (LPBYTE)&Buf,
                        &dwSize) == ERROR_SUCCESS)
	{
		SendMessage(GetDlgItem(hwnd, IDC_UPDATE_SERVER_EDIT), WM_SETTEXT, -1, (LPARAM)Buf);
	}
	else
	{
		LoadString(GetModuleHandle(NULL), IDS_UPDATE_URL, Buf, sizeof(Buf) / sizeof(TCHAR));
		if (RegSetValueEx(hKey,
						  L"UpdateServer",
						  0,
						  REG_SZ,
						  (LPBYTE)Buf,
						  (DWORD)(sizeof(Buf) / sizeof(TCHAR))))
			return FALSE;
		else
		{
			SendMessage(GetDlgItem(hwnd, IDC_UPDATE_SERVER_EDIT), WM_SETTEXT, -1, (LPARAM)Buf);
		}
	}

	DWORD dwValue, dwType = REG_DWORD;
	dwSize = sizeof(DWORD);
	if (RegQueryValueEx(hKey,
                        L"DeleteInstaller",
                        NULL,
                        &dwType,
                        (LPBYTE)&dwValue,
                        &dwSize) == ERROR_SUCCESS)
	{
		if (dwValue == 0x1)
			SendMessage(GetDlgItem(hwnd, IDC_DELINST_FILES_CHECKBOX), BM_SETCHECK, 1, 1);
	}
	else
	{
		dwValue = 0x0;
		if (RegSetValueEx(hKey,
						  L"DeleteInstaller",
						  0,
						  REG_DWORD,
						  (LPBYTE)&dwValue,
						  sizeof(DWORD)))
			return FALSE;
	}

	RegCloseKey(hKey);

	return TRUE;
}

BOOL
ChooseFolder(HWND hwnd)
{
	BROWSEINFO fi;
	LPCITEMIDLIST lpItemList;
	TCHAR szPath[MAX_PATH],Buf[256];

	ZeroMemory(&fi, sizeof(BROWSEINFO));
	fi.hwndOwner = hwnd;
	LoadString(GetModuleHandle(NULL), IDS_CHOOSE_FOLDER, Buf, sizeof(Buf) / sizeof(TCHAR));
	fi.lpszTitle = (LPCTSTR)Buf;
	fi.ulFlags = BIF_DONTGOBELOWDOMAIN | BIF_RETURNONLYFSDIRS | BIF_BROWSEFORCOMPUTER | BIF_NEWDIALOGSTYLE;
	fi.lpfn = NULL;
	fi.lParam = -1;
	fi.iImage = 0;

	if(!(lpItemList = SHBrowseForFolder(&fi))) return FALSE;
	SHGetPathFromIDList(lpItemList, szPath);

	if (_tcslen(szPath) == 0) return FALSE;
	SendMessage(GetDlgItem(hwnd, IDC_DOWNLOAD_FOLDER_EDIT), WM_SETTEXT, -1, (LPARAM)szPath);

	return TRUE;
}

INT_PTR CALLBACK
ProfDlgProc(HWND hDlg,
			UINT message,
			WPARAM wParam,
			LPARAM lParam)
{
    static HICON hIcon;
    UNREFERENCED_PARAMETER(lParam);

    switch (message)
    {
        case WM_INITDIALOG:
        {
            hIcon = LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_MAIN),IMAGE_ICON,16,16,0);
            SendMessage(hDlg,WM_SETICON,ICON_SMALL,(LPARAM)hIcon);
			InitProfDlg(hDlg);
        }
		break;

        case WM_COMMAND:
        {
			switch (wParam)
			{
				case IDC_CHOOSE_BUTTON:
					ChooseFolder(hDlg);
				break;
				case IDOK:
				{
					SaveSettings(hDlg);
				    DestroyIcon(hIcon);
					EndDialog(hDlg,LOWORD(wParam));
					return TRUE;
				}
				break;
				case IDCANCEL:
				{
					DestroyIcon(hIcon);
					EndDialog(hDlg,LOWORD(wParam));
					return TRUE;
				}
				break;
			}
        }
        break;
    }

    return FALSE;
}

LRESULT CALLBACK
WndProc (HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
	static RECT DescriptionRect;

	switch (Message)
	{
		case WM_CREATE:
		{
			if(!SetupControls(hwnd))
				return -1;
			ShowMessage(Strings[IDS_WELCOME_TITLE], Strings[IDS_WELCOME]);
		}
		break;

		case WM_PAINT:
		{
			PAINTSTRUCT ps;
			HDC hdc = BeginPaint(hwnd, &ps);
			HDC BackbufferHdc = CreateCompatibleDC(hdc);
			HBITMAP BackbufferBmp = CreateCompatibleBitmap(hdc, ps.rcPaint.right, ps.rcPaint.bottom);
			SelectObject(BackbufferHdc, BackbufferBmp);

			FillRect(BackbufferHdc, &ps.rcPaint, CreateSolidBrush(RGB(235,235,235)));
			DrawBitmap(BackbufferHdc, 10, 12, hLogo);
			DrawDescription(BackbufferHdc, DescriptionRect);

			BitBlt(hdc, 0, 0, ps.rcPaint.right, ps.rcPaint.bottom, BackbufferHdc, 0, 0, SRCCOPY);
			DeleteObject(BackbufferBmp);
			DeleteDC(BackbufferHdc);
			EndPaint(hwnd, &ps);
		}
		break;

		case WM_COMMAND:
		{
			if(HIWORD(wParam) == BN_CLICKED)
			{
				if (lParam == (LPARAM)hProfButton)
				{
					DialogBox(GetModuleHandle(NULL),
							  MAKEINTRESOURCE(IDD_PROF),
							  hwnd,
							  ProfDlgProc);
				}
				if (lParam == (LPARAM)hDownloadButton)
				{
					if(SelectedApplication)
						DialogBoxW(GetModuleHandle(NULL), MAKEINTRESOURCEW(IDD_DOWNLOAD), 0, DownloadProc);
					else
						ShowMessage(Strings[IDS_NO_APP_TITLE], Strings[IDS_NO_APP]);
				}
				else if (lParam == (LPARAM)hUninstallButton)
				{
					if(SelectedApplication)
					{
						WCHAR Uninstaller[200];
						if(StrCmpW(SelectedApplication->RegName, L"")) {
							if(getUninstaller(SelectedApplication->RegName, Uninstaller))
								startUninstaller(Uninstaller);
						}
					}
				}
				else if (lParam == (LPARAM)hUpdateButton)
				{
					ShowMessage(Strings[IDS_UPDATE_TITLE], Strings[IDS_UPDATE]);
				}
				else if (lParam == (LPARAM)hHelpButton)
				{
					ShowMessage(Strings[IDS_HELP_TITLE], Strings[IDS_HELP]);
				}
			}
		}
		break;

		case WM_NOTIFY:
		{
			LPNMHDR data = (LPNMHDR)lParam;
			if(data->code == TVN_SELCHANGED)
			{
				BOOL bShowUninstaller = FALSE;
				if(data->hwndFrom == hCategories)
				{
					struct Category* Category = (struct Category*) ((LPNMTREEVIEW)lParam)->itemNew.lParam;
					CategoryChoosen (hApps, Category);
				}
				else if(data->hwndFrom == hApps)
				{
					SelectedApplication = (struct Application*) ((LPNMTREEVIEW)lParam)->itemNew.lParam;
					if(SelectedApplication)
					{
						ApplicationText[0]=L'\0';
						if(StrCmpW(SelectedApplication->Version, L"")) {
							StrCatW(ApplicationText, Strings[IDS_VERSION]);
							StrCatW(ApplicationText, SelectedApplication->Version);
							StrCatW(ApplicationText, L"\n");
						}
						if(StrCmpW(SelectedApplication->Licence, L"")) {
							StrCatW(ApplicationText, Strings[IDS_LICENCE]);
							StrCatW(ApplicationText, SelectedApplication->Licence);
							StrCatW(ApplicationText, L"\n");
						}
						if(StrCmpW(SelectedApplication->Maintainer, L"")) {
							StrCatW(ApplicationText, Strings[IDS_MAINTAINER]);
							StrCatW(ApplicationText, SelectedApplication->Maintainer);
							StrCatW(ApplicationText, L"\n");
						}
						if(StrCmpW(SelectedApplication->Licence, L"") || StrCmpW(SelectedApplication->Version, L"") || StrCmpW(SelectedApplication->Maintainer, L""))
							StrCatW(ApplicationText, L"\n");
						StrCatW(ApplicationText, SelectedApplication->Description);
						ShowMessage(SelectedApplication->Name, ApplicationText);
						WCHAR Uninstaller[200];
						if(StrCmpW(SelectedApplication->RegName, L"")) {
							if(getUninstaller(SelectedApplication->RegName, Uninstaller)) {
								bShowUninstaller = TRUE;
							}
						}
					}
				}
				if (bShowUninstaller)
					showUninstaller();
				else
					hideUninstaller();
			}
		}
		break;

		case WM_SIZING:
		{
			LPRECT pRect = (LPRECT)lParam;
			if (pRect->right-pRect->left < 520)
				pRect->right = pRect->left + 520;

			if (pRect->bottom-pRect->top < 300)
				pRect->bottom = pRect->top + 300;
		}
		break;

		case WM_SIZE:
		{
			int Split_Hozizontal = (HIWORD(lParam)-(45+60))/2 + 60;
			int Split_Vertical = 200;

			ResizeControl(hCategories, 10, 60, Split_Vertical, HIWORD(lParam)-10);
			ResizeControl(hApps, Split_Vertical+5, 60, LOWORD(lParam)-10, Split_Hozizontal);
			RECT Rect = {Split_Vertical+5, Split_Hozizontal+5, LOWORD(lParam)-10, HIWORD(lParam)-50};
			DescriptionRect = Rect;

			MoveWindow(hHelpButton, LOWORD(lParam)-50, 10, 40, 40, TRUE);
			MoveWindow(hUpdateButton, LOWORD(lParam)-150, 10, 40, 40, TRUE);
			MoveWindow(hProfButton, LOWORD(lParam)-100, 10, 40, 40, TRUE);
			if(IsWindowVisible(hUninstallButton))
				MoveWindow(hDownloadButton, (Split_Vertical+LOWORD(lParam))/2, HIWORD(lParam)-45, 140, 35, TRUE);
			else
				MoveWindow(hDownloadButton, (Split_Vertical+LOWORD(lParam))/2-70, HIWORD(lParam)-45, 140, 35, TRUE);
			MoveWindow(hUninstallButton, (Split_Vertical+LOWORD(lParam))/2-140, HIWORD(lParam)-45, 140, 35, TRUE);
		}
		break;

		case WM_DESTROY:
		{
			DeleteObject(hLogo);
			if(Root.Children)
				FreeTree(Root.Children);
			PostQuitMessage(0);
			return 0;
		}
		break;
	}

	return DefWindowProc (hwnd, Message, wParam, lParam);
}

INT WINAPI
wWinMain (HINSTANCE hInstance,
		  HINSTANCE hPrevInst,
		  LPTSTR lpCmdLine,
		  INT nCmdShow)
{
	int i;
	WNDCLASSEXW WndClass = {0};
	MSG msg;

	InitCommonControls();

	// Load strings
	for(i=0; i<STRING_COUNT; i++)
		LoadStringW(hInstance, i, Strings[i], MAX_STRING_LENGHT); // if you know a better method please tell me.

	// Create the window
	WndClass.cbSize			= sizeof(WNDCLASSEX);
	WndClass.lpszClassName	= L"Downloader";
	WndClass.lpfnWndProc	= WndProc;
	WndClass.hInstance		= hInstance;
	WndClass.style			= CS_HREDRAW | CS_VREDRAW;
	WndClass.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAIN));
	WndClass.hCursor		= LoadCursor(NULL, IDC_ARROW);

	RegisterClassExW(&WndClass);

	hwnd = CreateWindowW(L"Downloader",
						Strings[IDS_WINDOW_TITLE],
						WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN,
						CW_USEDEFAULT,
						CW_USEDEFAULT,
						650, 550,
						NULL, NULL,
						hInstance,
						NULL);

	// Show it
	ShowWindow(hwnd, SW_SHOW);
	UpdateWindow(hwnd);

	// Message Loop
	while(GetMessage(&msg,NULL,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return 0;
}
