C$$$  SUBPROGRAM DOCUMENTATION BLOCK
C                .      .    .                                       .
C SUBPROGRAM:    MHYDROFLTR  FILTER HYDRO OBS BASED ON USER CRITERIA
C   PRGMMR: M. BARTH          ORG: FSL        DATE: 01-07-24
C
C ABSTRACT: FILTER OUT HYDRO STATION RECORDS BASED ON USER CRITERIA
C
C PROGRAM HISTORY LOG:
C   01-07-24  M. BARTH      ORIGINAL VERSION
C   03-09-25  M. BARTH      ADDED LOGIC TO AVOID TOSSING OBS THAT ARE
C                           IN THE HIGH MINUTE BUT HAVE SOME SECONDS
C
C USAGE:    CALL MHYDROFLTR(ATIME, MINBCK, MINFWD, RECWIN, SOURCE,
C                           SPVAL, PROVDR_ENBL, NUMSTA, OBTIME, 
C                           STANAMES, WMOID, PROVDR, SUBSRC, LATS, LONS,
C                           ELEVATION, FNUM, RNUM, NUMSTA_NEW)
C
C   INPUT ARGUMENT LIST:
C     ATIME    - CHARACTER*9   YYJJJHHMM NOMINAL OB TIME
C     MINBCK   - INTEGER       NUMBER OF MINUTES RELATIVE TO NOMINAL
C                              TIME AT WHICH TO START TIME WINDOW
C     MINFWD   - INTEGER       NUMBER OF MINUTES RELATIVE TO NOMINAL
C                              TIME AT WHICH TO END TIME WINDOW
C     RECWIN   - INTEGER       0 - RETURN ALL RECORDS WITHIN *FILE*
C                              1 - RETURN ONE RECORD PER FIXED STATION,
C                                  CLOSEST IN TIME TO NOMINAL TIME
C                              2 - RETURN ONE RECORD PER FIXED STATION,
C                                  CLOSEST IN TIME TO START OF WINDOW
C                              3 - RETURN ONE RECORD PER FIXED STATION,
C                                  CLOSEST IN TIME TO END OF WINDOW
C                              4 - RETURN ALL RECORDS WITHIN *WINDOW*
C     SOURCE   - INTEGER       DATASET CODE NUMBER
C     SPVAL    - REAL          MISSING DATA FLAG
C     PROVDR_ENBL - LOGICAL    ARRAY OF PROVIDER-ENABLE FLAGS
C     NUMSTA   - INTEGER       NO. OF RECORDS IN OB ARRAYS
C
C   INPUT/OUTPUT ARGUMENT LIST:
C     OBTIME   - INTEGER OBTIME(NUMSTA)
C                INPUT I4TIMES FOR EACH OB "RECORD"
C     STANAMES - CHARACTER*(*) ARRAY STANAMES(NUMSTA)
C                STATION NAMES: ONLY THE FIRST 10 CHARACTERS ARE USED.
C     WMOID    - INTEGER ARRAY WMOID(NUMSTA) PART OF STA RECORD
C     PROVDR   - CHARACTER*(*) ARRAY PROVDR(NUMSTA) PART OF STA RECORD
C                10 CHARS USED IN LHYDRO FILTER
C     SUBSRC   - INTEGER ARRAY SUBSRC(NUMSTA) PART OF STA RECORD
C                USED IN PROVIDER-FILTERING
C     LATS     - REAL ARRAY LATS(NUMSTA)     PART OF STA RECORD
C     LONS     - REAL ARRAY LONS(NUMSTA)     PART OF STA RECORD
C     ELEVATION- REAL ARRAY ELEVATION(NUMSTA)PART OF STA RECORD
C     FNUM     - INTEGER ARRAY FNUM(NUMSTA)  PART OF STA RECORD
C     RNUM     - INTEGER ARRAY RNUM(NUMSTA)  PART OF STA RECORD
C
C   OUTPUT ARGUMENT LIST:
C     NUMSTA_NEW - INTEGER
C                NO. OF STA RECORDS REMAINING AFTER BEING CULLED
C
C SUBPROGRAMS CALLED:
C   M_MKI4TM
C
C REMARKS:
C
C   NOTE THAT TO KEEP THINGS SIMPLE THE TIME WINDOW IS INCLUSIVE.
C   THUS, GIVEN MINBCK = -15, MINFWD = 4 AND A NOMINAL TIME AT THE
C   TOP OF THE HOUR THIS ROUTINE WILL ACCEPT OBS TIME-STAMPED
C   BETWEEN MINUTE 45 OF THE PREVIOUS HOUR AND MINUTE 4 OF THE
C   CURRENT HOUR.  TO RUN 3 CYCLES IN AN HOUR WITHOUT OVERLAPPING
C   OBS, HERE'S AN EXAMPLE:
C
C   ATIME                                             971751200
C   1.  RUN TIME, MINBCK, MINFWD           1220          -15, 4
C   2.  RUN TIME, MINBCK, MINFWD           1240           5, 24
C   3.  RUN TIME, MINBCK, MINFWD           1300          25, 44
C
C   STANAMES, OBTIME, SUBSRC, AND PROVDR, ARE THE ARRAYS THAT ARE 
C   EXAMINED (THE LAST 2 ONLY IF FILTERING).  TO USE THIS ROUTINE
C   FOR OBS WITHOUT STATION NAMES YOU HAVE TO FILL IN STATION NAMES
C   UNIQUE THROUGH THE FIRST 10 CHARS.  
C
C   IN ADDITION TO THE ABOVE PARAGRAPH, STATIONS WITHOUT LAT, LON OR
C   ELEV WILL BE FILTERED.  IF DOMAIN FILTERING HAS BEEN SELECTED,
C   THAT WILL ALSO BE PERFORMED.
C
C ATTRIBUTES:
C   LANGUAGE: FORTRAN 77 + EXTENSIONS
C   MACHINE: UNIX
C
C$$$




      SUBROUTINE MHYDROFLTR(ATIME, MINBCK, MINFWD, RECWIN, SOURCE,
     1                      SPVAL, PROVDR_ENBL, NUMSTA, OBTIME, 
     2                      STANAMES, WMOID, PROVDR, SUBSRC, LATS, LONS,
     3                      ELEVATION, FNUM, RNUM, NUMSTA_NEW)




