#!/usr/bin/python

import string, sys
import xml.dom.minidom

global stereotypes
global classes
global dependencies
global generalizations
global associations
global statecharts

def clearGlobals():
	global stereotypes
	global classes
	global dependencies
	global generalizations
	global associations
	global statecharts

	stereotypes = []
	classes = []
	dependencies = []
	generalizations = []
	associations = []
	statecharts = []

def getStereotype(id):
	for s in stereotypes:
		if s.id == id:
			return s

def parseStereotype(s):
	text = s.name[2:len(s.name) - 2]
	tokens = text.split('(')
	function = tokens[0]
	args = tokens[1][:len(tokens[1]) - 1]
	return [function, args.split(',')]

def getClass(id):
	for c in classes:
		if c.id == id:
			return c

def getText(nodelist):
	rc = ""
	for node in nodelist:
		if node.nodeType == node.TEXT_NODE:
			rc = rc + node.data
	return rc

def isSubtype(parent, child):
	for g in generalizations:
		if g.parent == parent and g.child == child:
			return True
	return False

def getRootClass(cls):
	parent = cls
	for g in generalizations:
		if parent == g.child:
			parent = g.parent
	return parent

def areFamily(cls1, cls2):
	parent1 = getRootClass(cls1)
	parent2 = getRootClass(cls2)
	return parent1 == parent2

def getPlainAssociations():
	ret = []
	for a in associations:
		if a.type == '-->':
			ret.append(a)
	return ret

class Stereotype:
	def __init__(self, s):
		if s == "default":
			self.id = "null"
			self.name = "<<owns>>"
		else:
			self.id = s.getAttribute("xmi.id")
			self.name = "<<" + s.getAttribute("name") + ">>"

	def toString(self):
		print "[Stereotype] name= " + self.name + ", id= " + self.id

class Field:
	def __init__(self, f):
		self.name = getText(f.getElementsByTagName("Foundation.Core.ModelElement.name")[0].childNodes)
		self.visiblity = f.getElementsByTagName("Foundation.Core.ModelElement.visibility")[0].getAttribute("xmi.value")
		self.scope = f.getElementsByTagName("Foundation.Core.Feature.ownerScope")[0].getAttribute("xmi.value")
		self.type = f.getElementsByTagName("Foundation.Core.StructuralFeature.type")[0].getElementsByTagName("Foundation.Core.Classifier")[0].getAttribute("xmi.idref")

	def toString(self):
		print "[Field Element] " + self.name + ":" + getClass(self.type).name

class Method:
	def __init__(self, f):
		self.id = f.getAttribute("xmi.id")
		self.name = getText(f.getElementsByTagName("Foundation.Core.ModelElement.name")[0].childNodes)
		self.visiblity = f.getElementsByTagName("Foundation.Core.ModelElement.visibility")[0].getAttribute("xmi.value")
		self.scope = f.getElementsByTagName("Foundation.Core.Feature.ownerScope")[0].getAttribute("xmi.value")
		parameters = f.getElementsByTagName("Foundation.Core.BehavioralFeature.parameter")[0].getElementsByTagName("Foundation.Core.Parameter")
		for p in parameters:
			kind = p.getElementsByTagName("Foundation.Core.Parameter.kind")[0].getAttribute("xmi.value")
			if kind == "return":
				type = p.getElementsByTagName("Foundation.Core.Parameter.type")
				if len(type) > 0:
					self.type = type[0].getElementsByTagName("Foundation.Core.Classifier")[0].getAttribute("xmi.idref")
				else:
					self.type = None

	def toString(self):
		if (self.type != None):
			print "[Method Element:" + self.id + "] " + self.name + ":" + getClass(self.type).name
		else:
			print "[Method Element:" + self.id + "] <<ctor>> " + self.name

