;+
; NAME:
;	smei_buf_getframe
; PURPOSE:
;	Extracts individual frames from all *.buf files in the specified
;	source directory.
; CATEGORY:
;	camera/idl/buf
; CALLING SEQUENCE:
	FUNCTION smei_buf_getframe, trange, $
		source	= source	, $
		camera	= camera	, $
		count	= count 	, $
		dups_too= dups_too	, $
		usedb	= usedb 	, $
		silent	= silent
; INPUTS:
;	trange			array[n]; type: time structure
;						n=0: if not specified than all frames in all L1A files in
;								'source' are extracted.
;						n=1: extract frame for specified time
;						n=2: extract all frames between trange[0] and trange[1]
;						n>2: extract frames for specified times
; OPTIONAL INPUT PARAMETERS:
;	source=source	scalar, array; type: string
;						scalar: source directory containing L1A *.buf files
;						array : list of fully-qualified names of L1A files
;	camera=camera	scalar, array[2], array[3]
;						numbers 1, 2, or 3, identifying the cameras to be extracted
;						if 'camera' not set then all cameras are extracted.
;	/usedb			if set then an attempt is made to find a file pointer in the
;						first L1A file to be accessed close to trange[0] (by
;						looking for nearby frames in the SMEI data base).
;						(this is primarily used to replace corrupted frames in the
;						SMEI data base).
; OUTPUTS:
;	hdr 		array; type: smei_frm_hdr structure
; OPTIONAL OUTPUT PARAMETERS:
;	count=count 	scalar; type: integer
;						# frames returned in 'hdr'
; INCLUDE:
	@compile_opt.pro		; On error, return to caller
; CALLS:
;	InitVar, IsType, IsTime, CheckDir, FindAllFiles, smei_buf_read, boost
;	TimeSet, TimeUnit, TimeGet, where_common, TimeOp, TimeLimits
;	smei_property, destroyvar, smei_getfile
; EXTERNAL:
;	smei_buf_hdr__define, smei_frm_hdr__define
; PROCEDURE:
;	Frame headers are stored in the same order as they are read from the
;	L1A files, i.e. there will be contiguous groups of frames from each
;	L1A files. Each L1A file appears to be chronological, but subsequent
;	files overlap (because of the double dump?). As a result the frame
;	header array as a whole (from more than one L1A file) is probably not
;	chronological.
; MODIFICATION HISTORY:
;	MAR-2003, Paul Hick (UCSD/CASS; pphick@ucsd.edu)
;-

InitVar, dups_too, /key
InitVar, usedb	 , /key
InitVar, silent  , 0

InitVar, source, getenv('CDRD')
IF source[0] EQ '' THEN source = '/media/cdrecorder'

bad_result = {smei_frm_hdr}
usec = TimeUnit(/sec)

; Check for .buf files in source directory

CASE CheckDir(source[0]) OF
0: BEGIN
	buf_file = source
	count = n_elements(buf_file)
END
1: buf_file = FindAllFiles('*.buf', path=source, count=count)
ENDCASE

IF count EQ 0 THEN BEGIN
	message, /info, 'no *.buf files found in '+source
	RETURN, bad_result
ENDIF

IF IsTime(trange) THEN BEGIN

	IF n_elements(trange) NE 2 THEN BEGIN
		tall = trange
		trange = TimeLimits(trange, /bounds)
	ENDIF
	message, /info, 'extracting time range '+strjoin(TimeGet(trange,/_ydoy,upto=usec),' - ')

	; If trange is set then limit the files to be accessed to files containing
	; data inside time range

	hdr = replicate( {smei_buf_hdr}, count )

	FOR i=0L,count-1 DO	$
		IF smei_buf_read(buf_file[i], /get_file_header, file_header=tmp) THEN	$
			hdr[i] = tmp

	print

	;tmp = where(TimeOp(/subtract, trange[0], hdr.ut_stop , use ) LT 0 AND	$
	;			TimeOp(/subtract, trange[1], hdr.ut_start, usec ) GT 0 , count)
	tmp = where(TimeOp(/subtract, trange[0], hdr.ut_stop , usec ) LE 0 AND	$
				TimeOp(/subtract, trange[1], hdr.ut_start, usec ) GE 0 , count)

	IF count EQ 0 THEN BEGIN
		message, /info, 'no files with frames in this time range'
		RETURN, bad_result
	ENDIF

	buf_file = buf_file[tmp]
	trunc_time = trange[1]

	IF usedb THEN BEGIN

		tmp = smei_getfile(TimeOp(/subtract,trange[0],TimeSet(/diff,[61,1],usec)), camera=camera, count=cnt, /get_hdr )

		IF cnt NE 0 THEN BEGIN

			tmp = tmp[cnt-1]

			; Check one minute period prior to trange[0] for frames in the SMEI database
			; If a frame is found then the L1A pointer for that frame will be used to jump
			; into the L1A file(s) buf_file (in smei_buf_read).

			FOR i=0,n_elements(buf_file)-1 DO BEGIN
				IF smei_property(tmp,/l1a_file) EQ GetFileSpec(buf_file[i],part='name') THEN BEGIN
					pointer = smei_property(tmp,/l1a_pntr)
					message, /info, smei_property(tmp,/name)+'@'+strcompress(pointer,/rem)+' in '+smei_property(tmp,/l1a_file)
					buf_file = buf_file[i]
					count = 1
					break
				ENDIF ELSE	$
					message, /info, hide_env(buf_file[i])+', no location in SMEI data base found'
			ENDFOR

		ENDIF

