      module mod_raw_io
      contains


! Modified from Alan Wallcraft's RAW routine by Knut Liseter @ NERSC
! So far only the "I" in "IO" is present
      SUBROUTINE READRAW(A,AMN,AMX,IDM,JDM,LSPVAL,SPVAL,CFILE1,K)
      IMPLICIT NONE
C
      REAL*4     SPVALH
      PARAMETER (SPVALH=1.0E30_4)
C
      REAL*4,        INTENT(OUT) :: A(IDM,JDM)
      REAL*4,        INTENT(OUT) :: AMN,AMX
      INTEGER,       INTENT(IN)  :: IDM,JDM
      LOGICAL,       INTENT(IN)  :: LSPVAL
      REAL*4,        INTENT(INOUT)  :: SPVAL
      INTEGER,       INTENT(IN)  :: K
      CHARACTER(len=*), INTENT(IN)  :: CFILE1
C
      REAL*4 :: PADA(4096)
C
C     MOST OF WORK IS DONE HERE.
C

      INTEGER      LEN_TRIM
      INTEGER      I,J,IOS,NRECL
      INTEGER NPAD
C
      IF(.NOT.LSPVAL) THEN
        SPVAL = SPVALH
      ENDIF
C
!!! Calculate the number of elements padded!!!!!!!!!!!!!!!!!!!!!!!!
      NPAD=GET_NPAD(IDM,JDM)
C
      INQUIRE( IOLENGTH=NRECL) A,PADA(1:NPAD)
C     
C     
      OPEN(UNIT=11, FILE=CFILE1, FORM='UNFORMATTED', STATUS='old',
     +         ACCESS='DIRECT', RECL=NRECL, IOSTAT=IOS, ACTION='READ')
      IF     (IOS.NE.0) THEN
        write(6,*) 'Error: can''t open ',CFILE1(1:LEN_TRIM(CFILE1))
        write(6,*) 'ios   = ',ios
        write(6,*) 'nrecl = ',nrecl
        CALL EXIT(3)
      ENDIF
C
      READ(11,REC=K,IOSTAT=IOS) A
      close(11)
C
      IF     (IOS.NE.0) THEN
        WRITE(6,*) 'can''t read record ',K,
     &             ' from '//CFILE1(1:LEN_TRIM(CFILE1))
        CALL EXIT(4)
      ENDIF
C
      AMN =  SPVALH
      AMX = -SPVALH
      DO J= 1,JDM
      DO I=1,IDM
         IF     (A(I,J).LE.SPVALH) THEN
            AMN = MIN(real(AMN, 4), real(A(I,J), 4))
            AMX = MAX(real(AMX, 4), real(A(I,J), 4))
         ELSEIF (LSPVAL) THEN
            A(I,J) = SPVAL
         ENDIF
      END DO
      END DO
C                 
      RETURN
      END SUBROUTINE

! Modified from Alan Wallcraft's RAW routine by Knut Liseter @ NERSC
! This wll be the  "O" in "IO" is present
      SUBROUTINE WRITERAW(A,AMN,AMX,IDM,JDM,LSPVAL,SPVAL,CFILE1,K)
      IMPLICIT NONE
C
      REAL*4     SPVALH
      PARAMETER (SPVALH=1.0e30_4)
C
      REAL*4,        INTENT(INOUT) :: A(IDM,JDM)
      REAL*4,        INTENT(OUT)   :: AMN,AMX
      INTEGER,       INTENT(IN)    :: IDM,JDM
      LOGICAL,       INTENT(IN)    :: LSPVAL
      REAL*4,        INTENT(INOUT) :: SPVAL
      INTEGER,       INTENT(IN)    :: K
      CHARACTER(len=*), INTENT(IN) :: CFILE1
C
      REAL*4 :: PADA(4096)
C
C     MOST OF WORK IS DONE HERE.
C

      INTEGER      LEN_TRIM
      INTEGER      I,J,IOS,NRECL
      INTEGER NPAD
C
      IF(.NOT.LSPVAL) THEN
        SPVAL = SPVALH
      ENDIF
C
!!! Calculate the number of elements padded!!!!!!!!!!!!!!!!!!!!!!!!
      NPAD=GET_NPAD(IDM,JDM)
C
      PADA=0.
      INQUIRE( IOLENGTH=NRECL) A,PADA(1:NPAD)
