/*******************************************************\
{                                                       }
{       Microsoft Visual C++ Version 5.X                }
{       Time_Date_Edit Controls 1.0                     }
{                                                       }
{       Copyright (C) 1999, CAT Computing Center (R).   }
{                                                       }
\*******************************************************/

#define STRICT
#include <Windows.h>
#include <Windowsx.h>
#include <tchar.h>
#include <commctrl.h>
#include "Alarm.h"
#include "tdedit.h"

#define IDC_SPIN	115

LRESULT CALLBACK EditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK DTWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 
LRESULT OnNotify(HWND hWnd, UINT nID, NMHDR * pNmhdr);
void OnCommand(HWND hWnd, UINT nID, HWND hwndCtl, UINT codeNotify);

inline void GetWindowPos(HWND hParentWnd, HWND hChildWnd, LPRECT lpRect)
{
	GetWindowRect(hChildWnd, lpRect);
	ScreenToClient(hParentWnd, (LPPOINT)lpRect);
	ScreenToClient(hParentWnd, ((LPPOINT)lpRect)+1);
}

inline void SetNewEditProc(HWND hWnd)
{
	SetWindowLong(hWnd, GWL_USERDATA, (long)SetWindowLong(hWnd, GWL_WNDPROC, (LONG)EditProc));
}

BOOL InitTDEdit(HINSTANCE hDllInst)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style         = CS_HREDRAW|CS_VREDRAW;
	wcex.lpfnWndProc   = (WNDPROC)DTWinProc;
	wcex.cbClsExtra    = 0;
	wcex.cbWndExtra    = 0;
	wcex.hInstance     = hDllInst;
	wcex.hIcon         = NULL;
	wcex.hCursor       = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = NULL;
	wcex.lpszMenuName  = NULL;
	wcex.lpszClassName = _T("Time_Date_Edit");
	wcex.hIconSm = NULL;

	return RegisterClassEx(&wcex);
}

