;+

;PROCEDURE:	get_en_spec

;PURPOSE:	

;	Generates energy-time spectrogram data structures for tplot

;INPUT:		

;	get_dat, 	a string that defines the 'routine' that returns a 2D or 3D data structure

;			if 'probe' keyword set, assumes routine = get_dat

;			if 'probe' keyword is not set, assumes routine = 'get_'+ get_dat

;				unless get_dat already includes 'get_', in which case routine = get_dat

;			for example, get_dat='thc_peir' then routine = 'get_thc_peir'

;			for example, get_dat='thm_sst_pser' then routine = 'thm_sst_pser'

;

;KEYWORDS:

;	T1:		start time, seconds since 1970

;	T2:		end time, seconds since 1970		

;	ANGLE:		fltarr(2),fltarr(4)	angle range to sum over

;	ARANGE:		intarr(2)		bin range to sum over

;	BINS:		bytarr(dat.nbins)	bins to sum over

;	gap_time: 	time gap big enough to signify a data gap 

;			(default 200 sec, 8 sec for FAST)

;	NO_DATA: 	returns 1 if no_data else returns 0

;	UNITS:		convert to these units if included

;	NAME:  		New name of the Data Quantity, default = get_dat + '_en_spec'

;	BKG:  		A 3d data structure containing the background counts 

;			If bkg=1, it will run themis background subtraction routine

;	FLOOR:  	Sets the minimum value of any data point to sqrt(bkg).

;	MISSING: 	value for bad data.

;	RETRACE: 	Set to number of retrace energy steps to be eliminated starting at energy step 0

;	CALIB:		Calib keyword passed on to get_dat -- no longer used

;	PROBE:		probe keyword passed on to get_dat -- used by themis sst routines

;

;

;

;CREATED BY:	J.McFadden

;VERSION:	1

;LAST MODIFICATION:  97/03/04

;MOD HISTORY:

;		97/03/04	T1,T2 keywords added

;		97/05/22	CALIB keyword added

;		08/07/10	bkg keyword changed to work for Themis ion ESA

;		08/07/10	averaging routine changed to weight different angle bins by dat.gf 

;		08/12/31	bkg keyword changed to work for Themis electron sst

;		08/12/31	probe keyword added for themis sst routines

;		09/01/05	changed loop to use index to allow for dat.valid=0 data in stored data

;		09/01/05	calib keyword no longer passed to routine

;		09/04/16	bkg keyword removed for Themis electron sst, assume bkg removal is part of get_th?_pse?

;

;

;NOTES:	  

;	Current version only works for FAST and THEMIS

;-



pro get_en_spec,get_dat,  $

	T1=t1, $

	T2=t2, $

;	ENERGY=en, $

;	ERANGE=er, $

;	EBINS=ebins, $

	ANGLE=an, $

	ARANGE=ar, $

	BINS=bins, $

	gap_time=gap_time, $ 

	no_data=no_data, $

	units = units,  $

        name  = name, $

	bkg = bkg, $

        missing = missing, $

        floor = floor, $

        retrace = retrace, $

        CALIB = calib, $

	probe = probe







;	Time how long the routine takes

ex_start = systime(1)



;	Set defaults for keywords, etc.



n = 0l

all_same = 1





if strlowcase(strmid(get_dat,0,4)) eq 'get_' then begin

	routine = get_dat

	get_dat = strlowcase(strmid(get_dat,4,strlen(get_dat)))

endif else if keyword_set(probe) then begin

	routine = get_dat

endif else routine = 'get_'+get_dat 



if keyword_set(probe) then times = call_function(routine,probe=probe,/times) else times = call_function(routine,/times)

maxind = n_elements(times)-1



if keyword_set(t1) then tmpmax=min(abs(times-time_double(t1)),idx) else idx=1l

if keyword_set(t2) then tmpmax=min(abs(times-time_double(t2)),idxmax) else idxmax=maxind





if keyword_set(probe) then begin

	dat = call_function(routine,probe=probe,index=idx) 

	while (dat.valid eq 0 and idx lt idxmax) do begin

		idx = idx + 1

		dat = call_function(routine,probe=probe,index=idx)

	endwhile

endif else begin

	dat = call_function(routine,index=idx)

	while (dat.valid eq 0 and idx lt idxmax) do begin

		idx = idx + 1

		dat = call_function(routine,index=idx)

	endwhile

endelse





;if keyword_set(t1) then begin

;	t=t1

;	if keyword_set(calib) then dat = call_function(routine,t,CALIB=calib) $

;		else if keyword_set(probe) then dat = call_function(routine,t,probe=probe,index=idx) $

;		else if routine eq 'get_fa_sebs' then dat = call_function(routine,t,/first) $

;		else dat = call_function(routine,t)

;endif else begin

;	t = 1000             ; get first sample

;	idx=0

