!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine wifisyn_uvgrid_command(line,error)
  use gbl_message
  use gkernel_interfaces
  use wifisyn_interfaces, except_this=>wifisyn_uvgrid_command
  !----------------------------------------------------------------------
  ! @ private
  ! Support routine for command
  !    UVGRID
  !       1. /SHIFT
  !----------------------------------------------------------------------
  character(len=*), intent(inout) :: line
  logical,          intent(inout) :: error
  !
  logical :: doshift
  integer, parameter :: ishift = 1
  character(len=*), parameter :: rname='UVGRID/COMMAND'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  doshift = sic_present(ishift,0)
  call wifisyn_uvgrid_inter(doshift,error)
  if (error) return
  !
end subroutine wifisyn_uvgrid_command
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine wifisyn_uvgrid_inter(doshift,error)
  use gbl_message
  use wifisyn_interfaces, except_this=>wifisyn_uvgrid_inter
  use wifisyn_uv_buffer
  use wifisyn_cube_buffer
  use wifisyn_sic_buffer
  !----------------------------------------------------------------------
  ! @ private
  !----------------------------------------------------------------------
  logical, intent(in)    :: doshift
  logical, intent(inout) :: error
  !
  type(uv_t) :: uvtmp
  type(window_t) :: win
  character(len=*), parameter :: rname='UVGRID/INTER'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  call wifisyn_setup_main(usermap,uvr,progmap,uvtmp,error)
  if (error) return
  win = progmap%win%cur(1)
  call wifisyn_uvgrid_main(doshift,win,uvr,uvtmp,progmap,wifi,error)
  if (error) return
  call wifisyn_free_uv(uvtmp,error)
  if (error) return
  !
end subroutine wifisyn_uvgrid_inter
!
subroutine wifisyn_uvgrid_main(doshift,win,uvin,uvout,map,wifi,error)
  use gbl_message
  use wifisyn_interfaces, except_this=>wifisyn_uvgrid_main
  use wifisyn_gridding_types
  use wifisyn_uv_types
  use wifisyn_cube_types
  !----------------------------------------------------------------------
  ! @ private
  !----------------------------------------------------------------------
  logical,        intent(in)    :: doshift
  type(window_t), intent(in)    :: win
  type(uv_t),     intent(in)    :: uvin
  type(uv_t),     intent(inout) :: uvout
  type(map_t),    intent(inout) :: map
  type(wifi_t),   intent(inout) :: wifi
  logical,        intent(inout) :: error
  !
  integer :: ndata,nchan
  character(len=*), parameter :: rname='UVGRID/MAIN'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  ndata = map%n%data
  nchan = map%n%chan
  ! Get header ready for convolution
  call wifisyn_uvgrid_sort_and_weight(uvin,uvout,map,error)
  if (error) return
  ! Get data ready for convolution
  call wifisyn_reallocate_uv_data(uvout,ndata,nchan,code_uvt,error)
  if (error) return
  call wifisyn_uvgrid_shift_sort_transpose_data(win,map%shift,map%sort,uvin,uvout,error)
  if (error) return
  call wifisyn_reallocate_wifi(map,wifi,error)
  if (error) return
  if (doshift) then
    call wifisyn_uvgrid_shift(win,map,uvout,wifi,error)
     if (error) return
  else
     call wifisyn_uvgrid_convolve(win,map,uvout,wifi,error)
     if (error) return
  endif
  !
end subroutine wifisyn_uvgrid_main
!
subroutine wifisyn_reallocate_wifi(map,wifi,error)
  use gbl_message
  use wifisyn_interfaces, except_this=>wifisyn_reallocate_wifi
  use wifisyn_gridding_types
  use wifisyn_cube_types
  !----------------------------------------------------------------------
  ! @ private
  !----------------------------------------------------------------------
  type(map_t),  intent(in)    :: map
  type(wifi_t), intent(inout) :: wifi
  logical,      intent(inout) :: error
  !
  integer :: nchan,nx,ny,nu,nv
  character(len=*), parameter :: rname='REALLOCATE/WIFI'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  nchan = map%n%chan
  nx = map%axes(1)%x%sky%n
  ny = map%axes(2)%x%sky%n
  nu = map%axes(1)%u%uvp%n
  nv = map%axes(2)%u%uvp%n
  !
  wifi%xykind = .true.
  wifi%uvkind = .true.
  call wifisyn_wifi_header(map,wifi,error)
  if (error) return
  call wifisyn_cube_free_r3d(wifi%amp,error)
  if (error) return
  call wifisyn_reallocate_complex_cxyuv("wifi%cub",nchan,nx,ny,nu,nv,wifi%cub,error)
  if (error) return
  call wifisyn_wifi_weight_header(map,wifi,error)
  if (error) return
  call wifisyn_cube_reallocate_r4d("wifi%wei",wifi%wei,error)
  if (error) return
  !
