! $Id$
!
! Earth System Modeling Framework
! Copyright 2002-2003, University Corporation for Atmospheric Research,
! Massachusetts Institute of Technology, Geophysical Fluid Dynamics
! Laboratory, University of Michigan, National Centers for Environmental
! Prediction, Los Alamos National Laboratory, Argonne National Laboratory,
! NASA Goddard Space Flight Center.
! Licensed under the GPL.
!
!==============================================================================
!
!     ESMF Clock Module
      module ESMF_ClockMod
!     
!==============================================================================
!     
! This file contains the Clock class definition and all Clock class methods.
!     
!------------------------------------------------------------------------------
! INCLUDES
#include <ESMF_TimeMgr.inc> 

!==============================================================================
!BOPI
! !MODULE: ESMF_ClockMod
!     
! !DESCRIPTION:
! Part of Time Manager F90 API wrapper of C++ implemenation
!
! Defines F90 wrapper entry points for corresponding
! C++ class {\tt ESMC\_Time} implementation
!     
! See {\tt ../include/ESMC\_Clock.h} for complete description
!
!------------------------------------------------------------------------------
! !USES:
      ! inherit from ESMF base class
      use ESMF_BaseMod

      ! associated derived types
      use ESMF_TimeIntervalMod   ! , only : ESMF_TimeInterval
      use ESMF_TimeMod           ! , only : ESMF_Time
      use ESMF_AlarmMod,        only : ESMF_Alarm

      implicit none
!
!------------------------------------------------------------------------------
! !PRIVATE TYPES:
      private
!------------------------------------------------------------------------------
!     ! ESMF_Clock
!     
!     ! F90 class type to match C++ Clock class in size only;
!     !  all dereferencing within class is performed by C++ implementation


! internals for ESMF_Clock
      type ESMF_ClockInt
        type(ESMF_TimeInterval) :: TimeStep
        type(ESMF_Time)  :: StartTime
        type(ESMF_Time)  :: StopTime
        type(ESMF_Time)  :: RefTime
        type(ESMF_Time)  :: CurrTime
        type(ESMF_Time)  :: PrevTime
        integer(ESMF_KIND_I8) :: AdvanceCount
        integer :: ClockMutex
        integer :: NumAlarms
        ! Note:  to mimic ESMF 2.1.0+, AlarmList is maintained 
        ! within ESMF_Clock even though copies of each alarm are 
        ! returned from ESMF_AlarmCreate() at the same time they 
        ! are copied into the AlarmList!  This duplication is not 
        ! as hideous as it might be because the ESMF_Alarm type 
        ! has data members that are all POINTERs (thus the horrible 
        ! shallow-copy-masquerading-as-reference-copy hack works).  
        type(ESMF_Alarm), pointer, dimension(:) :: AlarmList => null()
      end type

! Actual public type:  this bit allows easy mimic of "deep" ESMF_ClockCreate 
! in ESMF 2.1.0+
! NOTE:  DO NOT ADD NON-POINTER STATE TO THIS DATA TYPE.  It emulates ESMF 
!        shallow-copy-masquerading-as-reference-copy.  
      type ESMF_Clock
        type(ESMF_ClockInt), pointer  :: clockint => null()
      end type

!------------------------------------------------------------------------------
! !PUBLIC TYPES:
      public ESMF_Clock
      public ESMF_ClockInt   ! needed on AIX but not PGI
!------------------------------------------------------------------------------
!
! !PUBLIC MEMBER FUNCTIONS:
      public ESMF_ClockCreate
      public ESMF_ClockDestroy
      public ESMF_ClockSet
!      public ESMF_ClockSetOLD
      public ESMF_ClockGet
!      public ESMF_ClockGetAdvanceCount
!      public ESMF_ClockGetTimeStep
!      public ESMF_ClockSetTimeStep
!      public ESMF_ClockGetCurrTime
!      public ESMF_ClockSetCurrTime
!      public ESMF_ClockGetStartTime
!      public ESMF_ClockGetStopTime
!      public ESMF_ClockGetRefTime
!      public ESMF_ClockGetPrevTime
!      public ESMF_ClockGetCurrSimTime
!      public ESMF_ClockGetPrevSimTime
! This must be public for ESMF_AlarmClockMod...  
      public ESMF_ClockAddAlarm
      public ESMF_ClockGetAlarmList
!      public ESMF_ClockGetNumAlarms
!      public ESMF_ClockSyncToWallClock
      public ESMF_ClockAdvance
      public ESMF_ClockIsStopTime
      public ESMF_ClockStopTimeDisable

! Required inherited and overridden ESMF_Base class methods

!      public ESMF_ClockRead
!      public ESMF_ClockWrite
      public ESMF_ClockValidate
      public ESMF_ClockPrint
!EOPI

!------------------------------------------------------------------------------
! The following line turns the CVS identifier string into a printable variable.
      character(*), parameter, private :: version = &
      '$Id$'

