/*
UserinfoEx plugin for Miranda IM

Copyright:
� 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol

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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#include "..\commonheaders.h"

/***********************************************************************************************************
 * typedefs
 ***********************************************************************************************************/

typedef struct {
	lpExImParam		ExImContact;
	DB::CEnumList*	pModules;
} EXPORTDATA, *LPEXPORTDATA;

/***********************************************************************************************************
 * modules stuff
 ***********************************************************************************************************/

/**
 * name:	ExportTree_AppendModuleList
 * desc:	according to the checked list items create the module list for exporting
 * param:	hTree		- handle to the window of the treeview
 *			hParent		- parent tree item for the item to add
 *			pModules	- module list to fill
 * return:	nothing
 **/
void ExportTree_AppendModuleList(HWND hTree, HTREEITEM hParent, DB::CEnumList* pModules)
{
	TVITEMA tvi;

	// add all checked modules
	if (tvi.hItem = TreeView_GetChild(hTree, hParent)) {
		CHAR szModule[MAXSETTING];

		// add optional items
		tvi.mask = TVIF_STATE|TVIF_TEXT;
		tvi.stateMask = TVIS_STATEIMAGEMASK;
		tvi.pszText = szModule;
		tvi.cchTextMax = MAXSETTING;

		do {
			if (
				SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&tvi) &&
				(
					tvi.state == INDEXTOSTATEIMAGEMASK(0) ||
					tvi.state == INDEXTOSTATEIMAGEMASK(2)
				) 
			 )
			{
				pModules->Insert(tvi.pszText);
			}
		}
		while (tvi.hItem = TreeView_GetNextSibling(hTree, tvi.hItem));
	}
}

/**
 * name:	ExportTree_FindItem
 * desc:	find a item by its label
 * param:	hTree		- handle to the window of the treeview
 *			hParent		- parent tree item for the item to add
 *			pszText		- text to match the label against
 * return:	a handle to the found treeitem or NULL
 **/
HTREEITEM ExportTree_FindItem(HWND hTree, HTREEITEM hParent, LPSTR pszText)
{
	TVITEMA tvi;
	CHAR szBuf[128];

	if (!pszText || !*pszText) return NULL;

	tvi.mask = TVIF_TEXT;
	tvi.pszText = szBuf;
	tvi.cchTextMax = SIZEOF(szBuf);

	for (tvi.hItem = TreeView_GetChild(hTree, hParent);
		tvi.hItem != NULL;
		tvi.hItem = TreeView_GetNextSibling(hTree, tvi.hItem))
	{
		if (SendMessageA(hTree, TVM_GETITEMA, NULL, (LPARAM)&tvi) && !mir_stricmp(tvi.pszText, pszText))
			return tvi.hItem;
	}
	return NULL;
}

/**
 * name:	ExportTree_AddItem
 * desc:	add an item to the tree view with given options
 * param:	hTree		- handle to the window of the treeview
 *			hParent		- parent tree item for the item to add
 *			pszDesc		- item label
 *			bUseImages	- icons are loaded
 *			bState		- 0-hide checkbox/1-unchecked/2-checked
 * return:	return handle to added treeitem 
 **/
HTREEITEM ExportTree_AddItem(HWND hTree, HTREEITEM hParent, LPSTR pszDesc, BYTE bUseImages, BYTE bState)
{
	TVINSERTSTRUCTA	tvii;
	HTREEITEM hItem = NULL;

	tvii.hParent = hParent;
	tvii.hInsertAfter = TVI_SORT;
	tvii.itemex.mask = TVIF_TEXT;
	if (bUseImages) {
		tvii.itemex.mask |= TVIF_IMAGE|TVIF_SELECTEDIMAGE;
		tvii.itemex.iImage = tvii.itemex.iSelectedImage = 1;
	}
	tvii.itemex.pszText = pszDesc;
	if (hItem = (HTREEITEM)SendMessageA(hTree, TVM_INSERTITEMA, NULL, (LPARAM)&tvii))
		TreeView_SetItemState(hTree, hItem, INDEXTOSTATEIMAGEMASK(bState), TVIS_STATEIMAGEMASK);
	return hItem;
}

/**
 * name:	SelectModulesToExport_DlgProc
 * desc:	dialog procedure for a dialogbox, which lists modules for a specific contact
 * param:	hDlg		- handle to the window of the dialogbox
 *			uMsg		- message to handle
 *			wParam		- message specific parameter
 *			lParam		- message specific parameter
 * return:	message specific
 **/
