!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine wifisyn_allocate_fft_wifi(ispace,wifi,fft,error)
  use gbl_message
  use wifisyn_interfaces, except_this=>wifisyn_allocate_fft_wifi
  use wifisyn_cube_types
  use wifisyn_transform_types
  use wifisyn_gridding_types
  !-------------------------------------------------------------------
  ! @ private
  !-------------------------------------------------------------------
  integer,              intent(in)    :: ispace
  type(wifi_t), target, intent(in)    :: wifi
  type(fft_t),          intent(out)   :: fft
  logical,              intent(inout) :: error
  !
  integer :: nx,ny
  character(len=*), parameter :: rname='ALLOCATE/FFT/WIFI'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  if (.not.associated(wifi%cub%val)) then
     call wifisyn_message(seve%t,rname,'Unallocated wifi%cub')
     error = .true.
     return
  endif
  fft%wifi => wifi%cub
  if (ispace.eq.code_space_uv) then
     nx = wifi%cub%nu
     ny = wifi%cub%nv
     fft%datakind => wifi%uvkind
  else if (ispace.eq.code_space_xy) then
     nx = wifi%cub%nx
     ny = wifi%cub%ny
     fft%datakind => wifi%xykind
  else
     call wifisyn_message(seve%e,rname,'Unknown plane')
     error = .true.
     return
  endif
  call wifisyn_allocate_complex_2d("fft plane",nx,ny,fft%plane,error)
  if (error) return
  call wifisyn_allocate_complex_1d("fft work space",max(nx,ny),fft%work,error)
  if (error) return
  !
end subroutine wifisyn_allocate_fft_wifi
!
subroutine wifisyn_allocate_fft_visi(visi,fft,error)
  use gbl_message
  use wifisyn_interfaces, except_this=>wifisyn_allocate_fft_visi
  use wifisyn_cube_types
  use wifisyn_transform_types
  use wifisyn_gridding_types
  !-------------------------------------------------------------------
  ! @ private
  !-------------------------------------------------------------------
  type(visi_t), target, intent(in)    :: visi
  type(fft_t),          intent(out)   :: fft
  logical,              intent(inout) :: error
  !
  integer :: nx,ny
  character(len=*), parameter :: rname='ALLOCATE/FFT/VISI'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  if (.not.associated(visi%cub%val)) then
     call wifisyn_message(seve%t,rname,'Unallocated visicub')
     error = .true.
     return
  endif
  fft%datakind => visi%uvkind
  fft%visi => visi%cub
  nx = visi%cub%nx
  ny = visi%cub%ny
  call wifisyn_allocate_complex_2d("fft plane",nx,ny,fft%plane,error)
  if (error) return
  call wifisyn_allocate_complex_1d("fft work space",max(nx,ny),fft%work,error)
  if (error) return
  !
end subroutine wifisyn_allocate_fft_visi
!
subroutine wifisyn_free_fft(fft,error)
  use gbl_message
  use wifisyn_interfaces, except_this=>wifisyn_free_fft
  use wifisyn_transform_types
  !-------------------------------------------------------------------
  ! @ private
  !-------------------------------------------------------------------
  type(fft_t), intent(inout) :: fft
  logical,     intent(inout) :: error
  !
  character(len=*), parameter :: rname='FREE/FFT'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  nullify(fft%wifi)
  nullify(fft%visi)
  call wifisyn_free_complex_2d(fft%plane,error)
  if (error) return
  call wifisyn_free_complex_1d(fft%work,error)
  if (error) return
  !
