module io_profile

  use vtype_module
  use ni3_module

  implicit none

  private

  public :: IOProfileInqDimLen
  public :: IOProfileRead
  public :: IOProfileReadPtcl
  public :: IOProfileOutput

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

contains

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

  subroutine IOProfileInqDimLen(      &
    & InFileName, DimName, &
    & NLev &
    & )

    character(*), intent(in ) :: InFileName
    character(*), intent(in ) :: DimName

    integer     , intent(out) :: NLev


    !
    ! local variables
    !
    character(stdstr) :: Mode
    integer           :: NcID


    Mode = "read"
    call ni3_open( InFileName, Mode, NcID )

    call ni3_inq_dimlen( NcID, DimName, NLev )

    call ni3_close( NcID )


  end subroutine IOProfileInqDimLen

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

  subroutine IOProfileRead(      &
    & InFileName, PressName, MolNumName, TempName, SurfTempName, VMRName, &
    & NLev, NMolNum, &
    & z_Press, m_MolNum, z_Temp, SurfTemp, zm_VMR     &
    & )

    character(*), intent(in) :: InFileName
    character(*), intent(in) :: PressName
    character(*), intent(in) :: MolNumName
    character(*), intent(in) :: TempName
    character(*), intent(in) :: SurfTempName
    character(*), intent(in) :: VMRName
    integer     , intent(in ) :: NLev
    integer     , intent(in ) :: NMolNum
    real(DP)    , intent(out) :: z_Press  (1:NLev)
    integer     , intent(out) :: m_MolNum (1:NMolNum)
    real(DP)    , intent(out) :: z_Temp   (1:NLev)
    real(DP)    , intent(out) :: SurfTemp
    real(DP)    , intent(out) :: zm_VMR   (1:NLev,1:NMolNum)


    !
    ! local variables
    !
    character(stdstr) :: Mode
    integer           :: NcID


    Mode = "read"
    call ni3_open( InFileName, Mode, NcID )

    call ni3_get_var( NcID, PressName   , z_Press  )
    call ni3_get_var( NcID, MolNumName  , m_MolNum )
    call ni3_get_var( NcID, TempName    , z_Temp   )
    call ni3_get_var( NcID, VMRName     , zm_VMR   )
    call ni3_get_var( NcID, SurfTempName, SurfTemp )

    call ni3_close( NcID )


  end subroutine IOProfileRead

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

  subroutine IOProfileReadPtcl(      &
    & InFileName, &
    & NLev, NPtclNum, &
    & z_Press, a_PtclNum, a_PtclName, a_PtclDens, za_PtclEffRad, za_PtclMMR  &
    & )

    character(*), intent(in ) :: InFileName
    integer     , intent(in ) :: NLev
    integer     , intent(in ) :: NPtclNum
    real(DP)    , intent(out) :: z_Press      (1:NLev)
    integer     , intent(out) :: a_PtclNum    (1:NPtclNum)
    character(*), intent(out) :: a_PtclName   (1:NPtclNum)
    real(DP)    , intent(out) :: a_PtclDens   (1:NPtclNum)
    real(DP)    , intent(out) :: za_PtclEffRad(1:NLev,1:NPtclNum)
    real(DP)    , intent(out) :: za_PtclMMR   (1:NLev,1:NPtclNum)


    !
    ! local variables
    !
    character(stdstr) :: Mode
    integer           :: NcID
    character(stdstr) :: Name


    Mode = "read"
    call ni3_open( InFileName, Mode, NcID )

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

    Name     = "PressM"
    call ni3_get_var( NcID, Name, z_Press )