C     ------------------------------------------------------------------
C     CONSTANTS
C     ------------------------------------------------------------------
      INCLUDE 'IMPLICIT'
      INCLUDE 'MADISCON'

C     ------------------------------------------------------------------
C     ARGUMENTS
C     ------------------------------------------------------------------
      CHARACTER*9 ATIME
      INTEGER MINBCK
      INTEGER MINFWD
      INTEGER RECWIN
      INTEGER SOURCE
      REAL SPVAL
      LOGICAL PROVDR_ENBL(*)
      INTEGER NUMSTA
      INTEGER OBTIME(NUMSTA)
      CHARACTER*(*) STANAMES(NUMSTA)
      INTEGER WMOID(NUMSTA)
      CHARACTER*(*) PROVDR(NUMSTA)
      INTEGER SUBSRC(NUMSTA)
      REAL LATS(NUMSTA)
      REAL LONS(NUMSTA)
      REAL ELEVATION(NUMSTA)
      INTEGER FNUM(NUMSTA)
      INTEGER RNUM(NUMSTA)
      INTEGER NUMSTA_NEW

C     ------------------------------------------------------------------
C     LOCAL VARIABLES
C     ------------------------------------------------------------------
      INTEGER I,J,LOW,NOM,HIGH,STATUS,OBMIN
      INTEGER LOCAL_OBTIME(MXHYDRO_P*4)
      CHARACTER*8 LOCAL_STANAMES(MXHYDRO_P*4)
      CHARACTER*10 LOCAL_DPNAME(MXHYDRO_P*4)
      INTEGER RECORD(MXHYDRO_P*4)
      LOGICAL HAVE_STATION,MDOMFLTR
      EXTERNAL MDOMFLTR
C
      NUMSTA_NEW = 0
      IF(NUMSTA.EQ.0)GO TO 900

      IF(RECWIN.NE.0)THEN
C
C     CREATE THE TIME WINDOW IN I4TIME.
C
         CALL M_MKI4TM(ATIME, NOM, STATUS)
         HIGH = NOM + MINFWD * 60
         LOW = NOM + MINBCK * 60

      ENDIF
C
C     FOR EACH RECORD WE'LL SEE IF WE ALREADY HAVE ONE FOR THIS
C     STATION.  IF NOT, WE'LL ADD THIS RECORD TO THE LIST.  IF SO,
C     AND WE'RE DOING TIME WINDOWING, WE'LL REPLACE THE ONE WE
C     ALREADY HAVE IF THE CURRENT ONE IS WITHIN THE TIME WINDOW
C     AND BETTER MEETS THE RECWIN CRITERIA.
C
      DO 3 I = 1, NUMSTA
C
         HAVE_STATION = .FALSE.
