/*
 * Xailer source code:
 *
 * TimePicker.prg
 * Control TimePicker
 *
 * Copyright 2003, 2007 Jose Lalin
 * Copyright 2003, 2007 Xailer.com
 * All rights reserved
 *
 */

#include "Xailer.ch"
#include "CommCtrl.api"


//--------------------------------------------------------------------------

CLASS XTimePicker FROM TStdControl

PUBLISHED:
   PROPERTY nWidth         INIT 90
   PROPERTY nHeight        INIT 20

   PROPERTY cTime          INIT "" READ INLINE ::FcTime := IIf( ! Empty( ::Handle ), ::GetTime(), ::FcTime );
                                   WRITE SetTime

   PROPERTY cMinTime       INIT ""  WRITE INLINE ::SetRange( Value, ::cMaxTime )
   PROPERTY cMaxTime       INIT ""  WRITE INLINE ::SetRange( ::cMinTime, Value )
   PROPERTY cCustomFormat  INIT ""  WRITE METHOD SetFormat

   EVENT OnChange( oSender, cTime ) // --> Nil

PUBLIC:
   PROPERTY cText
   PROPERTY lDragAcceptFiles  INIT .F.

PROTECTED:
   DATA cWinClassName INIT DATETIMEPICK_CLASS

PUBLIC:
   METHOD Create( oParent ) CONSTRUCTOR

RESERVED:
   METHOD Notify( nWParam, nLParam )
   METHOD Change( cTime )           INLINE ::OnChange( cTime )
   METHOD GetBkColor()              INLINE ::SendMsg( DTM_GETMCCOLOR, MCSC_BACKGROUND, 0 )
   METHOD GetMonthBkgColor()        INLINE ::SendMsg( DTM_GETMCCOLOR, MCSC_MONTHBK, 0 )
   METHOD GetTextColor()            INLINE ::SendMsg( DTM_GETMCCOLOR, MCSC_TEXT, 0 )
   METHOD GetTitleBkColor()         INLINE ::SendMsg( DTM_GETMCCOLOR, MCSC_TITLEBK, 0 )
   METHOD GetTitleTextColor()       INLINE ::SendMsg( DTM_GETMCCOLOR, MCSC_TITLETEXT, 0 )
   METHOD GetTrailingTextColor()    INLINE ::SendMsg( DTM_GETMCCOLOR, MCSC_TRAILINGTEXT, 0 )

   METHOD SetBkColor( nColor )         INLINE ::SendMsg( DTM_SETMCCOLOR, MCSC_BACKGROUND, nColor )
   METHOD SetMonthBkColor( nColor )    INLINE ::SendMsg( DTM_SETMCCOLOR, MCSC_MONTHBK, nColor )
   METHOD SetTextColor( nColor )       INLINE ::SendMsg( DTM_SETMCCOLOR, MCSC_TEXT, nColor )
   METHOD SetTitleBkColor( nColor )    INLINE ::SendMsg( DTM_SETMCCOLOR, MCSC_TITLEBK, nColor )
   METHOD SetTitleTextColor( nColor )  INLINE ::SendMsg( DTM_SETMCCOLOR, MCSC_TITLETEXT, nColor )
   METHOD SetTrailingTextColor( nColor )  INLINE ::SendMsg( DTM_SETMCCOLOR, MCSC_TRAILINGTEXT, nColor )

   METHOD WMEraseBkgnd()   INLINE 1
   METHOD WMPaint()        EXTERN XControl_EraseSolidAndPaint()
   METHOD WMDestroy()      INLINE ( ::FcTime := ::GetTime(), ::Super:WMDestroy() )

PROTECTED:
   METHOD SetTime( cTime )
   METHOD GetTime()
   METHOD SetRange( cMinTime, cMaxTime )
   METHOD GetRange()
   METHOD SetFormat( cFormat )

ENDCLASS

//--------------------------------------------------------------------------

