#!/usr/bin/python

#-----------------------------------------------------------------#
# A python code for parsing RS2 XML file into python data structures
# and from there into DORIS res file structure
#
# Author: TUDelft - 2010
# Maintainer: Mahmut Arikan
# License: GPL
#
# Developed based on tsx_dump_header2doris.py.
#
# this is rather fair implementation and should be used as a structure
# for the future implementation of XML/GeoTIFF data readers

# NO XPATH version
# 2012.Nov  Fix for ascending mode time parameters Samie Esfahany and Mahmut
#-----------------------------------------------------------------#

from lxml import etree
import string, time, sys

#try:
#    from lxml import etree
#except ImportError:
#    import xml.etree.ElementTree as etree


codeRevision=1.1   # this code revision number

def usage():
    print 'INFO    : @(#)Doris InSAR software, $Revision: %s $, $Author: TUDelft $' % codeRevision
    print
    print 'Usage   : python rs2_dump_header2doris.py rs2_XML_product > outputfile'
    print '                           where rs2_XML_product is the input filename'
    print
    print '          This software is part of Doris InSAR software package.\n'
    print '(c) 1999-2010 Delft University of Technology, the Netherlands.\n'

try:
    inputFileName  = sys.argv[1]
#    outputFileName = sys.argv[2]
#    outStream      = open(outputFileName,'w')
except:
    print '\nError   : Unrecognized input or missing arguments\n\n'
    usage()
    sys.exit(1)

inTree = etree.parse(inputFileName)



# constants
SOL             = 299792458.0;    # speed of light

# get default namespace
uri=inTree.getroot().nsmap[None]  # xmlns="http://www.rsi.ca/rs2/prod/xml/schemas" --> http://www.rsi.ca/rs2/prod/xml/schemas
NS='{'+uri+'}'                    # 

# inTree.find('{http://www.rsi.ca/rs2/prod/xml/schemas}sourceAttributes/{http://www.rsi.ca/rs2/prod/xml/schemas}inputDatasetId').text
# print etree.tounicode(inTree) # debug

