! For Version V 4.2
parse /WIDGET
!
define integer widget
let widget pro%parse%widget%narg
if (widget.eq.-1) then
  !
  if pro%parse%command%narg.eq.0 then
    if exist(selfcal__init) then
      @ selfcal_sum ! Just display the Summary
      return
    endif
  else if pro%parse%command%arg[1].eq."?" then
    @ i_selfcal
  else if exist(selfcal__init) then
    let string 'pro%parse%command%arg[1]' /upper /new char*5
    if string.eq."PHASE" then
      let self_mode PHASE
      @ selfcal_sub 
    else if string.eq."AMPLI" then
      let self_mode AMPLI
      @ selfcal_sub 
    else if string.eq."SUMMA" then
      @ selfcal_sum    
    else if string.eq."SHOW" then
      @ p_show_selfcal 'self_mode' &2 &3    
    else if string.eq."APPLY" then
      if (pro%parse%command%narg.eq.1) then
        @ selfcal_apply 'self_mode'
      else
        @ selfcal_apply &2 &3 
      endif
    else if string.eq."INPUT" then
      @ i_selfcal
    else if string.eq."RECOV" then
      if pro%parse%command%narg.eq.1 then
        if file("selfcal-PHASE.last") then
          if file("selfcal-AMPLI.last") then
            SAY "E-SELFCAL,  Specify RECOVER PHASE or AMPLI"
            return error
          else
            @ selfcal-PHASE.last
            SAY "I-SELFCAL,  Recovered last PHASE self-calibration parameters"
          endif
        else if file("selfcal-AMPLI.last") then
          @ selfcal-AMPLI.last
          SAY "I-SELFCAL,  Recovered last AMPLI self-calibration parameters"
        else
          SAY "E-SELFCAL,  No previous self-calibration parameters"
          return error
        endif
      else
        let string 'pro%parse%command%arg[2]' /upper 
        if file("selfcal-'string'.last") then
          @ selfcal-'string'.last
        else
          SAY "E-SELFCAL,  No previous "'string'" self-calibration parameters"
          return error
        endif
      endif
    else if string.eq."SAVE" then
      @ s_selfcal
    else if string.eq."FLAG" then
      @ selfcal_flag 'self_mode' &2
    else
      SAY "E-SELFCAL,  Unsupported argument "'pro%arg[1]'
    endif
  endif
  !
else if exist(selfcal__init) then
  @ x_selfcal
endif
!
if exist(selfcal__init) return
SAY "Defining Self-Calibration structures. See SELFCAL ?"
!
begin procedure sub_nloops
  !  
  ! Guess the number of loops. The rule is a bit complex:
  ! 1) constant values are assumed re-sizable
  ! 2) if all values are constant, self_times define the size
  !
  define integer sloop kiter times
  define real minflux
  kiter = self_niter[1]
  times = self_times[1]
  minflux = self_minflux[1]
  if (any(self_times.ne.times)) then
    sloop = size(self_times)
  else if (any(self_niter.ne.kiter)) then
    sloop = size(self_niter)
  else if (any(self_minflux.ne.minflux)) then
    sloop = size(self_minflux)
  else
    sloop = size(self_times)
  endif
  !
  if (sloop.ne.size(self_times)) then
    if (any(self_times.ne.times)) then
      define char*80 self_message /global
      if (sloop.eq.size(self_niter)) then
        self_message = 'ansi%red'"SELF_Times and SELF_Niter sizes do not match"'ansi%none'
      else
        self_message = 'ansi%red'"SELF_Times and SELF_Minflux sizes do not match"'ansi%none'
      endif
    else
      delet /var self_times
      define integer self_times[sloop] /global
      let self_times times
    endif
  endif
  if (sloop.ne.size(self_niter)) then
    if (any(self_niter.ne.kiter)) then
      if (exist(self_message)) then
        self_message = 'ansi%red'"SELF_Times, SELF_Minflux and SELF_Niter sizes do not match"'ansi%none'
      else
        define char*80 self_message /global
        self_message = 'ansi%red'"SELF_Niter and SELF_Minflux sizes do not match"'ansi%none'
      endif
    else
      delet /var self_niter
      define integer self_niter[sloop] /global
      let self_niter kiter
    endif
  endif
  if (sloop.ne.size(self_minflux)) then
    if (any(self_minflux.ne.minflux)) then
      if (exist(self_message)) then
        self_message = 'ansi%red'"SELF_Times, SELF_Niter and SELF_Minflux sizes do not match"'ansi%none'
      else
        define char*80 self_message /global
        if (any(self_times.ne.times)) then
          self_message = 'ansi%red'"SELF_Times and SELF_Minflux sizes do not match"'ansi%none'
        else
          self_message = 'ansi%red'"SELF_Niter and SELF_Minflux sizes do not match"'ansi%none'
        endif
      endif
    else
      delet /var self_minflux
      define real self_minflux[sloop] /global
      let self_minflux minflux
    endif
  endif
  !
  let self_loop /status write
  self_loop = sloop
  let self_loop /status read
  !
  if exist(self_message).and.("&1".ne."W") then
    @ i_selfcal E
    return BASE
  endif
