!= dc_date å†…ã§ä½¿ç”¨ã•ã‚Œã‚‹å†…éƒ¨å‘ã‘å®šæ•°, å¤‰æ•°, æ‰‹ç¶šãç¾¤
!= Internal constants, variables, procedures used in "dc_date"
!
! Authors::   Yasuhiro MORIKAWA, Eizi TOYODA
! Version::   $Id: dc_date_internal.f90,v 1.1 2009-05-25 10:01:34 morikawa Exp $
! Tag Name::  $Name:  $
! Copyright:: Copyright (C) GFD Dennou Club, 2000-2005. All rights reserved.
! License::   See COPYRIGHT[link:../../COPYRIGHT]

module dc_date_internal
  != dc_date å†…ã§ä½¿ç”¨ã•ã‚Œã‚‹å†…éƒ¨å‘ã‘å®šæ•°, å¤‰æ•°, æ‰‹ç¶šãç¾¤
  != Internal constants, variables, procedures used in "dc_date"

  use dc_date_types, only: DC_DATETIME, DC_DIFFTIME
  use dc_types, only: DP, STRING, TOKEN
  use dc_present, only: present_and_not_empty

  implicit none

  private
  public:: dcdate_normalize, dcdate_parse_unit, dcdate_set_day_seconds_scl
  public:: dcdate_nondimcheck

