subroutine uv_check_mosaic
  use clean_def
  use clean_arrays
  use gbl_message
  use imager_interfaces, only : sub_shift_mosaic, map_message
  use gkernel_interfaces
  !
  character(len=32) :: line
  character(len=16) :: comm
  integer :: nline
  logical :: error, do
  !
  if (themap%nfields.ge.0) return ! Single field or POINT Mosaic already
  do = .true.
  call sic_get_logi('READ_UVSHIFT',do,error)
  if (.not.do) return             ! Allows testing code without the patch below
  !
  ! Automatically convert to POINT Mosaic after READ if needed
  line = 'READ'
  nline = 4
  error = .false.
  call sic_analyse(comm,line,nline,error)
  huv%r2d => duv  ! Setup data pointer
  call sub_shift_mosaic(line,comm,huv,themap,error)
  call map_message(seve%w,comm,'Mosaic converted to POINTing format',1)
  !! call uv_shift_mosaic(line,comm,error)
end subroutine uv_check_mosaic
!    
subroutine uv_shift_mosaic(line,comm,error)
  use clean_def
  use clean_default
  use clean_arrays
  use imager_interfaces, only : sub_shift_mosaic
  !-------------------------------------------------------------------
  ! @ private-mandatory
  !*
  !  IMAGER -- Support routine for command  
  !       UV_SHIFT  MAP_CENTER   
  !                 [Xpos Ypos UNIT] [ANGLE Angle]  
  !
  !   Phase shift a Mosaic or Single Dish UV Table to a new
  !   common phase center and orientation.  
  !     Offx OffY are offsets in Angle UNIT 
  !               (default 0,0)  
  !     Angle     is the final position angle from North in Degree
  !               (default: no change)
  !
  !   Also called implicitely (with no command line arguments, i.e.
  !   no change of Phase Center unless the UV Table is with Phase Offsets)
  !   by command UV_MAP for Mosaics
  !!
  !-------------------------------------------------------------------
  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'
  !
  huv%r2d => duv  ! Setup data pointer
  !
  call sub_shift_mosaic(line,comm,huv,themap,error)
  !
