#! /usr/bin/env python
# -*- coding: latin-1 -*-

########################################################################################
#                                   caltrack_browse_factory.py
#
# Description : This script build the browses of the calxtract products (variables issued of many sensors under the CALIOP subtrace)
#
# Ex : ./caltrack_browse_factory.py -i /home/pascal/DATA/CALXTRACT/calxtract_2007:01:03T00:10:31_2007:01:03T23:14:54.hdf -v
#      python caltrack_browse_factory.py -i /disk1/projets/pascal/calxtract/data/calxtract_2007-01-05T02-23-27ZD.hdf -v
#
# Usage : ./production_calxtract.py ...
#
#    type ./production_calxtract.py --help for options details
#
# Input :
#      -i <input_file> [MANDATORY] The full path to the input file (ie: a calxtract product)
#      -o <output_file> The full path to the output file. If not precised, the output filename will be the input filename, with the ".hdf" extension replaced by ""
#
# Output : 0 if run end normally | 1 or 2 if something has gone wrong
#
# Warning :
#      - If the directory that contains the output file given in the command line arguments doesn't exist, the script will create it
#
# Limitations :
#      -
#
# Author : ICARE/CGTD/UDEV Nicolas PASCAL
########################################################################################

import os,os.path,glob,sys
import re
import tempfile
from optparse import OptionParser
import calendar
import datetime, time
from pyhdf import SD
from pylab import *
from matplotlib.dates import DateFormatter
import numpy

##### APPLICATION #####
__VERSION__="0.0.0"
__APP__="caltrack_browse_factory"
__DEBUG__=False
__RUN_PROCESS__=True

##### RETURN CODES #####
ERROR_FLAG_INPUTS=1 # command line or inputs error
ERROR_FLAG_PROCESS=2 # error during the process
ERROR_FLAG_GENERIC=3 # all other errors
SUCCESS_PROCESS=0 # successful run return code

##### DEFAULT PATHES #####
DEFAULT_APP_DIR   =os.environ['HOME']+"depot/calxtract/tools" # path to the application
APP_NAME          ="production_calxtract.py" # name of the application executable

##### EXCEPTIONS #####
BadCommandLineOption='BadCommandLineOption'
ProcessError='ProcessError'

##### TIME CONSTANTS #####
# DAO time starts at 1993:01:01T00:00:00, and epoch one at 1970:01:01T00:00:00 -> difference of 23 years + 6 days for bissextile years ; 23.*365.*24.*3600.+(6.*24.*3600.)=725 846 400 sec. from 1970/01/01T00:00:00 to 1993/01/01T00:00:00
NB_SEC_EPOCH_2_TAI93=725846400

##### name of the SDS to browse #####
latitude_sds="Latitude" # name of the sds that contains the latitude data
longitude_sds="Longitude" # name of the sds that contains the longitude data
time_sds="Time" # name of the sds that contains the time data

# set the characteristics of the sds data : each entry is set like : "sds_name":[threshold_min, threshold_max]
sds_to_browse={ 
#               "Latitude":[-90.,90.],
# 		"Longitude":[-180.,180.],
# 		"S_hgt":[-1.,1.],
# 		"Echo_hgt":[-1.,10.],
		"BT_IR":[250.,330.],
		"BT12":[250.,330.],
# 		"BT10_6":[150.,350.],
# 		"BT8_7":[150.,350.],
		"Nb_Cld_Layer_5km":[0,10],
# 		"Cld_Cover":[-0.1,1.1],
# 		"Po2":[0.,1000.],
# 		"Pray":[0.,1000.],
		"Ct_Pressure":[0.,1000.],
# 		"Opt_Th":[0.,100.],
# 		"Cld_Ph":[230.,250.]

		}