C     
C     
      OPEN(UNIT=11, FILE=CFILE1, FORM='UNFORMATTED', STATUS='unknown',
     +         ACCESS='DIRECT', RECL=NRECL, IOSTAT=IOS)
      IF     (IOS.NE.0) THEN
        write(6,*) 'Error: can''t open ',CFILE1(1:LEN_TRIM(CFILE1))
        write(6,*) 'ios   = ',ios
        write(6,*) 'nrecl = ',nrecl
        CALL EXIT(3)
      ENDIF
C
      WRITE(11,REC=K,IOSTAT=IOS) A,PADA(1:NPAD)
      close(11)
C
      IF     (IOS.NE.0) THEN
        WRITE(6,*) 'can''t write record ',K,
     &             ' from '//CFILE1(1:LEN_TRIM(CFILE1))
        CALL EXIT(4)
      ENDIF
C
      AMN =  SPVALH
      AMX = -SPVALH
      DO J= 1,JDM
      DO I=1,IDM
         IF     (A(I,J).LE.SPVALH) THEN
            AMN = MIN(real(AMN, 4), real(A(I,J), 4))
            AMX = MAX(real(AMX, 4), real(A(I,J), 4))
         ELSEIF (LSPVAL) THEN
            A(I,J) = SPVAL
         ENDIF
      END DO
      END DO
C                 
      RETURN
      END SUBROUTINE



!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Routine to get index of fields in data file (.a) from header file (.b)
      subroutine rst_index_from_header(fname,cfld,vlevel,tlevel,
     &                                 indx,bmin,bmax,skiphdr) 
      implicit none
      character(len=*), intent(in) :: fname     ! filename without extention
      character(len=*), intent(in) :: cfld      ! variable name
      integer         , intent(in) :: tlevel    ! time level
      integer         , intent(in) :: vlevel    ! vertical level
      integer         , intent(out):: indx      ! index in .a file
      real            , intent(out):: bmin,bmax ! min and max from b file
      logical         , intent(in) :: skiphdr

      integer :: itlevel, ivlevel
      character(len=8) :: icfld
      integer :: ios,i
      integer :: nskip_rst,nop
      logical :: match, ex

      nskip_rst=2
      nop = 999

      ! Open file
      inquire(exist=ex,file=trim(fname))
      if (.not. ex) then
         print *,'file '//trim(fname)//' is not present'
         call exit(1)
      end if
      open(nop,file=trim(fname),status='old',action='read')

      ! Skip first nskip lines
      if (skiphdr) then
         do i=1,nskip_rst
            read(nop,*)
         end do
      end if

      match=.false.
      indx=0
      ios=0
      do while (ios==0 .and. .not.match)
         read(nop,117,iostat=ios) icfld,ivlevel,itlevel,bmin,bmax
         match= icfld==cfld .and. ivlevel==vlevel .and. itlevel==tlevel
         indx=indx+1
         !print *,icfld,itlevel,ivlevel,bmin,bmax
      end do

      close(nop)

      if (.not.match) then
         !print *,'Could not find field '//cfld
         !print *,'Vertical level :',vlevel
         !print *,'Time     level :',tlevel
         indx=-1
         !call exit(1) ! Always return to caller
      endif

  117 format (a8,23x,i3,i3,2x,2e16.7)

      end subroutine
      
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Routine to get field desc in  header file (.b) from index in data file (.a)
      subroutine rst_header_from_index(fname,cfld,vlevel,tlevel,
     &                                 indx,bmin,bmax,skiphdr) 
      implicit none
      character(len=*), intent(in)  :: fname     ! filename without extention
      character(len=8), intent(out) :: cfld      ! variable name
      integer         , intent(out) :: tlevel    ! time level
      integer         , intent(out) :: vlevel    ! vertical level
      integer         , intent(in)  :: indx      ! index in .a file
      real            , intent(out) :: bmin,bmax ! min and max from b file
      logical         , intent(in ) :: skiphdr   ! Skip header of .b file

      integer :: ios,i
      integer :: nskip_rst,nop
      logical :: ex


      nskip_rst=2
      nop = 999

      ! Open file
      inquire(exist=ex,file=trim(fname))
      if (.not. ex) then
         print *,'file '//trim(fname)//' not present'
         call exit(1)
      end if
      open(nop,file=trim(fname),status='old',action='read')


      ! Skip first nskip + index-1 lines
      !print *,'hei'
      if (skiphdr) then
         do i=1,nskip_rst
            read(nop,*)
         end do
      end if
      do i=1,indx-1
         read(nop,*)
      end do
      read(nop,117,iostat=ios) cfld,vlevel,tlevel,bmin,bmax
      close(nop)

      if (ios/=0) then
         !print *,'Could not get info from  index',indx
         !call exit(1)
         cfld=''
         tlevel=-1
         vlevel=-1
      endif

  117 format (a8,23x,i3,i3,2x,2e16.7)

      end subroutine
      

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Routine to get index of fields in regional grid file (.a) from header file (.b)
      subroutine grid_index_from_header(fname,cfld,indx,bmin,bmax
     &                                  ,skiphdr) 
      implicit none
      character(len=*), intent(in) :: fname     ! filename without extention
      character(len=*), intent(in) :: cfld      ! variable name
      integer         , intent(out):: indx      ! index in .a file
      real            , intent(out):: bmin,bmax ! min and max from b file
      logical         , intent(in) :: skiphdr

      character(len=4) :: icfld
      character*80 :: cline
      integer :: ios,i
      integer :: nskip_grid,nop
      logical :: match, ex

      nskip_grid=3
      nop = 999

      ! Open file
      inquire(exist=ex,file=trim(fname))
      if (.not. ex) then
         print *,'file '//trim(fname)//' is not present'
         call exit(1)
      end if
      open(nop,file=trim(fname),status='old',action='read')


      ! Skip first nskip lines
      if (skiphdr) then
         do i=1,nskip_grid
            read(nop,*)
         end do
      end if

      match=.false.
      indx=0
      ios=0
      do while (ios==0 .and. .not.match)
         read(nop,'(a)') cline
         icfld=cline(1:4)
         i=index(cline,'=')
         read (cline(i+1:),*) bmin,bmax
         match= trim(icfld)==trim(cfld)
         indx=indx+1
      end do

      close(nop)

      if (.not.match) then
         indx=-1
      endif
      end subroutine grid_index_from_header