end subroutine wifisyn_free_fft
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine wifisyn_fft_command(line,error)
  use gbl_message
  use gkernel_interfaces
  use wifisyn_interfaces, except_this=>wifisyn_fft_command
  use wifisyn_sic_buffer
  use wifisyn_cube_buffer
  use wifisyn_transform_types
  !----------------------------------------------------------------------
  ! @ private
  ! Support routine for command
  !     FFT WIFI|VISI
  !       1 /DIRECT
  !       2 /INVERSE
  !       3 /UV
  !       4 /XY
  !----------------------------------------------------------------------
  character(len=*), intent(inout) :: line
  logical,          intent(inout) :: error
  !
  type(action_t) :: do
  character(len=*), parameter :: rname='FFT/COMMAND'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  call wifisyn_parse_transform(line,do,error)
  if (error) return
  if (do%cube.eq.code_cube_visi) then
     call wifisyn_fft_visi(do%dire,progmap%win%cur(1),visi,error)
     if (error) return
  else if (do%cube.eq.code_cube_wifi) then
     call wifisyn_fft_wifi(do%dire,do%space,progmap%win%cur(1),wifi,error)
     if (error) return
  else
     call wifisyn_message(seve%e,rname,'Unknown cube kind')
     error = .true.
     return
  endif
  !
end subroutine wifisyn_fft_command
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine wifisyn_fft_wifi(idir,ispace,win,wifi,error)
  use gbl_message
  use wifisyn_interfaces, except_this=>wifisyn_fft_wifi
  use wifisyn_gridding_types
  use wifisyn_cube_types
  use wifisyn_transform_types
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  integer,        intent(in)    :: idir
  integer,        intent(in)    :: ispace
  type(window_t), intent(in)    :: win
  type(wifi_t),   intent(inout) :: wifi
  logical,        intent(inout) :: error
  !
  type(fft_t) :: fft
  character(len=*), parameter :: rname='FFT/WIFI'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  call wifisyn_allocate_fft_wifi(ispace,wifi,fft,error)
  if (error) return
  if (ispace.eq.code_space_uv) then
     call wifisyn_fft_wifi_uv(idir,win,fft,error)
     if (error) return
  else if (ispace.eq.code_space_xy) then
     call wifisyn_fft_wifi_xy(idir,win,fft,error)
     if (error) return
  else
     call wifisyn_message(seve%e,rname,'Unknown plane')
     error = .true.
     return
  endif
  call wifisyn_free_fft(fft,error)
  if (error) return
  !
end subroutine wifisyn_fft_wifi
!
subroutine wifisyn_fft_wifi_xy(idir,win,fft,error)
  use gbl_message
  use gkernel_interfaces, nointerface=>fourt
  use gkernel_types
  use wifisyn_interfaces, except_this=>wifisyn_fft_wifi_xy
  use wifisyn_transform_types
  use wifisyn_gridding_types
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  integer,        intent(in)    :: idir
  type(window_t), intent(in)    :: win
  type(fft_t),    intent(inout) :: fft
  logical,        intent(inout) :: error
  !
  integer :: iu,iv,ic,dim(2)
  type(time_t) :: time
  character(len=*), parameter :: rname='FFT/WIFI/XY'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  if (idir.eq.code_direct) then
     call wifisyn_message(seve%i,rname,'WIFI XY direct FFT')
  else
     call wifisyn_message(seve%i,rname,'WIFI XY inverse FFT')
  endif
  !
  dim = (/ fft%wifi%nx,fft%wifi%ny/)
  call gtime_init(time,fft%wifi%nv*fft%wifi%nu*win%nchan,error)
  do iv=1,fft%wifi%nv
     do iu=1,fft%wifi%nu
        do ic=win%first,win%last
           call gtime_current(time)
           call wifisyn_fft_xyuv2xy(ic,iu,iv,fft)
           call fourt(fft%plane%val,dim,2,idir,code_type_complex,fft%work%val)
           call wifisyn_fft_xy2xyuv(ic,iu,iv,fft)
        enddo ! ic
     enddo ! iu
  enddo !iv
  fft%datakind = .not.fft%datakind
  !