INT_PTR CALLBACK SelectModulesToExport_DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	LPEXPORTDATA pDat = (LPEXPORTDATA)GetUserData(hDlg);

	switch (uMsg) {
	
		case WM_INITDIALOG:
		{
			HWND hTree;
			BYTE bImagesLoaded = 0;

			// get tree handle and set treeview style
			if (!(hTree = GetDlgItem(hDlg, IDC_TREE))) break;
			SetWindowLongPtr(hTree, GWL_STYLE, GetWindowLongPtr(hTree, GWL_STYLE) | TVS_NOHSCROLL | TVS_CHECKBOXES);

			// init the datastructure
			if (!(pDat = (LPEXPORTDATA)mir_alloc(sizeof(EXPORTDATA))))
				return FALSE;
			pDat->ExImContact	= ((LPEXPORTDATA)lParam)->ExImContact;
			pDat->pModules		= ((LPEXPORTDATA)lParam)->pModules;
			SetUserData(hDlg, pDat);

			// set icons
			{
				HICON hIcon;
				HIMAGELIST hImages;
				OSVERSIONINFO osvi;
				const ICONCTRL idIcon[] = {
					{ ICO_DLG_EXPORT,	WM_SETICON,		NULL		},
					{ ICO_DLG_EXPORT,	STM_SETIMAGE,	ICO_DLGLOGO	},
					{ ICO_BTN_EXPORT,	BM_SETIMAGE,	IDOK		},
					{ ICO_BTN_CANCEL,	BM_SETIMAGE,	IDCANCEL	}
				};
				const int numIconsToSet = db_get_b(NULL, MODNAME, SET_ICONS_BUTTONS, 1) ? SIZEOF(idIcon) : 2;
				IcoLib_SetCtrlIcons(hDlg, idIcon, numIconsToSet);

				// create imagelist for treeview
				osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
				GetVersionEx(&osvi);
				if ((hImages = ImageList_Create(
						GetSystemMetrics(SM_CXSMICON),
						GetSystemMetrics(SM_CYSMICON),
						((osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion >= 5 && osvi.dwMinorVersion >= 1) ? ILC_COLOR32 : ILC_COLOR16)|ILC_MASK,
						0, 1)
					) != NULL)
				{
					SendMessage(hTree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)hImages);

					bImagesLoaded 
						= ((((hIcon = Skin_GetIcon(ICO_LST_MODULES)) != NULL) && 0 == ImageList_AddIcon(hImages, hIcon))
						&& (((hIcon = Skin_GetIcon(ICO_LST_FOLDER)) != NULL) && 1 == ImageList_AddIcon(hImages, hIcon)));
				}
			}
			// do the translation stuff
			{
				SendDlgItemMessage(hDlg, BTN_CHECK, BUTTONTRANSLATE, NULL, NULL);
				SendDlgItemMessage(hDlg, BTN_UNCHECK, BUTTONTRANSLATE, NULL, NULL);
				SendDlgItemMessage(hDlg, IDOK, BUTTONTRANSLATE, NULL, NULL);
				SendDlgItemMessage(hDlg, IDCANCEL, BUTTONTRANSLATE, NULL, NULL);
			}
			// Set the Window Title and description
			{
				LPCTSTR name = NULL; 
				TCHAR	oldTitle[MAXDATASIZE], 
						newTitle[MAXDATASIZE];
				switch (pDat->ExImContact->Typ) {
					case EXIM_ALL:
					case EXIM_GROUP:
						name = TranslateT("All Contacts");
						break;
					case EXIM_CONTACT:
						if (pDat->ExImContact->hContact == NULL) {
							name = TranslateT("Owner");
						}
						else {
							name = DB::Contact::DisplayName(pDat->ExImContact->hContact);
						}
						break;
					case EXIM_SUBGROUP:
						name = (LPCTSTR) pDat->ExImContact->ptszName;
						break;
					case EXIM_ACCOUNT:
						PROTOACCOUNT* acc = ProtoGetAccount(pDat->ExImContact->pszName);
						name = (LPCTSTR) acc->tszAccountName;
						break;
				}
				TranslateDialogDefault(hDlg);			//to translate oldTitle
				GetWindowText(hDlg, oldTitle, MAXSETTING);
				mir_sntprintf(newTitle, MAXDATASIZE - 1, _T("%s - %s"), name, oldTitle);
				SetWindowText(hDlg, newTitle);
			}

			{
				LPSTR pszProto;
				TVINSERTSTRUCT	tviiT;
				DB::CEnumList Modules;
				HTREEITEM hItemEssential, hItemOptional;

				TreeView_SetIndent(hTree, 6);
				TreeView_SetItemHeight(hTree, 18);

				pszProto = (pDat->ExImContact->Typ == EXIM_CONTACT && pDat->ExImContact->hContact != NULL)
					? (LPSTR)DB::Contact::Proto(pDat->ExImContact->hContact)
					: NULL;

				// add items that are always exported
				tviiT.hParent = TVI_ROOT;
				tviiT.hInsertAfter = TVI_FIRST;
				tviiT.itemex.mask = TVIF_TEXT|TVIF_STATE;
				tviiT.itemex.pszText = TranslateT("Required modules");
				tviiT.itemex.state = tviiT.itemex.stateMask = TVIS_EXPANDED;
				if (bImagesLoaded) {
					tviiT.itemex.mask |= TVIF_IMAGE|TVIF_SELECTEDIMAGE;
					tviiT.itemex.iImage = tviiT.itemex.iSelectedImage = 0;
				}
				if (hItemEssential = TreeView_InsertItem(hTree, &tviiT)) {
					// disable state images
					TreeView_SetItemState(hTree, hItemEssential, INDEXTOSTATEIMAGEMASK(0), TVIS_STATEIMAGEMASK);

					// insert essential items (modul from UIEX)
					ExportTree_AddItem(hTree, hItemEssential, USERINFO, bImagesLoaded, 0);
					ExportTree_AddItem(hTree, hItemEssential, MOD_MBIRTHDAY, bImagesLoaded, 0);

					/*Filter/ protocol module is ignored for owner contact
					if (pDat->hContact != NULL) {
						ExportTree_AddItem(hTree, hItemEssential, "Protocol", bImagesLoaded, 0);
					}*/

					// base protocol is only valid for single exported contact at this position
					if (pszProto) {
						ExportTree_AddItem(hTree, hItemEssential, pszProto, bImagesLoaded, 0);
					}
				}

				// add items that are optional (and more essential)
				tviiT.hInsertAfter = TVI_LAST;
				tviiT.itemex.pszText = TranslateT("Optional modules");
				if (hItemOptional = TreeView_InsertItem(hTree, &tviiT)) {
					TreeView_SetItemState(hTree, hItemOptional, INDEXTOSTATEIMAGEMASK(0), TVIS_STATEIMAGEMASK);

					if (!Modules.EnumModules())	// init Modul list
					{
						int i;
						LPSTR p;

						for (i = 0; i < Modules.getCount(); i++)
						{
							p = Modules[i];
							/*Filter/
							if (!DB::Module::IsMeta(p))/end Filter*/
							{
								// module must exist in at least one contact
								if (pDat->ExImContact->Typ != EXIM_CONTACT) // TRUE = All Contacts
								{
									HANDLE hContact;
									
									for (hContact = db_find_first(); hContact != NULL; hContact = db_find_next(hContact))
									{
										// ignore empty modules
										if (!DB::Module::IsEmpty(hContact, p)) {
											pszProto = DB::Contact::Proto(hContact);
											// Filter by mode
											switch (pDat->ExImContact->Typ)
											{
												case EXIM_ALL:
												case EXIM_GROUP:
													break;
												case EXIM_SUBGROUP:
													if (mir_tcsncmp(pDat->ExImContact->ptszName, DB::Setting::GetTString(hContact, "CList", "Group"), mir_tcslen(pDat->ExImContact->ptszName))) {
														continue;
													}
													break;
												case EXIM_ACCOUNT:
													if (mir_strcmp(pDat->ExImContact->pszName, pszProto)) {
														continue;
													}
													break;
											}

											// contact's base protocol is to be added to the treeview uniquely
											if (!mir_stricmp(p, pszProto))
											{
												if (!ExportTree_FindItem(hTree, hItemEssential, p))
												{
													ExportTree_AddItem(hTree, hItemEssential, p, bImagesLoaded, 0);
												}
												break;
											}

											// add optional module, which is valid for at least one contact
											/*/Filter/*/
											if ( mir_stricmp(p, USERINFO) &&
												mir_stricmp(p, MOD_MBIRTHDAY) &&
												// Meta is only valid as base Proto at this point
												mir_stricmp(p, myGlobals.szMetaProto) /*&&
												mir_stricmp(p, "Protocol")*/
											 ) 
											{
												ExportTree_AddItem(hTree, hItemOptional, p, bImagesLoaded, 1);
												break;
											}
										}
									} // end for
								} // end TRUE = All Contacts

								// module must exist in the selected contact
								else if (
									/*Filter/*/
									!DB::Module::IsEmpty(pDat->ExImContact->hContact, p) &&
									(!pDat->ExImContact->hContact || mir_stricmp(p, pszProto)) &&
									//mir_stricmp(p, "Protocol") &&
									mir_stricmp(p, USERINFO) &&
									mir_stricmp(p, MOD_MBIRTHDAY))
								{
									ExportTree_AddItem(hTree, hItemOptional, (LPSTR)p, bImagesLoaded, 1);
								}
							} // end 
						}
					}
				}
			}
			TranslateDialogDefault(hDlg);
			return TRUE;
		}
		case WM_CTLCOLORSTATIC:
			if (GetDlgItem(hDlg, STATIC_WHITERECT) == (HWND)lParam || GetDlgItem(hDlg, ICO_DLGLOGO) == (HWND)lParam) {
				SetBkColor((HDC)wParam, RGB(255, 255, 255));
				return (INT_PTR)GetStockObject(WHITE_BRUSH);
			}
			SetBkMode((HDC)wParam, TRANSPARENT);
			return (INT_PTR)GetStockObject(NULL_BRUSH);

		case WM_COMMAND:
			switch (LOWORD(wParam)) {
				case IDOK:
				{
					HWND hTree = GetDlgItem(hDlg, IDC_TREE);
					HTREEITEM hParent;

					// search the tree item of optional items
					for (hParent = TreeView_GetRoot(hTree);
						hParent != NULL;
						hParent = TreeView_GetNextSibling(hTree, hParent))
					{
						ExportTree_AppendModuleList(hTree, hParent, pDat->pModules);
					}
					return EndDialog(hDlg, IDOK);
				}
				case IDCANCEL:
					return EndDialog(hDlg, IDCANCEL);

				case BTN_CHECK:
				case BTN_UNCHECK:
				{
					HWND hTree = GetDlgItem(hDlg, IDC_TREE);
					LPCSTR pszRoot = Translate("Optional modules");
					TVITEMA tvi;
					CHAR szText[128];

					tvi.mask = TVIF_TEXT;
					tvi.pszText = szText;
					tvi.cchTextMax = sizeof(szText);

					// search the tree item of optional items
					for (tvi.hItem = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_ROOT, NULL);
						tvi.hItem != NULL && SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&tvi);
						tvi.hItem = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)tvi.hItem))
					{
						if (!mir_stricmp(tvi.pszText, pszRoot)) {
							tvi.mask = TVIF_STATE;
							tvi.state = INDEXTOSTATEIMAGEMASK(LOWORD(wParam) == BTN_UNCHECK ? 1 : 2);
							tvi.stateMask = TVIS_STATEIMAGEMASK;

							for (tvi.hItem = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)tvi.hItem);
								tvi.hItem != NULL;
								tvi.hItem = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)tvi.hItem))
							{
								SendMessageA(hTree, TVM_SETITEMA, NULL, (LPARAM)&tvi);
							}
							break;
						}
					}
					break;
				}
			}
			break;

		case WM_DESTROY:
			mir_free(pDat);
			break;
	}
	return 0;
}

/**
 * name:	DlgExImModules_SelectModulesToExport
 * desc:	calls a dialog box that lists all modules for a specific contact
 * param:	ExImContact	- lpExImParam
 *			pModules	- pointer to an ENUMLIST structure that retrieves the resulting list of modules
 *			hParent		- handle to a window which should act as the parent of the created dialog
 * return:	0 if user pressed ok, 1 on cancel
 **/
int DlgExImModules_SelectModulesToExport(lpExImParam ExImContact, DB::CEnumList* pModules, HWND hParent)
{
	EXPORTDATA dat;

	dat.ExImContact = ExImContact;
	dat.pModules = pModules;
	return (IDOK != DialogBoxParam(ghInst, MAKEINTRESOURCE(IDD_EXPORT), hParent, SelectModulesToExport_DlgProc, (LPARAM)&dat));
}