;+
;
; Laboratory for Atmospheric and Space Physics
; University of Colorado, Boulder, Colorado, USA
;
; FILENAME:
;   generate_level_4.pro
;
; AUTHOR:
;   Dain Cilke
;
; DATE:    16 October 2009
;
; PURPOSE:
;   Generate a level_2 file using 1B data
;
; REFERENCES:
;   level_2_retrieval_server__define.pro
;
; USAGE EXAMPLE:
; stack = generate_level_2(level_1b, filler, orbit_info)
;
;-

Function make_common_volume, level_2_retrievals

	level_2cvcv=level_2_retrievals
	if SIZE( *level_2_retrievals.common_volume_map, /TYPE ) EQ 10 THEN BEGIN
		cv_index = WHERE( *(*level_2_retrievals.common_volume_map) Eq 1)
	ENDIF ELSE BEGIN
		cv_index = WHERE( *level_2_retrievals.common_volume_map Eq 1)
	ENDELSE
	
	If cv_index[0] Ne -1 Then Begin
		level_2cv.cld_albedo            =PTR_NEW(FLOAT((*(level_2cv.cld_albedo            ))[cv_index]))
		level_2cv.cld_albedo_unc        =PTR_NEW(FLOAT((*(level_2cv.cld_albedo_unc        ))[cv_index]))
		level_2cv.particle_radius       =PTR_NEW(FLOAT((*(level_2cv.particle_radius       ))[cv_index]))
		level_2cv.particle_radius_unc   =PTR_NEW(FLOAT((*(level_2cv.particle_radius_unc   ))[cv_index]))
		level_2cv.zenith_angle_ray_peak =PTR_NEW(FLOAT((*(level_2cv.zenith_angle_ray_peak ))[cv_index]))
		level_2cv.ut_time               =PTR_NEW(FLOAT((*(level_2cv.ut_time               ))[cv_index]))
		level_2cv.ratall     			=PTR_NEW(FLOAT((*(level_2cv.ratall     ))[cv_index]))
		IF ptr_valid( level_2cv.CLOUD_PRESENCE_MAP) THEN  level_2cv.CLOUD_PRESENCE_MAP = PTR_NEW(FLOAT((*(level_2cv.CLOUD_PRESENCE_MAP     ))[cv_index]))
		level_2cv.LATITUDE     			=PTR_NEW(FLOAT((*(level_2cv.LATITUDE     ))[cv_index]))
		level_2cv.LONGITUDE     		=PTR_NEW(FLOAT((*(level_2cv.LONGITUDE     ))[cv_index]))
		level_2cv.CLD_PHASE_ALBEDO     	=PTR_NEW(FLOAT((*(level_2cv.CLD_PHASE_ALBEDO     ))[cv_index]))
		level_2cv.CLD_PHASE_ALBEDO_UNC  =PTR_NEW(FLOAT((*(level_2cv.CLD_PHASE_ALBEDO_UNC     ))[cv_index]))
		level_2cv.ZENITH_ANGLE_RAY_PEAK =PTR_NEW(FLOAT((*(level_2cv.ZENITH_ANGLE_RAY_PEAK     ))[cv_index]))
		level_2cv.VIEW_ANGLE_RAY_PEAK   =PTR_NEW(FLOAT((*(level_2cv.VIEW_ANGLE_RAY_PEAK     ))[cv_index]))
		level_2cv.SCATTERING_ANGLE     	=PTR_NEW(FLOAT((*(level_2cv.SCATTERING_ANGLE     ))[cv_index]))
		level_2cv.ICE_WATER_CONTENT     =PTR_NEW(FLOAT((*(level_2cv.ICE_WATER_CONTENT     ))[cv_index]))
		level_2cv.ICE_WATER_CONTENT_UNC =PTR_NEW(FLOAT((*(level_2cv.ICE_WATER_CONTENT_UNC     ))[cv_index]))
		level_2cv.OZONE_COL_DENSITY     =PTR_NEW(FLOAT((*(level_2cv.OZONE_COL_DENSITY     ))[cv_index]))
		level_2cv.OZONE_COL_DENSITY_UNC =PTR_NEW(FLOAT((*(level_2cv.OZONE_COL_DENSITY_UNC     ))[cv_index]))
		level_2cv.SCALE_HEIGHT_RATIO    =PTR_NEW(FLOAT((*(level_2cv.SCALE_HEIGHT_RATIO     ))[cv_index]))
		level_2cv.SCALE_HEIGHT_RATIO_UNC=PTR_NEW(FLOAT((*(level_2cv.SCALE_HEIGHT_RATIO_UNC     ))[cv_index]))
	Endif
	HEAP_GC
	RETURN,level_2cv
