! Module  : mem_photsource_m
! Purpose : Define hdf5_photsource_t type, for representing a
!           source of photint_t's stored in memory
!
! Copyright 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 mem_photsource_m

   ! Uses

   use forum_m

   use photint_m
   use photsource_m
   use stat_m

   use ISO_FORTRAN_ENV

   ! No implicit typing

   implicit none

   ! Derived-type definitions

   type, extends(photsource_t) :: mem_photsource_t
      private
      class(photint_t), allocatable :: photints(:)
      integer                       :: n
   contains
      private
      procedure, public :: get_n
      procedure, public :: fetch
   end type mem_photsource_t

   ! Interfaces

   interface mem_photsource_t
      module procedure mem_photsource_t_
   end interface mem_photsource_t

   ! Access photifiers

   private

   public :: mem_photsource_t

contains

   function mem_photsource_t_(photints) result(photsource)

      class(photint_t), intent(in) :: photints(:)
      type(mem_photsource_t)       :: photsource

      ! Construct photsource with the array of photints

      ! Use sourced allocation rather than assignment, to work around
      ! gfortran PR 110877

      allocate(photsource%photints, SOURCE=photints)

      photsource%n = SIZE(photints)

      ! Finish

      return

   end function mem_photsource_t_

   !****

   subroutine get_n(self, n)

      class(mem_photsource_t), intent(in) :: self
      integer, intent(out)                :: n

      ! Get n

      n = self%n

      ! Finish

      return

   end subroutine get_n

   !****

   subroutine fetch(self, i, photint, stat)

      class(mem_photsource_t), intent(in)        :: self
      integer, intent(in)                        :: i
      class(photint_t), allocatable, intent(out) :: photint
      integer, intent(out), optional             :: stat

      ! Fetch the photint from memory

      if (i < 0 .OR. i > self%n) then
         if (PRESENT(stat)) then
            stat = STAT_INVALID_ARGUMENT
            return
         else
            @:ABORT('invalid argument')
         end if
      end if

      photint = self%photints(i)

      ! Finish

      if (PRESENT(stat)) stat = STAT_OK

      return

   end subroutine fetch

end module mem_photsource_m
