! Module  : specint_m
! Purpose : Define specint_t abstract type, for representing spectral
!           intensity
!
! Copyright 2021-2022 Rich Townsend & The MSG Team
!
! This file is part of MSG. MSG is free software: you can redistribute
! it and/or modify it under the terms of the GNU General Public
! License as published by the Free Software Foundation, version 3.
!
! MSG is distributed in the hope that it will be useful, but WITHOUT
! ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
! License for more details.
!
! You should have received a copy of the GNU General Public License
! along with this program.  If not, see <http://www.gnu.org/licenses/>.

#:include 'forum.inc'

module specint_m

   ! No implicit typing

   implicit none

   ! Derived-type definitions

   type, abstract :: specint_t
   contains
      private
      procedure(get_lam_min), deferred, public :: get_lam_min
      procedure(get_lam_max), deferred, public :: get_lam_max
      procedure(get_precise), deferred, public :: get_precise
      procedure(get_ssize), deferred, public   :: get_ssize
      #:for name in ('intensity', 'E_moment', 'D_moment', 'flux')
         procedure(interp_${name}$), deferred, public :: interp_${name}$
      #:endfor
      procedure(subset), deferred, public :: subset
      procedure(rebin), deferred, public  :: rebin
      procedure(filter), deferred, public :: filter
      procedure(read), deferred, public   :: read
      procedure(write), deferred, public  :: write
   end type specint_t

   ! Interfaces

   abstract interface

      #:for name, type in (('lam_min', 'real(RD)'),  &
                           ('lam_max', 'real(RD)'),  &
                           ('precise', 'logical'),   &
                           ('ssize', 'integer(ID)'))     

         subroutine get_${name}$(self, ${name}$)
            use forum_m
            import specint_t
            class(specint_t), intent(in) :: self
            ${type}$, intent(out)        :: ${name}$
         end subroutine get_${name}$
      
      #:endfor

      #:for name, arg_var, arg_type in (('intensity', 'mu', 'real(RD)'), &
                                        ('E_moment', 'k', 'integer'), &
                                        ('D_moment', 'l', 'integer'))

         subroutine interp_${name}$(self, ${arg_var}$, lam, res, stat)
            use forum_m
            import specint_t
            class(specint_t), intent(in)   :: self
            ${arg_type}$, intent(in)       :: ${arg_var}$
            real(RD), intent(in)           :: lam(:)
            real(RD), intent(out)          :: res(:)
            integer, intent(out), optional :: stat
         end subroutine interp_${name}$

      #:endfor
      
      #:for name, var in (('flux', 'F'),)

         subroutine interp_${name}$(self, lam, res, stat)
            use forum_m
            import specint_t
            class(specint_t), intent(in)   :: self
            real(RD), intent(in)           :: lam(:)
            real(RD), intent(out)          :: res(:)
            integer, intent(out), optional :: stat
         end subroutine interp_${name}$

      #:endfor

      subroutine subset(self, lam_min, lam_max, specint, stat)
         use forum_m
         import specint_t
         class(specint_t), intent(in)               :: self
         real(RD), intent(in)                       :: lam_min
         real(RD), intent(in)                       :: lam_max
         class(specint_t), allocatable, intent(out) :: specint
         integer, intent(out), optional             :: stat
      end subroutine subset

      subroutine rebin(self, range, specint, stat)
         use forum_m
         use range_m
         import specint_t
         class(specint_t), intent(in)               :: self
         class(range_t), intent(in)                 :: range
         class(specint_t), allocatable, intent(out) :: specint
         integer, intent(out), optional             :: stat
      end subroutine rebin

      subroutine filter(self, passband, photint, stat)
         use forum_m
         use passband_m
         use photint_m
         import specint_t
         class(specint_t), intent(in)               :: self
         type(passband_t), intent(in)               :: passband
         class(photint_t), allocatable, intent(out) :: photint
         integer, intent(out), optional             :: stat
      end subroutine filter

      subroutine read(self, hdf5io, stat)
         use forum_m
         import specint_t
         class(specint_t), intent(out)  :: self
         type(hdf5io_t), intent(inout)  :: hdf5io
         integer, intent(out), optional :: stat
      end subroutine read
         
      subroutine write(self, hdf5io, stat)
         use forum_m
         import specint_t
         class(specint_t), intent(in)   :: self
         type(hdf5io_t), intent(inout)  :: hdf5io
         integer, intent(out), optional :: stat
      end subroutine write
         
   end interface
         
   interface specint_t

      module function specint_t_type_(type) result(specint)
         character(*), intent(in)      :: type
         class(specint_t), allocatable :: specint
      end function specint_t_type_

   end interface specint_t
   
   ! Access specifiers

   private

   public :: specint_t

end module specint_m