End

Function generate_retrievals, l1b_data, l2a_data, l2_data, orbit_info

	hemisphere_flag = l2a_data.hemisphere
	revision = '01'
	season = get_season(usec2la(orbit_info[0].start_time), hemisphere_flag = hemisphere_flag)
	l2cat_fn = get_retrieval_filename(orbit_info=orbit_info, season=season, /cat, $
		/net_cdf, prelim=orbit_info.preliminary,path=path, revision=revision)
	l2cld_fn = get_retrieval_filename(orbit_info=orbit_info, season=season, /cld, $
		/net_cdf, prelim=orbit_info.preliminary,path=path, revision=revision)
	l2psf_fn = get_retrieval_filename(orbit_info=orbit_info, season=season, /psf, $
		/net_cdf, prelim=orbit_info.preliminary, revision=revision)
	l2ozo_fn = get_retrieval_filename(orbit_info=orbit_info, season=season, /ozo, $
		/net_cdf, prelim=orbit_info.preliminary, revision=revision)
		
	If ~FILE_TEST(l2cat_fn) Then Begin
	
		retrieval=get_retrieval_structure()
		; ------------------------------------------------------
		; Calculate any fields that could not be
		; directly pulled off of the stack or filler structures
		; ------------------------------------------------------
		retrieval.aim_orbit_number 		= l2a_data.aim_orbit_number
		retrieval.version 				= l2a_data.version
		retrieval.product_creation_time = jd2la(systime(/julian,/utc))
		retrieval.dependent_version 	= l2a_data.dependent1Bversion
		retrieval.ut_date 				= l2a_data.ut_date
		; Founf in make_tiles
		;   ut  = fltarr(n_xt, n_yt, n_layers) * !values.f_nan   ; universal time of each layer
		;   layer_time=dereference_single(stack.image_tlm_timestamp)
		;   layer_ut_time=usec2yd(layer_time)
		;   stack_ut_date=long(layer_ut_time[0])
		;   layer_ut_time-=stack_ut_date
		;   layer_ut_time*=24
		;   ut=total(/nan,ut,3)/n_good2
		
		ut_stack = PTRARR( l1b_data.nlayers )
		FOR i = 0, l1b_data.nlayers - 1 DO BEGIN
			array_size = SIZE(*(*l1b_data.albedo)[i], /DIMENSIONS )
			IF SIZE( (*l1b_data.image_tlm_timestamp), /TYPE ) EQ 10 THEN BEGIN
				time_stamp = (*(*l1b_data.image_tlm_timestamp))[i]
			ENDIF ELSE BEGIN
				time_stamp = (*l1b_data.image_tlm_timestamp)[i]
			ENDELSE
			ut_time_array = MAKE_ARRAY(array_size[0], array_size[1], /DOUBLE, VALUE = time_stamp )
			ut_time_array = usec2yd( ut_time_array )
			ut_time_array = ut_time_array - DOUBLE(LONG(ut_time_array))
			ut_time_array *= 24.0D
			nan_index = WHERE( ~FINITE( l2_data.zenith_angle_ray_peak) )
			IF nan_index[0] NE -1 THEN BEGIN
			;				ut_time_array[nan_index] = !values.f_nan
			ENDIF
			ut_stack[i] = PTR_NEW(FLOAT(ut_time_array))
		ENDFOR
		l1b_modified = copy_structure( l1b_data )
		l1b_modified = CREATE_STRUCT( l1b_modified, 'ut_stack', ut_stack )
		ut_layer = level_1b_compact(l1b_modified, 'ut_stack' )
		; Squish the ut time down to one layer. Take the total in each tile
		; discounting NaN, and divide it by the number of good values in each tile
		ut_time = total(ut_layer, 3, /nan) / total(finite(ut_layer), 3)
		
		nan_index = WHERE( ~FINITE( l2_data.zenith_angle_ray_peak) )
		IF nan_index[0] NE -1 THEN BEGIN
			ut_time_array[nan_index] = !values.f_nan
		ENDIF
		
		retrieval.ut_time =          ptr_new(FLOAT(ut_time))
		
		retrieval.hemisphere =       l2a_data.hemisphere
		retrieval.orbit_start_time = l2a_data.stack_start_time
		retrieval.orbit_end_time = l2a_data.stack_end_time
		ut_start_datetime = gps2ymdh(l2a_data.stack_start_time / 1000000.0)
		retrieval.orbit_start_time_ut = ut_start_datetime[1]
		retrieval.orbit_end_time =   orbit_info.stop_time
		retrieval.stack_id =         l2a_data.stack_id
		retrieval.xdim =             l2_data.xdim
		retrieval.ydim =             l2_data.ydim
		
		retrieval.km_per_pixel = 	 FIX(l2a_data.km_per_pixel)
		retrieval.bbox =           l2a_data.bbox
		retrieval.center_lon =     l2a_data.center_lon
		retrieval.center_lon =     l2a_data.center_lon
		retrieval.nlayers =     PTR_NEW(l2_data.nlayers)
		retrieval.percent_clouds =     l2_data.percent_clouds
		
		retrieval.cloud_presence_map =     PTR_NEW(BYTE(l2_data.cld_presence_map))
		retrieval.common_volume_map = PTR_NEW( dereference_single(l1b_data.common_volume_map) )
		
		;------------------------------------------------------------------------
		retrieval.ozone_col_density =  PTR_NEW(FLOAT(l2_data.ozone_col_density))
		retrieval.ozone_col_density_unc =  PTR_NEW(FLOAT(l2_data.ozone_col_density))
		(*retrieval.ozone_col_density_unc)[*] = 0.0
		
		retrieval.scale_height_ratio =  PTR_NEW(FLOAT(l2_data.scale_height_ratio))
		retrieval.scale_height_ratio_unc =  PTR_NEW(FLOAT(l2_data.scale_height_ratio))
		(*retrieval.scale_height_ratio_unc)[*,*] = 0.0
		
		;------------------------------------------------------------------------
		retrieval.cld_phase_albedo =       PTR_NEW(FLOAT(l2_data.cld_phase_albedo))
		retrieval.cld_phase_albedo_unc =   PTR_NEW(FLOAT(l2_data.cld_phase_albedo))
		(*retrieval.cld_phase_albedo_unc)[*,*,*] =  0.0
		
		retrieval.zenith_angle_ray_peak = PTR_NEW(FLOAT(l2_data.zenith_angle_ray_peak))
		retrieval.view_angle_ray_peak =   PTR_NEW(FLOAT(l2_data.view_angle_ray_peak))
		retrieval.scattering_angle =      PTR_NEW(FLOAT(l2_data.scattering_angle))
		retrieval.cld_albedo =            PTR_NEW(FLOAT(l2_data.cld_albedo))
		retrieval.cld_albedo_unc =        PTR_NEW(FLOAT(l2_data.cld_albedo))
		(*retrieval.cld_albedo_unc)[*,*] =   0.0
		
		retrieval.ice_water_content =     PTR_NEW(FLOAT(l2_data.iwc))
		retrieval.ice_water_content_unc = PTR_NEW(FLOAT(l2_data.iwc))
		(*retrieval.ice_water_content_unc)[*,*] = 0.0
		
		retrieval.particle_radius =       PTR_NEW(FLOAT(l2_data.Particle_Radius))
		retrieval.particle_radius_unc =   PTR_NEW(FLOAT(l2_data.Particle_Radius))
		(*retrieval.particle_radius_unc)[*,*] = 0.0
		
		FOR i = 0, N_ELEMENTS( (*l1b_data.albedo) ) - 1 DO BEGIN
			albedo_mask = WHERE( ~FINITE(*(*l1b_data.albedo)[i]) )
			IF albedo_mask[0] NE -1 THEN BEGIN
				(*(*l1b_data.latitude)[i])[albedo_mask] = !values.f_nan
				(*(*l1b_data.longitude)[i])[albedo_mask] = !values.f_nan
			ENDIF
		ENDFOR
		IF l2a_data.hemisphere EQ 'N' THEN south = 0 ELSE south = 1
		bbox_lat_lon,l2a_data.bbox,1,x=x,y=y,lat=lat_l1b,lon=lon_l1b, south=south, _extra=l2a_data
		;    lat_l1b=level_1b_compact(l1b_data,'latitude')
		;    lon_l1b=level_1b_compact(l1b_data,'longitude')
		;    lat_l1b = MEDIAN( lat_l1b, /DOUBLE, DIMENSION=3 )
		;    lon_l1b = MEDIAN( lon_l1b, /DOUBLE, DIMENSION=3 )
		
		retrieval.latitude = PTR_NEW(FLOAT(lat_l1b))
		retrieval.longitude = PTR_NEW(FLOAT(lon_l1b))
		retrieval.ozone_col_density_fg  = PTR_NEW(FLOAT(l2_data.ozone_col_density_fg))
		retrieval.scale_height_ratio_fg = PTR_NEW(FLOAT(l2_data.scale_height_ratio_fg))
		
		retrieval.ratall = PTR_NEW(FLOAT(l2_data.ratall))
		
		retrieval.num_sza = l2_data.n_sza
		retrieval.sza_bin_size = l2_data.sza_bin_size
		retrieval.sza_bins = PTR_NEW(FLOAT(l2_data.sza_bins))
		
		;------------------------------------------------------------------------
		; Write External File
		season = get_season(usec2la(orbit_info[0].start_time), hemisphere_flag = hemisphere_flag)
		l2cat_fn = get_retrieval_filename(orbit_info=orbit_info, season=season, /cat, $
			/net_cdf, prelim=orbit_info.preliminary,path=path, revision=revision)
		l2cld_fn = get_retrieval_filename(orbit_info=orbit_info, season=season, /cld, $
			/net_cdf, prelim=orbit_info.preliminary,path=path, revision=revision)
		l2psf_fn = get_retrieval_filename(orbit_info=orbit_info, season=season, /psf, $
			/net_cdf, prelim=orbit_info.preliminary, revision=revision)
		l2ozo_fn = get_retrieval_filename(orbit_info=orbit_info, season=season, /ozo, $
			/net_cdf, prelim=orbit_info.preliminary, revision=revision)
			
		level_2_cat = get_retrieval_structure(/catalog)
		level_2_cld = get_retrieval_structure(/cloud)
		level_2_psf = get_retrieval_structure(/phase)
		level_2_ozo = get_retrieval_structure(/ozone)
		
		; Write Catalog File
		STRUCT_ASSIGN,retrieval, level_2_cat
		print, "Saving: catalog file: "+l2cat_fn
		write_cips_file, level_2_cat, l2cat_fn, data_level='2', /net_cdf, /COMPRESS
		
		; Write Cloud File
		STRUCT_ASSIGN,retrieval, level_2_cld
		write_cips_file, level_2_cld, l2cld_fn, data_level='2cld', /net_cdf, /COMPRESS
		
		; Write Phase File
		STRUCT_ASSIGN,retrieval, level_2_psf
		write_cips_file, level_2_psf, l2psf_fn, data_level='2psf', /net_cdf, /COMPRESS
		
		; Write Ozone File
		STRUCT_ASSIGN,retrieval, level_2_ozo
		write_cips_file, level_2_ozo, l2ozo_fn, data_level='2ozo', /net_cdf, /COMPRESS
		
		IF (get_production_flag() GE 2) then begin
			cmd = 'scp ' + l2cat_fn + ' aimsds@laspftp:/rescha2/ftp/pub/aimsds/data/cips/cloud_properties/' + level_2_retrievals
			print, cmd
			spawn, cmd
			cmd = 'scp ' + l2cld_fn + ' aimsds@laspftp:/rescha2/ftp/pub/aimsds/data/cips/cloud_properties/' + level_2_retrievals
			print, cmd
			spawn, cmd
			cmd = 'scp ' + l2psf_fn + ' aimsds@laspftp:/rescha2/ftp/pub/aimsds/data/cips/cloud_properties/' + level_2_retrievals
			print, cmd
			spawn, cmd
			cmd = 'scp ' + l2ozo_fn + ' aimsds@laspftp:/rescha2/ftp/pub/aimsds/data/cips/cloud_properties/' + level_2_retrievals
			print, cmd
			spawn, cmd
		ENDIF
		
		;    IF (get_production_flag() GE 3) then begin
		;      Write PAN file
		IF SIZE( (*l1b_data.image_tlm_timestamp), /TYPE ) EQ 10 THEN BEGIN
			end_time = (*(*l1b_data.IMAGE_TLM_TIMESTAMP))[l1b_data.nlayers - 1]
		ENDIF ELSE BEGIN
			end_time = (*l1b_data.IMAGE_TLM_TIMESTAMP)[l1b_data.nlayers - 1]
		ENDELSE
		pan_data = prep_pan( l2cat_fn, 'Level 2', l1b_data.stack_start_time, end_time, data_directory='cloud_properties' )
	;    ENDIF
		
	Endif
	RETURN, 1
End