class Class:
	def __init__(self, c):
		stereotypes = c.getElementsByTagName("UML:Stereotype")
		if len(stereotypes) == 1:
			self.stereotype = getStereotype(stereotypes[0].getAttribute("xmi.idref"))
		else:
			self.stereotype = None
		self.id = c.getAttribute("xmi.id")
		self.name = c.getAttribute("name")
		self.isAbstract = c.getAttribute("isAbstract")
		self.isLeaf = c.getAttribute("isLeaf")

		# Collect features: fields and methods
		self.fields  = []
		features = c.getElementsByTagName("Foundation.Core.Classifier.feature")
		if len(features) > 0:
			elements = features[0].getElementsByTagName("Foundation.Core.Attribute")
			for e in elements:
				self.fields.append(Field(e))
			elements = features[0].getElementsByTagName("Foundation.Core.Operation")
			for e in elements:
				self.fields.append(Method(e))


		# Get statechart
		self.statechart = None
		statecharts = c.getElementsByTagName("Behavioral_Elements.State_Machines.StateMachine")
		if len(statecharts) > 0:
			self.statechart = statecharts[0]

	def getId(self):
		return self.id

	def toString(self):
		info = "[Class Element: "
		if self.stereotype != None:
			 info = info + self.stereotype.name
		info = info + "] name: " + self.name + " isAbstract:" + self.isAbstract + " id:" + self.id + " isLeaf:" + self.isLeaf + "]"
		print info

		for f in self.fields:
			f.toString()

	def hasConstraints(self):
		return self.stereotype != None or self.isAbstract == 'true'

	def getCodeFragment(self, pattern, name):
		# name is the TypeSymbol variable name
		indent = '  '
		cppCode = []
		if debug == True:
			cppCode .append('Coutput << "Class satisfies the following constraints:";')
			if self.stereotype != None:
				cppCode.append('Coutput << "' + self.stereotype.name + '";')
			if self.isAbstract == "true":
				cppCode.append('Coutput << "<<abstract>>";')
			cppCode.append('Coutput << endl;')

		cppCode.append('Coutput << "' + pattern + '|' + self.name + '|" << ' + name + '->Utf8Name() << leftEndType->file_symbol->FileName() << endl;')
		for i in range(len(cppCode)):
			cppCode[i] = indent + cppCode[i]

		constraints = ''
		if self.stereotype != None:
			if self.stereotype.name == '<<singleton>>':
				constraints = constraints + ' isSingletonClass(sym_tables, ' + name + ' ) '
		if self.isAbstract == 'true':
			if len(constraints) > 0:
				constraints = constraints + '&&'
			constraints = constraints + ' isAbstract( ' + name + ' ) '

		if constraints != '':
			cppCode.insert(0, 'if (' + constraints + ')')
			cppCode.insert(1, '{')
			cppCode.append('}')

		if debug == True:
			print cppCode

		return cppCode

	def genCompleteCode(self, pattern, index):
		cppCode = []
		indent = '  '

		# 1. Print recovery message
		cppCode.append('Coutput << "' + pattern + '|' + self.stereotype.name + '|" << type->Utf8Name() << "|" << type->file_symbol->FileName()<< endl;')

		# 2. Print stereotype constraint
		for i in range(len(cppCode)):
			cppCode[i] = indent + cppCode[i]

		cppCode.insert(0, 'TypeSymbol *type = (*cs_table)[c];')
		# Singleton class
		if self.stereotype.name == '<<singleton>>':
			cppCode.insert(1, 'if (isSingletonClass(sym_tables, type))')
		elif self.stereotype.name == '<<facade>>':
			cppCode.insert(1, 'if (isFacadeClass(type))')
		cppCode.insert(2, '{')
		cppCode.append('}')

		# 3. Traverse list of classes
		for i in range(len(cppCode)):
			cppCode[i] = indent + cppCode[i]

		cppCode.insert(0, 'for (unsigned c = 0; c < cs_table -> size(); c++)')
		cppCode.insert(1, '{')
		cppCode.append('}')

		# Print function header
		for i in range(len(cppCode)):
			cppCode[i] = indent + cppCode[i]
		cppCode.insert(0, 'void FindPattern' + str(index) + '(SymbolTables *sym_tables)')
		cppCode.insert(1, '{')
		cppCode.insert(2, indent + 'ClassSymbolTable *cs_table = sym_tables->getClassSymbolTable();')
		cppCode.insert(3, '\n')
		cppCode.append('}')

		# Print actual cpp code
		for line in cppCode:
			print line
		print '\n'