METHOD Create( oParent ) CLASS XTimePicker

   ::ChangeCtlStyle( DTS_TIMEFORMAT, .T. )
   ::ChangeCtlStyle( DTS_UPDOWN, .T. )

   InitCommonControls( ICC_DATE_CLASSES )

   ::Super:Create( oParent )

   ::SetTime( ::FcTime )

   IF ::cCustomFormat != Nil
      ::SetFormat( ::cCustomFormat )
   ENDIF

   IF ! Empty( ::FcMinTime ) .OR. ! Empty( ::FcMaxTime )
      ::SetRange( ::FcMinTime, ::FcMaxTime )
   ENDIF

RETURN Self

//--------------------------------------------------------------------------

#pragma BEGINDUMP

#undef _WIN32_WINNT
#define _WIN32_WINNT   0x0400

#include <windows.h>
#include <commctrl.h>
#include <shlobj.h>
#include <xailer.h>

//--------------------------------------------------------------------------

static BOOL XA_timeDecode( const char * pTime, long * wHour, long * wMinute, long * wSecond )
{
   BOOL bSuccess = FALSE;

   * wHour = 0;
   * wMinute = 0;
   * wSecond = 0;

   if( pTime )
   {
      ULONG ulLen;
      char * sTime, * szTime;

      sTime = hb_xgrab( 9 );
      strncpy( sTime, pTime, 8 );
      sTime[ 8 ] = '\0';
      szTime = sTime;

      /* LTrim */
      while( *szTime && HB_ISSPACE( * szTime ) )
         szTime++;

      /* RTrim */
      ulLen = strlen( szTime );

      while( ( ulLen > 1 ) && HB_ISSPACE( szTime[ ulLen - 1 ] ) )
         ulLen--;

      szTime[ ulLen ] = '\0';

      /* Si queda algo */
      if( * szTime )
      {
         char * pos;

         pos = strtok( szTime, ":" );

         if( pos )
            * wHour = atol( pos );

         pos = strtok( NULL, ":" );

         if( pos )
            * wMinute = atol( pos );

         pos = strtok( NULL, ":" );

         if( pos )
            * wSecond = atol( pos );

         bSuccess = TRUE;
      }
      hb_xfree( sTime );
   }

   return bSuccess;
}

//--------------------------------------------------------------------------

#if ( __GNUC__ >= 7 )
   #pragma GCC diagnostic ignored "-Wformat-overflow"
#endif