BOOL CreateEdits(HWND hWnd, long x, long y, BOOL fTime, BOOL fFull, LPTDEDATA lpTDData)
{
	if(!lpTDData)
		return FALSE;

	HDC hDC = GetDC(hWnd);
	if(!hDC)
		return FALSE;
	HGDIOBJ hOld = SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT));
	SIZE Size;
	GetTextExtentPoint32(hDC, _T("99"), 2, &Size);

	lpTDData->hEdit1 = CreateWindow(_T("EDIT"), NULL, ES_NUMBER|WS_CHILD|WS_VISIBLE|WS_TABSTOP, x, y, Size.cx + 2, Size.cy + 2, hWnd, (HMENU)0, g_AppData.hInstance, NULL);
	if(lpTDData->hEdit1)
	{
		SendMessage(lpTDData->hEdit1, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
		SendMessage(lpTDData->hEdit1, EM_LIMITTEXT, 2, 0);
		SetNewEditProc(lpTDData->hEdit1);
	}
	else
	{
		return FALSE;
	}

	SetRect(&lpTDData->Rect1, x + Size.cx, y, x + Size.cx + (Size.cx >> 1), Size.cy);
	
	lpTDData->hEdit2 = CreateWindow(_T("EDIT"), NULL, ES_NUMBER|WS_CHILD|WS_VISIBLE|WS_TABSTOP, x + Size.cx + (Size.cx >> 1), y, Size.cx + 2, Size.cy + 2, hWnd, (HMENU)1, g_AppData.hInstance, NULL);
	if(lpTDData->hEdit2)
	{
		SendMessage(lpTDData->hEdit2, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
		SendMessage(lpTDData->hEdit2, EM_LIMITTEXT, 2, 0);
		SetNewEditProc(lpTDData->hEdit2);
	}
	else
	{
		return FALSE;
	}

	if(!(fTime && !fFull))
	{
		lpTDData->Rect2;
		CopyRect(&lpTDData->Rect2, &lpTDData->Rect1);
		OffsetRect(&lpTDData->Rect2, Size.cx + (Size.cx >> 1), 0);

		if(!fTime && fFull)
		{
			SIZE Size2;
			GetTextExtentPoint32(hDC, _T("9999"), 4, &Size2);
			lpTDData->hEdit3 = CreateWindow(_T("EDIT"), NULL, ES_NUMBER|WS_CHILD|WS_VISIBLE|WS_TABSTOP, x + 2 * (Size.cx + (Size.cx >> 1)), y, Size2.cx + 2, Size.cy + 2, hWnd, (HMENU)2, g_AppData.hInstance, NULL);
			if(lpTDData->hEdit3)
			{
				SendMessage(lpTDData->hEdit3, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
				SendMessage(lpTDData->hEdit3, EM_LIMITTEXT, 4, 0);
				SetNewEditProc(lpTDData->hEdit3);
			}
			else
			{
				return FALSE;
			}
		}
		else
		{
			lpTDData->hEdit3 = CreateWindow(_T("EDIT"), NULL, ES_NUMBER|WS_CHILD|WS_VISIBLE|WS_TABSTOP, x + 2 * (Size.cx + (Size.cx >> 1)), y, Size.cx + 2, Size.cy + 2, hWnd, (HMENU)2, g_AppData.hInstance, NULL);
			if(lpTDData->hEdit3)
			{
				SendMessage(lpTDData->hEdit3, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
				SendMessage(lpTDData->hEdit3, EM_LIMITTEXT, 2, 0);
				SetNewEditProc(lpTDData->hEdit3);
			}
			else
			{
				return FALSE;
			}
		}
	}

	SelectObject(hDC, hOld);
	ReleaseDC(hWnd, hDC);
	return TRUE;
}

BOOL CreateSpin(HWND hWnd, long x, long y, long cx, long cy, LPTDEDATA lpTDData)
{
	lpTDData->hSpin = CreateWindow(_T("msctls_updown32"), NULL, WS_CHILD|WS_VISIBLE|UDS_ARROWKEYS|/*UDS_AUTOBUDDY|UDS_SETBUDDYINT|UDS_NOTHOUSANDS|*/UDS_WRAP, x, y, cx, cy, hWnd, (HMENU)IDC_SPIN, g_AppData.hInstance, NULL);
	if(lpTDData->hSpin)
		return TRUE;
	else
		return FALSE;
}

BOOL CreateOneEdit(HWND hWnd, long x, long y, long cx, long cy, BOOL fNum, LPTDEDATA lpTDData)
{
	lpTDData->hEdit1 = CreateWindow(_T("EDIT"), NULL, (fNum ? ES_NUMBER : 0)
		|WS_CHILD|WS_VISIBLE|WS_TABSTOP, 1, 1, cx - 2, cy, hWnd, (HMENU)0, g_AppData.hInstance, NULL);
	if(lpTDData->hEdit1)
	{
		SendMessage(lpTDData->hEdit1, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
		SetNewEditProc(lpTDData->hEdit1);
		if(IsWindow(lpTDData->hSpin))
		{
			SendMessage(lpTDData->hSpin, UDM_SETBUDDY, (WPARAM)lpTDData->hEdit1, 0);
			return TRUE;
		}
	}
	return FALSE;
}

void SetExStyles(DWORD dwStyles, LPTDEDATA lpTDData)
{
	if(TDS_READONLY & dwStyles)
	{
		if(IsWindow(lpTDData->hEdit1))
			SetWindowLong(lpTDData->hEdit1, GWL_STYLE, ES_READONLY | GetWindowLong(lpTDData->hEdit1, GWL_STYLE));
		if(IsWindow(lpTDData->hEdit2))
			SetWindowLong(lpTDData->hEdit2, GWL_STYLE, ES_READONLY | GetWindowLong(lpTDData->hEdit2, GWL_STYLE));
		if(IsWindow(lpTDData->hEdit3))
			SetWindowLong(lpTDData->hEdit2, GWL_STYLE, ES_READONLY | GetWindowLong(lpTDData->hEdit2, GWL_STYLE));
	}
}


BOOL OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct)
{
	LPTDEDATA lpTDData = new TDEDATA;
	if(!lpTDData)
		return FALSE;

	if(!(TDS_HIDESPIN & lpCreateStruct->style))
	{
		if(!CreateSpin(hWnd, lpCreateStruct->cx - GetSystemMetrics(SM_CXHSCROLL) - GetSystemMetrics(SM_CXEDGE) * 2, 0, 
			lpCreateStruct->cx - GetSystemMetrics(SM_CXEDGE), lpCreateStruct->cy - 4, lpTDData))
		{
			delete lpTDData;
			return FALSE;
		}
	}

	if(TDS_DATE & lpCreateStruct->style)
	{
		if(!CreateEdits(hWnd, 2, 2, FALSE, TDS_FULL & lpCreateStruct->style, lpTDData))
		{
			delete lpTDData;
			return FALSE;
		}
	}
	else if((TDS_NUMVALUE | TDS_STRVALUE) & lpCreateStruct->style)
	{
		int cx = lpCreateStruct->cx;
		if(IsWindow(lpTDData->hSpin))
		{
			RECT Rect;
			GetWindowRect(lpTDData->hSpin, &Rect);
			cx = cx - (Rect.right - Rect.left) - 6;
		}
		if(!CreateOneEdit(hWnd, 1, 1, cx - 2, lpCreateStruct->cy, TDS_NUMVALUE & lpCreateStruct->style, lpTDData))
		{
			delete lpTDData;
			return FALSE;
		}
	}
	else
	{
		if(!CreateEdits(hWnd, 2, 2, TRUE, TDS_FULL & lpCreateStruct->style, lpTDData))
		{
			delete lpTDData;
			return FALSE;
		}
	}

//	SetExStyles(lpCreateStruct->style, lpTDData);

	SetWindowLong(hWnd, GWL_STYLE, WS_CLIPCHILDREN|lpCreateStruct->style);
	SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_CONTROLPARENT|lpCreateStruct->dwExStyle);
	SetWindowLong(hWnd, GWL_USERDATA, (long)lpTDData);

	InvalidateRect(hWnd, NULL, FALSE);
	UpdateWindow(hWnd);
	return TRUE;
}

void OnPaint(HWND hWnd)
{
	DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);
	if((TDS_NUMVALUE | TDS_STRVALUE) & dwStyle)
	{
		DefWindowProc(hWnd, WM_PAINT, 0, 0);
		return;
	}

	PAINTSTRUCT ps;
	HDC hDC = BeginPaint(hWnd, &ps);
	HGDIOBJ hObj = SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT));

	SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
	SetBkColor(hDC, GetSysColor(COLOR_WINDOW));

	LPTDEDATA lpTDData = (LPTDEDATA)GetWindowLong(hWnd, GWL_USERDATA);

	LPTSTR szSep;
	if(dwStyle & TDS_DATE)
		szSep = _T(".");
	else
		szSep = _T(":");

	DrawText(hDC, szSep, 1, &lpTDData->Rect1, DT_SINGLELINE|DT_CENTER|DT_VCENTER);
	if((dwStyle & TDS_FULL) || (dwStyle & TDS_DATE))
		DrawText(hDC, szSep, 1, &lpTDData->Rect2, DT_SINGLELINE|DT_CENTER|DT_VCENTER);

	SelectObject(hDC, hObj);
	EndPaint(hWnd, &ps);
}

