subroutine uv_trim_comm(line,error)
  use gildas_def
  use image_def
  use gkernel_interfaces
  use imager_interfaces, except_this => uv_trim_comm
  use gbl_message
  !----------------------------------------------------------------------
  ! @ private
  !
  ! IMAGER
  !       Support routine for command
  !     UV_TRIM [Action] [/FILE File [FileOUT] 
  !
  ! Trim the current UV data or specified UV table for Trailing
  ! columns (Action = TRAIL) or flagged for all channels (Action = DATA),
  ! or flagged for any channel (Action = ANY) .
  !----------------------------------------------------------------------
  character(len=*), intent(in) :: line
  logical, intent(inout) :: error
  !
  integer, parameter :: o_file=1
  character(len=*), parameter :: rname='UV_TRIM'
  !
  character(len=filename_length) :: uvdata,uvtrim,original
  character(len=8) :: code
  integer :: wcol, ier, n
  logical :: in_place
  integer, parameter :: mvoc=3
  integer :: ikey
  character(len=8) :: argum, vocab(mvoc), key
  data vocab /'ANY     ','DATA    ', 'TRAIL   '/
  !
  if (.not.sic_present(o_file,0)) then
    call map_message(seve%e,rname,'Trimming current UV data not yet implemented')
    error = .true.
    return
  endif
  !
  argum = 'DATA'
  call sic_ke(line,0,1,argum,n,.false.,error)
  call sic_ambigs (rname,argum,key,ikey,vocab,mvoc,error)
  if (error) return
  !
  code = key
  select case(key)
  case ('DATA')
    wcol = 0
  case ('ANY')
    wcol = -1
    code = 'DATA'
  end select
  !
  ! Find out the Input and Output files
  call sic_ch(line,o_file,1,uvdata,n,.true.,error)
  if (error) return
  !
  in_place = .not.sic_present(o_file,2)
  if (in_place) then
    uvtrim = uvdata
    call sic_parse_file(uvtrim,' ','.uvt',original)
    uvtrim = "tmp_"//uvtrim
  else
    call sic_ch(line,o_file,2,uvtrim,n,.false.,error)
  endif
  if (error) return
  !
  call uv_trim_sub(uvdata, uvtrim, code, wcol, error)
  if (error) return
  !
  ! Move temporary file to its final destination
  if (in_place) then
    n = len_trim(uvtrim)
    if (uvtrim(n-3:n).ne.".uvt") then
      ier = gag_filrename(trim(uvtrim)//".uvt",original)
    else
      ier = gag_filrename(trim(uvtrim),original)
    endif
  endif
end subroutine uv_trim_comm
!
subroutine uv_trim_sub (cuvin, cuvou, code, wcol, error)
  use gkernel_interfaces
  use imager_interfaces, except_this => uv_trim_sub
  use image_def
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private
  !
  ! IMAGER 
  !   Trim a UV table,
  !       - remove the flagged data
  !   or  - trim trailing columns
  !---------------------------------------------------------------------
  character(len=*), intent(in) :: cuvin
  character(len=*), intent(in) :: cuvou
  character(len=*), intent(in) :: code
  integer, intent(in) :: wcol
  logical, intent(out) :: error
  !
  ! Local variables
  character(len=*), parameter :: rname='UV_TRIM'
  character(len=80)  :: mess
  type (gildas) :: uvin
  type (gildas) :: uvou
  integer :: ier, nblock, ib, invisi, ouvisi
  integer(index_length) :: mvis
  !
  ! Simple checks
  select case (code)
  case ('DATA','TRAIL')
    continue
  case default
    error =.true.
    call map_message(seve%e,rname,'Invalid code '//code)
    return
  end select
  !
  error = len_trim(cuvin).eq.0
  if (error) then
    call map_message(seve%e,rname,'No input UV table name')
    return
  endif
  !
  call gildas_null (uvin, type = 'UVT')     ! Define a UVTable gildas header
  call gdf_read_gildas (uvin, cuvin, '.uvt', error, data=.false.)
  if (error) then
    call map_message(seve%e,rname,'Cannot read input UV table')
    return
  endif
  !
  ! Here modify the header of the output UV table according
  ! to the desired goal
  !
  call gildas_null (uvou, type = 'UVT')     ! Define a UVTable gildas header
  call gdf_copy_header(uvin,uvou,error)
  call sic_parse_file(cuvou,' ','.uvt',uvou%file)
  !
  if (code.eq.'TRAIL') then
    uvou%gil%ntrail = 0
    do ib=1,code_uvt_last
      if (uvou%gil%column_pointer(ib).gt.uvin%gil%fcol) then
        uvou%gil%column_pointer(ib) =  0
        uvou%gil%column_size(ib) = 0
      endif
    enddo
    uvou%gil%dim(1) = uvou%gil%lcol
    call gdf_setuv(uvou,error)
  endif
  !
  ! Define blocking factor, on largest data file
  nblock = space_nitems('SPACE_GILDAS',uvin,1)
  ! Allocate respective space for each file if needed
  if (code.eq.'TRAIL') then
    allocate (uvin%r2d(uvin%gil%dim(1),nblock), uvou%r2d(uvou%gil%dim(1),nblock), stat=ier)
  else
    allocate (uvin%r2d(uvin%gil%dim(1),nblock), stat=ier)
  endif
  if (ier.ne.0) then
    write(mess,*) 'Memory allocation error ',uvin%gil%dim(1), nblock
    call map_message(seve%e,rname,mess)
    error = .true.
    return
  endif
  !
  ! create the image with smallest possible size
  uvou%gil%dim(2) = nblock
  uvou%gil%nvisi = 0
  call gdf_create_image(uvou,error)
  if (error) return
  !
  ! Loop over line table 
  uvin%blc = 0
  uvin%trc = 0
  uvou%blc = 0
  uvou%trc = 0
  uvou%blc(2) = 1  ! Get started
  !
  if (code.eq.'DATA') then
    do ib = 1,uvin%gil%nvisi,nblock
      write(mess,'(A,I0,A,I12,I12)') 'Reading ',ib,' / ',uvin%gil%nvisi,nblock
      call map_message(seve%i,rname,mess)
      uvin%blc(2) = ib
      uvin%trc(2) = min(uvin%gil%nvisi,ib-1+nblock)
      invisi = uvin%trc(2)-uvin%blc(2)+1
      call gdf_read_data(uvin,uvin%r2d,error)
      !
      call uv_trim_flag(uvin, invisi, uvou, ouvisi, wcol, error)
      if (error) return
      !
      if (ouvisi.gt.0) then
        uvou%trc(2) = uvou%blc(2)+ouvisi-1
        mvis = uvou%trc(2)
        !
        if (mvis.gt.uvou%gil%dim(2)) then
          write(mess,'(A,I0,A,I0)') 'Extending from ',uvou%gil%dim(2), ' to  ',mvis
          call map_message(seve%i,rname,mess)
          call gdf_close_image(uvou,error)
          call gdf_extend_image (uvou,mvis,error)
        endif
        call gdf_write_data (uvou,uvin%r2d,error)
        if (error) return
        uvou%blc(2) = uvou%trc(2)+1
      endif
    enddo
  else if (code.eq.'TRAIL') then
    do ib = 1,uvin%gil%nvisi,nblock
      write(mess,*) ib,' / ',uvin%gil%dim(2),nblock
      call map_message(seve%d,rname,mess)
      uvin%blc(2) = ib
      uvin%trc(2) = min(uvin%gil%nvisi,ib-1+nblock)
      invisi = uvin%trc(2)-uvin%blc(2)+1
      call gdf_read_data(uvin,uvin%r2d,error)
      !
      ouvisi = invisi
      !
      if (ouvisi.gt.0) then
        uvou%r2d(:,1:invisi) = uvin%r2d(1:uvin%gil%lcol,1:invisi)
        uvou%trc(2) = uvou%blc(2)+ouvisi-1
        mvis = uvou%trc(2)
        !
        if (mvis.gt.uvou%gil%dim(2)) then
          Print *,'Extending from ',uvou%gil%dim(2), ' to  ',mvis
          call gdf_close_image(uvou,error)
          call gdf_extend_image (uvou,mvis,error)
        endif
        call gdf_write_data (uvou,uvou%r2d,error)
        if (error) return
        uvou%blc(2) = uvou%trc(2)+1
      endif
    enddo
  endif
  !
  ! Finalize the image
  uvou%gil%nvisi = uvou%trc(2)
  uvou%gil%dim(2) = uvou%trc(2)
  call gdf_update_header(uvou,error)
  if (error) return
  call gdf_close_image(uvou,error)
  if (error) return
  !
  call gdf_close_image(uvin,error)
end subroutine uv_trim_sub
!
subroutine uv_trim_flag(in,invis,out,outvis,wcol,error)
  use gildas_def
  use image_def
  use gkernel_interfaces
  !---------------------------------------------------------------------
  ! @ private
  !
  ! IMAGER
  !       Trim an input UV table: get rid off all flagged visibilities
  !
  ! WCOL < 0    Trim if any channel is flagged
  ! WCOL = 0    Trim if all channels are flagged
  ! WCOL > 0    Trim if that channel is flagged
  !----------------------------------------------------------------------
  type (gildas), intent(inout) :: in, out
  integer, intent(in) :: invis
  integer, intent(out) :: outvis
  integer, intent(in) :: wcol
  logical, intent(out) :: error
  !
  ! Local variables:
  integer(kind=index_length), allocatable :: ivis(:)
  integer :: ier, np, nclow, ncup, ic
  integer :: iv, im, mv
  logical :: trim_any
  !
  np = in%gil%dim(1)
  if (wcol.lt.0) then
    nclow = 1
    ncup = in%gil%nchan
    trim_any = .true.
  else if (wcol.eq.0) then
    nclow = (in%gil%nchan+2)/3
    ncup = nclow
    trim_any = .false.
  else
    ncup = min(wcol,in%gil%nchan)
    nclow = ncup
    trim_any = .false.
  endif
  allocate(ivis(invis),stat=ier)
  if (ier.ne.0) then
    error = .true.
    return
  endif
  !
  ! First passs to identifiy all valid visibilities
  mv = 0
  if (trim_any) then
    do iv = 1,invis
      ! If a single channel is Bad, flag data
      im = 1
      do ic=nclow,ncup
        if (in%r2d(in%gil%fcol-1+3*ic,iv).le.0) then
          im = 0
          exit
        endif
      enddo
      if (im.ne.0) then
        mv = mv+1
        ivis(mv) = iv
      endif
    enddo
  else
    do iv = 1,invis
      ! If a single channel is Good, use data
      im = 0
      do ic=nclow,ncup
        if (in%r2d(in%gil%fcol-1+3*ic,iv).gt.0) then
          im = 1
          exit
        endif
      enddo
      if (im.ne.0) then
        mv = mv+1
        ivis(mv) = iv
      endif
    enddo
  endif
  !
  ! Second pass to keep the good visibilities only
  ! Memory saved by working in place, as the visibilities are ordered.
  do iv = 1,mv
    if (ivis(iv).gt.iv) in%r2d(:,iv) = in%r2d(:,ivis(iv))
  enddo
  outvis = mv
  deallocate(ivis)
  !
end subroutine uv_trim_flag
