#! /usr/bin/python
#
#  USGS Preliminary Computer Program: oci2n3.py
#  Written by: Eric B. Wolf
#  Written in: Python 2.6 + GDAL/OGR 1.6
#  Program ran on: Windows XP SP3
#
#  DISCLAIMER: Although this program has been used by the USGS, no warranty, 
#  expressed or implied, is made by the USGS or the United States Government 
#  as to the accuracy and functioning of the program and related program 
#  material nor shall the fact of distribution constitute any such warranty, 
#  and no responsibility is assumed by the USGS in connection therewith.
#
#  Uses OGR to connect to an Oracle Spatial instance and read a table.
#  Attributes are encoded as literals relying on the types from the table.
#  Shape geometry is stored as hasGeometry: <GML>
#
#  Actual output to N3 format is encapsulated in n3class.py
#

from osgeo import ogr
from osgeo import gdal

import sys
import string

from n3class import N3

def help_message():
	print "shp2n3.py -- Convert ESRI Shapefile to n3 notation"
	print "             Always generates schema and focuses on USGS NHD"
	print "   Usage: shp2n3.py infile outfile\n"
	sys.exit(0)
		
def write_headers():
	outFp.write("# Notation 3 formatted triples generated by shp2n3.py\n")

	inLyr.ResetReading()
	
	feat = inLyr.GetNextFeature()

	feat_defn = inLyr.GetLayerDefn()

	n3class = feat_defn.GetName()

	# Schema always generated
	outFp.write("# Schema based arbitrarily on TBC N3 file\n\n")
	outFp.write("@prefix :        <http://cegis.usgs.gov/ontology/0.1/"+n3class+".owl#> .\n")
	outFp.write("@prefix owl:     <http://www.w3.org/2002/07/owl#> .\n")
	outFp.write("@prefix rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n")
	outFp.write("@prefix rdfs:    <http://www.w3.org/2000/01/rdf-schema#> .\n")
	outFp.write("@prefix gmlr:    <http://www.opengis.net/gml/3.2/rdf#> .\n")
	outFp.write("@prefix xsd:     <http://www.w3.org/2001/XMLSchema#> .\n\n")

	outs = ":"+n3class+"\n"
	outFp.write(outs)
	outFp.write("      rdf:type owl:Class .\n\n")

	labels = []
	for i in range(0,feat_defn.GetFieldCount()):
		field_defn = feat_defn.GetFieldDefn(i)
		h = field_defn.GetNameRef()
		headings.append(h)
		labels.append(h) # raw heading field
		for j in range(0,len(h)):
			if h[j] not in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_":
				headings[i] = headings[i][:j] + "_" + headings[i] [j+1:]

		headings[i] = headings[i][:1].lower() + headings[i][1:] # Predicates initial lower case 

		outs = ""
		outs += ":" + headings[i] + "\n"
		outs += "      rdf:type owl:DatatypeProperty ;\n"
		outs += "      rdfs:domain :" + n3class + " ;\n"
		outs += '      rdfs:label "' + labels[i] + '"^^xsd:string ;\n'
		if (field_defn.GetType() == ogr.OFTInteger):
			outs += "      rdfs:range xsd:integer .\n"
		elif (field_defn.GetType() == ogr.OFTReal):
			outs += "      rdfs:range xsd:double .\n"
		elif (field_defn.GetType() == ogr.OFTDate):
			outs += "      rdfs:range xsd:date .\n"
		elif (field_defn.GetType() == ogr.OFTTime):
			outs += "      rdfs:range xsd:time .\n"
		elif (field_defn.GetType() == ogr.OFTDateTime):
			outs += "      rdfs:range xsd:dateTime .\n"
		else:  # Otherwise, make it a string
			outs += "      rdfs:range xsd:string .\n"

		outs += "\n";

		outFp.write(outs)

	outs = ""

	outs += "<http://cegis.usgs.gov/ontology/0.1/" + n3class +".owl#>\n"
	outs += "      rdf:type owl:Ontology ;\n"
	outs += '      owl:versionInfo "Created with tab2n3.py"^^xsd:string .\n\n'
	outFp.write(outs)

def write_triples():

	outs = ""

	inLyr.ResetReading()

	feat = inLyr.GetNextFeature()

	records = 0
	
	while feat is not None:
		records = records + 1

		feat_defn = inLyr.GetLayerDefn()

		# assign an arbitrary ID tag to this instance
		outs = ":_" + str(records) + "\n"
		outs += "      rdf:type :" +n3class +" ;\n"
		outs += '      rdfs:label "' + str(records) + '"^^xsd:string ;\n'
		outFp.write(outs)
		outs = ""
	
		for i in range (feat_defn.GetFieldCount()):
			field_defn = feat_defn.GetFieldDefn(i)

			v = feat.GetFieldAsString(i)
			v = v.strip()
			
			if (field_defn.GetType() == ogr.OFTInteger):
				outs += '      :%s "%s"^^xsd:integer ' % (headings[i], v)
			elif (field_defn.GetType() == ogr.OFTReal):
				outs += '      :%s "%s"^^xsd:double ' % (headings[i], v)
			elif (field_defn.GetType() == ogr.OFTDate):
				outs += '      :%s "%s"^^xsd:date ' % (headings[i], v)
			elif (field_defn.GetType() == ogr.OFTTime):
				outs += '      :%s "%s"^^xsd:time ' % (headings[i], v)
			elif (field_defn.GetType() == ogr.OFTDateTime):
				outs += '      :%s "%s"^^xsd:dateTime ' % (headings[i], v)
			else:  # Otherwise, make it a string
				outs += '      :%s "%s"^^xsd:string ' % (headings[i], v)
			
			outs += ";\n"
			
			outFp.write(outs)
			outs = ""
			
			geom = feat.GetGeometryRef()
			
			if geom is not None:
				gml = geom.ExportToGML()
			
				outs = '      :hasGML ' + gml + '^^gmlr:string '

				outs += ".\n"
				outFp.write(outs)
			else:
				print "Can't get geometry!"
				print "GDAL Error: " + gdal.GetLastErrorMsg()
				
			outs = ""
			
		outFp.write("\n\n")
		
		feat = inLyr.GetNextFeature()

	outs += "# Total number of records:" + str(records) + "\n"
	outFp.write(outs)
	
# End: function write_triples()


# Main function
try:
	infile = sys.argv[1];
	outfile = sys.argv[2];
except:
	help_message()

try:
	driver = ogr.GetDriverByName('OCI')
except:
	print "Error getting OCI driver"
	sys.exit(-1)
	
try:
	inShp = ogr.Open(infile)
    #inLyr = inShp.GetLayer(0)
except:
	print "Error opening database connection with string '" + infile + "'"
	sys.exit(-1)
	#help_message();


if inShp is None:
	print "Error opening database connection with string '" + infile + "'"
	print "inShp is ", inShp
	sys.exit(-1)
	
try:
	lyr = inShp.GetLayerByName('nhd.NHDAREA_TX')
except:
	print "Error opening table nhd.NHDAREA_TX"
	sys.exit(-1)

outFp = open(outfile, "w")

(n3class, cruft) = infile.rsplit("_", 1) 
n3class = n3class.upper()

write_headers()
write_triples() 

inShp.Destroy()
outFp.close()