BOOL OnEraseBkgnd(HWND hWnd, HDC hDC)
{
	LOGBRUSH lb;
	lb.lbStyle = BS_SOLID;
	lb.lbColor = GetSysColor(COLOR_WINDOW);
	lb.lbHatch = NULL;
	HBRUSH hBrush = CreateBrushIndirect(&lb);
	RECT Rect;
	GetClientRect(hWnd, &Rect);
	FillRect(hDC, &Rect, hBrush);
	DeleteObject(hBrush);
	return TRUE;
}

void OnDestroy(HWND hWnd)
{
	LPTDEDATA lpTDData = (LPTDEDATA)GetWindowLong(hWnd, GWL_USERDATA);
	if(lpTDData)
	{
		memset(lpTDData, 0, sizeof(tagTDEDATA));	// Do not allow call DestroyWindow
		delete lpTDData;
	}
}

BOOL OnSetData(HWND hWnd, LPSYSTEMTIME lpSt)
{
	LPTDEDATA lpTDData = (LPTDEDATA)GetWindowLong(hWnd, GWL_USERDATA);
	if(!lpTDData)
		return FALSE;
	DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);
	if((TDS_NUMVALUE | TDS_STRVALUE) & dwStyle)
		return FALSE;
	TCHAR szTemp[255] = _T("");
	if(TDS_DATE & dwStyle)
	{
		if(lpSt->wDay >= 10)
		{
			SetWindowText(lpTDData->hEdit1, _ltot(lpSt->wDay, szTemp, 10));
		}
		else
		{
			szTemp[0] = _T('0');
			SetWindowText(lpTDData->hEdit1, _ltot(lpSt->wDay, &szTemp[1], 10) - 1);
		}
		if(lpSt->wMonth >= 10)
		{
			SetWindowText(lpTDData->hEdit2, _ltot(lpSt->wMonth, szTemp, 10));
		}
		else
		{
			szTemp[0] = _T('0');
			SetWindowText(lpTDData->hEdit2, _ltot(lpSt->wMonth, &szTemp[1], 10) - 1);
		}
		if(TDS_FULL & dwStyle)
		{
			if(lpSt->wYear >= 10)
			{
				SetWindowText(lpTDData->hEdit3, _ltot(lpSt->wYear, szTemp, 10));
			}
			else
			{
				szTemp[0] = _T('0');
				SetWindowText(lpTDData->hEdit3, _ltot(lpSt->wYear, &szTemp[1], 10) - 1);
			}
		}
		else
		{
			if((lpSt->wYear % 100) >= 10)
			{
				SetWindowText(lpTDData->hEdit3, _ltot((lpSt->wYear % 100), szTemp, 10));
			}
			else
			{
				szTemp[0] = _T('0');
				SetWindowText(lpTDData->hEdit3, _ltot((lpSt->wYear % 100), &szTemp[1], 10) - 1);
			}
		}
		return TRUE;
	}
	else
	{
		if(lpSt->wHour >= 10)
		{
			SetWindowText(lpTDData->hEdit1, _ltot(lpSt->wHour, szTemp, 10));
		}
		else
		{
			szTemp[0] = _T('0');
			SetWindowText(lpTDData->hEdit1, _ltot(lpSt->wHour, &szTemp[1], 10) - 1);
		}
		if(lpSt->wMinute >= 10)
		{
			SetWindowText(lpTDData->hEdit2, _ltot(lpSt->wMinute, szTemp, 10));
		}
		else
		{
			szTemp[0] = _T('0');
			SetWindowText(lpTDData->hEdit2, _ltot(lpSt->wMinute, &szTemp[1], 10) - 1);
		}
		if(TDS_FULL & dwStyle)
		{
			if(lpSt->wSecond >= 10)
			{
				SetWindowText(lpTDData->hEdit3, _ltot(lpSt->wSecond, szTemp, 10));
			}
			else
			{
				szTemp[0] = _T('0');
				SetWindowText(lpTDData->hEdit3, _ltot(lpSt->wSecond, &szTemp[1], 10) - 1);
			}
		}
		return TRUE;
	}
	return FALSE;
}

