compile function rti_Popup_DateTime( object, method, param1, param2, param3, param4, param5, param6, param7, param8 )
/*
   ** Copyright (C) 2012-2022 Revelation Software Inc. All Rights Reserved **

   Author   : Mr C
   Date     : 12th Jan 2022
   Purpose  : Commuter module for the RTI_POPUP_DATETIME form

   Comments
   ========
   
   This source is included as an example of dialog box programming.
   Do not make modifications to this as it may be overwritten in a
   future update - take a copy in your own application instead and 
   make modifications there.
   

   Amended  Date        Reason
   =======  ====        ======
   Mr C     19 Jul 23   Fixed DTS mode return value
                        Fixed DT layout (hide SECONDS controls)
                        Improved "S" detection when parsing time conv patterns
*/
   #pragma precomp event_precomp

   declare function get_Property, set_Property, retStack, rti_ErrorText
   declare function ps_Get_Property, rti_Res2Str, msg, exec_Method, dialog_Box
   declare function ps_TypeInfo, msWin_GetDateFormat, rti_Convert
   $insert rti_Popup_DateTime_Equates
   $insert ps_EditTable_Equates
   $insert ps_Monitor_Equates
   $insert msWin_Locale_Equates
   $insert msWin_SystemTime_Equates
   $insert msWin_SysColor_Equates
   $insert rti_Struct_Equates
   $insert rti_StrConv_Equates
   $insert rti_Resources_Equates
   $insert rti_SSP_Equates
   $insert msg_Equates 
   $insert logical
   $insert colors
   
   equ FIRST_YEAR$      to 1980
   equ LAST_YEAR$       to 2050
   equ DAY_COUNT$       to "31,28,31,30,31,30,31,31,30,31,30,31"
     
   equ SECS_PER_DAY$    to 86400
   equ HOURS_PER_DAY$   to 24
   equ SECS_PER_HOUR$   to 3600
   equ SECS_PER_MINUTE$ to 60
   
   if assigned( object ) else object = ""
   if assigned( method ) else method = ""
   if assigned( param1 ) else param1 = ""
   if assigned( param2 ) else param2 = ""
   if assigned( param3 ) else param3 = ""
   if assigned( param4 ) else param4 = ""
   if assigned( param5 ) else param5 = ""
   if assigned( param6 ) else param6 = ""
   if assigned( param7 ) else param7 = ""
   if assigned( param8 ) else param8 = ""
   
   errorText = ""
   abort     = FALSE$
   retVal    = ""

   if bLen( method ) then
   
      locate method in "CHANGED,CLOSE,CREATE,DBLCLK,POSCHANGED,WRITE" using "," setting pos then
         on pos goSub onChanged,onClose,onCreate,onDblClk,onPosChanged,onWrite
      end else
         // ERR002: Invalid method "%1% passed to the %2% procedure
         errorText = rti_Res2Str( RESID$, "ERR002", method : @fm : retStack()<1> )
         abort     =  TRUE$
      end
   end else
      // Assume this is one of those lazy calls that tries to work out 
      // where it is and then handle everything from there...
      goSub onInit
   end

   if abort then
      if bLen( errorText ) then
         goSub errorMsg
         if ( method = "CREATE" ) then
            @@window->close( "" )
         end
         
      end
   end

