module cubetools_ascii
  use cubetools_parameters
  use cubetools_messaging
  !
  public :: writ_l
  public :: ascii_file_t
  private
  !
  character(len=*), parameter :: readwrite(3) = &
       ['readonly ','writeonly','readwrite']
  integer(kind=code_k), parameter :: read_only  = 1
  integer(kind=code_k), parameter :: write_only = 2
  integer(kind=code_k), parameter :: read_write = 3
  !
  integer(kind=4), parameter :: lun_k = 4
  integer(kind=4), parameter :: line_k = 4
  integer(kind=4), parameter :: writ_l = 256
  !
  type ascii_file_t
     character(len=file_l),private :: name
     integer(kind=code_k), private :: status
     integer(kind=lun_k),  private :: lun
     integer(kind=line_k), private :: iline
     integer(kind=line_k), private :: nline
   contains
     procedure, public :: open       => cubetools_ascii_file_open
     procedure, public :: read_next  => cubetools_ascii_file_read_next
     procedure, public :: write_next => cubetools_ascii_file_write_next
     procedure, public :: get_nline  => cubetools_ascii_file_get_nline
     procedure, public :: close      => cubetools_ascii_file_close
  end type ascii_file_t
  !
contains
  !
  subroutine cubetools_ascii_file_open(file,name,status,error)
    use gkernel_interfaces
    use cubetools_disambiguate
    !----------------------------------------------------------------------
    ! Opens an ASCII file 
    !----------------------------------------------------------------------
    class(ascii_file_t), intent(out)   :: file
    character(len=*),    intent(in)    :: name
    character(len=*),    intent(in)    :: status
    logical,             intent(inout) :: error
    !
    character(len=argu_l) :: argu
    integer(kind=4) :: ier
    character(len=*), parameter :: rname='ASCII>FILE>OPEN'
    !
    call cubetools_message(toolseve%trace,rname,'Welcome')
    !
    call cubetools_disambiguate_strict(status,readwrite,file%status,argu,error)
    if (error) return
    !
    ier = sic_getlun(file%lun)
    if (ier.ne.1) then
       call cubetools_message(seve%e,rname,'Cannot allocate LUN')
       error = .true.
       return
    endif
    select case(file%status)
    case(read_only)
       ier = sic_open(file%lun,name,'OLD',.true.)
    case(read_write)
       ier = sic_open(file%lun,name,'OLD',.false.)
    case(write_only)
       ier = sic_open(file%lun,name,'NEW',.false.)
    case default
       call cubetools_message(seve%e,rname,'Unrecognized status')
       error = .true.
       return
    end select
    if (ier.ne.0) then
       call cubetools_message(seve%e,rname,'Cannot open file '//name)
       error = .true.
       return
    endif
    file%name  = name
    file%iline = 0
    file%nline = 0
    !
    if (file%status.eq.read_only.or.file%status.eq.read_write) then
       do while (.true.)
          read(file%lun,*,iostat=ier)
          if (ier.ne.0) exit
          file%nline = file%nline+1
       enddo
       ier = sic_close(file%lun)
       ier = sic_open(file%lun,name,'OLD',.true.)
    endif
  end subroutine cubetools_ascii_file_open
  !
  subroutine cubetools_ascii_file_close(file,error)
    use gkernel_interfaces
    !----------------------------------------------------------------------
    ! Opens an ASCII file 
    !----------------------------------------------------------------------
    class(ascii_file_t), intent(inout) :: file
    logical,             intent(inout) :: error
    !
    integer(kind=4) :: ier
    character(len=*), parameter :: rname='ASCII>FILE>OPEN'
    !
    call cubetools_message(toolseve%trace,rname,'Welcome')
    !
    ier = sic_close(file%lun)
    call sic_frelun(file%lun)
    file%lun = 0
    file%iline = 0
    file%nline = 0
  end subroutine cubetools_ascii_file_close
  !
  function cubetools_ascii_file_get_nline(file) result(nline)
    !----------------------------------------------------------------------
    ! Gets the number of lines in an ASCII file
    !----------------------------------------------------------------------
    class(ascii_file_t),  intent(in) :: file
    integer(kind=line_k)             :: nline
    !
    character(len=*), parameter :: rname='ASCII>FILE>GET_NLINE'
    !
    call cubetools_message(toolseve%trace,rname,'Welcome')
    !
    nline = file%nline
  end function cubetools_ascii_file_get_nline
  !
  subroutine cubetools_ascii_file_read_next(file,line,error)
    !----------------------------------------------------------------------
    ! reads next line from an ASCII file
    ! Caveat: Line can only be up to 100 characters
    !----------------------------------------------------------------------
    class(ascii_file_t),  intent(inout) :: file
    character(len=*),     intent(out)   :: line
    logical,              intent(inout) :: error
    !
    character(len=*), parameter :: rname='ASCII>FILE>READ>NEXT'
    !
    call cubetools_message(toolseve%trace,rname,'Welcome')
    !
    file%iline = file%iline+1
    if (file%iline.gt.file%nline) then
       call cubetools_message(seve%e,rname,'Trying to read beyond end of the file')
       error = .true.
       return
    endif
    read(file%lun,'(a)') line
  end subroutine cubetools_ascii_file_read_next
  !
  subroutine cubetools_ascii_file_write_next(file,line,error)
    !----------------------------------------------------------------------
    ! write next line to an ASCII file
    !----------------------------------------------------------------------
    class(ascii_file_t),  intent(inout) :: file
    character(len=*),     intent(in)    :: line
    logical,              intent(inout) :: error
    !
    character(len=*), parameter :: rname='ASCII>FILE>WRITE>NEXT'
    !
    call cubetools_message(toolseve%trace,rname,'Welcome')
    !
    write(file%lun,'(a)') trim(line)
    file%iline = file%iline+1
    file%nline = file%nline+1
  end subroutine cubetools_ascii_file_write_next
end module cubetools_ascii