BOOL OnGetData(HWND hWnd, LPSYSTEMTIME lpSt)
{
	LPTDEDATA lpTDData = (LPTDEDATA)GetWindowLong(hWnd, GWL_USERDATA);
	if(!lpTDData)
		return FALSE;
	memset(lpSt, 0, sizeof(SYSTEMTIME));
	DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);
	if((TDS_NUMVALUE | TDS_STRVALUE) & dwStyle)
		return FALSE;
	TCHAR szTemp[255] = _T("");
	if(TDS_DATE & dwStyle)
	{
		GetWindowText(lpTDData->hEdit1, szTemp, 255);
		lpSt->wDay = (WORD)_ttol(szTemp);
		GetWindowText(lpTDData->hEdit2, szTemp, 255);
		lpSt->wMonth = (WORD)_ttol(szTemp);
		GetWindowText(lpTDData->hEdit3, szTemp, 255);
		lpSt->wYear = (WORD)_ttol(szTemp);
		return TRUE;
	}
	else
	{
		GetWindowText(lpTDData->hEdit1, szTemp, 255);
		lpSt->wHour = (WORD)_ttol(szTemp);
		GetWindowText(lpTDData->hEdit2, szTemp, 255);
		lpSt->wMinute = (WORD)_ttol(szTemp);
		if(TDS_FULL & dwStyle)
		{
			GetWindowText(lpTDData->hEdit3, szTemp, 255);
			lpSt->wSecond = (WORD)_ttol(szTemp);
		}
		return TRUE;
	}
	return FALSE;
}