!==============================================================================

      contains

!==============================================================================
!
! This section includes the Set methods.
!
!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockSetOLD - Initialize a clockint

! !INTERFACE:
      subroutine ESMF_ClockSetOLD(clockint, TimeStep, StartTime, &
                                  StopTime, RefTime, rc)

! !ARGUMENTS:
      type(ESMF_ClockInt), intent(out) :: clockint
      type(ESMF_TimeInterval), intent(in), optional :: TimeStep
      type(ESMF_Time), intent(in) :: StartTime
      type(ESMF_Time), intent(in) :: StopTime
      type(ESMF_Time), intent(in), optional :: RefTime
      integer, intent(out), optional :: rc
! Local
      integer i
    
! !DESCRIPTION:
!     Initialize an {\tt ESMF\_Clock}
!     
!     The arguments are:
!     \begin{description}
!     \item[clockint]
!          The object instance to initialize
!     \item[{[TimeStep]}]
!          The {\tt ESMF\_Clock}'s time step interval
!     \item[StartTime]
!          The {\tt ESMF\_Clock}'s starting time
!     \item[StopTime]
!          The {\tt ESMF\_Clock}'s stopping time
!     \item[{[RefTime]}]
!          The {\tt ESMF\_Clock}'s reference time
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!     
! !REQUIREMENTS:
!     TMG3.1, TMG3.4.4
!EOP
      IF ( PRESENT(TimeStep) ) clockint%TimeStep = TimeStep
      IF ( PRESENT(RefTime) )THEN
         clockint%RefTime = RefTime
      ELSE
         clockint%RefTime = StartTime
      END IF
      clockint%CurrTime = StartTime
      clockint%StartTime = StartTime
      clockint%StopTime = StopTime
      clockint%NumAlarms = 0
      clockint%AdvanceCount = 0
      ALLOCATE(clockint%AlarmList(MAX_ALARMS))
      ! TBH:  This incredible hack can be removed once ESMF_*Validate() 
      ! TBH:  can tell if a deep ESMF_* was created or not.  
      DO i = 1, MAX_ALARMS
        NULLIFY( clockint%AlarmList( i )%alarmint )
      ENDDO
      IF ( PRESENT( rc ) ) rc = ESMF_SUCCESS
    
      end subroutine ESMF_ClockSetOLD


! !IROUTINE: ESMF_ClockSet - Set clock properties -- for compatibility with ESMF 2.0.1

