! -----------------------------------------------------------------------------
! Bernese GPS Software Version 5.3
! -----------------------------------------------------------------------------

MODULE s_prn2svn

  IMPLICIT NONE

#include "COM_CPU.inc"

CONTAINS

SUBROUTINE prn2svn(isel,prn,epo,svnnr,timint,irc,svntn)

! -----------------------------------------------------------------------------
! Purpose:    Conversion of PRN number to SVN number
!             e.g.  51 (GPS 2000-025A) -> 20, with output of satellites start and end time,
!             using satellite info file, abort if more than one PRN at epoch,
!             warning and no output if epoch is outside the satellite availability
!
! Author:     A.Gaede
!
! Created:    27-Jul-2005
!
! Changes:    11-Jan-2006 HB: USE s_timst2
!             05-Oct-2011 SL: use m_bern with ONLY
!             04-Jul-2013 RD/LP: Round epo,timint to seconds
!             15-Dec-2016 ST: Add srName
!             15-Dec-2016 ST: Call cpu_enter and cpu_exit
!             05-Apr-2017 SS: Return true SVN (svntn) if desired
!             10-Apr-2017 ST: Move IMPLICIT NONE to module scope
!             10-Apr-2017 ST: Add #include "COM_CPU.inc"
!             10-Apr-2017 ST: Add IF(srfDebug) in front of CALL cpu_
!             20-May-2020 RD: Use an index (consistent to GTSATR)
!             09-Jun-2020 RD: Exception for ADDNEQ2 and SNX2NQ0
!             09-Feb-2021 LP: Add svntn for BDS3
!             13-Dec-2023 SS: Generally enabled a thorough search
!
! Copyright:  Astronomical Institute
!             University of Bern
!             Switzerland
! -----------------------------------------------------------------------------

  USE m_bern,   ONLY: i4b, r8b, fileNameLength, lfnErr
  USE m_cpu,    ONLY: cpu_enter, cpu_exit
  USE m_time,   ONLY: t_timint
  USE m_global, ONLY: maxprn
  USE d_satfil, ONLY: t_satfil,init_satfil
  USE s_exitrc
  USE s_gtflna
  USE s_rdsatfil
  USE s_timst2

! List of arguments
! -----------------
! In:
  INTEGER(i4b)         :: isel     ! What should do in case of error
                                   ! 0: no warning/aborting
                                   ! 1: warning if SVN not at epoch or no SVN found
                                   !    abort if more than one SVN at epoch found
                                   ! 2: warning if SVN not at epoch
                                   !    abort if no SVN or more than one SVN at epoch found
                                   ! 3: warning if no SVN found
                                   !    abort if SVN not at epoch
                                   !    abort if more than one SVN at epoch found
                                   ! 4: abort if no SVN or SVN not at epoch or
                                   !    more than one SVN at epoch found
  INTEGER(i4b)         :: prn      ! Satellite number
  REAL(r8b)            :: epo      ! Epoch

! Out:
  CHARACTER(Len=4)     :: svnnr    ! System flag with SVN number
  TYPE(t_timint)       :: timint   ! Time intervals in JULIAN DATE
  INTEGER(i4b)         :: irc      ! Error return code
                                   ! 0: PRN at epoch found
                                   ! 1: PRN found but not at epoch
                                   ! 2: more than one PRN at epoch found
                                   ! 3: no PRN found
! Optional output:
  CHARACTER(Len=4), OPTIONAL :: svntn
                                   ! True SVN number (for external formats)
! -------------------------------------------------------------------------

! Local parameters
! ----------------
  CHARACTER(LEN=*), PARAMETER :: srName = 'prn2svn'

! Dummy list
! ----------
  TYPE(t_satfil), SAVE :: satfil

! Local Variables
! ---------------
  CHARACTER(LEN=fileNameLength)  :: filename
  CHARACTER(LEN=19)              :: tstrng
  INTEGER(i4b)                   :: icrx,found
  INTEGER(i4b)                   :: count    ! number of PRN found within time interval
  INTEGER(i4b), DIMENSION(maxprn), SAVE :: idxPrn
  LOGICAL,      SAVE             :: first= .TRUE.

! DEBUG: entry
! ------------
  IF (srfDebug) CALL cpu_enter(srName)

! If called for the first time, read the entire sat.info file
! -----------------------------------------------------------
  IF (first) THEN
    first = .FALSE.

! Get the satellite info file name
    CALL gtflna(1,'SATELL ',filename,irc)

! Read satellite info file
    CALL init_satfil(satfil)
    CALL rdsatfil(filename,satfil)

    idxPrn = 0
  END IF

! Init varaiables
! ---------------
  found=0
  count=0
  svnnr='    '
  timint%t=0D0