return retVal

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// onInit subroutine
//
// This method is used to try and work out what the developer was intending
// when they couldn't be bothered to pass any params to the function - we 
// basically look at the control with focus, and if it's something we can 
// work with (i.e. it has a D,DT or MT iconv/conv then we'll do our best)
//
// Once we get something we're happy with we'll update it ourselves.
//
// ----------------------------------------------------------------------------
onInit:

   // Note ... @window is not reliable here because this not an 
   // RTI_POPUP_DATETIME event

   atFocus = $system->focus
   if bLen( atFocus ) else return
      
   bAMV     = ps_TypeInfo( "ISAMVTYPE", atFocus )
   conv     = @atFocus->conv
   
   colIdx   = ""
   rowIdx   = ""
   iVal     = ""
   
   begin case
      case ( bAMV )
      
         caretPos = @atFocus->caretPosX
         colIdx   = caretPos<1>
         rowIdx   = caretPos<2>
         
         if ( colIdx and rowIdx ) then
            conv = conv<0,0,colIdx>
            iVal = @atFocus->inValue{colIdx,rowIdx}
         end else
            // wut?
            atFocus = ""
         end
         
      case OTHERWISE$
         iVal = @atFocus->inValue
         
   end case
   
   if bLen( atFocus ) then
   
      createParam = ""
      createMode  = PDT_MODE_DEFAULT$
   
      begin case
         case ( conv[1,2] == "DT" )
         
            if index( conv[-1,"B^"], "S", 1 ) then
               createMode = PDT_MODE_DTS$
            end else
               createMode = PDT_MODE_DT$
            end
            
         case ( conv[1,2] == "MT" )
            if index( conv, "S", 1 ) then
               createMode = PDT_MODE_MTS$
            end else
               createMode = PDT_MODE_MT$
            end
         
         case ( conv[1,1] == "D" )
            createMode = PDT_MODE_D$
            
         case OTHERWISE$
            null
         
      end case
      
      createParam<PDT_CP_POS_MODE$> = createMode
      begin case
         case ( createMode[1,2] == PDT_MODE_DT$ ) ; // DTS,DT
            initDate = iVal[1,"."]
            
            // Simply using the fractional part can lose us precision here, 
            // so we'll run it through the MT processor to get something more 
            // accurate
            oVal = oconv( iVal, conv )
            
            // Now find the date/time delimiter from the conv spec so we
            // can extract the time...
            sepDelim = " "
            
            tmp = conv[-1,"B^"]
            if bLen( tmp ) then
               if num( tmp[1,1] ) then
                  if ( ( tmp[2,1] != "H" ) and ( tmp[2,1] != "S" ) ) then
                     sepDelim = tmp[2,1]
                     tmp[1,2] = ""
                  end else
                     tmp[1,1] = ""
                  end
               end
            end
            mtConv   = "MT" : tmp
            
            oVal = oVal[-1,"B" : sepDelim]
            
            initTime = iconv( oVal, mtConv )
                      
            if initDate else initDate = date()
            if initTime else initTime = time()
            
         case ( createMode[1,2] == PDT_MODE_MT$ ); // MTS,MT
            initDate = 0
            initTime = iVal
            
            if initTime else
               initTime = time()
            end
            
         case ( createMode == PDT_MODE_D$ )
            initDate = iVal
            initTime = 0
            
            if initDate else
               initDate = date()
            end
         
      end case
      
      createParam<PDT_CP_POS_INITDATE$>    = initDate
      createParam<PDT_CP_POS_INITTIME$>    = initTime
      createParam<PDT_CP_POS_OWNERID$>     = atFocus
      createParam<PDT_CP_POS_OWNERALIGN$>  = PDT_ALIGN_DEFAULT$
      
      parentWin = @atFocus->parentForm
      
      retVal = dialog_Box( "RTI_POPUP_DATETIME", parentWin, createParam )
           
      if bLen( retVal ) then
         if ( colIdx and rowIdx ) then
            @atFocus->inValue{colIdx,rowIdx} = retVal
         end else
            @atFocus->inValue = retVal
         end
      end
      
   end

return

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////  
// onChanged subroutine
//
// Main CHANGED event dispatch handler
//
// ----------------------------------------------------------------------------
// [i]   param1 : NewData - this is the text that has changed.
// ----------------------------------------------------------------------------
onChanged:

   transfer param1 to newData
   
   atCtrl = field( object, ".", 2, 999 )
   
   begin case
      case ( atCtrl == "CBO_MONTH" )
         goSub cboMonth_OnChanged
      case ( atCtrl == "CBO_YEAR" )
         goSub cboYear_OnChanged
   end case
   
   transfer newData to param1
   
return

///////////////////////////////////////////////////////////////////////////////  
// onClose subroutine
// 
// CLOSE event handler 
//
// ----------------------------------------------------------------------------
// [i]   param1 : Cancel Flag
// [i]   param2 : Close Flags   
// ----------------------------------------------------------------------------
onClose:

   cancelFlag = param1
   closeFlags = param2
   
return