LRESULT CALLBACK DTWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
		case WM_VSCROLL:
		{
			DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);
			if((TDS_NUMVALUE | TDS_STRVALUE) & dwStyle)
			{
				return SendMessage(GetParent(hWnd), uMsg, wParam, lParam);
			}
			else
			{
				LPTDEDATA lpTDData = (LPTDEDATA)GetWindowLong(hWnd, GWL_USERDATA);
				if(!lpTDData)
					return FALSE;
				HWND hFocus = GetFocus();
				if(!((hFocus == lpTDData->hEdit1) || (hFocus == lpTDData->hEdit2) || (hFocus == lpTDData->hEdit3)))
				{
					SetFocus(lpTDData->hEdit1);
					return FALSE;
				}
				TCHAR szTemp[256];
				int nPos = (short int) HIWORD(wParam);
				if(nPos >= 10)
				{
					_ltot(nPos, szTemp, 10);
				}
				else
				{
					szTemp[0] = _T('0');
					_ltot(nPos, &szTemp[1], 10);
				}

				if(hFocus == lpTDData->hEdit1)
				{
					SetWindowText(lpTDData->hEdit1, szTemp);
				}
				else if(hFocus == lpTDData->hEdit2)
				{
					SetWindowText(lpTDData->hEdit2, szTemp);
				}
				else if(hFocus == lpTDData->hEdit3)
				{
					SetWindowText(lpTDData->hEdit3, szTemp);
				}
				break;
			}
		}

		case TDM_CHANGESTYLE:
		{
			DWORD dwStyles = GetWindowLong(hWnd, GWL_STYLE);
			dwStyles = dwStyles & ~(TDS_HIDESPIN|TDS_SMARTSIZE|TDS_READONLY|TDS_NUMVALUE|TDS_STRVALUE|TDS_TIME|TDS_DATE|TDS_FULL);
			SetWindowLong(hWnd, GWL_STYLE, wParam|dwStyles);
			RECT Rect;
			GetWindowRect(hWnd, &Rect);
			CREATESTRUCT CreateStruct;
			memset(&CreateStruct, 0, sizeof(CREATESTRUCT));
			CreateStruct.style = wParam|dwStyles|TDS_READONLY;
			CreateStruct.x = Rect.left;
			CreateStruct.y = Rect.top;
			CreateStruct.cx = Rect.right - Rect.left;
			CreateStruct.cy = Rect.bottom - Rect.top;
			CreateStruct.dwExStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
			LPTDEDATA lpTDData = (LPTDEDATA)GetWindowLong(hWnd, GWL_USERDATA);
			if(lpTDData)
				delete lpTDData;
			return OnCreate(hWnd, &CreateStruct);
		}
		
		case TDM_SETDATA:
			return OnSetData(hWnd, (LPSYSTEMTIME)wParam);

		case TDM_GETDATA:
			return OnGetData(hWnd, (LPSYSTEMTIME)wParam);

		case TDM_SETRANGE:
		{
			LPTDEDATA lpTDData = (LPTDEDATA)GetWindowLong(hWnd, GWL_USERDATA);
			if(IsWindow(lpTDData->hSpin))
				return SendMessage(lpTDData->hSpin, UDM_SETRANGE, 0, lParam);
			return FALSE;
		}
			
		case TDM_GETRANGE:
		{
			LPTDEDATA lpTDData = (LPTDEDATA)GetWindowLong(hWnd, GWL_USERDATA);
			if(IsWindow(lpTDData->hSpin))
				return SendMessage(lpTDData->hSpin, UDM_GETRANGE, 0, 0);
			return 0;
		}
		
		case TDM_SETPOS:
		{
			LPTDEDATA lpTDData = (LPTDEDATA)GetWindowLong(hWnd, GWL_USERDATA);
			if(IsWindow(lpTDData->hSpin))
				return SendMessage(lpTDData->hSpin, UDM_SETPOS, 0, lParam);
			return FALSE;
		}
			
		case TDM_GETPOS:
		{
			LPTDEDATA lpTDData = (LPTDEDATA)GetWindowLong(hWnd, GWL_USERDATA);
			if(IsWindow(lpTDData->hSpin))
				return SendMessage(lpTDData->hSpin, UDM_GETPOS, 0, 0);
			return 0;
		}