class AssociationEnd:
	def __init__(self, e):
		self.type = getClass(e.getElementsByTagName("UML:Class")[0].getAttribute("xmi.idref"))

		self.aggregation = e.getAttribute("aggregation")

		range = e.getElementsByTagName("UML:MultiplicityRange")[0]
		self.lb = range.getAttribute("lower")
		self.ub = range.getAttribute("upper")

	def toString(self):
		return "<" + self.type.name + ">" + "(" + self.lb + ".." + self.ub + ")"

class Association:
	def __init__(self, a):
		stereotypes = a.getElementsByTagName("UML:Stereotype")
		if len(stereotypes) == 1:
			self.stereotype = getStereotype(stereotypes[0].getAttribute("xmi.idref"))
		else:
			self.stereotype = Stereotype("default")
		connection = a.getElementsByTagName("UML:Association.connection")[0]
		ends = connection.getElementsByTagName("UML:AssociationEnd")
		self.leftEnd = AssociationEnd(ends[0])
		self.rightEnd = AssociationEnd(ends[1])
		self.name = a.getAttribute("name")
		if self.leftEnd.aggregation == "composite" or self.leftEnd.aggregation == "aggregate":
			self.type = "<>-->"
		else:
			self.type = "-->"

	def toString(self):
		print "[Association: " + self.stereotype.name + "] " + self.leftEnd.toString() + " " + self.type + " " + self.rightEnd.toString()

	def genCompleteCode(self, pattern, index):
		# Three entities: the leftEnd, rightEnd classes, and vd (the aggregation field)
		cppCode = []
		indent  = '  '

		# 1. Print Recovery information
		if self.type == "<>-->":

			if self.stereotype.name != "<<owns>>":
				for i in range(len(cppCode)):
					cppCode[i] = indent + cppCode[i]

			constraints = []
			if self.stereotype.name == "<<creates(key)>>":
				constraint = 'createsFlyweights(vd->symbol, containing_type)'
				coutput = 'Coutput << "Stereotype: ' + self.stereotype.name + '" << endl;'
				constraints.append([constraint, coutput])
			if self.stereotype.name == "<<*delegates>>":
				constraint = '(star_delegates(sym_tables, vd, type, containing_type))'
				coutput = 'Coutput << "Stereotype: ' + self.stereotype.name + '" << endl;'
				constraints.append([constraint, coutput])
			if self.stereotype.name == "<<!delegates>>":
				constraint = 'bang_delegates(sym_tables, type, containing_type)'
				coutput = 'Coutput << "Stereotype: ' + self.stereotype.name + '" << endl;'
				constraints.append([constraint, coutput])
			if isSubtype(self.rightEnd.type, self.leftEnd.type):
				constraint = '(type -> IsSubtype(containing_type))'
				coutput = 'Coutput << type->Utf8Name() << " --|> " << containing_type->Utf8Name() << endl;'
				constraints.append([constraint, coutput])
			elif isSubtype(self.leftEnd.type, self.rightEnd.type):
				constraint = '(containing_type -> IsSubtype(type))'
				coutput = 'Coutput << containing_type->Utf8Name() << " --|> " << type->Utf8Name() << endl;'
				constraints.append([constraint, coutput])
			elif areFamily(self.leftEnd.type, self.rightEnd.type):
				constraint = '(type -> IsFamily(containing_type))'
				coutput = 'Coutput << type -> Utf8Name() << " and " << containing_type->Utf8Name() << " inherit from the same root class." << endl;'
				constraints.append([constraint, coutput])
			if self.leftEnd.type.isAbstract == "true":
				constraint = 'isAbstract(type)'
				coutput = 'Coutput << type->Utf8Name() << " is abstract class." << endl;'
				constraints.append([constraint, coutput])
			if self.rightEnd.type.isAbstract == "true":
				constraint = 'isAbstract(containing_type)'
				coutput = 'Coutput << containing_type->Utf8Name() << " is abstract class." << endl;'
				constraints.append([constraint, coutput])
			if len(dependencies) == 1:
				dependency = dependencies[0]
				if dependency.function == "!sets":
					args = dependency.args
					if len(args) == 1:
						assocName = args[0]
						if assocName == self.name:
							constraint = '(bang_sets(sym_tables, containing_type, vd->symbol))'
							coutput = 'Coutput << containing_type->Utf8Name() << " !sets association[" << vd->symbol->Utf8Name() << "]" << endl;'
							constraints.append([constraint, coutput])
				if dependency.function == "delegates":
					args = dependency.args
					if len(args) == 1:
						assocName = args[0]
						if assocName == "condition":
							constraint = '(cond_delegates(sym_tables, vd->symbol))'
							coutput = 'Coutput << vd->symbol->Utf8Name() << " satisfies ' + dependency.stereotype.name + '" << endl;'
							constraints.append([constraint, coutput])
						if assocName == "decorate":
							constraint = '(decor_delegates(sym_tables, vd->symbol))'
							coutput = 'Coutput << vd->symbol->Utf8Name() << " satisfies ' + dependency.stereotype.name + '" << endl;'
							constraints.append([constraint, coutput])

			plainAssociations = getPlainAssociations()
			for p in plainAssociations:
				if p.stereotype.name == "<<independent>>":
					constraint = 'areIndependentHierarchies(sym_tables, type, containing_type)'
					coutput = 'Coutput << type->Utf8Name() << " and " << containing_type->Utf8Name() << " satisfy ' + p.stereotype.name + '" << endl;'
					constraints.append([constraint, coutput])

			# 1.0 Print list of conjunctive constraints and the corresponding output results
			n = len(constraints)
			last = n - 1
			if_statement = 'if ('
			codeBlock = []
			for i in range(n):
				codeBlock.append(constraints[i][1])
				if_statement = if_statement + constraints[i][0]
				if i < last:
					if_statement = if_statement + ' && '
			if_statement = if_statement + ')'
			cppCode.append(if_statement)
			cppCode.append('{')
			if debug == True:
				for i in range(n):
					cppCode.append(indent + codeBlock[i])
			cppCode.append(indent + 'Coutput << "' + pattern + '|' + self.leftEnd.type.name + '|" << type->Utf8Name() << "|" << type->file_symbol->FileName() << endl;')
			cppCode.append(indent + 'Coutput << "' + pattern + '|' + self.rightEnd.type.name + '|" << containing_type->Utf8Name() << "|" << containing_type->file_symbol->FileName() << endl;')
			cppCode.append('}')


			# 1.1 Find VariableDeclarator
			for i in range(len(cppCode)):
				cppCode[i] = indent + cppCode[i]

			cppCode.insert(0, "AstVariableDeclarator* vd = field_decl -> VariableDeclarator(vi);")

			isOneToMany = False
			if self.rightEnd.lb == "1" and self.rightEnd.ub == "-1":
				# 1.3 One-to-many relationship found
				cppCode.insert(1, "TypeSymbol *containing_type = type -> IsOnetoMany(vd->symbol, d_table);")
				isOneToMany = True
			else:
				cppCode.insert(1, "TypeSymbol *containing_type = vd -> symbol -> Type();")

			cppCode.insert(2, "if (containing_type && containing_type -> file_symbol)")
			cppCode.insert(3, "{")
			if debug == True:
				cppCode.insert(4, indent + 'Coutput << "Aggregation Relationship found." << endl;')
			if isOneToMany == True:
				cppCode.insert(4, indent + 'Coutput << "' + pattern + '|one-to-many|" << vd->symbol->Utf8Name() << "|" << vd->symbol->ContainingType()->file_symbol->FileName() << endl;')
			else:
				cppCode.insert(4, indent + 'Coutput << "' + pattern + '|one-to-one|" << vd->symbol->Utf8Name() << "|" << vd->symbol->ContainingType()->file_symbol->FileName() << endl;')
			cppCode.append("}")

			for i in range(len(cppCode)):
				cppCode[i] = indent + cppCode[i]

			# 1.3 Find FieldDeclaration

			cppCode.insert(0, "AstFieldDeclaration* field_decl = type -> declaration -> InstanceVariable(i);")
			cppCode.insert(1, "for (unsigned vi = 0; vi < field_decl -> NumVariableDeclarators(); vi++)")
			cppCode.insert(2, "{")
			cppCode.append("}")

			for i in range(len(cppCode)):
				cppCode[i] = indent + cppCode[i]

			cppCode.insert(0, "TypeSymbol *type = (*cs_table)[c];")
			cppCode.insert(1, "for (unsigned i = 0; i < type -> declaration-> NumInstanceVariables(); i++)")
			cppCode.insert(2, "{")
			cppCode.append("}")

			for i in range(len(cppCode)):
				cppCode[i] = indent + cppCode[i]

			cppCode.insert(0, "for (unsigned c = 0; c < cs_table -> size(); c++)")
			cppCode.insert(1, "{")
			cppCode.append("}")


		else:
			if debug == True:
				cppCode.append('Coutput << "Association Relationship found." << endl;')
				cppCode.append('Coutput << "Stereotype: ' + self.stereotype.name + '" << endl;')
			cppCode.append('Coutput << "' + pattern + '|' + self.stereotype.name + '|" << method->Utf8Name() << "|" << method->containing_type->file_symbol->FileName() << endl;')

			# 1.1. Satisfy constraints for both association ends.
			if self.leftEnd.type.hasConstraints():
				cppCode.append("TypeSymbol *leftEndType = " + "method -> containing_type;")
				frag = self.leftEnd.type.getCodeFragment(pattern, "leftEndType")
				for line in range(len(frag)):
					cppCode.append(frag[line])

			if self.rightEnd.type.hasConstraints():
				if self.stereotype.name.find(":") > 0:
					cppCode.append("TypeSymbol *rightEndType = " + "method -> Type();")
				else:
					cppCode.append("TypeSymbol *rightEndType = " + "param -> Type();")
				frag = self.rightEnd.type.getCodeFragment(pattern, "rightEndType")
				for line in range(len(frag)):
					cppCode.append(frag[line])

			# 2. Print stereotype constraint
			for i in range(len(cppCode)):
				cppCode[i] = indent + cppCode[i]

			cppCode.insert(0, 'MethodSymbol *method = (*ms_table)[m];')

            # Dependency, obtained via MethodSymbol
			if self.stereotype.name.startswith('<<creates:'):
				cppCode.insert(1, 'if ( isFactoryMethod(sym_tables, method) )')
			if self.stereotype.name.startswith('<<!creates:'):
				cppCode.insert(1, 'if ( isFlyweightMethod(method) )')
			if self.stereotype.name.startswith('<<accepts('):
				cppCode.insert(1, 'if ( VariableSymbol *param = isVisitorMethod(method) )')
			cppCode.insert(2, '{')
			cppCode.append('}')

			# 3. Traverse list of methods
			for i in range(len(cppCode)):
				cppCode[i] = indent + cppCode[i]

			cppCode.insert(0, 'for (unsigned m = 0; m < ms_table -> size(); m++)')
			cppCode.insert(1, '{')
			cppCode.append('}')

		# Print function header
		for i in range(len(cppCode)):
			cppCode[i] = indent + cppCode[i]
		cppCode.insert(0, 'void FindPattern' + str(index) + '(SymbolTables *sym_tables)')
		cppCode.insert(1, '{')
		cppCode.insert(2, indent + 'ClassSymbolTable *cs_table = sym_tables->getClassSymbolTable();')
		cppCode.insert(3, indent + 'MethodSymbolTable *ms_table = sym_tables->getMethodSymbolTable();')
		cppCode.insert(4, indent + 'DelegationTable *d_table = sym_tables->getDelegationTable();')
		cppCode.insert(5, '\n')
		cppCode.append('}')

		# Print actual cpp code
		for line in cppCode:
			print line
		print '\n'

