! Module  : file_m
! Purpose : file-oriented support routines
!
! 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 file_m

   ! Uses

   use forum_m

   use stat_m

   use ISO_FORTRAN_ENV
   use ISO_C_BINDING

   ! No implicit typing

   implicit none

   ! Interfaces

   interface open_file
      module procedure open_file_
      module procedure open_file_c_
   end interface open_file

   ! Access specifiers

   private

   public :: open_file
   public :: check_type

   ! Procedures

contains

   subroutine open_file_(file_name, hdf5io, stat)

      character(*), intent(in)       :: file_name
      type(hdf5io_t), intent(out)    :: hdf5io
      integer, intent(out), optional :: stat

      logical :: file_exists

      ! Check the file exists

      INQUIRE(FILE=file_name, EXIST=file_exists)

      if (file_exists) then

         ! Open the file

         if (is_hdf5(file_name)) then

            hdf5io = hdf5io_t(file_name, OPEN_FILE_RO)

            if (PRESENT(stat)) stat = STAT_OK

         else

            if (PRESENT(stat)) then
               stat = STAT_INVALID_FILE_TYPE
            else
               @:ABORT('invalid file type')
            endif

         end if

      else

         if (PRESENT(stat)) then
            stat = STAT_FILE_NOT_FOUND
         else
            @:ABORT('file not found')
         endif

      endif

      ! Finish

      return

   end subroutine open_file_

   !****

   subroutine open_file_c_(c_file_name, hdf5io, stat)

      character(C_CHAR), intent(in)  :: c_file_name(*)
      type(hdf5io_t), intent(out)    :: hdf5io
      integer, intent(out), optional :: stat

      character(:), allocatable :: file_name
      
      ! Open the file

      call c_f_string(c_file_name, file_name)

      call open_file_(file_name, hdf5io, stat)

      ! Finish

   end subroutine open_file_c_

   !****

   subroutine check_type(hdf5io, type, stat)

      type(hdf5io_t), intent(inout)  :: hdf5io
      character(*), intent(in)       :: type
      integer, intent(out), optional :: stat

      character(TYPE_LEN) :: type_
      
      ! Check the type attribute stored in the HDF5 group

      if (hdf5io%attr_exists('TYPE')) then

         call hdf5io%read_attr('TYPE', type_)
         if (type_ /= type) then
            if (PRESENT(stat)) then
               stat = STAT_INVALID_GROUP_TYPE
               return
            else
               @:ABORT('invalid group type')
            end if
         end if

      else

         if (PRESENT(stat)) then
            stat = STAT_INVALID_GROUP_TYPE
            return
         else
            @:ABORT('invalid file type')
         end if

      end if

      ! Finish

      if (PRESENT(stat)) stat = STAT_OK

      return

   end subroutine check_type

end module file_m

