!
! We apply an unambiguous convention to convert Frequency
! to Velocity: the "radio" definition, under which the two scales are
! linear and simply proportional.
!
! Recall the Radio velocity convention:
!     F(v) = F_0 (1-v/c) = F_0 Doppler
! so   v/c = (F_0-F)/F_0
!     dV = -dF/F_0*c
!
! What matters is the frequency scale of the frequency axis, which
! is unambiguously translated to a velocity axis when and only when
! we have a defined rest frequency.
!
! In GILDAS/CLIC, that frequency scale is defined such that the source velocity
! is at the reference channel, and that, at the source velocity
! we are at the rest frequency which has been defined.
! Our convention is to have the frequencies in the frame
! of the source, not in the LSR frame like UVFITS and CASA.
! Both coincides if and only if Vsys = 0.
!
! A "MODIFY FREQUENCY" may change the reference channel, but the
! actual frequency of any channel will not change. The channel
! width in frequency will not change. Emission will appear at a
! different apparent velocity with such a new reference, and the
! velocity resolution will change according to the new frequency reference.
!
! On the contrary, a "MODIFY VELOCITY" will change the frame, resulting
! in a different frequency scale in the source frame.
!
! On "old" tables, we ALSO have the effective frequency given at the
! reference channel, %gil%val(1)
!   and the rest frequency
! and the LSR velocity also corresponds to the reference channel.
!
! Strictly speaking, we can compute a "Doppler" factor from these
! numbers (the frequency at the reference channel and the rest frequency)
! and scale the variable "c" to get the u and v in proper frame,
! since they represent delays in the specified frame.
!
! Velocity resolution and Frequency resolution should be rescaled
! accordingly ...
!
! Now, outside, the reference channel is kind of arbitrary...
!
! The intention is now to produce a frequency axis that is unambiguously
! defined in the current (source) frame. So for "old" tables, that frequency axis
! becomes f(i) = (i-ref)*inc + restfreq
! where inc has to be corrected for Doppler shift...
!
!    The observed frequency (to which u,v are referred) is
!        F_O(j) == (1 + Doppler - V/C) (F + Df (j-I))
!    with the same (u,v)
!
!    We thus link the old and new representations by
!     UV_FREQ = REST_FREQ * (1 + DOPPLER - VELOCITY/C)
!
! fits%gil%doppler = fits%gil%val(1) / fits%gil%restfreq &
!     & + fits%gil%voff / clight -1.d0
!
! For the spectral resolution, the rule is a little ambiguous
! as resampling in the LSR frame should have been done when
! creating the UV table, so it can be
!   EITHER  (if resampling have been done)
! df_0 = fits%gil%fres
!   OR      (if resampling has not been done)
! df_0 = fits%gil%inc(1) / (1+fits%gil%doppler-fits%gil%voff/clight)
! dv_0 = -df_0 / fits%gil%restfreq*clight
!
! The old version is identified by
!   code_version_uvt_freq
! The new one by
!   code_version_uvt_dopp
!
! For CASA, in TOUVT, the problem is that u,v are defined in the
! Observatory frame, while Frequencies are in the LSR frame, and the
! Doppler factor is not known ...
!
! To recompute it, one need something like compute_doppler in Class
! which calls do_object based on Time and Observatory knowledge
!
! I have created such a routine in ASTRO in uv_doppler.f90
! It computes (and optionally applies) the Doppler effect for each
! visibility. However, one needs to supply the Observatory...
!   (for astro_observatory)
! Once the correction has been made, the u,v refer to the LSR frame,
! and the code_version_uvt is changed to code_version_uvt_syst.
!
!
function gdf_uv_frequency(huv, dchan)
  use image_def
  !-----------------------------------------------------------------------
  ! @ public
  !
  ! GIO Library
  !   Get observing frequency at given channel
  !-----------------------------------------------------------------------
  type(gildas), intent(in) :: huv   ! UV Header
  real(8), intent(in), optional :: dchan      ! Channel number (possibly fractional)
  real(8) :: gdf_uv_frequency       ! Intent(out)
  !
  real(8) :: freq, chan
  integer :: iaxis, ichan
  real(8), parameter :: clight_kms = 299792.458d0   ! [km/s] Light velocity
  !
  if (huv%gil%type_gdf.eq.code_gdf_uvt) then
    iaxis = 1
  else
    iaxis = 2
  endif
  !
  if (present(dchan)) then
    chan = dchan
  else
    chan = (huv%gil%nchan+1)*0.5d0
  endif
  !
  !! Pre-Doppler, was bugged (no reference channel) ?
  !!  freq = huv%gil%val(iaxis)+huv%gil%fres*(huv%gil%val(iaxis)/huv%gil%freq)*chan
  !! Print *,'Frequency pre-doppler ', freq, ' Ichan ',ichan
  if (huv%gil%nfreq.eq.0) then
    ! Normal, regularly sampled Frequency axis
    freq = huv%gil%freq + huv%gil%fres*(chan-huv%gil%ref(iaxis))
  else
    ! Random sampling, use nearest channel
    ichan = nint(chan)
    freq = huv%gil%freqs(ichan)
  endif
  freq = freq * (1.d0 + huv%gil%dopp - huv%gil%voff/clight_kms)
  gdf_uv_frequency = freq
