/*

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

Copyright 2000-2009 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 "commonheaders.h"

struct HyperlinkWndData {
	HFONT hEnableFont,hDisableFont;
	RECT rcText;
	COLORREF enableColor, disableColor, focusColor;
	BYTE flags; /* see HLKF_* */
};

/* flags */
#define HLKF_HASENABLECOLOR   0x1 /* dat->enableColor is not system default */
#define HLKF_HASDISABLECOLOR  0x2 /* dat->disableColor is not system default */

/* internal messages */
#define HLK_MEASURETEXT  (WM_USER+1)
#define HLK_INVALIDATE   (WM_USER+2) 

static LRESULT CALLBACK HyperlinkWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
	struct HyperlinkWndData *dat=(struct HyperlinkWndData*)GetWindowLongPtr(hwnd,0);
	switch(msg) {
		case WM_NCCREATE:
			dat=(struct HyperlinkWndData*)mir_calloc(sizeof(struct HyperlinkWndData));
			if(dat==NULL) return FALSE; /* fail creation */
			SetWindowLongPtr(hwnd,0,(LONG_PTR)dat); /* always succeeds */
			/* fall thru */
		case WM_SYSCOLORCHANGE:
			if(!(dat->flags&HLKF_HASENABLECOLOR)) {
				if(GetSysColorBrush(COLOR_HOTLIGHT)==NULL) dat->enableColor=RGB(0,0,255);
				else dat->enableColor=GetSysColor(COLOR_HOTLIGHT);
				dat->focusColor = RGB(GetRValue(dat->enableColor) / 2, GetGValue(dat->enableColor) / 2, GetBValue(dat->enableColor) / 2);
			}
			if(!(dat->flags&HLKF_HASDISABLECOLOR))
				dat->disableColor=GetSysColor(COLOR_GRAYTEXT);
			break;

		case WM_SETFOCUS:
		case WM_KILLFOCUS:
			RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
			break;
		case WM_MOUSEACTIVATE:
			SetFocus(hwnd);
			return MA_ACTIVATE;
		case WM_GETDLGCODE:
		{
			if (lParam)
			{
				MSG *msg = (MSG *) lParam;
				if (msg->message == WM_KEYDOWN)
				{
					if (msg->wParam == VK_TAB)
						return 0;
					if (msg->wParam == VK_ESCAPE)
						return 0;
				} else
				if (msg->message == WM_CHAR)
				{
					if (msg->wParam == '\t')
						return 0;
					if (msg->wParam == 27)
						return 0;
				}
			}
			return DLGC_WANTMESSAGE;
		}

		case WM_KEYDOWN:
		{
			switch (wParam)
			{
			case VK_SPACE:
			case VK_RETURN:
				SendMessage(GetParent(hwnd),WM_COMMAND,MAKEWPARAM(GetDlgCtrlID(hwnd),STN_CLICKED),(LPARAM)hwnd);
				break;
			}
			return 0;
		}

		case WM_LBUTTONDOWN:
		{	POINT pt;
			POINTSTOPOINT(pt,MAKEPOINTS(lParam));
			if(!PtInRect(&dat->rcText,pt)) break;
			SendMessage(GetParent(hwnd),WM_COMMAND,MAKEWPARAM(GetDlgCtrlID(hwnd),STN_CLICKED),(LPARAM)hwnd);
			return 0;
		}
		case WM_SETFONT:
		{	LOGFONT lf;
			HFONT hFont;
			if((HFONT)wParam==NULL) { /* use default system color */
				dat->hEnableFont=dat->hDisableFont=NULL;
				return 0;
			}
			if(GetObject((HFONT)wParam,sizeof(lf),&lf)) {
				lf.lfUnderline=1;
				hFont=CreateFontIndirect(&lf);
				if(hFont!=NULL) {
					dat->hEnableFont=hFont;
					dat->hDisableFont=(HFONT)wParam;
					if(LOWORD(lParam)) SendMessage(hwnd,HLK_INVALIDATE,0,0);
					SendMessage(hwnd,HLK_MEASURETEXT,0,0);
				}
			}
			return 0;
		}
		case WM_ERASEBKGND:
			return TRUE;
		case WM_ENABLE:
		case HLK_INVALIDATE:
		{	RECT rcWnd;
			POINT pt;
			HWND hwndParent;
			if(!GetWindowRect(hwnd,&rcWnd)) break;
			pt.x=rcWnd.left;
			pt.y=rcWnd.top;
			hwndParent=GetParent(hwnd);
			if(hwndParent==NULL) hwndParent=hwnd;
			if(!ScreenToClient(hwndParent,&pt)) break;
			rcWnd.right=pt.x+(rcWnd.right-rcWnd.left);
			rcWnd.bottom=pt.y+(rcWnd.bottom-rcWnd.top);
			rcWnd.left=pt.x;
			rcWnd.top=pt.y;
			InvalidateRect(hwndParent,&rcWnd,TRUE);
			return 0;
		}
		case WM_GETFONT:
			return (LRESULT)dat->hDisableFont;
		case WM_CREATE:
		case HLK_MEASURETEXT:
		{	TCHAR szText[256];
			if(!GetWindowText(hwnd,szText,SIZEOF(szText))) return 0;
			lParam=(LPARAM)szText;
			/* fall thru */
		case WM_SETTEXT:
		{	HFONT hPrevFont = NULL;
			SIZE textSize;
			RECT rc;
			HDC hdc;
			LONG style;
			BOOL fMeasured=FALSE;
			hdc=GetDC(hwnd);
			if(hdc==NULL) return 0; /* text change failed */
			if(dat->hEnableFont!=NULL) hPrevFont=(HFONT)SelectObject(hdc,dat->hEnableFont);
			if(dat->hEnableFont==NULL || hPrevFont!=NULL) /* select failed? */
				if(GetTextExtentPoint32(hdc,(TCHAR*)lParam,lstrlen((TCHAR*)lParam),&textSize))
					if(GetClientRect(hwnd,&rc)) {
						dat->rcText.top=0;
						dat->rcText.bottom=dat->rcText.top+textSize.cy;
						style=GetWindowLongPtr(hwnd,GWL_STYLE);
						if(style&SS_CENTER) dat->rcText.left=(rc.right-textSize.cx)/2;
						else if(style&SS_RIGHT) dat->rcText.left=rc.right-textSize.cx;
						else dat->rcText.left=0;
						dat->rcText.right=dat->rcText.left+textSize.cx;
						fMeasured=TRUE;
					}
			if(dat->hEnableFont!=NULL && hPrevFont!=NULL) SelectObject(hdc,hPrevFont);
			ReleaseDC(hwnd,hdc);
			if(!fMeasured) return 0; /* text change failed */
			SendMessage(hwnd,HLK_INVALIDATE,0,0);
			break;
		}}
		case WM_SETCURSOR:
		{	POINT pt;
			HCURSOR hCursor;
			if(!GetCursorPos(&pt)) return FALSE;
			if(!ScreenToClient(hwnd,&pt)) return FALSE;
			if(PtInRect(&dat->rcText,pt)) {
				hCursor=(HCURSOR)GetClassLongPtr(hwnd,GCLP_HCURSOR);
				if(hCursor==NULL) hCursor=LoadCursor(NULL,IDC_HAND); /* Win2000+ */
			}
			else hCursor=LoadCursor(NULL,IDC_ARROW);
			SetCursor(hCursor);
			return TRUE;
		}
		case HLK_SETENABLECOLOUR:
		{	COLORREF prevColor=dat->enableColor;
			dat->enableColor=(COLORREF)wParam;
			dat->focusColor = RGB(GetRValue(dat->enableColor) / 2, GetGValue(dat->enableColor) / 2, GetBValue(dat->enableColor) / 2);
			dat->flags|=HLKF_HASENABLECOLOR;
			return (LRESULT)prevColor;
		}
		case HLK_SETDISABLECOLOUR:
		{	COLORREF prevColor=dat->disableColor;
			dat->disableColor=(COLORREF)wParam;
			dat->flags|=HLKF_HASDISABLECOLOR;
			return (LRESULT)prevColor;
		}
		case WM_NCPAINT:
			return 0;
		case WM_PAINT:
		{	HFONT hPrevFont;
			RECT rc;
			TCHAR szText[256];
			UINT alignFlag;
			COLORREF textColor;
			PAINTSTRUCT ps;
			HDC hdc;
			
			hdc=BeginPaint(hwnd,&ps);
			if(hdc!=NULL) {
				if(IsWindowEnabled(hwnd)) {
					hPrevFont=(HFONT)SelectObject(hdc,dat->hEnableFont);
					textColor = (GetFocus() == hwnd) ? dat->focusColor : dat->enableColor;
				} else {
					hPrevFont=(HFONT)SelectObject(hdc,dat->hDisableFont);
					textColor=dat->disableColor;
				}
				if(GetClientRect(hwnd,&rc) && GetWindowText(hwnd,szText,SIZEOF(szText))) {
					if (drawThemeParentBackground && IsWinVerXPPlus())
					{
						BOOL fSmoothing;
						UINT fSmoothingType;
						SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fSmoothing, 0);
						SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &fSmoothingType, 0);
						if (fSmoothing && fSmoothingType == FE_FONTSMOOTHINGCLEARTYPE)
							drawThemeParentBackground(hwnd, hdc, &rc);
					}
					SetBkMode(hdc,TRANSPARENT);
					SetTextColor(hdc,textColor);
					alignFlag=(GetWindowLongPtr(hwnd,GWL_STYLE)&(SS_CENTER|SS_RIGHT|SS_LEFT));
					DrawText(hdc,szText,-1,&rc,alignFlag|DT_NOPREFIX|DT_SINGLELINE|DT_TOP);
				}
				if(hPrevFont!=NULL) SelectObject(hdc,hPrevFont);
				EndPaint(hwnd,&ps);
			}
			return 0;
		}
		case WM_NCDESTROY:			
			if(dat->hEnableFont!=NULL) DeleteObject(dat->hEnableFont);
			mir_free(dat);			
			break;
	}
	return DefWindowProc(hwnd,msg,wParam,lParam);
}

int InitHyperlink(void)
{
	WNDCLASS wcl;

	wcl.lpfnWndProc=HyperlinkWndProc;
	wcl.cbClsExtra=0;
	wcl.cbWndExtra=sizeof(struct HyperlinkWndData*);
	wcl.hInstance=hMirandaInst;
	if(IsWinVer2000Plus()) wcl.hCursor=NULL;
	else wcl.hCursor=LoadCursor(wcl.hInstance,MAKEINTRESOURCE(IDC_HYPERLINKHAND));
	wcl.lpszClassName=WNDCLASS_HYPERLINK;
	wcl.hbrBackground=NULL;
	wcl.hIcon=NULL;
	wcl.lpszMenuName=NULL;
	wcl.style=CS_HREDRAW|CS_VREDRAW|CS_GLOBALCLASS|CS_PARENTDC;
	RegisterClass(&wcl);  /* automatically unregistered on exit */
	return 0;
}