# set the browses order
sds_order=[
#            "Latitude",
#            "Longitude",
#             "S_hgt",
#            "Echo_hgt",
		   "BT_IR",
		   "BT12",
# 		   "BT10_6",
# 		   "BT8_7",
		   "Nb_Cld_Layer_5km",
# 		   "Cld_Cover",
# 		   "Opt_Th",
# 		   "Po2",
# 		   "Pray",
		   "Ct_Pressure",
# 		   "Cld_Ph"
		   ]

class CalxtractBrowseFactory:
	parser=OptionParser() # The command line options parser
# 	lat=None # Array containing the latitudes along track
# 	lon=None # Array containing the longitudes along track
# 	s_lat_lon=None # Array containing the (lat,lon) as strings
	time=None # Array containing the times along track
	date=None # Array containing the times along track converted into datetime objects
	date_min=None
	date_max=None
	hdf=None # An opened SD interface to the input file

	##### command line options #####
	verbose=False # display processing informations
	overwrite=False # overwrite existing output files flag
	app_dir=DEFAULT_APP_DIR # directory that contains the application executable
	app_name=APP_NAME # name of the application executable
	infile=None # full path of the input file
	outfile=None # full path of the output file

	def __init__(self):
		"""
		Constructor. Parse the command line arguments if any
		"""
		if self.verbose:
			print "\n"
			print "  ################################### "+__APP__+" ####################################"
			print "  #                                                                                     #"
			print "  #                                     ICARE-CGTD                                      #"
			print "  #                                   version  "+__VERSION__+"                                    #"
			print "  #######################################################################################"

		# sets the available command line options
		self.init_prog_options()
		# check the command line options validity
		self.validate_options()
		if self.verbose:
			print "  -------------------------------------- Parametres -------------------------------------"
			print "  -                                                                                     -"
			print "  -                                       -Input-                                       -"
			print "  - Input file : "+self.infile
			print "  -                                                                                     -"
			print "  -                                       -Output-                                      -"
			print "  - Output file : "+self.outfile
			print "  ---------------------------------------------------------------------------------------"
			
		# run the process
		self.process()

	def process(self):
		"""
		The process can e split in the following actions :
		  1- Load the geolocation data (lat,lon,time)
		  2- Build the graphes of all sds we want to build the browse
		  3- Concatenate the different browses
		"""
		# open the SD interface
		self.hdf=SD.SD(self.infile)
		# load the lat,lon,time data
		self.load_geolocation_data()
		# build the graphes
		self.build_browse()
		
	def load_geolocation_data(self):
		"""
		Read the lat, lon, time data
		"""
		if self.verbose:
			print "Load the geolocation data"
		# read the latitudes
# 		sds=self.hdf.select(latitude_sds)
# 		self.lat=sds.get()
# 		# read the longitudes
# 		sds=self.hdf.select(longitude_sds)
# 		self.lon=sds.get()
		# read the times
		sds=self.hdf.select(time_sds)
		self.time=sds.get( start=(2304),count=(121) )
		self.date=[]
		for t in self.time:
			d=datetime.datetime.fromtimestamp(t+NB_SEC_EPOCH_2_TAI93)
			self.date.append(date2num(d)) # use pylab time convention
		self.date_min=amin(self.date)
		self.date_max=amax(self.date)
# 		self.s_lat_lon=[]
# 		# build the array used as axis graduation
# 		for i in range(len(self.lat)):
# 			self.s_lat_lon.append("("+str(self.lat[i])+","+str(self.lon[i])+")")
		
	def build_browse(self):
		"""
		Build the graph of all sds
		"""
		# initialize the browse
		figure(1)
		
		# build the graphes of 1D SDS

# 		sds_to_browse={"S_hgt":[0.,10.]}
		
		i_graph=1 # index of each drown graph
		nb_var=len(sds_to_browse)
		for sds_name in sds_order:
			if self.verbose:
				print "Draw the browse of "+sds_name
			limits=sds_to_browse[sds_name]
			
			# init the graph
			p=subplot(nb_var,1,i_graph)

			# add the titles
			if p.is_first_row():
				title("CALXTRACT DATA ("+self.infile[-23:-4]+")")
			# load the sds data
			sds=self.hdf.select(sds_name)
			data=numpy.clip(sds.get(start=(2304),count=(121)),limits[0],limits[1])
			
			# plot the data