///////////////////////////////////////////////////////////////////////////////
// onCreate subroutine
//
// CREATE event handler
// 
// ----------------------------------------------------------------------------
// [i]   param1 : CreateParam - see RTI_POPUP_DATETIME_EQUATES
// ----------------------------------------------------------------------------  
onCreate:

   transfer param1 to createParam
   
   // Cache the createParam for later use
   @@window->PDT_UDP_CREATEPARAM$ = createParam
   
   // Set the "highlight colors" for EDT_DAYS - note that the FOCUSRECT color
   // is already set in the FormDes
   tmp = $system->visualStyleColor{SYSCOLOR_HIGHLIGHTTEXT$}
   .edt_Day->PDT_UDP_SELFORECOLOR$ = tmp
   
   tmp = $system->visualStyleColor{SYSCOLOR_HIGHLIGHT$}
   .edt_Day->PDT_UDP_SELBACKCOLORCOLOR$ = tmp
   
   createMode = createParam<PDT_CP_POS_MODE$>
   // Size the window according to the mode.
   goSub onCreate_LayoutControls
   
   // Load the controls with the init data
   goSub onCreate_LoadInitData
   
   // Put it in place...
   goSub onCreate_PositionDialog
   
   // Final shuffle. Because of scaling issues sometimes the rows in EDT_DAYS 
   // won't fill the control properly, so what we need to do here is calculate
   // how high the edit table is and resize it's height accordingly. 
   // 
   // When we do this we might need to move the time controls and resize the 
   // form's client height as well.
   goSub onCreate_AdjustEdtDaysHeight
   
   transfer createParam to param1
   
   @@window->show( "" )
   
   if ( createMode[1,2] == "MT" ) then
      $system->focus = @window : ".EDL_HOUR"
   end else
      $system->focus = @window : ".EDT_DAY"
   end
   
return

///////////////////////////////////////////////////////////////////////////////
// onCreate_LayoutControls subroutine
//
// Set the size of the dialog based in the mode:
//
//    "D"         - Hide the time controls
//    "MT","MTS"  - Hide the date controls
//    "DT","DTS"  - Leave as designed.
//
// If we are not showing the seconds ("DT" or "MT" ) then we hide the seconds
// controls.  If it's an MT format then we also narrow the dialog to 
// compensate.
// 
// ----------------------------------------------------------------------------
// [i]   createMode : Specifies the mode the dialog operates in 
// ---------------------------------------------------------------------------- 
onCreate_LayoutControls:

   begin case
      case ( createMode == "D" )
      
         // Hide the TIME controls and resize the dialog to cover them
         objxArray =        "@.EDL_HOUR"
         objxArray := @rm : "@.UPD_HOUR"
         objxArray := @rm : "@.EDL_MINUTES"
         objxArray := @rm : "@.UPD_MINUTES"
         objxArray := @rm : "@.EDL_SECONDS"
         objxArray := @rm : "@.UPD_SECONDS"
         
         swap "@" with @window in objxArray
         call set_Property( objxArray, "VISIBLE", FALSE$ )
         
         // Reduce the height of the dialog to the bottom of the EDT_DAY
         // edit table plus a small margin
         @@window->clientHeight = ( .edt_day->bottom + PDT_BORDERMARGIN$ )
         
      case ( createMode[1,2] == "MT" )
      
         // Hide the date controls
         objxArray =        "@.CBO_MONTH"
         objxArray := @rm : "@.CBO_YEAR"
         objxArray := @rm : "@.EDT_DAY"
                 
         swap "@" with @window in objxArray
         call set_Property( objxArray, "VISIBLE", FALSE$ )
         
         // Now move the time controls - we could have put them on a panel 
         // and just moved that but where's the fun then eh?
         
         // Work out the offset height
         yOffset = .cbo_month->top - .lbl_hour->top
         
         ctrlNames = "HOUR,MINUTES,SECONDS" ; convert "," to @fm in ctrlNames
         ctrlTypes = ".LBL_,.EDL_,.UPD_"    ; convert "," to @fm in ctrlTypes
         for x = 1 to 3
            ctrlName = ctrlNames<x>
            for y = 1 to 3
               ctrlType = ctrlTypes<y>
               
               ctrlID = @window : ctrlType : ctrlName
               @ctrlID->offset( 0, yOffset )
               
            next
         next
         
         // Reduce the height of the dialog to the bottom of the BTN_CANCEL
         // button plus a small margin
         @@window->clientHeight = ( ( .btn_Cancel->bottom ) + PDT_BORDERMARGIN$ )
         
         if ( createMode[-1,1] != "S" ) then
         
            // Hide the seconds controls
            for y = 1 to 3
               ctrlType = ctrlTypes<y>
               ctrlID = @window : ctrlType : "SECONDS"
               @ctrlID->visible = FALSE$
            next
            
            // And make the dialog narrower - we shouldn't need to move the 
            // buttons ourselves because they are right-aligned.
            btnW = .btn_OK->width
            minR = .upd_minutes->right
            
            @@window->clientWidth = ( minR + btnW + ( 2 * PDT_BORDERMARGIN$ ) + PDT_BORDERMARGIN$ )
            
         end
         
      case OTHERWISE$
         
         if ( createMode[-1,1] != "S" ) then
            // Hide the seconds controls
            
            ctrlTypes = ".LBL_,.EDL_,.UPD_" ; convert "," to @fm in ctrlTypes
         
            for y = 1 to 3
               ctrlType = ctrlTypes<y>
               ctrlID = @window : ctrlType : "SECONDS"
               @ctrlID->visible = FALSE$
            next
            
         end
         
   end case
   
   locate createMode in "D,DT,DTS" using "," setting pos then
      // We need to load in the user locale's abbreviated day names - we start
      // from a known sunday and loop through each day ...
      
      st = ""
      st<SYSTEMTIME_POS_WYEAR$>        = 2022
      st<SYSTEMTIME_POS_WMONTH$>       = 1
      st<SYSTEMTIME_POS_WDAYOFWEEK$>   = 0 ; // Sunday
      st<SYSTEMTIME_POS_WDAY$>         = 9
      st<SYSTEMTIME_POS_WHOUR$>        = 0
      st<SYSTEMTIME_POS_WMINUTE$>      = 0
      st<SYSTEMTIME_POS_WSECOND$>      = 0
      st<SYSTEMTIME_POS_WMILLSECONDS$> = 0
      
      lpFormat  = str_Unicode( "ddd" : \00\ ) ; // Short day name format
      lpDateStr = str_Unicode( str( \00\, 10 ) )
      
      for x = 0 to 6
         
         st_ = var_To_Struct( st, SYSTEMTIME$ )
         if msWin_GetDateFormat( LOCALE_USER_DEFAULT$,    |
                                 0,                       |
                                 getPointer( st_ ),       |
                                 getPointer( lpFormat ),  |
                                 getPointer( lpDateStr ), |
                                 10 ) then
                                 
            tmp = unicode_Str( lpDateStr )[1,\00\]
            
            colIdx = ( x + 1 )
            .edt_Days.columns{colIdx}->headerText = tmp
            
         end else
            // wut?
            null
         end
         
         st<SYSTEMTIME_POS_WDAYOFWEEK$> = st<SYSTEMTIME_POS_WDAYOFWEEK$> + 1
         st<SYSTEMTIME_POS_WDAY$>       = st<SYSTEMTIME_POS_WDAY$> + 1
         
      next
      
   end

