module cubeio_interfaces_private
  interface
    subroutine cubeio_create_and_truncate_hgdf(header,desc,oorder,dim3,hgdf,error)
      use image_def
      use cubetools_header_types
      use cubeio_header
      use cubeio_cube
      use cubeio_desc
      use cubeio_messaging
      !---------------------------------------------------------------------
      ! @ private
      ! Same as cubeio_create_hgdf, but truncate the 3rd dimension to
      ! requested size.
      !---------------------------------------------------------------------
      type(cube_header_t),  intent(in)    :: header
      type(cubeio_desc_t),  intent(in)    :: desc
      integer(kind=code_k), intent(in)    :: oorder
      integer(kind=data_k), intent(in)    :: dim3
      type(gildas),         intent(inout) :: hgdf
      logical,              intent(inout) :: error
    end subroutine cubeio_create_and_truncate_hgdf
  end interface
  !
  interface
    subroutine cubeio_create_hfits(header,oorder,hfits,error)
      use cubefitsio_header
      use cubetools_parameters
      use cubetools_header_types
      use cubeio_header
      !---------------------------------------------------------------------
      ! @ private
      ! Create or recreate the hfits by converting the header with requested
      ! order.
      !---------------------------------------------------------------------
      type(cube_header_t),   intent(in)    :: header
      integer(kind=code_k),  intent(in)    :: oorder
      type(fitsio_header_t), intent(inout) :: hfits
      logical,               intent(inout) :: error
    end subroutine cubeio_create_hfits
  end interface
  !
  interface
    subroutine cubeio_create_and_truncate_hfits(header,oorder,dim3,hfits,error)
      use cubefitsio_header
      use cubetools_parameters
      use cubetools_header_types
      use cubeio_header
      use cubeio_messaging
      !---------------------------------------------------------------------
      ! @ private
      ! Same as cubeio_create_hgdf, but truncate the 3rd dimension to
      ! requested size.
      !---------------------------------------------------------------------
      type(cube_header_t),   intent(in)    :: header
      integer(kind=code_k),  intent(in)    :: oorder
      integer(kind=data_k),  intent(in)    :: dim3
      type(fitsio_header_t), intent(inout) :: hfits
      logical,               intent(inout) :: error
    end subroutine cubeio_create_and_truncate_hfits
  end interface
  !
  interface
    subroutine cubeio_iterate_read_chan(cubset,cubdef,head,icub,fchan,lchan,error)
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_cube_define
      use cubeio_cube
      use cubeio_messaging
      !---------------------------------------------------------------------
      ! @ private
      ! Pre-load all or part of the data from disk in a buffer which
      ! provides (at least) the requested channel range.
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cube_define_t),  intent(in)    :: cubdef
      type(cube_header_t),  intent(in)    :: head
      type(cubeio_cube_t),  intent(inout) :: icub
      integer(kind=chan_k), intent(in)    :: fchan
      integer(kind=chan_k), intent(in)    :: lchan
      logical,              intent(inout) :: error
    end subroutine cubeio_iterate_read_chan
  end interface
  !
  interface
    subroutine cubeio_iterate_read_pix(cubset,cubdef,head,icub,fypix,lypix,error)
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_cube_define
      use cubeio_cube
      use cubeio_messaging
      !---------------------------------------------------------------------
      ! @ private
      ! Pre-load all or part of the data from disk in a buffer which
      ! provides (at least) the requested Y pixel row range.
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cube_define_t),  intent(in)    :: cubdef
      type(cube_header_t),  intent(in)    :: head
      type(cubeio_cube_t),  intent(inout) :: icub
      integer(kind=pixe_k), intent(in)    :: fypix
      integer(kind=pixe_k), intent(in)    :: lypix
      logical,              intent(inout) :: error
    end subroutine cubeio_iterate_read_pix
  end interface
  !
  interface
    subroutine cubeio_iterate_read_subcube(cubset,cubdef,head,icub,first,last,error)
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_cube_define
      use cubeio_cube
      use cubeio_messaging
      !---------------------------------------------------------------------
      ! @ private
      ! Pre-load all or part of the data from disk in a buffer which
      ! provides (at least) the requested range.
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cube_define_t),  intent(in)    :: cubdef
      type(cube_header_t),  intent(in)    :: head
      type(cubeio_cube_t),  intent(inout) :: icub
      integer(kind=data_k), intent(in)    :: first
      integer(kind=data_k), intent(in)    :: last
      logical,              intent(inout) :: error
    end subroutine cubeio_iterate_read_subcube
  end interface
  !
  interface
    subroutine cubeio_iterate_write_chan(cubset,cubdef,head,ocub,fchan,lchan,error)
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_cube_define
      use cubeio_cube
      use cubeio_messaging
      !---------------------------------------------------------------------
      ! @ private
      ! Prepare a buffer covering all or part of the data, providing
      ! (at least) the requested channel range.
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cube_define_t),  intent(in)    :: cubdef
      type(cube_header_t),  intent(in)    :: head
      type(cubeio_cube_t),  intent(inout) :: ocub
      integer(kind=chan_k), intent(in)    :: fchan
      integer(kind=chan_k), intent(in)    :: lchan
      logical,              intent(inout) :: error
    end subroutine cubeio_iterate_write_chan
  end interface
  !
  interface
    subroutine cubeio_iterate_write_pix(cubset,cubdef,head,ocub,fypix,lypix,error)
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_cube_define
      use cubeio_cube
      use cubeio_messaging
      !---------------------------------------------------------------------
      ! @ private
      ! Prepare a buffer covering all or part of the data, providing
      ! (at least) the requested Y pixel row range
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cube_define_t),  intent(in)    :: cubdef
      type(cube_header_t),  intent(in)    :: head
      type(cubeio_cube_t),  intent(inout) :: ocub
      integer(kind=pixe_k), intent(in)    :: fypix
      integer(kind=pixe_k), intent(in)    :: lypix
      logical,              intent(inout) :: error
    end subroutine cubeio_iterate_write_pix
  end interface
  !
  interface
    subroutine cubeio_iterate_write_subcube(cubset,cubdef,head,ocub,first,last,error)
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_cube_define
      use cubeio_cube
      use cubeio_messaging
      !---------------------------------------------------------------------
      ! @ private
      ! Prepare a buffer covering all or part of the data, providing
      ! (at least) the requested range.
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cube_define_t),  intent(in)    :: cubdef
      type(cube_header_t),  intent(in)    :: head
      type(cubeio_cube_t),  intent(inout) :: ocub
      integer(kind=data_k), intent(in)    :: first
      integer(kind=data_k), intent(in)    :: last
      logical,              intent(inout) :: error
    end subroutine cubeio_iterate_write_subcube
  end interface
  !
  interface
    subroutine cubeio_check_input_chan_block(cubset,head,cub,first,last,error)
      use cubeio_messaging
      use cubetools_setup_types
      use cubetools_header_types
      use cubeio_block
      use cubeio_chan
      use cubeio_cube
      !---------------------------------------------------------------------
      ! @ private
      ! Check if the current block buffer provides the fichan:lichan channel
      ! range. If not, flush the previous contents and load proper one.
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cube_header_t),  intent(in)    :: head
      type(cubeio_cube_t),  intent(inout) :: cub
      integer(kind=chan_k), intent(in)    :: first
      integer(kind=chan_k), intent(in)    :: last
      logical,              intent(inout) :: error
    end subroutine cubeio_check_input_chan_block
  end interface
  !
  interface
    subroutine cubeio_check_input_pix_block(cubset,head,cub,first,last,error)
      use cubeio_messaging
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_block
      use cubeio_pix
      use cubeio_cube
      !---------------------------------------------------------------------
      ! @ private
      ! Check if the current block buffer provides the fypix:lypix Y pixel
      ! row range. If not, flush the previous contents and load proper one.
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cube_header_t),  intent(in)    :: head
      type(cubeio_cube_t),  intent(inout) :: cub
      integer(kind=pixe_k), intent(in)    :: first
      integer(kind=pixe_k), intent(in)    :: last
      logical,              intent(inout) :: error
    end subroutine cubeio_check_input_pix_block
  end interface
  !
  interface
    subroutine cubeio_check_input_any_block(cubset,head,cub,first,last,error)
      use cubeio_messaging
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_subcube
      use cubeio_block
      use cubeio_cube
      !---------------------------------------------------------------------
      ! @ private
      ! Check if the current block buffer provides the fi3:li3 data
      ! range. If not, flush the previous contents and load proper one.
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cube_header_t),  intent(in)    :: head
      type(cubeio_cube_t),  intent(inout) :: cub
      integer(kind=data_k), intent(in)    :: first
      integer(kind=data_k), intent(in)    :: last
      logical,              intent(inout) :: error
    end subroutine cubeio_check_input_any_block
  end interface
  !
  interface
    subroutine cubeio_read_chan_block(cubset,cub,lmvblock,error)
      use cubeio_messaging
      use cubetools_setup_types
      use cubeio_block
      use cubeio_range
      use cubeio_cube
      !---------------------------------------------------------------------
      ! @ private
      ! Read a LMV block of channels from LMV or VLM file on disk
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cubeio_cube_t),  intent(inout) :: cub
      type(cubeio_block_t), intent(inout) :: lmvblock
      logical,              intent(inout) :: error
    end subroutine cubeio_read_chan_block
  end interface
  !
  interface
    subroutine cubeio_read_y_block(cubset,cub,vlmblock,error)
      use cubeio_messaging
      use cubetools_setup_types
      use cubeio_block
      use cubeio_range
      use cubeio_cube
      !---------------------------------------------------------------------
      ! @ private
      ! Read a VLM block of channels from VLM or LMV file on disk
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cubeio_cube_t),  intent(inout) :: cub
      type(cubeio_block_t), intent(inout) :: vlmblock
      logical,              intent(inout) :: error
    end subroutine cubeio_read_y_block
  end interface
  !
  interface
    subroutine cubeio_read_any_block(cubset,cub,anyblock,error)
      use cubeio_messaging
      use cubetools_setup_types
      use cubeio_block
      use cubeio_range
      use cubeio_cube
      !---------------------------------------------------------------------
      ! @ private
      ! Read a block of planes from file on disk
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cubeio_cube_t),  intent(inout) :: cub
      type(cubeio_block_t), intent(inout) :: anyblock
      logical,              intent(inout) :: error
    end subroutine cubeio_read_any_block
  end interface
  !
  interface cubeio_read_cube_data
    subroutine cubeio_read_cube_data_r4(rname,cubset,cub,range,data,error)
      use gkernel_types
      use cubetools_nan
      use cubetools_dataformat
      use cubetools_setup_types
      use cubefitsio_image_read
      use cubeio_range
      use cubeio_cube
      use cubeio_messaging
      use cubeio_timing
      !---------------------------------------------------------------------
      ! @ private-generic cubeio_read_cube_data
      ! Wrapper around gdf_read_data (R*4 version)
      !---------------------------------------------------------------------
      character(len=*),     intent(in)    :: rname
      type(cube_setup_t),   intent(in)    :: cubset
      type(cubeio_cube_t),  intent(inout) :: cub   ! INOUT for cub%file%hgdf%blc/trc
      type(cubeio_range_t), intent(in)    :: range
      real(kind=4),         intent(out)   :: data(:,:,:)
      logical,              intent(inout) :: error
    end subroutine cubeio_read_cube_data_r4
    subroutine cubeio_read_cube_data_c4(rname,cubset,cub,range,data,error)
      use gkernel_types
      use cubetools_dataformat
      use cubetools_setup_types
      use cubeio_range
      use cubeio_cube
      use cubeio_messaging
      use cubeio_timing
      !---------------------------------------------------------------------
      ! @ private-generic cubeio_read_cube_data
      ! Wrapper around gdf_read_data (C*4 version)
      !---------------------------------------------------------------------
      character(len=*),     intent(in)    :: rname
      type(cube_setup_t),   intent(in)    :: cubset
      type(cubeio_cube_t),  intent(inout) :: cub   ! INOUT for cub%file%hgdf%blc/trc
      type(cubeio_range_t), intent(in)    :: range
      complex(kind=4),      intent(out)   :: data(:,:,:)
      logical,              intent(inout) :: error
    end subroutine cubeio_read_cube_data_c4
  end interface cubeio_read_cube_data
  !
  interface
    subroutine cubeio_update_cube(cubset,cubdef,head,cub,error)
      use cubeio_messaging
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_cube_define
      use cubeio_header
      use cubeio_range
      use cubeio_cube
      !---------------------------------------------------------------------
      ! @ private
      ! Update a cube from memory to disk
      !---------------------------------------------------------------------
      type(cube_setup_t),  intent(in)    :: cubset
      type(cube_define_t), intent(in)    :: cubdef
      type(cube_header_t), intent(in)    :: head
      type(cubeio_cube_t), intent(inout) :: cub
      logical,             intent(inout) :: error
    end subroutine cubeio_update_cube
  end interface
  !
  interface
    subroutine cubeio_write_cube(cubset,cubdef,head,cub,error)
      use cubeio_messaging
      use cubetools_dataformat
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_header
      use cubeio_cube_define
      use cubeio_cube
      !---------------------------------------------------------------------
      ! @ private
      ! Write a cube from memory to disk
      !---------------------------------------------------------------------
      type(cube_setup_t),  intent(in)    :: cubset
      type(cube_define_t), intent(in)    :: cubdef
      type(cube_header_t), intent(in)    :: head
      type(cubeio_cube_t), intent(inout) :: cub
      logical,             intent(inout) :: error
    end subroutine cubeio_write_cube
  end interface
  !
  interface
    subroutine cubeio_write_cube_gdf(cubset,cubdef,head,cub,error)
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_header
      use cubeio_range
      use cubeio_cube_define
      use cubeio_cube
      !---------------------------------------------------------------------
      ! @ private
      ! Write cube to disk under GDF format
      !---------------------------------------------------------------------
      type(cube_setup_t),  intent(in)    :: cubset
      type(cube_define_t), intent(in)    :: cubdef
      type(cube_header_t), intent(in)    :: head
      type(cubeio_cube_t), intent(inout) :: cub
      logical,             intent(inout) :: error
    end subroutine cubeio_write_cube_gdf
  end interface
  !
  interface
    subroutine cubeio_write_cube_fits(cubset,cubdef,head,cub,error)
      use cubefitsio_image_write
      use cubefitsio_image_utils
      use cubeio_messaging
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_header
      use cubeio_range
      use cubeio_cube_define
      use cubeio_cube
      !---------------------------------------------------------------------
      ! @ private
      ! Write cube to disk under FITS format
      !---------------------------------------------------------------------
      type(cube_setup_t),  intent(in)    :: cubset
      type(cube_define_t), intent(in)    :: cubdef
      type(cube_header_t), intent(in)    :: head
      type(cubeio_cube_t), intent(inout) :: cub
      logical,             intent(inout) :: error
    end subroutine cubeio_write_cube_fits
  end interface
  !
  interface
    subroutine cubeio_check_output_chan_block(cubset,head,cub,fochan,lochan,error)
      use cubeio_messaging
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_block
      use cubeio_cube
      !---------------------------------------------------------------------
      ! @ private
      ! Check is the current block buffer provides the fochan:lochan channel
      ! range. If not, flush the previous contents and load proper one.
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cube_header_t),  intent(in)    :: head
      type(cubeio_cube_t),  intent(inout) :: cub
      integer(kind=chan_k), intent(in)    :: fochan
      integer(kind=chan_k), intent(in)    :: lochan
      logical,              intent(inout) :: error
    end subroutine cubeio_check_output_chan_block
  end interface
  !
  interface
    subroutine cubeio_check_output_pix_block(cubset,head,cub,fypix,lypix,error)
      use cubeio_messaging
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_block
      use cubeio_cube
      !---------------------------------------------------------------------
      ! @ private
      ! Check is the current block buffer provides the fypix:lypix Y pixel
      ! range. If not, flush the previous contents and load proper one.
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cube_header_t),  intent(in)    :: head
      type(cubeio_cube_t),  intent(inout) :: cub
      integer(kind=pixe_k), intent(in)    :: fypix
      integer(kind=pixe_k), intent(in)    :: lypix
      logical,              intent(inout) :: error
    end subroutine cubeio_check_output_pix_block
  end interface
  !
  interface
    subroutine cubeio_check_output_any_block(cubset,head,cub,fo3,lo3,error)
      use cubeio_messaging
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_block
      use cubeio_cube
      !---------------------------------------------------------------------
      ! @ private
      ! Check is the current block buffer provides the fo3:lo3 data
      ! range. If not, flush the previous contents and load proper one.
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cube_header_t),  intent(in)    :: head
      type(cubeio_cube_t),  intent(inout) :: cub
      integer(kind=data_k), intent(in)    :: fo3
      integer(kind=data_k), intent(in)    :: lo3
      logical,              intent(inout) :: error
    end subroutine cubeio_check_output_any_block
  end interface
  !
  interface
    subroutine cubeio_write_any_block(cubset,head,cub,block,error)
      use cubeio_messaging
      use cubefitsio_image_write
      use cubetools_dataformat
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_header
      use cubeio_block
      use cubeio_range
      use cubeio_cube
      !---------------------------------------------------------------------
      ! @ private
      ! Write a block to file on disk
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cube_header_t),  intent(in)    :: head
      type(cubeio_cube_t),  intent(inout) :: cub
      type(cubeio_block_t), intent(inout) :: block
      logical,              intent(inout) :: error
    end subroutine cubeio_write_any_block
  end interface
  !
  interface
    subroutine cubeio_flush_block(cubset,head,cub,block,error)
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_block
      use cubeio_cube
      !---------------------------------------------------------------------
      ! @ private
      ! Flush IF RELEVANT a block buffer to file on disk
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cube_header_t),  intent(in)    :: head
      type(cubeio_cube_t),  intent(inout) :: cub
      type(cubeio_block_t), intent(inout) :: block
      logical,              intent(inout) :: error
    end subroutine cubeio_flush_block
  end interface
  !
  interface
    subroutine cubeio_flush_any_block(cubset,head,cub,block,error)
      use cubeio_messaging
      use cubetools_header_types
      use cubetools_setup_types
      use cubeio_block
      use cubeio_cube
      !---------------------------------------------------------------------
      ! @ private
      ! Flush IF RELEVANT a block of planes to file on disk
      !---------------------------------------------------------------------
      type(cube_setup_t),   intent(in)    :: cubset
      type(cube_header_t),  intent(in)    :: head
      type(cubeio_cube_t),  intent(inout) :: cub
      type(cubeio_block_t), intent(inout) :: block
      logical,              intent(inout) :: error
    end subroutine cubeio_flush_any_block
  end interface
  !
  interface cubeio_write_cube_data
    subroutine cubeio_write_cube_data_r4(rname,cubset,cub,range,data,error)
      use gkernel_types
      use cubetools_dataformat
      use cubetools_setup_types
      use cubefitsio_image_write
      use cubeio_range
      use cubeio_cube
      use cubeio_timing
      use cubeio_messaging
      !---------------------------------------------------------------------
      ! @ private-generic cubeio_write_cube_data
      ! Wrapper around gdf_write_data (R*4 version)
      !---------------------------------------------------------------------
      character(len=*),     intent(in)    :: rname
      type(cube_setup_t),   intent(in)    :: cubset
      type(cubeio_cube_t),  intent(inout) :: cub   ! INOUT for cub%file%hgdf%blc/trc
      type(cubeio_range_t), intent(in)    :: range
      real(kind=4),         intent(inout) :: data(:,:,:)  ! INOUT for reblank mode
      logical,              intent(inout) :: error
    end subroutine cubeio_write_cube_data_r4
    subroutine cubeio_write_cube_data_c4(rname,cubset,cub,range,data,error)
      use gkernel_types
      use cubetools_dataformat
      use cubetools_setup_types
      use cubeio_range
      use cubeio_cube
      use cubeio_timing
      use cubeio_messaging
      !---------------------------------------------------------------------
      ! @ private-generic cubeio_write_cube_data
      ! Wrapper around gdf_write_data (C*4 version)
      !---------------------------------------------------------------------
      character(len=*),     intent(in)    :: rname
      type(cube_setup_t),   intent(in)    :: cubset
      type(cubeio_cube_t),  intent(inout) :: cub   ! INOUT for cub%file%hgdf%blc/trc
      type(cubeio_range_t), intent(in)    :: range
      complex(kind=4),      intent(inout) :: data(:,:,:)  ! INOUT for reblank mode
      logical,              intent(inout) :: error
    end subroutine cubeio_write_cube_data_c4
  end interface cubeio_write_cube_data
  !
end module cubeio_interfaces_private
