subroutine selfcal_comm(line,comm,error)
  use gkernel_interfaces
  !---------------------------------------------------------------------
  ! @ private
  !*
  ! IMAGER -- Support for command SELFCAL
  !
  !   This actually cannot be in the CLEAN\ language, because it implies
  !   re-entrancy of RUN_CLEAN - Not a big issue, but currently forbidden 
  !   by our coding practice, so we place it the ADVANCED\ language
  !!
  !---------------------------------------------------------------------
  character(len=*), intent(in) :: comm        !! Command name
  character(len=*), intent(inout) :: line     !! Command line
  logical, intent(inout) :: error             !! Logical error flag
  !
  ! Local ---
  character(len=256) :: argum
  integer :: na
  logical :: do_insert
  !
  ! Code ----
  do_insert = sic_lire().eq.0
  if (sic_present(1,0)) then
    call exec_program('@ p_selfcal /WIDGET')
  else
    if (sic_narg(0).eq.0) then
      call sic_get_char('SELF_MODE',argum,na,error)
    else
      ! Pass all arguments "as they are"
      na = index(line,trim(comm))+8
      argum = line(na:)
    endif
    call exec_program('@ p_selfcal '//argum)
  endif
  if (do_insert) call sic_insert_log(line)
end subroutine selfcal_comm
!
subroutine init_selfcal(rname,line,error)
  use clean_arrays
  use clean_default
  use gbl_message
  use gkernel_interfaces
  use imager_interfaces, except_this => init_selfcal
  !---------------------------------------------------------------------
  ! @ private
  !*
  ! IMAGER -- Support for command 
  ! UV_SELF /RANGE [Min Max Type]
  !
  ! Create the Self-Calibration UV tables from the current one
  ! by averaging the specified range of channels.  
  !     a)  hself_calib and hself_raw : the continuum compressed line UV data   
  !     b)  Hself : the Continuum UV data  
  !!
  !---------------------------------------------------------------------
  character(len=*), intent(in) :: rname     !! Caller name
  character(len=*), intent(inout) :: line   !! Command line
  logical, intent(inout) :: error           !! Logical error flag
  !
  ! Constants
  integer, parameter :: opt_rang=1
  integer(kind=4), parameter :: mtype=3
  integer, parameter :: mranges=50
  character(len=12) :: types(mtype),mytype
  data types /'CHANNEL','VELOCITY','FREQUENCY'/
  !
  ! Local ---
  integer :: SELF_COMPRESS    ! Test variable
  logical :: SELF_DEBUG=.false.
  character(len=12) :: comm='UV_COMPRESS '
  integer :: ni,nt,nu,nv,nchan,ncomp
  integer :: channels(3)
  integer, allocatable :: chflag(:)
  !
  integer :: itype
  character(len=12) :: ctype
  integer :: ndim, ier
  real(8) :: drange(mranges)
  integer :: nc(mranges),numchan,ntmp,i
  !
  real :: cpu0, cpu1
  real :: uvmax, uvmin, field
  integer :: nline, n, narg
  logical :: sorted, shift, needed
  real(kind=8) :: new(3)
  character(len=80) :: chain, acomm, string
  !
  ! Code ----
  call map_message(seve%t,rname,'Init_Selfcal -- Starting ',seve%e)
  SELF_COMPRESS = 0
  call sic_get_inte('SELF_COMPRESS',SELF_COMPRESS,error)
  call sic_get_logi('DEBUG_SELF',self_debug,error)
  error = .false.
  !
  ! Code
  call map_message(seve%i,rname,'Initializing the "selfcal" UV data set',seve%w)
  !
  ! Erase current Self-Calibration UV tables
  if (associated(duvself)) then
    if (associated(duvself,duvcalib)) then
      nullify(duvself)
    else
      deallocate(duvself)
    endif
  endif
  if (allocated(duvcalib)) deallocate(duvcalib)
  if (allocated(duvraw)) deallocate(duvraw)
  call sic_delvariable('UVRAW',.false.,error) 
  call sic_delvariable('UVCALIB',.false.,error) 
  call sic_delvariable('UVSELF',.false.,error) 
  error = .false.
  !
  ! Decode the command line arguments
  numchan = max(sic_narg(opt_rang),0)
  nc = 0
  if (mod(numchan,2).eq.0) then
    !  Default CTYPE is CHANNEL
    mytype = 'CHANNEL'
  else if (numchan.eq.1) then
    call sic_ch(line,opt_rang,numchan,ctype,ndim,.true.,error)
    if (ctype.ne.'*') then
      call map_message(seve%e,rname,'/RANGE option syntax error')
      error = .true.
      return
    endif
    numchan = 0
  else
    call sic_ke(line,opt_rang,numchan,ctype,ndim,.true.,error)
    if (error) return
    call sic_ambigs(rname,ctype,mytype,itype,types,mtype,error)
    if (error)  return
    numchan = numchan-1
  endif
  !
  do i=1,numchan
    call sic_r8(line,opt_rang,i,drange(i),.true.,error)
    if (error) return
  enddo
  !
  ! Then, shift, rotate and sort the initial UV Table
  narg = sic_narg(0)
  string = defmap_center
  n = len_trim(string)
  !
  if (narg.eq.0) then
    if (n.ne.0) then
      line = 'CALIBRATE'//char(92)//trim(rname)//' '//string(1:n)
      nline = len_trim(line)
      call sic_analyse(acomm,line,nline,error)
      if (error) return
    endif
  endif
  call map_center(line,rname,huv_current,shift,new,error)
  if (error) return
  !
  call gag_cpu(cpu0)
  needed = themap%uniform(2).ne.0
  call uv_sort (huv_current,duv,error,sorted,shift,new,uvmax,uvmin,needed)
  if (error) return
  if (.not.sorted) then
    ! Redefine SIC variables (mandatory)
    call map_uvgildas ('UV',huv_current,error,duv)
    call gag_cpu(cpu1)
    write(chain,'(A,F9.2)') 'Finished sorting ',cpu1-cpu0
    call map_message(seve%i,rname,chain)
  endif
  !
  ! Now, define the Raw UV table
  call gildas_null(hself_raw,type='UVT')
  call gildas_null(hself_calib,type='UVT')
  call gildas_null(hself_self,type='UVT')
  !
  hself_calib%gil%nchan = 0 ! No known channel in Calib
  !
  IF (SELF_COMPRESS.eq.0) THEN
    !
    ! Here we use the UV_AVERAGE method - Single channel output
    huv_current%r2d => duv
    ndim = huv_current%gil%nlead+3+huv_current%gil%ntrail
    allocate(duvraw(ndim,huv_current%gil%dim(2)),duvcalib(ndim,huv_current%gil%dim(2)),stat=ier)
    if (ier.ne.0) then
      call map_message(seve%e,rname,'Self Calibration UV table allocation error')
      error = .true.
      return
    endif
    hself_raw%r2d => duvraw
    !
    ! At this stage, we should reset MAP_CENTER...
    acomm = 'LET MAP_CENTER " "'
    call exec_command(acomm,error)
    !
    ! Convert range to channels
    nc = 0
    if (numchan.eq.0) then
      numchan = 2
      nc(1) = 1
      nc(2) = huv_current%gil%nchan 
      !
      ! Could use here the same limit as defined by UV_CHECK BEAM
      call channel_restrict(rname,nc(1),nc(2),error)
      error = .false.
    else if (mytype.eq.'CHANNEL') then
      nc(1:numchan) = nint(drange(1:numchan))
    else if (mytype.eq.'VELOCITY') then
      ! drange = nc - y%gil%ref(y%gil%faxi) ) * y%gil%vres + y%gil%voff 
      nc(1:numchan) = (drange(1:numchan) - huv_current%gil%voff) / huv_current%gil%vres + huv_current%gil%ref(huv_current%gil%faxi)
    else if (mytype.eq.'FREQUENCY') then
      ! drange = nc - y%gil%ref(y%gil%faxi) ) * y%gil%vres + y%gil%voff 
      nc(1:numchan) = (drange(1:numchan) - huv_current%gil%freq) / huv_current%gil%fres + huv_current%gil%ref(huv_current%gil%faxi)
    else
      call map_message(seve%e,rname,"Type of value '"//trim(mytype)//"' not supported")
      error = .true.
      defmap_center = string
      return
    endif
    !
    do i=2,numchan,2
      if (nc(i).lt.nc(i-1)) then
        ntmp = nc(i)
        nc(i) = nc(i-1)
        nc(i-1) = ntmp
      endif
    enddo
    !SG
    huv_current%img%bounds(1) = nc(1)       ! Update the Bounds values
    huv_current%img%bounds(2) = nc(numchan) ! Update the Bounds values
    if (.not.allocated(huv_current%img%flags)) then
!!      Print *,'PROGRAM ERROR, huv_current%img%flags not allocated'
      allocate (huv_current%img%flags(huv_current%gil%nchan))
      huv_current%img%flags = 1
    endif
    !
    call do_uv_average(rname,huv_current,hself_raw,numchan,nc,error)
    ! Copy to UVCALIB & UVSELF
    call gdf_copy_header(hself_raw,hself_calib,error)
    call gdf_copy_header(hself_raw,hself_self,error)
    duvcalib(:,:) = duvraw(:,:)     ! A Physical copy
    duvself => duvcalib             ! A Pointer : no difference since only 1 channel
    hself_self%r2d => duvself
    call map_uvgildas ('UVSELF',hself_self,error,duvself)
  else
    !
    ! Here, we shall use the UV_COMPRESS approach 
    ! combined with the UV_CONTINUUM methodology
    call gdf_copy_header(huv_current,hself_raw,error)
    if (.not.associated(huv_current%r2d,duv)) then
      call map_message(seve%e,rname,'HUV_Current not associated to DUV - Attempting to process')
      huv_current%r2d => duv
    endif
    ncomp = max(0,SELF_COMPRESS)
    field = 0.0
    call sub_cont_average(comm,huv_current,hself_raw,ncomp,field,error)
    ! !call gdf_print_header (hself_raw) 
    !
    ! Work with complete structure
    hself_raw%gil%dim(1) = 3*hself_raw%gil%nchan + 7 + hself_raw%gil%ntrail ! and nothing more ...
    if (hself_raw%gil%ntrail.ne.0) then
      do i=1,code_uvt_last
        if (hself_raw%gil%column_pointer(i).gt.hself_raw%gil%lcol) hself_raw%gil%column_pointer(i) =  &
          & hself_raw%gil%column_pointer(i) + hself_raw%gil%dim(1) - huv_current%gil%dim(1)
      enddo
    endif
    !
    ni = huv_current%gil%dim(1)
    nu = hself_raw%gil%dim(1)
    nv = hself_raw%gil%dim(2)
    nt = hself_raw%gil%ntrail
    nchan = hself_raw%gil%nchan
    !
    allocate(duvraw(hself_raw%gil%dim(1),huv_current%gil%dim(2)),stat=ier)
    if (ier.ne.0) then
      call map_message(seve%e,rname,'Self Calibration UV table allocation error')
      error = .true.
      return
    endif
    call compress_uv (duvraw,nu,nv,nchan,duv,ni,ncomp,nt,huv_current%img%flags)   
    !
    ! Copy this one to CALIB area
    call gdf_copy_header(hself_raw,hself_calib,error)
    allocate(duvcalib(hself_raw%gil%dim(1),huv_current%gil%dim(2)),stat=ier)
    if (ier.ne.0) then
      call map_message(seve%e,rname,'CALIB Memory allocation error')
      error = .true.
      return
    endif
    duvcalib(:,:) = duvraw(:,:)
    call map_uvgildas('UVCALIB',hself_calib,error,duvcalib)
    !
    call map_uvgildas('UVRAW',hself_raw,error,duvraw)
    !
    if (nchan.gt.1) then
      !
      ! The convert the table to a Continuum one
      channels = [1,nchan,1]
      call uv_cont_header(rname,hself_calib,hself_self,channels,expand_cont,error)
      if (error) return
      ! and then the data
      allocate(duvself(hself_self%gil%dim(1),hself_self%gil%dim(2)),chflag(nchan),stat=ier) 
      if (ier.ne.0) then
        call map_message(seve%e,rname,'SELF Memory allocation error')
        error = .true.
        return
      endif
      chflag = 1
      ! 1=code_uvt, specifying UV Table shape
      hself_self%r2d => duvself
      hself_calib%r2d => duvcalib
      call t_continuum(hself_calib,hself_self,channels,1,error) ! No: ,spindex,ofreq)
      if (error) return
    else
      !
      ! Just point to that
      call gdf_copy_header(hself_calib,hself_self,error)
      duvself => duvcalib
    endif
    call map_uvgildas ('UVSELF',hself_self,error,duvself)
  ENDIF
  !
  if (self_debug) then
    Print *,'EXPAND_CONT ',expand_cont,' SELF_COMPRESS ',self_compress
    read(*,*) expand_cont
  endif
  !
  ! At this stage, we should reset MAP_CENTER again...
  defmap_center = string
  !
  ! And force Weight re-computation
  do_weig = .true.
  call map_message(seve%t,rname,'Init_Selfcal -- Ending ',-2)