return

///////////////////////////////////////////////////////////////////////////////
// onCreate_LoadInitData subroutine
//
// Set the size of the dialog based in the mode:
//
//    "D"    - Hide the time controls
//    "MT"   - Hide the date controls
//    "DT"   - Leave as designed.
// 
// ----------------------------------------------------------------------------
// [i]   createMode  : Specifies the mode the dialog operates in 
// [i]   createParam : See RTI_POPUP_DATETIME_EQUATES 
// ---------------------------------------------------------------------------- 
onCreate_LoadInitData:
   
   initDate   = createParam<PDT_CP_POS_INITDATE$>
   initTime   = createParam<PDT_CP_POS_INITTIME$>
   
   if bLen( initDate ) else initDate = date()
   if bLen( initTime ) else initTime = time()
      
   locate createMode in "D,DT,DTS" using "," setting pos then
      // Load the date controls - first preload the combos and then set
      // the date...
      
      firstYear = createParam<PDT_CP_POS_FIRSTYEAR$>
      lastYear  = createParam<PDT_CP_POS_LASTYEAR$>
      
      if bLen( firstYear ) else firstYear = FIRST_YEAR$
      if bLen( lastYear )  else lastYear  = LAST_YEAR$
      
      if ( lastYear < firstYear ) then
         lastYear = firstYear
      end else
         if ( firstYear > lastYear ) then
            firstYear = lastYear
         end
      end
      
      tmp = fmt( initDate, "DJS" )
      
      initYear  = tmp[1,4]
      initMonth = tmp[6,2]
      initDay   = tmp[9,2]
      
      if ( initYear < firstYear ) then
         firstYear = initYear
      end else
         if ( initYear > lastYear ) then
            lastYear = initYear
         end
      end
      
      tmp = ""
      for x = 1 to 12
         tmp<x> = x : "/1"
      next
      
      tmp = oconv( iconv( tmp, "DH" ), "DHL" )
      
      for x = 1 to 12
         tmp<x> = tmp<x>[1," "]
      next
      
      .cbo_month->list = tmp
      .cbo_month->selPos = initMonth
      
      tmp = ""
      for x = firstYear to lastYear
         tmp := x : @fm
      next
      tmp[-1,1] = ""
      
      .cbo_Year->list = tmp
      .cbo_Year->text = initYear
      
      @@window->PDT_UDP_CURRDAY$ = initDay
      goSub loadDaysForMonthYear
      
   end
   
   locate createMode in "MTS,MT,DTS,DT" using "," setting pos then
   
      // Load the time controls
      .edl_hour->text = int( initTime / SECS_PER_HOUR$ )
      tmp             = mod( initTime, SECS_PER_HOUR$ )
      
      .edl_minutes->text = int( tmp / SECS_PER_MINUTE$ )
      
      if ( createMode[-1,1] == "S" ) then
         .edl_seconds->text = mod( tmp, SECS_PER_MINUTE$ )
      end
      
   end
   