class Generalization:
	def __init__(self, g):
		self.child = getClass(g.getElementsByTagName("UML:Generalization.child")[0].getElementsByTagName("UML:Class")[0].getAttribute("xmi.idref"))
		self.parent = getClass(g.getElementsByTagName("UML:Generalization.parent")[0].getElementsByTagName("UML:Class")[0].getAttribute("xmi.idref"))

	def toString(self):
		print self.parent.name + " <|-- " + self.child.name

class Dependency:
	def __init__(self, d):
		stereotypes = d.getElementsByTagName("UML:Stereotype")
		if len(stereotypes) == 1:
			self.stereotype = getStereotype(stereotypes[0].getAttribute("xmi.idref"))
		else:
			self.stereotype = Stereotype("default")
		self.client = getClass(d.getElementsByTagName("UML:Dependency.client")[0].getElementsByTagName("UML:Class")[0].getAttribute("xmi.idref"))
		self.supplier = getClass(d.getElementsByTagName("UML:Dependency.supplier")[0].getElementsByTagName("UML:Class")[0].getAttribute("xmi.idref"))

		# Parse stereotype
		[self.function, self.args] = parseStereotype(self.stereotype)

	def toString(self):
		print "[Dependency: " + self.stereotype.name + "] " + self.client.name + " --> " + self.supplier.name
		print "   function = " + self.function + ",  args = " + string.join(self.args, ',')

