;+
; Project     :	STEREO - SECCHI
;
; Name        :	COR1_PBSERIES()
;
; Purpose     :	Find COR1 pB series of 0,120,240 degrees
;
; Category    :	STEREO, SECCHI, COR1, Analysis
;
; Explanation :	This routine uses SCC_READ_SUMMARY to search through the
;               summary files to find sets of three COR1 images taken at the
;               polarizer angles (0,120,240) in sequence and within two minutes
;               of each other.
;
; Syntax      :	Result = COR1_PBSERIES( DATE, SPACECRAFT )
;
; Examples    :	CAT = COR1_PBSERIES( '27-Mar-2007', 'Ahead' )
;               SECCHI_PREP, CAT.FILENAME, HEADER, IMAGE
;
;               DATE = ['15-Feb-2007 11:30', '15-Feb-2007 15:00']
;               CAT = COR1_PBSERIES( DATE, 'Combined' )
;
; Inputs      :	DATE    = Either the date of observation, or a beginning and
;                         end time to search on.  When a single date is passed,
;                         the entire day is returned.  Otherwise, only the
;                         portion between the beginning and end dates are
;                         returned.
;
;               SPACECRAFT = Can be one of the following forms:
;
;                               'A'             'B'
;                               'STA'           'STB'
;                               'Ahead'         'Behind'
;                               'STEREO Ahead'  'STEREO Behind'
;                               'STEREO-Ahead'  'STEREO-Behind'
;                               'STEREO_Ahead'  'STEREO_Behind'
;
;                            Alternatively, the word "Combined" (or "C") tells
;                            the routine to look for simultaneous sequences in
;                            both spacecraft.
;
; Opt. Inputs :	None.
;
; Outputs     :	The result of the function is a structure array containing
;               various information about the files.  See SCC_READ_SUMMARY for
;               more details.  The FILENAME tag will contain a complete path to
;               the file.
;
;               The dimensions of the result will be (3,N), where the first
;               dimension represents the three polarization angles, and the
;               second dimension is the individual sequences.  If the
;               spacecraft is specified as "Combined", then the result is
;               returned with the dimensions (3,N,2), where the last dimension
;               represents the two spacecraft "A" and "B".
;
;               If no results are found, or an error occurs, then the single
;               value of -1 is returned, rather than a structure.
;
; Opt. Outputs:	None.
;
; Keywords    :	SSR     = If passed, has the following meaning:
;
;                               SSR=1   Synoptic data (default)
;                               SSR=2   Special event data
;                               SSR=3   Synoptic + Special event
;                               SSR=7   Space weather
;
;               COUNT   = Returns the number of sequences found.
;
;               VALID   = If set, then only series with no missing blocks
;                         (NMISSING LE 0) are returned.
;
;               SAME_SIZE = If set, then only images with the most common size
;                           during the period are returned.  This allows one to
;                           filter out special tests which may be run during
;                           part of the day.
;
;               SOURCE  = Telemetry source, either "rt" (realtime), "pb"
;                         (playback), or "lz" (level-zero, default).
;
;               POLAR   = Can be used to pass an alternate polarizer sequence
;                         to search for, e.g. POLAR=[0,60,120].
;
;                         If the POLAR keyword is not passed, the routine will
;                         first look for sequences of [0,120,240].  If not
;                         found, it will then try [0,240,120], and then
;                         [60,180,300].
;
;               COR2    = If set, search for COR2 images instead of COR1.
;
;               EXPMIN  = Mininum exposure time used to filter out unusual COR1
;                         images that are not part of the normal synoptic
;                         sequence.  Default is 0.1 (seconds).
;
;               ERRMSG  = If defined and passed, then any error messages will
;                         be returned to the user in this parameter rather than
;                         depending on the MESSAGE routine in IDL.  If no
;                         errors are encountered, then the input string is
;                         returned unchanged.  In order to use this feature,
;                         ERRMSG must be defined first, e.g.
;
;                               ERRMSG = ''
;                               Result = COR1_PBSERIES( ERRMSG=ERRMSG, ... )
;                               IF ERRMSG NE '' THEN ...
;
; Calls       :	ANYTIM2UTC, PARSE_STEREO_NAME, SCC_READ_SUMMARY, UTC2TAI,
;               FORM_HISTO, SCC_DATA_PATH, CONCAT_DIR, FILE_EXIST, FXHREAD
;
; Common      :	None.
;
; Restrictions: If the requested time period includes both sequences of
;               [0,120,240] and [60,180,300] (or [0,240,120]), then only images
;               corresponding to the first sequence found will be returned.
;               However, *known* transitions between these sequences are
;               accounted for.
;
; Side effects:	None.
;
; Prev. Hist. :	None.
;
; History     :	Version 1, 4-Apr-2007, William Thompson, GSFC
;               05-Apr-2007, WTT, Fixed bug with /SAME_SIZE keyword
;                                 Added keyword COUNT
;               06-Apr-2007, WTT, Fixed bug with /VALID and non-existent files.
;               28-Feb-2008, WTT, Added keyword COR2
;               03-Mar-2008, WTT, Accommodate change in scc_read_summary
;               07-Jul-2009, WTT, fixed path bug when used with /beacon
;		19-Nov-2009, WTT, make loop variable long
;               19-Sep-2011, WTT, fix typos
;               27-Nov-2012, WTT, Also try 60,180,300
;               12-Dec-2012, WTT, Also try 0,240,120
;               30-Sep-2013, WTT, allow combinations for known dates.
;               13-Nov-2014, WTT, correct bug when no data found.
;               03-Feb-2022, WTT, add EXPMIN keyword
;
; Contact     :	WTHOMPSON
;-
;
function cor1_pbseries, date, spacecraft, ssr=k_ssr, polar=k_polar, $
                        source=k_source, valid=valid, same_size=same_size, $
                        count=count, cor2=cor2, expmin=expmin, errmsg=errmsg, $
                        _extra=_extra