end subroutine wifisyn_reallocate_wifi
!
subroutine wifisyn_wifi_weight_header(map,wifi,error)
  use gbl_message
  use wifisyn_interfaces, except_this=>wifisyn_wifi_weight_header
  use wifisyn_gridding_types
  use wifisyn_cube_types
  !----------------------------------------------------------------------
  ! @ private
  ! Should be merged with wifi_header *** JP
  !----------------------------------------------------------------------
  type(map_t),  intent(in)    :: map
  type(wifi_t), intent(inout) :: wifi
  logical,      intent(inout) :: error
  !
  character(len=*), parameter :: rname='WIFI/WEIGHT/HEADER'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  call wifisyn_common_header(map,wifi%wei,error)
  if (error) return
  wifi%wei%gil%xaxi = 0
  wifi%wei%gil%yaxi = 0
  if (wifi%xykind) then
     ! 1st axis
     wifi%wei%char%code(1) = 'RA'
     wifi%wei%gil%dim(1) = map%axes(1)%x%sky%n
     wifi%wei%gil%ref(1) = map%axes(1)%x%sky%ref
     wifi%wei%gil%val(1) = map%axes(1)%x%sky%val
     wifi%wei%gil%inc(1) = map%axes(1)%x%sky%inc
     ! 2nd axis
     wifi%wei%char%code(2) = 'DEC'
     wifi%wei%gil%dim(2) = map%axes(2)%x%sky%n
     wifi%wei%gil%ref(2) = map%axes(2)%x%sky%ref
     wifi%wei%gil%val(2) = map%axes(2)%x%sky%val
     wifi%wei%gil%inc(2) = map%axes(2)%x%sky%inc
  else
     ! 1st axis
     wifi%wei%char%code(1) = 'Us'
     wifi%wei%gil%dim(1) = map%axes(1)%x%uvp%n
     wifi%wei%gil%ref(1) = map%axes(1)%x%uvp%ref
     wifi%wei%gil%val(1) = map%axes(1)%x%uvp%val
     wifi%wei%gil%inc(1) = map%axes(1)%x%uvp%inc
     ! 2nd axis
     wifi%wei%char%code(2) = 'Vs'
     wifi%wei%gil%dim(2) = map%axes(2)%x%uvp%n
     wifi%wei%gil%ref(2) = map%axes(2)%x%uvp%ref
     wifi%wei%gil%val(2) = map%axes(2)%x%uvp%val
     wifi%wei%gil%inc(2) = map%axes(2)%x%uvp%inc
  endif
  if (wifi%uvkind) then
     ! 3rd axis
     wifi%wei%char%code(3) = 'Up'
     wifi%wei%gil%dim(3) = map%axes(1)%u%uvp%n
     wifi%wei%gil%ref(3) = map%axes(1)%u%uvp%ref
     wifi%wei%gil%val(3) = map%axes(1)%u%uvp%val
     wifi%wei%gil%inc(3) = map%axes(1)%u%uvp%inc
     ! 4th axis
     wifi%wei%char%code(4) = 'Vp'
     wifi%wei%gil%dim(4) = map%axes(2)%u%uvp%n
     wifi%wei%gil%ref(4) = map%axes(2)%u%uvp%ref
     wifi%wei%gil%val(4) = map%axes(2)%u%uvp%val
     wifi%wei%gil%inc(4) = map%axes(2)%u%uvp%inc
  else
     ! 3rd axis
     wifi%wei%char%code(3) = 'RA'
     wifi%wei%gil%dim(3) = map%axes(1)%u%sky%n
     wifi%wei%gil%ref(3) = map%axes(1)%u%sky%ref
     wifi%wei%gil%val(3) = map%axes(1)%u%sky%val
     wifi%wei%gil%inc(3) = map%axes(1)%u%sky%inc
     ! 4th axis
     wifi%wei%char%code(4) = 'DEC'
     wifi%wei%gil%dim(4) = map%axes(2)%u%sky%n
     wifi%wei%gil%ref(4) = map%axes(2)%u%sky%ref
     wifi%wei%gil%val(4) = map%axes(2)%u%sky%val
     wifi%wei%gil%inc(4) = map%axes(2)%u%sky%inc
  endif
  !
end subroutine wifisyn_wifi_weight_header
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine wifisyn_uvgrid_sort_and_weight(uvin,uvout,map,error)
  use gbl_message
  use wifisyn_interfaces, except_this=>wifisyn_uvgrid_sort_and_weight
  use wifisyn_uv_types
  use wifisyn_gridding_types
  !----------------------------------------------------------------------
  ! @ private
  !----------------------------------------------------------------------
  type(uv_t),  intent(in)    :: uvin
  type(uv_t),  intent(inout) :: uvout
  type(map_t), intent(inout) :: map
  logical,     intent(inout) :: error
  !
  integer :: ndata
  character(len=*), parameter :: rname='UVGRID/SORT+WEIGHT'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  ndata = uvin%head%type%ndata
  ! Sorting
  call wifisyn_set_index(ndata,map%sort,error)
  if (error) return
  call wifisyn_sort_head(map%sort,uvout,error)
  if (error) return
  ! Weighting
  call wifisyn_weighting_extract_sort(map%win%cur(1)%wchan,uvin,map%sort,map%weight,error)
  if (error) return
  call wifisyn_weighting_taper(uvout%head,map%taper,map%weight%mod,error)
  if (error) return
  call wifisyn_weighting_noise(map%weight,map%noise,error)
  if (error) return
  !
