/*

'AutoShutdown'-Plugin for Miranda IM

Copyright 2004-2007 H. Herkenrath

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 (Shutdown-License.txt); if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "common.h"

/* Show Frame */
extern HINSTANCE hInst;
static HWND hwndCountdownFrame;
static WORD hFrame;
/* Misc */
static HANDLE hHookModulesLoaded;

/************************* Helpers ************************************/

#define FRAMEELEMENT_BAR     1
#define FRAMEELEMENT_BKGRND  2
#define FRAMEELEMENT_TEXT    3
static COLORREF GetDefaultColor(BYTE id) 
{ 
	switch(id) { 
		case FRAMEELEMENT_BAR:
			return RGB(250,0,0); /* same color as used on header icon */
		case FRAMEELEMENT_BKGRND:
			return (COLORREF)DBGetContactSettingDword(NULL,"CLC","BkColour",CLCDEFAULT_BKCOLOUR);
		case FRAMEELEMENT_TEXT:
			return GetSysColor(COLOR_WINDOWTEXT);
	}
	return 0; /* never happens */
}

static LOGFONT* GetDefaultFont(LOGFONT *lf) 
{ 
	NONCLIENTMETRICS ncm;
	ZeroMemory(&ncm,sizeof(ncm));
	ncm.cbSize=sizeof(ncm);
	if(SystemParametersInfo(SPI_GETNONCLIENTMETRICS,ncm.cbSize,&ncm,0)) {
		*lf=ncm.lfStatusFont;
		return lf;
	}
	return (LOGFONT*)NULL;
} 

static HICON SetFrameTitleIcon(WORD hFrame,HICON hNewIcon)
{
	HICON hPrevIcon;
	hPrevIcon=(HICON)CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS,MAKEWPARAM(FO_ICON,hFrame),0);
	CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS,MAKEWPARAM(FO_ICON,hFrame),(LPARAM)hNewIcon);
	if((int)hPrevIcon==-1) return (HICON)NULL;
	return hPrevIcon;
}

static LRESULT CALLBACK ProgressBarSubclassProc(HWND hwndProgress,UINT msg,WPARAM wParam,LPARAM lParam) 
{ 
	switch(msg) {
		case WM_ERASEBKGND:
			return TRUE;
		case WM_LBUTTONDOWN:
		case WM_LBUTTONDBLCLK:
			return SendMessage(GetParent(hwndProgress),msg,wParam,lParam);
	}
	return CallWindowProc((WNDPROC)GetWindowLongPtr(hwndProgress, GWLP_USERDATA), hwndProgress, msg, wParam, lParam); 
} 

/************************* Window Class *******************************/

#define COUNTDOWNFRAME_CLASS  _T("AutoShutdownCountdown")

/* Data */
struct CountdownFrameWndData {  /* sizeof=57, max cbClsExtra=40 on Win32 */
	time_t countdown,settingLastTime;
	HANDLE hHookColorsChanged,hHookFontsChanged,hHookIconsChanged;
	HWND hwndIcon,hwndProgress,hwndDesc,hwndTime,hwndToolTip;
	HBRUSH hbrBackground;
	COLORREF clrBackground,clrText;
	HFONT hFont;
	WORD fTimeFlags;
	BYTE flags;
};

/* Flags */
#define FWPDF_PAUSED            0x01
#define FWPDF_PAUSEDSHOWN       0x02
#define FWPDF_COUNTDOWNINVALID  0x04
#define FWPDF_TIMEISCLIPPED     0x08

/* Menu Items */
#define MENUITEM_STOPCOUNTDOWN   1
#define MENUITEM_PAUSECOUNTDOWN  2

/* Messages */
#define M_REFRESH_COLORS    (WM_USER+0)
#define M_REFRESH_ICONS     (WM_USER+1)
#define M_REFRESH_FONTS     (WM_USER+2)
#define M_SET_COUNTDOWN     (WM_USER+3)
#define M_UPDATE_COUNTDOWN  (WM_USER+4)
#define M_CHECK_CLIPPED     (WM_USER+5)
#define M_CLOSE_COUNTDOWN   (WM_USER+6)
#define M_PAUSE_COUNTDOWN   (WM_USER+7)