end function gdf_uv_frequency
!
subroutine gdf_modify(h,velocity,frequency,unit,error)
  use image_def
  use gbl_message
  use gio_dependencies_interfaces
  use gio_interfaces, only : gio_message
  !---------------------------------------------------------------------
  ! @ public
  !   Modify the reference frequency and reference velocity of an input
  ! GDF header, and optionaly the axis unit (FREQUENCY or VELOCITY)
  !---------------------------------------------------------------------
  type(gildas),     intent(inout), target :: h          ! Header to be shifted
  real(kind=4),     intent(in)            :: velocity   ! New velocity
  real(kind=8),     intent(in)            :: frequency  ! New frequency
  character(len=*), intent(in), optional  :: unit       ! New axis unit
  logical,          intent(out)           :: error      ! Error flag
  ! Local
  real(8), parameter :: clight_kms=299792.458d0   
  !
  character(len=*), parameter :: rname='GIO_FRAME'
  integer(kind=4) :: faxi
  real(kind=8) :: iref,dopple,fshift
  real(kind=8), pointer :: ref(:),val(:),inc(:)
  character(len=12) :: newunit
  real(kind=8) :: freqori, beamfac
  !
  freqori = h%gil%freq
  !
  ! Can not assume the h%gil%ref(:) and other pointers are associated.
  ! Must use h%gil%convert. Use custom pointers for better readability
  ! of the code
  ref => h%gil%convert(1,:)
  val => h%gil%convert(2,:)
  inc => h%gil%convert(3,:)
  !
  if (h%gil%spec_words.le.0) then
    call gio_message(seve%e,rname,'Gildas Header has no spectroscopic section')
    error = .true.
    return
  endif
  if (h%gil%faxi.eq.0) then
    call gio_message(seve%e,rname,"Gildas Header has no Frequency/Velocity axis")
    error = .true.
    return
  endif
  faxi = h%gil%faxi
  !
  if (present(unit)) then
    if (h%char%code(faxi).ne.'FREQUENCY' .and. h%char%code(faxi).ne.'VELOCITY')  then
      call gio_message(seve%e,rname,'Can not change '//trim(h%char%code(faxi))//' spectroscopic axis to '//unit)
      error = .true.
    endif
    if (unit.ne.'FREQUENCY' .and. unit.ne.'VELOCITY')  then
      call gio_message(seve%e,rname,'Spectroscopic axis unit can only be changed to FREQUENCY or VELOCITY')
      error = .true.
    endif
    if (error)  return
    newunit = unit
  else
    newunit = h%char%code(faxi)
  endif
  !
  ! Find the channel where Current Rest Frequency and Velocity happen
  select case (h%char%code(faxi))
  case ('VELOCITY')
    iref = ref(faxi) + (h%gil%voff-val(faxi))/h%gil%vres
  case ('FREQUENCY')
    iref = ref(faxi) + (h%gil%freq-val(faxi))/h%gil%fres
  case ('UV-DATA','UV-RAW')  ! UV-RAW is a patch for old UV Tables...
    if (h%gil%version_uv.eq.code_version_uvt_freq) then
      !
      ! In this version, the Rest Frequency always matches the
      ! Observing frequency at the reference channel -
      iref = ref(faxi)
      dopple = val(faxi)/h%gil%freq
      !! Print *,'UVT_FREQ case ',h%gil%version_uv
    else
      ! Here also, the Rest Frequency must correspond to the
      ! reference channel, by convention.
      iref = ref(faxi)
      !
      ! If not, it means something wrong, as all our code assumes so.
      !
      if (val(faxi).ne.h%gil%freq) then
        call gio_message(seve%e,rname, &
        & "Rest frequency is not matching Frequency at reference channel")
        !
        ! Check if by any chance (i.e. any previous bug...) this mismatch 
        ! is due to a confusion between the LSRK and the Source frame
        !
        fshift = h%gil%freq*(1.d0-h%gil%voff/clight_kms)
        if (abs(fshift-val(faxi)).lt.1D-3) then
          call gio_message(seve%i,rname, &
          & ' probably due to confusion between LSRK and Source frame')
          call gio_message(seve%i,rname, &
          & ' Set (headername)%convert[2,1] = (header)%RESTFRE to correct the problem')
        endif
        error = .true. 
        return
      endif
      dopple = 1.d0
    endif
  case default
    call gio_message(seve%e,rname,"Frequency/Velocity axis is neither "//  &
      &   "FREQUENCY nor VELOCITY but "//h%char%code(faxi))
    error = .true.
    return
  end select
  !
  call modify_frame_velocity(velocity,iref,h%gil%freq,h%gil%fres,h%gil%voff,h%gil%vres,error)
  if (error)  return
  call modify_rest_frequency(frequency,iref,h%gil%freq,h%gil%fima,h%gil%fres,h%gil%vres,error)
  if (error)  return
  !
  call gdf_modify_resolution(freqori,h%gil%freq,h%gil%majo,h%gil%mino,error)
  if(error) return
  !
  h%char%code(faxi) = newunit
  select case (h%char%code(faxi))
  case ('VELOCITY')
    ref(faxi) = iref
    val(faxi) = h%gil%voff
    inc(faxi) = h%gil%vres
  case ('FREQUENCY')
    ref(faxi) = iref
    val(faxi) = h%gil%freq
    inc(faxi) = h%gil%fres
  case ('UV-DATA','UV-RAW')  ! UV-RAW is a patch for old UV Tables...
    if (h%gil%version_uv.eq.code_version_uvt_freq) then
      ref(faxi) = iref
      val(faxi) = h%gil%freq*dopple
      inc(faxi) = h%gil%fres
    else
      ref(faxi) = iref
      val(faxi) = h%gil%freq
      inc(faxi) = h%gil%fres
    endif
  end select
  !
end subroutine gdf_modify
!
subroutine gdf_uv_doppler(huv,version_uv)
  use image_def
  use gbl_message
  use gio_interfaces, only : gio_message
  use gio_uv
  !------------------------------------------------------------------
  ! @ public
  !   GIO
  !     Convert a UV table Frequency information to the appropriate
  !     shape. The Frequency information model of the data is
  !     in huv%gil%version_uv, and it is converted towards model
  !     described by version_uv, which can be
  !   code_version_uvt_freq
  !     Observing frequency is in the first axis - This is the
  !     historical behaviour.
  !   code_version_uvt_dopp
  !     Observing frequency is derived from a mean Doppler correction
  !     and the rest frequency in the Spectroscopy section.
  !   code_version_uvt_syst
  !     Observing frequency is derived from a time-dependent Doppler
  !     correction stored in the code_uvt_topo column,
  !     and the rest frequency in the Spectroscopy section
  !     It falls back to the code_version_uvt_dopp behaviour if
  !     no such column is found.
  !------------------------------------------------------------------
  type(gildas), intent(inout) :: huv
  integer, intent(in) :: version_uv
  !
  character(len=*), parameter :: rname='GDF_UV_DOPPLER'
  integer :: uaxi
  real(8), parameter :: clight_kms=299792.458d0
  character(len=80) :: mess
  !
  ! Test if something needs to be done
  if (huv%gil%version_uv.eq.version_uv) return
  !
  write(mess,'(A,A,F3.1,A,F3.1,A,F3.1,A,F3.1)')  'Header version:' &
    & ,' Image V',0.1*huv%gil%version_uv &
    & ,' System V',0.1*code_version_uvt_default  &
    & ,' Current V',0.1*code_version_uvt_current &
    & ,' Goal V',0.1*version_uv
  call gio_message(seve%d,rname,mess)
  !
  ! This was a debatable decision:
  ! If Doppler tracking was done, do not change anything
  ! if (huv%gil%version_uv .ge. code_version_uvt_syst) return
  !
  ! Programming note:
  ! I use here %gil%convert(2,) instead of %gil%val() to ensure
  ! that this part of the GIO library can be called prior to
  ! pointer initialization.
  !
  if (huv%gil%type_gdf.eq.code_gdf_tuv) then
    uaxi = 2
  else
    uaxi = 1
  endif
  !
  select case (huv%gil%version_uv)
  case (code_version_uvt_freq)
    ! Destination can be code_version_uvt_dopp or code_version_uvt_syst
    !
    ! Initial version has no Doppler information, compute it
    huv%gil%dopp = huv%gil%convert(2,uaxi)/huv%gil%freq - 1.d0 &
    &   + huv%gil%voff/clight_kms
    huv%gil%convert(2,uaxi) = huv%gil%freq
    huv%gil%vres = -huv%gil%fres / huv%gil%freq * clight_kms
    !
  case (code_version_uvt_dopp)
    ! Destination can be code_version_uvt_syst or code_version_uvt_freq
    !
    if (version_uv.eq.code_version_uvt_freq) then
      !
      ! Initial version has no Frequency information, compute it
      !
      ! First, set the reference channel so that it matches
      ! the Rest Frequency
      huv%gil%convert(1,uaxi) = huv%gil%convert(1,uaxi) + &
        & (huv%gil%freq-huv%gil%convert(2,uaxi))/huv%gil%fres
      !
      ! Compute apparent observing frequency from Current Doppler
      ! and Velocity
      huv%gil%convert(2,uaxi) = huv%gil%freq * &
        & (1.d0 + huv%gil%dopp - huv%gil%voff/clight_kms   )
    endif
  case (code_version_uvt_syst)
    ! Initial version may have a Doppler tracking column
    !
    ! Do nothing if there is a Doppler column...
    if (huv%gil%column_pointer(code_uvt_topo).ne.0) then
      call gio_message(seve%e,rname, &
      & 'Table has Doppler tracking column, no change of UV version')
      return
    endif
    !
    if (version_uv.eq.code_version_uvt_freq) then
      ! First, set the reference channel so that it matches
      ! the Rest Frequency
      huv%gil%convert(1,uaxi) = huv%gil%convert(1,uaxi) + &
        & (huv%gil%freq-huv%gil%convert(2,uaxi))/huv%gil%fres
      !
      ! Compute apparent observing frequency from Current Doppler
      ! and Velocity
      huv%gil%convert(2,uaxi) = huv%gil%freq * &
        & (1.d0 + huv%gil%dopp - huv%gil%voff/clight_kms   )
    endif
  end select
  !
  huv%gil%version_uv = version_uv
end subroutine gdf_uv_doppler
!
subroutine gdf_modify_resolution(old_freq,new_freq,majo,mino,error)
  !---------------------------------------------------------------------
  ! @ private
  ! Modify the resolution according to old and new frequencies
  !---------------------------------------------------------------------
  real(kind=8), intent(in)    :: old_freq  !
  real(kind=8), intent(in)    :: new_freq  !
  real(kind=4), intent(inout) :: majo      !
  real(kind=4), intent(inout) :: mino      !
  logical,      intent(inout) :: error     !
  ! Local
  real(kind=8) :: factor
  !
  if (old_freq.eq.new_freq)  return
  !
  factor = old_freq/new_freq
  majo = majo*factor
  mino = mino*factor
  !
end subroutine gdf_modify_resolution