end subroutine wifisyn_uvgrid_sort_and_weight
!
subroutine wifisyn_uvgrid_shift_sort_transpose_data(win,shift,sort,tabin,tabout,error)
  use gbl_message
  use wifisyn_interfaces, except_this=>wifisyn_uvgrid_shift_sort_transpose_data
  use wifisyn_uv_types
  use wifisyn_gridding_types
  !----------------------------------------------------------------------
  ! @ private
  ! The output visibilities are a rotated, phase shifted, transposed, sorted
  ! copy of the input ones. This is the sorting and the transposition
  ! which makes it different from wifisyn_shift_uv_data. All the operations
  ! are grouped here to avoid copying 3 times the same data... Note that
  ! only the visibility are changed, the header data (U,V,X,Y,...)
  ! stays untouched. Weights are not carried over.
  !----------------------------------------------------------------------
  type(window_t),   intent(in)    :: win
  type(shift_t),    intent(inout) :: shift
  type(sort_t),     intent(inout) :: sort
  type(uv_t),       intent(in)    :: tabin
  type(uv_t),       intent(inout) :: tabout
  logical,          intent(inout) :: error
  !
  integer :: nchan,first,last
  integer :: ndata,idata,is
  real :: phi,cphi,sphi
  character(len=*), parameter :: rname='UVGRID/SHIFT+SORT+TRANS/DATA'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  ndata = tabin%head%type%ndata
  nchan = tabin%head%type%nchan
  first = win%first
  last  = win%last
  !
  ! Sanity check
  if (inconsistent_size(rname,'input  table',ndata,'output table',tabout%head%type%ndata,error)) return
  if (inconsistent_size(rname,'input  table',tabin%head%type%nchan,'output table',tabout%head%type%nchan,error)) return
  if (inconsistent_size(rname,'input  table',ndata,'v sign',shift%vsign%n,error)) return
  if (inconsistent_size(rname,'input  table',ndata,'sort index',sort%idx%n,error)) return
  if (tabin%head%type%order.ne.code_tuv) then
     call wifisyn_message(seve%e,rname,'Input table order must be TUV')
     error = .true.
     return
  endif
  if (tabout%head%type%order.ne.code_uvt) then
     call wifisyn_message(seve%e,rname,'Output table order must be UVT')
     error = .true.
     return
  endif
  if (first.lt.1) then
     call wifisyn_message(seve%e,rname,'First channel lower than 1')
     error = .true.
     return
  endif
  if (last.gt.nchan) then
     call wifisyn_message(seve%e,rname,'Last channel greater than nchan')
     error = .true.
     return
  endif
  !
  if (shift%xy(1).eq.0 .and. shift%xy(2).eq.0) then
     ! Simple case: No phase shift
     do idata=1,ndata
        is = sort%idx%val(idata)
        if (shift%vsign%val(is)) then
           tabout%data(1:2,first:last,idata) = tabin%data(is,1:2,first:last)
        else
           tabout%data(1,first:last,idata) =  tabin%data(is,1,first:last)
           tabout%data(2,first:last,idata) = -tabin%data(is,2,first:last)
        endif
     enddo
  else
     ! Complex case: Phase center has been shifted
     do idata=1,ndata
        is = sort%idx%val(idata)
        phi = shift%xy(1)*tabout%head%u(is)+shift%xy(2)*tabout%head%v(is)
        cphi = cos(phi)
        sphi = sin(phi)
        if (shift%vsign%val(is)) then
           tabout%data(1,first:last,idata) = tabin%data(is,1,first:last)*cphi - tabin%data(is,2,first:last)*sphi
           tabout%data(2,first:last,idata) = tabin%data(is,1,first:last)*sphi + tabin%data(is,2,first:last)*cphi
        else
           tabout%data(1,first:last,idata) = tabin%data(is,1,first:last)*cphi + tabin%data(is,2,first:last)*sphi
           tabout%data(2,first:last,idata) = tabin%data(is,1,first:last)*sphi - tabin%data(is,2,first:last)*cphi
        endif
     enddo
  endif
  !
  ! Clean up
  call wifisyn_free_inte_1d(sort%idx,error)
  if (error) return
  call wifisyn_free_logi_1d(shift%vsign,error)
  if (error) return
  !
end subroutine wifisyn_uvgrid_shift_sort_transpose_data
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