end subroutine init_selfcal
!
subroutine do_uv_average(rname,hin,hou,numchan,nc,error)
  use gildas_def
  use gkernel_interfaces
  use imager_interfaces, only : map_message, sub_uv_average
  use image_def
  use gbl_format
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private
  !*
  ! IMAGER --  Support for command SELFCAL
  !
  !   Average all selected line channels to 1 continuum channel
  !   Driver routine: prepare header and call per-visibility processing
  !   subroutine
  !!
  !---------------------------------------------------------------------
  character(len=*), intent(in) :: rname     !! Caller
  type(gildas), intent(in) :: hin           !! Input raw visibility header
  type(gildas), intent(inout) :: hou        !! Output Self-Cal header
  integer, intent(in) :: numchan            !! Number of channel ranges
  integer, intent(in) :: nc(numchan)        !! Channel ranges
  logical, intent(out) :: error             !! Logical error flag
  !
  ! Local ---
  character(len=filename_length) :: text
  integer(4) :: nchan, nsum, i
  real(8) :: freq
  !
  ! Code ----
  error = .false.
  !
  if (hin%loca%size.eq.0 .or. .not.associated(hin%r2d)) then
    call map_message(seve%e,rname,'Input UV data is not allocated')
    error = .true.
    return
  endif
  !
  ! Define number of channels being added and effective mean channel
  nchan = 0
  nsum = 0
  do i=2,numchan,2
    nchan = nc(i)-nc(i-1)+1+nchan
    nsum = (nc(i)+nc(i-1))*(nc(i)-nc(i-1)+1)/2+nsum
    if (i.eq.2) then
      write (text,'(2(A,I0))') 'Averaging channels from ',   &
              nc(i-1),' to ',nc(i)
    else
      write (text,'(2(A,I0))') '              and  from ',   &
              nc(i-1),' to ',nc(i)
    endif
    call map_message(seve%i,rname,text)
  enddo
  !
  ! Define output image
  call gdf_copy_header (hin, hou, error)
  !
  ! Do not forget trailing columns
  hou%gil%dim(1) = 10+hou%gil%ntrail
  hou%gil%inc(1) = hou%gil%inc(1)*nchan
  hou%gil%ref(1) = 1.d0-(float(nsum)/nchan-hou%gil%ref(1))/nchan
  hou%gil%vres = nchan*hou%gil%vres
  hou%gil%fres = nchan*hou%gil%fres
  hou%gil%nchan = 1
  call gdf_uv_shift_columns(hin,hou)
  call gdf_setuv (hou, error)
  if (error) return
  !
  ! Bring reference channel to 1
  freq = (1.d0-hou%gil%ref(1))*hou%gil%inc(1) + hou%gil%val(1)
  hou%gil%ref(1) = 1.
  hou%gil%val(1) = freq
  ! Set Frequency accordingly
  hou%gil%freq = freq
  !
  if (.not.allocated(hin%img%flags)) call map_message(seve%e,rname, &
    & 'Flags not allocated')
  call sub_uv_average (hou%r2d, hou%gil%dim(1),hou%gil%dim(2),   &
   &    hou%gil%nlead,  hou%gil%ntrail,               &
   &    hin%r2d ,hin%gil%dim(1),nc,numchan, hin%img%flags)
  hou%loca%size = hou%gil%dim(1) * hou%gil%dim(2)