end procedure sub_nloops
  !
begin procedure selfcal_sub
  let self_status 0         ! No solution
  if .not.exist(UV) then
    MESSAGE E SELFCAL 'ansi%bold''ansi%red'"No UV data loaded"'ansi%none'
    return error
  endif
  let self_applied 0        ! No calibration applied
  if (self_flux.ne.0) then
    gtvl\gtv SEARCH <CCT
    if (.not.gtv%exist) gtvl\create directory <CCT
  endif
  !
  ! Check the variables length and the number of loops
  @ sub_nloops E 
  !
  if (exist(self_rmsclean)) delete /var self_rmsclean self_maxclean self_dynamic
  define real self_rmsclean['self_loop+1'] -
    self_maxclean['self_loop+1'] self_dynamic['self_loop+1'] /global
  !
  ! Remove previous result files
  for i 1 to self_loop
    if file("'self_sname'-'i'.tab") sic delete 'self_sname'"-"'i'".tab"
  next
  if file("'self_sname'.tab") sic delete 'self_sname'".tab"
  !
  ! Self calibration Loops
  for i 1 to self_loop
    let self_iter self_niter[i]
    @ selfcal_iteration 'i'
    sic rename 'self_sname'".tab" 'self_sname'-'i'".tab"
  next
  !
  calibrate\uv_self
  if self_flux.gt.0 then
    clean\clean /flux  0 self_flux
  else
    clean\clean
  endif
  if self_restore then
    calibrate\uv_self /restore !! self
  endif
  let self_maxclean['self_loop+1'] clean%max
  stat clean /noise self_rmsclean['self_loop+1']
  let cc self_rmsclean['self_loop+1'] /format 1PES11.2 /new char*12
  let self_dynamic['self_loop+1'] self_maxclean['self_loop+1']/self_rmsclean['self_loop+1']
  say " --- After self-calibration loop "'self_loop'"  -- rms "'cc'
  show clean 
  !
  ! Update color range if needed
  if (self_color.ne.0) color self_color
  !
  ! Collect all solutions in one file
  @ selfcal_gather 'self_loop'
  !
  ! Set default status 
  if (self_mode.eq."PHASE") then
    let self_status 1
  else
    let self_status 2
  endif
  !
  @ selfcal_sum
  !
