!-------------------------------------------------------------
! Copyright (c) 2013-2016 Kawai Yuta. All rights reserved.
!-------------------------------------------------------------
!> @brief a template module
!!
!! @author Kawai Yuta
!!
!!
module DSIce_IO_History_mod

  ! ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«å¼•ç”¨; Use statements
  !

  !* gtool5

  use dc_types, only:               &
       & DP, TOKEN, STRING

  use dc_string, only:              &
       & StrInclude

  use dc_message, only:             &
       & MessageNotify

  use gtool_history, only: &
       & gt_history,         &
       & HistorySetTime,                       &
       & HistoryCreate, HistoryClose,          &
       & HistoryAddVariable, HistoryAddAttr,   &
       & HistoryPut

  use dc_calendar, only: &
       & DCCalConvertByUnit

  !* Dennou-OGCM / SIce

  use DSIce_Admin_Grid_mod, only: &
       & IM, IS, IE, IA, &
       & JM, JS, JE, JA, &
       & KM, KS, KE, KA

  use DSIce_Admin_TInteg_mod, only: &
       & CurrentTime, RestartTime, &
       & IntegTime, EndTime

  ! å®£è¨€æ–‡; Declareration statements
  !
  implicit none
  private

  ! å…¬é–‹æ‰‹ç¶šã
  ! Public procedure
  !
  public :: DSIce_IO_History_Init, DSIce_IO_History_Final
  public :: DSIce_IO_History_Create
  public :: DSIce_IO_History_RegistVar
  public :: DSIce_IO_History_Output
  public :: DSIce_IO_History_IsOutputTiming

  interface DSIce_IO_History_HistPut
     module procedure DSIce_IO_History_HistPut1D
     module procedure DSIce_IO_History_HistPut2D
     module procedure DSIce_IO_History_HistPut3D
  end interface DSIce_IO_History_HistPut
  public :: DSIce_IO_History_HistPut

  ! å…¬é–‹å¤‰æ•°
  ! Public variable
  !
  character(TOKEN), public, save :: FilePrefix
  real(DP), public, save :: OutputIntrvalSec
  character(TOKEN), public, save :: OutputIntUnit

  ! éžå…¬é–‹æ‰‹ç¶šã
  ! Private procedure
  !

  ! éžå…¬é–‹å¤‰æ•°
  ! Private variable
  !
  character(*), parameter:: module_name = 'DSIce_IO_History_mod' !< Module Name

  integer :: HstDimsID_I = 1
  integer :: HstDimsID_J = 2
  integer :: HstDimsID_K = 3
  integer :: HstDimsID_T = 4
  character(TOKEN) :: HstDimsList(4)

  integer :: HstVarsNum
  integer, parameter :: HstVarsNumMax = 50
  character(TOKEN) :: HstVarsList(HstVarsNumMax)

  logical :: isHistoryCreated

  type(gt_history), save :: hst_seaice