! !INTERFACE:
      subroutine ESMF_ClockSet(clock, TimeStep, StartTime, StopTime, &
                               RefTime, CurrTime, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(inout) :: clock
      type(ESMF_TimeInterval), intent(in), optional :: TimeStep
      type(ESMF_Time), intent(in), optional :: StartTime
      type(ESMF_Time), intent(in), optional :: StopTime
      type(ESMF_Time), intent(in), optional :: RefTime
      type(ESMF_Time), intent(in), optional :: CurrTime
      integer, intent(out), optional :: rc
! Local
      integer ierr
    
! !DESCRIPTION:
!     Initialize an {\tt ESMF\_Clock}
!     
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to initialize
!     \item[{[TimeStep]}]
!          The {\tt ESMF\_Clock}'s time step interval
!     \item[StartTime]
!          The {\tt ESMF\_Clock}'s starting time
!     \item[StopTime]
!          The {\tt ESMF\_Clock}'s stopping time
!     \item[{[RefTime]}]
!          The {\tt ESMF\_Clock}'s reference time
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!     
! !REQUIREMENTS:
!     TMG3.1, TMG3.4.4
!EOP
      ierr = ESMF_SUCCESS
      IF ( PRESENT(TimeStep) ) THEN
        CALL ESMF_ClockSetTimeStep ( clock, TimeStep, rc=ierr )
      ENDIF
      IF ( PRESENT(RefTime) ) clock%clockint%RefTime = RefTime
      IF ( PRESENT(StartTime) ) clock%clockint%StartTime = StartTime
      IF ( PRESENT(StopTime) ) clock%clockint%StopTime = StopTime
      IF ( PRESENT(CurrTime) ) THEN
        CALL ESMF_ClockSetCurrTime(clock, CurrTime, rc=ierr)
      ENDIF
      IF ( PRESENT(rc) ) rc = ierr

      end subroutine ESMF_ClockSet


! Create ESMF_Clock using ESMF 2.1.0+ semantics
      FUNCTION ESMF_ClockCreate( name, TimeStep, StartTime, StopTime, &
                                 RefTime, rc )
        ! return value
        type(ESMF_Clock) :: ESMF_ClockCreate
        ! !ARGUMENTS:
        character (len=*),       intent(in),  optional :: name
        type(ESMF_TimeInterval), intent(in), optional :: TimeStep
        type(ESMF_Time), intent(in) :: StartTime
        type(ESMF_Time), intent(in) :: StopTime
        type(ESMF_Time), intent(in), optional :: RefTime
        integer, intent(out), optional :: rc
        ! locals
        type(ESMF_Clock) :: clocktmp
         ! TBH:  ignore allocate errors, for now
        ALLOCATE( clocktmp%clockint )
        CALL ESMF_ClockSetOLD( clocktmp%clockint,   &
                               TimeStep= TimeStep,  &
                               StartTime=StartTime, &
                               StopTime= StopTime,  &
                               RefTime=RefTime, rc=rc )
        ESMF_ClockCreate = clocktmp
      END FUNCTION ESMF_ClockCreate

      !
      ! Deallocate memory for ESMF_Clock
      !
      SUBROUTINE ESMF_ClockDestroy( clock, rc )

         TYPE(ESMF_Clock), INTENT(INOUT) :: clock
         INTEGER,          INTENT(  OUT), OPTIONAL :: rc

         if (associated(clock%clockint)) then
            if (associated(clock%clockint%AlarmList)) deallocate(clock%clockint%AlarmList)
            deallocate(clock%clockint)
         endif

         ! TBH:  ignore deallocate errors, for now
         IF ( PRESENT( rc ) ) rc = ESMF_SUCCESS

      END SUBROUTINE ESMF_ClockDestroy


!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockGet - Get clock properties -- for compatibility with ESMF 2.0.1 

! tcraig added alarmCount for ccsm4, consistent with ESMF3 interface

! !INTERFACE:
      subroutine ESMF_ClockGet(clock, StartTime, CurrTime,       &
                               AdvanceCount, StopTime, TimeStep, &
                               PrevTime, RefTime, AlarmCount, &
                               rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(in) :: clock
      type(ESMF_Time), intent(out), optional :: StartTime
      type(ESMF_Time), intent(out), optional :: CurrTime
      type(ESMF_Time), intent(out), optional :: StopTime
      type(ESMF_Time), intent(out), optional :: PrevTime
      type(ESMF_Time), intent(out), optional :: RefTime
      integer(ESMF_KIND_I8), intent(out), optional :: AdvanceCount
      integer,         intent(out), optional :: AlarmCount
      type(ESMF_TimeInterval), intent(out), optional :: TimeStep
      integer, intent(out), optional :: rc
      integer :: ierr

! !DESCRIPTION:
!     Returns the number of times the {\tt ESMF\_Clock} has been advanced
!     (time stepped)
!
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to get the advance count from
!     \item[StartTime]
!          The start time
!     \item[CurrTime]
!          The current time
!     \item[AdvanceCount]
!          The number of times the {\tt ESMF\_Clock} has been advanced
!     \item[StopTime]
!          The {\tt ESMF\_Clock}'s stopping time
!     \item[{[TimeStep]}]
!          The {\tt ESMF\_Clock}'s time step interval
!     \item[{[PrevTime]}]
!          The {\tt ESMF\_Clock}'s previous current time
!     \item[{[PrevTime]}]
!          The {\tt ESMF\_Clock}'s reference time
!     \item[{[AlarmCount]}]
!          The {\tt ESMF\_Clock}'s number of valid alarms
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}

! !REQUIREMENTS:
!     TMG3.5.1
!EOP
      ierr = ESMF_SUCCESS

      IF ( PRESENT (StartTime) ) THEN
        CALL ESMF_ClockGetStartTime( clock, StartTime=StartTime, rc=ierr )
      ENDIF
      IF ( PRESENT (CurrTime) ) THEN
        CALL ESMF_ClockGetCurrTime( clock , CurrTime, ierr )
      ENDIF
      IF ( PRESENT (StopTime) ) THEN
        CALL ESMF_ClockGetStopTime( clock , StopTime, ierr )
      ENDIF
      IF ( PRESENT (AdvanceCount) ) THEN
        CALL ESMF_ClockGetAdvanceCount(clock, AdvanceCount, ierr)
      ENDIF
      IF ( PRESENT (TimeStep) ) THEN
        CALL ESMF_ClockGetTimeStep(clock, TimeStep, ierr)
      ENDIF
      IF ( PRESENT (PrevTime) ) THEN
        CALL ESMF_ClockGetPrevTime(clock, PrevTime, ierr)
      ENDIF
      IF ( PRESENT (RefTime) ) THEN
        CALL ESMF_ClockGetRefTime(clock, RefTime, ierr)
      ENDIF
      IF ( PRESENT (AlarmCount) ) THEN
        CALL ESMF_ClockGetNumAlarms(clock, AlarmCount, ierr)
      ENDIF

      IF ( PRESENT (rc) ) THEN
        rc = ierr
      ENDIF
    
      end subroutine ESMF_ClockGet


! !IROUTINE: ESMF_ClockGetAdvanceCount - Get the clock's advance count

! !INTERFACE:
      subroutine ESMF_ClockGetAdvanceCount(clock, AdvanceCount, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(in) :: clock
      integer(ESMF_KIND_I8), intent(out) :: AdvanceCount
      integer, intent(out), optional :: rc

! !DESCRIPTION:
!     Returns the number of times the {\tt ESMF\_Clock} has been advanced
!     (time stepped)
!
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to get the advance count from
!     \item[AdvanceCount]
!          The number of times the {\tt ESMF\_Clock} has been advanced
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}

! !REQUIREMENTS:
!     TMG3.5.1
!EOP

      AdvanceCount = clock%clockint%AdvanceCount

      IF ( PRESENT(rc) ) rc = ESMF_SUCCESS
    
      end subroutine ESMF_ClockGetAdvanceCount

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockGetTimeStep - Get a clock's timestep interval

! !INTERFACE:
      subroutine ESMF_ClockGetTimeStep(clock, TimeStep, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(in) :: clock
      type(ESMF_TimeInterval), intent(out) :: TimeStep
      integer, intent(out), optional :: rc

! !DESCRIPTION:
!     Get an {\tt ESMF\_Clock}'s timestep interval
!
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to get the time step from
!     \item[TimeStep]
!          The time step
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
! !REQUIREMENTS:
!     TMG3.5.2
!EOP

      TimeStep = clock%clockint%TimeStep
      IF ( PRESENT(rc) ) rc = ESMF_SUCCESS
    
      end subroutine ESMF_ClockGetTimeStep

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockSetTimeStep - Set a clock's timestep interval

! !INTERFACE:
      subroutine ESMF_ClockSetTimeStep(clock, TimeStep, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(inout) :: clock
      type(ESMF_TimeInterval), intent(in) :: TimeStep
      integer, intent(out), optional      :: rc

! !DESCRIPTION:
!     Set an {\tt ESMF\_Clock}'s timestep interval
!
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to set the time step
!     \item[TimeStep]
!          The time step
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
! !REQUIREMENTS:
!     TMG3.4.2
!EOP

      clock%clockint%TimeStep = TimeStep
      IF ( PRESENT(rc) ) rc = ESMF_SUCCESS

      end subroutine ESMF_ClockSetTimeStep

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockGetCurrTime - Get a clock's current time

! !INTERFACE:
      subroutine ESMF_ClockGetCurrTime(clock, CurrTime, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(in) :: clock
      type(ESMF_Time), intent(out) :: CurrTime
      integer, intent(out), optional :: rc

! !DESCRIPTION:
!     Get an {\tt ESMF\_Clock}'s current time     
!
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to get the current time from
!     \item[CurrTime]
!          The current time
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
! !REQUIREMENTS:
!     TMG3.5.4
!EOP

      CurrTime = clock%clockint%CurrTime
      IF ( PRESENT(rc) ) rc = ESMF_SUCCESS
      end subroutine ESMF_ClockGetCurrTime

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockSetCurrTime - Set a clock's current time

! !INTERFACE:
      subroutine ESMF_ClockSetCurrTime(clock, CurrTime, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(inout) :: clock
      type(ESMF_Time), intent(in) :: CurrTime
      integer, intent(out), optional :: rc

! !DESCRIPTION:
!     Set an {\tt ESMF\_Clock}'s current time
!
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to set the current time from
!     \item[CurrTime]
!          The current time
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
! !REQUIREMENTS:
!     TMG3.4.3
!EOP

      clock%clockint%CurrTime = CurrTime
      IF ( PRESENT(rc) ) rc = ESMF_SUCCESS
    
      end subroutine ESMF_ClockSetCurrTime

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockGetStartTime - Get a clock's start time

! !INTERFACE:
      subroutine ESMF_ClockGetStartTime(clock, StartTime, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(in) :: clock
      type(ESMF_Time), intent(out) :: StartTime
      integer, intent(out), optional :: rc

! !DESCRIPTION:
!     Get an {\tt ESMF\_Clock}'s start time
!
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to get the start time from
!     \item[StartTime]
!          The start time
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
! !REQUIREMENTS:
!     TMG3.5.3
!EOP

      StartTime = clock%clockint%StartTime
      IF ( PRESENT(rc) ) rc = ESMF_SUCCESS
    
      end subroutine ESMF_ClockGetStartTime

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockGetStopTime - Get a clock's stop time

! !INTERFACE:
      subroutine ESMF_ClockGetStopTime(clock, StopTime, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(in) :: clock
      type(ESMF_Time), intent(out) :: StopTime
      integer, intent(out), optional :: rc

! !DESCRIPTION:
!     Get an {\tt ESMF\_Clock}'s stop time
! 
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to get the stop time from
!     \item[StopTime]
!          The stop time
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
! !REQUIREMENTS:
!     TMG3.5.3
!EOP

      StopTime = clock%clockint%StopTime
      IF ( PRESENT(rc) ) rc = ESMF_SUCCESS
    
      end subroutine ESMF_ClockGetStopTime

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockGetRefTime - Get a clock's reference time

! !INTERFACE:
      subroutine ESMF_ClockGetRefTime(clock, RefTime, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(in) :: clock
      type(ESMF_Time), intent(out) :: RefTime
      integer, intent(out), optional :: rc

! !DESCRIPTION:
!     Get an {\tt ESMF\_Clock}'s reference time
!
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to get the reference time from
!     \item[RefTime]
!          The reference time
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
! !REQUIREMENTS:
!     TMG3.5.3
!EOP
      refTime = clock%clockint%RefTime
      IF ( PRESENT(rc) ) rc = ESMF_SUCCESS
      end subroutine ESMF_ClockGetRefTime

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockGetPrevTime - Get a clock's previous current time

! !INTERFACE:
      subroutine ESMF_ClockGetPrevTime(clock, PrevTime, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(in) :: clock
      type(ESMF_Time), intent(out) :: PrevTime
      integer, intent(out), optional :: rc

! !DESCRIPTION:
!     Get an {\tt ESMF\_Clock}'s previous current time
!
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to get the previous current time from
!     \item[PrevTime]
!          The previous current time
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
! !REQUIREMENTS:
!     TMG3.5.4
!EOP

      prevTime = Clock%clockint%CurrTime - Clock%clockint%TimeStep
      IF ( PRESENT(rc) ) rc = ESMF_SUCCESS
      end subroutine ESMF_ClockGetPrevTime

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockGetCurrSimTime - Get a clock's current simulation time

! !INTERFACE:
      subroutine ESMF_ClockGetCurrSimTime(clock, CurrSimTime, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(in) :: clock
      type(ESMF_TimeInterval), intent(out) :: CurrSimTime
      integer, intent(out), optional :: rc

! !DESCRIPTION:
!     Get an {\tt ESMF\_Clock}'s current simulation time
! 
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to get the current simulation time from
!     \item[CurrSimTime]
!          The current simulation time
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
! !REQUIREMENTS:
!     TMG3.5.5
!EOP
      CALL wrf_error_fatal( 'ESMF_ClockGetCurrSimTime not supported' )
      end subroutine ESMF_ClockGetCurrSimTime

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockGetPrevSimTime - Get a clock's previous simulation time

! !INTERFACE:
      subroutine ESMF_ClockGetPrevSimTime(clock, PrevSimTime, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(in) :: clock
      type(ESMF_TimeInterval), intent(out) :: PrevSimTime
      integer, intent(out), optional :: rc

! !DESCRIPTION:
!     Get an {\tt ESMF\_Clock}'s previous simulation time
!
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to get the previous simulation time from
!     \item[PrevSimTime]
!          The previous simulation time
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
! !REQUIREMENTS:
!     TMG3.5.5
!EOP
      CALL wrf_error_fatal( 'ESMF_ClockGetPrevSimTime not supported' )
      end subroutine ESMF_ClockGetPrevSimTime

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockAddAlarm - Add an alarm to a clock's alarm list

! !INTERFACE:
      subroutine ESMF_ClockAddAlarm(clock, Alarm, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(inout) :: clock
      type(ESMF_Alarm), intent(inout) :: Alarm
      integer, intent(out), optional :: rc

! !DESCRIPTION:
!     Add an {\tt ESMF\_Alarm} to an {\tt ESMF\_Clock}'s {\tt ESMF\_Alarm} list
!
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to add an {\tt ESMF\_Alarm} to
!     \item[Alarm]
!          The {\tt ESMF\_Alarm} to add to the {\tt ESMF\_Clock}'s
!          {\tt ESMF\_Alarm} list
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!   
! !REQUIREMENTS:
!     TMG4.1, TMG4.2
!EOP
    
      IF ( PRESENT( rc ) ) rc = ESMF_SUCCESS
      clock%clockint%NumAlarms = clock%clockint%NumAlarms + 1
      IF ( clock%clockint%NumAlarms > SIZE (clock%clockint%AlarmList) ) THEN
        CALL wrf_error_fatal ( 'ESMF_ClockAddAlarm:  too many alarms' )
      ELSE IF ( .NOT. ASSOCIATED( Alarm%alarmint ) ) THEN
        CALL wrf_error_fatal ( &
               'ESMF_ClockAddAlarm:  alarm not created' )
      ELSE
!TBH:  why do all this initialization here?  
        IF ( Alarm%alarmint%RingTimeSet ) THEN
           Alarm%alarmint%PrevRingTime = Alarm%alarmint%RingTime - &
                                         Alarm%alarmint%RingInterval
        ELSE
           Alarm%alarmint%PrevRingTime = clock%clockint%CurrTime
        ENDIF
        Alarm%alarmint%Ringing = .FALSE.

        ! finally, load the alarm into the list
        clock%clockint%AlarmList(clock%clockint%NumAlarms) = Alarm
      ENDIF
    
      end subroutine ESMF_ClockAddAlarm

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockGetAlarmList - Get a clock's alarm list

! !INTERFACE:
      subroutine ESMF_ClockGetAlarmList(clock, AlarmList, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(in) :: clock
      type(ESMF_Alarm), pointer :: AlarmList(:)
      integer, intent(out), optional :: rc

! !DESCRIPTION:
!     Get an {\tt ESMF\_Clock}'s {\tt ESMF\_Alarm} list     
!   
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to get the {\tt ESMF\_Alarm} list from
!     \item[AlarmList]
!          The {\tt ESMF\_Clock}'s {\tt ESMF\_Alarm} list
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!   
! !REQUIREMENTS:
!     TMG4.3
!EOP

      AlarmList => clock%clockint%AlarmList
      IF ( PRESENT(rc) ) rc = ESMF_SUCCESS

      end subroutine ESMF_ClockGetAlarmList

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockGetNumAlarms - Get the number of alarms in a clock's alarm list

! !INTERFACE:
      subroutine ESMF_ClockGetNumAlarms(clock, NumAlarms, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(in) :: clock
      integer, intent(out) :: NumAlarms
      integer, intent(out), optional :: rc

! !DESCRIPTION:
!     Get the number of {\tt ESMF\_Alarm}s in an {\tt ESMF\_Clock}'s
!       {\tt ESMF\_Alarm} list     
!   
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to get the number of {\tt ESMF\_Alarm}s from
!     \item[NumAlarms]
!          The number of {\tt ESMF\_Alarm}s in the {\tt ESMF\_Clock}'s
!            {\tt ESMF\_Alarm} list
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!   
! !REQUIREMENTS:
!     TMG4.3
!EOP

      NumAlarms = clock%clockint%NumAlarms
      IF ( PRESENT(rc) ) rc = ESMF_SUCCESS
    
      end subroutine ESMF_ClockGetNumAlarms

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockSyncToWallClock - Set clock's current time to wall clock time

! !INTERFACE:
      subroutine ESMF_ClockSyncToWallClock(clock, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(inout) :: clock
      integer, intent(out), optional :: rc
    
! !DESCRIPTION:
!     Set an {\tt ESMF\_Clock}'s current time to wall clock time     
!   
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to synchronize to wall clock time
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!   
! !REQUIREMENTS:
!     TMG3.4.5
!EOP
      CALL wrf_error_fatal( 'ESMF_ClockSyncToWallClock not supported' )
      end subroutine ESMF_ClockSyncToWallClock

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockAdvance - Advance a clock's current time by one time step

! !INTERFACE:
      subroutine ESMF_ClockAdvance(clock, RingingAlarmList, &
                                   NumRingingAlarms, rc)

use ESMF_TimeMod

! !ARGUMENTS:
      type(ESMF_Clock), intent(inout) :: clock
      type(ESMF_Alarm), dimension(MAX_ALARMS), intent(out), optional :: &
                                        RingingAlarmList
      integer, intent(out), optional :: NumRingingAlarms
      integer, intent(out), optional :: rc
! Local
      logical pred1, pred2, pred3
      integer i, n
      type(ESMF_Alarm) :: alarm
!   
! !DESCRIPTION:
!     Advance an {\tt ESMF\_Clock}'s current time by one time step
!  
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to advance
!     \item[{[RingingAlarmList]}]
!          Return a list of any ringing alarms after the time step
!     \item[{[NumRingingAlarms]}]
!          The number of ringing alarms returned
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!  
! !REQUIREMENTS:
!     TMG3.4.1
!EOP
      clock%clockint%CurrTime = clock%clockint%CurrTime + &
                                clock%clockint%TimeStep

      IF ( Present(NumRingingAlarms) ) NumRingingAlarms = 0
      clock%clockint%AdvanceCount = clock%clockint%AdvanceCount + 1
      DO i = 1, MAX_ALARMS
        alarm = clock%clockint%AlarmList(i)
        ! TBH:  This is really dangerous.  We need to be able to NULLIFY 
        ! TBH:  alarmint at compile-time (F95 synax) to make this safe.  
!$$$TBH:  see if F95 compile-time pointer-nullification is supported by all 
!$$$TBH:  compilers we support
        IF ( ASSOCIATED( alarm%alarmint ) ) THEN
          IF ( alarm%alarmint%Enabled ) THEN
            IF ( alarm%alarmint%RingIntervalSet ) THEN
              pred1 = .FALSE. ; pred2 = .FALSE. ; pred3 = .FALSE.
              IF ( alarm%alarmint%StopTimeSet ) THEN
                PRED1 = clock%clockint%CurrTime > alarm%alarmint%StopTime
              ENDIF
              IF ( alarm%alarmint%RingTimeSet ) THEN
                 PRED2 = ( alarm%alarmint%RingTime <= clock%clockint%CurrTime     &
                        .AND. clock%clockint%CurrTime < alarm%alarmint%RingTime + &
                              clock%clockint%TimeStep )
              ENDIF
              IF ( alarm%alarmint%RingIntervalSet ) THEN
                 PRED3 = ( alarm%alarmint%PrevRingTime + alarm%alarmint%RingInterval <= &
                           clock%clockint%CurrTime )
              ENDIF
              IF ( ( .NOT. ( pred1 ) ) .AND. &
                   ( ( pred2 ) .OR. ( pred3 ) ) ) THEN
                 alarm%alarmint%Ringing = .TRUE.
                 IF ( PRED3) alarm%alarmint%PrevRingTime = alarm%alarmint%PrevRingTime + &
                                                  alarm%alarmint%RingInterval
                 IF ( PRESENT( RingingAlarmList ) .AND. &
                      PRESENT ( NumRingingAlarms ) ) THEN
                   NumRingingAlarms = NumRingingAlarms + 1
                   RingingAlarmList( NumRingingAlarms ) = alarm
                 ENDIF
              ENDIF
            ELSE IF ( alarm%alarmint%RingTimeSet ) THEN
              IF ( alarm%alarmint%RingTime <= clock%clockint%CurrTime ) THEN
                 alarm%alarmint%Ringing = .TRUE.
                 IF ( PRESENT( RingingAlarmList ) .AND. &
                      PRESENT ( NumRingingAlarms ) ) THEN
                   NumRingingAlarms = NumRingingAlarms + 1
                   RingingAlarmList( NumRingingAlarms ) = alarm
                 ENDIF
              ENDIF
            ENDIF
            IF ( alarm%alarmint%StopTimeSet ) THEN
            ENDIF
          ENDIF
        ENDIF
        clock%clockint%AlarmList(i) = alarm
      ENDDO
      IF ( PRESENT( rc ) ) rc = ESMF_SUCCESS
    
      end subroutine ESMF_ClockAdvance

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockStopTimeDisable - NOOP for compatibility with ESMF 2.1.0+

! !INTERFACE:
      subroutine ESMF_ClockStopTimeDisable(clock, rc)
!
! !ARGUMENTS:
      type(ESMF_Clock), intent(in) :: clock
      integer, intent(out), optional :: rc

      rc = ESMF_SUCCESS

      end subroutine ESMF_ClockStopTimeDisable

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockIsStopTime - Has the clock reached its stop time ?

! !INTERFACE:
      function ESMF_ClockIsStopTime(clock, rc)
!
! !RETURN VALUE:
      logical :: ESMF_ClockIsStopTime

! !ARGUMENTS:
      type(ESMF_Clock), intent(in) :: clock
      integer, intent(out), optional :: rc

! !DESCRIPTION:
!     Return true if {\tt ESMF\_Clock} has reached its stop time, false 
!     otherwise     
!
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to check
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}

! !REQUIREMENTS:
!     TMG3.5.6
!EOP

      if ( clock%clockint%CurrTime .GE. clock%clockint%StopTime ) THEN
        ESMF_ClockIsStopTime = .TRUE.
      else
        ESMF_ClockIsStopTime = .FALSE.
      endif
      IF ( PRESENT( rc ) ) rc = ESMF_SUCCESS
    
      end function ESMF_ClockIsStopTime

!------------------------------------------------------------------------------
!
! This section defines the overridden Read, Write, Validate and Print methods
! from the ESMF_Base class
!
!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockRead - Restores a clock

! !INTERFACE:
      subroutine ESMF_ClockRead(clock, TimeStep, StartTime, StopTime, &
                                RefTime, CurrTime, PrevTime, AdvanceCount, &
                                AlarmList, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(out) :: clock
      type(ESMF_TimeInterval), intent(in) :: TimeStep
      type(ESMF_Time), intent(in) :: StartTime
      type(ESMF_Time), intent(in) :: StopTime
      type(ESMF_Time), intent(in) :: RefTime
      type(ESMF_Time), intent(in) :: CurrTime
      type(ESMF_Time), intent(in) :: PrevTime
      integer(ESMF_KIND_I8), intent(in) :: AdvanceCount
      type(ESMF_Alarm), dimension(MAX_ALARMS), intent(in) :: AlarmList
      integer, intent(out), optional :: rc
    
! !DESCRIPTION:
!     Restore an {\tt ESMF\_Clock}
!     
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to restore
!     \item[TimeStep]
!          The {\tt ESMF\_Clock}'s time step interval
!     \item[StartTime]
!          The {\tt ESMF\_Clock}'s starting time
!     \item[StopTime]
!          The {\tt ESMF\_Clock}'s stopping time
!     \item[RefTime]
!          The {\tt ESMF\_Clock}'s reference time
!     \item[CurrTime]
!          The {\tt ESMF\_Clock}'s current time
!     \item[PrevTime]
!          The {\tt ESMF\_Clock}'s previous time
!     \item[AdvanceCount]
!          The number of times the {\tt ESMF\_Clock} has been advanced
!     \item[AlarmList]
!          The {\tt ESMF\_Clock}'s {\tt ESMF\_Alarm} list
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!     
! !REQUIREMENTS:
!EOP
      CALL wrf_error_fatal( 'ESMF_ClockRead not supported' )
      end subroutine ESMF_ClockRead

!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_ClockWrite - Saves a clock

! !INTERFACE:
      subroutine ESMF_ClockWrite(clock, TimeStep, StartTime, StopTime, &
                            RefTime, CurrTime, PrevTime, AdvanceCount, &
                            AlarmList, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(in) :: clock
      type(ESMF_TimeInterval), intent(out) :: TimeStep
      type(ESMF_Time), intent(out) :: StartTime
      type(ESMF_Time), intent(out) :: StopTime
      type(ESMF_Time), intent(out) :: RefTime
      type(ESMF_Time), intent(out) :: CurrTime
      type(ESMF_Time), intent(out) :: PrevTime
      integer(ESMF_KIND_I8), intent(out) :: AdvanceCount
      type(ESMF_Alarm), dimension(MAX_ALARMS), intent(out) :: AlarmList
      integer, intent(out), optional :: rc
    
! !DESCRIPTION:
!     Save an {\tt ESMF\_Clock}
!     
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          The object instance to save
!     \item[TimeStep]
!          The {\tt ESMF\_Clock}'s time step interval
!     \item[StartTime]
!          The {\tt ESMF\_Clock}'s starting time
!     \item[StopTime]
!          The {\tt ESMF\_Clock}'s stopping time
!     \item[RefTime]
!          The {\tt ESMF\_Clock}'s reference time
!     \item[CurrTime]
!          The {\tt ESMF\_Clock}'s current time
!     \item[PrevTime]
!          The {\tt ESMF\_Clock}'s previous time
!     \item[AdvanceCount]
!          The number of times the {\tt ESMF\_Clock} has been advanced
!     \item[AlarmList]
!          The {\tt ESMF\_Clock}'s {\tt ESMF\_Alarm} list
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!     
! !REQUIREMENTS:
!EOP
      CALL wrf_error_fatal( 'ESMF_ClockWrite not supported' )
      end subroutine ESMF_ClockWrite

!------------------------------------------------------------------------------
!BOP
! !IROUTINE:  ESMF_ClockValidate - Validate a Clock's properties

! !INTERFACE:
      subroutine ESMF_ClockValidate(clock, opts, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(in) :: clock
      character (len=*), intent(in), optional :: opts
      integer, intent(out), optional :: rc

! !DESCRIPTION:
!     Perform a validation check on an {\tt ESMF\_Clock}'s properties
!
!     The arguments are:  
!     \begin{description}
!     \item[clock]
!          {\tt ESMF\_Clock} to validate
!     \item[{[opts]}]
!          Validate options
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description} 
!
! !REQUIREMENTS:
!     TMGn.n.n
!EOP
      CALL wrf_error_fatal( 'ESMF_ClockValidate not supported' )
      end subroutine ESMF_ClockValidate

!------------------------------------------------------------------------------
!BOP
! !IROUTINE:  ESMF_ClockPrint - Print out a Clock's properties

! !INTERFACE:
      subroutine ESMF_ClockPrint(clock, opts, rc)

! !ARGUMENTS:
      type(ESMF_Clock), intent(in) :: clock
      character (len=*), intent(in), optional :: opts
      integer, intent(out), optional :: rc

! !DESCRIPTION:
!     To support testing/debugging, print out an {\tt ESMF\_Clock}'s
!     properties.
! 
!     The arguments are:
!     \begin{description}
!     \item[clock]
!          {\tt ESMF\_Clock} to print out
!     \item[{[opts]}]
!          Print options
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
! !REQUIREMENTS:
!     TMGn.n.n
!EOP
      type(ESMF_Time) :: start_time
      type(ESMF_Time) :: stop_time
      type(ESMF_Time) :: curr_time
      type(ESMF_Time) :: ref_time
      type(ESMF_TimeInterval) :: timestep

      call ESMF_ClockGet( clock, startTime=start_time, &
                          stoptime=stop_time, currTime=curr_time, &
                          refTime=ref_time, timeStep=timestep, rc=rc )
      print *, 'Start time: '
      call ESMF_TimePrint( start_time )
      print *, 'Stop time: '
      call ESMF_TimePrint( stop_time )
      print *, 'Reference time: '
      call ESMF_TimePrint( ref_time )
      print *, 'Current time: '
      call ESMF_TimePrint( curr_time )
      print *, 'Time step: '
      call ESMF_TimeIntervalPrint( timestep)
      end subroutine ESMF_ClockPrint

!------------------------------------------------------------------------------

      end module ESMF_ClockMod
