SUBROUTINE UG_DCOD  ( cldt, usgsfl, usgtbl, 
     +                        bufrtb, nhours, iret )
C************************************************************************
C* UG_DCOD								*
C*									*
C* This routine decodes the USGS river and stream runoff data into      *
C* BUFR format.			                        		*
C*									*
C* UG_DCOD ( CLDT, USGSFL, USGTBL, BUFRTB, NHOURS, IRET )		*
C*									*
C* Input parameters:							*
C*	CLDT		CHAR*		Date-time from command line	*
C*	USGSFL		CHAR*		USGS data file			*
C*	USGTBL		CHAR*		Station table   		*
C*	BUFRTB		CHAR*		BUFR tables file		*
C*	NHOURS		INTEGER		Max # of hours before run time	*
C*					for creating BUFR output	*
C*									*
C* Output parameters:							*
C*	IRET		INTEGER		Return code:			*
C*					  0 = normal return		*
C*									*
C**									*
C* Log:									*
C* C. Caruso Magee/NCEP5	Based on dcalps				*
C* J. Ator/NCEP		07/08	Increased capacity to handle additional	*
C*				data fields (up to 28)			*
C* J. Ator/NCEP		03/09	Use DC_BSRC for station lookup, and	*
C				convert	report time from local to UTC	*
C* J. Ator/NCEP		05/09	Use MXFLDS and MXRECL parameters, use	*
C*				new UK_BKST subroutine, and add	decode	*
C*				of specific conductance (00095) 	*
C* J. Ator/NCEP		06/11	Allow station IDs up to 16 characters	*
C* J. Ator/NCEP		08/13	Use ST_INTG to decode date field	*
C* J. Ator/NCEP		08/13	Use timezone from report		*
C* J. Ator/NCEP		10/16	Look for underscore in each field of	*
C*				header record, rather than assuming it's*
C*				always in the 3rd character		*
C************************************************************************
	INCLUDE		'GEMPRM.PRM'
	INCLUDE		'ugcmn.cmn'
C*
	CHARACTER*(*)	cldt, usgsfl, usgtbl, bufrtb
C*
	CHARACTER	rundt*12, sysdt*12,
     +			report*(MXRECL), rptcpy*(MXRECL),
     +			rimnem(NRIMN)*8, cimnem(NCIMN)*8,
     +			flds(MXFLDSP3)*16,
     +                  parmlist(MXFLDS)*5, ddlist(MXFLDS)*7,
     +                  siteno*16, param(NDPRM)*5, tmpparm*16,
     +                  dummyparm*5, dummydd*2
C*
	INTEGER		irundt (5), irptdt (5)
C*
        LOGICAL         match, havdata, rptok
C*
        DATA  param     / '00010','00020','00021','00035','00036',
     +                    '00045','00055','00060','00065','00480', 
     +                    '61728','72020','00095' /
        DATA  dummyparm / 'XXXXX' /
        DATA  dummydd   / 'DD' /
C*
	INCLUDE		'ERMISS.FNC'
C*-----------------------------------------------------------------------
	iret = 0
	ieread = -9
	loglev = 3
C
C*      Open and read the USGS station table file.
C
        CALL UG_STOR  ( usgtbl, ierugt )
C
C*	Set the pointers for the interface arrays.
C
	CALL UG_IFSP  ( rimnem, cimnem, ierfsp )
	IF  ( ierfsp .ne. 0 )  THEN
	    RETURN
	END IF
C
C*	Open the USGS data file.
C
	CALL FL_SOPN  ( usgsfl, iunndf, ierspn )
	IF  ( ierspn .ne. 0 )  THEN
	    CALL DC_WLOG  ( 0, 'FL', ierspn, usgsfl, ierwlg )
	    RETURN
	END IF
C
C*	Open the BUFR tables file.
C
	CALL FL_SOPN  ( bufrtb, iunbft, ierspn )
	IF  ( ierspn .ne. 0 )  THEN
	    CALL DC_WLOG  ( 0, 'FL', ierspn, bufrtb, ierwlg )
	    RETURN
	END IF
