;+
; NAME:
;     GETPARMS
; PURPOSE:
;     Routine to read GCAL files (offsets and gain parameters) and return
;     the appropriate values for a given date and time
; CATEGORY:
;     OVRO APC UTILITY
; CALLING SEQUENCE:
;     gparm = getparms(tls)
; INPUTS:
;     tls        A standard time/label structure giving the date and time for
;                  which the parameters are desired.
; OPTIONAL (KEYWORD) INPUT PARAMETERS:
; ROUTINES CALLED:
;     break_file
; OUTPUTS:
;     gparm      A structure containing the offsets and gain parameters.  If
;                  there was a problem finding or reading the files, GAINPARM
;                  will contain nominal values (offsets all zero, nonlinearity
;                  zero, and unit attenuation factors), and the epoch will have
;                  day number set to zero.
;                  Structure contents:
;                   {gparm,  epoch: strarr(2)          ; Each of length 17, YYYY.DDD HH:MM:SS
;                          poffsets: ptr to fltarr(NANT^2) ; Array of offsets, one for each chan
;                              pgnp: ptr to NANT-element array of structures as follows
;                                   {gnp,nlparm: float     ; Nonlinearity parameter
;                                      attn: fltarr(3) ; Attenuation factor
;                                     ndfac: float     ; ND_eff factor (relative to 500)
;                                     resid: float     ; Residual indicating quality of GCAL
;                                }
;                             dlcal:  fltarr(4,14)     ; To hold Delay line calibration
;                             pgcal: ptr to NANT-element x NF-element array with GCAL results
;                                    {gcal, rcvr: float ; Receiver IF level
;                                           nd:   float ; Noise Diode increment
;                                        resid:   float ; RMS difference of model to data
;                                }
;                         }
; COMMENTS:
; SIDE EFFECTS:
; RESTRICTIONS:
;     Contains code specific to 5 antennas.
; MODIFICATION HISTORY:
;     Written 23-Aug-1998 by Dale E. Gary
;     05-Sep-1998  DG
;       Made the GPARM structure a named structure.
;     26-Nov-1999  DG
;       Changed to return a new form of GPARM structure (introduced due
;       to creation of GAINPARM segment).
;-

function getline,files,nfiles,tls

   ; Helper function to search through a list of files and return the line
   ; that is the next earlier one in time to the time given by tls

   ; Error return if no files
   if (nfiles eq 0) then return,-1

   ; Get the expected file name root (e.g. 199808) from year and month
   ; of today's date.
   ymd = cvdoy(tls.year,tls.day)
   yrmon = string(ymd(0:1),format='(I4,I2.2)')

   ; Sort the file names into date order
   files = files(sort(files))

find:
   ; Find the filename that matches YRMON, or is the next earlier one
   for i = 0, nfiles-1 do begin
      filename = files(i)
      break_file,filename,disk,direc,root,ext
      if (root eq yrmon) then begin
         ; We have an exact match, so go with it
         goto,done
      endif else if (root gt yrmon) then begin
         ; We found a file later than the one we want, so
         ; take the next earlier one, if any
         if (i eq 0) then begin
            ; This was the earliest file, and is too late, so return
            ; an error (-1) to indicate failure
            return,-1
         endif
         filename = files(i-1)
         goto,done
      endif
      ; No file yet, so keep going
   endfor
done:
   ; The filename is either the correct date or the next earlier one
   ; Now search through the entries to find the best date within the file
   ON_IOERROR,err_rtn
   openr,lun,/get_lun,filename

   ; Read and discard the header lines
   hedlines = strarr(3)
   readf,lun,hedlines

   today = tls.yrday+tls.timstr
   prevline = (line = '')
   while (not EOF(lun)) do begin
      readf,lun,line
      reads,line,timstr,format='(A17)'
      if (timstr eq today) then begin
         ; We have an exact match, so go with it
         free_lun,lun
         return,line
      endif else if (timstr gt today) then begin
         ; We found a time later than the one we want, so
         ; take the next earlier one, if any
         if (prevline eq '') then begin
            ; This was the earliest line, and is too late, so we have to go back
            ; to an earlier file!
            ; Subtract one month from YRMON
            yrmon = string(long(yrmon)-1,format='(i6)')
            ; Handle case of month of January by subtracting one year
            ; and adding 12 months
            if (strmid(yrmon,4,2) eq '00') then begin
               yrmon = string(long(yrmon)-100,format='(i6)')  ; Subtract year
               strput,yrmon,'12',4                            ; Replace month w/ 12
            endif
            free_lun,lun
            ; Go back to find the next earlier file
            goto,find
         endif else begin
            free_lun,lun
            return,prevline
         endelse
      endif
      ; No match yet, so keep going
      prevline = line
   endwhile

   free_lun,lun
   ; We reached the end of the file without a match, but the last line must
   ; be the right one, so if it is not empty then return it
   if (line eq '') then return,-1 $
                   else return,line

