/*

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 "..\..\core\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=hInst;
	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;
}