! Taking the entry in the satfil-structure from the index
! -------------------------------------------------------
  IF ( idxPrn(prn) /= 0 ) THEN
    icrx = idxPrn(prn)
    IF (satfil%satellite(icrx)%svn == prn .AND.               &
        epo > satfil%satellite(icrx)%timint%t(1)-0.5d0/86400.D0.AND.&
        epo < satfil%satellite(icrx)%timint%t(2)+0.5d0/86400.D0) THEN
      found = icrx
      count = 1
    ELSE
      idxPrn(prn) = 0
    ENDIF
  ENDIF


! Searching the satellite in the satfil-structure
! -----------------------------------------------
  IF ( idxPrn(prn) == 0 ) THEN
    DO icrx = 1,satfil%nsatellite
      IF ( satfil%satellite(icrx)%svn == prn ) THEN
        IF (found == 0) found = -icrx
        IF ((satfil%satellite(icrx)%timint%t(1)==0.D0.OR.                           &
             DNINT((epo-satfil%satellite(icrx)%timint%t(1))*86400.D0).GE.0.D0) .AND.&
            (satfil%satellite(icrx)%timint%t(2)==1.D20.OR.                          &
             DNINT((epo-satfil%satellite(icrx)%timint%t(2))*86400.D0).LE.0.D0)) THEN
            ! The first request should not sit on a right boundary
            IF ( idxPrn(prn) == 0  .AND.  &
                (epo >= satfil%satellite(icrx)%timint%t(2)-0.5d0/86400d0).AND. &
                (epo <= satfil%satellite(icrx)%timint%t(2)+0.5d0/86400d0)) THEN
              CYCLE
            ENDIF
            found = icrx
            count=count+1
        END IF
      END IF
    END DO
  ENDIF

! No SPRN found
  IF (found == 0) THEN
    irc = 3

! PRN found, but not for epoch
  ELSEIF (found < 0) THEN
    irc = 1

! PRN found for epoch
  ELSEIF (found > 0) THEN
    irc = 0
    IF ( count == 1 ) idxPrn(prn) = found
    svnnr = satfil%satellite(found)%svnnr
    timint%t(1) = satfil%satellite(found)%timint%t(1)
    timint%t(2) = satfil%satellite(found)%timint%t(2)

! Convert Bernese (internal) SVN to true (external) SVN
    IF (PRESENT(svntn)) THEN
      svntn = svnnr
      IF (svntn(1:2) == 'C4') svntn(1:2) = 'C0'
      IF (svntn(1:2) == 'C9') svntn(1:2) = 'C1'
      IF (svntn(1:2) == 'C6') svntn(1:2) = 'C2'
      IF (svntn(1:2) == 'J5') svntn(1:2) = 'J0'
    ENDIF
  ENDIF

! more than one SPRN found for epoch
  IF (count > 1) THEN
    irc = 2
  ENDIF


!ERROR handling
!=================================================
  If (irc .NE. 0 .AND. isel .NE. 0) THEN
    CALL timst2(1,1,epo,tstrng)
  END IF

  IF (irc == 1) THEN
    IF (isel == 1 .OR. isel == 2)  THEN
      WRITE(lfnerr, &
        "(/,' ### SR PRN2SVN: PRN not found at epoch',                  &
        & /,'                 PRN number: ',I4,                         &
        & /,'                 Epoch     : ',A,/)") prn, tstrng
    ELSE IF (isel == 3) THEN
      WRITE(lfnerr, &
        "(/,' *** SR PRN2SVN: PRN not found at epoch',                  &
        & /,'                 PRN number: ',I4,                         &
        & /,'                 Epoch     : ',A,/)") prn, tstrng
      CALL exitrc(2)
    END IF
  ELSEIF (irc == 3) THEN
    IF (isel == 1 .OR. isel == 3)  THEN
      WRITE(lfnerr, &
        "(/,' ### SR PRN2SVN: PRN not found in satellite info file',    &
        & /,'                 PRN number: ',I4,                         &
        & /,'                 Epoch     : ',A,/)") prn, tstrng
    ELSE IF (isel == 2) THEN
      WRITE(lfnerr, &
        "(/,' *** SR PRN2SVN: PRN not found in satellite info file',    &
        & /,'                 PRN number: ',I4,                         &
        & /,'                 Epoch     : ',A,/)") prn, tstrng
      CALL exitrc(2)
    END IF
  ELSE IF (irc == 2) THEN
    IF (isel .NE. 0) THEN
      WRITE(lfnerr, &
        "(/,' *** SR PRN2SVN:',I2,' PRN numbers found at epoch',        &
        & /,'                 PRN number: ',I4,                         &
        & /,'                 Epoch     : ',A,/)") count, prn, tstrng
      CALL exitrc(2)
    END IF
  ENDIF

! DEBUG: exit
! ------------
  IF (srfDebug) CALL cpu_exit(srName)

  RETURN
END SUBROUTINE prn2svn

END MODULE s_prn2svn