err_rtn:
   ; Return code for file read error
   return,-2

end

function getparms,tls

   ; Find all potential offsets files in the DATABASE directory (DBDIR)
   offiles = findfile(!defaults.dbdir+'*.off',count=noff)
   ; Find all potential gain parameter files in the DATABASE directory (DBDIR)
   gnfiles = findfile(!defaults.dbdir+'*.gnp',count=ngnp)

   ; This will have to be made general for different numbers of antennas
   ; Declare storage for the offsets
   offsets = fltarr(25)
   gnp = replicate({gnp},5)

   ; Get the offsets file entry that is the next earlier time with respect to TLS
   ; using the GETLINE routine above.
   line = getline(offiles,noff,tls)
   offepoch = {epoch}

   ; Check the variable type of LINE.  It should be 7 (i.e. a string), so if
   ; not then GETLINE() returned an error.
   if ((size(line))(1) ne 7) then begin
      if (line eq -1) then begin
         errstr = 'GETPARMS: Channel offsets file not found.  Will use 0 for all.'
         IF (keyword_set(cmdfile)) THEN printf,msglun,errstr,format='(a)' $
                                   ELSE ans = widget_message(errstr,/ERROR)
      endif else begin
         errstr = 'GETPARMS: Error reading channel offsets file.  Will use 0 for all.'
         IF (keyword_set(cmdfile)) THEN printf,msglun,errstr,format='(a)' $
                                   ELSE ans = widget_message(errstr,/ERROR)
      endelse
      ; Flag epoch as current year but ZERO day number
      offepoch.yr = tls.year
      offepoch.doy = 0
      offepoch.sec = 0
   endif else begin
      reads,line,offsets,format='(17X,25F5.1)'
      offepoch.yr  = strmid(line,0,4)
      offepoch.doy = strmid(line,5,3)
      offepoch.sec = long(strmid(line,9,2)*3600L+strmid(line,12,2)*60L+strmid(line,15,2))
   endelse


   ; Get the gain parameter file entry that is the next earlier time with respect to TLS
   ; using the GETLINE routine above.
   line = getline(gnfiles,ngnp,tls)

   ; Check the variable type of LINE.  It should be 7 (i.e. a string), so if
   ; not then GETLINE() returned an error.
   if ((size(line))(1) ne 7) then begin
      if (line eq -1) then begin
         errstr = 'GETPARMS: Gain parm file not found.  Will use nominal values.'
         IF (keyword_set(cmdfile)) THEN printf,msglun,errstr,format='(a)' $
                                   ELSE ans = widget_message(errstr,/ERROR)
      endif else begin
         errstr = 'GETPARMS: Error reading gain parm file.  Will use nominal values.'
         IF (keyword_set(cmdfile)) THEN printf,msglun,errstr,format='(a)' $
                                   ELSE ans = widget_message(errstr,/ERROR)
      endelse
      ; Flag epoch as current year but ZERO day number
      gnpepoch = string(tls.year,format='(I4,".000 00:00:00")')
   endif else begin
      reads,strmid(line,17,strlen(line)-17),gnp
      gnpepoch = strmid(line,0,17)
   endelse

   ; Convert offsets to a square, 8x8 array to match the new form of offsets.  Since
   ; the offsets are in a fixed format, just hardwire the conversion
   ibl = [ 0, 6, 8,10,12 ,$
           5, 1,14,16,18 ,$
           7,13, 2,20,22 ,$
           9,15,19, 3,24 ,$
          11,17,21,23, 4 ]

   offsetsq = fltarr(8,8) + !values.f_nan
   for j = 0, 4 do begin
      for i = 0, 4 do begin
         offsetsq[i,j] = offsets[ibl[j*5 + i]]
      endfor
   endfor

   gparm = {epoch:offepoch,poffsets:ptr_new(offsetsq),pgnp:ptr_new(gnp),$
                  dlcal:fltarr(4,14),pgcal:ptr_new(0)}
return,gparm
end