!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
module uv_baseline
  use gbl_message
  !
  public :: uv_baseline_comm
  private
  !
contains
  !
  subroutine uv_baseline_comm(line,error)
    use gildas_def
    use uv_filter
    !----------------------------------------------------------
    ! Command line interaction for UV_BASELINE command
    !----------------------------------------------------------
    character(len=*), intent(inout) :: line 
    logical,          intent(inout) :: error
    !
    integer                    :: degree           ! degree of the baseline to subtract
    integer, allocatable       :: channellist(:,:) ! list of ranges of channels to exclude
    integer(kind=size_length)  :: nelem            ! Number of excluded ranges
    character(len=*), parameter :: rname='UV_BASELINE'
    !
    degree = 0
    call sic_i4(line,0,1,degree,.false.,error)
    if (error) return
    if (degree.ne.0 .and. degree.ne.1) then
       call map_message(seve%e,rname,'Only degree 0 or 1 supported')
       error = .true.
       return
    endif
    !
    ! Call UV Filter to do the parsing
    call uv_filter_channel_parsing(rname,line,channellist,nelem,error)
    if (error) return
    !
    ! Now do the work
    call uv_baseline_sub(degree,channellist,nelem,error)
  end subroutine uv_baseline_comm
  !
  subroutine uv_baseline_sub(degree,channellist,nelem,error)
    use gildas_def
    use gkernel_interfaces
    use uv_buffers
    !----------------------------------------------------------
    ! Coordinates baseline fitting and subtraction
    !----------------------------------------------------------
    integer, intent(in)                   :: degree           ! Polynomial degree of baseline
    integer, allocatable,intent(in)       :: channellist(:,:) ! list of ranges of channels to exclude
    integer(kind=size_length),intent(in)  :: nelem            ! Number of excluded ranges
    logical, intent(out)                  :: error            ! Error flag
    !
    integer(kind=size_length)              :: nvisi         ! Number of visibilities
    integer(kind=index_length)             :: ivisi         ! visibility index
    integer(kind=index_length)             :: iranges       ! spectral ranges index
    integer(kind=index_length)             :: ichan         ! channel index
    integer(kind=index_length)             :: ivalid        ! valid channel index
    integer(kind=index_length),allocatable :: rindexes(:)   ! indexes for valid real channels
    integer(kind=index_length),allocatable :: iindexes(:)   ! indexes for valid imaginary channels
    integer(kind=index_length),allocatable :: cnumbers(:)   ! valid channels
    real,allocatable                       :: rdata(:)      ! valid real channels
    real,allocatable                       :: idata(:)      ! valid imaginary channels
    integer(kind=4),allocatable            :: notflagged(:)
    integer(kind=size_length)              :: nchan         ! number of channels
    integer                                :: ier
    integer                                :: nvalid        ! NUmber of valid channels
    integer                                :: fchan, lchan  ! First and last channels in a range of channels
    character(len=50)                      :: warning       ! Warning message
    integer(kind=index_length)             :: cols(3)       ! Columns for a specific channel
    integer(kind=1), parameter             :: bit=1         ! 1 in i1
    real                                   :: areal,breal   ! Fit parameters for real part
    real                                   :: aimag,bimag   ! Fit parameters for imaginary part
    character(len=*), parameter :: rname='UV_BASELINE'
    !
    nchan = huv%gil%nchan
    nvisi = huv%gil%nvisi
    allocate(notflagged(nchan),stat=ier)
    if (failed_allocate(rname,'Flagged list',ier,error))  return
    notflagged(:) = 1
    !
    ! Getting the flagged ranges
    do iranges=1, nelem
       fchan = channellist(1,iranges)
       lchan = channellist(2,iranges)
       if (lchan.lt.1.or.fchan.gt.huv%gil%nchan) then
          write(warning,1000) iranges,"-th spectral range is outside UV table"
          call map_message(seve%w,rname, trim(warning))
       else
          if (lchan.gt.nchan) lchan = nchan
          if (fchan.lt.1)     fchan = 1
          notflagged(fchan:lchan) = 0
       endif
    enddo
    nvalid = sum(notflagged)
    allocate(rindexes(nvalid),iindexes(nvalid),rdata(nvalid),idata(nvalid),cnumbers(nvalid),stat=ier)
    if (failed_allocate(rname,'Real and imaginary arrays',ier,error))  return
    ivalid=1
    do ichan=1,nchan
       if (notflagged(ichan).eq.bit) then
          call uv_spectral_getcols(ichan,cols)
          rindexes(ivalid) = cols(1)
          iindexes(ivalid) = cols(2)
          cnumbers(ivalid) = ichan
          ivalid = ivalid+1
       endif
    end do
    deallocate(notflagged)
    do ivisi=1, nvisi
       do ivalid=1,nvalid
          rdata(ivalid) = duv(rindexes(ivalid),ivisi)
          idata(ivalid) = duv(iindexes(ivalid),ivisi)
       enddo
       call uv_baseline_baseline(cnumbers,rdata,nvalid,degree,areal,breal,error)
       call uv_baseline_baseline(cnumbers,idata,nvalid,degree,aimag,bimag,error)
       do ichan=1,nchan
          call uv_spectral_getcols(ichan,cols)
          duv(cols(1),ivisi) =  duv(cols(1),ivisi)-(areal*ichan+breal)
          duv(cols(2),ivisi) =  duv(cols(2),ivisi)-(aimag*ichan+bimag)
       enddo
    enddo
1000 format(i4,a38) 
  end subroutine uv_baseline_sub
  !
  subroutine uv_baseline_baseline(xdata,ydata,npoints,degree,acoeff,bcoeff,error)
    use gkernel_interfaces
    use gildas_def
    !----------------------------------------------------------
    ! Computes baseline from input arrays
    !----------------------------------------------------------
    integer(kind=index_length), allocatable, intent(in)  :: xdata(:)
    real,                       allocatable, intent(in)  :: ydata(:)
    integer,                                 intent(in)  :: npoints
    integer,                                 intent(in)  :: degree
    real,                                    intent(out) :: acoeff
    real,                                    intent(out) :: bcoeff
    logical,                                 intent(out) :: error
    !
    real              :: sumx  ! Sum of xdata
    real              :: sumy  ! Sum of y data
    real              :: sumxy ! Sum of x*y
    real              :: sumxx ! Sum of x^2
    real              :: delta ! midway coefficient
    real, allocatable :: warr(:) ! allocatable workhorse array
    integer           :: ier   ! error flag
    character(len=*), parameter :: rname='UV_BASELINE'
    !
    if (degree.eq.0) then
       acoeff = 0.0
       bcoeff = sum(ydata)/npoints
    else if (degree.eq.1)then
       allocate(warr(npoints),stat=ier)
       if (failed_allocate(rname,'Work array',ier,error))  return
       sumx = sum(xdata)
       sumy = sum(ydata)
       warr = xdata**2
       sumxx = sum(warr)
       warr = xdata*ydata
       sumxy = sum(warr)
       delta = (npoints*sumxx-sumx**2)
       bcoeff = (sumxx*sumy-sumx*sumxy)/delta
       acoeff = (npoints*sumxy-sumx*sumy)/delta
       deallocate(warr)
    endif
  end subroutine uv_baseline_baseline
end module uv_baseline
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