# query syntax for every field
queryList = {\
             # mission info
             'mission'             : './/%ssourceAttributes/%ssatellite' % (NS,NS),\
             # imageData file
             # fullResolutionImageData pole="HH" # inTree.findall('.//imageAttributes/fullResolutionImageData')[0].text, and more [1] .. [3]
             'imageData'           : './/%simageAttributes/%sfullResolutionImageData' % (NS,NS),\
             #'imageLines'          : './/imageAttributes/rasterAttributes/numberOfLines',\
             'imageLines'          : './/%simageAttributes//%snumberOfLines' % (NS,NS),\
             'imagePixels'         : './/%simageAttributes//%snumberOfSamplesPerLine' % (NS,NS),\
             # volume info
             #'volFile' : './/productComponents/annotation/file/location/filename',\ # HARDCODED!!! for radarsat-2
             # following smt like Level 1B Product, check manual
             'volID'               : './/%sproductId' % (NS),\
             'volRef'              : './/%sdocumentIdentifier' % (NS),\
             # product info
             #productSpec'          : './/generalHeader/referenceDocument',\  # TSX
             'productSpec'         : './/%sdocumentIdentifier' % (NS),\
             'productVolDate'      : './/%simageGenerationParameters//%sprocessingTime' % (NS,NS),\
             'productSoftVer'      : './/%simageGenerationParameters//%ssoftwareVersion' % (NS,NS),\
             'productDate'         : './/%ssourceAttributes/%srawDataStartTime' % (NS,NS),\
             'productFacility'     : './/%simageGenerationParameters//%sprocessingFacility' % (NS,NS),\
             # scene info
             #'scenePol'           : './/sourceAttributes/radarParameters/acquisitionType',\    # Fine Quad Polarization
             'scenePol'            : './/%ssourceAttributes//%spolarizations' % (NS,NS),\
             'sceneBeam'           : './/%ssourceAttributes//%sbeams' % (NS,NS),\
             'sceneBeamMode'       : './/%ssourceAttributes/%sbeamModeMnemonic' % (NS,NS),\
             'sceneCenLat'         : './/%simageAttributes/%sgeographicInformation/%srationalFunctions/%slatitudeOffset'  % (NS,NS,NS,NS),\
             'sceneCenLon'         : './/%simageAttributes/%sgeographicInformation/%srationalFunctions/%slongitudeOffset' % (NS,NS,NS,NS),\
             'sceneRecords'        : './/%ssarProcessingInformation/%snumberOfLinesProcessed' % (NS,NS),\
             'antennaLookDir'      : './/%ssourceAttributes//%santennaPointing' % (NS,NS),\
             'missinglines'        : './/%ssourceAttributes//%snumberOfMissingLines' % (NS,NS),\
             # orbit info
             'orbitABS'            : './/%sorbitAndAttitude//%sorbitDataFile'           % (NS,NS),\
             'orbitDir'            : './/%ssourceAttributes//%spassDirection'           % (NS,NS),\
             'orbitTime'           : './/%ssourceAttributes//%sstateVector/%stimeStamp' % (NS,NS,NS),\
             'orbitX'              : './/%ssourceAttributes//%sstateVector/%sxPosition' % (NS,NS,NS),\
             'orbitY'              : './/%ssourceAttributes//%sstateVector/%syPosition' % (NS,NS,NS),\
             'orbitZ'              : './/%ssourceAttributes//%sstateVector/%szPosition' % (NS,NS,NS),\
             'orbitXV'             : './/%ssourceAttributes//%sstateVector/%sxVelocity' % (NS,NS,NS),\
             'orbitYV'             : './/%ssourceAttributes//%sstateVector/%syVelocity' % (NS,NS,NS),\
             'orbitZV'             : './/%ssourceAttributes//%sstateVector/%szVelocity' % (NS,NS,NS),\
             # range
             'rangeRSR'            : './/%ssourceAttributes//%sadcSamplingRate'                           % (NS,NS),\
             'rangeBW'             : './/%simageGenerationParameters//%srangeLookBandwidth'               % (NS,NS),\
             'rangeWind'           : './/%simageGenerationParameters//%srangeWindow/%swindowName'         % (NS,NS,NS),\
             'rangeTimePix'        : './/%simageGenerationParameters//%sslantRangeTimeToFirstRangeSample' % (NS,NS),\
             # azimuth
             'azimuthPRF'          : './/%ssourceAttributes//%spulseRepetitionFrequency'          % (NS,NS),\
             'azimuthBW'           : './/%simageGenerationParameters//%sazimuthLookBandwidth'     % (NS,NS),\
             'azimuthWind'         : './/%simageGenerationParameters//%swindowName'               % (NS,NS),\
             'azimuthTimeStart'    : './/%simageGenerationParameters//%szeroDopplerTimeFirstLine' % (NS,NS),\
             'azimuthTimeStop'    : './/%simageGenerationParameters//%szeroDopplerTimeLastLine' % (NS,NS),\
             # doppler
             'dopplerTime'         : './/%simageGenerationParameters//%stimeOfDopplerCentroidEstimate' % (NS,NS),\
             'dopplerCoeff'        : './/%simageGenerationParameters//%sdopplerCentroidCoefficients'   % (NS,NS),\
             # for wavelength computation
             'radarfreq'           : './/%ssourceAttributes//%sradarCenterFrequency'                   % (NS,NS),
             #  wavelength_computed = (0.000000001*SOL/atof(c8freq));// seems more reliable, BK 03/04
             }



# temp variables and parameters
container     = {}
# containerTemp = {}        
events        = ('end',)

# functions : not sure if needed
def fast_iter_string(context):
    for event,elem in context:
        return elem.text

# works with lists
def fast_iter_list(context,tag=''):
    for event,elem in context:
        return elem.iterchildren(tag=tag).next().text

