//=======================================================================
//
//  Copyright (c) 1998-1999 Microsoft Corporation.  All Rights Reserved.
//
//  File:   Link.h
//
//  Owner:  a-josem
//
//  Description:
//
//      Static control subclassing Class used to display links.
//
//
//=======================================================================


#pragma once
#include <stdlib.h>
#include <malloc.h>

#include "windowsx.h"
#include "tchar.h"
#include "htmlhelp.h"
#include <shellapi.h>
#include <safefunc.h>
#include "mistsafe.h"

const TCHAR strObjPtr[]  = TEXT("strSysLinkObjPtr");

const struct
{
	enum { cxWidth = 32, cyHeight = 32 };
	int xHotSpot;
	int yHotSpot;
	unsigned char arrANDPlane[cxWidth * cyHeight / 8];
	unsigned char arrXORPlane[cxWidth * cyHeight / 8];
} _Link_CursorData = 
{
	5, 0, 
	{
		0xF9, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 
		0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 
		0xF0, 0x00, 0xFF, 0xFF, 0x10, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 
		0x80, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x7F, 0xFF, 
		0xE0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 
		0xF8, 0x01, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
	},
	{
		0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 
		0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x06, 0xD8, 0x00, 0x00, 
		0x06, 0xDA, 0x00, 0x00, 0x06, 0xDB, 0x00, 0x00, 0x67, 0xFB, 0x00, 0x00, 0x77, 0xFF, 0x00, 0x00, 
		0x37, 0xFF, 0x00, 0x00, 0x17, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x00, 
		0x0F, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 
		0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	}
};

class CSysLink
{
public:
	CSysLink(BOOL fIsHtmlHelp= TRUE):/*bInit(FALSE),*/m_OrigWndProc(NULL),m_lpstrLabel(NULL), m_lpstrHyperLink(NULL),m_hWnd(NULL),
			m_hCursor(NULL), m_hFont(NULL), /* m_bPaintLabel(true),*/ m_clrLink(RGB(0, 0, 255)), m_PaintedFocusRect(false), m_IsHtmlHelp(fIsHtmlHelp)
	{
		SetRectEmpty(&m_rcLink);
	}

	~CSysLink()
	{
#if 0		
		free(m_lpstrLabel);
		free(m_lpstrHyperLink);
		if(m_hFont != NULL)
			::DeleteObject(m_hFont);
		if(m_hCursor != NULL)
			::DestroyCursor(m_hCursor);
#endif		
	}

	void Uninit()
	{
		SafeFreeNULL(m_lpstrLabel);
		SafeFreeNULL(m_lpstrHyperLink);
		if(m_hFont != NULL)
		{
			::DeleteObject(m_hFont);
			m_hFont = NULL;
		}
		if(m_hCursor != NULL)
		{
			::DestroyCursor(m_hCursor);
			m_hCursor = NULL;
		}
	}

	void Init()
	{	
		LONG ctrlstyle = GetWindowLong(m_hWnd,GWL_STYLE);
		ctrlstyle |= SS_NOTIFY;
		SetWindowLongPtr(m_hWnd,GWL_STYLE,ctrlstyle);

		HWND wnd = GetParent(m_hWnd);
		HFONT hFont = (HFONT)SendMessage(wnd,WM_GETFONT,0,0);
/*		if(m_bPaintLabel) */
		{
			if(hFont != NULL)
			{
				LOGFONT lf;
				GetObject(hFont, sizeof(LOGFONT), &lf);
				lf.lfUnderline = TRUE;
				m_hFont = CreateFontIndirect(&lf);
			}
		}

		// set label (defaults to window text)
		if(m_lpstrLabel == NULL)
		{
			int nLen = GetWindowTextLength(m_hWnd);
			if(nLen > 0)
			{
				LPTSTR lpszText = (LPTSTR)malloc((nLen+1)*sizeof(TCHAR));
				if(NULL != lpszText && GetWindowText(m_hWnd,lpszText, nLen+1))
					SetLabel(lpszText);
				SafeFree(lpszText);
			}
		}

		// set hyperlink (defaults to label)
		if(m_lpstrHyperLink == NULL && m_lpstrLabel != NULL)
			SetHyperLink(m_lpstrLabel);

		CalcLabelRect();
	}

	void SubClassWindow(HWND hWnd)
	{
		if (SetProp(hWnd, strObjPtr, (HANDLE)this))
		{
//			bInit = TRUE;
			m_hWnd = hWnd;
			m_OrigWndProc = (WNDPROC) SetWindowLongPtr(hWnd,GWLP_WNDPROC,(LONG_PTR)CSysLink::_SysLinkWndProc);
		}
		Init();
	}