print, buf_file

	ENDIF

ENDIF

; Read all frame headers

destroyvar, hdr 				; Don't remove !!

FOR i=0L,count-1 DO BEGIN
	IF smei_buf_read(buf_file[i], frame_headers=tmp, trunc_time=trunc_time,start_pointer=pointer, silent=silent) THEN BEGIN
		boost, hdr, tmp

		cnt = n_elements(tmp)
		IF cnt GT 1 THEN BEGIN
			dt = smei_property(tmp,/time)
			dt = TimeOp(/subtract, dt, dt[0], usec)
			dt = where( dt[1:cnt-1] LT dt[0:cnt-2], cnt )
			IF cnt NE 0 THEN BEGIN
				message, /info, 'file not in chronological order: '+buf_file[i]
				FOR j=0,cnt-1 DO print, '>>>>>  ', strjoin( $
					TimeGet( smei_property(tmp[dt[j]:dt[j]+1],/time), /_ydoy, upto=usec )+ $
					' ('+strcompress(tmp[dt[j]:dt[j]+1].frame_nr,/rem)+')'	$
					,' - ')
			ENDIF
		ENDIF
	ENDIF
ENDFOR

count = n_elements(hdr)

IF count EQ 0 THEN BEGIN
	message, /info, 'no frames found. Bummer, should not have happened'
	RETURN, bad_result
ENDIF

thdr = smei_property(hdr, /time)

IF IsTime(trange) THEN BEGIN

	; If trange is set only retain headers inside time range

	tmp = where(TimeOp(/subtract, thdr, trange[0], usec ) GE 0 AND	$
				TimeOp(/subtract, thdr, trange[1], usec ) LE 0, count)

	IF count EQ 0 THEN BEGIN
		message, /info, 'no frames in this time range'
		RETURN, bad_result
	ENDIF

	hdr  = hdr [tmp]
	thdr = thdr[tmp]

	IF IsType(tall, /defined) THEN BEGIN
		tmp  = where_common( TimeOp(/subtract,thdr,thdr[0],usec), TimeOp(/subtract,tall,thdr[0],usec), count=count )

		IF count EQ 0 THEN BEGIN
			message, /info, 'none of the frames found'
			RETURN, bad_result
		ENDIF

		hdr  = hdr [tmp]
		thdr = thdr[tmp]

		trange = tall
	ENDIF

ENDIF

; Check for cameras

IF IsType(camera, /defined) THEN BEGIN

	tmp = where_common(hdr.camera, camera, count=count)

	IF count EQ 0 THEN BEGIN
		message, /info, 'no frames for cameras '+strjoin( strcompress(camera,/rem), ' or ' )
		RETURN, bad_result
	ENDIF

	hdr  = hdr [tmp]
	thdr = thdr[tmp]

ENDIF

IF count GT 1 AND NOT dups_too THEN BEGIN

	nhdr = count

	; The L1A files appear to be in chronological order, but subsequent files overlap.
	; Each frame appears to be present twice in different L1A files (probably we are getting
	; both telemetry dumps).

	; Eliminate the double entries here. I'm not sure which frame is retained by
	; the IDL uniq function (probably the last).
	; Compare camera and time of frames.

	tmp = TimeGet(thdr, /_ydoy, upto=usec)+'_'+strcompress(hdr.camera,/rem)
	tmp = uniq(tmp, sort(tmp))

	count = n_elements(tmp)

	message, /info, strcompress(nhdr-count,/rem)+' dups;'+	$
		strcompress(count)+'/'+strcompress(nhdr,/rem)+' frames remain'

	; The sort operation maintains the original order of the entries in hdr.
	; Headers are grouped by file making extraction of frames by smei_buf_read faster.

	tmp  = tmp[sort(tmp)]
	hdr  = hdr [tmp]
	thdr = thdr[tmp]

ENDIF

RETURN, hdr  &  END
