#!/usr/bin/env python
# -----------------------------------------------------------------------------
# Copyright (C) 2002-2004 Networks Associates Technology Inc.
# All rights reserved.
#
# $Date: 2004/07/13 14:32:20 $
# $Revision: 1.4 $
# -----------------------------------------------------------------------------

import os, sys, libxml2, getopt, re

def usage():
	print >>sys.stderr, "usage: %s [OPTION] XML_CONF SOURCE_FILE INPUT_FILE OUTPUTFILE" % (os.path.basename(sys.argv[0]))
	print >>sys.stderr, "XML_CONF:				  the XML replacement ruleset"
	print >>sys.stderr, "SOURCE_FILE:			  the XML input file"
	print >>sys.stderr, "INPUT_FILE:			  the XML template file"
	print >>sys.stderr, "OUTPUT_FILE:			  the XML output file"
	print >>sys.stderr, "OPTIONS:"
	print >>sys.stderr, "  -h, --help			  displays this help"
try:
	opts, args = getopt.getopt(sys.argv[1:], "hx:", ["help", "xpath="])
	if len(args) != 4:
		raise RuntimeError
except:
	usage()
	sys.exit(-1)

xpath = None
file = None
for o, a in opts:
	if o in ("-h", "--help"):
		usage()
		sys.exit(0)
xml_path = args[0]
src_path = args[1]
in_path = args[2]
out_path = args[3]

try:
	try:
		xml_doc = libxml2.parseFile(xml_path)
	except:
		print "unable to parse the xml rule file"
		sys.exit(-1)

	try:
		src_doc = libxml2.parseFile(src_path)
	except:
		print "unable to parse the xml source file"
		sys.exit(-1)

	try:
		in_doc = libxml2.parseFile(in_path)
	except:
		print "unable to parse the xml input file"
		sys.exit(-1)

	ictxt = xml_doc.xpathNewContext()
	sctxt = src_doc.xpathNewContext()
	octxt = in_doc.xpathNewContext()

	# simple transformations
	simpletransforms = ictxt.xpathEval("/UpgradeXml/Value")
	retrue = re.compile(r'^(1|true|yes|on)$', re.I)		# match for bool true
	refalse = re.compile(r'^(0|false|no|off)$', re.I)	# match for bool false
	for t in simpletransforms:
		xpath = (t.prop("xprefix") or "") + t.prop("xpath")
		spath = t.prop("spath")
		selems = sctxt.xpathEval(spath)
		if len(selems) > 0:
			s = selems[-1]
			found = octxt.xpathEval(xpath)
			for f in found:
				nval = s.content
				try:
					if f.prop("type") == "bool":
						# bool Attr - set value 0 or 1 only
						tm = t.prop("truematch")
						fm = t.prop("falsematch")
						nt = None
						if tm is not None or fm is not None:
							if tm is not None \
								and re.match('^('+tm+')$', nval, re.I):
									nt="1"
							elif fm is not None:
								if re.match('^('+fm+')$', nval, re.I):
									nt="0"
								elif tm is None:
									nt="1"
							else:	# fm is None, tm is not None, no tm match
								nt="0"
						elif retrue.match(nval):
							nt="1"
						elif refalse.match(nval):
							nt="0"
						if nt is None:
							continue	# don't understand - don't touch
						nval = nt
					elif t.prop("lowercase"):
						nval = nval.lower()
				except Exception, details:
					print "Pain in the regex!", details
				else:
					f.setProp("value", nval)

	# netobjects
	netobjects = ictxt.xpathEval("/UpgradeXml/NetObjects")
	for r in netobjects:
		xpath = (r.prop("xprefix") or "") + r.prop("xpath")
		spath = r.prop("spath")
		old = octxt.xpathEval(xpath + "/NetObject")
		for o in old:
			o.unlinkNode()
		source = sctxt.xpathEval(spath)
		found = octxt.xpathEval(xpath)
		for f in found:
			for s in source:
				o = f.newChild(None, "NetObject", None)
				t = s.prop("NetObjectType")
				o.setProp("type", t)
				sc = s.children
				while sc != None:
					cn = sc.name
					if cn.startswith("Object"):
						cn = cn[len("Object") : ]
						oc = o.newChild(None, cn, None)
						oc.setProp("value", sc.content)
					sc = sc.next

	# attrlists
	attrlists = ictxt.xpathEval("/UpgradeXml/AttrList")
	for r in attrlists:
		xpath = (r.prop("xprefix") or "") + r.prop("xpath")
		spath = r.prop("spath")
		ppath = r.prop("prefix_path")
		pfx = r.prop("prefix") or ""
		sp = r.prop("split")
		old = octxt.xpathEval(xpath + "/Attr")
		for o in old:
			o.unlinkNode()
		source = sctxt.xpathEval(spath)
		found = octxt.xpathEval(xpath)
		for f in found:
			n = 0
			for s in source:
				for t in sp and re.split(sp,s.content) or [s.content]:
					if not t:
						continue
					o = f.newChild(None, "Attr", None)
					o.setProp("name", `n`)
					n += 1
					pl = ppath and s.xpathEval(ppath)
					if pl:
						t = pl[0].content + " " + t
					o.setProp("value", pfx + t)

	# initialization flag
	found = octxt.xpathEval("//GlobalSettings[@name='machine']//Settings[@name='initialization']/Attr[@name='Initialized']")
	for f in found:
		f.setProp("value","1")

	# write the output file
	in_doc.saveFile(out_path)

except Exception, details:
	print "ouch!", details
	sys.exit(1)

