subroutine mask_comm(line,error)
  use gildas_def
  use gbl_message
  use gkernel_types
  use clean_arrays
  use gkernel_interfaces
  !---------------------------------------------------------------------
  ! @ private
  !   IMAGER
  ! Support routine for command
  !   ADVANCED\MASK
  !
  ! Several modes
  !   MASK  ADD Figure Description
  !                 Add the corresponding figure to mask
  !   MASK  APPLY Variable  
  !                 Apply the current mask to 3-D Variable
  !   MASK  INIT [2D|3D]
  !                 Initialize a mask
  !   MASK  OVERLAY
  !                 Overlay the mask on the current Image
  !   MASK  READ File
  !                 Read a Mask from disk (is that a .msk or a .pol ?) 
  !                 (redundant with READ MASK )
  !   MASK  REMOVE  Fig_Description
  !                 Removed the figure from mask
  !   MASK  USE   
  !                 Activate the current mask as a Support
  !                 (redundant with SUPPORT /MASK)
  !   MASK  SHOW    
  !                 as SHOW MASK
  !   MASK  THRESHOLD Raw Smooth [Length]
  !                 automatic Mask builder by Thresholding
  !   MASK  WRITE File
  !                 Write a mask to disk 
  !                 (almost redundant with WRITE MASK ? )
  !
  !   MASK          Launch interactive mask definition
  !          (would be better on currently displayed image, rather
  !           than only the CLEAN data cube. Rank could depend
  !           on how many channels are displayed)
  !
  !---------------------------------------------------------------------
  character(len=*), intent(in)  :: line   ! Input command line
  logical,          intent(out) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='MASK'
  !
  !! Not needed, actually
  !! integer, parameter :: v_mask=8  ! MASK is number 8 in list
  !
  type(gildas) :: head
  integer, parameter :: mvoc=12
  character(len=12) :: vocab(mvoc), key, lkey
  data vocab /'ADD','APPLY','CHECK','INITIALIZE','INTERACTIVE','OVERLAY','READ','REMOVE', &
    & 'SHOW','THRESHOLD','USE','WRITE'/
  integer, parameter :: mfig=4
  character(len=12) :: figure(mfig), kfig
  data figure /'CIRCLE','ELLIPSE','POLYGON','RECTANGLE'/
  character(len=24) :: argum, chain
  character(len=filename_length) :: name
  character(len=commandline_length) :: aline
  integer :: ikey,is,nc,na,narg
  logical :: do_insert, all
  real :: r4
  !
  integer :: nchans(2)
  !
  error = .false.
  !
  do_insert = sic_lire().eq.0
  !
  ! If no argument, activate the default interactive mode
  argum = 'INTERACTIVE'
  !
  call sic_ke(line,0,1,argum,nc,.false.,error)
  if (error) return  !
  call sic_ambigs (rname,argum,key,ikey,vocab,mvoc,error)
  if (error) return
  !
  if (key.eq.'CHECK') then
    call mask_check(.true.,error)
    return
  endif
  ! These create the MASK
  select case(key)
  case ('INITIALIZE')
    if (sic_narg(0).eq.1) then
      argum = '3D'
    else
      call sic_ke(line,0,2,argum,nc,.false.,error)
    endif
    call mask_init(argum,error)
    if (error) return
    call exec_program('@ p_mask init NO')  ! Support is void at this stage
  case ('READ') 
    call sic_ch(line,0,2,name,nc,.true.,error)
    if (error) return
    !
    call gildas_null(head)
    call sic_parse_file(name,' ','.msk',head%file)
    call gdf_read_header (head,error)
    if (error) return
    !
    nchans = 0
    call map_read (head,'MASK',nchans,.false.,error)  
    call gdf_close_image (head,error)
    call exec_program('@ p_mask init YES')  ! Support is filled 
  case ('THRESHOLD')
    call mask_threshold(line,error)
    call exec_program('@ p_mask init YES')  ! Support is filled 
  !
  ! These need the MASK and the Clean image
  case ('INTERACTIVE') 
    call mask_check(.true.,error)
    if (error) return
    !
    argum = '1'
    call sic_ke(line,0,2,argum,nc,.false.,error)
    call exec_program('@ p_mask interactive '//argum)
  case ('ADD','REMOVE')
    call mask_check(.true.,error)
    if (error) return
    call sic_ke(line,0,2,argum,nc,.false.,error)
    if (error) return  !
    call sic_ambigs (rname,argum,kfig,ikey,figure,mfig,error)
    if (error) return
    call sic_lower(kfig)
    lkey = key
    call sic_lower(lkey)
    narg = sic_narg(0)
    if (narg.gt.2) then
      ! Get the numerical values of all arguments
      aline = '@ p_mask '//trim(lkey)//' '//kfig
      na = len_trim(aline)+2
      do is=3,narg
        call sic_r4(line,0,is,r4,.true.,error)
        if (error) return
        write(chain,*) r4
        aline(na:) = chain
        na = na + len_trim(chain)
      enddo
      call exec_program(aline)
    else
      call exec_program('@ p_mask '//trim(lkey)//' '//kfig)
    endif
  case ('APPLY') 
    call mask_check(.true.,error)
    if (error) return
    call mask_apply(line,error)
    do_insert = .false.
  case ('OVERLAY') 
    call mask_check(.true.,error)
    if (error) return
    call exec_program('@ p_mask over')
  !
  ! Only MASK is needed below
  case ('USE')
    call mask_check(.false.,error)
    if (error) return
    call exec_program('SUPPORT /MASK')
  case ('SHOW')
    call mask_check(.false.,error)
    if (error) return
    call exec_program('SHOW MASK')
  case ('WRITE')
    call mask_check(.false.,error)
    if (error) return
    !
    is = sic_start(0,2) 
    call exec_program('WRITE MASK '//line(is:))
  case default
    call map_message(seve%e,rname,trim(key)//' not yet supported')
    error = .true.
    return
  end select  
  if (do_insert) call sic_insert_log(line)
end subroutine mask_comm
!
subroutine mask_apply(line,error)
  use gildas_def
  use gbl_message
  use gkernel_types
  use clean_arrays
  use gkernel_interfaces
  !---------------------------------------------------------------------
  ! @ private
  !   IMAGER
  ! Support routine for command
  !   ADVANCED\MASK APPLY Variable
  !---------------------------------------------------------------------  
  character(len=*), intent(in)  :: line   ! Input command line
  logical,          intent(out) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='MASK'
  !
  type(gildas) :: hin
  type(sic_descriptor_t) :: desc
  real(kind=4) :: blank
  real(kind=8) :: i_freq
  integer(kind=4) :: nc,ier,ikey
  character(len=6) :: argum,key
  integer :: iplane, ipm
  logical :: equal
  integer(kind=address_length) :: ipnt
  integer, save :: memory(8)
  !
  if (hmask%loca%size.eq.0) then
    call map_message(seve%e,rname,'No mask defined')
    error = .true.
    return
  endif
  error = .false.
  !
  call sic_ke(line,0,2,argum,nc,.false.,error)
  if (error) return
  !
  if (argum.eq.'MASK') then
    call map_message(seve%e,rname,'Cannot MASK the Mask...')
    error = .true.
    return
  endif
  !
  ! Any SIC 2-D+ variable with matching coordinate is acceptable
  call gildas_null(hin)
  call get_gildas(rname,argum,desc,hin,error)
  if (error) return
  !
  blank = hin%gil%bval
  hin%gil%eval = max(hin%gil%eval,0.0)
  !
  ! Check that HIN and HMASK match in 2-D and that Frequency axis
  ! can be interpolated properly
  call gdf_compare_2d(hin,hmask,equal)
  if (.not.equal) then
    call map_message(seve%e,rname,'MASK and '//trim(argum)//' do not match')
    error = .true.
    return
  endif
  !
  ipnt = gag_pointer(desc%addr,memory)
  hmask%r3d => dmask
  call sub_mask_apply(hin,hmask,memory(ipnt),error)
  !
end subroutine mask_apply
  !
subroutine sub_mask_apply(hin,hmask,din,error)
  use image_def
  use gbl_message
  !---------------------------------------------------------------------
  ! @ no-interface
  !   Apply a mask
  !---------------------------------------------------------------------
  type(gildas), intent(in) :: hin
  type(gildas), intent(in) :: hmask
  real, intent(inout) :: din(hin%gil%dim(1),hin%gil%dim(2),hin%gil%dim(3))
  logical :: error
  !
  character(len=*), parameter :: rname='MASK'
  integer :: iplane, ipm
  real(8) :: i_freq
  real :: blank
  !
  blank = hin%gil%bval
  !
  !!Print *,'Mask rank ',hmask%gil%ndim,hmask%gil%dim(1:3)
  if (hmask%gil%dim(3).le.1) then
    !
    ! Apply Mask to all planes
    do iplane=1,hin%gil%dim(3)
      !!PRINT *,'DOING ',iplane,hin%gil%dim(3),' Blank ',blank
      where (hmask%r3d(:,:,1).eq.0) din(:,:,iplane) = blank
    enddo
  else
    if (hin%gil%faxi.ne.3) then
      call map_message(seve%e,rname,'3rd axis is not Frequency | Velocity')
      error = .true.
      return
    endif
    !
    ! Find matching planes
    do iplane=1,hin%gil%dim(3)
      ! This may be the better way of doing it:
      i_freq = (iplane-hin%gil%ref(3))*hin%gil%fres + hin%gil%freq
      ! i_freq = (ibeam-hbeam%gil%ref(4))*hbeam%gil%fres + hbeam%gil%freq
      ipm = nint((i_freq-hmask%gil%freq)/hmask%gil%fres + hmask%gil%ref(3))
      ipm = min(max(1,ipm),hmask%gil%dim(3)) ! Just  in case
      where (hmask%r3d(:,:,ipm).eq.0) din(:,:,iplane) = blank
    enddo
  endif
end subroutine sub_mask_apply
!
subroutine gdf_compare_2d(hone,htwo,equal)
  use image_def
  !---------------------------------------------------------------------
  ! @ private
  !   Check 2D consistency of data cubes
  !---------------------------------------------------------------------
  type(gildas), intent(in) :: hone
  type(gildas), intent(in) :: htwo
  logical, intent(out) :: equal
  !
  real(8) :: tolerance=0.001    ! Pixels...
  real(8) :: x0, y0
  integer :: i
  !
  ! Compare first 2 axes
  equal = .true.
  do i=1,2
    if (hone%gil%dim(i).ne.htwo%gil%dim(i)) then
      equal = .false.
      return
    else
      x0 = (0-hone%gil%ref(i))*hone%gil%inc(i) + hone%gil%val(i)
      y0 = (0-htwo%gil%ref(i))*htwo%gil%inc(i) + htwo%gil%val(i)
      if ( abs(x0-y0).gt.tolerance*abs(hone%gil%inc(i)) ) then
        equal = .false.
        return
      endif
    endif
  enddo
end subroutine gdf_compare_2d  
!
subroutine mask_threshold(line,error)
  use gkernel_interfaces
  use imager_interfaces, only : map_message, sub_mask_threshold
  use clean_arrays
  use clean_default
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private
  !   IMAGER
  ! Support for command
  !   ADVANCED\MASK THRESHOLD Raw Smooth [Length]
  !
  !  Raw      Thresholding (in Sigma) of the Clean image
  !  Smooth   Thresholding (in Sigma) after smoothing
  !  Length   Smoothing length: default is Clean beam major axis
  !
  ! Select CLEAN or SKY depending on last available
  !---------------------------------------------------------------------
  character(len=*), intent(in) :: line
  logical, intent(inout) :: error
  !
  if (last_shown.eq.'CLEAN') then
    call sub_mask_threshold(hclean,last_shown,line,error)
  else if (last_shown.eq.'SKY') then
    call sub_mask_threshold(hsky,last_shown,line,error)
  else
    call map_message(seve%e,'MASK','No CLEAN or SKY available')
    error = .true.
  endif
end subroutine mask_threshold
!
subroutine sub_mask_threshold(head,name,line,error)
  use gkernel_interfaces
  use imager_interfaces, only : map_message, mask_clean
  use clean_arrays  
  use clean_support
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private
  !
  ! IMAGER
  !   Support for command
  ! MASK THRESHOLD Raw Smooth [Length]
  !
  !  Raw      Thresholding (in Sigma) of the Clean image
  !  Smooth   Thresholding (in Sigma) after smoothing
  !  Length   Smoothing length: default is Clean beam major axis
  !---------------------------------------------------------------------
  type(gildas), intent(in) :: head
  character(len=*), intent(in) :: name
  character(len=*), intent(in) :: line
  logical, intent(inout) :: error
  !
  integer, parameter :: o_thre=0 ! In command line, not in option
  integer, parameter :: a_offs=1 ! But shifted by 1 argument
  character(len=*), parameter :: rname='MASK'
  !
  real :: raw,smo,length,noise,margin
  integer :: ier
  !
  if (head%loca%size.eq.0) then
    call map_message(seve%e,rname,'No '//trim(name)//' image')
    error = .true.
    return
  endif
  raw = 5.0
  smo = 2.0
  length = head%gil%majo
  !
  call sic_r4(line,o_thre,a_offs+1,raw,.false.,error)
  if (error) return
  call sic_r4(line,o_thre,a_offs+2,smo,.false.,error)
  if (error) return
  call sic_r4(line,o_thre,a_offs+3,length,.false.,error)
  if (error) return
  if (length.eq.0)  length = head%gil%majo
  margin = 0.18
  call sic_r4(line,o_thre,a_offs+4,margin,.false.,error)
  if (margin.lt.0 .or. margin.gt.0.5) then
    call map_message(seve%e,rname,'Margin must be >0 and <0.5')
    error = .true.
    return
  endif
  !
  noise = max(hdirty%gil%noise,head%gil%noise,head%gil%rms)
  if (noise.le.0) then
    call map_message(seve%e,rname,'No noise estimate, use STATISTIC before')
    error = .true.
    return
  endif
  !
  call sic_delvariable('MASK',.false.,error)
  if (allocated(dmask)) deallocate(dmask)    
  call gdf_copy_header(head,hmask,error)
  allocate(dmask(hmask%gil%dim(1),hmask%gil%dim(2),hmask%gil%dim(3)),   &
   &        stat=ier)
  !
  call mask_clean(hmask,dmask,head%r3d,raw*noise,smo*noise,length,margin,error)
  if (error) return
  !
  ! sic_mapgildas produces a Read-Only variable, so preset the
  ! content as 0/1 and the Min Max as appropriate.
  where(dmask.ne.0) dmask = 1.0 
  hmask%gil%rmin = 0.0
  hmask%gil%rmax = 1.0
  !
  call sic_mapgildas('MASK',hmask,error,dmask)
  user_method%do_mask = .true.
  support_type = 1 ! First plane will be used by default 
  !
end subroutine sub_mask_threshold
!
subroutine mask_clean (head,mask,data,raw,smo,length,margin,error) 
  use clean_def
  use image_def
  use gbl_message
  use gkernel_interfaces
  use imager_interfaces, only : mulgau, map_message
  !---------------------------------------------------------------------
  ! @ private-mandatory
  !
  ! IMAGER
  !   Support routine for SUPPORT /THRESHOLD and
  !   MASK THRESHOLD 
  !
  !   Builds a Mask from a Threshold and Smoothing 
  !---------------------------------------------------------------------
  type (gildas), intent(inout) :: head
  real, intent(out), target :: mask(head%gil%dim(1),head%gil%dim(2),head%gil%dim(3))
  real, intent(in) :: data (head%gil%dim(1),head%gil%dim(2),head%gil%dim(3))
  real, intent(in) :: raw
  real, intent(in) :: smo
  real, intent(in) :: length
  real, intent(in) :: margin
  logical, intent(out) :: error
  !
  real(8), parameter :: pi=3.141592653589793d0
  character(len=*), parameter :: rname='MASK'
  !
  integer nx,ny,nc,ix,iy,ic,jx,jy,ndim,dim(2),ier
  real xinc, yinc,fact
  real, allocatable :: wfft(:)
  real, pointer :: tmp(:,:)
  complex, allocatable :: ft(:,:)
  character(len=80) :: chain
  !
  nx = head%gil%dim(1)
  ny = head%gil%dim(2)
  nc = head%gil%dim(3)
  allocate (wfft(2*max(nx,ny)),ft(nx,ny),stat=ier)
  if (ier.ne.0) then
    call map_message(seve%e,rname,'Memory allocation error in MASK_CLEAN')
    error = .true.
    return
  endif
  xinc = head%gil%convert(3,1)
  yinc = head%gil%convert(3,2)
  !
  dim(1) = nx
  dim(2) = ny
  ndim = 2
  jy = margin*ny
  jx = margin*nx
  !
  write(chain,'(A,1PG10.2,1PG10.2,A,0PF8.2,A,F6.2)') 'Threshold',raw,smo, &
    & ',  Smoothing ',length*180.*3600./pi,'", guard band ',margin
  call map_message(seve%i,rname,chain)
  !
  do ic=1,nc
    tmp => mask(:,:,ic)
    !
    ! Guard band of margin-th of the image size on each edge to
    ! avoid aliased sidelobes and "raw" thresholding
    tmp = 0.0
    if (head%gil%eval.ge.0.0) then
      do iy=jy+1,ny-jy
        do ix=jx+1,nx-jx
          if (abs(data(ix,iy,ic)-head%gil%bval).gt.head%gil%eval) then
            if (data(ix,iy,ic).ge.raw) tmp(ix,iy) = data(ix,iy,ic)
          endif
        enddo
      enddo    
    else
      do iy=jy+1,ny-jy
        do ix=jx+1,nx-jx
          if (data(ix,iy,ic).ge.raw) tmp(ix,iy) = data(ix,iy,ic)
        enddo
      enddo
    endif
    !
    ! Smoothing of "raw" mask
    ft(:,:) = cmplx(tmp,0.0)
    !
    call fourt(ft,dim,ndim,-1,0,wfft)
    !
    ! Correct for Beam Area for flux density normalisation
    fact = length**2*pi/(4.0*log(2.0))/abs(xinc*yinc)/(nx*ny)
    call mulgau(ft,nx,ny,   &
         &    length, length, 0.0,   &
         &    fact,xinc,yinc, -1)
    call fourt(ft,dim,ndim,1,1,wfft)
    !
    ! Extract Real part
    tmp(:,:) = real(ft)
    where (tmp.lt.smo) tmp = 0.0
  enddo
  !
  ! To be coded: Pruning small isolated regions
  ! a) Label fields
  ! b) Sort them by size
  ! c) Suppress those with size smaller than fraction of beam
  !
  deallocate (wfft,ft)
end subroutine mask_clean
!
subroutine mask_init(key,error)
  use clean_arrays
  use clean_types
  use clean_default
  use gkernel_interfaces
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private
  !   IMAGER
  !     Support for command
  !   MASK INIT [2D|3D]
  !--------------------------------------------------------------------- 
  character(len=*), intent(in) :: key
  logical, intent(inout) :: error
  !
  character(len=*), parameter :: rname='MASK'
  integer :: ier
  !
  error = .false.
  !
  ! Free the current MASK if any
  save_data(code_save_mask) = .false.
  call sic_delvariable ('MASK',.false.,error)
  if (allocated(dmask)) deallocate(dmask,stat=ier)
  hmask%loca%size = 0
  if (key.eq.' ') return
  !
  if (key.ne.'2D'.and.key.ne.'3D') then
    call map_message(seve%e,rname,' INITIALIZE invalid argument '//trim(key))
    error = .true.
    return
  endif
  !
  !!Print *,'Last_Shown ',last_shown
  if (last_shown.eq.'CLEAN') then
    if (hclean%loca%size.eq.0) then
      call map_message(seve%e,rname,' INITIALIZE : no Clean image')
      error = .true.
      return
    endif
    call gdf_copy_header(hclean,hmask,error)  
  else if (last_shown.eq.'SKY') then
    if (hsky%loca%size.eq.0) then
      call map_message(seve%e,rname,' INITIALIZE : no Sky image')
      error = .true.
      return
    endif
    call gdf_copy_header(hsky,hmask,error)  
  else
    call map_message(seve%e,rname,' INITIALIZE : no Clean or Sky image')
    error = .true.
    return
  endif
  !
  if (key.eq.'2D') hmask%gil%dim(3) = 1
  allocate(dmask(hmask%gil%dim(1),hmask%gil%dim(2),hmask%gil%dim(3)),   &
   &        stat=ier)
  dmask = 0.0 ! By default, nothing is selected
  hmask%loca%size = hmask%gil%dim(1)*hmask%gil%dim(2)*hmask%gil%dim(3)
  !
  call sic_mapgildas ('MASK',hmask,error,dmask)
end subroutine mask_init
!
subroutine mask_check(all,error)
  use clean_arrays
  use imager_interfaces, only : map_message
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private
  !   IMAGER
  ! Support for command MASK
  !---------------------------------------------------------------------
  logical, intent(in) :: all
  logical, intent(inout) :: error
  character(len=*), parameter :: rname='MASK'
  !
  error = .true.
  !
  if (hmask%loca%size.eq.0) then
    call map_message(seve%e,rname,'No Mask defined')
    return
  endif  
  if (hclean%loca%size.eq.0) then
    call map_message(seve%w,rname,'No Clean image')
    error = all
    return
  endif
  !
  if (any(hmask%gil%dim(1:2).ne.hclean%gil%dim(1:2))) then
    call map_message(seve%e,rname,'Mask and Clean sizes do not match')
    return
  else if (hmask%gil%dim(3).ne.1) then
    ! Check matching velocity range would be better
    if (hmask%gil%dim(3).ne.hclean%gil%dim(3)) then
      call map_message(seve%w,rname,'Mask and Clean planes mismatch, proceed at own risk')
    endif
  endif 
  error = .false.
end subroutine mask_check