class State:
	def __init__(self, s, kind):
		self.id = s.getAttribute("xmi.id")

		if type == "pseudo":
			self.kind = s.getElementsByTagName("Behavioral_Elements.State_Machines.Pseudostate.kind")[0].getAttribute("xmi.value")
		else:
			self.kind = kind

		self.incoming = [] # stores a list of transition ids
		tag = s.getElementsByTagName("Behavioral_Elements.State_Machines.StateVertex.incoming")
		if (len(tag) > 0):
			edges = tag[0].getElementsByTagName("Behavioral_Elements.State_Machines.Transition")
			for e in edges:
				self.incoming.append(e.getAttribute("xmi.idref"))

		self.outgoing = [] # stores a list of transition ids
		tag = s.getElementsByTagName("Behavioral_Elements.State_Machines.StateVertex.outgoing")
		if (len(tag) > 0):
			edges = tag[0].getElementsByTagName("Behavioral_Elements.State_Machines.Transition")
			for e in edges:
				self.outgoing.append(e.getAttribute("xmi.idref"))

		self.doActivity = None
		tag = s.getElementsByTagName("Behavioral_Elements.State_Machines.State.doActivity")
		if (len(tag) > 0):
			self.doActivity = getText(tag[0].getElementsByTagName("Foundation.Data_Types.Expression.body")[0].childNodes)

	def toString(self):
		output = self.kind + " state(" + self.id + "): incoming= " + str(self.incoming) + " outgoing=" + str(self.outgoing) + " doActivity: "
		if self.doActivity == None:
			output = output + "None"
		else:
			output = output + self.doActivity
		print output