end subroutine do_uv_average
!
subroutine sub_uv_average (out,nx,nv,nlead,ntrail,inp,ny,nc,num,goodch)
  use gildas_def
  !---------------------------------------------------------------------
  ! @ private
  !*
  ! IMAGER -- Support for command SELFCAL  
  !   Average all selected line channels to 1 continuum channel
  !!
  !---------------------------------------------------------------------
  integer(kind=index_length) :: nx    !! Size of output visibility
  integer(kind=index_length) :: nv    !! Number of visibilities
  integer, intent(in) :: nlead        !! Leading columns
  integer, intent(in) :: ntrail       !! Trailing columns
  real :: out(nx,nv)                  !! Output visibilities
  integer(kind=index_length) :: ny    !! Size of input visibility
  real :: inp(ny,nv)                  !! Input visibilities
  integer :: num                      !! Number of ranges times 2
  integer :: nc(num)                  !! Range boundaries
  integer :: goodch(:)                !! Channel flags
  !
  ! Local ---
  integer :: k,kk,l
  integer(kind=index_length) :: j
  real :: a,b,c
  !
  ! Code ----
  do j=1,nv
    out(1:nlead,j) = inp(1:nlead,j)
    a = 0.0
    b = 0.0
    c = 0.0
    do l=2,num,2
      do k=nc(l-1),nc(l)
        if (goodch(k).gt.0) then
          kk = nlead+3*k
          if (inp(kk,j).gt.0) then
            a = a+inp(kk-2,j)*inp(kk,j)
            b = b+inp(kk-1,j)*inp(kk,j)
            c = c+inp(kk  ,j)
          endif
        endif
      enddo
    enddo
    if (c.ne.0.0) then
      out(8,j) =a/c
      out(9,j) =b/c
      out(10,j)=c              ! time*band
    else
      out(8,j) =0.0
      out(9,j) =0.0
      out(10,j)=0.0
    endif
    if (ntrail.gt.0) out(11:nx,j) = inp(ny-ntrail+1:ny,j)
  enddo
