! $Id$
!
! Earth System Modeling Framework
! Copyright (c) 2002-2025, 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 University of Illinois-NCSA License.
!
!==============================================================================
#define ESMF_FILENAME "ESMF_Calendar.F90"
!==============================================================================
!
!     ESMF Calendar Module
      module ESMF_CalendarMod
!
!==============================================================================
!
! This file contains the Calendar class definition and all Calendar class
! methods.
!
!------------------------------------------------------------------------------
! INCLUDES
#include "ESMF_TimeMgr.inc"
#include "ESMF.h"

!==============================================================================
!BOPI
! !MODULE: ESMF_CalendarMod
!
! !DESCRIPTION:
! Part of Time Manager Fortran API wrapper of C++ implementation.
!
! Defines Fortran wrapper entry points for corresponding
! C++ class { \tt ESMC\_Calendar} implementation.
!
! See {\tt ../include/ESMC\_Calendar.h} for complete description.
!
!------------------------------------------------------------------------------
! !USES:
      ! inherit from ESMF base class
      use ESMF_BaseMod
      use ESMF_UtilTypesMod
      use ESMF_InitMacrosMod
      use ESMF_LogErrMod
      use ESMF_IOUtilMod

      implicit none
!
!------------------------------------------------------------------------------
! !PRIVATE TYPES:
      private
!------------------------------------------------------------------------------

!------------------------------------------------------------------------------
!     ! ESMF_CalKind_Flag
!
!     ! Fortran "enum" type to match C++ ESMC_CalKind_Flag enum

      ! TODO: add isInit init macro infrastructure to initialize calkindflag ?
      !       to 0 (to detect unset) or possibly 8 (default 
      !       ESMF_CALKIND_NOCALENDAR)
      type ESMF_CalKind_Flag
#ifndef ESMF_NO_SEQUENCE
      sequence
#endif
      private
        integer :: calkindflag
      end type

      type(ESMF_CalKind_Flag), parameter :: &
                            ESMF_CALKIND_GREGORIAN =    ESMF_CalKind_Flag(1), &
                            ESMF_CALKIND_JULIAN =       ESMF_CalKind_Flag(2), &
                            ESMF_CALKIND_JULIANDAY =    ESMF_CalKind_Flag(3), &
                            ESMF_CALKIND_MODJULIANDAY = ESMF_CalKind_Flag(4), &
                           ! like Gregorian, except Feb always has 28 days
                            ESMF_CALKIND_NOLEAP =       ESMF_CalKind_Flag(5), & 
                           ! 12 months, 30 days each
                            ESMF_CALKIND_360DAY =       ESMF_CalKind_Flag(6), & 
                           ! user defined
                            ESMF_CALKIND_CUSTOM =       ESMF_CalKind_Flag(7), &
                           ! track base time seconds only
                            ESMF_CALKIND_NOCALENDAR =   ESMF_CalKind_Flag(8)

!------------------------------------------------------------------------------
!     ! ESMF_Calendar
!
      type ESMF_Calendar
#ifndef ESMF_NO_SEQUENCE
      sequence
#endif
      private
        type(ESMF_Pointer) :: this
        ESMF_INIT_DECLARE
      end type
!
!------------------------------------------------------------------------------
! !PUBLIC TYPES:
      public ESMF_CalKind_Flag
      public ESMF_CALKIND_GREGORIAN, ESMF_CALKIND_JULIAN, &
             ESMF_CALKIND_JULIANDAY, ESMF_CALKIND_MODJULIANDAY, &
             ESMF_CALKIND_NOLEAP,    ESMF_CALKIND_360DAY, &
             ESMF_CALKIND_CUSTOM,    ESMF_CALKIND_NOCALENDAR
      public ESMF_Calendar
!------------------------------------------------------------------------------
!
! !PUBLIC MEMBER FUNCTIONS:

! - ESMF-public methods:
      public operator(==)
      public operator(/=)
      public assignment(=)
      public ESMF_CalendarCreate
      public ESMF_CalendarDestroy
      public ESMF_CalendarFinalize
      public ESMF_CalendarGet
      public ESMF_CalendarInitialize
      public ESMF_CalendarIsCreated
      public ESMF_CalendarIsLeapYear
      public ESMF_CalendarPrint
      public ESMF_CalendarReadRestart
      public ESMF_CalendarSet
      public ESMF_CalendarSetDefault
      public ESMF_CalendarValidate
      public ESMF_CalendarWriteRestart

! - ESMF-internal methods:
      public ESMF_CalendarGetInit
      public ESMF_CalendarSetInitCreated

!EOPI

! !PRIVATE MEMBER FUNCTIONS:
      private ESMF_CalendarEQ
      private ESMF_CalendarNE
      private ESMF_CalendarKindEQ
      private ESMF_CalendarKindNE
      private ESMF_CalendarCalAndKindEQ
      private ESMF_CalendarCalAndKindNE
      private ESMF_CalendarKindAndCalEQ
      private ESMF_CalendarKindAndCalNE
      private ESMF_CalendarCreateBuiltIn
      private ESMF_CalendarCreateCopy
      private ESMF_CalendarCreateCustom
      private ESMF_CalendarIsLeapYearI4
      private ESMF_CalendarIsLeapYearI8
      private ESMF_CalendarSetBuiltIn
      private ESMF_CalendarSetCustom
      private ESMF_CalendarSetDefaultKind
      private ESMF_CalendarSetDefaultCal

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

!==============================================================================
! 
! INTERFACE BLOCKS
! 
!==============================================================================

interface assignment (=)
  module procedure ESMF_CalKindToInt
  module procedure ESMF_IntToCalKind
end interface

!==============================================================================
!BOP
! !IROUTINE:  ESMF_CalendarAssignment(=) - Assign a Calendar to another Calendar
!
! !INTERFACE:
!     interface assignment(=)
!     calendar1 = calendar2
!
! !ARGUMENTS:
!     type(ESMF_Calendar) :: calendar1
!     type(ESMF_Calendar) :: calendar2
! 
!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Assign {\tt calendar1} as an alias to the same {\tt ESMF\_Calendar} 
!     object in memory as {\tt calendar2}. If {\tt calendar2} is invalid, then 
!     {\tt calendar1} will be equally invalid after the assignment.
!
!     The arguments are:
!     \begin{description} 
!     \item[calendar1] 
!          The {\tt ESMF\_Calendar} object on the left hand side of the 
!          assignment.
!     \item[calendar2] 
!          The {\tt ESMF\_Calendar} object on the right hand side of the 
!          assignment.
!     \end{description}
!
!EOP
! !PRIVATE MEMBER FUNCTIONS:
!     None, documentation only, to describe the behavior of the default 
!     Fortran assignment(=).
!
! !REQUIREMENTS:
!     API review 11/2010.
! 
!     end interface
! 
!------------------------------------------------------------------------------
!BOP
! !IROUTINE:  ESMF_CalendarOperator(==) - Test if Calendar argument 1 is equal to Calendar argument 2
!
! !INTERFACE:
      interface operator(==)