static LRESULT CALLBACK FrameWndProc(HWND hwndFrame,UINT msg,WPARAM wParam,LPARAM lParam)
{
	struct CountdownFrameWndData *dat=(struct CountdownFrameWndData*)GetWindowLongPtr(hwndFrame, GWLP_USERDATA);
	
	switch(msg) {
		case WM_NCCREATE:  /* init window data */
			dat=(struct CountdownFrameWndData*)mir_calloc(sizeof(*dat));
			SetWindowLongPtr(hwndFrame, GWLP_USERDATA, (LONG)dat);
			if(dat==NULL) return FALSE; /* creation failed */
			dat->fTimeFlags=*(WORD*)((CREATESTRUCT*)lParam)->lpCreateParams;
			dat->flags=FWPDF_COUNTDOWNINVALID;
			break;
		case WM_CREATE:  /*  create childs */
		{	CREATESTRUCT *params=(CREATESTRUCT*)lParam;
			dat->hwndIcon=CreateWindowEx(WS_EX_NOPARENTNOTIFY,
					_T("Static"),
					NULL,
					WS_CHILD|WS_VISIBLE|SS_ICON|SS_CENTERIMAGE|SS_NOTIFY,
					3, 0,
					GetSystemMetrics(SM_CXICON),
					GetSystemMetrics(SM_CYICON),
					hwndFrame,
					NULL,
					params->hInstance, 
					NULL);
			dat->hwndProgress=CreateWindowEx(WS_EX_NOPARENTNOTIFY,
					PROGRESS_CLASS,
					(dat->fTimeFlags&SDWTF_ST_TIME)?TranslateT("Shutdown at:"):TranslateT("Time left:"),
					WS_CHILD|WS_VISIBLE|PBS_SMOOTH,
					GetSystemMetrics(SM_CXICON)+5,
					5, 90,
					(GetSystemMetrics(SM_CXICON)/2)-5,
					hwndFrame,
					NULL,
					params->hInstance, 
					NULL);
			if(dat->hwndProgress==NULL) return -1; /* creation failed, calls WM_DESTROY */
			SendMessage(dat->hwndProgress,PBM_SETSTEP,(WPARAM)1,0);
			SetWindowLongPtr(dat->hwndProgress, GWLP_USERDATA, SetWindowLongPtr(dat->hwndProgress, GWLP_WNDPROC, (LONG)ProgressBarSubclassProc));
			dat->hwndDesc=CreateWindowEx(WS_EX_NOPARENTNOTIFY,
					_T("Static"),
					(dat->fTimeFlags&SDWTF_ST_TIME)?TranslateT("Shutdown at:"):TranslateT("Time left:"),
					WS_CHILD|WS_VISIBLE|SS_LEFTNOWORDWRAP|SS_NOTIFY,
					GetSystemMetrics(SM_CXICON)+5,
					(GetSystemMetrics(SM_CXICON)/2),
					75,
					(GetSystemMetrics(SM_CXICON)/2),
					hwndFrame,
					NULL,
					params->hInstance, 
					NULL);
			dat->hwndTime=CreateWindowEx(WS_EX_NOPARENTNOTIFY,
					_T("Static"),
					NULL, /* hh:mm:ss */
					WS_CHILD|WS_VISIBLE|SS_RIGHT|SS_NOTIFY|SS_ENDELLIPSIS,
					(GetSystemMetrics(SM_CXICON)+80),
					(GetSystemMetrics(SM_CXICON)/2),
					35,
					(GetSystemMetrics(SM_CXICON)/2),
					hwndFrame,
					NULL,
					params->hInstance, 
					NULL);
			if(dat->hwndTime==NULL) return -1; /* creation failed, calls WM_DESTROY */
			/* create tooltips */
			if(IsWinVer98Plus() || IsWinVer2000Plus()) {
				TTTOOLINFO ti;
				dat->hwndToolTip=CreateWindowEx(WS_EX_TOPMOST,
						TOOLTIPS_CLASS,
						NULL,
						WS_POPUP|TTS_ALWAYSTIP|TTS_NOPREFIX,		
						CW_USEDEFAULT, CW_USEDEFAULT,
						CW_USEDEFAULT, CW_USEDEFAULT,
						hwndFrame,
						NULL,
						params->hInstance,
						NULL);
				if(dat->hwndToolTip!=NULL) {
					SetWindowPos(dat->hwndToolTip,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
					ZeroMemory(&ti,sizeof(ti));
					ti.cbSize=sizeof(ti);
					ti.hwnd=hwndFrame;
					ti.uFlags=TTF_IDISHWND|TTF_SUBCLASS|TTF_TRANSPARENT;
					ti.lpszText=LPSTR_TEXTCALLBACK; /* commctl 4.70+ */
					ti.uId=(UINT)dat->hwndTime; /* in-place tooltip */
					SendMessage(dat->hwndToolTip,TTM_ADDTOOL,0,(LPARAM)&ti);
					ti.uFlags&=~TTF_TRANSPARENT;
					ti.uId=(UINT)dat->hwndProgress;
					SendMessage(dat->hwndToolTip,TTM_ADDTOOL,0,(LPARAM)&ti);
					if(dat->hwndDesc!=NULL) {
						ti.uId=(UINT)dat->hwndDesc;
						SendMessage(dat->hwndToolTip,TTM_ADDTOOL,0,(LPARAM)&ti);
					}
					if(dat->hwndIcon!=NULL) {
						ti.uId=(UINT)dat->hwndIcon;
						SendMessage(dat->hwndToolTip,TTM_ADDTOOL,0,(LPARAM)&ti);
					}
				}
			}
			/* init layout */
			dat->hHookColorsChanged=HookEventMessage(ME_COLOUR_RELOAD,hwndFrame,M_REFRESH_COLORS);
			dat->hHookFontsChanged=HookEventMessage(ME_FONT_RELOAD,hwndFrame,M_REFRESH_FONTS);
			dat->hHookIconsChanged=HookEventMessage(ME_SKIN2_ICONSCHANGED,hwndFrame,M_REFRESH_ICONS);
			SendMessage(hwndFrame,M_REFRESH_COLORS,0,0);
			SendMessage(hwndFrame,M_REFRESH_FONTS,0,0);
			SendMessage(hwndFrame,M_REFRESH_ICONS,0,0);
			SendMessage(hwndFrame,M_SET_COUNTDOWN,0,0);
			SendMessage(hwndFrame,M_UPDATE_COUNTDOWN,0,0);
			if(!SetTimer(hwndFrame,1,1000,NULL)) return -1; /* creation failed, calls WM_DESTROY */
			return 0;
		}
		case WM_DESTROY:
		{	HICON hIcon;
			if(dat==NULL) return 0;
			UnhookEvent(dat->hHookColorsChanged);
			UnhookEvent(dat->hHookFontsChanged);
			UnhookEvent(dat->hHookIconsChanged);
			/* other childs are destroyed automatically */
			if(dat->hwndToolTip!=NULL) DestroyWindow(dat->hwndToolTip); 
			hIcon=(HICON)SendMessage(dat->hwndIcon,STM_SETIMAGE,IMAGE_ICON,(LPARAM)NULL);
			IcoLib_ReleaseIcon(hIcon); /* does NULL check */
			break;
		}
		case WM_NCDESTROY:
			if(dat==NULL) return 0;
			if(dat->hFont!=NULL) DeleteObject(dat->hFont);
			if(dat->hbrBackground!=NULL) DeleteObject(dat->hbrBackground);
			mir_free(dat);
			SetWindowLongPtr(hwndFrame, GWLP_USERDATA, (LONG)NULL);
			break; 
		case WM_SIZE:
		{	RECT rc;
			LONG width,height;
			HDWP hdwp;
			UINT defflg=SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOACTIVATE;
			SetRect(&rc,0,0,LOWORD(lParam),HIWORD(lParam)); /* width,height */
			/* workaround: reduce flickering of frame in clist */
			InvalidateRect(hwndFrame,&rc,FALSE);
			hdwp=BeginDeferWindowPos(3);
			/* progress */
			width=rc.right-GetSystemMetrics(SM_CXICON)-10;
			height=rc.bottom-(GetSystemMetrics(SM_CYICON)/2)-5;
			hdwp=DeferWindowPos(hdwp,dat->hwndProgress,NULL,0,0,width,height,SWP_NOMOVE|defflg);
			/* desc */
			if(dat->hwndDesc!=NULL) hdwp=DeferWindowPos(hdwp,dat->hwndDesc,NULL,GetSystemMetrics(SM_CXICON)+5,5+height,0,0,SWP_NOSIZE|defflg);
			/* time */
			hdwp=DeferWindowPos(hdwp,dat->hwndTime,NULL,GetSystemMetrics(SM_CXICON)+85,5+height,width-80,(GetSystemMetrics(SM_CXICON)/2),defflg);
			EndDeferWindowPos(hdwp);
			PostMessage(hwndFrame,M_CHECK_CLIPPED,0,0);
			return 0;
		}
		case M_REFRESH_COLORS:
		{	COLORREF clrBar;
			if(FontService_GetColor(TranslateT("Automatic Shutdown"),TranslateT("Progress Bar"),&clrBar))
				clrBar=GetDefaultColor(FRAMEELEMENT_BAR);
			if(FontService_GetColor(TranslateT("Automatic Shutdown"),TranslateT("Background"),&dat->clrBackground))
				dat->clrBackground=GetDefaultColor(FRAMEELEMENT_BKGRND);
			if(dat->hbrBackground!=NULL) DeleteObject(dat->hbrBackground); 
			dat->hbrBackground=CreateSolidBrush(dat->clrBackground);
			SendMessage(dat->hwndProgress,PBM_SETBARCOLOR,0,(LPARAM)clrBar);
			SendMessage(dat->hwndProgress,PBM_SETBKCOLOR,0,(LPARAM)dat->clrBackground);
			InvalidateRect(hwndFrame,NULL,TRUE);
			return 0;
		}
		case M_REFRESH_ICONS:
			if(dat->hwndIcon!=NULL)
				IcoLib_ReleaseIcon((HICON)SendMessage(dat->hwndIcon,STM_SETIMAGE,IMAGE_ICON,(LPARAM)IcoLib_GetIcon("AutoShutdown_Header")));
			if(hFrame) /* refresh frame title icon */
				IcoLib_ReleaseIcon(SetFrameTitleIcon(hFrame,IcoLib_GetIcon("AutoShutdown_Active")));
			return 0;
		case M_REFRESH_FONTS:
		{	LOGFONT lf;
			if(!FontService_GetFont(TranslateT("Automatic Shutdown"),TranslateT("Countdown on Frame"),&dat->clrText,&lf)) {
				if(dat->hFont!=NULL) DeleteObject(dat->hFont);
				dat->hFont=CreateFontIndirect(&lf);
			}
			else {
				dat->clrText=GetDefaultColor(FRAMEELEMENT_TEXT);
				if(GetDefaultFont(&lf)!=NULL) {
					if(dat->hFont!=NULL) DeleteObject(dat->hFont);
					dat->hFont=CreateFontIndirect(&lf);
				}
			}
			if(dat->hwndDesc!=NULL)
				SendMessage(dat->hwndDesc,WM_SETFONT,(WPARAM)dat->hFont,FALSE);
			SendMessage(dat->hwndTime,WM_SETFONT,(WPARAM)dat->hFont,FALSE);
			InvalidateRect(hwndFrame,NULL,FALSE);
			return 0;
		}
		case WM_SYSCOLORCHANGE:
			SendMessage(hwndFrame,M_REFRESH_COLORS,0,0);
			break;
		case WM_SETTINGCHANGE: /* colors depend on windows settings */
			SendMessage(hwndFrame,M_REFRESH_COLORS,0,0);
			SendMessage(hwndFrame,M_REFRESH_FONTS,0,0);
			SendMessage(hwndFrame,M_UPDATE_COUNTDOWN,0,0);
			RedrawWindow(hwndFrame,NULL,NULL,RDW_INVALIDATE|RDW_ALLCHILDREN|RDW_ERASE);
			break;
		case WM_TIMECHANGE: /* windows system clock changed */
			SendMessage(hwndFrame,M_SET_COUNTDOWN,0,0);
			PostMessage(hwndFrame,M_UPDATE_COUNTDOWN,0,0);
			break;
		case WM_CTLCOLORDLG:
		case WM_CTLCOLORSTATIC:
			SetTextColor((HDC)wParam,dat->clrText);
			SetBkColor((HDC)wParam,dat->clrBackground);
			return (BOOL)dat->hbrBackground;
		case WM_ERASEBKGND:
		{	RECT rc;
			if(dat->hbrBackground!=NULL && GetClientRect(hwndFrame,&rc)) {
				FillRect((HDC)wParam,&rc,dat->hbrBackground);
				return TRUE;
			}
			return FALSE;
		}
		case M_SET_COUNTDOWN:
			if(dat->fTimeFlags&SDWTF_ST_TIME) {
				dat->settingLastTime=(time_t)DBGetContactSettingDword(NULL,"AutoShutdown","TimeStamp",SETTING_TIMESTAMP_DEFAULT);
				dat->countdown=time(NULL);
				if(dat->settingLastTime>dat->countdown) dat->countdown=dat->settingLastTime-dat->countdown;
				else dat->countdown=0;
			}
			else if(dat->flags&FWPDF_COUNTDOWNINVALID) {
				dat->countdown=(time_t)DBGetContactSettingDword(NULL,"AutoShutdown","Countdown",SETTING_COUNTDOWN_DEFAULT);
				dat->countdown*=(time_t)DBGetContactSettingDword(NULL,"AutoShutdown","CountdownUnit",SETTING_COUNTDOWNUNIT_DEFAULT);
			}
			dat->flags&=~FWPDF_COUNTDOWNINVALID;
			/* commctl 4.70+, Win95: 1-100 will work fine (wrap around) */
			SendMessage(dat->hwndProgress,PBM_SETRANGE32,(WPARAM)0,(LPARAM)dat->countdown);
			return 0;
		case WM_TIMER:
			if(dat==NULL) return 0;
			if(dat->countdown!=0 && !(dat->flags&FWPDF_COUNTDOWNINVALID) && !(dat->flags&FWPDF_PAUSED)) {
				dat->countdown--;
				PostMessage(dat->hwndProgress,PBM_STEPIT,0,0);
			}
			if(IsWindowVisible(hwndFrame)) PostMessage(hwndFrame,M_UPDATE_COUNTDOWN,0,0);
			if(dat->countdown==0) {
				SendMessage(hwndFrame,M_CLOSE_COUNTDOWN,0,0);
				ServiceShutdown(0,TRUE);
				ServiceStopWatcher(0,0);
			}
			return 0;
		case WM_SHOWWINDOW:
			/* the text is kept unchanged while hidden */
			if((BOOL)wParam) SendMessage(hwndFrame,M_UPDATE_COUNTDOWN,0,0);
			break;
		case M_UPDATE_COUNTDOWN:
			if(dat->flags&FWPDF_PAUSED && !(dat->flags&FWPDF_PAUSEDSHOWN)) {
				SetWindowText(dat->hwndTime,TranslateT("Paused"));
				dat->flags|=FWPDF_PAUSEDSHOWN;
			}
			else {
				TCHAR szOutput[256];
				if(dat->fTimeFlags&SDWTF_ST_TIME)
					GetFormatedDateTime(szOutput,SIZEOF(szOutput),dat->settingLastTime,TRUE);
				else GetFormatedCountdown(szOutput,SIZEOF(szOutput),dat->countdown);
				SetWindowText(dat->hwndTime,szOutput);
				PostMessage(hwndFrame,M_CHECK_CLIPPED,0,0);
				/* update tooltip text (if shown) */
				if(dat->hwndToolTip!=NULL && !(dat->flags&FWPDF_PAUSED)) {
					TTTOOLINFO ti;
					ti.cbSize=sizeof(ti);
					if(SendMessage(dat->hwndToolTip,TTM_GETCURRENTTOOL,0,(LPARAM)&ti) && (HWND)ti.uId!=dat->hwndIcon)
						SendMessage(dat->hwndToolTip,TTM_UPDATE,0,0);
				} else dat->flags&=~FWPDF_PAUSEDSHOWN;
			}
			return 0;
		case M_CLOSE_COUNTDOWN:
			KillTimer(hwndFrame,1);
			dat->countdown=0;
			dat->flags&=~FWPDF_PAUSED;
			SendMessage(hwndFrame,M_UPDATE_COUNTDOWN,0,0);
			dat->flags|=FWPDF_COUNTDOWNINVALID;
			/* step up to upper range */
			SendMessage(dat->hwndProgress,PBM_SETPOS,SendMessage(dat->hwndProgress,PBM_GETRANGE,FALSE,0),0);
			SetWindowLongPtr(dat->hwndProgress, GWL_STYLE, GetWindowLongPtr(dat->hwndProgress, GWL_STYLE) | PBM_SETMARQUEE);
			SendMessage(dat->hwndProgress,PBM_SETMARQUEE,TRUE,10); /* marquee for rest of time */
			return 0;
		case M_PAUSE_COUNTDOWN:
			if(dat->flags&FWPDF_PAUSED) {
				/* unpause */
				dat->flags&=~(FWPDF_PAUSED|FWPDF_PAUSEDSHOWN);
				SendMessage(hwndFrame,M_SET_COUNTDOWN,0,0);
				SendMessage(dat->hwndProgress,PBM_SETSTATE,PBST_NORMAL,0); /* WinVista+ */
			}
			else {
				/* pause */
				dat->flags|=FWPDF_PAUSED;
				SendMessage(dat->hwndProgress,PBM_SETSTATE,PBST_PAUSED,0); /* WinVista+ */
			}
			SendMessage(hwndFrame,M_UPDATE_COUNTDOWN,0,0);
			return 0;
		case WM_CONTEXTMENU:
		{	HMENU hContextMenu;
			POINT pt;
			if(dat->flags&FWPDF_COUNTDOWNINVALID) return 0;
			POINTSTOPOINT(pt,MAKEPOINTS(lParam));
			if(pt.x==-1 && pt.y==-1) { /* invoked by keyboard */
				RECT rc;
				/* position in middle above rect */
				if(!GetWindowRect(hwndFrame, &rc)) return 0;
				pt.x=rc.left+((int)(rc.right-rc.left)/2); 
				pt.y=rc.top+((int)(rc.bottom-rc.top)/2);
			}
			hContextMenu=CreatePopupMenu();
			if(hContextMenu!=NULL) {
				AppendMenu(hContextMenu,MF_STRING,MENUITEM_PAUSECOUNTDOWN,(dat->flags&FWPDF_PAUSED)?TranslateT("&Unpause Countdown"):TranslateT("&Pause Countdown"));
				SetMenuDefaultItem(hContextMenu,MENUITEM_PAUSECOUNTDOWN,FALSE);
				AppendMenu(hContextMenu,MF_STRING,MENUITEM_STOPCOUNTDOWN,TranslateT("&Cancel Countdown"));
				TrackPopupMenuEx(hContextMenu,TPM_LEFTALIGN|TPM_TOPALIGN|TPM_HORPOSANIMATION|TPM_VERPOSANIMATION|TPM_RIGHTBUTTON,pt.x,pt.y,hwndFrame,NULL);
				DestroyMenu(hContextMenu);
			}
			return 0;
		}
		case WM_LBUTTONDBLCLK:
			if(!(dat->flags&FWPDF_COUNTDOWNINVALID))
				SendMessage(hwndFrame,M_PAUSE_COUNTDOWN,0,0);
			return 0;
		case WM_COMMAND:
			switch(LOWORD(wParam)) {
				case MENUITEM_STOPCOUNTDOWN:
					/* close only countdown window when other watcher types running */
					if(dat->fTimeFlags&~(SDWTF_SPECIFICTIME|SDWTF_ST_MASK))
						CloseCountdownFrame(); /* something else is running */
					else ServiceStopWatcher(0,0); /* calls CloseCountdownFrame() */
					return 0;
				case MENUITEM_PAUSECOUNTDOWN:
					SendMessage(hwndFrame,M_PAUSE_COUNTDOWN,0,0);
					return 0;
			}
			break;
		case M_CHECK_CLIPPED: /* for in-place tooltip on dat->hwndTime */
		{	RECT rc;
			HDC hdc;
			SIZE size;
			HFONT hFontPrev=NULL;
			TCHAR szOutput[256];
			dat->flags&=~FWPDF_TIMEISCLIPPED;
			if(GetWindowText(dat->hwndTime,szOutput,SIZEOF(szOutput)-1))
				if(GetClientRect(dat->hwndTime,&rc)) {
					hdc=GetDC(dat->hwndTime);
					if(hdc!=NULL) {
						if(dat->hFont!=NULL)
							hFontPrev = (HFONT)SelectObject(hdc,dat->hFont);
						if(GetTextExtentPoint32(hdc,szOutput,lstrlen(szOutput),&size))
							if(size.cx>=(rc.right-rc.left))
								dat->flags&=FWPDF_TIMEISCLIPPED;
						if(dat->hFont!=NULL)
							SelectObject(hdc,hFontPrev);
						ReleaseDC(dat->hwndTime,hdc);
					}
				}
			return 0;
		}
		case WM_NOTIFY:
			if(((NMHDR*)lParam)->hwndFrom==dat->hwndToolTip)
				switch(((NMHDR*)lParam)->code) {
					case TTN_SHOW: /* 'in-place' tooltip on dat->hwndTime */
						if(dat->flags&FWPDF_TIMEISCLIPPED && (HWND)wParam==dat->hwndTime && IsWinVer2000Plus()) {
							RECT rc;
							if(GetWindowRect(dat->hwndTime,&rc)) {
								SetWindowLongPtr(dat->hwndToolTip, GWL_STYLE, GetWindowLongPtr(dat->hwndToolTip, GWL_STYLE) | TTS_NOANIMATE);
								SetWindowLongPtr(dat->hwndToolTip, GWL_EXSTYLE, GetWindowLongPtr(dat->hwndToolTip, GWL_EXSTYLE) | WS_EX_TRANSPARENT);
								SendMessage(dat->hwndToolTip,TTM_ADJUSTRECT,TRUE,(LPARAM)&rc);
								SetWindowPos(dat->hwndToolTip,NULL,rc.left,rc.top,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
								return TRUE; /* self-defined position */
							}
						}
						SetWindowLongPtr(dat->hwndToolTip, GWL_STYLE, GetWindowLongPtr(dat->hwndToolTip, GWL_STYLE) & (~TTS_NOANIMATE));
						SetWindowLongPtr(dat->hwndToolTip, GWL_EXSTYLE, GetWindowLongPtr(dat->hwndToolTip, GWL_EXSTYLE) & (~WS_EX_TRANSPARENT));
						return 0;
					case TTN_POP:
						/* workaround #5: frame does not get redrawn after
						 * in-place tooltip	hidden on dat->hwndTime */
						RedrawWindow(hwndCountdownFrame,NULL,NULL,RDW_INVALIDATE|RDW_ALLCHILDREN|RDW_ERASE);
						return 0;
					case TTN_NEEDTEXT:
					{	NMTTDISPINFO *ttdi=(NMTTDISPINFO*)lParam;
						if(dat->flags&FWPDF_TIMEISCLIPPED && (HWND)wParam==dat->hwndTime) {
							if(GetWindowText(dat->hwndTime,ttdi->szText,SIZEOF(ttdi->szText)-1))
								ttdi->lpszText=ttdi->szText;
						}
						else if((HWND)wParam==dat->hwndIcon)
							ttdi->lpszText=TranslateT("Automatic Shutdown");
						else {
							TCHAR szTime[SIZEOF(ttdi->szText)];
							if(dat->fTimeFlags&SDWTF_ST_TIME)
								GetFormatedDateTime(szTime,SIZEOF(szTime),dat->settingLastTime,FALSE);
							else GetFormatedCountdown(szTime,SIZEOF(szTime),dat->countdown);
							mir_sntprintf(ttdi->szText,SIZEOF(ttdi->szText),_T("%s %s"),(dat->fTimeFlags&SDWTF_ST_TIME)?TranslateT("Shutdown at:"):TranslateT("Time left:"),szTime);
							ttdi->lpszText=ttdi->szText;
						}
						return 0;
					}
				}
			break;
	}
	return DefWindowProc(hwndFrame,msg,wParam,lParam); 
}

/************************* Show Frame *********************************/

void ShowCountdownFrame(WORD fTimeFlags)
{
	hwndCountdownFrame=CreateWindowEx(WS_EX_CONTROLPARENT|WS_EX_NOPARENTNOTIFY|WS_EX_TRANSPARENT,
	                                  COUNTDOWNFRAME_CLASS,
	                                  NULL,
	                                  WS_CHILD|WS_TABSTOP,
	                                  0, 0,
	                                  GetSystemMetrics(SM_CXICON)+103,
	                                  GetSystemMetrics(SM_CYICON)+2,
	                                  (HWND)CallService(MS_CLUI_GETHWND,0,0),
	                                  NULL,
	                                  hInst,
	                                  &fTimeFlags);
	if(hwndCountdownFrame==NULL) return;

	if(ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) {
		CLISTFrame clf;
		ZeroMemory(&clf,sizeof(clf));
		clf.cbSize=sizeof(clf);
		clf.hIcon=IcoLib_GetIcon("AutoShutdown_Active"); /* CListFrames does not make a copy */
		clf.align=alBottom;
		clf.height=GetSystemMetrics(SM_CYICON);
		clf.Flags=F_VISIBLE|F_SHOWTBTIP|F_NOBORDER|F_SKINNED;
		clf.name=Translate("AutoShutdown");
		clf.TBname=Translate("Automatic Shutdown");
		clf.hWnd=hwndCountdownFrame;
		hFrame=(WORD)CallService(MS_CLIST_FRAMES_ADDFRAME,(WPARAM)&clf,0);
		if(hFrame) {
			ShowWindow(hwndCountdownFrame,SW_SHOW);
			CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS,MAKEWPARAM(FO_TBTIPNAME,hFrame),(LPARAM)clf.name);
			/* HACKS TO FIX CLUI FRAMES:
			 * *** why is CLUIFrames is horribly buggy??! *** date: sept 2005, nothing changed until sept 2006
			 * workaround #1: MS_CLIST_FRAMES_REMOVEFRAME does not finish with destroy cycle (clist_modern, clist_nicer crashes) */
			SendMessage((HWND)CallService(MS_CLUI_GETHWND,0,0),WM_SIZE,0,0);
			/* workaround #2: drawing glitch after adding a frame (frame positioned wrongly when hidden) */
			CallService(MS_CLIST_FRAMES_UPDATEFRAME,hFrame,FU_FMPOS|FU_FMREDRAW);
			/* workaround #3: MS_CLIST_FRAMES_SETFRAMEOPTIONS does cause redrawing problems */
			if(!(CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS,MAKEWPARAM(FO_FLAGS,hFrame),0)&F_VISIBLE))
				CallService(MS_CLIST_FRAMES_SHFRAME,hFrame,0);
			/* workaround #4: MS_CLIST_FRAMES_SHFRAME does cause redrawing problems when frame was hidden */
			RedrawWindow(hwndCountdownFrame,NULL,NULL,RDW_INVALIDATE|RDW_ALLCHILDREN|RDW_ERASE);
			/* workaround #5: for in-place tooltip TTN_POP
			 * workaround #6 and #7: see CloseCountdownFrame() */
		}
	}
}