end subroutine sub_uv_average
!
subroutine switch_uv_cont(line,comm,do_cct,error)
  use gildas_def 
  use clean_arrays
  use gbl_message
  use gkernel_interfaces
  use imager_interfaces, except_this => switch_uv_cont
  !---------------------------------------------------------------------
  ! @ private
  !
  ! IMAGER --  Support for command UV_MAP /CONT (and UV_SELF)
  !
  ! Temporarily point towards the "continuum" UV data
  !---------------------------------------------------------------------
  character(len=*), intent(inout) :: line     !! Command line
  character(len=*), intent(in)    :: comm     !! Command name
  logical, intent(in) :: do_cct     !! Remove Clean Components before ?
  logical, intent(inout) :: error   !! Logical error flag
  !
  ! Constants
  ! ' UV_MAP', '/TRUNCATE',  '/FIELDS', '/RANGE', '/CONTINUUM', '/INDEX'
  integer, parameter :: o_trunc=1
  integer, parameter :: o_field=2
  integer, parameter :: o_range=3
  integer, parameter :: o_cont=4
  integer, parameter :: o_index=5
  !
  ! Local ---
  integer :: channels(3)
  integer :: ier
  !
  ! Code ----
  !
  ! Select the data set. Can be UV_DATA, UV_MODEL, or UV_RESIDUAL
  ! We may have an issue about data sorting here,
  ! as well as Weight re-computation
  call uvdata_select(comm,error)
  if (error) return
  !
  if (do_cct) then
    ! The UV data may have changed since last UV_MAP /CONT command
    if (huv_cont%loca%size.eq.0) then
      call map_message(seve%e,comm,'Continuum UV data not defined')
      error = .true.
      return
    endif
    ! Take the imaging mode from previous values
    if (.not.associated(huv_cont%r2d,duvc)) then  !
      call map_message(seve%w,comm,'UVCONT Pointer not associated',seve%e)
      huv_cont%r2d => duvc
      do_weig = .true.
    endif
    call print_imaging(comm,'Continuum DO_CCT ',huv_cont%img)
  else
    call sub_uvcont_header(line,error,huv_cont,channels,o_cont,o_index,o_range)
    if (error) return
    call print_imaging(comm,'UV_CONT',huv_cont%img)
    !
    if (allocated(duvc)) deallocate(duvc)
    allocate(duvc(huv_cont%gil%dim(1),huv_cont%gil%dim(2)),stat=ier)
    huv_cont%loca%size = huv_cont%gil%dim(1)*huv_cont%gil%dim(2)
    huv_cont%r2d => duvc      ! Could use pointer directly
    huv_current%r2d => duv    ! Normally verified
    call sub_uvcont_data(line,huv_cont,huv_current,channels,o_index,error)
    if (error) return
    !
    ! Save the range of channels and imaging mode.
    huv_cont%img = huv_current%img      !SG
    huv_cont%img%bounds = channels(1:2) !SG
    huv_cont%img%mode = code_img_cont   !SG
    !
    ! Weights must be recomputed
    do_weig = .true.
    call sic_delvariable('UVCONT',.false.,error)
    call sic_mapgildas('UVCONT',huv_cont,error,duvc)
  endif