end procedure selfcal_sub
! 
begin procedure selfcal_iteration
  defin integer my_iter
  if &1.eq.1 then
    if any(self_channel.ne.0) then
      calibrate\uv_self /range  'self_channel[1]' 'self_channel[2]' CHANNEL
    else
      calibrate\uv_self /range
    endif
  else
    calibrate\uv_self
  endif
  if (self_display) then
    let my_iter clean_niter
  else
    let clean_niter self_iter
  endif
  if self_flux.gt.0 then
    clean /flux  0 self_flux
    gtvl\gtv search <CCT
    if .not.gtv%exist gtvl\create directory <CCT
    gtvl\change dir <CCT
    @ p_show_cct cct
    greg1\draw text -1 -1 "Self Calibration # &1" 1 /char 9
    gvl\change dir <GREG
  else
    clean\clean
  endif
  !
  if self_restore then
    calibrate\uv_self /restore
  endif
  !
  let self_maxclean[&1] clean%max
  stat clean /noise self_rmsclean[&1]
  let self_dynamic[&1] self_maxclean[&1]/self_rmsclean[&1]
  if (self_display) then
    show clean 
    if (self_color.ne.0) color 'self_color'
    let cc self_rmsclean[&1] /format 1PES11.2 /new char*12
    let dd self_dynamic[&1] /format F11.2 /new char*12
    say " --- Before self-calibration loop &1 -- rms "'cc'" -- Dynamic "'dd'
    SIC\PAUSE  
  endif
  !
  if self_minflux[&1].eq.0 then
    calibrate\MODEL Self_Iter 
  else
    calibrate\MODEL 100000 /MINVAL self_minflux[&1] Jy
  endif
  on error "return base"
  if (self_flag) then
    calibrate\SOLVE Self_times[&1] Self_snr /MODE 'self_mode' FLAG
  else
    calibrate\SOLVE Self_times[&1] Self_snr /MODE 'self_mode' 
  endif
  clean\WRITE SELFCAL 'self_sname'".tab"
end procedure selfcal_iteration
!
begin procedure selfcal_gather
  define integer ns nd nc
  let nc &1
  let ns 0
  for i 1 to nc
    define header a 'self_sname'-'i'.tab read
    let ns max(a%dim[1],ns)
    let nd a%dim[2]
    delet /var a
  next
  !
  define image b[ns,nd,nc] 'self_sname'.gdf real
  for i 1 to nc
    define image a 'self_sname'-'i'.tab read
    if (i.eq.1) then
      let b% a%
      let b%unit3 "Iteration"
    endif
    let ns size(a,1)
    let b[1:ns,,i] a
    delet /var a
    sic delete 'self_sname'-'i'.tab
  next
end procedure selfcal_gather 
!
begin procedure selfcal_apply
  if self_status.eq.0 then
    MESSAGE E SELFCAL 'ansi%bold''ansi%red'"No Self-Calibration to be applied"'ansi%none'
  else if self_applied.ne.0 then
    MESSAGE W SELFCAL 'ansi%bold''ansi%blue''self_mode'" Self-Calibration already applied"'ansi%none'
  else if self_status.lt.0 then
    MESSAGE E SELFCAL 'ansi%bold''ansi%red''self_mode'" Self-Calibration is not good"'ansi%none'
  else
    let oloop self_status/10 /new integer
    if (oloop.ne.0) then
      MESSAGE W SELFCAL 'ansi%bold''ansi%blue''self_mode'" Self-Calibration would be better with "'oloop'" iterations"'ansi%none'
    endif
    if self_flag then
      calibrate\apply &1 &2 /flag
    else
      calibrate\apply &1 &2 
    endif
    let self_applied mod(self_status,10)
    !
    ! Create the selfcal.last file
    @ s_selfcal  
  endif
end procedure selfcal_apply
!
begin procedure selfcal_flag
  if self_status.eq.0 then
    MESSAGE E SELFCAL 'ansi%bold''ansi%red'"No Self-Calibration to be applied"'ansi%none'
    return
  endif
  !
  if self_applied.ne.0 then
    MESSAGE W SELFCAL 'ansi%bold''ansi%blue''self_mode'" Self-Calibration was already applied"'ansi%none'
  else if self_status.lt.0 then
    MESSAGE W SELFCAL 'ansi%bold''ansi%red''self_mode'" Self-Calibration is not good"'ansi%none'
  else
    let oloop self_status/10 /new integer
    if (oloop.ne.0) then
      MESSAGE W SELFCAL 'ansi%bold''ansi%blue''self_mode'" Self-Calibration would be better with "'oloop'" iterations"'ansi%none'
    endif
  endif
  !
  calibrate\apply &1 0 /flag &2 
end procedure selfcal_flag
!
@ d_selfcal
define integer selfcal__init /global
!
if widget.ge.0 then
  @ x_selfcal
endif