contains

  subroutine dcdate_normalize(day, sec, day_seconds, nondim_flag)
    !
    !=== æ—¥ã¨ç§’ã®æ£è¦åŒ–
    !
    ! ã“ã®ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã¯å†…éƒ¨å‘ã‘ãªã®ã§ dc_date ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«å¤–ã§ã¯
    ! æ¥µåŠ›ä½¿ç”¨ã—ãªã„ã§ãã ã•ã„.
    !
    ! æ—¥ä»˜ *day* ã¨ç§’æ•° *sec* ã®æ£è¦åŒ–ã‚’è¡Œã„ã¾ã™. *sec* ãŒ *day_seconds*
    ! (çœç•¥ã•ã‚Œã‚‹å ´åˆã¯ dc_date_types#day_seconds) ã‚’è¶…ãˆã‚‹å ´åˆ, *day*
    ! ã«ç¹°ä¸Šã’ã‚’è¡Œã„ã¾ã™.
    ! ã¾ãŸ, *sec* ã¨ *day* ã®ç¬¦å·ãŒé€†ã®å ´åˆ, åŒç¬¦å·ã«ãªã‚‹ã‚ˆã†
    ! è¨å®šã—ã¾ã™.
    !
    use dc_date_types, only: &
      & flag_set_day_seconds_scl, day_seconds_scl
    use dc_scaledsec, only: DC_SCALED_SEC, &
      & operator(<), operator(>), operator(<=), operator(>=), &
      & operator(+), operator(-), operator(*), operator(/), &
      & modulo, int, abs, sign
    implicit none
    type(DC_SCALED_SEC), intent(inout):: day
    type(DC_SCALED_SEC), intent(inout):: sec
    type(DC_SCALED_SEC), intent(in), optional:: day_seconds
    logical, intent(in):: nondim_flag
    type(DC_SCALED_SEC):: sgn, day_sec, zero_sec
  continue
    if ( nondim_flag ) return
    if (present(day_seconds)) then
      day_sec = day_seconds
    else
      if ( .not. flag_set_day_seconds_scl ) call dcdate_set_day_seconds_scl
      day_sec = day_seconds_scl
    end if
    if (abs(sec) >= day_sec) then
      day = day + int(sec / day_sec)
      sec = modulo(sec, day_sec)
    end if
!!    zero_sec = 0  (ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ = 0 ã‚’ä½¿ç”¨ã™ã‚‹).
    if (      ( sec > zero_sec .and. day < zero_sec ) &
      &  .or. ( sec < zero_sec .and. day > zero_sec )   ) then
      sgn = sign(day, 1)
      day = day - sgn
      sec = sec + sgn * day_sec
    endif
  end subroutine dcdate_normalize

  subroutine dcdate_set_day_seconds_scl
    use dc_scaledsec, only: DC_SCALED_SEC, assignment(=)
    use dc_date_types, only: day_seconds,  &
      & flag_set_day_seconds_scl, day_seconds_scl
  continue
    if ( .not. flag_set_day_seconds_scl ) then
      flag_set_day_seconds_scl = .true.
      day_seconds_scl = day_seconds
    end if
  end subroutine dcdate_set_day_seconds_scl

  subroutine dcdate_nondimcheck(opr, diff1, diff2, rslt)
    !
    ! ã“ã®ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã¯å†…éƒ¨å‘ã‘ãªã®ã§ dc_date ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«å¤–ã§ã¯
    ! æ¥µåŠ›ä½¿ç”¨ã—ãªã„ã§ãã ã•ã„.
    !
    ! diff1 ã¨ diff2 ãŒä¸¡æ–¹ã¨ã‚‚æœ‰æ¬¡å…ƒã‚‚ã—ãã¯ç„¡æ¬¡å…ƒã‹ã‚’ãƒã‚§ãƒƒã‚¯ã—,
    ! ä¸¡æ–¹ãŒåŒã˜ã§ã‚ã‚Œã°, ãã®çµæžœã‚’ rslt ã«é©ç”¨ã—ã¾ã™.
    ! 2ã¤ã®å¼•æ•°ã§ç‰‡æ–¹ãŒæœ‰æ¬¡å…ƒ, ã‚‚ã†ç‰‡æ–¹ãŒç„¡æ¬¡å…ƒã®å ´åˆã«ã¯
    ! ã‚¨ãƒ©ãƒ¼ã‚’ç™ºç”Ÿã•ã›ã¾ã™.
    !
    use dc_error, only: StoreError, DC_EDIMTIME
    implicit none
    character(*), intent(in):: opr  ! æ¼”ç®—åã®åç§°
    type(DC_DIFFTIME), intent(in):: diff1, diff2
    type(DC_DIFFTIME), intent(inout):: rslt
  continue
    if (      (       diff1 % nondim_flag .and. .not. diff2 % nondim_flag ) &
      &  .or. ( .not. diff1 % nondim_flag .and.       diff2 % nondim_flag ) ) then
      call StoreError(DC_EDIMTIME, opr)
    end if
    rslt % nondim_flag = diff1 % nondim_flag
  end subroutine dcdate_nondimcheck

  function ParseTimeUnits(str) result(symbol)
    !
    ! å¼•æ•° *str* ã«ä¸Žãˆã‚‰ã‚ŒãŸæ–‡å—åˆ—ã‚’è§£é‡ˆã—, æ—¥æ™‚ã®å˜ä½ã‚’ç¤ºã™
    ! ã‚·ãƒ³ãƒœãƒ«ã‚’è¿”ã—ã¾ã™. ãã‚Œãžã‚Œä»¥ä¸‹ã®æ–‡å—åˆ—ãŒæ—¥æ™‚ã®å˜ä½ã¨ã—ã¦è§£é‡ˆã•ã‚Œã¾ã™.
    ! å¤§æ–‡å—ã¨å°æ–‡å—ã¯åŒºåˆ¥ã•ã‚Œã¾ã›ã‚“.
    !
    ! å¹´         :: dc_date_types#UNIT_YEAR
    ! æœˆ         :: dc_date_types#UNIT_MONTH
    ! æ—¥         :: dc_date_types#UNIT_DAY
    ! æ™‚         :: dc_date_types#UNIT_HOUR
    ! åˆ†         :: dc_date_types#UNIT_MIN
    ! ç§’         :: dc_date_types#UNIT_SEC
    ! ç„¡æ¬¡å…ƒæ™‚é–“ :: dc_date_types#UNIT_NONDIM
    !
    ! è¿”ã‚‹ã‚·ãƒ³ãƒœãƒ« (æ•´æ•°åž‹) ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™.
    !
    ! å¹´         :: dc_date_types#UNIT_SYMBOL_YEAR
    ! æœˆ         :: dc_date_types#UNIT_SYMBOL_MONTH
    ! æ—¥         :: dc_date_types#UNIT_SYMBOL_DAY
    ! æ™‚         :: dc_date_types#UNIT_SYMBOL_HOUR
    ! åˆ†         :: dc_date_types#UNIT_SYMBOL_MIN
    ! ç§’         :: dc_date_types#UNIT_SYMBOL_SEC
    ! ç„¡æ¬¡å…ƒæ™‚é–“ :: dc_date_types#UNIT_SYMBOL_NONDIM
    !
    ! ã“ã‚Œã‚‰ã«è©²å½“ã—ãªã„æ–‡å—åˆ—ã‚’ *str* ã«ä¸ŽãˆãŸå ´åˆ,
    ! dc_date_types#UNIT_SYMBOL_ERR ãŒè¿”ã‚Šã¾ã™.
    !
    use dc_types, only: TOKEN
    use dc_date_types, only: UNIT_YEAR, UNIT_MONTH, UNIT_DAY, &
      & UNIT_HOUR, UNIT_MIN, UNIT_SEC, UNIT_NONDIM, &
      & UNIT_SYMBOL_YEAR, UNIT_SYMBOL_MONTH, UNIT_SYMBOL_DAY, &
      & UNIT_SYMBOL_HOUR, UNIT_SYMBOL_MIN, UNIT_SYMBOL_SEC, &
      & UNIT_SYMBOL_NONDIM, UNIT_SYMBOL_ERR
    use dc_string, only: StriEq
    implicit none
    character(*), intent(in):: str
    integer:: symbol
    integer:: unit_str_size, i
    character(TOKEN):: unit
  continue
    unit = adjustl(str)
    unit_str_size = size(UNIT_NONDIM)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_NONDIM(i)))) then
        symbol = UNIT_SYMBOL_NONDIM
        return
      end if
    end do

    unit_str_size = size(UNIT_SEC)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_SEC(i)))) then
        symbol = UNIT_SYMBOL_SEC
        return
      end if
    end do

    unit_str_size = size(UNIT_MIN)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_MIN(i)))) then
        symbol = UNIT_SYMBOL_MIN
        return
      end if
    end do

    unit_str_size = size(UNIT_HOUR)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_HOUR(i)))) then
        symbol = UNIT_SYMBOL_HOUR
        return
      end if
    end do

    unit_str_size = size(UNIT_DAY)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_DAY(i)))) then
        symbol = UNIT_SYMBOL_DAY
        return
      end if
    end do

    unit_str_size = size(UNIT_MONTH)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_MONTH(i)))) then
        symbol = UNIT_SYMBOL_MONTH
        return
      end if
    end do

    unit_str_size = size(UNIT_YEAR)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_YEAR(i)))) then
        symbol = UNIT_SYMBOL_YEAR
        return
      end if
    end do

    symbol = UNIT_SYMBOL_ERR

  end function ParseTimeUnits

  character(TOKEN) function dcdate_parse_unit(str) result(unit)
    !
    ! ã“ã®ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã¯å†…éƒ¨å‘ã‘ãªã®ã§ dc_date ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«å¤–ã§ã¯
    ! æ¥µåŠ›ä½¿ç”¨ã—ãªã„ã§ãã ã•ã„.
    !
    ! å¼•æ•° *str* ã«ä¸Žãˆã‚‰ã‚ŒãŸæ–‡å—åˆ—ã‚’è§£é‡ˆã—, æ—¥æ™‚ã®å˜ä½ã‚’
    ! è¿”ã—ã¾ã™. ãã‚Œãžã‚Œä»¥ä¸‹ã®æ–‡å—åˆ—ãŒæ—¥æ™‚ã®å˜ä½ã¨ã—ã¦è§£é‡ˆã•ã‚Œã¾ã™.
    ! å¤§æ–‡å—ã¨å°æ–‡å—ã¯åŒºåˆ¥ã•ã‚Œã¾ã›ã‚“.
    ! è¿”ã‚‹æ–‡å—åˆ—ã¯ä»¥ä¸‹ã®æ–‡å—åž‹ã®é…åˆ—ã®å…ˆé ã®æ–‡å—åˆ—ã§ã™.
    ! (ä¾‹: *str* ã« 'hrs.' ãŒä¸Žãˆã‚‰ã‚Œã‚‹å ´åˆ, dc_date_types#UNIT_HOUR
    ! é…åˆ—ã®å…ˆé ã®æ–‡å—åˆ— UNIT_HOUR(1) ãŒè¿”ã‚Šã¾ã™.)
    !
    ! å¹´         :: dc_date_types#UNIT_YEAR
    ! æœˆ         :: dc_date_types#UNIT_MONTH
    ! æ—¥         :: dc_date_types#UNIT_DAY
    ! æ™‚         :: dc_date_types#UNIT_HOUR
    ! åˆ†         :: dc_date_types#UNIT_MIN
    ! ç§’         :: dc_date_types#UNIT_SEC
    ! ç„¡æ¬¡å…ƒæ™‚é–“ :: dc_date_types#UNIT_NONDIM
    !
    ! ã“ã‚Œã‚‰ã«è©²å½“ã—ãªã„æ–‡å—åˆ—ã‚’ *str* ã«ä¸ŽãˆãŸå ´åˆ, ç©ºæ–‡å—ãŒè¿”ã‚Šã¾ã™.
    !
    use dc_types, only: TOKEN
    use dc_date_types, only: UNIT_YEAR, UNIT_MONTH, UNIT_DAY, &
      & UNIT_HOUR, UNIT_MIN, UNIT_SEC, UNIT_NONDIM
    use dc_string, only: StriEq
    implicit none
    character(*), intent(in):: str
    integer :: unit_str_size, i
  continue
    unit = adjustl(str)
    unit_str_size = size(UNIT_NONDIM)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_NONDIM(i)))) then
        unit = UNIT_NONDIM(1)
        return
      end if
    end do

    unit_str_size = size(UNIT_SEC)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_SEC(i)))) then
        unit = UNIT_SEC(1)
        return
      end if
    end do

    unit_str_size = size(UNIT_MIN)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_MIN(i)))) then
        unit = UNIT_MIN(1)
        return
      end if
    end do

    unit_str_size = size(UNIT_HOUR)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_HOUR(i)))) then
        unit = UNIT_HOUR(1)
        return
      end if
    end do

    unit_str_size = size(UNIT_DAY)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_DAY(i)))) then
        unit = UNIT_DAY(1)
        return
      end if
    end do

    unit_str_size = size(UNIT_MONTH)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_MONTH(i)))) then
        unit = UNIT_MONTH(1)
        return
      end if
    end do

    unit_str_size = size(UNIT_YEAR)
    do i = 1, unit_str_size
      if (StriEq(trim(unit), trim(UNIT_YEAR(i)))) then
        unit = UNIT_YEAR(1)
        return
      end if
    end do

    unit = ''

  end function dcdate_parse_unit

end module dc_date_internal