/*

Miranda IM: the free IM client for Microsoft* Windows*

Copyright 2000-2008 Miranda ICQ/IM project,
all portions of this codebase are copyrighted to the people
listed in contributors.txt.

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 "hdr/modern_commonheaders.h"
#include "hdr/modern_clist.h"
#include "hdr/modern_commonprototypes.h"
#include "hdr/modern_sync.h"

/*******************************/
// Main skin selection routine //
/*******************************/
#define MAX_NAME 100
typedef struct _SkinListData
{
	TCHAR Name[MAX_NAME];
	TCHAR File[MAX_PATH];
} SkinListData;

HBITMAP hPreviewBitmap = NULL;
HTREEITEM AddItemToTree( HWND hTree, TCHAR * folder, TCHAR * itemName, void * data );
HTREEITEM AddSkinToListFullName( HWND hwndDlg, TCHAR * fullName );
HTREEITEM AddSkinToList( HWND hwndDlg, TCHAR * path, TCHAR* file );
HTREEITEM FillAvailableSkinList( HWND hwndDlg );

INT_PTR CALLBACK DlgSkinOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);

int SkinOptInit(WPARAM wParam, LPARAM lParam)
{
	if ( !g_CluiData.fDisableSkinEngine) {
		//Tabbed settings
		OPTIONSDIALOGPAGE odp = { sizeof(odp) };
		odp.position = -200000000;
		odp.hInstance = g_hInst;
		odp.pfnDlgProc = DlgSkinOpts;
		odp.pszTemplate = MAKEINTRESOURCEA( IDD_OPT_SKIN );
		odp.ptszGroup = LPGENT("Skins");
		odp.ptszTitle = LPGENT("Contact List");
		odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR;
		odp.ptszTab = LPGENT("Load/Save");
		Options_AddPage(wParam, &odp);

		if ( db_get_b( NULL, "ModernData", "EnableSkinEditor", SETTING_ENABLESKINEDITOR_DEFAULT )) {
			odp.pfnDlgProc = DlgSkinEditorOpts;
			odp.pszTemplate = MAKEINTRESOURCEA( IDD_OPT_SKINEDITOR );
			odp.ptszTab = LPGENT("Object Editor");
			Options_AddPage(wParam, &odp);
		}
	}
	return 0;
}