end subroutine wifisyn_fft_wifi_xy
!
subroutine wifisyn_fft_xyuv2xy(ic,iu,iv,fft)
  use gbl_message
  use wifisyn_interfaces, except_this=>wifisyn_fft_xyuv2xy
  use wifisyn_transform_types
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  integer,     intent(in)    :: ic
  integer,     intent(in)    :: iu
  integer,     intent(in)    :: iv
  type(fft_t), intent(inout) :: fft
  !
  integer :: ix,mx
  integer :: iy,my
  character(len=*), parameter :: rname='FFT/XYUV2XY'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  mx = fft%plane%nx/2
  my = fft%plane%ny/2
  do iy=1,my
     ! xy bottom, left quarter
     do ix=1,mx
        fft%plane%val(ix,iy) = fft%wifi%val(ic,ix+mx,iy+my,iu,iv)
     enddo
     ! xy bottom, right quarter
     do ix=1,mx
        fft%plane%val(ix+mx,iy) = fft%wifi%val(ic,ix,iy+my,iu,iv)
     enddo
  enddo
  do iy=1,my
     ! xy top, left quarter
     do ix=1,mx
        fft%plane%val(ix,iy+my) = fft%wifi%val(ic,ix+mx,iy,iu,iv)
     enddo
     ! xy top, right quarter
     do ix=1,mx
        fft%plane%val(ix+mx,iy+my) = fft%wifi%val(ic,ix,iy,iu,iv)
     enddo
  enddo
  !
end subroutine wifisyn_fft_xyuv2xy
!
subroutine wifisyn_fft_xy2xyuv(ic,iu,iv,fft)
  use gbl_message
  use image_def
  use wifisyn_interfaces, except_this=>wifisyn_fft_xy2xyuv
  use wifisyn_transform_types
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  integer,     intent(in)    :: ic
  integer,     intent(in)    :: iu
  integer,     intent(in)    :: iv
  type(fft_t), intent(inout) :: fft
  !
  integer :: ix,mx
  integer :: iy,my
  character(len=*), parameter :: rname='FFT/XY2XYUV'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  mx = fft%plane%nx/2
  my = fft%plane%ny/2
  do iy=1,my
     ! xy bottom, left quarter
     do ix=1,mx
        fft%wifi%val(ic,ix+mx,iy+my,iu,iv) = fft%plane%val(ix,iy)
     enddo
     ! xy bottom, right quarter
     do ix=1,mx
        fft%wifi%val(ic,ix,iy+my,iu,iv) = fft%plane%val(ix+mx,iy)
     enddo
  enddo
  do iy=1,my
     ! xy top, left quarter
     do ix=1,mx
        fft%wifi%val(ic,ix+mx,iy,iu,iv) = fft%plane%val(ix,iy+my)
     enddo
     ! xy top, right quarter
     do ix=1,mx
        fft%wifi%val(ic,ix,iy,iu,iv) = fft%plane%val(ix+mx,iy+my)
     enddo
  enddo
  !
end subroutine wifisyn_fft_xy2xyuv
!
subroutine wifisyn_fft_wifi_uv(idir,win,fft,error)
  use gbl_message
  use gkernel_interfaces, nointerface=>fourt
  use gkernel_types
  use wifisyn_interfaces, except_this=>wifisyn_fft_wifi_uv
  use wifisyn_transform_types
  use wifisyn_gridding_types
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  integer,        intent(in)    :: idir
  type(window_t), intent(in)    :: win
  type(fft_t),    intent(inout) :: fft
  logical,        intent(inout) :: error
  !
  integer :: ix,iy,ic,dim(2)
  type(time_t) :: time
  character(len=*), parameter :: rname='FFT/WIFI/UV'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  if (idir.eq.code_direct) then
     call wifisyn_message(seve%i,rname,'WIFI UV direct FFT')
  else
     call wifisyn_message(seve%i,rname,'WIFI UV inverse FFT')
  endif
  !
  dim = (/ fft%wifi%nu,fft%wifi%nv/)
  call gtime_init(time,fft%wifi%nx*fft%wifi%ny*win%nchan,error)
  do iy=1,fft%wifi%ny
     do ix=1,fft%wifi%nx
        do ic=win%first,win%last
           call gtime_current(time)
           call wifisyn_fft_xyuv2uv(ic,ix,iy,fft)
           call fourt(fft%plane%val,dim,2,idir,code_type_complex,fft%work%val)
           call wifisyn_fft_uv2xyuv(ic,ix,iy,fft)
        enddo ! ic
     enddo ! ix
  enddo !iy
  fft%datakind = .not.fft%datakind
  !