	static INT_PTR CALLBACK _SysLinkWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		CSysLink *pThis = (CSysLink *)GetProp(hwnd, strObjPtr);

//		if (NULL != pThis)
//		{
			switch(uMsg)
			{
				HANDLE_MSG(hwnd, WM_ERASEBKGND,	pThis->_OnEraseBkgnd);
				HANDLE_MSG(hwnd, WM_PAINT, pThis->_OnPaint);
				HANDLE_MSG(hwnd, WM_SETFOCUS, pThis->_OnFocus);
				HANDLE_MSG(hwnd, WM_KILLFOCUS, pThis->_OnFocus);
				HANDLE_MSG(hwnd, WM_MOUSEMOVE, pThis->_OnMouseMove);
				HANDLE_MSG(hwnd, WM_LBUTTONDOWN, pThis->_OnLButtonDown);
				HANDLE_MSG(hwnd, WM_LBUTTONUP, pThis->_OnLButtonUp);
				HANDLE_MSG(hwnd, WM_CHAR, pThis->_OnChar);
				HANDLE_MSG(hwnd, WM_GETDLGCODE,  pThis->_OnGetDlgCode);
				HANDLE_MSG(hwnd, WM_SETCURSOR,  pThis->_OnSetCursor);
			}
//		}
		return CallWindowProc(pThis->m_OrigWndProc, hwnd,uMsg,wParam,lParam);
	}

	BOOL Invalidate(BOOL bErase = TRUE)
	{
		return InvalidateRect(m_hWnd, NULL, bErase);
	}

	BOOL Navigate()
	{
		if (m_IsHtmlHelp == TRUE)
			HtmlHelp(NULL,m_lpstrHyperLink,HH_DISPLAY_TOPIC,NULL);
		else
		{
			ShellExecute(0, _T("open"), m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL);
		}
		return TRUE;
	}

	void SetSysLinkInstanceHandle(HINSTANCE hInstance)
	{
		m_hInstance = hInstance;
		m_hCursor = ::CreateCursor(hInstance, _Link_CursorData.xHotSpot, _Link_CursorData.yHotSpot, _Link_CursorData.cxWidth, _Link_CursorData.cyHeight, _Link_CursorData.arrANDPlane, _Link_CursorData.arrXORPlane);
	}

