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

MODULE s_READBIASNX

  IMPLICIT NONE

#include "COM_CPU.inc"

CONTAINS

SUBROUTINE readbiasnx(biafil, dcbfil, window)

! --------------------------------------------------------------------------
! Purpose:    Read the BIA-SINEX file
!
! Author:     A. Villiger
!
! Created:    22-Jun-2021
!
! Changes:    22-Jun-2021 AV: Obtain svn number from prn (satinfo file)
!             29-Jul-2021 AV: Bugfix: add nextline after rewind of lfn001
!             12-Oct-2021 RD: Correct format of error/warning messages
!             27-Apr-2022 AV: Remove debug print statement
!             12-May-2023 RD: Consider (optional) time window
!             26-Jan-2024 SS: Keep imported SVN numbers unchanged;
!                             check them for internal consistency
!
! Copyright:  Astronomical Institute
!             University of Bern
!             Switzerland
! --------------------------------------------------------------------------

  USE m_bern,    ONLY: i4b, r8b, lfn001, lfnErr, longLineLength, fileNameLength
  USE m_cpu,     ONLY: cpu_enter, cpu_exit
  USE m_time,    ONLY: t_timint, OPERATOR(.isIn.)
  USE m_global,  ONLY: g_svnSys, maxSvnSys
  USE p_bia2osb, ONLY: t_bia2osb_opt
  USE d_dcbfil,  ONLY: t_dcbFil, init_dcbFil

  USE f_nextline
  USE s_alcerr
  USE s_exitrc
  USE s_opnerr
  USE s_opnfil
  USE s_prn2svn
  USE s_sindat
  USE s_stripdir
  USE f_prtflnam

! List of arguments
! -----------------
! Input:
  CHARACTER(LEN=fileNameLength), INTENT(IN)  :: biafil ! Name of the bias file

! Output:
  TYPE(t_dcbFil),                INTENT(OUT) :: dcbFil ! Code bias values

! Input:
  TYPE(t_timint), OPTIONAL,      INTENT(IN)  :: window ! Time window for reading the biases


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

! Local variables
! ---------------
  INTEGER(i4b)                  :: iRec
  INTEGER(i4b)                  :: iSys
  INTEGER(i4b)                  :: iPrn
  INTEGER(i4b)                  :: ios, iac
  INTEGER(i4b)                  :: nCount
  INTEGER(i4b)                  :: nEntries

  REAL(r8b)                     :: dcbVal
  REAL(r8b)                     :: dcbRms
  REAL(r8b)                     :: dEpo

  CHARACTER(LEN=14)             :: startTime, endTime
  CHARACTER(LEN=1)              :: techSNX
  CHARACTER(LEN=longLineLength) :: line
  CHARACTER(LEN=4)              :: biasType
  CHARACTER(LEN=4)              :: sSvn, svnBN, svnTN
  CHARACTER(LEN=3)              :: sPrn
  CHARACTER(LEN=9)              :: staname
  CHARACTER(LEN=4)              :: sObst1, sObst2, sUnit
  CHARACTER(LEN=14)             :: sTimStr1, sTimStr2
  CHARACTER(LEN=20)             :: sBiasMode
  CHARACTER(LEN=fileNameLength) :: sHlpStr

  TYPE(t_timint)                :: timint

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

  ! Open the input file
  ! -------------------
  CALL opnfil(lfn001,biafil,'OLD','FORMATTED','READONLY',' ',ios)
  CALL opnerr(lfnerr,lfn001,ios,biafil,srName)

  ! Read the first line, allocate memory
  ! ------------------------------------
  line = nextline(lfn001,0)

  IF(line(1:10) /= "%=BIA 1.00") THEN
    WRITE(lfnErr,'(/,A,A,A,/,A,A,/,A,A,/)') &
        " *** SR ", srName, ": The give BIAS-SINEX file is not in the BIAS-SINEX V1.00 format",&
        "                    File name : ", prtFlNam(biafil,64),   &
        "                    First line: ", line
          CALL exitrc(2)
  ENDIF

  nCount = 0