end subroutine wifisyn_fft_wifi_uv
!
subroutine wifisyn_fft_xyuv2uv(ic,ix,iy,fft)
  use gbl_message
  use wifisyn_interfaces, except_this=>wifisyn_fft_xyuv2uv
  use wifisyn_transform_types
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  integer,     intent(in)    :: ic
  integer,     intent(in)    :: ix
  integer,     intent(in)    :: iy
  type(fft_t), intent(inout) :: fft
  !
  integer :: iu,mu
  integer :: iv,mv
  character(len=*), parameter :: rname='FFT/XYUV2UV'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  mu = fft%plane%nx/2
  mv = fft%plane%ny/2
  do iv=1,mv
     ! uv bottom, left quarter
     do iu=1,mu
        fft%plane%val(iu,iv) = fft%wifi%val(ic,ix,iy,iu+mu,iv+mv)
     enddo
     ! uv bottom, right quarter
     do iu=1,mu
        fft%plane%val(iu+mu,iv) = fft%wifi%val(ic,ix,iy,iu,iv+mv)
     enddo
  enddo
  do iv=1,mv
     ! uv top, left quarter
     do iu=1,mu
        fft%plane%val(iu,iv+mv) = fft%wifi%val(ic,ix,iy,iu+mu,iv)
     enddo
     ! uv top, right quarter
     do iu=1,mu
        fft%plane%val(iu+mu,iv+mv) = fft%wifi%val(ic,ix,iy,iu,iv)
     enddo
  enddo
  !
end subroutine wifisyn_fft_xyuv2uv
!
subroutine wifisyn_fft_uv2xyuv(ic,ix,iy,fft)
  use gbl_message
  use image_def
  use wifisyn_interfaces, except_this=>wifisyn_fft_uv2xyuv
  use wifisyn_transform_types
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  integer,     intent(in)    :: ic
  integer,     intent(in)    :: ix
  integer,     intent(in)    :: iy
  type(fft_t), intent(inout) :: fft
  !
  integer :: iu,mu
  integer :: iv,mv
  character(len=*), parameter :: rname='FFT/UV2XYUV'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  mu = fft%plane%nx/2
  mv = fft%plane%ny/2
  do iv=1,mv
     ! uv bottom, left quarter
     do iu=1,mu
        fft%wifi%val(ic,ix,iy,iu+mu,iv+mv) = fft%plane%val(iu,iv)
     enddo
     ! uv bottom, right quarter
     do iu=1,mu
        fft%wifi%val(ic,ix,iy,iu,iv+mv) = fft%plane%val(iu+mu,iv)
     enddo
  enddo
  do iv=1,mv
     ! uv top, left quarter
     do iu=1,mu
        fft%wifi%val(ic,ix,iy,iu+mu,iv) = fft%plane%val(iu,iv+mv)
     enddo
     ! uv top, right quarter
     do iu=1,mu
        fft%wifi%val(ic,ix,iy,iu,iv) = fft%plane%val(iu+mu,iv+mv)
     enddo
  enddo
  !
end subroutine wifisyn_fft_uv2xyuv
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine wifisyn_fft_visi(idir,win,visi,error)
  use gbl_message
  use wifisyn_interfaces, except_this=>wifisyn_fft_visi
  use wifisyn_gridding_types
  use wifisyn_cube_types
  use wifisyn_transform_types
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  integer,        intent(in)    :: idir
  type(window_t), intent(in)    :: win
  type(visi_t),   intent(inout) :: visi
  logical,        intent(inout) :: error
  !
  type(fft_t) :: fft
  character(len=*), parameter :: rname='FFT/VISI'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  call wifisyn_allocate_fft_visi(visi,fft,error)
  if (error) return
  call wifisyn_fft_visi_uv(idir,win,fft,error)
  if (error) return
  call wifisyn_free_fft(fft,error)
  if (error) return
  !