return

///////////////////////////////////////////////////////////////////////////////
// onCreate_PositionDialog subroutine
//
// Position the dialog below it's owner using the specified horizontal 
// alignment.
// 
//    1) If there is not enough room to display below it owner then place it 
//       above
//
//    2) Ensure it stays within the bounds of it's owner's monitor
//
// ----------------------------------------------------------------------------
// [i]   createParam : See RTI_POPUP_DATETIME_EQUATES 
// ---------------------------------------------------------------------------- 
onCreate_PositionDialog:

   ownerID = createParam<PDT_CP_POS_OWNERID$>
   if bLen( ownerID ) else
      // wut?
      @@window->center( TRUE$ )
      return
   end
   
   ownerSize = rti_Convert( createParam<PDT_CP_POS_OWNERSCREENSIZE$>, @vm, @fm )
   colIdx    = ""
   rowIdx    = ""
   
   begin case
      case ( @ownerID->type == "EDITTABLE" )
         caretPos  = @ownerID->caretPosX
         colIdx    = caretPos<1>
         rowIdx    = caretPos<2>
         
         if bLen( ownerSize ) else
            if ( colIdx and rowIdx ) then
               ownerSize = @ownerID.cells{colIdx,rowIdx}->screenSize
            end
         end
      
      case ps_TypeInfo( "ISAMVTYPE", ownerID )
         caretPos = @ownerID->defPosProp
         colIdx   = caretPos<1>
         rowIdx   = caretPos<2>
         
      case OTHERWISE$
         if bLen( ownerSize ) else
            ownerSize = @ownerID->screenSize
         end
         
   end case
   
   if ( colIdx and rowIdx ) then
      @@window->PDT_UDP_CARETPOS$ = colIdx : @fm : rowIdx
   end
   
   if bLen( ownerSize ) else
      // wut?
      @@window->center( TRUE$ )
      return
   end
   
   ownerMon  = @ownerID->monitor
   winSize   = @@window->size
   monRect   = rti_Convert( ownerMon<PS_MON_POS_WORKAREARECT$>, @vm, @fm )
   
   ownerB = ( ownerSize<2> + ownerSize<4> )
   if ( ( monRect<4> - ownerB ) < winSize<4> ) then
      // Display above - I assume that if we can't display below then we'll
      // be fine above and on the monitor, because no-one has a monitor that 
      // small, right?
      winSize<2> = ( ownerSize<2> - winSize<4> )
   end else
      // Display below, and if we're outside the work rectangle then push us up 
      // until we're all on.
      winSize<2> = ( ownerSize<2> + ownerSize<4> + 1 )
      
      winB = ( winSize<2> + winSize<4> )
      if ( winB > monRect<4> ) then
         winSize<2> = ( monRect<4> - winSize<4> )
      end
      
   end
   
   // Now h-Align...
   if ( createParam<PDT_CP_POS_OWNERALIGN$> == PDT_ALIGN_R$ ) then
   
      // Right align then check...
      winSize<1> = ( ownerSize<1> + ownerSize<3> ) - winSize<3>
      winR       = ( winSize<1> + winSize<3> )
      
      if ( winR > monRect<3> ) then
         // Dialog is off the right side of the monitor so push it left
         winSize<1> = monRect<3> - winSize<1>
      end else
         if ( winSize<1> < monRect<1> ) then
            // We're off the left side (!) so push it right...
            winSize<1> = monRect<1>
         end
      end
   
   end else
      winSize<1> = ownerSize<1>
      if ( winSize<1> < monRect<1> ) then
         // Dialog is off the left size of the monitor so push it back
         winSize<1> = monRect<1>
      end else
         winR = ( winSize<1> + winSize<3> )
         if ( winR > monRect<3> ) then
            // Dialog is off the right side of the monitor, so push it 
            // back
            winSize<1> = ( monRect<3> - winSize<3> )
         end
      end
   end
   
   winSize<5> = -1 ; // Keep invisible
   
   @@window->size = winSize
   