int ModernSkinOptInit(WPARAM wParam, LPARAM lParam)
{
	MODERNOPTOBJECT obj = {0};
	obj.cbSize = sizeof(obj);
	obj.dwFlags = MODEROPT_FLG_TCHAR;
	obj.hIcon = LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
	obj.hInstance = g_hInst;
	obj.iSection = MODERNOPT_PAGE_SKINS;
	obj.iType = MODERNOPT_TYPE_SELECTORPAGE;
	obj.lptzSubsection = _T("Contact List");
	obj.lpzThemeExtension = ".msf";
	obj.lpzThemeModuleName = "ModernSkinSel";
	CallService(MS_MODERNOPT_ADDOBJECT, wParam, (LPARAM)&obj);
	return 0;
}
INT_PTR CALLBACK DlgSkinOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch ( msg )
	{
	case WM_DESTROY:
		{
			if ( hPreviewBitmap ) ske_UnloadGlyphImage( hPreviewBitmap );
			break;
		}

	case WM_INITDIALOG:
		{
			TranslateDialogDefault( hwndDlg );
			HTREEITEM it = FillAvailableSkinList( hwndDlg );
			HWND wnd = GetDlgItem( hwndDlg, IDC_TREE1 );
			TreeView_SelectItem( wnd, it );
		}
		return 0;
	case WM_COMMAND:
		{
			int isLoad = 0;
			switch ( LOWORD(wParam )) {
			case IDC_COLOUR_MENUNORMAL:
			case IDC_COLOUR_MENUSELECTED:
			case IDC_COLOUR_FRAMES:
			case IDC_COLOUR_STATUSBAR:
				SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
				break;

			case IDC_BUTTON_INFO:
				{
					TCHAR Author[255], URL[MAX_PATH], Contact[255], Description[400], text[2000];
					SkinListData *sd = NULL;
					HTREEITEM hti = TreeView_GetSelection( GetDlgItem( hwndDlg, IDC_TREE1 ));
					if ( hti == 0 ) return 0;
					{
						TVITEM tvi = {0};
						tvi.hItem = hti;
						tvi.mask = TVIF_HANDLE|TVIF_PARAM;
						TreeView_GetItem( GetDlgItem( hwndDlg, IDC_TREE1 ), &tvi );
						sd = ( SkinListData* )( tvi.lParam);
					}
					if ( !sd ) return 0;
					if ( sd->File && !_tcschr( sd->File, _T('%')))
					{
						GetPrivateProfileString( _T("Skin_Description_Section"), _T("Author"), 	TranslateT("( unknown )"), 	Author, 		SIZEOF( Author ), 		sd->File );
						GetPrivateProfileString( _T("Skin_Description_Section"), _T("URL"), 		_T(""), 						URL, 		SIZEOF( URL ), 		sd->File );
						GetPrivateProfileString( _T("Skin_Description_Section"), _T("Contact"), 	_T(""), 						Contact, 	SIZEOF( Contact ), 	sd->File );
						GetPrivateProfileString( _T("Skin_Description_Section"), _T("Description"), _T(""), 					Description, SIZEOF( Description ), sd->File );
						mir_sntprintf(text, SIZEOF(text), TranslateT("%s\n\n%s\n\nAuthor(s):\t %s\nContact:\t %s\nWeb:\t %s\n\nFile:\t %s"),
							sd->Name, Description, Author, Contact, URL, sd->File);
					}
					else
					{
						mir_sntprintf(text, SIZEOF(text), TranslateT("%s\n\n%s\n\nAuthor(s): %s\nContact:\t %s\nWeb:\t %s\n\nFile:\t %s"),
							TranslateT("reVista for Modern v0.5"),
							TranslateT("This is second default Modern Contact list skin in Vista Aero style"),
							TranslateT("Angeli-Ka (graphics), FYR (template)"),
							_T("JID: fyr@jabber.ru"),
							_T("fyr.mirandaim.ru"),
							TranslateT("Inside library"));
					}
					MessageBox( hwndDlg, text, TranslateT("Skin Information"), MB_OK|MB_ICONINFORMATION );
				}
				break;
			case IDC_BUTTON_APPLY_SKIN:
				if ( HIWORD(wParam ) == BN_CLICKED )
				{
					SkinListData *sd = NULL;
					HTREEITEM hti = TreeView_GetSelection( GetDlgItem( hwndDlg, IDC_TREE1 ));
					if ( hti == 0 ) return 0;
					{
						TVITEM tvi = {0};
						tvi.hItem = hti;
						tvi.mask = TVIF_HANDLE|TVIF_PARAM;
						TreeView_GetItem( GetDlgItem( hwndDlg, IDC_TREE1 ), &tvi );
						sd = ( SkinListData* )( tvi.lParam);
					}
					if ( !sd ) return 0;
					if ( glSkinWasModified>0 )
					{
						int res = 0;
						if ( glSkinWasModified == 1 )
							res = MessageBox( hwndDlg, TranslateT("Skin editor contains not stored changes.\n\nAll changes will be lost.\n\n Continue to load new skin?"), TranslateT("Warning!"), MB_OKCANCEL|MB_ICONWARNING|MB_DEFBUTTON2|MB_TOPMOST );
						else
							res = MessageBox( hwndDlg, TranslateT("Current skin was not saved to file.\n\nAll changes will be lost.\n\n Continue to load new skin?"), TranslateT("Warning!"), MB_OKCANCEL|MB_ICONWARNING|MB_DEFBUTTON2|MB_TOPMOST );
						if ( res != IDOK ) return 0;
					}
					ske_LoadSkinFromIniFile( sd->File, FALSE );
					ske_LoadSkinFromDB();
					glOtherSkinWasLoaded = TRUE;
					pcli->pfnClcBroadcast( INTM_RELOADOPTIONS, 0, 0 );
					Sync( CLUIFrames_OnClistResize_mod, 0, 0 );
					ske_RedrawCompleteWindow( );
					Sync( CLUIFrames_OnClistResize_mod, 0, 0 );
					{
						HWND hwnd = pcli->hwndContactList;
						RECT rc = {0};
						GetWindowRect( hwnd, &rc );
						Sync( CLUIFrames_OnMoving, hwnd, &rc );
					}
					if ( g_hCLUIOptionsWnd )
					{
						SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_LEFTMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "LeftClientMargin", SETTING_LEFTCLIENTMARIGN_DEFAULT ));
						SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_RIGHTMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "RightClientMargin", SETTING_RIGHTCLIENTMARIGN_DEFAULT ));
						SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_TOPMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "TopClientMargin", SETTING_TOPCLIENTMARIGN_DEFAULT ));
						SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_BOTTOMMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "BottomClientMargin", SETTING_BOTTOMCLIENTMARIGN_DEFAULT ));
					}
				}
				break;
			case IDC_BUTTON_RESCAN:
				if (HIWORD(wParam ) == BN_CLICKED)
				{
					HTREEITEM it = FillAvailableSkinList(hwndDlg);
					HWND wnd = GetDlgItem(hwndDlg, IDC_TREE1);
					TreeView_SelectItem(wnd, it);
				}
			}
			break;
		}
	case WM_DRAWITEM:
		if ( wParam == IDC_PREVIEW )
		{
			//TODO:Draw hPreviewBitmap here
			int mWidth, mHeight;
			HBRUSH hbr = CreateSolidBrush( GetSysColor( COLOR_3DFACE ));
			DRAWITEMSTRUCT *dis = ( DRAWITEMSTRUCT * )lParam;
			mWidth = dis->rcItem.right-dis->rcItem.left;
			mHeight = dis->rcItem.bottom-dis->rcItem.top;
			HDC memDC = CreateCompatibleDC( dis->hDC );
			HBITMAP hbmp = ske_CreateDIB32( mWidth, mHeight );
			HBITMAP holdbmp = ( HBITMAP )SelectObject( memDC, hbmp );
			RECT workRect = dis->rcItem;
			OffsetRect( &workRect, -workRect.left, -workRect.top );
			FillRect( memDC, &workRect, hbr );
			DeleteObject( hbr );
			if ( hPreviewBitmap )
			{
				//variables
				BITMAP bmp = {0};
				POINT imgPos = {0};
				float xScale = 1, yScale = 1;
				//GetSize
				GetObject( hPreviewBitmap, sizeof( BITMAP ), &bmp );
				int wWidth = workRect.right-workRect.left;
				int wHeight = workRect.bottom-workRect.top;
				if ( wWidth < bmp.bmWidth ) xScale = ( float )wWidth/bmp.bmWidth;
				if ( wHeight < bmp.bmHeight ) yScale = ( float )wHeight/bmp.bmHeight;
				xScale = min( xScale, yScale );
				yScale = xScale;
				int dWidth = ( int )( xScale*bmp.bmWidth );
				int dHeight = ( int )( yScale*bmp.bmHeight );
				//CalcPosition
				imgPos.x = workRect.left+(( wWidth-dWidth )>>1 );
				imgPos.y = workRect.top+(( wHeight-dHeight )>>1 );
				//DrawImage
				DrawAvatarImageWithGDIp( memDC, imgPos.x, imgPos.y, dWidth, dHeight, hPreviewBitmap, 0, 0, bmp.bmWidth, bmp.bmHeight, 8, 255 );
			}
			BitBlt( dis->hDC, dis->rcItem.left, dis->rcItem.top, mWidth, mHeight, memDC, 0, 0, SRCCOPY );
			SelectObject( memDC, holdbmp );
			DeleteObject( hbmp );
			DeleteDC( memDC );
		}
		break;

	case WM_NOTIFY:
		switch (( ( LPNMHDR )lParam)->idFrom ) {
		case IDC_TREE1:
			{
				NMTREEVIEW * nmtv = ( NMTREEVIEW * ) lParam;
				if (nmtv == NULL)
					return 0;

				if (nmtv->hdr.code == TVN_SELCHANGEDA || nmtv->hdr.code == TVN_SELCHANGEDW) {
					SkinListData * sd = NULL;
					if (hPreviewBitmap) {
						ske_UnloadGlyphImage( hPreviewBitmap );
						hPreviewBitmap = NULL;
					}

					if (nmtv->itemNew.lParam) {
						sd = ( SkinListData* )nmtv->itemNew.lParam;

						TCHAR buf[MAX_PATH];
						PathToRelativeT(sd->File, buf);
						SetDlgItemText(hwndDlg,IDC_EDIT_SKIN_FILENAME,buf);

						TCHAR prfn[MAX_PATH] = {0}, imfn[MAX_PATH] = {0}, skinfolder[MAX_PATH] = {0};
						GetPrivateProfileString( _T("Skin_Description_Section"), _T("Preview"), _T(""), imfn, SIZEOF( imfn ), sd->File );
						IniParser::GetSkinFolder( sd->File, skinfolder );
						mir_sntprintf(prfn, SIZEOF(prfn), _T("%s\\%s"), skinfolder, imfn);
						PathToAbsoluteT(prfn, imfn);
						hPreviewBitmap = ske_LoadGlyphImage(imfn);

						EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_APPLY_SKIN ), TRUE );
						EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_INFO ), TRUE );
						if ( hPreviewBitmap )
							InvalidateRect( GetDlgItem( hwndDlg, IDC_PREVIEW ), NULL, TRUE );
						else { //prepare text
							TCHAR Author[255], URL[MAX_PATH], Contact[255], Description[400], text[2000];
							SkinListData* sd = NULL;
							HTREEITEM hti = TreeView_GetSelection( GetDlgItem( hwndDlg, IDC_TREE1 ));
							if ( hti == 0 ) return 0;
							{
								TVITEM tvi = {0};
								tvi.hItem = hti;
								tvi.mask = TVIF_HANDLE|TVIF_PARAM;
								TreeView_GetItem( GetDlgItem( hwndDlg, IDC_TREE1 ), &tvi );
								sd = ( SkinListData* )( tvi.lParam);
							}
							if ( !sd ) return 0;

							if ( sd->File && !_tcschr( sd->File, _T('%')))
							{
								GetPrivateProfileString( _T("Skin_Description_Section"), _T("Author"), 	TranslateT("( unknown )"), 	Author, 		SIZEOF( Author ), 		sd->File );
								GetPrivateProfileString( _T("Skin_Description_Section"), _T("URL"), 		_T(""), 						URL, 		SIZEOF( URL ), 		sd->File );
								GetPrivateProfileString( _T("Skin_Description_Section"), _T("Contact"), 	_T(""), 						Contact, 	SIZEOF( Contact ), 	sd->File );
								GetPrivateProfileString( _T("Skin_Description_Section"), _T("Description"), _T(""), 					Description, SIZEOF( Description ), sd->File );
								mir_sntprintf(text, SIZEOF(text), TranslateT("Preview is not available\n\n%s\n----------------------\n\n%s\n\nAUTHOR(S):\n%s\n\nCONTACT:\n%s\n\nHOMEPAGE:\n%s"),
									sd->Name, Description, Author, Contact, URL);
							}
							else
							{
								mir_sntprintf(text, SIZEOF(text), TranslateT("%s\n\n%s\n\nAUTHORS:\n%s\n\nCONTACT:\n%s\n\nWEB:\n%s\n\n\n"),
									TranslateT("reVista for Modern v0.5"),
									TranslateT("This is second default Modern Contact list skin in Vista Aero style"),
									TranslateT("graphics by Angeli-Ka\ntemplate by FYR"),
									_T("JID: fyr@jabber.ru"),
									_T("fyr.mirandaim.ru"));
							}
							ShowWindow( GetDlgItem( hwndDlg, IDC_PREVIEW ), SW_HIDE );
							ShowWindow( GetDlgItem( hwndDlg, IDC_STATIC_INFO ), SW_SHOW );
							SetDlgItemText(hwndDlg, IDC_STATIC_INFO, text);
						}
					}
					else {
						//no selected
						SetDlgItemText(hwndDlg, IDC_EDIT_SKIN_FILENAME, TranslateT("Select skin from list"));
						EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_APPLY_SKIN ), FALSE );
						EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_INFO ), FALSE );
						SetDlgItemText(hwndDlg, IDC_STATIC_INFO, TranslateT("Please select skin to apply"));
						ShowWindow( GetDlgItem( hwndDlg, IDC_PREVIEW ), SW_HIDE );
					}
					ShowWindow( GetDlgItem( hwndDlg, IDC_PREVIEW ), hPreviewBitmap?SW_SHOW:SW_HIDE );
					return 0;
				}
				else if (nmtv->hdr.code == TVN_DELETEITEMA || nmtv->hdr.code == TVN_DELETEITEMW) {
					mir_free_and_nil( nmtv->itemOld.lParam);
					return 0;
				}
			}
			break;

		case 0:
			switch (((LPNMHDR)lParam)->code) {
			case PSN_APPLY:
				pcli->pfnClcBroadcast( INTM_RELOADOPTIONS, 0, 0 );
				NotifyEventHooks( g_CluiData.hEventBkgrChanged, 0, 0 );
				pcli->pfnClcBroadcast( INTM_INVALIDATE, 0, 0 );
				RedrawWindow( GetParent( pcli->hwndContactTree ), NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_ALLCHILDREN );
			}
			break;
		}
	}
	return 0;
}

