PRO read_xrt, files, index, data,                                    $
              nodata=nodata,   force=force, strtemplate=strtemplate, $
              ss_read=ss_read, ss_noread=ss_noread, verbose=verbose, $
              quiet=quiet, qabort=qabort,   qstop=qstop, nohistupd=nohistupd

; =========================================================================
;+
; PROJECT:
;       Solar-B / XRT 
;
; NAME:
;       
;       READ_XRT
;
; CATEGORY:
;       
;       File I/O.
;
; PURPOSE:
;       
;       Read XRT data image files--- just headers, or headers and data.
;
; CALLING SEQUENCE:
;
;       READ_XRT, files, index [,data] [,/nodata] [,/force]      $
;                 [,/verbose] [,/quiet] [,/qstop] [,qabort=qabort]
;       
; INPUTS:
;       
;       FILES        - [Mandatory] (string or string array, [Nimg])
;                      FITS filenames to read, of number Nimg.
;
; KEYWORDS:
;       
;	/NODATA      - [Optional] (Boolean) Read in headers only, not data.  
;                      Set automatically if no parameter to store data is 
;                      passed in. /NODATA overrides /FORCE.
;       /FORCE       - [Optional] (Boolean) This allows you to read in a set 
;                      of images even if they have different array sizes.
;                      Keyword not necessary if only "index" is requested,
;                      or if the images are all the same size. See Note #2.
;                      /FORCE is overridden by /NODATA.
;       /STRTEMPLATE - [Optional] (Structure scalar)
;                      This keyword is passed through to <mreadfits.pro>.
;                      It is included here to facilitate some automatic
;                      processing of the data archive.
;       SS_READ      - [Optional] (Long array, [Nfoundimg])
;                      Should be input as a named variable.
;                      Output is the list of FILES indices for files found.
;                      See Note #5.
;       SS_NOREAD    - [Optional] (Long array, [Nimg-Nfoundimg])
;                      Should be input as a named variable.
;                      Output is the list of FILES indices for files NOT
;                      found.
;                      See Note #5.
;	/VERBOSE     - [Optional] (Boolean) If set, print out extra
;                      information. Overrides "/quiet" (see Note #3).
;       /QUIET       - [Optional] (Boolean) If set, suppress messages 
;                      (see Note #3).
;       /QSTOP       - [Optional] (Boolean) For debugging.
;       /NOHISTUPD   - [Optional] (Boolean) If set, suppress updating of the
;                      HISTORY record in the index structure
;
; OUTPUTS:
;       
;       INDEX        - [Mandatory] (structure, or structure array, [Nfoundimg])
;                      FITS header keywords. One structure per image.
;                      See Note #5.
;       DATA         - [Optional] (integer array, [Nx,Ny,Nfoundimg]) 
;                      Data array/cube, depending on whether 1 or multiple 
;                      files are input (follows format of read_trace.pro).
;                      See Note #5.
;       QABORT       - [Optional] (Boolean) Indicates that the program
;                      exited gracefully without completing. (Might be
;                      useful for calling programs.)
;                      0: Program ran to completion.
;                      1: Program aborted before completion.
;
; EXAMPLES:
;      
;       Two ways to read just the "index":
;       IDL> read_xrt, files, index
;       IDL> read_xrt, files, index, data, /nodata
;
;       Read "index" and "data" for images of mixed sizes:
;       IDL> read_xrt, files, index, data, /force
;
;       Same thing, but turn off the "READFITS" messages
;       and error messages:
;       IDL> read_xrt, files, index, data, /force, /quiet
;
;       Same thing, but turn on all messages:
;       IDL> read_xrt, files, index, data, /force, /verbose
;
; COMMON BLOCKS:
;
; 	none 
;
; NOTES:
;
;       1) If no "data" is requested, just the "index", then all
;          files will be read, regardless of mixed image sizes.
;
;       2) If the "force" keyword is used to read image data of 
;          various sizes, the "data" array will be given the maximum
;          required dimensions. Smaller images will be embedded in the
;          lowest corner of the respective 2D slice, with zero values in
;          the buffer pixels.
;
;       3) There are three levels of verbosity.
;          a) "verbose" = highest priority. All errors and messages are
;                         displayed. ("if q_vb")
;          b) "quiet" = lower priority. No errors or messages are
;                       displayed. ("if q_qt")
;          c) neither = lowest priority. All errors and some messages are
;                       displayed. ("if not q_qt")
;
;       4) The "index.HISTORY" is updated to reflect the origin file
;          of the data unless the keyword nohistupd is set.
;
;       5) This program only reads the files that it can find. 
;          Therefore, the "Nfoundimg" dimension of the returned INDEX
;          and DATA may be less than the "Nimg" of the input FILES.
;          The keyword SS_READ reports which of the input FILES were
;          found. The keyword SS_NOREAD reports which of the input FILES 
;          were NOT found.
;
; CONTACT:
;
;       Comments, feedback, and bug reports regarding this routine may be 
;       directed to this email address: 
;                xrt_manager ~at~ head.cfa.harvard.edu 
;       
; MODIFICATION HISTORY:
;
progver = 'v2006-Apr-29' ;--- (J.Cirtain (SAO)) Written. (Based on 
;                             <read_trace.pro>.)
progver = 'v2006-Aug-01' ;--- (LLL) Use "mreadfits.pro" for reading
;                             multiple files. Add keywords "loud", 
;                             "quiet", and "nodata". 
progver = 'v2006-Nov-07' ;--- (PRJ) Added the "force" keyword to handle
;                             different image sizes.
progver = 'v2006-Nov-30' ;--- (MW) Cleaned up the formatting and remarks.
;                             Also fixed it so that "force" is not needed 
;                             if "nodata" is set.
progver = 'v2007-Feb-13' ;--- (MW) Fixed a "nodata" passing to
;                             <xrt_mreadfits.pro> to use "q_nodata". This
;                             eliminates a scenario of unnecessary
;                             data reading.
progver = 'v2007-May-09' ;--- (MW) Fixed text for Note #2.
progver = 'v2007-May-18' ;--- (MW) No longer crashes for invalid filenames.
;                             Added SS_READ and SS_NOREAD keywords. 
;                             Added Note #5.
progver = 'v2007-May-22' ;--- (MW) Tuned for performance: Don't read files
;                             twice if you only want the index. Also fixed
;                             the /verbose prints to appear consistently.
progver = 'v2007-May-23' ;--- (MW) Fixed some internal keyword state 
;                             clashes.
progver = 'v2014-May-27' ;--- (JDS) Added nohistupd keyword to suppress 
;                             updating the HISTORY record
;                      
;-
; =========================================================================