!!$    Name     = "CharNum"
!!$    call ni3_get_var( NcID, Name, a_CharNum )

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

    if ( NPtclNum > 0 ) then

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

      Name     = "PtclNum"
      call ni3_get_var( NcID, Name, a_PtclNum )

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

      Name     = "PtclDens"
      call ni3_get_var( NcID, Name, a_PtclDens )
      !
      Name     = "PtclName"
      call ni3_get_var( NcID, Name, a_PtclName )
      !
      Name     = "PtclEffRad"
      call ni3_get_var( NcID, Name, za_PtclEffRad )
      !
      Name     = "PtclMMR"
      call ni3_get_var( NcID, Name, za_PtclMMR )

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

    end if

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

    call ni3_close( NcID )


  end subroutine IOProfileReadPtcl

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

  subroutine IOProfileOutput( &
    & OutNcFn, &
    & NLev, NMolNum, r_Press, m_MolNum, &
    & r_Temp, rm_VMR, Ps, Ts, &
    & z_Press, &
    & NChar, NPtcl, a_PtclNum, a_PtclName, &
    & a_PtclDens, za_PtclEffRad, za_PtclMMR &
    & )

    character(*), intent(in) :: OutNcFn
    integer     , intent(in) :: NLev
    integer     , intent(in) :: NMolNum
    real(dp)    , intent(in) :: r_Press (NLev)
    integer     , intent(in) :: m_MolNum(NMolNum)
    real(dp)    , intent(in) :: r_Temp  (NLev)
    real(dp)    , intent(in) :: rm_VMR  (NLev,NMolNum)
    real(dp)    , intent(in) :: Ps
    real(dp)    , intent(in) :: Ts
    real(dp)    , intent(in) :: z_Press      (NLev-1)
    integer     , intent(in) :: NChar
    integer     , intent(in) :: NPtcl
    integer     , intent(in) :: a_PtclNum    (NPtcl)
    character(*), intent(in) :: a_PtclName   (NPtcl)
    real(dp)    , intent(in) :: a_PtclDens   (NPtcl)
    real(dp)    , intent(in) :: za_PtclEffRad(NLev-1,NPtcl)
    real(dp)    , intent(in) :: za_PtclMMR   (NLev-1,NPtcl)


    ! Local variables
    !
    integer                 :: NcID
    character(extstr)       :: Mode
    character(extstr)       :: Name
    character(extstr)       :: StdName
    character(extstr)       :: LongName
    character(extstr)       :: Units
    integer                 :: NDims
    character(extstr), allocatable :: a_DimNames(:)

    integer                 :: a_CharNum( NChar )

    integer :: l


    do l = 1, NChar
      a_CharNum(l) = l
    end do


    ! Output

    Mode = "new"
    call ni3_open( OutNcFN, Mode, NcID )

    Name     = "Press"
    StdName  = Name
    LongName = "Pressure"
    Units    = "Pa"
    call ni3_set_dim( NcID, Name, NI3_DOUBLE, r_Press, &
      & StdName, LongName, Units )
    Name     = "MolNum"
    StdName  = Name
    LongName = "Molecular number"
    Units    = "1"
    call ni3_set_dim( NcID, Name, NI3_DOUBLE, m_MolNum, &
      & StdName, LongName, Units )
    Name     = "PtclNum"
    StdName  = Name
    LongName = "Particle number"
    Units    = "1"
    call ni3_set_dim( NcID, Name, NI3_INT, a_PtclNum, &
      & StdName, LongName, Units )
    Name     = "PressM"
    StdName  = Name
    LongName = "Pressure"
    Units    = "Pa"
    call ni3_set_dim( NcID, Name, NI3_DOUBLE, z_Press, &
      & StdName, LongName, Units )
    Name     = "CharNum"
    StdName  = Name
    LongName = "character number"
    Units    = "1"
    call ni3_set_dim( NcID, Name, NI3_INT, a_CharNum, &
      & StdName, LongName, Units )


    NDims = 1
    allocate( a_DimNames( NDims ) )
    !
    Name     = "Temp"
    StdName  = Name
    LongName = "Temperature"
    Units    = "K"
    a_DimNames( 1 ) = "Press"
    call ni3_def_var( NcID, Name, NI3_DOUBLE, NDims, a_DimNames, &
      & StdName, LongName, Units )
    call ni3_put_var( NcID, Name, r_Temp )