! Count number of entries
  Count_Loop: DO
    line = nextline(lfn001,0)
    IF (line      == '')  EXIT Count_Loop
    IF(line == "+BIAS/DESCRIPTION") THEN
      DO
        line = nextline(lfn001,0)
        IF(line(1:1) == '-') CYCLE Count_Loop
        IF(line(1:10) == " BIAS_MODE") THEN
          sBiasMode = line(42:61)
          IF(sBiasMode /= "ABSOLUTE") THEN
            WRITE(lfnErr,'(/,A,A,A,/,A,A,A,/,A,A,/)') &
              " *** SR ", srName, ": Only absolute biases supported:", &
              "                    ",TRIM(sBiasMode)," biases found in BIAS-SINEX file.", &
              "                    BIAS-SINEX:  ", prtFlNam(biaFil,64)
            CALL exitrc(2)
          ENDIF
        ENDIF
      ENDDO
    ELSEIF (line == '+BIAS/SOLUTION') THEN
      DO
        line = nextline(lfn001,0)
        IF (line(1:1) == '-') EXIT Count_Loop
        nCount = nCount + 1
      ENDDO
    ENDIF
  ENDDO Count_Loop

  ! Reset file reader
  REWIND lfn001

  ! Read first line
  line = nextline(lfn001,0)
  READ(line,'(34x,A14,1x,A14,1x,A1,1x,i8)') &
       startTime, endTime, techSNX, nEntries

  IF(nCount /= nEntries) THEN
    WRITE(lfnErr,'(/,A,A,A,/,A,A,/,A,I8,/,A,I8,/)') &
        " ### SR ", srName, ": Number of entries in BIAS-SINEX header does not match number of entries:", &
        "                    BIAS-SINEX:                   ", prtFlNam(biaFil,32),   &
        "                    Indicated number of entries:  ", nEntries, &
        "                    Effective number of entries:  ", nCount
  ENDIF

  ! Create DCB array
  ! -----------------
  CALL init_dcbFil(dcbFil)
  dcbFil%nVal = nCount
  ALLOCATE(dcbFil%dcbLst(dcbFil%nVal),stat=iac)
  CALL alcErr(iac,'dcbFil%dcbLst',(/dcbFil%nVal/), srName)
  DO iRec=1,dcbFil%nVal
    dcbFil%dcbLst(irec)%stanam=""
    dcbFil%dcbLst(irec)%flg=""
    dcbFil%dcbLst(irec)%rem=""
    dcbFil%dcbLst(irec)%sys=""
    dcbFil%dcbLst(irec)%obstyp="   "
    dcbFil%dcbLst(irec)%typ=0
    dcbFil%dcbLst(irec)%svn=0
    dcbFil%dcbLst(irec)%refsys=0
    dcbFil%dcbLst(irec)%dcbVal=0D0
    dcbFil%dcbLst(irec)%dcbRms=0D0
  ENDDO


  ! Main Loop
  ! ---------
  iRec = 0
  Main_Loop: DO
    line = nextline(lfn001,0)
    IF (line      == '')  EXIT  Main_Loop
    IF (line      == '%ENDSNX') EXIT  Main_Loop
    IF (line(1:1) /= '+'  ) CYCLE Main_Loop
    IF (line == '+BIAS/SOLUTION') THEN
      DO
        line = nextline(lfn001,0)
        IF (line(1:1) == '-') CYCLE Main_Loop
        iRec = iRec + 1
        IF(iRec > nCount) THEN
          WRITE(lfnErr,'(/,A,A,A,/,A,I8,/,A,A,/)') &
            " *** SR ", srName, ": Number of entries in BIAS-SINEX exceeds indicated number of estimates", &
            "                    Number of expected estimates: ", nCount, &
            "                    BIAS-SINEX:                   ", prtFlNam(biaFil,32)
          CALL exitrc(2)
        ENDIF

       READ(line,'(1X,A4,1X,A4,1X,A3,1X,A9,2(1X,A4),2(1X,A14), &
                  & 1X,A4,2(1X,F21.4,1X,F11.4))')                  &
          biasType, sSvn, sPrn, staName, sObst1, sObst2, sTimStr1, &
          sTimStr2,sUnit,dcbVal,dcbRms

        IF(biasType /= "OSB ") THEN
          WRITE(lfnErr,'(/,A,A,A,/,A,A,A,/,A,A,/)') &
            " *** SR ", srName, ": Only observable-specifc biases supported:", &
            "                    ",TRIM(biasType), " not supported." , &
            "                    BIAS-SINEX: ", prtFlNam(biaFil,32)
          CALL exitrc(2)
        ENDIF

        CALL sindat(101, dcbFil%dcbLst(iRec)%tim%t(1), sTimStr1)
        CALL sindat(102, dcbFil%dcbLst(iRec)%tim%t(2), sTimStr2)
        READ(sPrn(2:3),'(I2)') dcbFil%dcbLst(iRec)%prn

