module ac_calc_utils

  use vtype_module

  implicit none

  private

  public :: ACCalcUtilsModifyWavenumberRange1
  public :: ACCalcUtilsModifyWavenumberRange2

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

contains

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

  subroutine ACCalcUtilsModifyWavenumberRange1( &
    & NProcs, MyRank, &
    & DelWaveNum, &
    & WaveNumS, WaveNumE &
    & )

    integer , intent(in   ) :: NProcs
    integer , intent(in   ) :: MyRank
    real(dp), intent(in   ) :: DelWaveNum
    real(dp), intent(inout) :: WaveNumS
    real(dp), intent(inout) :: WaveNumE


    ! Local variables
    !
    integer :: NWaveNum
    integer :: iRank


    NWaveNum = int( ( WaveNumE - WaveNumS ) / DelWaveNum ) + 1
    WaveNumE = WaveNumS - DelWaveNum
    do iRank = 0, MyRank
      WaveNumS = WaveNumE + DelWaveNum
      WaveNumE = WaveNumS + ( int( NWaveNum / NProcs ) - 1 ) * DelWaveNum
      if ( iRank+1 <= mod( NWaveNum, NProcs ) ) then
        WaveNumE = WaveNumE + DelWaveNum
      end if
    end do


  end subroutine ACCalcUtilsModifyWavenumberRange1

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

  subroutine ACCalcUtilsModifyWavenumberRange2( &
    & FlagNetCDF, NHIT, a_HITFileName, &
    & NProcs, MyRank, &
    & NMolNum, m_MolNum, &
    & DelWaveNum, &
    & WaveNumS, WaveNumE &
    & )

    use lbl_module

    logical         , intent(in   ) :: FlagNetCDF
    integer         , intent(in   ) :: NHIT
    character(len=*), intent(in   ) :: a_HITFileName( NHIT )
    integer         , intent(in   ) :: NProcs
    integer         , intent(in   ) :: MyRank
    integer         , intent(in   ) :: NMolNum
    integer         , intent(in   ) :: m_MolNum(NMolNum)
    real(dp)        , intent(in   ) :: DelWaveNum
    real(dp)        , intent(inout) :: WaveNumS
    real(dp)        , intent(inout) :: WaveNumE


    ! Local variables
    !
    integer, parameter :: MolNumChk = 2
    logical            :: FlagClear

    type( LineParam )         :: LParam
    character(len=extstr)     :: FileName

    integer  :: iLineS
    integer  :: iLineE
    integer  :: NLine
    real(dp) :: a_WaveNumBnds(2,0:NProcs-1)

    integer :: l
    integer :: m
    integer :: n


    FlagClear = .false.
    do m = 1, NMolNum
      if ( m_MolNum(m) == MolNumChk ) then
        FlagClear = .true.
      end if
    end do
    if ( .not. FlagClear ) then
      write( 6, * ) 'Unable to find ', MolNumChk, 'th molecule.'
      write( 6, * ) ' ', m_MolNum
      stop
    end if


    m = MolNumChk

    FileName = a_HITFileName( m )
    write( 6, '(a)' ) '  Line File: ' // trim( FileName )

    if ( FlagNetCDF ) then
      call lbl_readfile_netcdf( FileName, 1, LParam )
      write( 6, '(a,i9)' ) '             Number of lines : ', LParam%NLine
    else
      write( 6, * ) 'Ascii format HITRAN data file is not supported, now.'
      stop
    end if


    do l = 1, LParam%NLine
      if ( WaveNumS <= LParam%wnlc0(l) ) exit
    end do
    iLineS = l
    iLineS = min( max( iLineS, 1 ), LParam%NLine )
    do l = iLineS, LParam%NLine
      if ( WaveNumE <= LParam%wnlc0(l) ) exit
    end do
    iLineE = l
    iLineE = min( max( iLineE, iLineS ), LParam%NLine )

    NLine = iLineE - iLineS + 1

    if ( NLine < NProcs ) then
      write( 6, * ) 'Number of processes are too large.'
      write( 6, * ) '  ', NLine, NProcs
      stop
    end if

    do n = 0, NProcs-1
      if ( n == 0 ) then
        a_WaveNumBnds(1,n) = WaveNumS
      else
        a_WaveNumBnds(1,n) = a_WaveNumBnds(2,n-1) + DelWaveNum
      end if
      if ( n == (NProcs-1) ) then
        a_WaveNumBnds(2,n) = WaveNumE
      else
        l = iLineS + int( NLine / NProcs ) * ( n+1 )
        a_WaveNumBnds(2,n) = WaveNumS &
          & + int( max( LParam%wnlc0(l) - WaveNumS, 0.0d0 ) / DelWaveNum ) * DelWaveNum
      end if
    end do

    WaveNumS = a_WaveNumBnds(1,MyRank)
    WaveNumE = a_WaveNumBnds(2,MyRank)

    if ( WaveNumS == WaveNumE ) then
      write( 6, * ) 'Unexpected zero wavenumber range for process ', MyRank
      stop
    end if

    call lbl_lineparam_finalize( LParam )


  end subroutine ACCalcUtilsModifyWavenumberRange2

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

end module ac_calc_utils