int SearchSkinFiles( HWND hwndDlg, TCHAR * Folder )
{
	struct _tfinddata_t fd = {0};
	TCHAR mask[MAX_PATH];
	long hFile;
	mir_sntprintf(mask, SIZEOF(mask), _T("%s\\*.msf"), Folder);
	//fd.attrib = _A_SUBDIR;
	hFile = _tfindfirst( mask, &fd );
	if ( hFile != -1 )
	{
		do {
			AddSkinToList( hwndDlg, Folder, fd.name );
		}
			while ( !_tfindnext( hFile, &fd ));
		_findclose( hFile );
	}
	mir_sntprintf(mask, SIZEOF(mask), _T("%s\\*"), Folder);
	hFile = _tfindfirst( mask, &fd );
	{
		do {
			if ( fd.attrib&_A_SUBDIR && !( _tcsicmp( fd.name, _T("."))  == 0  || _tcsicmp( fd.name, _T("..")) == 0 ))
			{//Next level of subfolders
				TCHAR path[MAX_PATH];
				mir_sntprintf(path, SIZEOF(path), _T("%s\\%s"), Folder, fd.name);
				SearchSkinFiles( hwndDlg, path );
			}
		}while ( !_tfindnext( hFile, &fd ));
		_findclose( hFile );
	}
	return 0;
}