class Transition:
	def __init__(self, t):
		self.id = t.getAttribute("xmi.id")

		# get trigger
		self.trigger = None
		tag = t.getElementsByTagName("Behavioral_Elements.State_Machines.Transition.trigger")
		if len(tag) > 0:
			self.trigger = tag[0].getElementsByTagName("Behavioral_Elements.State_Machines.Event")[0].getAttribute("xmi.idref")

		# get state machine
		self.stateMachine = t.getElementsByTagName("Behavioral_Elements.State_Machines.Transition.stateMachine")[0].getElementsByTagName("Behavioral_Elements.State_Machines.StateMachine")[0].getAttribute("xmi.idref")

		#get source
		self.source = t.getElementsByTagName("Behavioral_Elements.State_Machines.Transition.source")[0].getElementsByTagName("Behavioral_Elements.State_Machines.StateVertex")[0].getAttribute("xmi.idref")

		# gettarget
		self.target = t.getElementsByTagName("Behavioral_Elements.State_Machines.Transition.target")[0].getElementsByTagName("Behavioral_Elements.State_Machines.StateVertex")[0].getAttribute("xmi.idref")

	def toString(self):
		print "Trigger[" + self.id + "]"
		output = "trigger="
		if self.trigger == None:
			output = output + "None"
		else:
			output = output + self.trigger
		output = output + " stateMachine=" + self.stateMachine + " source=" + self.source + " target=" + self.target
		print output