!     if (<calendar argument 1> == <calendar argument 2>) then ... endif
!                                 OR
!     result = (<calendar argument 1> == <calendar argument 2>)
!
! !RETURN VALUE:
!     logical :: result
!
! !ARGUMENTS:
!     <calendar argument 1>, see below for supported values
!     <calendar argument 2>, see below for supported values
!
! !DESCRIPTION:
!     \begin{sloppypar}
!     Overloads the (==) operator for the {\tt ESMF\_Calendar} class.
!     Compare an {\tt ESMF\_Calendar} object or {\tt ESMF\_CalKind\_Flag} with
!     another calendar object or calendar kind for equality.  Return
!     {\tt .true.} if equal, {\tt .false.} otherwise.  Comparison is based on
!     calendar kind, which is a property of a calendar object.
!     \end{sloppypar}
!
!     If both arguments are {\tt ESMF\_Calendar} objects, and both are of  
!     type {\tt ESMF\_CALKIND\_CUSTOM}, then all the calendar's properties, 
!     except name, are compared.
!
!     If both arguments are {\tt ESMF\_Calendar} objects, and either of them
!     is not in the {\tt ESMF\_INIT\_CREATED} status, an error will be logged.
!     However, this does not affect the return value, which is {\tt .true.} 
!     when both arguments are in the {\em same} status, and {\tt .false.}
!     otherwise.
!
!     If one argument is an {\tt ESMF\_Calendar} object, and the other is an
!     {\tt ESMF\_CalKind\_Flag}, and the calendar object is not in the
!     {\tt ESMF\_INIT\_CREATED} status, an error will be logged and
!     {\tt .false.} will be returned.
!
!     Supported values for <calendar argument 1> are:
!     \begin{description}
!     \item type(ESMF\_Calendar),     intent(in) :: calendar1
!     \item type(ESMF\_CalKind\_Flag), intent(in) :: calkindflag1
!     \end{description}
!     Supported values for <calendar argument 2> are:
!     \begin{description}
!     \item type(ESMF\_Calendar),     intent(in) :: calendar2
!     \item type(ESMF\_CalKind\_Flag), intent(in) :: calkindflag2
!     \end{description}
!
!     The arguments are:
!     \begin{description}   
!     \item[<calendar argument 1>]
!          The {\tt ESMF\_Calendar} object or {\tt ESMF\_CalKind\_Flag} on the
!          left hand side of the equality operation.
!     \item[<calendar argument 2>]
!          The {\tt ESMF\_Calendar} object or {\tt ESMF\_CalKind\_Flag} on the
!          right hand side of the equality operation.
!     \end{description}
!
!EOP
! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_CalendarEQ              ! internal implementation
      module procedure ESMF_CalendarKindEQ          ! internal implementation
      module procedure ESMF_CalendarCalAndKindEQ    ! internal implementation
      module procedure ESMF_CalendarKindAndCalEQ    ! internal implementation
!
      end interface
!
!
!------------------------------------------------------------------------------
!BOP
! !IROUTINE:  ESMF_CalendarOperator(/=) - Test if Calendar argument 1 is not equal to Calendar argument 2
!
! !INTERFACE:
      interface operator(/=)
!     if (<calendar argument 1> /= <calendar argument 2>) then ... endif
!                                 OR
!     result = (<calendar argument 1> /= <calendar argument 2>)
!
! !RETURN VALUE:
!     logical :: result
!
! !ARGUMENTS:
!     <calendar argument 1>, see below for supported values
!     <calendar argument 2>, see below for supported values
!
! !DESCRIPTION:
!     \begin{sloppypar}
!     Overloads the (/=) operator for the {\tt ESMF\_Calendar} class.
!     Compare a {\tt ESMF\_Calendar} object or {\tt ESMF\_CalKind\_Flag} with
!     another calendar object or calendar kind for inequality.  Return
!     {\tt .true.} if not equal, {\tt .false.} otherwise.  Comparison is based
!     on calendar kind, which is a property of a calendar object.
!     \end{sloppypar}
!
!     If both arguments are {\tt ESMF\_Calendar} objects, and both are of  
!     type {\tt ESMF\_CALKIND\_CUSTOM}, then all the calendar's properties,
!     except name, are compared.
!
!     If both arguments are {\tt ESMF\_Calendar} objects, and either of them
!     is not in the {\tt ESMF\_INIT\_CREATED} status, an error will be logged.
!     However, this does not affect the return value, which is {\tt .true.} 
!     when both arguments are {\em not} in the {\em same} status, and
!     {\tt .false.} otherwise.
!
!     If one argument is an {\tt ESMF\_Calendar} object, and the other is an
!     {\tt ESMF\_CalKind\_Flag}, and the calendar object is not in the
!     {\tt ESMF\_INIT\_CREATED} status, an error will be logged and
!     {\tt .true.} will be returned.
!
!     Supported values for <calendar argument 1> are:
!     \begin{description}
!     \item type(ESMF\_Calendar),     intent(in) :: calendar1
!     \item type(ESMF\_CalKind\_Flag), intent(in) :: calkindflag1
!     \end{description}
!     Supported values for <calendar argument 2> are:
!     \begin{description}
!     \item type(ESMF\_Calendar),     intent(in) :: calendar2
!     \item type(ESMF\_CalKind\_Flag), intent(in) :: calkindflag2
!     \end{description}
!
!     The arguments are:
!     \begin{description}   
!     \item[<calendar argument 1>]
!          The {\tt ESMF\_Calendar} object or {\tt ESMF\_CalKind\_Flag} on the
!          left hand side of the non-equality operation.
!     \item[<calendar argument 2>]
!          The {\tt ESMF\_Calendar} object or {\tt ESMF\_CalKind\_Flag} on the
!          right hand side of the non-equality operation.
!     \end{description}
!
!EOP
! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_CalendarNE              ! internal implementation
      module procedure ESMF_CalendarKindNE          ! internal implementation
      module procedure ESMF_CalendarCalAndKindNE    ! internal implementation
      module procedure ESMF_CalendarKindAndCalNE    ! internal implementation
!
      end interface
!
!
!------------------------------------------------------------------------------
!BOPI
! !IROUTINE: ESMF_CalendarCreate - Create an ESMF Calendar
!
! !INTERFACE:
      interface ESMF_CalendarCreate

! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_CalendarCreateBuiltIn
      module procedure ESMF_CalendarCreateCopy
      module procedure ESMF_CalendarCreateCustom

! !DESCRIPTION:
!     This interface provides a single entry point for {\tt ESMF\_Calendar}
!     Create methods.
!
!EOPI
      end interface
!
!------------------------------------------------------------------------------
!BOPI
! !IROUTINE: ESMF_CalendarIsLeapYear - Determine if given year is a leap year
!
! !INTERFACE:
      interface ESMF_CalendarIsLeapYear

! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_CalendarIsLeapYearI4
      module procedure ESMF_CalendarIsLeapYearI8

! !DESCRIPTION:
!     This interface provides a single entry point for {\tt ESMF\_Calendar}
!     IsLeapYear methods.
!
!EOPI
      end interface
!
!------------------------------------------------------------------------------
!BOPI
! !IROUTINE: ESMF_CalendarSet - Set properties of an ESMF Calendar
!
! !INTERFACE:
      interface ESMF_CalendarSet

! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_CalendarSetBuiltIn
      module procedure ESMF_CalendarSetCustom

! !DESCRIPTION:
!     This interface provides a single entry point for {\tt ESMF\_Calendar}
!     Set methods.
!
!EOPI
      end interface
!
!------------------------------------------------------------------------------
!BOPI
! !IROUTINE: ESMF_CalendarSetDefault - Set the default ESMF Calendar
!
! !INTERFACE:
      interface ESMF_CalendarSetDefault

! !PRIVATE MEMBER FUNCTIONS:
      module procedure ESMF_CalendarSetDefaultKind
      module procedure ESMF_CalendarSetDefaultCal

! !DESCRIPTION:
!     This interface provides a single entry point for {\tt ESMF\_Calendar}
!     Set default methods.
!
!EOPI
      end interface
!
!==============================================================================

      contains

subroutine ESMF_CalKindToInt(lhsInt, rhsCalKind)
  integer,                  intent(out) :: lhsInt
  type(ESMF_CalKind_Flag),  intent(in)  :: rhsCalKind
  lhsInt = rhsCalKind%calkindflag
end subroutine

subroutine ESMF_IntToCalKind(lhsCalKind, rhsInt)
  type(ESMF_CalKind_Flag),  intent(out) :: lhsCalKind
  integer,                  intent(in)  :: rhsInt
  lhsCalKind = ESMF_CalKind_Flag(rhsInt)
end subroutine

!==============================================================================
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarGetInit()"
!BOPI
! !IROUTINE:  ESMF_CalendarGetInit - Get initialization status.

! !INTERFACE:
      function ESMF_CalendarGetInit(d)
