subroutine uv_shift_comm(line,comm,error)
  use gkernel_interfaces, only : sic_present
  use imager_interfaces, only : map_message
  use clean_types
  use clean_arrays
  use gbl_message
  !-------------------------------------------------------------------
  !  IMAGER 
  !   Support routine for command
  !       UV_SHIFT [Xpos Ypos UNIT] [ANGLE [Angle]]  [/FILE FileIn]
  !   Dispatch according to option presenced
  !-------------------------------------------------------------------
  character(len=*), intent(in) :: line  ! Command line
  character(len=*), intent(in) :: comm  ! Command name 
  logical error                         ! Logical error flag
  !
  integer, parameter :: o_file=1
  !
  if (sic_present(o_file,0)) then
    call uv_shift_file(line,comm,error)
  else
    if (huv%loca%size.eq.0) then
      call map_message(seve%e,comm,'No UV data loaded')
      error = .true.
      return
    endif
    call uv_shift_mosaic(line,comm,error)
  endif
end subroutine uv_shift_comm
!
subroutine uv_shift_file(line,comm,error)
  use clean_def
  use clean_default
  use phys_const
  use gkernel_types
  use gkernel_interfaces
  use gbl_message
  use imager_interfaces, except_this => uv_shift_file
  !-------------------------------------------------------------------
  ! @ private
  !
  !  IMAGER 
  !   Support routine for command
  !       UV_SHIFT [Xpos Ypos UNIT] [ANGLE [Angle]]  [/FILE FileIn]
  !
  !   Phase shift a Mosaic or Single Field UV Table to a new
  !   common phase center and orientation
  !     Offx OffY are offsets in Angle UNIT or ABSOLUTE values
  !               (default 0,0)
  !     Angle     is the final position angle from North in Degree
  !               (default: no change)
  !
  !-------------------------------------------------------------------
  character(len=*), intent(in) :: line  ! Command line
  character(len=*), intent(in) :: comm  ! Command name 
  logical error                         ! Logical error flag
  !
  character(len=*), parameter :: rname='UV_SHIFT'
  integer, parameter :: o_file=1
  !
  type(gildas) :: hiouv
  type(uvmap_par) :: map
  character(len=filename_length) :: file
  real, allocatable :: offxy(:,:)       ! Work arrays for fields offsets
  real, allocatable :: doff(:,:)        ! Fields offsets
  integer :: nf, n
  !
  character(len=80) :: mess
  character(len=12) :: chain
  type(projection_t) :: proj, old_proj, new_proj
  real(8) :: newoff(3), newabs(3), oldabs(3)
  real(4) :: cs(2), angold
  real(8), allocatable :: rpos(:,:)
  real(8) :: freq
  logical :: precise=.true.
  logical :: shift, doit, lshift, err
  integer :: nc,nu,nv,i,ier,loff,moff,xoff,yoff,lid,ixoff,iyoff
  !
  real(8) :: old(2), new(2), tabs(2), off(2)
  integer :: iv,ib,nblock
  integer :: ncode, np
  integer :: codes(2)
  real :: value
  !
  call sic_ch(line,o_file,1,file,n,.true.,error)
  if (error) return
  !
  call gildas_null(hiouv,type='UVT')
  call sic_parse_file(file,' ','.uvt',hiouv%file)
  call gdf_read_header(hiouv,error)
  if (error) return
  !
  loff = hiouv%gil%column_pointer(code_uvt_loff)
  moff = hiouv%gil%column_pointer(code_uvt_moff)
  xoff = hiouv%gil%column_pointer(code_uvt_xoff)
  yoff = hiouv%gil%column_pointer(code_uvt_yoff)
  lid  = hiouv%gil%column_pointer(code_uvt_id)
  !
  oldabs = [hiouv%gil%a0,hiouv%gil%d0,hiouv%gil%pang]   !!! Remember map_center
  newabs = oldabs
  newoff = 0.d0
  !
  if (lid.ne.0 .and. (loff.eq.0.or.moff.eq.0)) then
    !
    ! Source ID column: check status...
    ncode = 1
    codes(1) = code_uvt_id
    allocate(offxy(1,hiouv%gil%nvisi),stat=ier)    
    call gdf_read_uvonly_codes(hiouv,offxy,codes,ncode,error)
    !
    value = offxy(1,1)
    if (any(offxy(1,:).ne.value)) then 
      nf = maxval(offxy(1,:))
      write(chain,'(I12)') nf
      call map_message(seve%e,'READ','Mosaic of '//adjustl(trim(chain))//' fields with only Source ID column')
      call map_message(seve%i,'READ','Use command UV_FIELDS to specify field coordinates')
      error = .true.
      return
    else
      map%nfields = 0
      call map_message(seve%w,'READ','Degenerate mosaic of 1 field with Source ID column')
    endif    
    shift = .false.
  else if (xoff.eq.0 .and. yoff.eq.0 .and. loff.eq.0 .and. moff.eq.0) then
    call map_message(seve%i,rname,'UV data is a single field') 
    shift = .false.
    map%nfields = 0
  else if (xoff.ne.0 .or. yoff.ne.0) then
    call map_message(seve%i,rname,'Mosaic UV data is already in Pointing offsets')
    shift = .false.
    map%nfields = 0  ! Will be updated later
  else
    call map_message(seve%w,rname,'Mosaic UV data is in Phase offsets')
    !
    ! One should derive the number of fields here: Read the Phase offsets
    !
    ncode = 2
    codes(1:2) = [code_uvt_loff,code_uvt_moff]
    allocate(offxy(2,hiouv%gil%nvisi),stat=ier)  
    if (ier.ne.0) then
      call map_message(seve%e,rname,'Memory allocation error')
      error = .true.
      return
    endif
    !
    call gdf_read_uvonly_codes(hiouv,offxy,codes,ncode,error)
    if (error) return
    !
    nv = hiouv%gil%nvisi
    np = 2
    ixoff = 1
    iyoff = 2
    call mosaic_getfields (offxy,np,nv,ixoff,iyoff,nf,doff)
    !
    map%nfields = -nf   ! Negative: it is phase. It seems there was an error, to be checked 
    write(mess,'(A,I0,A)') 'Mosaic UV data has ',abs(map%nfields),' fields'
    call map_message(seve%i,rname,mess)
    !
    ! Compute the mean offset as phase center position
    newoff(1) = minval(doff(1,:)) + maxval(doff(1,:))
    newoff(2) = minval(doff(2,:)) + maxval(doff(2,:))
    newoff = newoff*0.5d0
    !
    call gwcs_projec(hiouv%gil%a0,hiouv%gil%d0,hiouv%gil%pang,hiouv%gil%ptyp,proj,error)
    if (error)  return
    call rel_to_abs(proj,newoff(1),newoff(2),newabs(1),newabs(2),1)
    !
    shift = .true.
    call print_change_header('PHASE_TO_POINT',hiouv,newabs,shift)
    !
    ! Set the new center so that the Offsets are relative to this one now
    hiouv%gil%a0 = newabs(1)
    hiouv%gil%d0 = newabs(2)
  endif   
  !
  ! Check for valid syntax
  if (.not.sic_present(0,2)) then
    if (sic_present(0,1).or.(map%nfields.eq.0)) then
      call map_message(seve%e,rname,'Missing or insufficient argument(s) to command')
      error = .true.
      return
    else
      call map_message(seve%w,rname,'No argument, converting Mosaic to default phase center')
    endif
  endif
  !
  ! Check if command line specifies another center and/or orientation
  call map_center(line,rname,hiouv,lshift,newabs,error)
  if (error) return
  !
  ! Restore the original Projection 
  hiouv%gil%a0 = oldabs(1)
  hiouv%gil%d0 = oldabs(2)
  hiouv%gil%pang = oldabs(3)
  !
  ! Shifting is the Combination of Phase-->Pointing conversion
  ! and User requested shift through MAP_CENTER or command line arguments
  shift = shift .or. lshift 
  doit = .false.
  !
  if (.not.shift) then
    call map_message(seve%w,rname,'No shift required')
  else
    if ((newabs(3).ne.0.0).and.(map%nfields.ne.0)) then
      call map_message(seve%w,rname,'Rotated UV Mosaic cannot be saved -- No convention adopted by IRAM')
    endif  
    !
    ! Verify the case of Pointing Offsets now
    if (xoff.ne.0 .or. yoff.ne.0) then      
      !
      ! One should derive the number of fields here: Read the Pointing offsets
      ncode = 2
      codes(1:2) = [code_uvt_xoff,code_uvt_yoff]
      allocate(offxy(2,hiouv%gil%nvisi),stat=ier)  
      if (ier.ne.0) then
        call map_message(seve%e,rname,'Memory allocation error')
        error = .true.
        return
      endif
      !
      call gdf_read_uvonly_codes(hiouv,offxy,codes,ncode,error)
      if (error) return
      !
      nv = hiouv%gil%nvisi
      np = 2
      ixoff = 1
      iyoff = 2
      call mosaic_getfields (offxy,np,nv,ixoff,iyoff,nf,doff)
      !
      map%nfields = nf    ! Positive: must be POINTING
      write(mess,'(A,I0,A)') 'Mosaic UV data has ',abs(map%nfields),' fields'
      call map_message(seve%i,rname,mess)
    endif
    !
    doit = .true.   ! Make absolutely sure we do the shift ...
    call uv_shift_header (newabs,hiouv%gil%a0,hiouv%gil%d0,hiouv%gil%pang,newoff,doit)
    !
    if (.not.doit) then
      call map_message(seve%w,rname,'Shift is below possible precision')
      ! So, no change of Phase Center and Orientation, but the conversion
      ! from Phase to Pointing centers remains to be done.
      !
    else
      !
      ! Compute observing frequency, and new phase center in wavelengths
      !
      if (precise) then
        nc = hiouv%gil%nchan
        allocate(rpos(2,nc),stat=ier)
        do i=1,hiouv%gil%nchan
          freq = gdf_uv_frequency(hiouv,dble(i))
          rpos(1:2,i) = - freq * f_to_k * newoff(1:2)
        enddo
      else
        nc = 1
        allocate(rpos(2,1),stat=ier)
        freq = gdf_uv_frequency(hiouv)
        rpos(1:2,1) = - freq * f_to_k * newoff(1:2)
      endif
      !
      ! Define the rotation
      cs  = [1.0,0.0]
      angold = hiouv%gil%pang
      hiouv%gil%pang = newabs(3)
      cs(1)  =  cos(hiouv%gil%pang-angold)
      cs(2)  = -sin(hiouv%gil%pang-angold) !! This sign MAY BE WRONG
    endif
    !
    if (map%nfields.ne.0 .or. doit) then
      !
      ! Do things only if needed
      !
      ! BLOCK Operations -----------------------------------------------
      !
      ! Set the Blocking Factor
      nblock = space_nitems('SPACE_IMAGER',hiouv,1)
      ! Recenter all channels, Loop over line table
      ! We work in place - We do not play with UV buffers
      !
      ! Allocate respective space for each file
      allocate (hiouv%r2d(hiouv%gil%dim(1),nblock),stat=ier)
      if (failed_allocate(rname,'UV data allocation error',ier,error)) then
        call gdf_close_image(hiouv,err)
        return    
      endif
      !
      if (map%nfields.ne.0) then
        ! Prepare the Offset changes
        !
        ! The code below assumes everything is relative to the Phase Center.
        !
        if (map%nfields.lt.0) then
          ixoff = hiouv%gil%column_pointer(code_uvt_loff) 
          iyoff = hiouv%gil%column_pointer(code_uvt_moff)
        else if (map%nfields.gt.0) then
          ixoff = hiouv%gil%column_pointer(code_uvt_xoff) 
          iyoff = hiouv%gil%column_pointer(code_uvt_yoff)
        endif
        !
        hiouv%blc(2) = 1
        hiouv%trc(2) = 1
        call gdf_read_data(hiouv,hiouv%r2d,error)
        old(1) = hiouv%r2d(ixoff,1)
        old(2) = hiouv%r2d(iyoff,1)
        !
        call gwcs_projec(oldabs(1),oldabs(2),oldabs(3),hiouv%gil%ptyp,old_proj,error)  ! Previous projection system
        call gwcs_projec(newabs(1),newabs(2),newabs(3),hiouv%gil%ptyp,new_proj,error)  ! New projection system
        call rel_to_abs(old_proj,old(1),old(2),tabs(1),tabs(2),1)
        call abs_to_rel(new_proj,tabs(1),tabs(2),new(1),new(2),1)
      endif
      !
      ! Loop over line table
      hiouv%blc = 0
      hiouv%trc = 0
      !
      do ib = 1,hiouv%gil%dim(2),nblock
        write(mess,*) ib,' / ',hiouv%gil%dim(2),nblock
        call map_message(seve%i,rname,mess)
        hiouv%blc(2) = ib
        hiouv%trc(2) = min(hiouv%gil%nvisi,ib-1+nblock)
        call gdf_read_data(hiouv,hiouv%r2d,error)
        if (error) exit
        !
        nu = hiouv%gil%dim(1)
        nv = hiouv%trc(2)-hiouv%blc(2)+1
        !
        ! This rotates the U,V coordinates and Shift the Phases
        if (doit) call shift_uvdata (hiouv,nu,nv,hiouv%r2d,cs,nc,rpos)
        !
        ! This modifies the offsets
        if (map%nfields.ne.0) then
          do iv=1,nv
            off(1) = hiouv%r2d(xoff,iv)
            off(2) = hiouv%r2d(yoff,iv)
            if (any(off.ne.old)) then
              old(1) = hiouv%r2d(xoff,iv)
              old(2) = hiouv%r2d(yoff,iv)
              call rel_to_abs(old_proj,old(1),old(2),tabs(1),tabs(2),1)
              call abs_to_rel(new_proj,tabs(1),tabs(2),new(1),new(2),1)
            endif
            hiouv%r2d(xoff,iv) = new(1)
            hiouv%r2d(yoff,iv) = new(2)
          enddo
        endif
        !
        call gdf_write_data (hiouv,hiouv%r2d,error)
        if (error) exit
      enddo
      !
      !! END OF BLOCK OPERATIONS
      !
      ! Set the new Phase center and Orientation
      hiouv%gil%a0 = newabs(1)
      hiouv%gil%d0 = newabs(2)  
      hiouv%gil%pang = newabs(3)
    endif
  endif
  !
  ! Work is Done if Single Field (0) or already Pointing columns (>0)
  ! but header must be updated
  !
  ! Convert the LOFF - MOFF columns into Pointing columns if needed
  if (map%nfields.lt.0) then
    ! "Phase" columns
    hiouv%gil%column_pointer(code_uvt_xoff) = loff
    hiouv%gil%column_pointer(code_uvt_yoff) = moff
    hiouv%gil%column_size(code_uvt_xoff) = 1
    hiouv%gil%column_size(code_uvt_yoff) = 1
    !
    hiouv%gil%column_pointer(code_uvt_loff) = 0
    hiouv%gil%column_pointer(code_uvt_moff) = 0
    hiouv%gil%column_size(code_uvt_loff) = 0
    hiouv%gil%column_size(code_uvt_moff) = 0
    !
    map%nfields = abs(map%nfields)
  endif
  !
  if (doit.and.map%nfields.ne.0) then
    !
    ! For convenience, to avoid any ambiguity, we set the
    ! Pointing center equal to the Phase center in Mosaics...
    !
    hiouv%gil%ra = hiouv%gil%a0
    hiouv%gil%dec = hiouv%gil%d0 
    !
  endif
  !
  ! And now, we update the File Header
  !
  call gdf_update_header(hiouv,error)
  if (error) return
  call gdf_close_image(hiouv,error)
  if (error) return
end subroutine uv_shift_file

!