;=== Initial setup =======================================

  ;=== Set Booleans which control print statements.
  ;=== Keyword "verbose" overrules "quiet".
  q_vb = keyword_set(verbose)
  q_qt = keyword_set(quiet) and (not q_vb)
  q_hstupd = (not keyword_set(nohistupd))
  ;=== Initialize program constants.
  prognam='READ_XRT'
  prognul='        '

  ;=== Announce version of <read_xrt.pro>.
  if q_vb then box_message, 'READ_XRT: Running ' + prognam + $
                            ' ' + progver + '.'
  if q_vb then print, 'READ_XRT: Performing initial setup...'

  ;=== Set some keyword Booleans.
  q_force   = keyword_set(force)
  qstop   = keyword_set(qstop)
  qabort  = 0B

  ;=== Don't read data if no output specified.
  q_data = (n_params() eq 3) and (keyword_set(nodata) eq 0)

  if q_vb then print, '                                  ...OK'


;=== Check inputs ========================================

  if q_vb then print, 'READ_XRT: Checking inputs...'

  ;=== Check for number of inputs.
  if ((n_params() lt 2) or (n_params() gt 3)) then begin
    if (not q_qt) then box_message, 'READ_XRT: Incorrect number of ' $
                                    + 'parameters. Aborting.'
    qabort = 1B
    return
  endif

  ;=== Check whether files exist.
  ss_read   = file_exist(files)
  ss_noread = where(ss_read eq 0)
  ss_read   = where(temporary(ss_read) eq 1, nf)
  if (nf ne n_elements(files)) then begin
    if (not q_qt) then box_message, ['READ_XRT: Cannot find all of ' $
              + 'the files. Only reading found files.', '          ' $
              + '(Try SS_NOREAD keyword.)']
  endif

  ;=== Check whether ANY files were found.
  if (nf eq 0) then begin
    if (not q_qt) then box_message,                       $
      ['READ_XRT: Cannot find ANY of the files. Aborting.']
    qabort = 1B
    return
  endif

  if q_vb then print, '                         ...OK'