! Time window handling
! --------------------
        IF ( PRESENT(window) ) THEN

          ! Record outside from the time window
          IF (window%t(1) > dcbFil%dcbLst(iRec)%tim%t(2) .OR. &
              window%t(2) < dcbFil%dcbLst(iRec)%tim%t(1)) THEN
            iRec = iRec - 1
            CYCLE
          ENDIF

          ! Adjust the left boundary to the user window
          IF (window%t(1) /= 0d0 .AND. &
              window%t(1) > dcbFil%dcbLst(iRec)%tim%t(1)) THEN
            dcbFil%dcbLst(iRec)%tim%t(1) = window%t(1)
          ENDIF

          ! Adjust the left boundary to the user window
          IF (window%t(2) /= 1d20 .AND. &
              window%t(2) < dcbFil%dcbLst(iRec)%tim%t(2)) THEN
            dcbFil%dcbLst(iRec)%tim%t(2) = window%t(2)
          ENDIF
        ENDIF ! end of time window handling

        IF(dcbFil%dcbLst(iRec)%prn > 0) THEN
          dEpo = (dcbFil%dcbLst(iRec)%tim%t(1) + dcbFil%dcbLst(iRec)%tim%t(2)) / 2d0
          iPrn = dcbFil%dcbLst(iRec)%prn
          DO iSys = 0, maxSvnSys - 1
            IF(g_svnSys(iSys) == sPrn(1:1)) THEN
              iPrn = iPrn + iSys * 100
              EXIT
            ENDIF
          ENDDO
          CALL PRN2SVN(1,iPrn,dEpo,svnBN,timint,iac,svnTN=svnTN)
          IF (sSvn /= svnTN .AND. iac == 0) THEN
            WRITE(lfnErr,'(/,A,A,A,A4," (",A4,") ",A3,1X,A3,F12.5)') &
              " ### SR ",srName,": SVN inconsistency found for: ",   &
              sSvn,svnTN,sPrn,sObsT1,dEpo
          ENDIF
          READ(sSvn(2:4),'(I3)') dcbFil%dcbLst(iRec)%svn
        ENDIF
        dcbFil%dcbLst(iRec)%sys       = sPrn(1:1)
        dcbFil%dcbLst(iRec)%staNam    = staName
        dcbFil%dcbLst(irec)%obstyp(1) = sObst1(1:3)
        dcbFil%dcbLst(irec)%obstyp(2) = sObst2(1:3)
        dcbFil%dcbLst(iRec)%dcbVal    = dcbVal
        dcbFil%dcbLst(iRec)%dcbRms    = dcbRms
     ENDDO
    ELSEIF(line == "+BIAS/DESCRIPTION") THEN
      DO
        line = nextline(lfn001,0)
        IF(line(1:1) == '-') CYCLE Main_Loop
        IF(line(1:21) == " DETERMINATION_METHOD") THEN
          dcbFil%refDat = line(42:61)
        ELSEIF(line(1:10) == " BIAS_MODE") THEN
          sBiasMode = line(42:61)
          IF(sBiasMode /= "ABSOLUTE") THEN
            WRITE(lfnErr,'(/,A,A,A,/,A,A,A,/,A,A,/)') &
              " *** SR ", srName, ": Only absolute biases supported:", &
              "                    ",sBiasMode," biases not supported.", &
              "                    BIAS-SINEX: ", prtFlNam(biaFil,32)
            CALL exitrc(2)
          ENDIF
        ELSEIF(line(1:12) == " TIME_SYSTEM") THEN
          dcbFil%refSys = line(42:61)
        ENDIF
      ENDDO
    ENDIF
  ENDDO Main_Loop

  ! Indicate file name
  sHlpStr = biaFil
  CALL stripdir(sHlpStr)
  dcbFil%source = sHlpStr

  CLOSE(lfn001)


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

  RETURN
END SUBROUTINE readbiasnx

END MODULE s_READBIASNX