return

///////////////////////////////////////////////////////////////////////////////
// onCreate_AdjustEdtDaysHeight subroutine 
//
// ----------------------------------------------------------------------------
onCreate_AdjustEdtDaysHeight:

   edtOrigH = .edt_Days->height
   colHdrH  = .edt_Days->colHeaderHeight
   rowH     = .edt_Days->rowHeight
   
   .edt_Days->clientHeight = ( colHdrH + ( rowH * 6 ) )
   
   edtH  = .edt_Days->height
   diffH = ( edtH - edtOrigH )
   if ( diffH ) then
      ctrlNames = "HOUR,MINUTES,SECONDS" ; convert "," to @fm in ctrlNames
      ctrlTypes = ".LBL_,.EDL_,.UPD_"    ; convert "," to @fm in ctrlTypes
      for x = 1 to 3
         ctrlName = ctrlNames<x>
         for y = 1 to 3
            ctrlType = ctrlTypes<y>
            
            ctrlID = @window : ctrlType : ctrlName
            @ctrlID->offset( 0, diffH )
            
         next
      next
      
      @@window->clientHeight = ( @@window->clientHeight + diffH )
      
   end
   
return

///////////////////////////////////////////////////////////////////////////////
// onDblClk subroutine
//
// Main DBLCLK event dispatch handler
//
// ----------------------------------------------------------------------------
// [i]   param1 : ctrlKey  - TRUE$ if the Ctrl key is down   
// [i]   param2 : shiftKey - TRUE$ if the Shift  key is down
// [i]   param3 : mouseButton - TRUE$ if the right mouseButton is down
// ---------------------------------------------------------------------------
onDblClk:

   transfer param1 to ctrlKey
   transfer param2 to shiftKey
   transfer param3 to mouseButton

   atCtrl = field( object, ".", 2, 999 )
   
   begin case
      case ( atCtrl == "EDT_DAY" )
         goSub edtDay_OnDblClk
   end case
   
   transfer ctrlKey     to param1
   transfer shiftKey    to param2
   transfer mouseButton to param3 

return

///////////////////////////////////////////////////////////////////////////////
// onPosChanged subroutine
//
// Main POSCHANGED event handler dispatch handler.
//
// ----------------------------------------------------------------------------
// [i]   nextColumn : Column index of the current cell
// [i]   nextRow    : Row Index in the current cell
// ----------------------------------------------------------------------------
onPosChanged:
   
   transfer param1 to nextColumn
   transfer param1 to nextRow
   
   atCtrl = field( object, ".", 2, 999 )
 
   begin case
      case ( atCtrl == "EDT_DAY" )
         goSub edtDay_OnPosChanged
   end case
   
   transfer nextRow    to param2
   transfer nextColumn to param1
   
   
return

///////////////////////////////////////////////////////////////////////////////
// onWrite subroutine
//
// WRITE event handler.  Return the date/time in internal format to the dialog
// owner
//
// ----------------------------------------------------------------------------
onWrite:

   if ( @@window->PDT_UDP_EXECWRITE$ ) then
      return
   end
   
   @@window->PDT_UDP_EXECWRITE$ = TRUE$
   
   goSub getDateTimeValue ; // returns dtVal
      
   @@window->closeDialog( dtVal )
   
return 

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////  
// cboMonth_OnChanged subroutine
//
// CHANGED event handler for the CBO_MONTH control.  When the month changes
// then update the day numbers in EDT_DAY
//
// ----------------------------------------------------------------------------
// [i]   NewData : New month
// ----------------------------------------------------------------------------
cboMonth_OnChanged:

   goSub loadDaysForMonthYear
   
return

///////////////////////////////////////////////////////////////////////////////  
// cboYear_OnChanged subroutine
//
// CHANGED event handler for the CBO_YEAR control.  When the year changes
// then update the day numbers in EDT_DAY
//
// ----------------------------------------------------------------------------
// [i]   NewData : New year
// ----------------------------------------------------------------------------
cboYear_OnChanged:

   goSub loadDaysForMonthYear
   