# 			plot(self.s_lat_lon, data)
						
			# plot the dates using a formatter
			date_formatter=DateFormatter("%H")
			plot_date(self.date,data, "b:.",markersize=5, markerfacecolor="r", markeredgecolor="b")
			p.xaxis.set_major_formatter(date_formatter)

			# rotate the x ticks labels
			xticks=p.get_xticklabels()
			setp(xticks,fontsize=8)
			yticks=p.get_yticklabels()
			setp(yticks,fontsize=8)
			# add the labels
			ylabel(sds_name,fontsize=8)
			grid(True)
			
			# set the axis range
			axis([self.date_min,self.date_max,limits[0],limits[1]])

			if p.is_last_row():
				xlabel("time (hour)",fontsize=8)

			i_graph+=1
		show()

	############################
	### COMMAND LINE PARSING ###
	############################

	def init_prog_options(self):
		"""
		Sets the available program options, and their default values
		"""
 		self.parser.add_option("-i","--input_file",
 						  action="store", default="",
 						  type="string",dest="infile",help="An input file issued of calxtract")
		self.parser.add_option("-o","--output_file",
						  action="store", default="",
						  type="string",dest="outfile",help="The output file")
		self.parser.add_option("-v", "--verbose", action="store_true", dest="verbose", \
						  help="Print out processing informations")
		self.parser.add_option("-x", "--overwrite", action="store_true", dest="overwrite", \
						  help="Overwrite existing files")

		# check the number of command line arguments
		if len(sys.argv)<3:
			self.parser.print_help()
			msg="\nNot enough command-line options\n"
			raise BadCommandLineOption,msg

		# parse the command line arguments
		(options, args) = self.parser.parse_args()

		# set program options
		self.outfile=options.outfile
		self.infile=options.infile
		self.verbose=options.verbose
		self.overwrite=options.overwrite

	def validate_options(self):
		"""
		Check if the command line options are valid. If not, throws an exception describing the problem
		"""
		if (self.infile==None or self.infile=="" or not os.path.exists(self.infile)):
			msg="Invalid input file : "+self.infile
			raise BadCommandLineOption,msg
		if (self.outfile==None or self.outfile==""):
			# set a default output file
			self.outfile=os.path.splitext(self.infile)[0]+".png"
		# if the output file directory doesn't exist, create it
		output_dir=os.path.dirname(self.outfile)
		if (not os.path.exists(output_dir)):
			print "The output file directory "+output_dir+" doesn't exist -> create it\n"
			os.makedirs(output_dir)

"""
Main script
"""
def main():
	# parse command line options
	try:
		print "\n	 ---------- CALTRACK BROWSE FACTORY SCRIPT -------------\n"
		prog=CalxtractBrowseFactory()
	except BadCommandLineOption,msg:
		print msg
		print "	 ---------- end of CALTRACK BROWSE FACTORY with status "+str(ERROR_FLAG_INPUTS)+" -------------"
		sys.exit(ERROR_FLAG_INPUTS)
	except ProcessError,msg:
		print msg
		print "	 ---------- end of CALTRACK BROWSE FACTORY with status "+str(ERROR_FLAG_PROCESS)+" -------------"
		sys.exit(ERROR_FLAG_PROCESS)
	except :
		print "	 ---------- end of CALTRACK BROWSE FACTORY with status "+str(ERROR_FLAG_GENERIC)+" -------------"
		sys.exit(ERROR_FLAG_GENERIC)
	# all works good
	print "	 ---------- end of CALTRACK BROWSE FACTORY with status "+str(SUCCESS_PROCESS)+" -------------"
	sys.exit(SUCCESS_PROCESS)


if __name__ == "__main__":
	main()