C
C*	Open the BUFR output file.
C
	CALL FL_GLUN  ( iunbfo, iergln )
	IF  ( iergln .ne. 0 )  THEN
	    CALL DC_WLOG  ( 0, 'FL', iergln, ' ', ierwlg )
	    RETURN
	END IF
C
C*	Connect the BUFR tables and output files to the BUFR interface.
C
	CALL OPENBF  ( iunbfo, 'NUL', iunbft )
C
C*	Specify the use of BUFR edition 4, since Table C operator 2-07
C*	is being utilized within the BUFR tables file.
C
	CALL PKVS01  ( 'BEN', 4 )	
C
C*	Close the BUFR tables file.
C
	CALL FL_CLOS  ( iunbft, iercls )
	IF  ( iercls .ne. 0 )  THEN
	    CALL DC_WLOG  ( 0, 'FL', iercls, ' ', ierwlg )
	END IF
C
C*	Get the system time.
C
	itype = 1
	CALL CSS_GTIM  ( itype, sysdt, iergtm )
	IF  ( iergtm .ne. 0 )  THEN
	    CALL DC_WLOG  ( 2, 'SS', iergtm, ' ', ierwlg )
	    RETURN
	END IF
C
C*	If a date-time was entered on the command line, then use it as
C*	the run date-time.  Otherwise, use the system time as the run
C*	date-time.
C
	IF  ( cldt .eq. 'SYSTEM' )  THEN
	    rundt = sysdt
	ELSE
	    CALL TI_STAN  ( cldt, sysdt, rundt, ierstn )
	    IF  ( ierstn .ne. 0 )  THEN
		CALL DC_WLOG  ( 2, 'TI', ierstn, ' ', ierwlg )
		RETURN
	    END IF
	END IF
C
C*	Convert the run date-time to integer.
C
	CALL TI_CTOI  ( rundt, irundt, iercto )
	IF  ( iercto .ne. 0 )  THEN
	    CALL DC_WLOG  ( 2, 'TI', iercto, ' ', ierwlg )
	    RETURN
	END IF
C
        irc = 0
C
	DO WHILE  ( .true. )
C
	   irc = irc + 1
           havdata = .false.
C
C*	   Read the next record (i.e. line) from the USGS data file.
C
           READ ( UNIT = iunndf, FMT = '(A)', ERR = 900, END = 910 )
     +	     report
C
           IF ( ( report ( 1:4 ) .eq. 'agen' ) .or. 
     +          ( report ( 1:4 ) .eq. 'USGS' ) ) THEN
C
C*	     Break the record into an array of substrings (i.e. fields).
C
             CALL ST_LSTR ( report, lenr, ilret ) 
             IF ( lenr .gt. MXRECL ) THEN
                  WRITE ( UNIT = logmsg, FMT='(I4)' ) lenr
	          CALL DC_WLOG  ( 2, 'UG', 10, logmsg(1:4), ierwlg )
		  lenr = MXRECL
             END IF
	     CALL UG_BKST ( report, lenr, flds, numfld, iret )
             IF ( iret .ne. 0 ) THEN
                WRITE ( UNIT = logmsg, FMT='(A,I2)' )
     +		    'more than ', MXFLDS
	        CALL DC_WLOG  ( 2, 'UG', 2, logmsg(1:12), ierwlg )
             END IF
C
C*	     The first 4 fields are fixed fields containing the "USGS"
C*	     label, the station number, the datetime and the timezone.
C
	     nff = 4
C
	     IF ( numfld .gt. nff ) THEN
