#!/usr/bin/env python
#
# created by Dylan Beaudette
#
# simple script to convert kistmet .gps files into a shapefile
# modify projection code accordingly
#
#./process_kismet_gpslog.py -f Kismet-Aug-09-2007-4.gps -o wifi1.shp

import sys, math
import ogr, osr
from optparse import OptionParser
from elementtree import ElementTree

#process command line (optparse)
parser = OptionParser()
parser.add_option("-f", "--file", dest="infile", help="input Kismet-xxx.gps file", metavar="FILE")

parser.add_option("-o", "--outfile", dest="outfile", help="full name of shapefile to create", metavar="FILE")

# process args
(options, args) = parser.parse_args()

#require an input file
if not options.infile:
	print "ERROR: must supply an input file"
	sys.exit(1)

#hack
#require an output file
if not options.outfile:
	print "ERROR: must supply an output file"
	sys.exit(1)

#open input file
try:
   infile = options.infile
   #input data source
   data = open(infile,'r').read()
except:
   print "ERROR: Cannot open: " + infile
   sys.exit(1)
   



# Set up spatial reference systems
#something planimetric, units in meters: using our AEA projection
proj = osr.SpatialReference()
proj.ImportFromProj4('+proj=aea +x_0=0.0 +y_0=0 +lon_0=-96 +lat_0=40.0 +lat_1=20 +lat_2=60.0 +datum=NAD83')

#original lat/lon
latlong = osr.SpatialReference()
latlong.ImportFromProj4('+proj=latlong +datum=WGS84')


#create range output layer
filename = options.outfile
driver = ogr.GetDriverByName('ESRI Shapefile')
driver.DeleteDataSource(filename)
ds = driver.CreateDataSource(filename)


#output layer type
layer = ds.CreateLayer('gps_wifi', geom_type=ogr.wkbPoint)

# Create a field for the SSID
fd = ogr.FieldDefn('ssid', ogr.OFTString)
fd.SetWidth(25)
fd.SetPrecision(0)
layer.CreateField(fd)

# Create a field for the signal strength
fd = ogr.FieldDefn('snr', ogr.OFTReal)
fd.SetWidth(10)
fd.SetPrecision(8)
layer.CreateField(fd)

# Create a field for the signal strength
fd = ogr.FieldDefn('signal', ogr.OFTReal)
fd.SetWidth(10)
fd.SetPrecision(0)
layer.CreateField(fd)

# Create a field for the signal strength
fd = ogr.FieldDefn('noise', ogr.OFTReal)
fd.SetWidth(10)
fd.SetPrecision(0)
layer.CreateField(fd)

# Create a field for the signal strength
fd = ogr.FieldDefn('elev', ogr.OFTReal)
fd.SetWidth(10)
fd.SetPrecision(6)
layer.CreateField(fd)




# Create a field for the GPS fix code
fd = ogr.FieldDefn('fix', ogr.OFTInteger)
fd.SetWidth(10)
fd.SetPrecision(0)
layer.CreateField(fd)




# parse the input xml file
detection = ElementTree.XML(data)

#
# each node represents a GPS + network observation
#
# note that a BSSID labeled as "GP:SD:TR:AC:KL:OG" is some kind of 
#
# seperate tracklog

for node in detection.getchildren():
	# print out the available attributes for each node
	# print node.keys()	
	
	# access each attribute for this node
	bssid = node.get("bssid")
	
	# the network we are observing
	source = node.get("source")
	
	# signal strength in Db
	signal =  node.get("signal")
	noise = node.get("noise")
	
	# positional data:
	lat = node.get("lat")
	lon = node.get("lon")
	elev = node.get("alt") # in the native units of the GPS (ft)
	fix = node.get("fix") # quality of the GPS fix
	
	# heading : the direction of movement ? 
	heading = node.get("heading")
	
	## add to the shapefile 
	if bssid != "GP:SD:TR:AC:KL:OG" and lat != None :
		
		# debug
		#print "%s,%s,%s,%s,%s" % (lon, lat, source, signal, noise) 
		#continue
	
		# compute signal to noise ratio
		if int(noise) == 0 or int(signal) == 0:
			snr = 0
		else:
			snr = float(signal) / float(noise)
		#print snr
		
		
		#init the feature
		f = ogr.Feature(feature_def=layer.GetLayerDefn())
		
		#make a text version each point 
		wkt = 'POINT(%s %s)' % (lon, lat)
		p = ogr.CreateGeometryFromWkt(wkt)
		#assign latlon WG84 srs
		p.AssignSpatialReference(latlong)
		
		#transform to planimetric projection:
		p.TransformTo(proj)
		
		# register feature
		f.SetGeometryDirectly(p)
		
		#assign attribute data:
		f.SetField(0,source)
		f.SetField(1,snr)
		f.SetField(2,signal)
		f.SetField(3,noise)
		f.SetField(4,elev)
		f.SetField(5,fix)
		
		#save feature
		layer.CreateFeature(f)
		f.Destroy()
	

# done, cleanup and close file
ds.Destroy()

# make the .prj file
wkt_proj = proj.ExportToWkt()

#open a filehandle
prj_file_name = filename[:-4] + '.prj'
prj_file = open(prj_file_name, 'w')
prj_file.write(wkt_proj)
prj_file.close()