;	if keyword_set(calib) then dat = call_function(routine,t,CALIB=calib,/start) $

;		else if keyword_set(probe) then dat = call_function(routine,probe=probe,index=idx) $

;		else if routine eq 'get_fa_sebs' then dat = call_function(routine,t,/first) $

;		else dat = call_function(routine,t,/start)

;endelse

;if dat.valid eq 0 then begin no_data = 1 & return & end $

;else no_data = 0





ytitle = get_dat + '_en_spec'

last_time = (dat.time+dat.end_time)/2.

nbins = dat.nbins

nmaxvar = dat.nenergy



default_gap_time = 200.

if dat.project_name eq 'FAST' then begin

	nmaxvar=96

	default_gap_time = 8.

endif

if strupcase(strmid(dat.project_name,0,6)) eq 'THEMIS' then begin

	nmaxvar=32

	default_gap_time = 13.

endif

if not keyword_set(gap_time) then gap_time = default_gap_time



maxpts = idxmax-idx+1000 < 300000l			; this limits a tplot str to < 77 MBytes

time   = dblarr(maxpts)

data   = fltarr(maxpts,nmaxvar)

var   = fltarr(maxpts,nmaxvar)

nvar = dat.nenergy

nmax=nvar



if not keyword_set(units) then units = 'Counts'

if not keyword_set(missing) then missing = !values.f_nan







;	Collect the data - Main Loop

    

; May want to use the following lines when "index" is operational in FAST get* routines    

;times = call_function(routine,t,CALIB=calib, /times)

;for idx=0,n_elements(times)-1 do begin

;    if (dat.valid eq 0) or (n ge maxpts) then  goto, continue  ; goto YUCK!





;while (dat.valid ne 0) and (n lt maxpts) do begin

while (idx lt idxmax) and (n lt maxpts) do begin



if (dat.valid eq 1) then begin



	if ndimen(dat.data) eq ndimen(dat.bins) then dat.data=dat.data*dat.bins

	count = dat.nbins

	if keyword_set(an) then begin

		str_element,dat,'PHI',INDEX=tf_phi

		if tf_phi lt 0 then bins=angle_to_bins(dat,an)

		if tf_phi gt 0 then begin

			th=reform(dat.theta(0,*)/!radeg)

			ph=reform(dat.phi(fix(dat.nenergy/2),*)/!radeg)

			xx=cos(ph)*cos(th)

			yy=sin(ph)*cos(th)

			zz=sin(th)

			Bmag=(dat.magf(0)^2+dat.magf(1)^2+dat.magf(2)^2)^.5

			pitch=acos((dat.magf(0)*xx+dat.magf(1)*yy+dat.magf(2)*zz)/Bmag)*!radeg

			if an(0) gt an(1) then an=reverse(an)

			bins= pitch gt an(0) and pitch lt an(1)

			if total(bins) eq 0 then begin

				tmp=min(abs(pitch-(an(0)+an(1))/2.),ind)

				bins(ind)=1

			endif

		endif

	endif

	if keyword_set(ar) then begin

		nb=dat.nbins

		bins=bytarr(nb)

		if ar(0) gt ar(1) then begin

			bins(ar(0):nb-1)=1

			bins(0:ar(1))=1

		endif else begin

			bins(ar(0):ar(1))=1

		endelse

	endif

; Set the "count" to the number of bins summed over



	if not keyword_set(bins) then ind=indgen(dat.nbins) else ind=where(bins,count)

	if max(ind) gt dat.nbins-1 then ind=-1

	if units eq 'Counts' or units eq 'counts' then norm = 1 else norm = count



	if abs((dat.time+dat.end_time)/2.-last_time) ge gap_time then begin

		if n ge 2 then dbadtime = time(n-1) - time(n-2) else dbadtime = gap_time/2.

		time(n) = (last_time) + dbadtime

		data(n,*) = missing

		var(n,*) = missing

		n=n+1

		if (dat.time+dat.end_time)/2. gt time(n-1) + gap_time then begin

			time(n) = (dat.time+dat.end_time)/2. - dbadtime

			data(n,*) = missing

			var(n,*) = missing

			n=n+1

		endif

	endif



	if keyword_set(bkg) then begin

; sub3d requires bkg to be the subtraction array -- sub3d is a general routine and works similar to the pse routine

		if ndimen(bkg) ne 0 then dat = sub3d(dat,bkg) $

;		else if dat.UNITS_PROCEDURE eq 'thm_convert_esa_units' then dat=thm_esa_bgnd_sub(dat) $ ; old routine

		else if dat.UNITS_PROCEDURE eq 'thm_convert_esa_units' and dat.charge gt 0. then dat=thm_pei_bkg_sub(dat) $ 

		else if dat.UNITS_PROCEDURE eq 'thm_convert_esa_units' and dat.charge lt 0. then dat=thm_pee_bkg_sub(dat) 