def hms2sec(hmsString,convertFlag='int'):
    # input hmsString syntax: XX:XX:XX.xxxxxx
    secString = int(hmsString[0:2])*3600 + \
        int(hmsString[3:5])*60 + \
        float(hmsString[6:])
    if convertFlag == 'int' :
        return int(secString)
    elif convertFlag == 'float' :
        return float(secString)
    else:
        return int(secString)

for key in queryList.keys():

    try:
        vars()[key];                     # check if non-existed
    except KeyError or NameError:
        vars()[key] = [];                # if non-exist, initialize

    for nodes in inTree.findall(queryList[key]):
#
        if key == 'dopplerCoeff':
            vars()[key].append(nodes.text)
            vars()[key] = vars()[key][0].split() # ['-1.668835506800000e+02 1.055662889201444e+05 -2.651685365500000e+07']
            container['dopplerCoeff0']= [ vars()[key][0] ]
            container['dopplerCoeff1']= [ vars()[key][1] ]
            container['dopplerCoeff2']= [ vars()[key][2] ]

#            if nodes.attrib.values()[0] == '0':
#                keyTemp = 'dopplerCoeff0' # reset key
#                try:
#                    vars()[keyTemp];
#                except KeyError or NameError:
#                    vars()[keyTemp] = [];
#                vars()[keyTemp].append(nodes.text)
#
#            elif nodes.attrib.values()[0] == '1':
#                keyTemp = 'dopplerCoeff1' # reset key
#                try:
#                    vars()[keyTemp];
#                except KeyError or NameError:
#                    vars()[keyTemp] = [];
#                vars()[keyTemp].append(nodes.text)
#
#            elif nodes.attrib.values()[0] == '2':
#                keyTemp = 'dopplerCoeff2' # reset key
#                try:
#                    vars()[keyTemp];
#                except KeyError or NameError:
#                    vars()[keyTemp] = [];
#                vars()[keyTemp].append(nodes.text)
#
#            container[keyTemp] = vars()[keyTemp]
#
        else:
            vars()[key].append(nodes.text)
            
    container[key] = vars()[key]


# ---------------------------------------------------------------------------------------------------------

#print container['mission']
#exit()

dummyVar = 'DUMMY'

if container['orbitDir'][0] == 'Ascending':
 azimuthTimeDoris =  container['azimuthTimeStop'][0]
else:
 azimuthTimeDoris =  container['azimuthTimeStart'][0]