end subroutine uv_shift_mosaic
!
subroutine sub_shift_mosaic(line,comm,huvl,pmap,error)
  use clean_def
  use clean_default
  use phys_const
  use gkernel_types
  use gkernel_interfaces
  use gbl_message
  use imager_interfaces, except_this => sub_shift_mosaic
  !-------------------------------------------------------------------
  ! @ private-mandatory
  !*
  !  IMAGER -- Support routine for command  
  !       UV_SHIFT  MAP_CENTER   
  !                 [Xpos Ypos UNIT] [ANGLE Angle]  
  !
  !   Phase shift a Mosaic or Single Dish UV Table to a new
  !   common phase center and orientation.  
  !     Offx OffY are offsets in Angle UNIT 
  !               (default 0,0)  
  !     Angle     is the final position angle from North in Degree
  !               (default: no change)
  !
  !   Also called implicitely (with no command line arguments, i.e.
  !   no change of Phase Center unless the UV Table is with Phase Offsets)
  !   by command UV_MAP for Mosaics
  !!
  !-------------------------------------------------------------------
  character(len=*), intent(in) :: line    !! Command line
  character(len=*), intent(in) :: comm    !! Command name 
  type(gildas), intent(inout)  :: huvl    !! Local UV header & data
  type(uvmap_par), intent(inout) :: pmap  !! UV_MAP parameters
  logical error                           !! Logical error flag
  !
  character(len=*), parameter :: rname='UV_SHIFT'
  ! Local ---
  real, pointer :: duv(:,:)
  !
  character(len=80) :: mess
  character(len=16) :: ctype
  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
  integer :: nc,nu,nv,i,ier,loff,moff,xoff,yoff,idoff
  !
  real(8) :: old(2), new(2), tabs(2), off(2)
  integer :: iv,ip
  !
  ! Code ----
  !
  call imager_tree('SUB_SHIFT_MOSAIC',.false.)
  !
  loff = huvl%gil%column_pointer(code_uvt_loff)
  moff = huvl%gil%column_pointer(code_uvt_moff)
  xoff = huvl%gil%column_pointer(code_uvt_xoff)
  yoff = huvl%gil%column_pointer(code_uvt_yoff)
  idoff = huvl%gil%column_pointer(code_uvt_id)
  call uvdebug_pointers(comm,'Huv ',huvl)
  !
  oldabs = [huvl%gil%a0,huvl%gil%d0,huvl%gil%pang]   !!! Remember map_center
  newabs = oldabs
  newoff = 0.d0
  !
  shift = .false.
  if (pmap%nfields.eq.0) then
    call map_message(seve%i,rname,'UV data is a single field') 
  else
    if (idoff.ne.0) then
      ctype = 'ID column'
    else if (pmap%nfields.gt.0) then
      ctype = 'Pointing Offsets'
    else if (pmap%nfields.lt.0) then
      ctype = 'Phase Offsets    '
    endif
    write(mess,'(A,I0,A)') 'Mosaic UV data has ',abs(pmap%nfields),' fields in '//ctype
    call map_message(seve%i,rname,mess)
    if (idoff.ne.0) then
      if (pmap%nfields.gt.0) then
        call map_message(seve%i,rname,'Pointing ID Mosaics do not need shifting',3)
        return
      endif
    endif
    !
    if (pmap%nfields.lt.0) then
      !
      ! Compute the mean offset as phase center position
      if (allocated(huvl%mos%fields)) then
        newoff(1) = minval(huvl%mos%fields(:)%opoint(1)) + maxval(huvl%mos%fields(:)%opoint(1))
        newoff(2) = minval(huvl%mos%fields(:)%opoint(2)) + maxval(huvl%mos%fields(:)%opoint(2))
      else
        newoff(1) = minval(pmap%offxy(1,:)) + maxval(pmap%offxy(1,:))
        newoff(2) = minval(pmap%offxy(2,:)) + maxval(pmap%offxy(2,:))
      endif
      newoff = newoff*0.5d0
      !
      call gwcs_projec(huvl%gil%a0,huvl%gil%d0,huvl%gil%pang,huvl%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',huvl,newabs,shift)
      !
      ! Set the new center so that the Offsets are relative to this one now
      huvl%gil%a0 = newabs(1)
      huvl%gil%d0 = newabs(2)
    endif
  endif 
  !                 
  ! Check for valid syntax
  if (comm.ne.'UV_MOSAIC') then
    if (.not.sic_present(0,2)) then
      if (sic_present(0,1).or.(pmap%nfields.eq.0)) then
        call map_message(seve%e,rname,'Missing or insufficient argument(s) to command '//comm)
        error = .true.
        return
      else
        call map_message(seve%w,rname,'Converting Mosaic to default phase center')
      endif
    endif
  endif  
  !
  ! Check if command line specifies another center and/or orientation
  if (line.ne.' ') then
    call map_center(line,rname,huvl,lshift,newabs,error)
    if (error) return
  else
    lshift = .false.
  endif
  !
  ! Restore the original Projection 
  huvl%gil%a0 = oldabs(1)
  huvl%gil%d0 = oldabs(2)
  huvl%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.
  !
  duv => huvl%r2d
  !
  if (.not.shift) then
    call map_message(seve%w,rname,'No shift required')
  else
    if ((newabs(3).ne.0.0).and.(pmap%nfields.ne.0)) then
      call map_message(seve%w,rname,'Rotated UV Mosaic cannot be saved -- No convention adopted by IRAM',3)
    endif      
    !
    doit = .true.   ! Make absolutely sure we do the shift ...
    call uv_shift_header (newabs,huvl%gil%a0,huvl%gil%d0,huvl%gil%pang,newoff,doit)
    !
    ! But if a PHASE to POINTING convention is required, we MUST correct the phases
    if (pmap%nfields.lt.0) doit = .true.
    !
    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 = huvl%gil%nchan
        allocate(rpos(2,nc),stat=ier)
        do i=1,huvl%gil%nchan
          freq = gdf_uv_frequency(huvl,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(huvl)
        rpos(1:2,1) = - freq * f_to_k * newoff(1:2)
      endif
      !
      ! Define the rotation
      cs  = [1.0,0.0]
      angold = huvl%gil%pang
      huvl%gil%pang = newabs(3)
      cs(1)  =  cos(huvl%gil%pang-angold)
      cs(2)  = -sin(huvl%gil%pang-angold) !! This sign MAY BE WRONG
      !
      ! Recenter all channels, Loop over line table
      ! We work in place - We do not play with UV buffers
      !
      nu = huvl%gil%dim(1)
      nv = huvl%gil%nvisi
      !
      ! This rotates the U,V coordinates and Shift the Phases
      call shift_uvdata (huvl,nu,nv,duv,cs,nc,rpos)
      !
      ! Set the new Phase center and Orientation
      huvl%gil%a0 = newabs(1)
      huvl%gil%d0 = newabs(2)  
      huvl%gil%pang = newabs(3)
    endif
  endif
  !
  ! Done if Single Field (0) or already Pointing columns (>0)
  if (pmap%nfields.eq.0) return ! Single Field
  !
  ! Convert the LOFF - MOFF columns into Pointing columns if needed
  if (pmap%nfields.lt.0) then
    ! "Phase" columns
    huvl%gil%column_pointer(code_uvt_xoff) = loff
    huvl%gil%column_pointer(code_uvt_yoff) = moff
    huvl%gil%column_size(code_uvt_xoff) = 1
    huvl%gil%column_size(code_uvt_yoff) = 1
    !
    huvl%gil%column_pointer(code_uvt_loff) = 0
    huvl%gil%column_pointer(code_uvt_moff) = 0
    huvl%gil%column_size(code_uvt_loff) = 0
    huvl%gil%column_size(code_uvt_moff) = 0
    !
    pmap%nfields = abs(pmap%nfields)
    !
    ! In case there is a Pointing Table, update it
    if (huvl%mos%nfields.gt.1) then
      call change_fields(rname,pmap%nfields,huvl%mos%fields,newabs,error)
      huvl%mos%fields(:)%aphase(1) = huvl%gil%a0
      huvl%mos%fields(:)%aphase(2) = huvl%gil%d0
    endif
  endif
  !
  ! And now convert the Offset values to new Coordinate system
  ! 
  ! Before: it was Relative to "OLDABS"
  ! Now it is Relative to "NEWABS"
  !
  if (doit) then
    ! A common, modified, Phase center and "Pointing Offsets"
    !
    ! The whole question is whether the "Pointing Offsets" are
    ! relative to the "Pointing Center" (with no rotation Angle)
    ! or to the "Phase Center" (with a rotation Angle)
    !
    ! The code below assumes everything is relative to the Phase Center.
    !
    idoff = huvl%gil%column_pointer(code_uvt_id)
    call gwcs_projec(oldabs(1),oldabs(2),oldabs(3),huvl%gil%ptyp,old_proj,error)  ! Previous projection system
    call gwcs_projec(newabs(1),newabs(2),newabs(3),huvl%gil%ptyp,new_proj,error)  ! New projection system
    if (idoff.eq.0) then
      xoff = huvl%gil%column_pointer(code_uvt_xoff) 
      yoff = huvl%gil%column_pointer(code_uvt_yoff)
      !
      old(1) = duv(xoff,1)
      old(2) = duv(yoff,1)
      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)
      !
      do iv=1,nv
        off(1) = duv(xoff,iv)
        off(2) = duv(yoff,iv)
        if (any(off.ne.old)) then
          old(1) = duv(xoff,iv)
          old(2) = duv(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
        duv(xoff,iv) = new(1)
        duv(yoff,iv) = new(2)
      enddo
      !
      ! And we also correct the Pointing / Phase Offset values
      do ip=1,abs(pmap%nfields)
        off = pmap%offxy(:,ip)
        call rel_to_abs(old_proj,off(1),off(2),tabs(1),tabs(2),1)
        call abs_to_rel(new_proj,tabs(1),tabs(2),off(1),off(2),1)
        pmap%offxy(:,ip) = off
      enddo
      !
    else if (huvl%mos%nfields.gt.1) then
      !
      ! Just update the Offsets 
      do ip=1,abs(pmap%nfields)
        call abs_to_rel(new_proj,huvl%mos%fields(ip)%apoint(1),huvl%mos%fields(ip)%apoint(2),off(1),off(2),1)
        huvl%mos%fields(ip)%opoint = off
        call abs_to_rel(new_proj,huvl%mos%fields(ip)%aphase(1),huvl%mos%fields(ip)%aphase(2),off(1),off(2),1)
        huvl%mos%fields(ip)%ophase = off
      enddo
      !
    else
      call map_message(seve%e,rname,'ID column but not Mosaic header',1)
      error = .true.
    endif
    !
    ! And for convenience, to avoid any ambiguity, we set the
    ! (irrelevant) Pointing center equal to the Phase center
    !
    huvl%gil%ra = huvl%gil%a0
    huvl%gil%dec = huvl%gil%d0 
  endif
  !
  call imager_tree('SUB_SHIFT_MOSAIC',.true.)
end subroutine sub_shift_mosaic
!