HTREEITEM FillAvailableSkinList(HWND hwndDlg)
{
	struct _finddata_t fd = {0};
	//long hFile;
	HTREEITEM res = (HTREEITEM)-1;
	int attrib;

	TreeView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_TREE1));
	AddSkinToList(hwndDlg, TranslateT("Default Skin"), _T("%Default Skin%"));
	attrib = GetFileAttributes(SkinsFolder);
	if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY))
		SearchSkinFiles(hwndDlg, SkinsFolder);
	{
		TCHAR skinfull[MAX_PATH];
		ptrT skinfile( db_get_tsa( NULL, SKIN, "SkinFile"));
		if (skinfile) {
			PathToAbsoluteT(skinfile, skinfull);
			res = AddSkinToListFullName(hwndDlg, skinfull);
		}
	}
	return res;
}
HTREEITEM AddSkinToListFullName( HWND hwndDlg, TCHAR * fullName )
{
	TCHAR path[MAX_PATH] = {0};
	TCHAR file[MAX_PATH] = {0};
	TCHAR *buf;
	_tcsncpy( path, fullName, SIZEOF( path ));
	buf = path + _tcslen( path );
	while ( buf > path )
	{
		if ( *buf == _T( '\\' ))
		{
			*buf = _T( '\0' );
			break;
		}
		buf--;
	}
	buf++;
	_tcsncpy( file, buf, SIZEOF( file ));
	return AddSkinToList( hwndDlg, path, file );
}