on_error, 2
;
;  Define the default SOURCE and POLAR angles.
;
if n_elements(k_source) eq 1 then source = k_source else source = 'lz'
if n_elements(k_polar)  eq 3 then polar  = k_polar  else polar  = [0,120,240]
;
;  Make sure that DATE is set correctly.
;
if n_elements(date) eq 0 then begin
    message = 'DATE is undefined'
    goto, handle_error
endif
if n_elements(date) gt 2 then begin
    message = 'DATE must have 1 or 2 elements'
    goto, handle_error
endif
message = ''
utc = anytim2utc(date, /ccsds, errmsg=message)
if message ne '' then goto, handle_error
;
;  Check the spacecraft name.
;
if n_elements(spacecraft) ne 1 then begin
    message = 'SPACECRAFT must be a scalar'
    goto, handle_error
endif
if datatype(spacecraft) ne 'STR' then begin
    message = 'SPACECRAFT must be either "A" or "B" (or "COMBINED")'
    goto, handle_error
endif
;
;  Handle cases where the date range spans over changes in the COR1-B polarizer
;  sequence.
;
sc = parse_stereo_name( spacecraft, ['A', 'B'])
if (n_elements(utc) eq 2) and (sc eq 'B') and (not keyword_set(cor2)) then begin
    bseq_dates = anytim2utc(['2012-11-29', '2012-12-04', '2012-12-12', $
                             '2013-04-30', '2013-09-25'], /ccsds)
    w = where((utc[0] lt bseq_dates) and (utc[1] gt bseq_dates), seqcount)
    if seqcount gt 0 then begin
        middate = bseq_dates[w[0]]
        cat1 = cor1_pbseries([utc[0],middate], sc, count=count1, ssr=k_ssr, $
                             polar=k_polar, valid=valid, source=k_source, $
                             same_size=same_size, cor2=cor2, errmsg=message)
        cat2 = cor1_pbseries([middate,utc[1]], sc, count=count2, ssr=k_ssr, $
                             polar=k_polar, valid=valid, source=k_source, $
                             same_size=same_size, cor2=cor2, errmsg=message)
        count = count1 + count2
        if count eq 0 then goto, no_results
        if count1 eq 0 then cat = cat2 else begin
            cat = cat1
            if count2 ne 0 then cat = [[cat], [cat2]]
        endelse
        return, cat
    endif
endif
;
;  If the spacecraft name was passed as "Combined", then find simultaneous pB
;  sequences for both spacecraft.
;
if strupcase(spacecraft) eq strmid('COMBINED',0,strlen(spacecraft)) then begin
    message = ''
    cata = cor1_pbseries(utc, 'A', ssr=k_ssr, polar=k_polar, valid=valid, $
                         source=k_source, same_size=same_size, cor2=cor2, $
                         errmsg=message)
    if message ne '' then goto, handle_error
    catb = cor1_pbseries(utc, 'B', ssr=k_ssr, polar=k_polar, valid=valid, $
                         source=k_source, same_size=same_size, cor2=cor2, $
                         errmsg=message)
    if message ne '' then goto, handle_error
;
;  Look for matching filenames.
;
    break_file, cata[0,*].filename, diska, dira, namea
    break_file, catb[0,*].filename, diskb, dirb, nameb
    namea = strmid(namea,0,15)
    nameb = strmid(nameb,0,15)
    match, namea, nameb, wa, wb, count=count
    if count eq 0 then goto, no_results
    return, reform([[cata[*,wa]], [catb[*,wb]]], 3, count, 2)
endif
;
;  Otherwise, parse the spacecraft name.
;
if (sc ne 'A') and (sc ne 'B') then begin
    message = 'Unrecognized spacecraft name ' + spacecraft
    goto, handle_error
endif
;
;  Read the summary files.
;
read_summary:
if keyword_set(cor2) then tel='COR2' else tel='COR1'
cat = scc_read_summary(date=utc, spacecraft=spacecraft, telescope=tel, $
                       type='seq', source=source, _extra=_extra)