class Statechart:
	def __init__(self, sc):
		# construct a list of states
		self.id = sc.getAttribute("xmi.id")
		self.states = []
		self.context = sc.getElementsByTagName("Behavioral_Elements.State_Machines.StateMachine.context")[0].getElementsByTagName("Foundation.Core.ModelElement")[0].getAttribute("xmi.idref")
		states = sc.getElementsByTagName("Behavioral_Elements.State_Machines.StateMachine.top")[0].getElementsByTagName("Behavioral_Elements.State_Machines.CompositeState")[0].getElementsByTagName("Behavioral_Elements.State_Machines.CompositeState.subvertex")[0]

		pseudoStates = states.getElementsByTagName("Behavioral_Elements.State_Machines.Pseudostate")
		for ps in pseudoStates:
			self.states.append(State(ps, "pseudo"))

		intermediateStates = states.getElementsByTagName("Behavioral_Elements.State_Machines.State")
		for ist in intermediateStates:
			self.states.append(State(ist, "inter"))

		fs = states.getElementsByTagName("Behavioral_Elements.State_Machines.FinalState")[0]
		self.states.append(State(fs, "final"))

		# construct a list of transitions
		self.transitions = []
		transitions = sc.getElementsByTagName("Behavioral_Elements.State_Machines.StateMachine.transitions")[0].getElementsByTagName("Behavioral_Elements.State_Machines.Transition")
		for t in transitions:
			self.transitions.append(Transition(t))

	def toString(self):
		print "Statechart[" + self.id + "] (" + self.context + ")"
		for s in self.states:
			s.toString()
		for t in self.transitions:
			t.toString()