static char * XA_timeEncode( SYSTEMTIME st )
{
   static char szTime[ 9 ] = "        ";

   sprintf( szTime, "%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond );
   szTime[ 8 ] = '\0';

   return szTime;
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XTIMEPICKER_NOTIFY )
{
   PHB_ITEM Self = hb_stackSelfItem();
   LPNMDATETIMECHANGE dtc = (LPNMDATETIMECHANGE) hb_parnl( 2 );
   UINT uiCode = dtc->nmhdr.code;

   hb_ret();

   switch( uiCode )
   {
      case DTN_DATETIMECHANGE:
      {
         XA_ObjSendC( Self, "Change", XA_timeEncode( dtc->st ) );
      }
      break;
   }
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XTIMEPICKER_SETFORMAT )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hwnd = GetHandleOf( Self );

   XA_ObjSendC( Self, "_FcCustomFormat", hb_parc( 1 ) );
   if( hwnd )
      hb_retl( SendMessage( hwnd, DTM_SETFORMAT, 0, (LPARAM) hb_parc( 1 ) ) );
   else
      hb_retl( TRUE );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XTIMEPICKER_SETRANGE )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hwnd = GetHandleOf( Self );
   SYSTEMTIME st[ 2 ];
   DWORD wFlags = 0;
   BOOL bSuccess = FALSE;

   if( HB_ISCHAR( 1 ) )
   {
      PHB_ITEM pTimeMin = hb_param( 1, HB_IT_STRING );
      LONG wHour, wMinute, wSecond;
      int wYear, wMonth, wDay;

      XA_ObjSendItem( Self, "_FcMinTime", pTimeMin );
      XA_timeDecode( hb_itemGetCPtr( pTimeMin ), &wHour, &wMinute, &wSecond );

      hb_dateToday( &wYear, &wMonth, &wDay );

      st[ 0 ].wYear        = wYear;
      st[ 0 ].wMonth       = wMonth;
      st[ 0 ].wDay         = wDay;
      st[ 0 ].wDayOfWeek   = 0;

      st[ 0 ].wHour        = wHour;
      st[ 0 ].wMinute      = wMinute;
      st[ 0 ].wSecond      = wSecond;
      st[ 0 ].wMilliseconds = 0;

      wFlags = GDTR_MIN;
   }

   if( HB_ISCHAR( 2 ) )
   {
      PHB_ITEM pTimeMax = hb_param( 2, HB_IT_STRING );
      LONG wHour, wMinute, wSecond;
      int wYear, wMonth, wDay;

      XA_ObjSendItem( Self, "_FcMaxTime", pTimeMax );
      XA_timeDecode( hb_itemGetCPtr( pTimeMax ), &wHour, &wMinute, &wSecond );

      hb_dateToday( &wYear, &wMonth, &wDay );

      st[ 1 ].wYear        = wYear;
      st[ 1 ].wMonth       = wMonth;
      st[ 1 ].wDay         = wDay;
      st[ 1 ].wDayOfWeek   = 0;

      st[ 1 ].wHour        = wHour;
      st[ 1 ].wMinute      = wMinute;
      st[ 1 ].wSecond      = wSecond;
      st[ 1 ].wMilliseconds = 0;

      wFlags = wFlags | GDTR_MAX;
   }

   if( hwnd )
      bSuccess = SendMessage( hwnd, DTM_SETRANGE, wFlags, (LPARAM) &st );

   hb_retl( bSuccess );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XTIMEPICKER_SETTIME )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hwnd = GetHandleOf( Self );
   SYSTEMTIME st;

   if( HB_ISCHAR( 1 ) && hb_parclen( 1 ) )
   {
      const char * szTime = hb_parc( 1 );
      LONG wHour, wMinute, wSecond;
      int wYear, wMonth, wDay;

      XA_ObjSendC( Self, "_FcTime", szTime );
      XA_timeDecode( szTime, &wHour, &wMinute, &wSecond );

      hb_dateToday( &wYear, &wMonth, &wDay );

      st.wYear          = wYear;
      st.wMonth         = wMonth;
      st.wDay           = wDay;
      st.wDayOfWeek     = 0;

      st.wHour          = wHour;
      st.wMinute        = wMinute;
      st.wSecond        = wSecond;
      st.wMilliseconds  = 0;

      if( hwnd )
         SendMessage( hwnd, DTM_SETSYSTEMTIME, (WPARAM) GDT_VALID, (LPARAM) &st );
   }

   hb_retc( hb_parc( 1 ) );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XTIMEPICKER_GETTIME )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hwnd = GetHandleOf( Self );
   SYSTEMTIME st;
   DWORD dwResult;

   if( hwnd )
   {
      dwResult = (DWORD) SendMessage( hwnd, DTM_GETSYSTEMTIME, 0, (LPARAM) &st );
      if( dwResult == GDT_VALID )
         hb_retc( XA_timeEncode( st ) );
      else
         hb_retc( XA_ObjGetC( Self, "FcTime" ) );
   }
   else
      hb_retc( XA_ObjGetC( Self, "FcTime" ) );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XTIMEPICKER_GETRANGE )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hwnd = GetHandleOf( Self );
   SYSTEMTIME st[ 2 ];
   DWORD dwFlags;
   PHB_ITEM pArray = hb_itemArrayNew( 2 );
   PHB_ITEM pItem = hb_itemNew( NULL );

   dwFlags = SendMessage( hwnd, DTM_GETRANGE, 0, (LPARAM) &st );

   if( dwFlags & GDTR_MIN )
      hb_itemPutC( pItem, XA_timeEncode( st[ 0 ] ) );

   hb_itemArrayPut( pArray, 1, pItem );

   if( dwFlags & GDTR_MAX )
      hb_itemPutC( pItem, XA_timeEncode( st[ 1 ] ) );

   hb_itemArrayPut( pArray, 2, pItem );

   hb_itemReturnForward( pArray );
   hb_itemRelease( pItem );
   hb_itemRelease( pArray );
}

#pragma ENDDUMP

//--------------------------------------------------------------------------