contains

  !>
  !!
  !!
  subroutine DSIce_IO_History_Init(configNmlFileName)

    ! ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«å¼•ç”¨; Use statement
    !

    ! å®£è¨€æ–‡; Declaration statement
    !
    character(*), intent(in) :: configNmlFileName

    ! å±€æ‰€å¤‰æ•°
    ! Local variable
    !
    character(STRING) :: outputFileName

    ! å®Ÿè¡Œæ–‡; Executable statements
    !

    !
    HstVarsNum = 0

    call read_nmlData( configNmlFileName )

    isHistoryCreated = .false.

  end subroutine DSIce_IO_History_Init

  !>
  !!
  !!
  subroutine DSIce_IO_History_Final()

    ! å®Ÿè¡Œæ–‡; Executable statements
    !

    if (isHistoryCreated) then
       call HistoryClose( hst_seaice )
    end if

  end subroutine DSIce_IO_History_Final

  logical function DSIce_IO_History_isOutputTiming(CurrentTimeSec)

    ! å®£è¨€æ–‡; Declaration statement
    !
    real(DP), intent(in) :: CurrentTimeSec

    ! å®Ÿè¡Œæ–‡; Executable statement
    !

    DSIce_IO_History_isOutputTiming &
         & = ( mod(CurrentTimeSec, OutputIntrvalSec) == 0 )

  end function DSIce_IO_History_isOutputTiming

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

  !> @brief
  !!
  !!
  subroutine DSIce_IO_History_HistPut1D(varName, var)

    ! å®£è¨€æ–‡; Declaration statement
    !
    character(*), intent(in) :: varName
    real(DP), intent(in) :: var(:)

    ! å®Ÿè¡Œæ–‡; Executable statement
    !

    if (.not. StrInclude(HstVarsList(1:HstVarsNum), trim(varName)) ) return

    call HistoryPut(varName, var, history=hst_seaice)

  end subroutine DSIce_IO_History_HistPut1D

  !> @brief
  !!
  !!
  subroutine DSIce_IO_History_HistPut2D(varName, var)

    ! å®£è¨€æ–‡; Declaration statement
    !
    character(*), intent(in) :: varName
    real(DP), intent(in) :: var(:,:)

    ! å®Ÿè¡Œæ–‡; Executable statement
    !

    if (.not. StrInclude(HstVarsList(1:HstVarsNum), trim(varName)) ) return

    call HistoryPut(varName, var, history=hst_seaice)

  end subroutine DSIce_IO_History_HistPut2D

  !> @brief
  !!
  !!
  subroutine DSIce_IO_History_HistPut3D(varName, var)

    ! å®£è¨€æ–‡; Declaration statement
    !
    character(*), intent(in) :: varName
    real(DP), intent(in) :: var(:,:,:)

    ! å®Ÿè¡Œæ–‡; Executable statement
    !

    if (.not. StrInclude(HstVarsList(1:HstVarsNum), trim(varName)) ) return

    call HistoryPut(varName, var, history=hst_seaice)

  end subroutine DSIce_IO_History_HistPut3D

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

  !> @brief
  !!
  !!
  subroutine DSIce_IO_History_Output()

    ! ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«å¼•ç”¨; Use statement
    !

    ! å®£è¨€æ–‡; Declaration statement
    !

    ! å±€æ‰€å¤‰æ•°
    ! Local variables
    !

    ! å®Ÿè¡Œæ–‡; Executable statement
    !

    if( .not. DSIce_IO_History_isOutputTiming(CurrentTime) ) return

    call HistorySetTime( &
         & timed=DCCalConvertByUnit(CurrentTime, "sec", OutputIntUnit), &
         & history=hst_seaice                                           &
         & )

  end subroutine DSIce_IO_History_Output

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

  subroutine DSIce_IO_History_RegistVar( &
       & varName, varDimsName, varLongName, varUnits  & ! (in)
       & )

    ! å®£è¨€æ–‡; Declaration statement
    !
    character(*), intent(in) :: varName
    character(*), intent(in) :: varDimsName
    character(*), intent(in) :: varLongName
    character(*), intent(in) :: varUnits

    ! å±€æ‰€å¤‰æ•°
    ! Local variables
    !
    character(TOKEN) :: varDims(size(HstDimsList))
    integer :: varDimsLen

    if (.not. StrInclude(HstVarsList(1:HstVarsNum), trim(varName)) ) return

    select case (varDimsName)
    case ('K')
       varDimsLen = 1
       varDims(1:varDimsLen) = (/ HstDimsList(HstDimsID_K) /)
    case ('IJ')
       varDimsLen = 2
       varDims(1:varDimsLen) = (/ HstDimsList(HstDimsID_I),  HstDimsList(HstDimsID_J) /)
    case ('IJK')
       varDimsLen = 3
       varDims(1:varDimsLen) = (/ HstDimsList(HstDimsID_I),  HstDimsList(HstDimsID_J), HstDimsList(HstDimsID_K) /)
    case ('IJT')
       varDimsLen = 3
       varDims(1:varDimsLen) = (/ HstDimsList(HstDimsID_I),  HstDimsList(HstDimsID_J), HstDimsList(HstDimsID_T) /)
    case ('IJKT')
       varDimsLen = 4
       varDims(1:varDimsLen) = (/ HstDimsList(HstDimsID_I),  HstDimsList(HstDimsID_J), HstDimsList(HstDimsID_K), &
            &                     HstDimsList(HstDimsID_T) /)
    case default
       call MessageNotify( 'E', module_name, &
            & "Specified varDimsName(=%a) is not supported. Check!", ca=(/ trim(varDimsName) /) )
    end select

    call HistoryAddVariable( varname=trim(varName), &
         & dims=varDims(1:varDimsLen), longname=varLongName, units=trim(varUnits), &
         & history=hst_seaice                                                      &
         & )

  end subroutine DSIce_IO_History_RegistVar

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

  subroutine DSIce_IO_History_Create( configNmlFileName )

    ! ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«å¼•ç”¨; Use statement
    !
    use DSIce_Admin_Grid_mod, only: &
         & AXIS_INFO, &
         & IAXIS_info, JAXIS_info, KAXIS_info, TAXIS_info, &
         & x_CI, y_CJ, z_CK, x_FI, y_FJ, z_FK,             &
         & x_IAXIS_Weight, y_JAXIS_Weight, z_KAXIS_Weight

    ! å®£è¨€æ–‡; Declaration statement
    !
    character(*), intent(in) :: configNmlFileName

    ! å®Ÿè¡Œæ–‡; Executable statements
    !

    ! å±€æ‰€å¤‰æ•°
    ! Local variables
    !

    character(TOKEN) :: dims_K(1)
    character(TOKEN) :: dims_IJ(2)
    character(TOKEN) :: dims_IJK(3)
    character(TOKEN) :: dims_IJT(3)
    character(TOKEN) :: dims_KT(2)
    character(TOKEN) :: dims_IJKT(4)

    character(STRING) :: HstLongNameList(4)
    character(TOKEN) :: HstUnitsList(4)
    character(TOKEN) :: HstTypeList(4)

    ! Set arrays storing the name of axises
    !
    dims_K = (/ KAXIS_info%name /)
    dims_KT = (/ KAXIS_info%name, TAXIS_info%name /)
    dims_IJ = (/ IAXIS_info%name, JAXIS_info%name /)
    dims_IJK = (/ IAXIS_info%name, JAXIS_info%name, KAXIS_info%name /)
    dims_IJT = (/ IAXIS_info%name, JAXIS_info%name, TAXIS_info%name /)
    dims_IJKT = (/ IAXIS_info%name, JAXIS_info%name, KAXIS_info%name, TAXIS_info%name /)

    ! Initialize gtool objects
    !
    HstDimsList(HstDimsID_I) = IAXIS_info%name
    HstDimsList(HstDimsID_J) = JAXIS_info%name
    HstDimsList(HstDimsID_K) = KAXIS_info%name
    HstDimsList(HstDimsID_T) = TAXIS_info%name

    HstLongNameList(HstDimsID_I) = IAXIS_info%long_name
    HstLongNameList(HstDimsID_J) = JAXIS_info%long_name
    HstLongNameList(HstDimsID_K) = KAXIS_info%long_name
    HstLongNameList(HstDimsID_T) = TAXIS_info%long_name

    HstUnitsList(HstDimsID_I) = IAXIS_info%units
    HstUnitsList(HstDimsID_J) = JAXIS_info%units
    HstUnitsList(HstDimsID_K) = KAXIS_info%units
    HstUnitsList(HstDimsID_T) = outputIntUnit    !TAXIS_info%units

    call HistoryCreate( &                            ! ãƒ’ã‚¹ãƒˆãƒªãƒ¼ä½œæˆ
         & file   = trim(FilePrefix) // "history_sice.nc",                  &
         & title  = 'DSIce Output',                                         &
         & source = 'DSIce Output',                                         &
         & institution='GFD_Dennou Club OGCM and sea-ice model  project',   &
         & dims=HstDimsList, dimsizes=(/ IM, JM, KM,  0 /),                 &
         & longnames=HstLongNameList, units=HstUnitsList,                   &
         & origind=DCCalConvertByUnit(RestartTime, "sec", OutputIntUnit),   &
         & history=hst_seaice )

    isHistoryCreated = .true.

    ! åº§æ¨™ãƒ‡ãƒ¼ã‚¿ã®è¨å®š
    ! Axes data settings

    call regist_axis(IAXIS_info, x_CI(IS:IE), x_IAXIS_Weight(IS:IE))
    call regist_axis(JAXIS_info, y_CJ(JS:JE), y_JAXIS_Weight(JS:JE))
    call regist_axis(KAXIS_info, z_CK(KS:KE), z_KAXIS_Weight(KS:KE))

  contains
    subroutine regist_axis(axis, cell_pos, cell_weight)
      type(AXIS_INFO), intent(in) :: axis
      real(DP), intent(in) :: cell_pos(:)
      real(DP), intent(in) :: cell_weight(:)

      call HistoryAddAttr(axis%name, 'standard_name', axis%long_name, &
           & history = hst_seaice )
      call HistoryPut(axis%name, cell_pos, &
           & history = hst_seaice )
    end subroutine regist_axis

  end subroutine DSIce_IO_History_Create

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

  subroutine read_nmlData( configNmlFileName )

    ! ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«å¼•ç”¨; Use statement
    !

    use dc_string, only: &
         & Replace, Split

    ! ãƒ•ã‚¡ã‚¤ãƒ«å…¥å‡ºåŠ›è£œåŠ©
    ! File I/O support
    !
    use dc_iounit, only: FileOpen

    ! ç¨®åˆ¥åž‹ãƒ‘ãƒ©ãƒ¡ã‚¿
    ! Kind type parameter
    !
    use dc_types, only: STDOUT ! æ¨™æº–å‡ºåŠ›ã®è£…ç½®ç•ªå·. Unit number of standard output

    ! å®£è¨€æ–‡; Declaration statement
    !
    character(*), intent(in) :: configNmlFileName

    ! å±€æ‰€å¤‰æ•°
    ! Local variables
    !
    integer:: unit_nml        ! NAMELIST ãƒ•ã‚¡ã‚¤ãƒ«ã‚ªãƒ¼ãƒ—ãƒ³ç”¨è£…ç½®ç•ªå·.
                              ! Unit number for NAMELIST file open

    integer:: iostat_nml      ! NAMELIST èªã¿è¾¼ã¿æ™‚ã® IOSTAT.
                              ! IOSTAT of NAMELIST read

    character(TOKEN) :: pos_nml

    real(DP) :: IntValue
    character(TOKEN) :: IntUnit
    character(STRING) :: Name

    character(TOKEN), pointer :: HstVarsList_ptr(:)
    integer :: n

    ! NAMELIST å¤‰æ•°ç¾¤
    ! NAMELIST group name
    !
    namelist /seaice_io_history_nml/ &
         & IntValue, IntUnit, FilePrefix, &
         & Name

    ! å®Ÿè¡Œæ–‡; Executable statements

    ! ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ã®è¨å®š
    ! Default values settings
    !
    IntValue = 0d0
    IntUnit = "sec"
    FilePrefix = ''

    ! NAMELIST ã‹ã‚‰ã®å…¥åŠ›
    ! Input from NAMELIST
    !
    if ( trim(configNmlFileName) /= '' ) then
       call MessageNotify( 'M', module_name, "reading namelist '%a'", ca=(/ configNmlFileName /))
       call FileOpen( unit_nml, &             ! (out)
            & configNmlFileName, mode = 'r' ) ! (in)

       pos_nml = ''; iostat_nml = 0
       do while ( trim(pos_nml) /= 'APPEND' .and. iostat_nml == 0 )
          read( unit_nml, &           ! (in)
               & nml = seaice_io_history_nml, iostat = iostat_nml )   ! (out)
          inquire( unit_nml, &      !(in)
               & position=pos_nml ) !(out)

          HstVarsList_ptr => null()
          Name = Replace( trim(Name), " ", "", .true.)
          call Split( trim(Name), HstVarsList_ptr, ",")

          if (associated(HstVarsList_ptr)) then
             do n = 1, size(HstVarsList_ptr)
                if ( .not. StrInclude( HstVarsList(1:HstVarsNum), trim(HstVarsList_ptr(n)) )) then
                   HstVarsNum = HstVarsNum + 1
                   if (HstVarsNum > HstVarsNumMax) then
                      call MessageNotify( 'E', module_name, "Exceed the number of variables allowed to regist. Check!")
                   end if
                   HstVarsList(HstVarsNum) = trim(HstVarsList_ptr(n))
                end if
             end do
             deallocate( HstVarsList_ptr )
          end if

       end do
       close( unit_nml )
    end if

    outputIntUnit = IntUnit
    OutputIntrvalSec = DCCalConvertByUnit(IntValue, IntUnit, "sec")

    ! å°å— ; Print
    !
    call MessageNotify( 'M', module_name, '----- Initialization Messages -----' )
    call MessageNotify( 'M', module_name, 'Output Interval %f [%c]', d=(/IntValue/), c1=trim(IntUnit) )

  end subroutine read_nmlData

end module DSIce_IO_History_mod