return

///////////////////////////////////////////////////////////////////////////////
// edtDay_OnDblClk subroutine
//
// DBLCLK event handler for the EDT_DAY control.
//
// If the user double-clicks on a day number then return the data to the user
//
// ----------------------------------------------------------------------------
// [i]   ctrlKey  - TRUE$ if the Ctrl key is down   
// [i]   shiftKey - TRUE$ if the Shift  key is down
// [i]   mouseButton - TRUE$ if the right mouseButton is down
// ---------------------------------------------------------------------------
edtDay_OnDblClk:

   caretPos = @object->caretPosX
   colIdx   = caretPos<1>
   rowIdx   = caretPos<2>
   
   dayNo    = @object.cells{colIdx,rowIdx}->text
      
   if dayNo then
      @@window->writeRow( "" )
   end

return

///////////////////////////////////////////////////////////////////////////////
// edtDay_OnPosChanged subroutine
//
// POSCHANGED event handler 
//
// ----------------------------------------------------------------------------
// [i]   param1 : nextColumn
// [i]   param2 : nextRow
// ----------------------------------------------------------------------------
edtDay_OnPosChanged:

   caretPos = @object->caretPosX
   colIdx   = caretPos<1>
   rowIdx   = caretPos<2>
   
   dayNo =  @object.cells{colIdx,rowIdx}->text
      
   if bLen( dayNo ) else
      // Moved onto a non-date cell so no coloring update...
      return
   end
   
   @object->redraw = FALSE$
   
   @@window->PDT_UDP_CURRDAY$ = dayNo
   
   colorPos = @object->PDT_UDP_COLORPOS$
   if bLen( colorPos ) then
      if ( colorPos != caretPos ) then
         cs = ""
         cs<PS_EDT_CS_POS_FORECOLOR$>     = CLR_USEDEFAULT$
         cs<PS_EDT_CS_POS_BACKCOLORFROM$> = CLR_TRANSPARENT$
         cs<PS_EDT_CS_POS_BACKCOLORTO$>   = CLR_TRANSPARENT$
         cs<PS_EDT_CS_POS_BOLD$>          = FALSE$
         
         @object.cells->cellStyle( colorPos<1>, colorPos<2>, PS_EDT_CS_NORMAL$, FALSE$, cs )
         
      end
   end
   
   cs = ""
   cs<PS_EDT_CS_POS_FORECOLOR$>     = .edt_Day->PDT_UDP_SELFORECOLOR$ 
   cs<PS_EDT_CS_POS_BACKCOLORFROM$> = .edt_Day->PDT_UDP_SELBACKCOLORCOLOR$
   cs<PS_EDT_CS_POS_BACKCOLORTO$>   = cs<PS_EDT_CS_POS_BACKCOLORFROM$>
   cs<PS_EDT_CS_POS_BOLD$>          = TRUE$
   
   @object.cells->cellStyle( colIdx, rowIdx, PS_EDT_CS_NORMAL$, FALSE$, cs )
   
   @object->PDT_UDP_COLORPOS$ = caretPos
   
   @object->redraw = TRUE$
   
return

///////////////////////////////////////////////////////////////////////////////
// getDateTimeValue subroutine
//
// Extracts the data from the controls and constructs the date, time or 
// datetime value that should be returned to the caller based on the create
// mode
//
// ----------------------------------------------------------------------------
// [o] dtVal : Returned date/time value
// ----------------------------------------------------------------------------
getDateTimeValue:

   createParam = @@window->PDT_UDP_CREATEPARAM$
   
   createMode = createParam<PDT_CP_POS_MODE$>
   
   iDate = 0
   iTime = 0
   dtVal = ""
   
   locate createMode in "D,DT,DTS" using "," setting pos then
   
      dayNo      = @@window->PDT_UDP_CURRDAY$
      monthNo    = .cbo_Month->selPos
      year       = .cbo_Year->text
      
      iDate      = iconv( dayNo : "/" : monthNo : "/" : year, "D4/E" )
      
   end
   
   locate createMode in "MTS,MT,DT,DTS" using "," setting pos then
   
      hour = .edl_Hour->text
      mins = .edl_Minutes->text
      secs = .edl_Seconds->text
      
      iTime = ( hour * SECS_PER_HOUR$ ) + ( mins * SECS_PER_MINUTE$ ) + secs
      
   end
   
   begin case
      case ( createMode == "D" )
         dtVal = iDate
         
      case ( createMode[1,2] == "MT" )
         dtVal = iTime
         
      case OTHERWISE$
         dtVal = iDate + ( iTime / SECS_PER_DAY$ )
         
   end case

