! Module  : range_m
! Purpose : Define range_t abstract type, represnting an ordered sequence
!           of values spanning a range
!
! 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 range_m

   ! No implicit typing

   implicit none

   ! Derived-type definitions

   type, abstract :: range_t
   contains
      procedure(get_n), deferred     :: get_n
      procedure(get_x_min), deferred :: get_x_min
      procedure(get_x_max), deferred :: get_x_max
      procedure(get_ssize), deferred :: get_ssize
      procedure(unpack), deferred    :: unpack
      procedure(subset), deferred    :: subset
      procedure(read), deferred      :: read
      procedure(write), deferred     :: write
   end type range_t

   ! Interfaces

   abstract interface

      #:for name, type in (('n', 'integer'), &
                           ('x_min', 'real(RD)'), &
                           ('x_max', 'real(RD)'), &
                           ('ssize', 'integer(ID)'))
                           
         subroutine get_${name}$(self, ${name}$)
            use forum_m
            import range_t
            class(range_t), intent(in) :: self
            ${type}$, intent(out)       :: ${name}$
         end subroutine get_${name}$

      #:endfor

      subroutine unpack(self, x)
         use forum_m
         import range_t
         class(range_t), intent(in)  :: self
         real(RD), intent(out)       :: x(:)
      end subroutine unpack

      subroutine subset(self, i_a, i_b, range, stat)
         import range_t
         class(range_t), intent(in)               :: self
         integer, intent(in)                      :: i_a
         integer, intent(in)                      :: i_b
         class(range_t), allocatable, intent(out) :: range
         integer, intent(out), optional           :: stat
      end subroutine subset

      subroutine read(self, hdf5io, stat)
         use forum_m
         import range_t
         class(range_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 range_t
         class(range_t), intent(in)     :: self
         type(hdf5io_t), intent(inout)  :: hdf5io
         integer, intent(out), optional :: stat
      end subroutine write

   end interface

   interface range_t

      module function range_t_type_(type) result(range)
         character(*), intent(in)    :: type
         class(range_t), allocatable :: range
      end function range_t_type_

   end interface range_t
   
   ! Access specifiers

   private

   public :: range_t

end module range_m