!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Routine to get index of fields in regional grid file (.a) from header file (.b)
      subroutine daily_index_from_header(fname,cfld,coord,indx,
     &   bmin,bmax)
      implicit none
      character(len=*), intent(in) :: fname     ! filename without extention
      character(len=*), intent(in) :: cfld      ! variable name
      integer         , intent(in) :: coord     ! vertical coordinate
      integer         , intent(out):: indx      ! index in .a file
      real            , intent(out):: bmin,bmax ! min and max from b file

      logical, parameter:: skiphdr=.true.
      character(len=5) :: char5
      character(len=8) :: char8
      integer :: ios
      integer :: nop
      logical :: match, ex
      real    :: dens,rday
      integer :: lcoord,nstep

      nop = 999

      ! Open file
      inquire(exist=ex,file=trim(fname))
      if (.not. ex) then
         print *,'file '//trim(fname)//' is not present'
         call exit(1)
      end if
      open(nop,file=trim(fname),status='old')

      ! Skip first nskip lines
      if (skiphdr) then
         do while (char5/='field' .and. ios==0)
            read(nop,'(a5)',iostat=ios) char5
         end do
      end if

      ! Read until we get the field we want
      indx=0
      ios=0
      char8=''
      lcoord=-1
      match=.false.
      do while(.not.match .and. ios==0)
         read(nop,117,iostat=ios) char8,nstep,rday,lcoord,dens,
     &                            bmin,bmax
         match=(trim(cfld)==trim(char8) .and. lcoord==coord)
         indx=indx+1
      end do
      close(nop)

      if (.not.match) then
         indx=-1
      endif

  117 format (a8,' = ',i11,f11.2,i3,f7.3,1p2e16.7)
      end subroutine daily_index_from_header


!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!







      INTEGER FUNCTION GET_NPAD(IDM,JDM)
      IMPLICIT NONE
      INTEGER, INTENT(IN) :: IDM,JDM
         GET_NPAD = 4096 - MOD(IDM*JDM,4096)
         GET_NPAD = mod(GET_NPAD,4096)
      END FUNCTION
      end module mod_raw_io