!!$  !
!!$  Name     = "MolWt"
!!$  StdName  = Name
!!$  LongName = "Molecular weight"
!!$  Units    = "kg mol-1"
!!$  a_DimNames( 1 ) = "MolNum"
!!$  call ni3_def_var( NcID, Name, NI3_DOUBLE, NDims, a_DimNames, &
!!$    & StdName, LongName, Units )
!!$  call ni3_put_var( NcID, Name, m_MolWt )
    !
    deallocate( a_DimNames )


    NDims = 2
    allocate( a_DimNames( NDims ) )
    !
    Name     = "VMR"
    StdName  = Name
    LongName = "Volume mixing ratio"
    Units    = "1"
    a_DimNames( 1 ) = "Press"
    a_DimNames( 2 ) = "MolNum"
    call ni3_def_var( NcID, Name, NI3_DOUBLE, NDims, a_DimNames, &
      & StdName, LongName, Units )
    call ni3_put_var( NcID, Name, rm_VMR )
    !
    deallocate( a_DimNames )

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

    NDims = 0
    allocate( a_DimNames( NDims ) )
    !
    Name     = "Ts"
    StdName  = Name
    LongName = "Surface temperature"
    Units    = "K"
    call ni3_def_var( NcID, Name, NI3_DOUBLE, NDims, a_DimNames, &
      & StdName, LongName, Units )
    call ni3_put_var( NcID, Name, Ts )
    !
    Name     = "Ps"
    StdName  = Name
    LongName = "Surface pressure"
    Units    = "Pa"
    call ni3_def_var( NcID, Name, NI3_DOUBLE, NDims, a_DimNames, &
      & StdName, LongName, Units )
    call ni3_put_var( NcID, Name, Ps )
    !
    deallocate( a_DimNames )

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

    NDims = 1
    allocate( a_DimNames( NDims ) )
    !
    Name     = "PtclDens"
    StdName  = Name
    LongName = "particle density"
    Units    = "kg m-3"
    a_DimNames( 1 ) = "PtclNum"
    call ni3_def_var( NcID, Name, NI3_DOUBLE, NDims, a_DimNames, &
      & StdName, LongName, Units )
    call ni3_put_var( NcID, Name, a_PtclDens )
    !
    deallocate( a_DimNames )

    NDims = 2
    allocate( a_DimNames( NDims ) )
    !
    Name     = "PtclName"
    StdName  = Name
    LongName = "particle name"
    Units    = "m"
    a_DimNames( 1 ) = "CharNum"
    a_DimNames( 2 ) = "PtclNum"
    call ni3_def_var( NcID, Name, NI3_CHAR, NDims, a_DimNames, &
      & StdName, LongName, Units )
    call ni3_put_var( NcID, Name, a_PtclName )
    !
    Name     = "PtclEffRad"
    StdName  = Name
    LongName = "particle effective radius"
    Units    = "m"
    a_DimNames( 1 ) = "PressM"
    a_DimNames( 2 ) = "PtclNum"
    call ni3_def_var( NcID, Name, NI3_DOUBLE, NDims, a_DimNames, &
      & StdName, LongName, Units )
    call ni3_put_var( NcID, Name, za_PtclEffRad )
    !
    Name     = "PtclMMR"
    StdName  = Name
    LongName = "particle mass mixing ratio"
    Units    = "1"
    a_DimNames( 1 ) = "PressM"
    a_DimNames( 2 ) = "PtclNum"
    call ni3_def_var( NcID, Name, NI3_DOUBLE, NDims, a_DimNames, &
      & StdName, LongName, Units )
    call ni3_put_var( NcID, Name, za_PtclMMR )
    !
    deallocate( a_DimNames )

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

    call ni3_close( NcID )


  end subroutine IOProfileOutput

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

end module io_profile