end subroutine switch_uv_cont
!
subroutine uvdebug_pointers(name,text,huvl)
  use image_def
  use gbl_message
  use imager_interfaces, only : map_message
  !! IMAGER - Debug the Mosaic offset pointers
  character(len=*), intent(in) :: name    !! Caller name
  character(len=*), intent(in) :: text    !! Buffers name
  type (gildas), intent(in) :: huvl       !! UV header
  !
  character(len=80) :: chain
  !
  write(chain,'(A,I6,I6,A,I6,I6,A,I4)') ', X (Point) ',&
    & huvl%gil%column_pointer(code_uvt_xoff), &
    & huvl%gil%column_pointer(code_uvt_yoff), &
    & ',  L (phase) ', &
    & huvl%gil%column_pointer(code_uvt_loff), &
    & huvl%gil%column_pointer(code_uvt_moff), &
    & ',  ID (Source) ', &
    & huvl%gil%column_pointer(code_uvt_id)
  call map_message(seve%d,name,text//chain,seve%e)
end subroutine uvdebug_pointers
!
!
subroutine no_mosaic(rname)
  use clean_def
  use clean_default
  use clean_arrays
  use gbl_message
  use gkernel_interfaces
  use imager_interfaces, only : map_message
  !---------------------------------------------------------------------  !
  ! @ private
  !*
  ! IMAGER -- Switch back prompt to IMAGER>
  !!
  !---------------------------------------------------------------------  !
  character(len=*), intent(in) :: rname  !! Caller name
  !
  logical :: error
  !
  if (user_method%mosaic) then
    call map_message(seve%i,rname,'Switching to NORMAL mode')
    call gprompt_set('IMAGER')
    user_method%trunca = 0.0
    call sic_delvariable('PRIMARY',.false.,error)
    hprim%gil%dim(1) = 1
    user_method%mosaic = .false.
  endif
end subroutine no_mosaic
!

