program uv_ref_model
  use gildas_def
  use gkernel_interfaces
  use mapping_interfaces
  use image_def
  use gbl_format
  !---------------------------------------------------------------------
  ! TASK  Self-Calibration relative to a uv model
  !	Applies "Self-Calibration" results to a CLIC UV table.
  ! Input :
  !	TABLE$	The UV table to be self-calibrated
  !	SELF$	The "gain" table, i.e. a UV table used as phase reference
  !       UVMODEL$  The UV model table
  !	DTIME$	The smoothing time constant
  !       WCOL$   The reference channel
  !	TYPE$	Type of self-cal, Ampli, Phase or Both
  !	SUBT$	Subtract point source model from data
  ! R.Moreno 17-Jun-1999
  !---------------------------------------------------------------------
  ! Local
  type(gildas) :: x,y,z
  character(len=filename_length) :: uv_table,self_name,model_name,name
  character(len=8) :: type
  real*8 :: time,stime,dtime
  integer :: wcol,itype
  !
  complex(4) :: model,  resul, self
  real(8), allocatable :: ipw(:)
  integer, allocatable :: ipi(:)
  integer :: sblock=1000
  integer :: i,nvs,nvi,kvs,kvi,nsc,nc,n,j, ier, k, wrange(2), mrange(2)
  real :: factor,rbase(2),reel,imgi,uv(2)
  real :: kilow,weight
  logical :: error
  real(8) :: freq
  real(8), parameter :: pi=3.14159265358979323846d0
  real(8), parameter :: f_to_k = 1.d0/299792458.d-6
  !
  call gildas_open
  call gildas_char('UV_TABLE$',uv_table)
  call gildas_char('SELF$',self_name)
  call gildas_char('UVMODEL$',model_name)
  call gildas_dble('DTIME$',dtime,1)
  call gildas_inte('WCOL$',wcol,1)
  call gildas_char('TYPE$',type)
  call gildas_real('SUB$',factor,1)
  call gildas_close
  !
  self = cmplx(1.0,0.0)
  if (type.eq.'BOTH') then
    itype = 0
  elseif (type.eq.'AMPLI') then
    itype = -1
  elseif (type.eq.'PHASE') then
    itype = 1
  elseif (type.eq.'NONE') then
    itype = 2
    weight = 1.0
  endif
  dtime = 0.5d0*dtime
  mrange(1:2) = 1
  !
  ! Open continuum table
  n = lenc(self_name)
  if (n.le.0) goto 999
  name = self_name(1:n)
  !
  ! Open continuum table
  n = lenc(self_name)
  if (n.le.0) goto 999
  name = self_name(1:n)
  call gildas_null (y, type = 'UVT')
  call gdf_read_gildas(y, name, '.uvt', error)
  if (error) then
    call gagout('F-SELF_CAL,  Cannot read input UV table')
    goto 999
  endif
  nsc = y%gil%nchan 
  freq = y%gil%val(1)+y%gil%fres*(y%gil%val(1)/y%gil%freq)*((nsc+1)*0.5-y%gil%ref(1))
  kilow = freq*f_to_k
  wcol = max(1,wcol)
  wcol = min(wcol,nsc)
  wrange(1:2) = wcol
  !
  ! Load time variable and sort by time order
  nvs = y%gil%dim(1)
  nvi = y%gil%dim(2)
  allocate (ipw(nvi), ipi(nvi), stat=ier)
  !
  ! Open Model table : in Z slot
  n = lenc(model_name)
  if (n.le.0) goto 999
  name = model_name(1:n)
  call gildas_null (z, type = 'UVT')
  call gdf_read_gildas(z, name, '.uvt', error)
  if (error) then
    call gagout('F-SELF_CAL,  Cannot read input UV model')
    goto 999
  endif
  !
  ! Open line table
  n = lenc(uv_table)
  if (n.le.0) goto 999
  name = uv_table(1:n)
  call sic_parsef(name,x%file,' ','.uvt')
  call gildas_null(x, type = 'UVT')
  call gdf_read_gildas(x, name, '.uvt', error, data=.false.)
  if (error) then
    call gagout ('F-SELF_CAL,  Cannot read input/output UV table')
    goto 999
  endif
  nc = x%gil%nchan 
  !
  ! Sort self-cal table
  call dotime (nvs, nvi, y%r2d, ipw, ipi, stime)
  allocate (x%r2d(x%gil%dim(1), sblock), stat=ier)
  kvs = z%gil%dim(1)
  kvi = z%gil%dim(2)
  !
  ! Loop over line table
  do i=1,x%gil%dim(2),sblock
    x%blc(2) = i
    x%trc(2) = min(x%gil%dim(2),i-1+sblock)
    call gdf_read_data(x,x%r2d,error)
    k = 0
    do j=x%blc(2),x%trc(2)
      k = k+1
      call getiba (x%r2d(:,k),stime,time,rbase,uv)
      !
      ! Compute the observed reference visibility for that baseline
      call geself (nvs,nvi,wrange,y%r2d,   &
     &        time,dtime,ipw,ipi,   &
     &        rbase,resul,uv)
      !
      ! No data: flag
      if (resul.eq.cmplx(0.,0.)) then
        call doflag (nc,x%r2d(:,k)) 
      else
        !
        ! Compute the model visibility
        call geself (kvs,kvi,mrange,z%r2d,  &
     &          time,dtime,ipw,ipi,  &
     &          rbase,model,uv)
        ! Compute self-cal correction
        if (itype.ne.2) then
          call doself  (model,resul,itype,self,weight)
        endif
        ! Compute fraction of source to remove
        reel = factor*real(model)
        imgi = factor*imag(model)
        ! Apply self-cal and remove source
        call doscal (nc,x%r2d(:,k),real(self),imag(self), &
        &       reel,imgi,weight)
      endif
    enddo
    call gdf_write_data(x, x%r2d, error)
  enddo
  ! end loop
  call gdf_close_image(x,error)
  call gdf_close_image(y,error)
  call gdf_close_image(z,error)
  call gagout('S-UV_REF_MODEL,  Successful completion')
  call sysexi(1)
  999   call sysexi(fatale)
end program uv_ref_model