/*		case TDM_CHANGEEDIT:
		{
			CHANGEEDIT CngEdit;
			CngEdit.hdr.hwndFrom = hWnd;
			CngEdit.hdr.idFrom = GetWindowLong(hWnd, GWL_ID);
			CngEdit.hdr.code = TDN_CHANGEEDIT;
			LPTDEDATA lpTDData = (LPTDEDATA)GetWindowLong(hWnd, GWL_USERDATA);
			if(wParam == (WPARAM)lpTDData->hEdit1)
				CngEdit.iNum = 0;
			else if(wParam == (WPARAM)lpTDData->hEdit2)
				CngEdit.iNum = 1;
			else if(wParam == (WPARAM)lpTDData->hEdit3)
				CngEdit.iNum = 2;
			return SendMessage(GetParent(hWnd), WM_NOTIFY, CngEdit.hdr.idFrom, (LPARAM)&CngEdit);
		}*/

		case TDM_SETTEXT:
		{
			DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);
			if((TDS_NUMVALUE | TDS_STRVALUE) & dwStyle)
			{
				LPTDEDATA lpTDData = (LPTDEDATA)GetWindowLong(hWnd, GWL_USERDATA);
				if(IsWindow(lpTDData->hEdit1))
					return SendMessage(lpTDData->hEdit1, WM_SETTEXT, 0, lParam);
			}
			return FALSE;
		}

		case TDM_GETTEXT:
		{
			DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);
			if((TDS_NUMVALUE | TDS_STRVALUE) & dwStyle)
			{
				LPTDEDATA lpTDData = (LPTDEDATA)GetWindowLong(hWnd, GWL_USERDATA);
				if(IsWindow(lpTDData->hEdit1))
					return SendMessage(lpTDData->hEdit1, WM_GETTEXT, wParam, lParam);
			}
			return FALSE;
		}

		HANDLE_WINMSG(hWnd, WM_CREATE, OnCreate);
		HANDLE_WINMSG(hWnd, WM_PAINT, OnPaint);
		HANDLE_WINMSG(hWnd, WM_ERASEBKGND, OnEraseBkgnd);
		HANDLE_WINMSG(hWnd, WM_DESTROY, OnDestroy);
		HANDLE_WINMSG(hWnd, WM_NOTIFY, OnNotify);
		HANDLE_WINMSG(hWnd, WM_COMMAND, OnCommand);
	}

	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

