!# This source file is part of code Pégase.3.0.1 (2019-02-21).
!# Copyright: Michel Fioc (Michel.Fioc@iap.fr), Sorbonne université, 
!# Institut d'astrophysique de Paris/CNRS, France.
!# 
!# Pégase.3.0.1 is governed by the CeCILL license under French law and abides 
!# by the rules of distribution of free software. You can use, modify and/or 
!# redistribute this software under the terms of the CeCILL license as circulated 
!# by CEA, CNRS and INRIA at "http://www.cecill.info". The text of this license
!# is also available in French and in English in directory "doc_dir/" of this
!# code.
!# 
!# As a counterpart to the access to the source code and to the rights to copy,
!# modify and redistribute it granted by the license, users are provided only
!# with a limited warranty, and the software's author, the holder of the
!# economic rights, and the successive licensors have only limited
!# liability. 
!# 
!# The fact that you are presently reading this means that you have had
!# knowledge of the CeCILL license and that you accept its terms.
!#====================================================================== 

module mod_read_reserv_infall_param

  use mod_types
  use mod_analyze_statement, only : get_val, file_name, line_number, &
       error_message, warning_message
  use mod_convert_type, only : to_string
  use mod_spectra_constants, only : max_dim_reserv, max_dim_infall_epis

  implicit none
  public

  real(CDR), dimension(max_dim_reserv), save :: reserv_init_mass, &
       reserv_Z

  integer, dimension(max_dim_infall_epis), save :: infall_source
  real(CDR), dimension(max_dim_infall_epis), save :: infall_begin_time, &
       infall_end_time

  character(len=std_string), dimension(max_dim_infall_epis), save :: &
       infall_type
  real(CDR), dimension(max_dim_infall_epis), save :: infall_inst_mass, &
       infall_const_mass, &
       infall_expo_timescale, infall_expo_mass, &
       infall_reserv_timescale, infall_reserv_power
  character(len=std_string), dimension(max_dim_infall_epis), save :: &
       infall_file
  integer, dimension(max_dim_infall_epis), save :: infall_file_dim_time
  type(irreg_array_CDR), dimension(max_dim_infall_epis), save :: &
       infall_file_time, infall_file_rate

  logical, dimension(max_dim_infall_epis), private :: infall_file_set, &
       infall_expo_timescale_set, &
       infall_reserv_timescale_set

contains

!#======================================================================

  subroutine read_reserv_init_mass(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_reserv) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    call get_val(reserv_init_mass, rhs, indices_string, &
         index_present)

  end subroutine read_reserv_init_mass

!#======================================================================

  subroutine read_reserv_Z(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_reserv) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(reserv_Z, rhs, indices_string, index_present)

  end subroutine read_reserv_Z

!#======================================================================

  subroutine reset_reserv_infall

    use mod_spectra_def_param
    implicit none
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    reserv_init_mass(:) = reserv_init_mass_def
    reserv_Z(:) = reserv_Z_def

    infall_source(:) = 1

    infall_begin_time(:) = infall_begin_time_def
    infall_end_time(:) = infall_end_time_def

    infall_type(:) = infall_type_def

    infall_inst_mass(:) = infall_inst_mass_def

    infall_const_mass(:) = infall_const_mass_def

    infall_expo_timescale_set(:) = .false.
    infall_expo_mass(:) = infall_expo_mass_def

    infall_reserv_timescale_set(:) = .false.
    infall_reserv_power(:) = infall_reserv_power_def

    infall_file_set(:) = .false.

  end subroutine reset_reserv_infall

!#======================================================================

  subroutine infall_check

    implicit none