if datatype(cat,1) ne 'Structure' then goto, no_results
;
;  Filter the data by the SSR keyword.
;
if n_elements(k_ssr) eq 1 then ssr = k_ssr else ssr=1
case ssr of
    2:    w = where(cat.dest eq 'SSR2', count)
    3:    w = where(cat.dest ne 'SW', count)
    7:    w = where(cat.dest eq 'SW', count)
    else: w = where(cat.dest eq 'SSR1', count)
endcase
if count gt 0 then cat = cat[w] else goto, no_results
;
;  Find all files with a polar angle of 0 degrees.
;
w0 = where(cat.value eq polar[0], count0)
if count0 eq 0 then goto, no_results
;
;  Make sure that there are at least two files after the last entry.
;
if n_elements(cat)-w0[count0-1] lt 3 then begin
    count0 = count0-1
    if count0 eq 0 then goto, no_results
    w0 = w0[0:count0-1]
endif
;
;  Check to see that the next files in sequence have a polar angle of 120
;  degrees, and the difference in time is no more than a minute.
;
tai = utc2tai(cat.date_obs, /nocorrect)
dtai = tai[w0+1] - tai[w0]
w1 = where((cat[w0+1].value eq polar[1]) and (dtai le 60), count1)
if count1 gt 0 then begin
    count0 = count1
    w0 = w0[w1]
end else goto, no_results
;
;  Check to see that the next files in sequence after that have a polar angle
;  of 240 degrees, and the difference in time is no more than two minutes.
;
dtai = tai[w0+2] - tai[w0]
w2 = where((cat[w0+2].value eq polar[2]) and (dtai lt 120), count2)
if count2 gt 0 then begin
    count0 = count2
    w0 = w0[w2]
end else goto, no_results
;
;  Concatenate all the results together.
;
w = transpose([[w0],[w0+1],[w0+2]])
cat = cat[w]
;
;  If the SAME_SIZE keyword was passed, then select out the most common size of
;  the day.
;
if keyword_set(same_size) then begin
    message = ''
    form_histo, cat.xsize, sx, hx, delta=1, errmsg=message
    if message eq '' then begin
        xsize = sx[where(hx eq max(hx))]
        xsize = xsize[0]
    end else xsize = cat[0].xsize
;
    message = ''
    form_histo, cat.ysize, sy, hy, delta=1, errmsg=message
    if message eq '' then begin
        ysize = sy[where(hy eq max(hy))]
        ysize = ysize[0]
    end else ysize = cat[0].ysize
;
    test = total( (cat.xsize eq xsize) and (cat.ysize eq ysize), 1 )
    w = where(test eq 3, count0)
    if count0 eq 0 then goto, no_results
    cat = cat[*,w]
endif
;
;  Step through the files, and determine the path.  If the VALID keyword was
;  passed, then check to make sure that NMISSING <= 0.
;
filename = strarr(3,count0)
for iseries = 0L,count0-1 do begin
    for ipolar = 0,2 do begin
        cat0 = cat[ipolar,iseries]
        path = scc_data_path(cat0.spacecraft, source=source, type=cat0.type, $
                             telescope=cat0.telescope, date=cat0.date_obs, $
                             _extra=_extra)
        filename = concat_dir(path, cat0.filename)
        cat[ipolar,iseries].filename = filename
        nmissing = 999
        if keyword_set(valid) then begin
            if file_exist(filename) then begin
                openr, unit, filename, /get_lun
                fxhread, unit, header, status
                free_lun, unit
                if status eq 0 then nmissing = fxpar(header, 'nmissing')
            endif
            if nmissing gt 0 then begin
                cat[*,iseries].filename = ''
                goto, next_series
            endif
        endif
    endfor
next_series:
endfor
;
w = where(cat[0,*].filename ne '', count)
if count gt 0 then cat=cat[*,w] else goto, no_results
;
;  Remove some "extra" COR1 images that are not part of the desired synoptic
;  observations.
;
if (not keyword_set(cor2)) then begin
    if not keyword_set(expmin) then expmin = 0.1
    w = where((cat[0,*].dest eq 'SW') or ((cat[0,*].xsize ge 512) and $
              (cat[0,*].exptime gt expmin)), npb)
    if npb ne 0 then cat = cat[*,w]
endif
;
return, cat
;
;  Error point for no results.  If [0,120,240] not found, then try [0,240,120],
;  followed by [60,180,300].
;
no_results:
if (n_elements(k_polar) ne 3) and (polar[0] eq 0) then begin
    if polar[1] eq 120 then polar = [0,240,120] else polar = [60,180,300]
    goto, read_summary
endif
message = 'No results found'
;
;  Point for general error handling.
;
handle_error:
if n_elements(errmsg) eq 0 then message, message, /continue else $
  errmsg = message
count = 0
return, -1
end