end subroutine wifisyn_fft_visi
!
subroutine wifisyn_fft_visi_uv(idir,win,fft,error)
  use gbl_message
  use gkernel_interfaces, nointerface=>fourt
  use gkernel_types
  use wifisyn_interfaces, except_this=>wifisyn_fft_visi_uv
  use wifisyn_transform_types
  use wifisyn_gridding_types
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  integer,        intent(in)    :: idir
  type(window_t), intent(in)    :: win
  type(fft_t),    intent(inout) :: fft
  logical,        intent(inout) :: error
  !
  integer :: ic,dim(2)
  type(time_t) :: time
  character(len=*), parameter :: rname='FFT/VISI/UV'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  if (idir.eq.code_direct) then
     call wifisyn_message(seve%i,rname,'VISI direct FFT')
  else
     call wifisyn_message(seve%i,rname,'VISI inverse FFT')
  endif
  !
  dim = (/ fft%visi%nx,fft%visi%ny/)
  call gtime_init(time,win%nchan,error)
  do ic=win%first,win%last
     call gtime_current(time)
     call wifisyn_fft_visi2plane(ic,fft)
     call fourt(fft%plane%val,dim,2,idir,code_type_complex,fft%work%val)
     call wifisyn_fft_plane2visi(ic,fft)
  enddo ! ic
  fft%datakind = .not.fft%datakind
  !
end subroutine wifisyn_fft_visi_uv
!
subroutine wifisyn_fft_visi2plane(ic,fft)
  use gbl_message
  use wifisyn_interfaces, except_this=>wifisyn_fft_visi2plane
  use wifisyn_transform_types
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  integer,     intent(in)    :: ic
  type(fft_t), intent(inout) :: fft
  !
  integer :: ix,mx
  integer :: iy,my
  character(len=*), parameter :: rname='FFT/VISI2PLANE'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  mx = fft%plane%nx/2
  my = fft%plane%ny/2
  do iy=1,my
     ! Plane bottom, left quarter
     do ix=1,mx
        fft%plane%val(ix,iy) = fft%visi%val(ix+mx,iy+my,ic)
     enddo
     ! Plane bottom, right quarter
     do ix=1,mx
        fft%plane%val(ix+mx,iy) = fft%visi%val(ix,iy+my,ic)
     enddo
  enddo
  do iy=1,my
     ! Plane top, left quarter
     do ix=1,mx
        fft%plane%val(ix,iy+my) = fft%visi%val(ix+mx,iy,ic)
     enddo
     ! Plane top, right quarter
     do ix=1,mx
        fft%plane%val(ix+mx,iy+my) = fft%visi%val(ix,iy,ic)
     enddo
  enddo
  !
end subroutine wifisyn_fft_visi2plane
!
subroutine wifisyn_fft_plane2visi(ic,fft)
  use gbl_message
  use image_def
  use wifisyn_interfaces, except_this=>wifisyn_fft_plane2visi
  use wifisyn_transform_types
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  integer,     intent(in)    :: ic
  type(fft_t), intent(inout) :: fft
  !
  integer :: ix,mx
  integer :: iy,my
  character(len=*), parameter :: rname='FFT/PLANE2VISI'
  !
  call wifisyn_message(seve%t,rname,'Welcome')
  !
  mx = fft%plane%nx/2
  my = fft%plane%ny/2
  do iy=1,my
     ! Plane bottom, left quarter
     do ix=1,mx
        fft%visi%val(ix+mx,iy+my,ic) = fft%plane%val(ix,iy)
     enddo
     ! Plane bottom, right quarter
     do ix=1,mx
        fft%visi%val(ix,iy+my,ic) = fft%plane%val(ix+mx,iy)
     enddo
  enddo
  do iy=1,my
     ! Plane top, left quarter
     do ix=1,mx
        fft%visi%val(ix+mx,iy,ic) = fft%plane%val(ix,iy+my)
     enddo
     ! Plane top, right quarter
     do ix=1,mx
        fft%visi%val(ix,iy,ic) = fft%plane%val(ix+mx,iy+my)
     enddo
  enddo
  !
end subroutine wifisyn_fft_plane2visi
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