HTREEITEM AddSkinToList( HWND hwndDlg, TCHAR * path, TCHAR* file )
{
	SkinListData *sd = ( SkinListData * )mir_alloc( sizeof( SkinListData ));
	if ( !sd )
		return 0;

	TCHAR fullName[MAX_PATH], defskinname[MAX_PATH];
	mir_sntprintf(fullName, SIZEOF(fullName), _T("%s\\%s"), path, file);
	memmove(defskinname, file, (_tcslen( file )-4) * sizeof(TCHAR));
	defskinname[_tcslen( file )+1] = _T('\0');
	if ( !file || _tcschr( file, _T('%'))) {
		mir_sntprintf(sd->File, MAX_PATH, _T("%%Default Skin%%"));
		mir_sntprintf(sd->Name, 100, TranslateT("%Default Skin%"));
		_tcsncpy(fullName, TranslateT("Default Skin"), SIZEOF(fullName));
	}
	else {
		GetPrivateProfileString( _T("Skin_Description_Section"), _T("Name"), defskinname, sd->Name, SIZEOF( sd->Name ), fullName );
		_tcscpy(sd->File, fullName);
	}
	return AddItemToTree( GetDlgItem( hwndDlg, IDC_TREE1 ), fullName, sd->Name, sd );
}

HTREEITEM FindChild( HWND hTree, HTREEITEM Parent, TCHAR * Caption, void * data )
{
	HTREEITEM res = NULL, tmp = NULL;
	if ( Parent )
		tmp = TreeView_GetChild( hTree, Parent );
	else
		tmp = TreeView_GetRoot( hTree );

	while (tmp) {
		TVITEM tvi;
		TCHAR buf[255];
		tvi.hItem = tmp;
		tvi.mask = TVIF_TEXT|TVIF_HANDLE;
		tvi.pszText = (LPTSTR)&buf;
		tvi.cchTextMax = 254;
		TreeView_GetItem( hTree, &tvi );
		if ( _tcsicmp(Caption, tvi.pszText) == 0) {
			if (!data)
				return tmp;

			TVITEM tvi = {0};
			tvi.hItem = tmp;
			tvi.mask = TVIF_HANDLE|TVIF_PARAM;
			TreeView_GetItem(hTree, &tvi);
			SkinListData *sd = (SkinListData*)tvi.lParam;
			if (sd)
				if ( !_tcsicmp(sd->File, (( SkinListData* )data )->File))
					return tmp;
		}
		tmp = TreeView_GetNextSibling(hTree, tmp);
	}
	return tmp;
}