long GetRange(HWND hWnd, LPTDEDATA lpTDData)
{
	DWORD dwStyle = GetWindowLong(GetParent(hWnd), GWL_STYLE);
	BOOL bTime;
	short nUpper = 0;
	short nLower = 0;
	if(TDS_DATE & dwStyle)
	{
		bTime = FALSE;
		nLower = 1;
	}
	else
	{
		bTime = TRUE;
		nLower = 0;
	}
	if(hWnd == lpTDData->hEdit1)
	{
		if(bTime)
		{
			nUpper = 23;
		}
		else
		{
			SYSTEMTIME st;
			SendMessage(GetParent(hWnd), TDM_GETDATA, (WPARAM)&st, 0);
			switch(st.wMonth)
			{
				case 2:
					nUpper = 28;
				break;
				case 4:
				case 6:
				case 9:
				case 11:
					nUpper = 30;
				break;
				default:
					nUpper = 31;
			}
		}
	}
	else if(hWnd == lpTDData->hEdit2)
	{
		if(bTime)
			nUpper = 59;
		else
			nUpper = 12;
	}
	else if(hWnd == lpTDData->hEdit3)
	{
		nLower = 0;
		if(bTime)
			nUpper = 59;
		else if(TDS_FULL & dwStyle)
			nUpper = 9999;
		else
			nUpper = 99;
	}
	return MAKELONG(nUpper, nLower);
}

long GetPos(HWND hWnd, LPTDEDATA lpTDData)
{
	SYSTEMTIME st;
	SendMessage(GetParent(hWnd), TDM_GETDATA, (WPARAM)&st, 0);
	DWORD dwStyle = GetWindowLong(GetParent(hWnd), GWL_STYLE);
	short nPos;
	BOOL bTime;
	if(TDS_DATE & dwStyle)
	{
		bTime = FALSE;
	}
	else
	{
		bTime = TRUE;
	}
	if(hWnd == lpTDData->hEdit1)
	{
		if(bTime)
			nPos = st.wHour;
		else
			nPos = st.wDay;
	}
	else if(hWnd == lpTDData->hEdit2)
	{
		if(bTime)
			nPos = st.wMinute;
		else
			nPos = st.wMonth;
	}
	else if(hWnd == lpTDData->hEdit3)
	{
		if(bTime)
			nPos = st.wSecond;
		else
			nPos = st.wYear;
	}
	return MAKELONG(nPos, 0);
}