;		else if strmid(dat.DATA_NAME,0,12) eq 'SST Electron' then dat=thm_pse_bkg_sub(dat) ; added to get_routine

	endif

	if keyword_set(units) then dat = conv_units(dat,units)



	nvar = dat.nenergy

	if nvar gt nmax then nmax = nvar

	time(n)   = (dat.time+dat.end_time)/2.

	if ind(0) ne -1 then begin

		if ndimen(dat.data) gt 1 and n_elements(ind) gt 1 then begin

			if units eq 'Counts' or units eq 'counts' then begin

				data(n,0:nvar-1) = total( dat.data(*,ind), 2)/norm

				var(n,0:nvar-1) = total( dat.energy(*,ind), 2)/count

			endif else begin

				data(n,0:nvar-1) = total( dat.data(*,ind)*dat.gf(*,ind), 2)/total(dat.gf(*,ind),2)

				var(n,0:nvar-1) = total( dat.energy(*,ind), 2)/count

			endelse

		endif else if ndimen(dat.data) gt 1 then begin

			data(n,0:nvar-1) = dat.data(*,ind)/norm

			var(n,0:nvar-1) = dat.energy(*,ind)/count

		endif else begin

			data(n,0:nvar-1) = dat.data(*)

			var(n,0:nvar-1) = dat.energy(*)

		endelse

	endif else begin

		data(n,0:nvar-1) = 0

		var(n,0:nvar-1) =  dat.energy(*,0)

	endelse



; test the following lines, the 96-6-19 version of tplot did not work with !values.f_nan

;	if nvar lt nmaxvar then data(n,nvar:nmaxvar-1) = !values.f_nan

;	if nvar lt nmaxvar then var(n,nvar:nmaxvar-1) = !values.f_nan

	if nvar lt nmaxvar then data(n,nvar:nmaxvar-1) = data(n,nvar-1)

	if nvar lt nmaxvar then var(n,nvar:nmaxvar-1) = 1.5*var(n,nvar-1)-.5*var(n,nvar-2)



	if (all_same eq 1) then begin

		if dimen1(where(var(n,0:nvar-1) ne var(0,0:nvar-1))) gt 1 then all_same = 0

	endif

	last_time = time(n)

	n=n+1



endif else begin

	print,'Invalid packet, dat.valid ne 1, at: ',time_to_str(dat.time)

endelse

	idx=idx+1

	if keyword_set(probe) then dat = call_function(routine,probe=probe,index=idx) else dat = call_function(routine,index=idx)



;	if keyword_set(probe) then idx=idx+1

;	if keyword_set(calib) then dat = call_function(routine,t,CALIB=calib,/ad) $

;		else if keyword_set(probe) then dat = call_function(routine,probe=probe,index=idx) $

;		else dat = call_function(routine,t,/ad)

;;	dat = call_function(routine,t,CALIB=calib,index=idx)

;	if dat.valid ne 0 then if dat.time gt tmax then dat.valid=0



endwhile

;endfor

;continue:













;	Store the data



	if count ne nbins then ytitle = ytitle+'_'+strtrim(count,2)

	if keyword_set(name) eq 0 then name=ytitle else ytitle = name

	ytitle = ytitle+' ('+units+')'



if not keyword_set(retrace) then begin

;	If you want to plot the retrace, set the retrace flag to 1.

	data = data(0l:n-1,0:nmax-1)

	var = var(0l:n-1,0:nmax-1)

endif else begin

	data = data(0l:n-1,retrace:nmax-1)

	var = var(0l:n-1,retrace:nmax-1)

endelse





if not all_same then print,'all_same=',all_same

;labels=''

; The following has be removed so that FAST summary cdf files contain both arrays

;if all_same then begin

;	var = reform(var(0,*))

;	labels = strtrim( round(var) ,2)+ ' eV'

;endif



time = time(0l:n-1)



print,'get_en_spec time range = ',time_string(minmax(time))

;if keyword_set(t1) then begin

;	ind=where(time ge t1,count)

;	print,count

;	if count ne 0 then begin

;		time=time(ind) 

;		data=data(ind,*)

;		var=var(ind,*)

;	endif else return

;endif

;if keyword_set(t2) then begin

;	ind=where(time le t2,count)

;	print,count

;	if count ne 0 then begin

;		time=time(ind)

;		data=data(ind,*)

;		var=var(ind,*)

;	endif else return

;endif



; remove any negative values caused by background subtractions

	data=data>0.



;datastr = {ztitle:units,x:time,y:data,v:var,  $

;	labels:labels,	$

;    ylog:1,panel_size:2.}

datastr = {x:time,y:data,v:var}

store_data,name,data=datastr



ex_time = systime(1) - ex_start

message,string(ex_time)+' seconds execution time.',/cont,/info

print,'Number of data points = ',n



return



end