!#......................................................................
    integer :: i_epis
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    do i_epis = 1, max_dim_infall_epis
       if (infall_type(i_epis) == "none") cycle

       if (infall_type(i_epis) == "exponential") then
          if (.not. infall_expo_timescale_set(i_epis)) then
             call error_message("Value of `infall_expo_timescale(" // &
                  to_string(i_epis) // ")` is unknown.")
          endif
       endif

       if (infall_type(i_epis) == "reserv_mass") then
          if (.not. infall_reserv_timescale_set(i_epis)) then
             call error_message("Value of `infall_reserv_timescale(" // &
                  to_string(i_epis) // ")` is unknown.")
          endif
       endif

       if (infall_type(i_epis) == "file") then
          if (.not. infall_file_set(i_epis)) then
             call error_message("Value of `infall_file(" // &
                  to_string(i_epis) // ")` is unknown.")
          endif
       endif

       if (infall_end_time(i_epis) <= infall_begin_time(i_epis)) &
            call warning_message("`infall_end_time(" // &
            to_string(i_epis) // ")` = " // &
            to_string(infall_end_time(i_epis), "(f6.0)") // &
            " <= `infall_begin_time(" // to_string(i_epis) // ")` = " // &
            to_string(infall_begin_time(i_epis), "(f6.0)") // ".")
    enddo

  end subroutine infall_check

!#======================================================================

  subroutine read_infall_source(rhs, indices_string)

    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_infall_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(infall_source, rhs, indices_string, index_present)

  end subroutine read_infall_source

!#======================================================================

  subroutine read_infall_begin_time(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_infall_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(infall_begin_time, rhs, indices_string, index_present)
    where (infall_begin_time(:) > 0)
!# To make sure that the interval is closed on the left.
       infall_begin_time(:) = nearest(infall_begin_time(:), -1.)
    end where

  end subroutine read_infall_begin_time

!#======================================================================

  subroutine read_infall_end_time(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_infall_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(infall_end_time, rhs, indices_string, index_present)
    where (infall_end_time(:) > 0)
!# To make sure that the interval is open on the right.
       infall_end_time(:) = nearest(infall_end_time(:), -1.)
    end where

  end subroutine read_infall_end_time

!#======================================================================

  subroutine read_infall_type(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_infall_epis) :: index_present
    integer :: i_epis
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(infall_type, rhs, indices_string, index_present)
    do i_epis = 1, max_dim_infall_epis
       if (index_present(i_epis)) then
          if (all(infall_type(i_epis) /= (/ &
               "none         ", &
               "instantaneous", &
               "constant     ", &
               "exponential  ", &
               "reserv_mass  ", &
               "file         "/))) &
               call error_message("The value of `infall_type(" // &
               to_string(i_epis) // ")` should be ""none"", &
               &""instantaneous"", ""constant"", ""exponential"", &
               &""reserv_mass"" or ""file"".")
       endif
    enddo

  end subroutine read_infall_type

!#======================================================================
  
  subroutine read_infall_inst_mass(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_infall_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(infall_inst_mass, rhs, indices_string, index_present)
    call set_infall_type(index_present, "instantaneous")

  end subroutine read_infall_inst_mass

!#======================================================================

  subroutine read_infall_const_mass(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_infall_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(infall_const_mass, rhs, indices_string, index_present)
    call set_infall_type(index_present, "constant")

  end subroutine read_infall_const_mass

!#======================================================================

  subroutine read_infall_expo_timescale(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_infall_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(infall_expo_timescale, rhs, indices_string, index_present)
    where (index_present(:)) infall_expo_timescale_set(:) = .true.
    call set_infall_type(index_present, "exponential")

  end subroutine read_infall_expo_timescale

!#======================================================================

  subroutine read_infall_expo_mass(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_infall_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(infall_expo_mass, rhs, indices_string, index_present)
    call set_infall_type(index_present, "exponential")

  end subroutine read_infall_expo_mass

!#======================================================================

  subroutine read_infall_reserv_timescale(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_infall_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(infall_reserv_timescale, rhs, indices_string, index_present)
    where (index_present(:)) infall_reserv_timescale_set(:) = .true.
    call set_infall_type(index_present, "reserv_mass")

  end subroutine read_infall_reserv_timescale

!#======================================================================

  subroutine read_infall_reserv_power(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_infall_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(infall_reserv_power, rhs, indices_string, index_present)
    call set_infall_type(index_present, "reserv_mass")

  end subroutine read_infall_reserv_power

!#======================================================================

  subroutine read_infall_file(rhs, indices_string)

    use mod_strings, only : same_case_equal
    use mod_directories, only : scenarios_dir
    use mod_read_columns
    use mod_file_access, only : path_file

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    integer :: i_epis
    logical, dimension(max_dim_infall_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(infall_file, rhs, indices_string, index_present)

    do i_epis = 1, max_dim_infall_epis
       if (index_present(i_epis)) then
          call read_columns(path_file(scenarios_dir, adjustl(infall_file(i_epis))), &
               infall_file_dim_time(i_epis), infall_file_time(i_epis) % val, &
               infall_file_rate(i_epis) % val)
       endif
    enddo

    where (index_present(:)) infall_file_set(:) = .true.
    call set_infall_type(index_present, "file")

  end subroutine read_infall_file

!#======================================================================

  subroutine set_infall_type(index_present, string)

    implicit none
    logical, dimension(:), intent(in) :: index_present
    character(len=*), intent(in) :: string
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    where (index_present(:)) infall_type(:) = string

  end subroutine set_infall_type

end module mod_read_reserv_infall_param