# Generate FindPattern function from an XMI
def genFindPattern(index, xmiFile):
	clearGlobals()

	tree = xml.dom.minidom.parse(xmiFile)

	# Get all stereotypes
	elements = tree.getElementsByTagName("UML:Stereotype")

	if len(elements) != 0:
		for e in elements:
			if e.getAttribute("xmi.id") != "":
				stereotypes.append(Stereotype(e))

	if debug == True:
		for s in stereotypes:
			s.toString()

	# Get all classes
	elements = tree.getElementsByTagName("UML:Class")

	if len(elements) == 0:
		print "Error: No classes defined in " + xmifile + "."
		sys.exit(1)

	for e in elements:
		if e.getAttribute("xmi.id") != "":
			classes.append(Class(e))

	if debug == True:
		for c in classes:
			c.toString()

	# Get all association relationships
	elements = tree.getElementsByTagName("UML:Association")

	for e in elements:
		if e.getAttribute("xmi.id") != "":
			associations.append(Association(e))

	if debug == True:
		for a in associations:
			a.toString()

	# Get all dependency relationships
	elements = tree.getElementsByTagName("UML:Dependency")

	for e in elements:
		if e.getAttribute("xmi.id") != "":
			dependencies.append(Dependency(e))

	if debug == True:
		for d in dependencies:
			d.toString()

	# Get all generalization relationships
	elements = tree.getElementsByTagName("UML:Generalization")

	for e in elements:
		if e.hasChildNodes():
			generalizations.append(Generalization(e))

	if debug == True:
		for g in generalizations:
			g.toString()


	# Get all statecharts
	elements = tree.getElementsByTagName("Behavioral_Elements.State_Machines.StateMachine")
	for e in elements:
		if e.hasChildNodes():
			statecharts.append(Statechart(e))

	if debug == True:
		for sc in statecharts:
			sc.toString()

	#
	# Generate Code
	#

	# Case 1. Single class constraint

	if len(classes) == 1:
		classes[0].genCompleteCode(xmiFile.split('.')[0], index)

	# Case 2. Single assiciation constraint

	if len(associations) > 0:
		associations[0].genCompleteCode(xmiFile.split('.')[0], index)
	

def printUsage():
	print "Usage: viognier [-debug] <XMI file (ArgoUML perferred)>+"
	sys.exit(1)

#
# Driver starts here:
#

# Parse command line arguments
debug = False
xmiFiles = []
for i in range(1, len(sys.argv)):
	arg = sys.argv[i]
	if arg.endswith(".xmi"):
		xmiFiles.append(arg)
	elif arg == "-debug":
		debug = True
	else:
		printUsage()

if debug == True:
	print '\nGenerate Code:\n'

# Generate headers

print '#include "ast.h"\n#include "control.h"\n#include "symbol.h"\n#include <vector>\n#include <iostream>\n'
print 'using namespace std;\n'
print '#define cout cout\n#define Coutput cout\n'

print 'extern "C"'
print '{'
print '  int getCount();'
for i in range(len(xmiFiles)):
	print '  void FindPattern' + str(i) + '(SymbolTables*);'
print '}\n'

print 'extern bool isAbstract(TypeSymbol*);'
print 'extern bool isSingletonClass(SymbolTables*, TypeSymbol*);'
print 'extern bool isFacadeClass(TypeSymbol*);'
print 'extern bool isFactoryMethod(SymbolTables*, MethodSymbol*);'
print 'extern bool createsFlyweights(VariableSymbol*, TypeSymbol*);'
print 'extern VariableSymbol *isVisitorMethod(MethodSymbol*);'
print 'extern bool *bang_sets(SymbolTables*, TypeSymbol *setter, VariableSymbol *vsym);'
print 'extern bool star_delegates(SymbolTables*, AstVariableDeclarator*, TypeSymbol*, TypeSymbol*);'
print 'extern bool bang_delegates(SymbolTables *, TypeSymbol*, TypeSymbol*);'
print 'extern bool cond_delegates(SymbolTables*, VariableSymbol*);'
print 'extern bool decor_delegates(SymbolTables *, VariableSymbol*);'
print 'extern bool areIndependentHierarchies(SymbolTables*, TypeSymbol*, TypeSymbol*);'
print '\n'

# Generate Query functions for PINOT2
print 'int getCount()'
print '{'
print '   return ' + str(len(xmiFiles)) + ';'
print '}'
print '\n'

# Generate pattern detection functions for each XMI
for i in range(len(xmiFiles)):
	xmiFile = xmiFiles[i]
	genFindPattern(i, xmiFile)