!
! !ARGUMENTS:
      type(ESMF_Calendar), intent(in), optional :: d
      ESMF_INIT_TYPE                            :: ESMF_CalendarGetInit
!
! !DESCRIPTION:
!     Get the initialization status of the Deep class {\tt calendar}. 
!
!     The arguments are:
!     \begin{description}
!     \item [{[d]}]
!           {\tt ESMF\_Calendar} from which to retrieve status.
!     \end{description}
!
!EOPI

      if (present(d)) then
        ESMF_CalendarGetInit = ESMF_INIT_GET(d)
      else
        ESMF_CalendarGetInit = ESMF_INIT_CREATED
      endif

      end function ESMF_CalendarGetInit

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarSetInitCreated()"
!BOPI
! !IROUTINE: ESMF_CalendarSetInitCreated - Set Calendar init code to "CREATED"

! !INTERFACE:
      subroutine ESMF_CalendarSetInitCreated(c, rc)
!
! !ARGUMENTS:
      type(ESMF_Calendar), intent(inout),  optional :: c
      integer,             intent(out),    optional :: rc  
!         
!
! !DESCRIPTION:
!     Set init code in Calendar object to "CREATED".
! 
!     Used by other classes to set the isInit value of a calendar, since it
!     is private to the {\tt ESMF\_Calendar} class.  Within the 
!     {\tt ESMF\_Calendar} class, the macro {\tt ESMF\_INIT\_SET\_CREATED()}
!     is used instead, since the {\tt ESMF\_Calendar} class and its methods
!     are encapsulated within the same module.  This gives the calendar 
!     methods direct access to the private isInit member.  Compare to the 
!     other TimeMgr classes which have their types defined in separate
!     modules from their methods, due to mutual dependencies.  They must
!     call their own {\tt ESMF\_*Init*()} method rather than use the 
!     {\tt ESMF\_INIT\_SET\_*()} macro.
!
!     The arguments are:
!     \begin{description}
!     \item[{[c]}] 
!          Specified {\tt ESMF\_Calendar} object.
!     \item[{[rc]}] 
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOPI
!------------------------------------------------------------------------------

      ! Set return code to not implemented
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
    
      ! Set init code
      if (present(c)) then
        ESMF_INIT_SET_CREATED(c)
      endif

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
    
      end subroutine ESMF_CalendarSetInitCreated

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


!==============================================================================
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarCreateBuiltIn()"
!BOP
! !IROUTINE: ESMF_CalendarCreate - Create a new ESMF Calendar of built-in type

! !INTERFACE:
      ! Private name; call using ESMF_CalendarCreate()
      function ESMF_CalendarCreateBuiltIn(calkindflag, keywordEnforcer, &
        name, rc)

! !RETURN VALUE:
      type(ESMF_Calendar) :: ESMF_CalendarCreateBuiltIn

! !ARGUMENTS:
      type(ESMF_CalKind_Flag), intent(in)            :: calkindflag
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      character (len=*),       intent(in),  optional :: name
      integer,                 intent(out), optional :: rc