return 

///////////////////////////////////////////////////////////////////////////////
// loadDaysForMonthYear
//
// This subroutine loads in the day numbers into EDT_DAY based on the Month 
// and Year in their respective combos.
//
// ----------------------------------------------------------------------------
loadDaysForMonthYear:

   currYear  = .cbo_Year->text
   currMonth = .cbo_Month->selPos
   
   prevYear  = @@window->PDT_UDP_PREVYEAR$
   prevMonth = @@window->PDT_UDP_PREVMONTH$
   
   if ( currYear == prevYear ) then
      if ( currMonth == prevMonth ) then
         return
      end
   end
   
   .edt_Day->redraw = FALSE$
   
   .edt_Day->PDT_UDP_COLORPOS$ = ""
   
   currDay = @@window->PDT_UDP_CURRDAY$
   if ( currDay ) else currDay = 1
   
   firstDay = iconv( currYear : "-" : currMonth : "-01", "DJS" )
   colIdx   = mod( firstDay, 7 ) + 1
   rowIdx   = 1
   
   currCol  = ""
   currRow  = ""
   
   dayCount = field( DAY_COUNT$, ",", currMonth )
   if ( currMonth == 2 ) then
      if ( mod( currYear, 4 ) == 0 ) and ( mod( currYear, 100 ) or mod( currYear, 400 ) == 0 ) then
         // Leap Year
         dayCount += 1
      end
   end
   
   dayCells = ""; dayCells<6,7> = "" ; // fill the array..
   
   for dayNo = 1 to dayCount
      if ( colIdx > 7 ) then
         colIdx  =  1
         rowIdx  += 1
      end
      
      dayCells<rowIdx,colIdx> = dayNo
      if ( dayNo == currDay ) then
         currCol = colIdx
         currRow = rowIdx
      end
      
      colIdx += 1
      
   next
   
   .edt_Day->list = dayCells
   
   if ( currCol ) then
      .edt_Day->caretPosX = currCol : @fm : currRow
   end
   
   // Now set any non-day cells to skipped, and the HOT color to the same as
   // the back color so that hot tracking looks like it's not on.
   cs = ""
   cs<PS_EDT_CS_POS_FORECOLOR$>     = CLR_USEDEFAULT$
   cs<PS_EDT_CS_POS_BACKCOLORFROM$> = ( $system->visualStyleColor{SYSCOLOR_WINDOW$} + 1 )
   cs<PS_EDT_CS_POS_BACKCOLORTO$>   = cs<PS_EDT_CS_POS_BACKCOLORFROM$>
   
   for rowIdx = 1 to 6
      for colIdx = 1 to 7
         dayNo = .edt_Day.cells{colIdx,rowIdx}->text
         if bLen( dayNo ) else
            .edt_Day.cells{colIdx,rowIdx}->skipOver = TRUE$
            .edt_Day.cells->cellStyle( colIdx, rowIdx, PS_EDT_CS_NORMAL$, FALSE$, cs )
         end
      next
   next
   
   .edt_Day->redraw = TRUE$
   
return

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// errorMsg subroutine
//
// Displays a simple error message
//
// ----------------------------------------------------------------------------
// [i]   errorText    : Text to display in the message
// [i]   errorCaption : Caption for the message
// ----------------------------------------------------------------------------
errorMsg:

   if assigned( errorCaption ) else errorCaption = ""
   if bLen( errorCaption ) else
      errorCaption = @@window->text
   end

   msgArray            = ""
   msgArray<MTEXT$>    = errorText
   msgArray<MICON$>    = "!"
   msgArray<MCOL$>     = -2
   msgArray<MROW$>     = -2
   msgArray<MJUST$>    = "C"
   msgArray<MCAPTION$> = errorCaption

   call msg( @window, msgArray )

return

///////////////////////////////////////////////////////////////////////////////
// setSPError subroutine
//
// Translates an SSP status error array into a "text version" from REVERROR.DAT
//
// ----------------------------------------------------------------------------
// [i,o] errorText : SSP status error to convert.  Returns the "text" version 
// [o]   abort     : Always set to TRUE$
// ----------------------------------------------------------------------------
setSPError:
   errorText = rti_ErrorText( "SP", errorText )
   abort = TRUE$
return

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
$insert copyright
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