C
C     FILTER OUT STATIONS MISSING LAT, LON, ELEVATION OR TIME.
C
         IF(LATS(I).EQ.SPVAL.OR.LONS(I).EQ.SPVAL
     1      .OR.ELEVATION(I).EQ.SPVAL.OR.OBTIME(I).EQ.SPVAL)GO TO 3
C
C     REMOVE THE SECONDS FROM THE OBTIME FOR USE IN COMPARING AGAINST
C     THE HIGH SIDE OF THE WINDOW:  THIS WAS DISCOVERED WHEN ADDING
C     ACARS DATA -- IF A TIME IS, SAY, 23:59:59, WE WON'T GET IT IN
C     A WINDOW SPECIFIED TO BE FROM MINUTE 0 TO MINUTE 59.  BY
C     REDUCING THE 23:59:59 TO 23:59:00 WE WILL GET IT.
C
         IF(OBTIME(I).NE.SPVAL)THEN
            OBMIN = OBTIME(I)/60*60
            IF(OBTIME(I).LT.0)OBMIN = OBMIN - 60
         ENDIF
C
C     FILTER OUT DISABLED PROVIDERS.
C
         IF(SUBSRC(I).NE.0.AND.SUBSRC(I).NE.999)THEN
            IF(.NOT.PROVDR_ENBL(SUBSRC(I)))GO TO 3
         ENDIF
C
C     IF WE'RE RETURNING ALL RECORDS (RECWIN 0 - IN THE FILE, 4 - IN THE
C     WINDOW), SKIP THE TIME WINDOW FILTERING.
C
         IF(RECWIN.EQ.0.OR.RECWIN.EQ.4)GO TO 40

         DO 4 J = 1, NUMSTA_NEW
C
C     LDAD HYDRO FILTERING MEANS THAT WE CAN'T COUNT ON THE STATION 
C     NAMES BEING UNIQUE.  WHAT WE CAN COUNT ON IS THE COMBINATION OF
C     STATION NAME AND DATA PROVIDER NAME WILL BE UNIQUE.
C
            IF((SOURCE.NE.LHYDRO_DS_P.AND.
     2          LOCAL_STANAMES(J).EQ.STANAMES(I)(1:10)).OR.
C
     3         (SOURCE.EQ.LHYDRO_DS_P.AND.
     4          LOCAL_STANAMES(J).EQ.STANAMES(I)(1:10).AND.
     5          LOCAL_DPNAME(J).EQ.PROVDR(I)(1:10)))THEN
C
C     NOTE THE TEST ON TIME IS .GE. AND NOT .GT. THIS SHOULD
C     COVER CORRECTED OBS WITHOUT HAVING TO LOOK AT THE
C     CORRECTED FLAG AS THE CORRECTED OB ALWAYS COMES IN LATER
C     AND BY RULE MUST HAVE THE SAME TIME AS THE OB BEING
C     CORRECTED.  IF THERE IS EVER ANY DESIRE TO SHUFFLE
C     OBS BEFORE CALLING THIS ROUTINE SO THAT THIS CANNOT BE
C     GUARANTEED THEN THE CORRECTED FLAG MUST BE USED.  ALSO
C     NOTE THAT AS THE TIMES ARE THE SAME, THIS LOGIC WORKS
C     FOR ALL 3 TIME WINDOW CRITERIA.
C
               HAVE_STATION = .TRUE.

               IF(RECWIN.EQ.3)THEN
                  IF(OBTIME(I).GE.LOCAL_OBTIME(J).AND.OBMIN.LE.HIGH.AND.
     1                 OBTIME(I).NE.SPVAL)THEN
                     LOCAL_OBTIME(J) = OBTIME(I)
                     RECORD(J) = I
                  ENDIF
               ELSE IF(RECWIN.EQ.2)THEN
                  IF(OBTIME(I).LE.LOCAL_OBTIME(J).AND.OBMIN.LE.HIGH.AND.
     1                 OBTIME(I).NE.SPVAL)THEN
                     LOCAL_OBTIME(J) = OBTIME(I)
                     RECORD(J) = I
                  ENDIF
               ELSE IF(RECWIN.EQ.1)THEN
                  IF(ABS(OBTIME(I)-NOM).LE.ABS(LOCAL_OBTIME(J)-NOM).AND.
     1                 OBMIN.LE.HIGH.AND.OBTIME(I).NE.SPVAL)THEN
                     LOCAL_OBTIME(J) = OBTIME(I)
                     RECORD(J) = I
                  ENDIF
               ENDIF
            ENDIF

 4       CONTINUE
C
C     IF WE DIDN'T ALREADY HAVE ONE FOR THIS STATION, ADD IT IN IF
C     WITHIN THE TIME WINDOW.
C
 40      IF((.NOT.HAVE_STATION.AND.OBTIME(I).GE.LOW.AND.
     1       OBMIN.LE.HIGH.AND.OBTIME(I).NE.SPVAL).OR.RECWIN.EQ.0)THEN