HTREEITEM AddItemToTree(HWND hTree, TCHAR *folder, TCHAR *itemName, void *data)
{
	HTREEITEM cItem = NULL;
	//Insert item node
	cItem = FindChild( hTree, 0, itemName, data );
	if (!cItem) {
		TVINSERTSTRUCT tvis = {0};
		tvis.hInsertAfter = TVI_SORT;
		tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_PARAM;
		tvis.item.pszText = itemName;
		tvis.item.lParam = (LPARAM)data;
		return TreeView_InsertItem(hTree, &tvis);
	}

	mir_free(data); //need to free otherwise memory leak
	return cItem;
}

INT_PTR SvcActiveSkin(WPARAM wParam, LPARAM lParam)
{
	ptrT skinfile( db_get_tsa(NULL, SKIN, "SkinFile"));
	if (skinfile) {
		TCHAR skinfull[MAX_PATH];
		PathToAbsoluteT(skinfile, skinfull);
		return (INT_PTR)mir_tstrdup(skinfull);
	}

	return NULL;
}

INT_PTR SvcApplySkin(WPARAM wParam, LPARAM lParam)
{
	ske_LoadSkinFromIniFile((TCHAR *)lParam, FALSE);
	ske_LoadSkinFromDB( );
	glOtherSkinWasLoaded = TRUE;
	pcli->pfnClcBroadcast( INTM_RELOADOPTIONS, 0, 0 );
	Sync( CLUIFrames_OnClistResize_mod, 0, 0 );
	ske_RedrawCompleteWindow( );
	Sync( CLUIFrames_OnClistResize_mod, 0, 0 );

	HWND hwnd = pcli->hwndContactList;
	RECT rc = {0};
	GetWindowRect( hwnd, &rc );
	Sync( CLUIFrames_OnMoving, hwnd, &rc );

	if (g_hCLUIOptionsWnd) {
		SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_LEFTMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "LeftClientMargin", SETTING_LEFTCLIENTMARIGN_DEFAULT ));
		SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_RIGHTMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "RightClientMargin", SETTING_RIGHTCLIENTMARIGN_DEFAULT ));
		SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_TOPMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "TopClientMargin", SETTING_TOPCLIENTMARIGN_DEFAULT ));
		SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_BOTTOMMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "BottomClientMargin", SETTING_BOTTOMCLIENTMARIGN_DEFAULT ));
	}
	return 0;
}