;=== Make preparations to read files =====================

  if q_vb then print, prognam+': Reading the files...'

  ;=== Currently assuming flat fits always. 
  if q_vb then print, 'READ_XRT: Flat fits assumed.'

  ;=== This block reads in the index and checks to see that all files 
  ;=== have same size data (if the data is going to be read). 
  if (q_vb and q_data) then                                      $
               print, prognam+': Checking if image sizes match...'
  xrt_mreadfits, files[ss_read], test_index, /nodata, $
                 quiet=quiet, strtemplate=strtemplate

  if q_data then begin

    ;=== If can't find tags, and want data, then abort.
    if (not required_tags(test_index, 'NAXIS1,NAXIS2')) then begin
      if (q_qt eq 0) then box_message, $
        [prognam+': Cannot ascertain the relative sizes of the data.', $
         prognul+'  (NAXIS1,NAXIS2) are missing. Aborting.']
      qabort = 1B
      return

    ;=== If did find tags, then actually compare image sizes.
    endif else begin
      nx = gt_tagval(test_index, /naxis1)
      ny = gt_tagval(test_index, /naxis2)
      size_different = bytarr(nf)
      for ii = 0, (nf-1) do begin 
        size_different[ii] = (nx[ii] ne nx[0]) or (ny[ii] ne ny[0])
      endfor

      ;=== If all sizes not the same AND want data:
      if ((total(size_different) ne 0) and (q_force eq 0)) then begin 
        if (not q_qt) then box_message,                                $
          [prognam+': Files must have same size data, OR you must use', $
           prognul+'  the /FORCE keyword. Aborting.']
        qabort = 1B
        return
      endif

    endelse
  endif

  if (q_vb and q_data) then                                      $
             print, prognul+'                               ...OK'


;=== If DATA, then read files ============================

    ;=== If reading data.
    if q_data then begin

      ;=== If using the "/force" keyword, then issue a warning:
      if (q_force and (not q_qt)) then begin
        box_message, $
          ['READ_XRT: Buffer pixels will be added adjacent to the smaller', $
           '          images so that they fit into the datacube.']
      endif

      ;=== Read in the files.
      qnodata = (q_data eq 0)
      xrt_mreadfits, files[ss_read], index, data, nodata=qnodata, $
                     quiet=quiet, strtemplate=strtemplate
 
    ;=== Else if not reading data then just use previous index.
    endif else begin
      index = test_index
    endelse

    if q_vb then print, '                           ...OK'


;=== Update HISTORY ======================================

  ;=== If image header contains the HISTORY tag, then update.
  if required_tags(index, 'HISTORY', loud=q_verbose) and $
      q_hstupd then begin
    if q_vb then print, 'READ_XRT: Updating HISTORY...'
    hist_prefix = prognam + ' ' + progver + ': (' + systim() + ') '
    if (q_data eq 0) then begin
      hist_entry0 = 'Read header only. Origin file: ' + $
                    strip_dirname(files[ss_read])
    endif else begin
      hist_entry0 = 'Read header + data. Origin file: ' + $
                    strip_dirname(files[ss_read])
    endelse
    hist_entry  = hist_prefix + hist_entry0
    update_history, index, hist_entry, /mode, /noroutine
    if q_vb then print, '                          ...OK'
  endif


if qstop then stop


END ;======================================================================