public: //Message Handlers
	BOOL _OnSetCursor(HWND hwnd, HWND hwndCursor, UINT codeHitTest, UINT msg)
	{
		POINT pt;
		GetCursorPos(&pt);
		ScreenToClient(m_hWnd,&pt);
		if(m_lpstrHyperLink != NULL && ::PtInRect(&m_rcLink, pt))
		{
			return TRUE;
		}
		return (BOOL)CallWindowProc(m_OrigWndProc, hwnd,WM_SETCURSOR,(WPARAM)hwndCursor,MAKELPARAM(codeHitTest,msg));
	}

	UINT _OnGetDlgCode(HWND hwnd, LPMSG lpmsg)
	{
		return DLGC_WANTCHARS;
	}

	void _OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
	{
		POINT pt = { x, y};
		if(m_lpstrHyperLink != NULL && PtInRect(&m_rcLink, pt))
			SetCursor(m_hCursor);
	}

	void _OnFocus(HWND hwnd, HWND hwndOldFocus)
	{
		Invalidate();
	}

	void _OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
	{
		POINT pt = { x, y };
		if(PtInRect(&m_rcLink, pt))
		{
			SetFocus(m_hWnd);
			SetCapture(m_hWnd);
		}
	}

	void _OnPaint(HWND hwnd)
	{
		PAINTSTRUCT ps;
		HDC hDC = BeginPaint(hwnd, &ps);
		m_hWnd = hwnd;
		DoPaint(hDC);
		EndPaint(hwnd, &ps);
	}

	void _OnChar(HWND hwnd, TCHAR ch, int cRepeat)
	{
		if(ch == VK_RETURN || ch == VK_SPACE)
			Navigate();
	}

	BOOL _OnEraseBkgnd(HWND hwnd, HDC hdc)
	{
/*		if(m_bPaintLabel)*/
		{
			HBRUSH hBrush = (HBRUSH)::SendMessage(GetParent(hwnd), WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)m_hWnd);
			if(hBrush != NULL)
			{
				RECT rect;
				GetClientRect(m_hWnd, &rect);
				FillRect(hdc, &rect, hBrush);
			}
		}
		return 1;
	}

	void _OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
	{
		if(GetCapture() == m_hWnd)
		{
			ReleaseCapture();
			POINT pt = { x, y };
			if(PtInRect(&m_rcLink, pt))
				Navigate();
		}
	}

	void DoPaint(HDC hDC)
	{
		if (m_PaintedFocusRect)
		{
			m_PaintedFocusRect = false;
			DrawFocusRect(hDC, &m_rcLink);
		}

		SetBkMode(hDC, TRANSPARENT);
		SetTextColor(hDC, m_clrLink);
		if(m_hFont != NULL)
			SelectFont(hDC, m_hFont);

		LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;

		LONG_PTR dwStyle = GetWindowLongPtr(m_hWnd,GWL_STYLE);

		int nDrawStyle = DT_LEFT;
		if (dwStyle & SS_CENTER)
			nDrawStyle = DT_CENTER;
		else if (dwStyle & SS_RIGHT)
			nDrawStyle = DT_RIGHT;

		DrawText(hDC, lpstrText, -1, &m_rcLink, nDrawStyle | DT_WORDBREAK);

		if((GetFocus() == m_hWnd)&&(!m_PaintedFocusRect))
		{
			m_PaintedFocusRect = true;
			DrawFocusRect(hDC, &m_rcLink);
		}
	}

	bool CalcLabelRect()
	{
		if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL)
			return false;

		HDC hDC = GetDC(m_hWnd);

		RECT rect;
		GetClientRect(m_hWnd, &rect);
		m_rcLink = rect;

		HFONT hOldFont = NULL;
		if(m_hFont != NULL)
			hOldFont = SelectFont(hDC, m_hFont);
		LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;

		DWORD dwStyle = (DWORD)GetWindowLongPtr(m_hWnd,GWL_STYLE);
		int nDrawStyle = DT_LEFT;
		if (dwStyle & SS_CENTER)
			nDrawStyle = DT_CENTER;
		else if (dwStyle & SS_RIGHT)
			nDrawStyle = DT_RIGHT;
		DrawText(hDC, lpstrText, -1, &m_rcLink, nDrawStyle | DT_WORDBREAK | DT_CALCRECT);
		if(m_hFont != NULL)
			SelectFont(hDC, hOldFont);
		return true;
	}

	bool SetLabel(LPCTSTR lpstrLabel)
	{
		free(m_lpstrLabel);
		m_lpstrLabel = NULL;
		int ilen = lstrlen(lpstrLabel) + 1;
		m_lpstrLabel = (LPTSTR)malloc(ilen * sizeof(TCHAR));
		if(m_lpstrLabel == NULL)
			return false;
		//lstrcpy(m_lpstrLabel, lpstrLabel);
		if (FAILED(StringCchCopyEx(m_lpstrLabel, ilen, lpstrLabel, NULL, NULL, MISTSAFE_STRING_FLAGS)))
		{
			free(m_lpstrLabel);
			m_lpstrLabel = NULL;
			return false;
		}
		CalcLabelRect();
		return true;
	}

#if 0
	bool GetLabel(LPTSTR lpstrBuffer, int nLength)
	{
		if (NULL != m_lpstrLabel &&
			nLength > lstrlen(m_lpstrLabel) &&
			SUCCEEDED(StringCchCopyEx(lpstrBuffer, nLength, m_lpstrLabel, NULL, NULL, MISTSAFE_STRING_FLAGS)))
		{
			return true;
		}
		return false;
	}
#endif

	bool SetHyperLink(LPCTSTR lpstrLink)
	{
		free(m_lpstrHyperLink);
		m_lpstrHyperLink = NULL;
		int ilen = lstrlen(lpstrLink) + 1;
		m_lpstrHyperLink = (LPTSTR)malloc(ilen * sizeof(TCHAR));
		if(m_lpstrHyperLink == NULL)
			return false;
		if (FAILED(StringCchCopyEx(m_lpstrHyperLink, ilen, lpstrLink, NULL, NULL, MISTSAFE_STRING_FLAGS)))
		{
			free(m_lpstrHyperLink);
			m_lpstrHyperLink = NULL;
			return false;
		}
		if(m_lpstrLabel == NULL)
			CalcLabelRect();
		return true;
	}

#if 0
	bool GetHyperLink(LPTSTR lpstrBuffer, int nLength)
	{
		if (NULL != m_lpstrHyperLink &&
			nLength > lstrlen(m_lpstrHyperLink) &&
			SUCCEEDED(StringCchCopyEx(lpstrBuffer, nLength, m_lpstrHyperLink, NULL, NULL, MISTSAFE_STRING_FLAGS)))
		{
			return true;
		}
		return false;
	}
#endif

private:
//	BOOL bInit;
	BOOL m_IsHtmlHelp;
	HWND m_hWnd;
	WNDPROC m_OrigWndProc;

	LPTSTR m_lpstrLabel;
	LPTSTR m_lpstrHyperLink;
	HCURSOR m_hCursor;
//	bool m_bPaintLabel;
	HFONT m_hFont;
	RECT m_rcLink;

	bool m_PaintedFocusRect;
	COLORREF m_clrLink; //set once

	HINSTANCE m_hInstance;
};