C
C     WHOOPS, NOT SO FAST.  FIRST TOSS STUFF OUTSIDE THE USER'S
C     DOMAIN, IF SO DESIRED.
C
            IF(.NOT.MDOMFLTR(LATS(I),LONS(I)))THEN

               NUMSTA_NEW = NUMSTA_NEW + 1
               LOCAL_OBTIME(NUMSTA_NEW) = OBTIME(I)
               LOCAL_STANAMES(NUMSTA_NEW) = STANAMES(I)(1:10)

               IF(SOURCE.EQ.LHYDRO_DS_P)
     1              LOCAL_DPNAME(NUMSTA_NEW) = PROVDR(I)(1:10)

               RECORD(NUMSTA_NEW) = I

            ENDIF

         ENDIF
C
 3    CONTINUE
C
 900  IF(NUMSTA_NEW.NE.0)THEN
C
C     FILL IN THE ARRAYS IN PLACE.
C
         DO 6 I = 1, NUMSTA_NEW
            OBTIME(I) = LOCAL_OBTIME(I)
            STANAMES(I) = STANAMES(RECORD(I))
            WMOID(I) = WMOID(RECORD(I))
            PROVDR(I) = PROVDR(RECORD(I))
            LATS(I) = LATS(RECORD(I))
            LONS(I) = LONS(RECORD(I))
            ELEVATION(I) = ELEVATION(RECORD(I))
            FNUM(I) = FNUM(RECORD(I))
            RNUM(I) = RNUM(RECORD(I))
 6       CONTINUE
C
      ENDIF
C
      RETURN
      END
C**---------------------------------------------------------------------
C**REQUIRED STANDARD FSL DISCLAIMER (NOVEMBER 2000)
C**---------------------------------------------------------------------
C**  OPEN SOURCE LICENSE/DISCLAIMER,  FORECAST SYSTEMS LABORATORY
C**  NOAA/OAR/FSL, 325 BROADWAY BOULDER, CO 80305
C**
C**  THIS SOFTWARE IS DISTRIBUTED UNDER THE OPEN SOURCE DEFINITION, 
C**  WHICH MAY BE FOUND AT http://www.opensource.org/osd.html.
C**
C**  IN PARTICULAR, REDISTRIBUTION AND USE IN SOURCE AND BINARY FORMS,
C**  WITH OR WITHOUT MODIFICATION, ARE PERMITTED PROVIDED THAT THE 
C**  FOLLOWING CONDITIONS ARE MET:
C**
C**  - REDISTRIBUTIONS OF SOURCE CODE MUST RETAIN THIS NOTICE, THIS LIST
C**    OF CONDITIONS AND THE FOLLOWING DISCLAIMER.
C**
C**  - REDISTRIBUTIONS IN BINARY FORM MUST PROVIDE ACCESS TO THIS 
C**    NOTICE, THIS LIST OF CONDITIONS AND THE FOLLOWING DISCLAIMER, AND
C**    THE UNDERLYING SOURCE CODE.
C**
C**  - ALL MODIFICATIONS TO THIS SOFTWARE MUST BE CLEARLY DOCUMENTED, 
C**    AND ARE SOLELY THE RESPONSIBILITY OF THE AGENT MAKING THE 
C**    MODIFICATIONS.
C**
C**  - IF SIGNIFICANT MODIFICATIONS OR ENHANCEMENTS ARE MADE TO THIS
C**    SOFTWARE, THE FSL SOFTWARE POLICY MANAGER 
C**    (softwaremgr.fsl@noaa.gov) BE NOTIFIED.
C**
C**  THIS SOFTWARE AND ITS DOCUMENTATION ARE IN THE PUBLIC DOMAIN AND 
C**  ARE FURNISHED "AS IS."  THE AUTHORS, THE UNITED STATES GOVERNMENT,
C**  ITS INSTRUMENTALITIES, OFFICERS, EMPLOYEES, AND AGENTS MAKE NO 
C**  WARRANTY, EXPRESS OR IMPLIED, AS TO THE USEFULNESS OF THE SOFTWARE
C**  AND DOCUMENTATION FOR ANY PURPOSE.  THEY ASSUME NO RESPONSIBILITY 
C**  (1) FOR THE USE OF THE SOFTWARE AND DOCUMENTATION; OR (2) TO 
C**  PROVIDE TECHNICAL SUPPORT TO USERS.
C**---------------------------------------------------------------------
