
#pragma once

#include "ListTypes.h"

#define DATE_STRING					32

class CListDate : public CWindowImpl< CListDate, CDateTimePickerCtrl >
{
public:
	CListDate()
	{
		m_nItem = NULL_ITEM;
		m_nSubItem = NULL_SUBITEM;
		m_nFlags = ITEM_FLAGS_NONE;
		m_nExitChar = 0;
	}
	
	~CListDate()
	{
	}

protected:
	int m_nItem;
	int m_nSubItem;
	UINT m_nFlags;
	TCHAR m_nExitChar;
	CFont m_fntDateFont;
	
public:
	BOOL Create( HWND hWndParent, int nItem, int nSubItem, CRect& rcRect, UINT nFlags, SYSTEMTIME& stItemDate )
	{
		m_nItem = nItem;
		m_nSubItem = nSubItem;
		m_nFlags = nFlags;
		m_nExitChar = 0;
		
		// destroy old date control...
		if ( IsWindow() )
			DestroyWindow();
			
		DWORD dwStyle = WS_CHILD | WS_CLIPCHILDREN;
		
		if ( nFlags & ITEM_FLAGS_DATETIME_NONE )
			dwStyle |= DTS_SHOWNONE;
		
		if ( nFlags & ITEM_FLAGS_TIME_ONLY )
			dwStyle |= DTS_UPDOWN;
		
		// create date-time control
		CRect Area( rcRect.left + 3, rcRect.top + 2, rcRect.right - 3, rcRect.bottom - 2 );
		if ( CWindowImpl< CListDate, CDateTimePickerCtrl >::Create( hWndParent, Area, NULL, dwStyle ) == NULL )
			return FALSE;
		
		// remove border
		ModifyStyleEx( WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED );
		
		// get system message font
		CLogFont logFont;
		logFont.SetMessageBoxFont();
		if ( !m_fntDateFont.IsNull() )
			m_fntDateFont.DeleteObject();
		if ( m_fntDateFont.CreateFontIndirect( &logFont ) == NULL )
			return FALSE;
		SetMonthCalFont( m_fntDateFont );
		SetFont( m_fntDateFont );
		
		TCHAR szDateFormat[ DATE_STRING ];
		GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE, szDateFormat, DATE_STRING );
		
		TCHAR szTimeFormat[ DATE_STRING ];
		GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, szTimeFormat, DATE_STRING );
		
		if ( nFlags & ITEM_FLAGS_DATE_ONLY )
			SetFormat( szDateFormat );
		else if ( nFlags & ITEM_FLAGS_TIME_ONLY )
			SetFormat( szTimeFormat );
		else
			SetFormat( stdstr_f("%s %s",szDateFormat,szTimeFormat ).c_str() );
		
		// get current date if setting time-only
		if ( nFlags & ITEM_FLAGS_TIME_ONLY )
		{
			SYSTEMTIME stCurrentDate;
			if ( GetSystemTime( &stCurrentDate ) == GDT_VALID )
			{
				stItemDate.wYear = stCurrentDate.wYear;
				stItemDate.wMonth = stCurrentDate.wMonth;
				stItemDate.wDay = stCurrentDate.wDay;
			}
		}
		
		SetSystemTime( ( !( nFlags & ITEM_FLAGS_TIME_ONLY ) && stItemDate.wYear == 0 ) ? GDT_NONE : GDT_VALID, &stItemDate );
		
		// show date-time control
		ShowWindow( SW_SHOW );
		
		SetFocus();
		
		return TRUE;
	}
		
	BEGIN_MSG_MAP_EX(CListDate)
		MSG_WM_KILLFOCUS(OnKillFocus)
		REFLECTED_NOTIFY_CODE_HANDLER_EX(DTN_CLOSEUP, OnCloseUp)
		MSG_WM_GETDLGCODE(OnGetDlgCode)
		MSG_WM_CHAR(OnChar)
		DEFAULT_REFLECTION_HANDLER()
	END_MSG_MAP()
	
	void OnKillFocus( HWND hNewWnd )
	{
		// have we dropped down the calendar control?
		if ( hNewWnd != NULL && GetMonthCal() == hNewWnd )
			return;
		
		// have we selected a new date from the calendar control?
		if ( GetFocus() == m_hWnd )
			return;
		
		// hide calendar control in case it's not closed by losing focus
		if ( GetMonthCal().IsWindow() )
			GetMonthCal().ShowWindow( SW_HIDE );
		
		CWindow wndParent( GetParent() );
		if ( wndParent.IsWindow() )
		{
			SYSTEMTIME stItemDate;
			BOOL bValidDate = ( GetSystemTime( &stItemDate ) == GDT_VALID );
			if ( !bValidDate )
				ZeroMemory( &stItemDate, sizeof( SYSTEMTIME ) );
			
			if ( m_nFlags & ITEM_FLAGS_DATE_ONLY )
			{
				stItemDate.wHour = 0;
				stItemDate.wMinute = 0;
				stItemDate.wSecond = 0;
				stItemDate.wMilliseconds = 0;
			}
			
			if ( m_nFlags & ITEM_FLAGS_TIME_ONLY )
			{
				stItemDate.wYear = 0;
				stItemDate.wMonth = 0;
				stItemDate.wDay = 0;
				stItemDate.wDayOfWeek = 0;				
			}
				
			CListNotify listNotify;
			listNotify.m_hdrNotify.hwndFrom = m_hWnd;
			listNotify.m_hdrNotify.idFrom = GetDlgCtrlID();
			listNotify.m_hdrNotify.code = LCN_ENDEDIT;
			listNotify.m_nItem = m_nItem;
			listNotify.m_nSubItem = m_nSubItem;
			listNotify.m_nExitChar = m_nExitChar;
			listNotify.m_lpszItemText = bValidDate ? _T( "1" ) : _T( "0" );
			listNotify.m_lpItemDate = &stItemDate;

			// forward notification to parent
			FORWARD_WM_NOTIFY( wndParent, listNotify.m_hdrNotify.idFrom, &listNotify.m_hdrNotify, ::SendMessage );
		}
		
		ShowWindow( SW_HIDE );
	}
	
	LRESULT OnCloseUp( LPNMHDR /*lpNMHDR*/ )
	{
		SetMsgHandled( FALSE );
		SetFocus();
		return TRUE;
	}
	
	UINT OnGetDlgCode( LPMSG /*lpMessage*/ )
	{
		return DLGC_WANTALLKEYS;
	}
	
	void OnChar( TCHAR nChar, UINT /*nRepCnt*/, UINT /*nFlags*/ )
	{
		switch ( nChar )
		{
			case VK_TAB:
			case VK_RETURN:
			case VK_ESCAPE:	{
								m_nExitChar = nChar;
								CWindow wndParent( GetParent() );
								if ( wndParent.IsWindow() )
									wndParent.SetFocus();
							}
							break;
			default:		SetMsgHandled( FALSE );
							break;
		}
	}
};