INT_PTR SvcPreviewSkin(WPARAM wParam, LPARAM lParam)
{
	DRAWITEMSTRUCT *dis = ( DRAWITEMSTRUCT * )wParam;
	int mWidth = dis->rcItem.right-dis->rcItem.left;
	int mHeight = dis->rcItem.bottom-dis->rcItem.top;
	RECT workRect = dis->rcItem;
	OffsetRect( &workRect, -workRect.left, -workRect.top );

	if (lParam) {
		TCHAR prfn[MAX_PATH] = {0};
		TCHAR imfn[MAX_PATH] = {0};
		TCHAR skinfolder[MAX_PATH] = {0};
		GetPrivateProfileString( _T("Skin_Description_Section"), _T("Preview"), _T(""), imfn, SIZEOF( imfn ), (LPCTSTR)lParam);
		IniParser::GetSkinFolder((LPCTSTR)lParam, skinfolder );
		mir_sntprintf(prfn, SIZEOF(prfn), _T("%s\\%s"), skinfolder, imfn);
		PathToAbsoluteT(prfn, imfn);

		hPreviewBitmap = ske_LoadGlyphImage(imfn);
		if (hPreviewBitmap) {
			//variables
			BITMAP bmp = {0};
			POINT imgPos = {0};
			int wWidth, wHeight;
			int dWidth, dHeight;
			float xScale = 1, yScale = 1;
			//GetSize
			GetObject( hPreviewBitmap, sizeof( BITMAP ), &bmp );
			wWidth = workRect.right-workRect.left;
			wHeight = workRect.bottom-workRect.top;
			if ( wWidth < bmp.bmWidth ) xScale = ( float )wWidth/bmp.bmWidth;
			if ( wHeight < bmp.bmHeight ) yScale = ( float )wHeight/bmp.bmHeight;
			xScale = min( xScale, yScale );
			yScale = xScale;
			dWidth = ( int )( xScale*bmp.bmWidth );
			dHeight = ( int )( yScale*bmp.bmHeight );
			//CalcPosition
			imgPos.x = workRect.left+(( wWidth-dWidth )>>1 );
			imgPos.y = workRect.top+(( wHeight-dHeight )>>1 );
			//DrawImage
			DrawAvatarImageWithGDIp( dis->hDC, imgPos.x, imgPos.y, dWidth, dHeight, hPreviewBitmap, 0, 0, bmp.bmWidth, bmp.bmHeight, 8, 255 );
			ske_UnloadGlyphImage(hPreviewBitmap);
		}
	}

	return 0;
}