program uv_closephase
  use gildas_def
  use gkernel_interfaces
!
! Apply a phase error (antenna based) to an input UV table
!
  character(len=filename_length) nami,namo
  real(4) :: phase
  logical error
!
  call gildas_open
  call gildas_char('INPUT$',nami)
  call gildas_char('OUTPUT$',namo)
  call gildas_real('PHASE$',phase,1)
  call gildas_close
  call sub_closephase(nami,namo,phase,error)
  call gagout('I-UV_CLOSEPHASE,  Successful completion')
end program uv_closephase
!<ff>
subroutine sub_closephase(nami,namo,phase,error)
  use image_def
  use gkernel_interfaces
  character(len=*) nami,namo
  real :: phase
  logical error
!
  type (gildas) :: hin,hout
  real, allocatable :: din(:,:)
  integer nt,nv,nant,ntime,ier
  real(8), allocatable :: altimes(:), intimes(:)
  integer, allocatable :: inant(:)
  character*60 chain
!
! Read Header of a sorted, UV table
  call gildas_null(hin)
  call sic_parsef (nami,hin%file,' ','.uvt')
  call gdf_read_header (hin,error)
  if (error) return
  allocate (din(hin%gil%dim(1),hin%gil%dim(2)),stat=ier)
  call gdf_read_data (hin,din,error)
  if (error) return
  nt = hin%gil%dim(1) 
  nv = hin%gil%dim(2)
!
! Define the problem size
  allocate (intimes(nv),altimes(nv),inant(nv),stat=ier)
  call analyze_uvtable(din,nt,nv,intimes,altimes,inant,nant,ntime) 
!
! Define the image header
  call gdf_copy_header (hin,hout,error)
  call sic_parsef (namo,hout%file,' ','.uvt')
!
! Load the sorted data
  phase = phase*acos(-1.0)/180.
  call treat_uvtable (phase,din,nt,nv,intimes,altimes,inant,nant,ntime)
!
  call gdf_write_image(hout,din,error)
  if (gildas_error(hout,'CLOSEPHASE',error)) call sysexi(fatale)
  deallocate (intimes,altimes,inant)
  deallocate (din)
  call gagout('I-CLOSEPHASE,  Successful completion')
  return
end subroutine sub_closephase
!
subroutine analyze_uvtable(din,nt,nv,intimes,altimes,inant,nant,ntime)
  integer, intent(in) :: nv
  integer, intent(in) :: nt
  integer, intent(out) :: nant            ! Number of antennas
  integer, intent(out) :: ntime           ! Number of times
  real, intent(in) :: din(nt,nv) 
  real(8), intent(out) :: intimes(nv)     ! Times for each visibility
  real(8), intent(out) :: altimes(nv)     ! Number of times
  integer, intent(out) :: inant(nv)       ! Number of antennas for each time
  !
  integer, allocatable :: it(:), work(:)
  integer nd,iv,ii
  logical ok, error
  character*60 chain
  !
  ! Scan how many dates
  nd = 1
  altimes(nd) = din(4,1)
  do iv=1,nv
     intimes(iv) = 0
     do ii=1,nd
        if (din(4,iv).eq.altimes(ii)) then
           intimes(iv) = ii
        endif
     enddo
     if (intimes(iv).eq.0) then
        nd = nd+1
        altimes(nd) = din(4,iv)
        intimes(iv) = nd
     endif
  enddo
  write(chain,*) 'Found ',nd,' dates '
  call gagout(chain(2:))
!
! Time compacted value
  do iv=1,nv
     intimes(iv) = intimes(iv)-1.d0+din(5,iv)/86400d0
  enddo
!
! Find out how many times...
  altimes = 0.0
  altimes(1) = intimes(1)
  inant(1) = din(7,iv)      ! End antenna
  ntime = 1
  do iv=2,nv
     ok = .false.
     ii = 1
     do while (.not.ok.and.ii.le.ntime)
        if (intimes(iv).eq.altimes(ii)) then
           ok = .true.
           ! Now about antennas. This assumes no antenna is ever flagged...
           if (din(7,iv).gt.inant(ii)) then
              inant(ii) = din(7,iv)
           endif
        else
           ii = ii+1
        endif
     enddo
     if (.not.ok) then
        ntime = ntime+1
        altimes(ntime) = intimes(iv)
        inant(ntime) = din(7,iv)
     endif
  enddo
!
  write(chain,*) 'I-UV,  Found ',ntime,' times '
  call gagout(chain(2:))
!
! Pending nightmare: are the times sorted ?
! Answer: of course not, let us do it now...
  allocate(it(nv), work(nv))
  do ii=1,ntime
     it(ii) = ii
  enddo
  call gr8_trie(altimes,it,ntime,error)
  call gi4_sort(inant,work,it,ntime,error)
!
! Find out how many antennas
  nd = 1
  do ii=1,ntime
    nd = max(nd,inant(ii))
  enddo
  deallocate(it,work)
  write(chain,*) 'I-UV,  Found ',nd,' antennas '
  nant = nd
  call gagout(chain(2:))
end subroutine analyze_uvtable
!
!<FF>
subroutine treat_uvtable (phase_error,din,nt,nv,intimes,altimes,inant,nant,ntime)
  use gkernel_interfaces
  integer, intent(in) :: nv
  integer, intent(in) :: nt
  integer, intent(in) :: nant
  integer, intent(in) :: ntime
  real, intent(inout) :: din(nt,nv)
  real(8), intent(in) :: intimes(nv)     ! Times for each visibility
  real(8), intent(in) :: altimes(ntime)  ! Number of times
  integer, intent(in) :: inant(ntime)    !
  real, intent(in) :: phase_error        !
  !
  integer iv,it,ia, ier
  real, allocatable :: aphase(:,:)
  real :: phase, re, im, cp, sp
  !
  allocate (aphase(nant,ntime),stat=ier)
  do it=1,ntime
    ! Get random antenna phase
    do ia = 1,inant(it)
       aphase(ia,it) = rangau(phase_error)
    enddo
  enddo
  !
  do iv=1,nv
    !
    ! Check next time match
    do it = 1,ntime
      if (intimes(iv).eq.altimes(it)) then
        phase = aphase(nint(din(6,iv)),it) - aphase(nint(din(7,iv)),it)
        exit
      endif
    enddo
    cp = cos(phase)
    sp = sin(phase)
    !
    ! Apply phase error. Channels must be added here...
    re = din(8,iv)*cp-din(9,iv)*sp 
    im = din(8,iv)*sp+din(9,iv)*cp
    din(8,iv) = re
    din(9,iv) = im
  enddo    
  !
  deallocate (aphase)
end subroutine treat_uvtable
