module cubetuple_entry
  use cubetools_parameters
  use cubetools_header_methods
  use cubetools_setup_types
  use cubeio_interfaces_public
  use cubeio_cube_define
  use cube_types

  public :: cubetuple_get_chan,cubetuple_get_pix,cubetuple_get_subcube
  public :: cubetuple_put_chan,cubetuple_put_pix,cubetuple_put_subcube
  private

contains

  subroutine cubetuple_get_chan(cubset,cubdef,cub,ichan,chan,error)
    use cubeio_chan
    !---------------------------------------------------------------------
    ! Get all data (Nx x Ny) for the desired channel
    !---------------------------------------------------------------------
    type(cube_setup_t),   intent(in)    :: cubset
    type(cube_define_t),  intent(in)    :: cubdef
    type(cube_t),         intent(inout) :: cub
    integer(kind=chan_k), intent(in)    :: ichan
    type(cube_chan_t),    intent(inout) :: chan
    logical,              intent(inout) :: error
    !
    call cubeio_get_chan(cubset,cubdef,cub%head,cub%tuple%current,ichan,chan,error)
    if (error)  return
  end subroutine cubetuple_get_chan

  subroutine cubetuple_get_pix(cubset,cubdef,cub,xpix,ypix,pix,error)
    use cubeio_pix
    !---------------------------------------------------------------------
    ! Get all data (Nc) for the desired pixel
    !---------------------------------------------------------------------
    type(cube_setup_t),   intent(in)    :: cubset
    type(cube_define_t),  intent(in)    :: cubdef
    type(cube_t),         intent(inout) :: cub
    integer(kind=pixe_k), intent(in)    :: xpix,ypix
    type(cube_pix_t),     intent(inout) :: pix
    logical,              intent(inout) :: error
    !
    call cubeio_get_pix(cubset,cubdef,cub%head,cub%tuple%current,xpix,ypix,pix,error)
    if (error)  return
  end subroutine cubetuple_get_pix

  subroutine cubetuple_get_subcube(cubset,cubdef,cub,first,last,subcube,error)
    use cubeio_subcube
    !---------------------------------------------------------------------
    ! Get the desired subcube from first to last plane
    !---------------------------------------------------------------------
    type(cube_setup_t),     intent(in)    :: cubset
    type(cube_define_t),    intent(in)    :: cubdef
    type(cube_t),           intent(inout) :: cub
    integer(kind=data_k),   intent(in)    :: first,last
    type(cubeio_subcube_t), intent(inout) :: subcube
    logical,                intent(inout) :: error
    !
    call cubeio_get_subcube(cubset,cubdef,cub%head,cub%tuple%current,  &
      first,last,subcube,error)
    if (error)  return
  end subroutine cubetuple_get_subcube

  subroutine cubetuple_put_chan(cubset,cubdef,cub,itask,ichan,chan,error)
    use cubeio_chan
    !---------------------------------------------------------------------
    ! Put all data (Nx x Ny) for the desired channel
    ! (This is symetric to cubeio_get_chan)
    !---------------------------------------------------------------------
    type(cube_setup_t),   intent(in)    :: cubset
    type(cube_define_t),  intent(in)    :: cubdef
    type(cube_t),         intent(inout) :: cub
    integer(kind=entr_k), intent(in)    :: itask
    integer(kind=chan_k), intent(in)    :: ichan
    type(cube_chan_t),    intent(in)    :: chan
    logical,              intent(inout) :: error
    !
    call cubeio_put_chan(cubset,cubdef,cub%head,cub%tuple%current,ichan,chan,error)
    if (error)  return
    !
    if (cubset%output%extrema .and. .not.chan%iscplx) then
      call cubetools_header_extrema_update_image(chan%r4,  &
        chan%nx,chan%ny,ichan,cub%proc%ext(itask),error)
      if (error)  return
    endif
  end subroutine cubetuple_put_chan

  subroutine cubetuple_put_pix(cubset,cubdef,cub,itask,xpix,ypix,pix,error)
    use cubeio_pix
    !---------------------------------------------------------------------
    ! Put all data (Nc) for the desired pixel
    ! (This is symetric to cubeio_get_pix)
    !---------------------------------------------------------------------
    type(cube_setup_t),   intent(in)    :: cubset
    type(cube_define_t),  intent(in)    :: cubdef
    type(cube_t),         intent(inout) :: cub
    integer(kind=entr_k), intent(in)    :: itask
    integer(kind=pixe_k), intent(in)    :: xpix,ypix
    type(cube_pix_t),     intent(in)    :: pix
    logical,              intent(inout) :: error
    !
    call cubeio_put_pix(cubset,cubdef,cub%head,cub%tuple%current,xpix,ypix,pix,error)
    if (error)  return
    !
    if (cubset%output%extrema .and. .not.pix%iscplx) then
      call cubetools_header_extrema_update_spectrum(pix%r4,  &
        pix%nc,xpix,ypix,cub%proc%ext(itask),error)
      if (error)  return
    endif
  end subroutine cubetuple_put_pix

  subroutine cubetuple_put_subcube(cubset,cubdef,cub,itask,first,last,subcube,error)
    use cubeio_subcube
    !---------------------------------------------------------------------
    ! Get the desired subcube from first to last plane
    !---------------------------------------------------------------------
    type(cube_setup_t),     intent(in)    :: cubset
    type(cube_define_t),    intent(in)    :: cubdef
    type(cube_t),           intent(inout) :: cub
    integer(kind=entr_k),   intent(in)    :: itask
    integer(kind=data_k),   intent(in)    :: first,last
    type(cubeio_subcube_t), intent(inout) :: subcube
    logical,                intent(inout) :: error
    !
    call cubeio_put_subcube(cubset,cubdef,cub%head,cub%tuple%current,  &
      first,last,subcube,error)
    if (error)  return
    !
    if (cubset%output%extrema .and. .not.subcube%iscplx) then
      call cubetools_header_extrema_update_subcube(subcube%f3,subcube%r4,  &
        subcube%n1,subcube%n2,subcube%n3,cub%proc%ext(itask),error)
      if (error)  return
    endif
  end subroutine cubetuple_put_subcube

end module cubetuple_entry