C
C*		Make a copy of the report with the tabs and any
C*		extra spaces removed, then write this copy to the
C*		decoder log.
C
		rptcpy = ' '
		IF ( flds (3)(13:13) .eq. ':' ) THEN
		    rptcpy = flds(1)(1:4) // '  ' //
     +			     flds(2)(1:16) // '  ' //
     +			     flds(3)(1:10) // ' ' //
     +			     flds(3)(11:15) // ' ' //
     +			     flds(4)(1:4) // '  '
		    lrcpy = 47
		    nspc = 3
		ELSE
		    rptcpy = '      site_no           datetime' //
     +			     '       tmzone '
		    lrcpy = 46 
		    nspc = 1
		END IF
		DO ii = nff+1, numfld
		    IF ( INDEX ( flds (ii), '_cd' ) .eq. 0 ) THEN
			CALL ST_LSTR ( flds (ii), lfld, ierstr )
			IF ( lfld .ne. 0 ) THEN
			  DO jj = 1, nspc
			    rptcpy ( lrcpy+1 : lrcpy+1 ) = ' '
			    lrcpy = lrcpy + 1
			  END DO
			  rptcpy ( lrcpy+1 : lrcpy+lfld ) =
     +				flds (ii)(1:lfld)
			  lrcpy = lrcpy + lfld
			END IF
		    END IF
		END DO
		IF ( lrcpy .ge. 100 ) THEN
		    CALL DC_WLOG  ( 2, ' ', 1, rptcpy, ierwlg )
		ELSE
		    CALL DC_WLOG  ( 2, 'DC', 2, rptcpy, ierwlg )
		END IF
C
C*             Check to see if this is a header record for a station.
C
               IF ( flds ( 1 ) .eq. 'agency_cd') THEN
C
C*               Yes, so search for fields which define the data
C*		 parameters for this station.
C
                 DO i = nff+1, numfld
                    match = .false.
		    iusc = INDEX ( flds ( i ), '_' )
		    IF ( ( iusc .gt. 1 ) .and. ( iusc+5 .lt. 16 ) ) THEN
                      DO j = 1, NDPRM 
                        IF ( .not. match ) THEN
                          IF ( flds ( i )( iusc+1 : iusc+5 ) .eq. 
     +                                   param ( j )( 1:5 ) ) THEN
                            parmlist ( i - nff ) = param ( j )
                            ddlist ( i - nff ) =
     +				flds ( i )( 1 : MIN( iusc-1, 7 ) )
                            match = .true.
                          END IF
                        END IF
                      END DO
		    END IF
                    IF ( .not. match ) THEN
                       parmlist ( i - nff ) = dummyparm
                       ddlist ( i - nff ) = dummydd
                    END IF
                 END DO
               ELSE
C            
C*	         This is a data record, so store it into the interface.
C
		 rptok = .true.
C
C*               Initialize the interface arrays.
C
 	         CALL UG_IFIV ( ierifi )
C
C*		 Look for the station in the station table.
C
	         siteno = flds ( 2 )
		 CALL DC_BSRC ( siteno, stnid, jstnm, ipos, ierbrc )
		 IF ( ipos .eq. 0 ) THEN
                   CALL DC_WLOG  ( 0, 'UG', 3, siteno, ierwlg )
		   rptok = .false.
		 ELSE
                   civals ( icstid ) = stnid ( ipos )
                   rivals ( irselv ) = elev ( ipos )
                   rivals ( irslat ) = ylat ( ipos )
                   rivals ( irslon ) = ylong ( ipos )
                   civals ( icagcy ) = flds ( 1 )
		 END IF
C
		 IF ( rptok ) THEN
C
C*		   Get the report date-time.  This time is reported
C*		   as a local time at the station, so it needs to be
C*		   converted to UTC.
C
		   CALL ST_INTG ( flds(3)(1:4), irptdt(1), iersi1)
		   CALL ST_INTG ( flds(3)(6:7), irptdt(2), iersi2)
		   CALL ST_INTG ( flds(3)(9:10), irptdt(3), iersi3)
		   CALL ST_INTG ( flds(3)(11:12), irptdt(4), iersi4)
		   CALL ST_INTG ( flds(3)(14:15), irptdt(5), iersi5)
		   IF ( ( iersi1 .ne. 0 ) .or. ( iersi2 .ne. 0 ) .or.
     +			( iersi3 .ne. 0 ) .or. ( iersi4 .ne. 0 ) .or.
     +			( iersi5 .ne. 0 ) ) THEN
		     rptok = .false.
		   END IF
		 END IF
C
		 IF ( rptok ) THEN