LRESULT CALLBACK EditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)	
	{
		case WM_SETFOCUS:
		{
			DWORD dwStyle = GetWindowLong(GetParent(hWnd), GWL_STYLE);
			if(!((TDS_NUMVALUE | TDS_STRVALUE) & dwStyle))
			{
				LPTDEDATA lpTDData = (LPTDEDATA)GetWindowLong(GetParent(hWnd), GWL_USERDATA);
				if(IsWindow(lpTDData->hSpin))
				{
					SendMessage(lpTDData->hSpin, UDM_SETBUDDY, (WPARAM)hWnd, 0);
					SendMessage(lpTDData->hSpin, UDM_SETRANGE, 0, GetRange(hWnd, lpTDData));
					SendMessage(lpTDData->hSpin, UDM_SETPOS, 0, GetPos(hWnd, lpTDData));
				}
			}
			break;
		}
		case WM_KEYUP:
		{
			LPTDEDATA lpTDData = (LPTDEDATA)GetWindowLong(GetParent(hWnd), GWL_USERDATA);
			if(IsWindow(lpTDData->hSpin))
			{
				if(wParam == VK_END || wParam == VK_NEXT)
				{
					SendMessage(hWnd, WM_KEYUP, VK_UP, lParam);
					return FALSE;
				}
				else if(wParam == VK_HOME || wParam == VK_PRIOR)
				{
					SendMessage(hWnd, WM_KEYUP, VK_DOWN, lParam);
					return FALSE;
				}
			}
		}
		case WM_KEYDOWN:
		{
			LPTDEDATA lpTDData = (LPTDEDATA)GetWindowLong(GetParent(hWnd), GWL_USERDATA);
			DWORD dwStyle = GetWindowLong(GetParent(hWnd), GWL_STYLE);
			if(IsWindow(lpTDData->hSpin))
			{
				if(wParam == VK_END || wParam == VK_NEXT)
				{
					if(!((TDS_NUMVALUE | TDS_STRVALUE) & dwStyle))
						SendMessage(lpTDData->hSpin, UDM_SETPOS, 0, LOWORD(GetRange(hWnd, lpTDData)));
					else
						SendMessage(lpTDData->hSpin, UDM_SETPOS, 0, LOWORD(SendMessage(lpTDData->hSpin, UDM_GETRANGE, 0, 0)));
					SendMessage(hWnd, WM_KEYDOWN, VK_UP, lParam);
					return FALSE;
				}
				else if(wParam == VK_HOME || wParam == VK_PRIOR)
				{
					if(!((TDS_NUMVALUE | TDS_STRVALUE) & dwStyle))
						SendMessage(lpTDData->hSpin, UDM_SETPOS, 0, HIWORD(GetRange(hWnd, lpTDData)));
					else
						SendMessage(lpTDData->hSpin, UDM_SETPOS, 0, HIWORD(SendMessage(lpTDData->hSpin, UDM_GETRANGE, 0, 0)));
					SendMessage(hWnd, WM_KEYDOWN, VK_DOWN, lParam);
					return FALSE;
				}
			}
			if(wParam != VK_DELETE)
				break;
		}
		case WM_PASTE:
		case WM_CUT:
		case WM_CLEAR:
		case WM_CHAR:
		{
			DWORD dwStyle = GetWindowLong(GetParent(hWnd), GWL_STYLE);
			if(dwStyle & TDS_READONLY)
				return TRUE;
			break;
		}
	}

	WNDPROC oldWndPros = (WNDPROC)GetWindowLong(hWnd, GWL_USERDATA);
	if(oldWndPros)
		return CallWindowProc(oldWndPros, hWnd, uMsg, wParam, lParam);
	else
		return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

void OnCommand(HWND hWnd, UINT nID, HWND hwndCtl, UINT codeNotify)
{
	if(codeNotify == EN_UPDATE)
	{
		NMHDR Nmhdr;
		Nmhdr.hwndFrom = hWnd;
		Nmhdr.idFrom = GetWindowLong(hWnd, GWL_ID);
		Nmhdr.code = TDN_CHANGEDATA;
		SendMessage(GetParent(hWnd), WM_NOTIFY, Nmhdr.idFrom, (LPARAM)&Nmhdr);
	}
}

LRESULT OnNotify(HWND hWnd, UINT nID, NMHDR *pNmhdr)
{
	if(nID == IDC_SPIN)
	{
		LPNMUPDOWN pud = (LPNMUPDOWN)pNmhdr;
		if(pud->hdr.code == UDN_DELTAPOS)
		{
			DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);
			if((TDS_NUMVALUE | TDS_STRVALUE) & dwStyle)
			{
				pud->hdr.hwndFrom = hWnd;
				pud->hdr.idFrom = GetWindowLong(hWnd, GWL_ID);
				pud->hdr.code = TDN_CHANGEPOS;
				return SendMessage(GetParent(hWnd), WM_NOTIFY, pud->hdr.idFrom, (LPARAM)pNmhdr);
			}
		}
	}
	return FALSE;
}