!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Creates and sets a {\tt calendar} to the given built-in
!     {\tt ESMF\_CalKind\_Flag}. 
!
!     The arguments are:
!     \begin{description}
!     \item[calkindflag]
!          The built-in {\tt ESMF\_CalKind\_Flag}.  Valid values are:
!            \newline
!            {\tt ESMF\_CALKIND\_360DAY}, 
!            \newline
!            {\tt ESMF\_CALKIND\_GREGORIAN},
!            \newline
!            {\tt ESMF\_CALKIND\_JULIAN}, 
!            \newline
!            {\tt ESMF\_CALKIND\_JULIANDAY},
!            \newline
!            {\tt ESMF\_CALKIND\_MODJULIANDAY}, 
!            \newline
!            {\tt ESMF\_CALKIND\_NOCALENDAR},
!            \newline
!            and {\tt ESMF\_CALKIND\_NOLEAP}.
!            \newline
!          See Section ~\ref{subsec:Calendar_options} for a description of each
!          calendar kind.
!     \item[{[name]}]
!          The name for the newly created calendar.  If not specified, a
!          default unique name will be generated: "CalendarNNN" where NNN
!          is a unique sequence number from 001 to 999.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!    
!EOP

      ! initialize name length to zero for non-existent name
      integer :: nameLen, localrc

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      nameLen = 0

      ! get length of given name for C++ validation
      if (present(name)) then
        nameLen = len_trim(name)
      end if
    
      ! invoke C to C++ entry point
      call c_ESMC_CalendarCreateBuiltIn(ESMF_CalendarCreateBuiltIn, nameLen, &
                                        name, calkindflag, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return
    
      ! mark output as successfully initialized
      ESMF_INIT_SET_CREATED(ESMF_CalendarCreateBuiltIn)

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end function ESMF_CalendarCreateBuiltIn
    
!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarCreateCopy()"
!BOP    
! !IROUTINE: ESMF_CalendarCreate - Create a copy of an ESMF Calendar

! !INTERFACE:
      ! Private name; call using ESMF_CalendarCreate()
      function ESMF_CalendarCreateCopy(calendar, keywordEnforcer, rc)

! !RETURN VALUE:
      type(ESMF_Calendar) :: ESMF_CalendarCreateCopy

! !ARGUMENTS:
      type(ESMF_Calendar), intent(in)            :: calendar
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      integer,             intent(out), optional :: rc

!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Creates a complete (deep) copy of a given {\tt ESMF\_Calendar}.
!
!     The arguments are:
!     \begin{description}
!     \item[calendar]
!        The {\tt ESMF\_Calendar} to copy.
!     \item[{[rc]}]
!        Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOP
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      ! check input
      ESMF_INIT_CHECK_DEEP(ESMF_CalendarGetInit,calendar,rc)

      ! invoke C to C++ entry point to copy calendar
      call c_ESMC_CalendarCreateCopy(ESMF_CalendarCreateCopy, calendar, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! mark output as successfully initialized
      ESMF_INIT_SET_CREATED(ESMF_CalendarCreateCopy)

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end function ESMF_CalendarCreateCopy

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarCreateCustom()"
!BOP
! !IROUTINE: ESMF_CalendarCreate - Create a new custom ESMF Calendar

! !INTERFACE:
      ! Private name; call using ESMF_CalendarCreate()
      function ESMF_CalendarCreateCustom(keywordEnforcer, &
        daysPerMonth, secondsPerDay, &
        daysPerYear, daysPerYearDn, daysPerYearDd, name, rc)

! !RETURN VALUE:
      type(ESMF_Calendar) :: ESMF_CalendarCreateCustom

! !ARGUMENTS:
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      integer,               intent(in),  optional :: daysPerMonth(:)
      integer(ESMF_KIND_I4), intent(in),  optional :: secondsPerDay
      integer(ESMF_KIND_I4), intent(in),  optional :: daysPerYear
      integer(ESMF_KIND_I4), intent(in),  optional :: daysPerYearDn
      integer(ESMF_KIND_I4), intent(in),  optional :: daysPerYearDd
      character (len=*),     intent(in),  optional :: name
      integer,               intent(out), optional :: rc

!
! !DESCRIPTION:
!     Creates a custom {\tt ESMF\_Calendar} and sets its properties.
!
!     The arguments are:
!     \begin{description}
!     \item[{[daysPerMonth]}]
!          Integer array of days per month, for each month of the year.
!          The number of months per year is variable and taken from the
!          size of the array.  If unspecified, months per year = 0,
!          with the days array undefined.
!     \item[{[secondsPerDay]}]
!          Integer number of seconds per day.  Defaults to 0 if not 
!          specified.
!     \item[{[daysPerYear]}]
!          Integer number of days per year.  Use with daysPerYearDn and
!          daysPerYearDd (see below) to specify a days-per-year calendar
!          for any planetary body.  Default = 0.
!     \item[{[daysPerYearDn]}]
!          \begin{sloppypar}
!          Integer numerator portion of fractional number of days per year
!          (daysPerYearDn/daysPerYearDd).
!          Use with daysPerYear (see above) and daysPerYearDd (see below) to
!          specify a days-per-year calendar for any planetary body.
!          Default = 0.
!          \end{sloppypar}
!     \item[{[daysPerYearDd]}]
!          Integer denominator portion of fractional number of days per year
!          (daysPerYearDn/daysPerYearDd).
!          Use with daysPerYear and daysPerYearDn (see above) to
!          specify a days-per-year calendar for any planetary body.
!          Default = 1.
!     \item[{[name]}]
!          The name for the newly created calendar.  If not specified, a
!          default unique name will be generated: "CalendarNNN" where NNN
!          is a unique sequence number from 001 to 999.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!     
!EOP

      ! initialize name length to zero for non-existent name
      !   and initialize number of months per year to zero for not-present
      !   daysPerMonth
      integer :: nameLen, monthsPerYear
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      nameLen = 0
      monthsPerYear = 0

      ! get length of given name for C++ validation
      if (present(name)) then
        nameLen = len_trim(name)
      end if

      ! get size of given daysPerMonth array for C++ validation
      if (present(daysPerMonth)) then
        monthsPerYear = size(daysPerMonth)
      end if

      ! invoke C to C++ entry point
      if (present(daysPerMonth)) then
        call c_ESMC_CalendarCreateCustom1(ESMF_CalendarCreateCustom, &
                                         nameLen, name, &
                                         daysPerMonth(1), monthsPerYear, &
                                         secondsPerDay, &
                                         daysPerYear, daysPerYearDn, &
                                         daysPerYearDd, localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) return
      else
        call c_ESMC_CalendarCreateCustom0(ESMF_CalendarCreateCustom, &
                                         nameLen, name, &
                                         monthsPerYear, &
                                         secondsPerDay, &
                                         daysPerYear, daysPerYearDn, &
                                         daysPerYearDd, localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) return
      end if
    
      ! mark output as successfully initialized
      ESMF_INIT_SET_CREATED(ESMF_CalendarCreateCustom)

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end function ESMF_CalendarCreateCustom
    
!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarDestroy()"
!BOP
! !IROUTINE: ESMF_CalendarDestroy - Release resources associated with a Calendar
!
! !INTERFACE:
      subroutine ESMF_CalendarDestroy(calendar, keywordEnforcer, rc)
!
! !ARGUMENTS:
      type(ESMF_Calendar), intent(inout)          :: calendar
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      integer,             intent(out),  optional :: rc
!
!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Releases resources associated with this {\tt ESMF\_Calendar}.
!
!     The arguments are:
!     \begin{description}
!     \item[calendar]
!       Release resources associated with this {\tt ESMF\_Calendar} and mark the
!       object as invalid.  It is an error to pass this object into any other
!       routines after being destroyed.
!     \item[[rc]]
!       Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOP
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      ! check input
      ESMF_INIT_CHECK_DEEP(ESMF_CalendarGetInit,calendar,rc)

      ! invoke C to C++ entry point
      call c_ESMC_CalendarDestroy(calendar, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! mark output as successfully deleted
      ESMF_INIT_SET_DELETED(calendar)

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_CalendarDestroy

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarFinalize()"
!BOPI
! !IROUTINE: ESMF_CalendarFinalize
!
! !INTERFACE:
      subroutine ESMF_CalendarFinalize(keywordEnforcer, rc)
!
! !ARGUMENTS:
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      integer, intent(out), optional :: rc
!
! !DESCRIPTION:
!     Releases all internal built-in calendars.
!
!     The arguments are:
!     \begin{description}
!     \item[[rc]]
!       Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOPI
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

     ! invoke C to C++ entry point
      call c_ESMC_CalendarFinalize(localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_CalendarFinalize

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarGet()"
!BOP
! !IROUTINE: ESMF_CalendarGet - Get Calendar properties

! !INTERFACE:
      subroutine ESMF_CalendarGet(calendar, keywordEnforcer, &
        name, calkindflag, daysPerMonth, monthsPerYear, &
        secondsPerDay, secondsPerYear, &
        daysPerYear, daysPerYearDn, daysPerYearDd, rc)

! !ARGUMENTS:
      type(ESMF_Calendar),    intent(in)            :: calendar
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      type(ESMF_CalKind_Flag),intent(out), optional :: calkindflag
      integer,                intent(out), optional :: daysPerMonth(:)
      integer,                intent(out), optional :: monthsPerYear
      integer(ESMF_KIND_I4),  intent(out), optional :: secondsPerDay
      integer(ESMF_KIND_I4),  intent(out), optional :: secondsPerYear
      integer(ESMF_KIND_I4),  intent(out), optional :: daysPerYear
      integer(ESMF_KIND_I4),  intent(out), optional :: daysPerYearDn
      integer(ESMF_KIND_I4),  intent(out), optional :: daysPerYearDd
      character (len=*),      intent(out), optional :: name
      integer,                intent(out), optional :: rc

!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Gets one or more of an {\tt ESMF\_Calendar}'s properties.
!
!     The arguments are:
!     \begin{description}
!     \item[calendar]
!          The object instance to query.
!     \item[{[calkindflag]}]
!          The {\tt CalKind\_Flag} ESMF\_CALKIND\_GREGORIAN, 
!          ESMF\_CALKIND\_JULIAN, etc.
!     \item[{[daysPerMonth]}]
!          Integer array of days per month, for each month of the year.
!     \item[{[monthsPerYear]}]
!          Integer number of months per year; the size of the
!          daysPerMonth array.
!     \item[{[secondsPerDay]}]
!          Integer number of seconds per day.
!     \item[{[secondsPerYear]}]
!          Integer number of seconds per year.
!     \item[{[daysPerYear]}]
!          Integer number of days per year.  For calendars with
!          intercalations, daysPerYear is the number of days for years without
!          an intercalation.  For other calendars, it is the number of days in
!          every year.
!     \item[{[daysPerYearDn]}]
!          \begin{sloppypar}
!          Integer fractional number of days per year (numerator).
!          For calendars with intercalations, daysPerYearDn/daysPerYearDd is
!          the average fractional number of days per year (e.g. 25/100 for
!          Julian 4-year intercalation).  For other calendars, it is zero.
!          \end{sloppypar}
!     \item[{[daysPerYearDd]}]
!          Integer fractional number of days per year (denominator).  See
!          daysPerYearDn above.
!     \item[{[name]}]
!          The name of this calendar.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!     
!EOP

      ! temp name for C++ to fill
      character (len=ESMF_MAXSTR) :: tempName

      ! initialize name lengths to zero for non-existent name
      !   and initialize daysPerMonth list size to zero for not-present list
      integer :: nameLen
      integer :: tempNameLen
      integer :: sizeofDaysPerMonth
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      ! check input
      ESMF_INIT_CHECK_DEEP(ESMF_CalendarGetInit,calendar,rc)

      nameLen = 0
      tempNameLen = 0
      sizeofDaysPerMonth = 0

      ! get length of given name for C++ validation
      if (present(name)) then
        nameLen = len(name)
      end if

      ! get size of given daysPerMonth list for C++ validation
      if (present(daysPerMonth)) then   
        sizeofDaysPerMonth = size(daysPerMonth)
      end if

      ! invoke C to C++ entry point

      if (present(daysPerMonth)) then
        call c_ESMC_CalendarGet1(calendar, nameLen, tempNameLen, tempName, &
                         calkindflag, &
                         daysPerMonth(1), sizeofDaysPerMonth, &
                         monthsPerYear, secondsPerDay, secondsPerYear, &
                         daysPerYear, daysPerYearDn, daysPerYearDd, localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) return
      else
        call c_ESMC_CalendarGet0(calendar, nameLen, tempNameLen, tempName, &
                         calkindflag, &
                         sizeofDaysPerMonth, &
                         monthsPerYear, secondsPerDay, secondsPerYear, &
                         daysPerYear, daysPerYearDn, daysPerYearDd, localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) return
      end if
    
      ! copy temp name back to given name to restore native Fortran
      !   storage style
      if (present(name)) then
        name = tempName(1:tempNameLen)
      endif

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_CalendarGet
    
!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarInitialize()"
!BOPI
! !IROUTINE: ESMF_CalendarInitialize - Initialize the default Calendar kind

! !INTERFACE:
      subroutine ESMF_CalendarInitialize(keywordEnforcer, calkindflag, rc)

! !ARGUMENTS:
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      type(ESMF_CalKind_Flag), intent(in),  optional :: calkindflag
      integer,                 intent(out), optional :: rc

! !DESCRIPTION:
!     Initializes the default {\tt calendar} to the given type.  Subsequent
!     Time Manager operations requiring a calendar where one isn't specified
!     will use the default internal calendar of this type.
!
!     The arguments are:
!     \begin{description}
!     \item[{[calkindflag]}]
!          The calendar kind to initialize the default to.  If not specified,
!          the default is set to {\tt ESMF\_CALKIND\_NOCALENDAR}.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!    
!EOPI
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL
    
      ! invoke C to C++ entry point
      call c_ESMC_CalendarInitialize(calkindflag, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_CalendarInitialize


! -------------------------- ESMF-public method -------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarIsCreated()"
!BOP
! !IROUTINE: ESMF_CalendarIsCreated - Check whether a Calendar object has been created

! !INTERFACE:
  function ESMF_CalendarIsCreated(calendar, keywordEnforcer, rc)
! !RETURN VALUE:
    logical :: ESMF_CalendarIsCreated
!
! !ARGUMENTS:
    type(ESMF_Calendar), intent(in)            :: calendar
type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
    integer,             intent(out), optional :: rc

! !DESCRIPTION:
!   Return {\tt .true.} if the {\tt calendar} has been created. Otherwise return 
!   {\tt .false.}. If an error occurs, i.e. {\tt rc /= ESMF\_SUCCESS} is 
!   returned, the return value of the function will also be {\tt .false.}.
!
! The arguments are:
!   \begin{description}
!   \item[calendar]
!     {\tt ESMF\_Calendar} queried.
!   \item[{[rc]}]
!     Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!   \end{description}
!
!EOP
  !-----------------------------------------------------------------------------    
    ESMF_CalendarIsCreated = .false.   ! initialize
    if (present(rc)) rc = ESMF_SUCCESS
    if (ESMF_CalendarGetInit(calendar)==ESMF_INIT_CREATED) &
      ESMF_CalendarIsCreated = .true.
  end function
!------------------------------------------------------------------------------
    
!------------------------------------------------------------------------------
!BOP
! !IROUTINE: ESMF_CalendarIsLeapYear - Determine if given year is a leap year
!
! !INTERFACE:
!     ! Private name; call using ESMF_CalendarIsLeapYear()
!     function ESMF_CalendarIsLeapYear<kind>(calendar, yy, keywordEnforcer, rc)
!
! !RETURN VALUE:
!     logical :: ESMF_CalendarIsLeapYear<kind>
!
! !ARGUMENTS:
!     type(ESMF_Calendar),       intent(in)            :: calendar
!     integer(ESMF_KIND_<kind>), intent(in)            :: yy
!     type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
!     integer,                   intent(out), optional :: rc
!
!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     \begin{sloppypar}
!     Returns {\tt .true.} if the given year is a leap year within the given
!     calendar, and {\tt .false.} otherwise.  Custom calendars do not define
!     leap years, so {\tt .false.} will always be returned in this case;
!     see Section ~\ref{subsec:Calendar_rest}.
!     See also {\tt ESMF\_TimeIsLeapYear()}.
!     \end{sloppypar}
!
!     The arguments are:
!     \begin{description}
!     \item[calendar]
!          {\tt ESMF\_Calendar} to determine leap year within.
!     \item[yy]
!          Year to check for leap year.  The type is integer and the <kind> can
!          be either I4 or I8:  {\tt ESMF\_KIND\_I4} or {\tt ESMF\_KIND\_I8}.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!    
!EOP
!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarIsLeapYearI4()"
!BOPI
! !IROUTINE: ESMF_CalendarIsLeapYear - Determine if given year is a leap year

! !INTERFACE:
      ! Private name; call using ESMF_CalendarIsLeapYear()
      function ESMF_CalendarIsLeapYearI4(calendar, yy, keywordEnforcer, rc)

! !RETURN VALUE:
      logical :: ESMF_CalendarIsLeapYearI4

! !ARGUMENTS:
      type(ESMF_Calendar),   intent(in)            :: calendar
      integer(ESMF_KIND_I4), intent(in)            :: yy
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      integer,               intent(out), optional :: rc

!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     \begin{sloppypar}
!     Returns {\tt .true.} if the given year is a leap year within the given
!     calendar, and {\tt .false.} otherwise.  Custom calendars do not define
!     leap years, so {\tt .false.} will always be returned in this case;
!     see Section ~\ref{subsec:Calendar_rest}.
!     See also {\tt ESMF\_TimeIsLeapYear()}.
!     \end{sloppypar}
!
!     The arguments are:
!     \begin{description}
!     \item[calendar]
!          {\tt ESMF\_Calendar} to determine leap year within.
!     \item[yy]
!          Year to check for leap year.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!    
!EOPI
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      ! Initialize output value in case of error
      ESMF_CalendarIsLeapYearI4 = .false.

      ! check input
      ESMF_INIT_CHECK_DEEP(ESMF_CalendarGetInit,calendar,rc)

      ! invoke C to C++ entry point
      call c_ESMC_CalendarIsLeapYearI4(calendar, yy, &
                                       ESMF_CalendarIsLeapYearI4, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS    
      end function ESMF_CalendarIsLeapYearI4
    
!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarIsLeapYearI8()"
!BOPI
! !IROUTINE: ESMF_CalendarIsLeapYear - Determine if given year is a leap year

! !INTERFACE:
      ! Private name; call using ESMF_CalendarIsLeapYear()
      function ESMF_CalendarIsLeapYearI8(calendar, yy, keywordEnforcer, rc)

! !RETURN VALUE:
      logical :: ESMF_CalendarIsLeapYearI8

! !ARGUMENTS:
      type(ESMF_Calendar),   intent(in)            :: calendar
      integer(ESMF_KIND_I8), intent(in)            :: yy
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      integer,               intent(out), optional :: rc

!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     \begin{sloppypar}
!     Returns {\tt .true.} if the given year is a leap year within the given
!     calendar, and {\tt .false.} otherwise.  Custom calendars do not define
!     leap years, so {\tt .false.} will always be returned in this case;
!     see Section ~\ref{subsec:Calendar_rest}.
!     See also {\tt ESMF\_TimeIsLeapYear()}.
!     \end{sloppypar}
!
!     The arguments are:
!     \begin{description}
!     \item[calendar]
!          {\tt ESMF\_Calendar} to determine leap year within.
!     \item[yy]
!          Year to check for leap year.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!    
!EOPI
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL
 
      ! Initialize output value in case of error
      ESMF_CalendarIsLeapYearI8 = .false.

      ! check input
      ESMF_INIT_CHECK_DEEP(ESMF_CalendarGetInit,calendar,rc)

      ! invoke C to C++ entry point
      call c_ESMC_CalendarIsLeapYearI8(calendar, yy, &
                                       ESMF_CalendarIsLeapYearI8, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS 
      end function ESMF_CalendarIsLeapYearI8
    
!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarPrint()"
!BOP
! !IROUTINE:  ESMF_CalendarPrint - Print Calendar information

! !INTERFACE:
      subroutine ESMF_CalendarPrint(calendar, options, rc)

! !ARGUMENTS:
      type(ESMF_Calendar), intent(in)            :: calendar
      character (len=*),   intent(in),  optional :: options
      integer,             intent(out), optional :: rc

!
! !DESCRIPTION:
!     Prints out an {\tt ESMF\_Calendar}'s properties to {\tt stdio}, 
!     in support of testing and debugging.  The options control the 
!     type of information and level of detail. \\
!
!     The arguments are:
!     \begin{description}
!     \item[calendar]
!          {\tt ESMF\_Calendar} to be printed out.
!     \item[{[options]}]
!          Print options. If none specified, prints all calendar property
!                             values. \\
!          "calkindflag"    - print the calendar's type 
!                               (e.g. ESMF\_CALKIND\_GREGORIAN). \\
!          "daysPerMonth"   - print the array of number of days for
!                               each month. \\
!          "daysPerYear"    - print the number of days per year
!                             (integer and fractional parts). \\
!          "monthsPerYear"  - print the number of months per year. \\
!          "name"           - print the calendar's name. \\
!          "secondsPerDay"  - print the number of seconds in a day. \\
!          "secondsPerYear" - print the number of seconds in a year. \\
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOP
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL
 
      ! check input
      ESMF_INIT_CHECK_DEEP(ESMF_CalendarGetInit,calendar,rc)

      ! invoke C to C++ entry point
      call ESMF_UtilIOUnitFlush (ESMF_UtilIOStdout, rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      call c_ESMC_CalendarPrint(calendar, options, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_CalendarPrint
      
!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarReadRestart()"
!BOPI
! !IROUTINE:  ESMF_CalendarReadRestart - Restore the contents of a Calendar (not implemented)

! !INTERFACE:
      function ESMF_CalendarReadRestart(name, keywordEnforcer, rc)
! 
! !RETURN VALUE:
      type(ESMF_Calendar) :: ESMF_CalendarReadRestart
!
! !ARGUMENTS:
      character (len=*),   intent(in)            :: name
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      integer,             intent(out), optional :: rc

! !DESCRIPTION:
!     Restores an {\tt ESMF\_Calendar} object from the last call to
!     {\tt ESMF\_CalendarWriteRestart()}.  (Not implemented yet).
!
!     The arguments are:
!     \begin{description}
!     \item[name]
!          The name of the object instance to restore.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOPI
      integer :: nameLen, localrc

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      ! get length of given name for C++ validation
      nameLen = len_trim(name)

      ! invoke C to C++ entry point to allocate and restore calendar
      call c_ESMC_CalendarReadRestart(ESMF_CalendarReadRestart, nameLen, name, &
                                      localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! mark output as successfully initialized
      ESMF_INIT_SET_CREATED(ESMF_CalendarReadRestart)

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS 
      end function ESMF_CalendarReadRestart

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarSetBuiltIn()"
!BOP
! !IROUTINE: ESMF_CalendarSet - Set a Calendar to a built-in type

! !INTERFACE:
      ! Private name; call using ESMF_CalendarSet()
      subroutine ESMF_CalendarSetBuiltIn(calendar, calkindflag, &
        keywordEnforcer, name, rc)

! !ARGUMENTS:
      type(ESMF_Calendar),     intent(inout)         :: calendar
      type(ESMF_CalKind_Flag), intent(in)            :: calkindflag
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      character (len=*),       intent(in),  optional :: name
      integer,                 intent(out), optional :: rc

!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Sets {\tt calendar} to the given built-in {\tt ESMF\_CalKind\_Flag}. 
!
!     The arguments are:
!     \begin{description}
!     \item[calendar]
!          The object instance to initialize.
!     \item[calkindflag]
!          The built-in {\tt CalKind\_Flag}.  Valid values are:
!            \newline
!            {\tt ESMF\_CALKIND\_360DAY}, 
!            \newline
!            {\tt ESMF\_CALKIND\_GREGORIAN},
!            \newline
!            {\tt ESMF\_CALKIND\_JULIAN}, 
!            \newline
!            {\tt ESMF\_CALKIND\_JULIANDAY},
!            \newline
!            {\tt ESMF\_CALKIND\_MODJULIANDAY}, 
!            \newline
!            {\tt ESMF\_CALKIND\_NOCALENDAR},
!            \newline
!            and {\tt ESMF\_CALKIND\_NOLEAP}.
!            \newline
!          See Section ~\ref{subsec:Calendar_options} for a description of each
!          calendar kind.
!     \item[{[name]}]
!          The new name for this calendar.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!    
!EOP
    
      ! initialize name length to zero for non-existent name
      integer :: nameLen, localrc

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      ! check input
      ESMF_INIT_CHECK_DEEP(ESMF_CalendarGetInit,calendar,rc)

      nameLen = 0

      ! get length of given name for C++ validation
      if (present(name)) then
        nameLen = len_trim(name)
      end if
    
      ! invoke C to C++ entry point
      call c_ESMC_CalendarSetBuiltIn(calendar, nameLen, name, calkindflag, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_CalendarSetBuiltIn
    
!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarSetCustom()"
!BOP
! !IROUTINE: ESMF_CalendarSet - Set properties of a custom Calendar

! !INTERFACE:
      ! Private name; call using ESMF_CalendarSet()
      subroutine ESMF_CalendarSetCustom(calendar, keywordEnforcer, &
        daysPerMonth, secondsPerDay, &
        daysPerYear, daysPerYearDn, daysPerYearDd, name, rc)

! !ARGUMENTS:
      type(ESMF_Calendar),  intent(inout)         :: calendar
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      integer,              intent(in),  optional :: daysPerMonth(:)
      integer(ESMF_KIND_I4),intent(in),  optional :: secondsPerDay
      integer(ESMF_KIND_I4),intent(in),  optional :: daysPerYear
      integer(ESMF_KIND_I4),intent(in),  optional :: daysPerYearDn
      integer(ESMF_KIND_I4),intent(in),  optional :: daysPerYearDd
      character (len=*),    intent(in),  optional :: name
      integer,              intent(out), optional :: rc

!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Sets properties in a custom {\tt ESMF\_Calendar}.
!
!     The arguments are:
!     \begin{description}
!     \item[calendar]
!          The object instance to initialize.
!     \item[{[daysPerMonth]}]
!          Integer array of days per month, for each month of the year.
!          The number of months per year is variable and taken from the
!          size of the array.  If unspecified, months per year = 0,
!          with the days array undefined.
!     \item[{[secondsPerDay]}]
!          Integer number of seconds per day.  Defaults to 0 if not 
!          specified.
!     \item[{[daysPerYear]}]
!          Integer number of days per year.  Use with daysPerYearDn and
!          daysPerYearDd (see below) to specify a days-per-year calendar
!          for any planetary body.  Default = 0.
!     \item[{[daysPerYearDn]}]
!          Integer numerator portion of fractional number of days per year
!          (daysPerYearDn/daysPerYearDd).
!          Use with daysPerYear (see above) and daysPerYearDd (see below) to
!          specify a days-per-year calendar for any planetary body.
!          Default = 0.
!     \item[{[daysPerYearDd]}]
!          \begin{sloppypar}
!          Integer denominator portion of fractional number of days per year
!          (daysPerYearDn/daysPerYearDd).
!          Use with daysPerYear and daysPerYearDn (see above) to
!          specify a days-per-year calendar for any planetary body.
!          Default = 1.
!          \end{sloppypar}
!     \item[{[name]}]
!          The new name for this calendar.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!     
!EOP

      ! initialize name length to zero for non-existent name
      !   and initialize number of months per year to zero for not-present
      !   daysPerMonth
      integer :: nameLen
      integer :: monthsPerYear
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      ! check input
      ESMF_INIT_CHECK_DEEP(ESMF_CalendarGetInit,calendar,rc)

      nameLen = 0
      monthsPerYear = 0

      ! get length of given name for C++ validation
      if (present(name)) then
        nameLen = len_trim(name)
      end if

      ! get size of given daysPerMonth array for C++ validation
      if (present(daysPerMonth)) then
        monthsPerYear = size(daysPerMonth)
      end if

      ! invoke C to C++ entry point

      if (present(daysPerMonth)) then
        call c_ESMC_CalendarSetCustom1(calendar, &
                                      nameLen, name, &
                                      daysPerMonth(1), monthsPerYear, &
                                      secondsPerDay, &
                                      daysPerYear, daysPerYearDn, &
                                      daysPerYearDd, localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) return
      else
        call c_ESMC_CalendarSetCustom0(calendar, &
                                      nameLen, name, &
                                      monthsPerYear, &
                                      secondsPerDay, &
                                      daysPerYear, daysPerYearDn, &
                                      daysPerYearDd, localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) return
      end if

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_CalendarSetCustom
    
!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarSetDefaultKind()"
!BOP
! !IROUTINE: ESMF_CalendarSetDefault - Set the default Calendar kind

! !INTERFACE:
      ! Private name; call using ESMF_CalendarSetDefault()
      subroutine ESMF_CalendarSetDefaultKind(calkindflag, rc)

! !ARGUMENTS:
      type(ESMF_CalKind_Flag), intent(in)            :: calkindflag
      integer,                 intent(out), optional :: rc

!
! !DESCRIPTION:
!     Sets the default {\tt calendar} to the given type.  Subsequent Time
!     Manager operations requiring a calendar where one isn't specified will
!     use the internal calendar of this type.
!
!     The arguments are:
!     \begin{description}
!     \item[calkindflag]
!          The calendar kind to be the default.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!    
!EOP
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL
    
      ! invoke C to C++ entry point
      call c_ESMC_CalendarSetDefaultKind(calkindflag, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_CalendarSetDefaultKind
    
!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarSetDefaultCal()"
!BOP
! !IROUTINE: ESMF_CalendarSetDefault - Set the default Calendar

! !INTERFACE:
      ! Private name; call using ESMF_CalendarSetDefault()
      subroutine ESMF_CalendarSetDefaultCal(calendar, rc)

! !ARGUMENTS:
      type(ESMF_Calendar),     intent(in)            :: calendar
      integer,                 intent(out), optional :: rc

!
! !DESCRIPTION:
!     Sets the default {\tt calendar} to the one given.  Subsequent Time
!     Manager operations requiring a calendar where one isn't specified will
!     use this calendar.
!
!     The arguments are:
!     \begin{description}
!     \item[calendar]
!          The object instance to be the default.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!    
!EOP
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL 

      ! check input
      ESMF_INIT_CHECK_DEEP(ESMF_CalendarGetInit,calendar,rc)

      ! invoke C to C++ entry point
      call c_ESMC_CalendarSetDefaultCal(calendar, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS 
      end subroutine ESMF_CalendarSetDefaultCal
    
!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarValidate()"
!BOP
! !IROUTINE:  ESMF_CalendarValidate - Validate a Calendar's properties

! !INTERFACE:
      subroutine ESMF_CalendarValidate(calendar, keywordEnforcer, rc)
 
! !ARGUMENTS:
      type(ESMF_Calendar), intent(in)            :: calendar
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      integer,             intent(out), optional :: rc

!
! !STATUS:
! \begin{itemize}
! \item\apiStatusCompatibleVersion{5.2.0r}
! \end{itemize}
!
! !DESCRIPTION:
!     Checks whether a {\tt calendar} is valid.  
!     Must be one of the defined calendar kinds.  daysPerMonth, daysPerYear,
!     secondsPerDay must all be greater than or equal to zero.
! 
!     The arguments are:
!     \begin{description}
!     \item[calendar]
!          {\tt ESMF\_Calendar} to be validated.
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOP
      integer :: localrc                        ! local return code
      character :: options ! dummy options

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL
      
      ! check input
      ESMF_INIT_CHECK_DEEP(ESMF_CalendarGetInit,calendar,rc)

      ! invoke C to C++ entry point
      call c_ESMC_CalendarValidate(calendar, options, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_CalendarValidate

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarWriteRestart()"
!BOPI
! !IROUTINE:  ESMF_CalendarWriteRestart - Save the contents of a Calendar (not implemented)

! !INTERFACE:
      subroutine ESMF_CalendarWriteRestart(calendar, keywordEnforcer, rc)

! !ARGUMENTS:
      type(ESMF_Calendar), intent(in)            :: calendar
      type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below
      integer,             intent(out), optional :: rc

! !DESCRIPTION:  
!     Saves an {\tt ESMF\_Calendar} object.  Default options are to select the
!     fastest way to save to disk.  (Not implemented yet).
!
!     The arguments are:
!     \begin{description}
!     \item[calendar]
!          The object instance to save.  
!     \item[{[rc]}]
!          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
!     \end{description}
!
!EOPI
      integer :: localrc                        ! local return code

      ! Assume failure until success
      if (present(rc)) rc = ESMF_RC_NOT_IMPL
      localrc = ESMF_RC_NOT_IMPL

      ! check input
      ESMF_INIT_CHECK_DEEP(ESMF_CalendarGetInit,calendar,rc)

      ! invoke C to C++ entry point 
      call c_ESMC_CalendarWriteRestart(calendar, localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) return

      ! Return success
      if (present(rc)) rc = ESMF_SUCCESS
      end subroutine ESMF_CalendarWriteRestart

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarEQ()"
!BOPI
! !IROUTINE:  ESMF_CalendarEQ - Compare two Calendars for equality
!
! !INTERFACE:
      impure elemental function ESMF_CalendarEQ(calendar1, calendar2)
! 
! !RETURN VALUE:
      logical :: ESMF_CalendarEQ

! !ARGUMENTS:
      type(ESMF_Calendar), intent(in) :: calendar1
      type(ESMF_Calendar), intent(in) :: calendar2

! !DESCRIPTION:
!     This method overloads the (==) operator for the {\tt ESMF\_Calendar}
!     class.  See "interface operator(==)" above for complete description.
!
!EOPI

      ESMF_INIT_TYPE calinit1, calinit2
      integer :: localrc1, localrc2
      logical :: lval1, lval2

      ! Use the following logic, rather than "ESMF-INIT-CHECK-DEEP", to gain 
      ! init checks on both args, and in the case where both are uninitialized,
      ! to distinguish equality based on uninitialized type (uncreated,
      ! deleted).

      ! TODO: Consider moving this logic to C++: use Base class? status?
      !       Or replicate logic for C interface also.

      ! check inputs
      calinit1 = ESMF_CalendarGetInit(calendar1)
      calinit2 = ESMF_CalendarGetInit(calendar2)

      ! TODO: this line must remain split in two for SunOS f90 8.3 127000-03
      if (calinit1 .eq. ESMF_INIT_CREATED .and. &
          calinit2 .eq. ESMF_INIT_CREATED) then
        ! invoke C to C++ entry point
        call c_ESMC_CalendarEQ(calendar1, calendar2, ESMF_CalendarEQ)
      else
        ! log error, convert to return code, and compare
        lval1 = ESMF_IMErr(calinit1, ESMF_CONTEXT, rc=localrc1)
        lval2 = ESMF_IMErr(calinit2, ESMF_CONTEXT, rc=localrc2)
        ESMF_CalendarEQ = localrc1.eq.localrc2
      endif

      end function ESMF_CalendarEQ

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarKindEQ()"
!BOPI
! !IROUTINE:  ESMF_CalendarKindEQ - Compare two Calendar kinds for equality
!
! !INTERFACE:
      impure elemental function ESMF_CalendarKindEQ(calkindflag1, calkindflag2)
! 
! !RETURN VALUE:
      logical :: ESMF_CalendarKindEQ

! !ARGUMENTS:
      type(ESMF_CalKind_Flag), intent(in) :: calkindflag1
      type(ESMF_CalKind_Flag), intent(in) :: calkindflag2

! !DESCRIPTION:
!     This method overloads the (==) operator for the {\tt ESMF\_Calendar}
!     class.  See "interface operator(==)" above for complete description.
!             
!EOPI
      ! invoke C to C++ entry point
      call c_ESMC_CalendarKindEQ(calkindflag1, calkindflag2, &
                                 ESMF_CalendarKindEQ)

      end function ESMF_CalendarKindEQ

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarCalAndKindEQ()"
!BOPI
! !IROUTINE:  ESMF_CalendarCalAndKindEQ - Compare a Calendar and Calendar kind for equality
!
! !INTERFACE:
      impure elemental function ESMF_CalendarCalAndKindEQ(calendar, calkindflag)
! 
! !RETURN VALUE:
      logical :: ESMF_CalendarCalAndKindEQ

! !ARGUMENTS:
      type(ESMF_Calendar),     intent(in) :: calendar
      type(ESMF_CalKind_Flag), intent(in) :: calkindflag

! !DESCRIPTION:
!     This method overloads the (==) operator for the {\tt ESMF\_Calendar}
!     class.  See "interface operator(==)" above for complete description.
!             
!EOPI

      integer :: localrc

      ! Initialize output value in case of error
      ESMF_CalendarCalAndKindEQ = .false.

      ! check input
      ESMF_INIT_CHECK_DEEP(ESMF_CalendarGetInit,calendar,localrc)

      ! invoke C to C++ entry point
      call c_ESMC_CalendarCalAndKindEQ(calendar, calkindflag, &
                                       ESMF_CalendarCalAndKindEQ)

      end function ESMF_CalendarCalAndKindEQ

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarKindAndCalEQ()"
!BOPI
! !IROUTINE:  ESMF_CalendarKindAndCalEQ - Compare a Calendar kind and Calendar for equality
!
! !INTERFACE:
      impure elemental function ESMF_CalendarKindAndCalEQ(calkindflag, calendar)
! 
! !RETURN VALUE:
      logical :: ESMF_CalendarKindAndCalEQ

! !ARGUMENTS:
      type(ESMF_CalKind_Flag), intent(in) :: calkindflag
      type(ESMF_Calendar),     intent(in) :: calendar

! !DESCRIPTION:
!     This method overloads the (==) operator for the {\tt ESMF\_Calendar}
!     class.  See "interface operator(==)" above for complete description.
!             
!EOPI

      integer :: localrc

      ! Initialize output value in case of error
      ESMF_CalendarKindAndCalEQ = .false.

      ! check input
      ESMF_INIT_CHECK_DEEP(ESMF_CalendarGetInit,calendar,localrc)

      ! invoke C to C++ entry point
      call c_ESMC_CalendarKindAndCalEQ(calkindflag, calendar, &
                                       ESMF_CalendarKindAndCalEQ)

      end function ESMF_CalendarKindAndCalEQ

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarNE()"
!BOPI
! !IROUTINE:  ESMF_CalendarNE - Compare two Calendars for inequality
!
! !INTERFACE:
      impure elemental function ESMF_CalendarNE(calendar1, calendar2)
! 
! !RETURN VALUE:
      logical :: ESMF_CalendarNE

! !ARGUMENTS:
      type(ESMF_Calendar), intent(in) :: calendar1
      type(ESMF_Calendar), intent(in) :: calendar2

! !DESCRIPTION:
!     This method overloads the (/=) operator for the {\tt ESMF\_Calendar}
!     class.  See "interface operator(/=)" above for complete description.
!             
!EOPI

      ESMF_INIT_TYPE calinit1, calinit2
      integer :: localrc1, localrc2
      logical :: lval1, lval2

      ! Use the following logic, rather than "ESMF-INIT-CHECK-DEEP", to gain 
      ! init checks on both args, and in the case where both are uninitialized,
      ! to distinguish equality based on uninitialized type (uncreated,
      ! deleted).

      ! TODO: Consider moving this logic to C++: use Base class? status?
      !       Or replicate logic for C interface also.

      ! check inputs
      calinit1 = ESMF_CalendarGetInit(calendar1)
      calinit2 = ESMF_CalendarGetInit(calendar2)

      ! TODO: this line must remain split in two for SunOS f90 8.3 127000-03
      if (calinit1 .eq. ESMF_INIT_CREATED .and. &
          calinit2 .eq. ESMF_INIT_CREATED) then
        ! invoke C to C++ entry point
        call c_ESMC_CalendarNE(calendar1, calendar2, ESMF_CalendarNE)
      else
        ! log error, convert to return code, and compare
        lval1 = ESMF_IMErr(calinit1, ESMF_CONTEXT, rc=localrc1)
        lval2 = ESMF_IMErr(calinit2, ESMF_CONTEXT, rc=localrc2)
        ESMF_CalendarNE = localrc1.ne.localrc2
      endif

      end function ESMF_CalendarNE

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarKindNE()"
!BOPI
! !IROUTINE:  ESMF_CalendarKindNE - Compare two Calendar kinds for inequality
!
! !INTERFACE:
      impure elemental function ESMF_CalendarKindNE(calkindflag1, calkindflag2)
! 
! !RETURN VALUE:
      logical :: ESMF_CalendarKindNE

! !ARGUMENTS:
      type(ESMF_CalKind_Flag), intent(in) :: calkindflag1
      type(ESMF_CalKind_Flag), intent(in) :: calkindflag2

! !DESCRIPTION:
!     This method overloads the (/=) operator for the {\tt ESMF\_Calendar}
!     class.  See "interface operator(/=)" above for complete description.
!             
!EOPI
      ! invoke C to C++ entry point
      call c_ESMC_CalendarKindNE(calkindflag1, calkindflag2, &
                                 ESMF_CalendarKindNE)

      end function ESMF_CalendarKindNE

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarCalAndKindNE()"
!BOPI
! !IROUTINE:  ESMF_CalendarCalAndKindNE - Compare a Calendar and Calendar kind for inequality
!
! !INTERFACE:
      impure elemental function ESMF_CalendarCalAndKindNE(calendar, calkindflag)
! 
! !RETURN VALUE:
      logical :: ESMF_CalendarCalAndKindNE

! !ARGUMENTS:
      type(ESMF_Calendar),     intent(in) :: calendar
      type(ESMF_CalKind_Flag), intent(in) :: calkindflag

! !DESCRIPTION:
!     This method overloads the (/=) operator for the {\tt ESMF\_Calendar}
!     class.  See "interface operator(/=)" above for complete description.
!             
!EOPI

      integer :: localrc

      ! Initialize output value in case of error
      ESMF_CalendarCalAndKindNE = .true.

      ! check input
      ESMF_INIT_CHECK_DEEP(ESMF_CalendarGetInit,calendar,localrc)

      ! invoke C to C++ entry point
      call c_ESMC_CalendarCalAndKindNE(calendar, calkindflag, &
                                       ESMF_CalendarCalAndKindNE)

      end function ESMF_CalendarCalAndKindNE

!------------------------------------------------------------------------------
#undef  ESMF_METHOD
#define ESMF_METHOD "ESMF_CalendarKindAndCalNE()"
!BOPI
! !IROUTINE:  ESMF_CalendarKindAndCalNE - Compare a Calendar kind and Calendar for inequality
!
! !INTERFACE:
      impure elemental function ESMF_CalendarKindAndCalNE(calkindflag, calendar)
! 
! !RETURN VALUE:
      logical :: ESMF_CalendarKindAndCalNE

! !ARGUMENTS:
      type(ESMF_CalKind_Flag), intent(in) :: calkindflag
      type(ESMF_Calendar),     intent(in) :: calendar

! !DESCRIPTION:
!     This method overloads the (/=) operator for the {\tt ESMF\_Calendar}
!     class.  See "interface operator(/=)" above for complete description.
!             
!EOPI

      integer :: localrc

      ! Initialize output value in case of error
      ESMF_CalendarKindAndCalNE = .true.

      ! check input
      ESMF_INIT_CHECK_DEEP(ESMF_CalendarGetInit,calendar,localrc)

      ! invoke C to C++ entry point
      call c_ESMC_CalendarKindAndCalNE(calkindflag, calendar, &
                                       ESMF_CalendarKindAndCalNE)

      end function ESMF_CalendarKindAndCalNE

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

      end module ESMF_CalendarMod