C
C*		   Using the reported timezone, determine the difference
C*		   (in hours) between UTC and the local time at that
C*		   location.
C
		   SELECT CASE( flds(4)(1:3) )
			CASE( "HST" )
			  idiff = 10
			CASE( "AKS" )
			  idiff = 9
			CASE( "AKD", "PST" )
			  idiff = 8
			CASE( "PDT" )
			  idiff = 7
			CASE( "CST" )
			  idiff = 6
			CASE( "CDT", "EST" )
			  idiff = 5
			CASE( "EDT", "AST" )
			  idiff = 4
			CASE( "ADT" )
			  idiff = 3
			CASE DEFAULT
			  rptok = .false.
		   END SELECT
		 END IF
C
		 IF ( rptok ) THEN
C
C*		   Convert the local time to UTC.
C
		   CALL TI_ADDM ( irptdt, idiff*60, irptdt, ieradm )
		   IF ( ieradm .ne. 0 ) THEN
		     CALL UT_EMSG ( 2, 'TI_ADDM', ieradm )
		     rptok = .false.
		   ELSE
		     rivals ( iryear ) = FLOAT ( irptdt(1) )
		     rivals ( irmnth ) = FLOAT ( irptdt(2) )
		     rivals ( irdays ) = FLOAT ( irptdt(3) )
		     rivals ( irhour ) = FLOAT ( irptdt(4) )
		     rivals ( irminu ) = FLOAT ( irptdt(5) )
		   END IF
		 END IF
C
		 IF ( rptok ) THEN
                   iwnds = 0
                   iwndr = 0
                   irsh = 0
                   idch = 0
                   ipcp = 0
                   DO k = 1, numfld - nff 
	             READ ( UNIT = flds( k+nff ), FMT = '(A)', 
     +                      IOSTAT = ier ) tmpparm
C
C*                   Convert character parm to real number.  If return
C*                   code is non-zero, conversion failed (parm either
C*                   contained letters or invalid non-numeric character).
C*                   Output parm for non-zero return code is RMISSD.
C 
C*                   Convert character parameter to either real directly
C*                   or to integer then real.
C
                     CALL ST_CRNM ( tmpparm, foutparm, icrret )
                     IF ( icrret .eq. 0 ) THEN
                        IF ( parmlist ( k ) .eq. '00010' ) THEN
                           havdata = .true.
                           rivals ( irwtmp ) = foutparm
                        ELSEIF ( parmlist ( k ) .eq. '00020' ) THEN
                           havdata = .true.
                           rivals ( irtmpc ) = foutparm
                        ELSEIF ( parmlist ( k ) .eq. '00021' ) THEN
                           havdata = .true.
                           rivals ( irtmpf ) = foutparm
                        ELSEIF ( parmlist ( k ) .eq. '00095' ) THEN
                           havdata = .true.
                           rivals ( irwacn ) = foutparm
                        ELSEIF ( parmlist ( k ) .eq. '00035' ) THEN
                           iwnds = iwnds + 1
                           IF ( iwnds .lt. 3 ) THEN
                             havdata = .true.
                             rivals ( irwspd (iwnds) ) = foutparm
                             CALL ST_CRNM ( ddlist ( k ), 
     +                          rivals ( irddws ( iwnds ) ), icrret2 )
                           ELSE
                             WRITE (UNIT=logmsg, FMT='(I2)') iwnds
	                     CALL DC_WLOG  ( 0, 'UG', 4, 
     +                                      logmsg(1:2), ierwlg )
                           END IF
                        ELSEIF ( parmlist ( k ) .eq. '00036' ) THEN
                           iwndr = iwndr + 1
                           IF ( iwndr .lt. 3 ) THEN
                             havdata = .true.
                             rivals ( irwdir (iwndr) ) = foutparm
                             CALL ST_CRNM ( ddlist ( k ), 
     +                          rivals ( irddwd ( iwndr ) ), icrret3 )
                           ELSE
                             WRITE (UNIT =logmsg, FMT='(I2)') iwndr
	                     CALL DC_WLOG  ( 0, 'UG', 4, 
     +                                       logmsg(1:2), ierwlg )
                           END IF
                        ELSEIF ( parmlist ( k ) .eq. '00045' ) THEN
                           ipcp = ipcp + 1
                           IF ( ipcp .lt. 3 ) THEN
                             havdata = .true.
                             rivals ( irprec ( ipcp ) ) = foutparm
                             CALL ST_CRNM ( ddlist ( k ), 
     +                         rivals ( irddpc ( ipcp ) ), icrret4 )
                           ELSE
                             WRITE (UNIT=logmsg, FMT='(I2)') ipcp
	                     CALL DC_WLOG  ( 0, 'UG', 7, 
     +                                       logmsg(1:2), ierwlg )
                           END IF
                        ELSEIF ( parmlist ( k ) .eq. '00055' ) THEN
                           havdata = .true.
                           rivals ( irstrv ) = foutparm
                        ELSEIF ( parmlist ( k ) .eq. '00060' ) THEN
                           idch = idch + 1
                           IF ( idch .lt. 3 ) THEN
                             havdata = .true.
                             rivals ( irdchg ( idch ) ) = foutparm
                             CALL ST_CRNM ( ddlist ( k ), 
     +                         rivals ( irdddc ( idch ) ), icrret5 )
                           ELSE
                             WRITE (UNIT=logmsg, FMT='(I2)') idch
	                     CALL DC_WLOG  ( 0, 'UG', 8, 
     +                                       logmsg(1:2), ierwlg )
                           END IF
                        ELSEIF ( parmlist ( k ) .eq. '00065' ) THEN
                           irsh = irsh + 1
                           IF ( irsh .lt. 3 ) THEN
                             havdata = .true.
                             rivals ( irrshm (irsh) ) = foutparm
                             CALL ST_CRNM ( ddlist ( k ), 
     +                         rivals ( irddrs ( irsh ) ), icrret6 )
                           ELSE
                             WRITE (UNIT=logmsg, FMT='(I2)') irsh
	                     CALL DC_WLOG  ( 0, 'UG', 9, 
     +                                       logmsg(1:2), ierwlg )
                           END IF
                        ELSEIF ( parmlist ( k ) .eq. '00480' ) THEN
                           havdata = .true.
                           rivals ( irsaln ) = foutparm
                        ELSEIF ( parmlist ( k ) .eq. '61728' ) THEN
                           havdata = .true.
                           rivals ( irgust ) = foutparm
                        ELSEIF ( parmlist ( k ) .eq. '72020' ) THEN
                           havdata = .true.
                           rivals ( irrsh9 ) = foutparm
                        END IF
                     END IF
                   END DO
                   rivals ( irnwnd ) = MAX0 ( iwnds, iwndr ) 
                   rivals ( irnrsh ) = irsh 
                   rivals ( irndch ) = idch 
                   rivals ( irnpcp ) = ipcp 
                 END IF