print('\nrs2_dump_header2doris.py v%s, doris software, 2009\n' % codeRevision)
print('*******************************************************************')
print('*_Start_readfiles:')
print('*******************************************************************')
print('Volume file: 					%s' % 'product.xml') # container['volFile'][0]) # HARDCODED!!! for Radarsat-2
print('Volume_ID: 					%s' % container['volID'][0])
print('Volume_identifier: 				%s' % container['volRef'][0])
print('Volume_set_identifier: 				%s' % dummyVar)
print('(Check)Number of records in ref. file: 		%s' % container['sceneRecords'][0])
print('SAR_PROCESSOR:                                  %s %s' % (str.split(container['productSpec'][0])[0][:2],container['productSoftVer'][0]))
print('SWATH:                                          %s' % container['sceneBeam'][0])
print('PASS:                                           %s' % container['orbitDir'][0])
print('IMAGING_MODE:                                   %s %s' % (container['sceneBeamMode'][0],container['scenePol'][0]))
print('RADAR_FREQUENCY (Hz):                           %f' % float(container['radarfreq'][0]))
print('')
print('Product type specifier: 	                %s' % container['mission'][0])
print('Logical volume generating facility: 		%s' % container['productFacility'][0])
print('Logical volume creation date: 			%s' % container['productVolDate'][0])
print('Location and date/time of product creation: 	%s' % container['productDate'][0])
#print('Scene identification: 				Orbit: %s %s Mode: %s' % (container['orbitABS'][0].split('_')[0],container['orbitDir'][0],container['sceneBeamMode'][0]))
print('Scene identification: 				Orbit: %s  %s' % (container['orbitABS'][0].split('_')[0], azimuthTimeDoris))
print('Scene location: 		                lat: %.4f lon: %.4f' % (float(container['sceneCenLat'][0]),float(container['sceneCenLon'][0])))
print('')
print('Leader file:                                 	%s' % 'product.xml') # container['volFile'][0]) # HARDCODED!!! for Radarsat-2
print('Sensor platform mission identifer:         	%s' % container['mission'][0])
print('Scene_centre_latitude:                     	%s' % container['sceneCenLat'][0])   # CORRECTT this by taking average or so!!!!!!!!!!
print('Scene_centre_longitude:                    	%s' % container['sceneCenLon'][0])
print('Scene_centre_heading:                            %s' % 'Null') # needs to be computed from geoinfo
print('Radar_wavelength (m):                      	%s' % str(SOL/float(radarfreq[0])))
print('First_pixel_azimuth_time (UTC):			%s %s' % (time.strftime("%d-%b-%Y",time.strptime(azimuthTimeDoris.split('T')[0],"%Y-%m-%d")),azimuthTimeDoris.split('T')[1][:-1]))
print('Pulse_Repetition_Frequency (computed, Hz): 	%s' % container['azimuthPRF'][0])
print('Total_azimuth_band_width (Hz):             	%s' % container['azimuthBW'][0])
print('Weighting_azimuth:                         	%s' % str.upper(container['azimuthWind'][0]))
print('Xtrack_f_DC_constant (Hz, early edge):     	%s' % container['dopplerCoeff0'][0])
print('Xtrack_f_DC_linear (Hz/s, early edge):     	%s' % container['dopplerCoeff1'][0])
print('Xtrack_f_DC_quadratic (Hz/s/s, early edge): 	%s' % container['dopplerCoeff2'][0])
print('Range_time_to_first_pixel (2way) (ms):     	%0.15f' % (float(container['rangeTimePix'][0])*1000))
print('Range_sampling_rate (computed, MHz):       	%0.6f' % (float(container['rangeRSR'][0])/1000000))
print('Total_range_band_width (MHz):               	%s' % (float(container['rangeBW'][0])/1000000))
print('Weighting_range:                            	%s' % str.upper(container['rangeWind'][0]))
print('')
print('*******************************************************************')
print('Datafile: 					%s' % container['imageData'][0])
print('Dataformat: 				%s' % 'GeoTIFF')  # hardcoded!!!
print('Number_of_lines_original: 			%s' % container['imageLines'][0])
print('Number_of_pixels_original: 	                %s' % container['imagePixels'][0])
print('*******************************************************************')
print('* End_readfiles:_NORMAL')
print('*******************************************************************')
print('')
print('')
print('*******************************************************************')
print('*_Start_leader_datapoints:  %s ' % container['orbitABS'][0].split('_')[1])
print('*******************************************************************')
print(' t(s)		X(m)		Y(m)		Z(m)      X_V(m/s)      Y_V(m/s)      Z_V(m/s)')
print('NUMBER_OF_DATAPOINTS: 			%s' % len(container['orbitTime']))
print('')

# MA : positions and velocities
for i in range(len(container['orbitTime'])):
    print(' %.5f %s %s %s %s %s %s' % (hms2sec(container['orbitTime'][i].split('T')[1].strip('Z'),'float'),\
                                  container['orbitX'][i],\
                                  container['orbitY'][i],\
                                  container['orbitZ'][i],\
                                  container['orbitXV'][i],\
                                  container['orbitYV'][i],\
                                  container['orbitZV'][i]))

print('')
print('*******************************************************************')
print('* End_leader_datapoints:_NORMAL')
print('*******************************************************************')
# print('\n')
# print('    Current time: %s\n' % time.asctime())
# print('\n')

#EOF