void CloseCountdownFrame(void)
{
	if(hwndCountdownFrame!=NULL) {
		SendMessage(hwndCountdownFrame,M_CLOSE_COUNTDOWN,0,0);
		if(hFrame) {
			IcoLib_ReleaseIcon(SetFrameTitleIcon(hFrame,NULL));
			/* HACKS TO FIX CLUIFrames:
			 * workaround #6: MS_CLIST_FRAMES_REMOVEFRAME does not finish with
			 * destroy cycle (clist_modern, clist_nicer crashes) */
			CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS,MAKEWPARAM(FO_FLAGS,hFrame),(LPARAM)CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS,MAKEWPARAM(FO_FLAGS,hFrame),0)&(~F_VISIBLE));
			#if !defined(_DEBUG)
				/* workaround #7: MS_CLIST_FRAMES_REMOVEFRAME crashes after two calls
				 * clist_nicer crashes after some calls (bug in it) */
				CallService(MS_CLIST_FRAMES_REMOVEFRAME,hFrame,0);
			#endif
		}
		else DestroyWindow(hwndCountdownFrame);
		hwndCountdownFrame=NULL;
		hFrame=0;
	}

}

/************************* Misc ***************************************/

static int FrameModulesLoaded(WPARAM wParam,LPARAM lParam)
{
	if(ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) {
		LOGFONT lf;
		COLORREF clr;
		HMODULE hUxThemeDLL;
		BOOL (WINAPI *pfnIsThemeActive)(VOID);
		/* built-in font module is not available before this hook */
		clr=GetDefaultColor(FRAMEELEMENT_TEXT);
		FontService_RegisterFont("AutoShutdown","CountdownFont",TranslateT("Automatic Shutdown"),TranslateT("Countdown on Frame"),0,FALSE,GetDefaultFont(&lf),clr);
		clr=GetDefaultColor(FRAMEELEMENT_BKGRND);
		FontService_RegisterColor("AutoShutdown","BkgColor",TranslateT("Automatic Shutdown"),TranslateT("Background"),clr);
		/* progressbar color can only be changed in windows classic theme */
		/* FIXME: should be registered/unregistered on WM_THEMECHANGED/ME_OPT_INITIALISE msg,
		 * currently not possible as no such font service exists */
		hUxThemeDLL=LoadLibraryA("UXTHEME"); /* all ascii */
		*(PROC*)&pfnIsThemeActive=(hUxThemeDLL!=NULL)?GetProcAddress(hUxThemeDLL,"IsThemeActive"):NULL;
		if(pfnIsThemeActive==NULL || !pfnIsThemeActive()) {
			/* progressbar color can only be changed with classic theme */
				clr=GetDefaultColor(FRAMEELEMENT_BAR);
			FontService_RegisterColor("AutoShutdown","ProgressColor",TranslateT("Automatic Shutdown"),TranslateT("Progress Bar"),clr);
		}
		if(hUxThemeDLL!=NULL) FreeLibrary(hUxThemeDLL);
	}
	return 0;
}

int InitFrame(void)
{
	WNDCLASSEX wcx;
	ZeroMemory(&wcx,sizeof(wcx));
	wcx.cbSize        =sizeof(wcx);
	wcx.style         =CS_DBLCLKS|CS_PARENTDC;
	wcx.lpfnWndProc   =FrameWndProc;
	wcx.hInstance     =hInst;
	wcx.hCursor       =(HCURSOR)LoadImage(NULL,IDC_ARROW,IMAGE_CURSOR,0,0,LR_SHARED);
	wcx.lpszClassName =COUNTDOWNFRAME_CLASS;
	if(!RegisterClassEx(&wcx)) return 1;

	hwndCountdownFrame=NULL;
	hHookModulesLoaded=HookEvent(ME_SYSTEM_MODULESLOADED,FrameModulesLoaded);
	return 0;
}

void UninitFrame(void)
{
	/* frame closed by UninitWatcher() */
	UnregisterClass(COUNTDOWNFRAME_CLASS,hInst); /* fails if window still exists */
	UnhookEvent(hHookModulesLoaded);
}