C
                 IF ( havdata ) THEN
C
C*	           Write the interface output to the decoder log.
C
     	           CALL UG_IFPT ( loglev, rimnem, cimnem, iret )
C
C*	           Do not create BUFR output for reports that are
C*	           more than NHOURS before or more than 3 hours
C*	           after the run time.
C
	           IF ( ( ERMISS ( rivals ( iryear ) ) ) .or.
     +	                ( ERMISS ( rivals ( irmnth ) ) ) .or.
     +	                ( ERMISS ( rivals ( irdays ) ) ) .or.
     +	                ( ERMISS ( rivals ( irhour ) ) ) .or.
     +	                ( ERMISS ( rivals ( irminu ) ) )  )  THEN
	                iertmk = -1
	           ELSE
                        CALL DC_TMCK  ( 2, irundt, irptdt, nhours,
     +	                                180, iertmk )
	           END IF
C
	           IF ( iertmk .eq. 0 )  THEN
C
C*      	        Convert interface-format data for this report
C*      	        into BUFR output and then write the BUFR output
C*		        to the BUFR output stream.
C
                        CALL UG_BUFR  ( iunbfo, irundt, rptcpy, lrcpy,
     +					ierbfr )
	           END IF
C
                 END IF
               END IF
             END IF
           END IF
C
	END DO
C
  900	ieread = -5
  910	CALL DC_WLOG  ( 0, 'DC', ieread, ' ', ierwlg )
C
C*	Make sure that all BUFR output has been written before exiting. 
C
	CALL UT_WBFR  ( iunbfo, 'usgs', 1, ierwbf )
C
	CALL CLOSBF  ( iunbfo )
	CALL FL_CLAL  ( iercal )
C*
	RETURN
	END