'
'	A script to generate LaTeX documentation for a package.
'	This script assumes that you have a main package, and
'	then a series of extension packages. On running, you pick the
'	main package.
'
'	This script is used in conjunction with the umldoc LaTeX
'	package.
'
'	$Author: Michael Spence$
'
'	$Date: 5/04/2000 9:43:12$
'

Const CRLF As String = chr$(13) & chr$(10)

' The various global bits and pieces
Public mainPackageName As String
Public mainPathName As String
Public hasDiagrams As Boolean
Public hasTables As Boolean
Public hasCites As Boolean


Function min(ByVal x As Integer, ByVal y As Integer) As Integer
	min = iif(x < y, x, y)
End Function

Function max(ByVal x As Integer, ByVal y As Integer) As Integer
	max = iif(x > y, x, y)
End Function

Sub DiagramBounds(theDiagram As ClassDiagram, lft As Variant, rght As Variant, tp As Variant, bm As Variant)
' Get the bounds of a diagram	
	Dim allViews As ItemViewCollection
	Dim theView As RoseItemView
	Dim theItem As RoseItem

	' First get the bounding box
	lft = 32767
	rght = -32767
	bm = 32767
	tp = -32767
	Set allViews = theDiagram.ItemViews
	For i = 1 To allViews.Count
		Set theView = allViews.getAt(i)
		lft = min(lft, theView.XPosition - theView.Width / 2)
		rght = max(rght, theView.XPosition + theView.Width / 2)
		bm = min(bm, theView.YPosition - theView.Height / 2)
		tp = max(tp, theView.YPosition + theView.Height / 2)
	Next i
End Sub	

Sub GetPackageList(pList() As String)
' Fill out the list of possible packages
	Dim allCategories As CategoryCollection 
	Dim i As Integer, count As Integer, rcount As Integer

	Set allCategories = RoseApp.CurrentModel.RootCategory.Categories
	count = allCategories.Count
	rcount = 0
	ReDim pList(count)
	For i = 1 To count
		If allCategories.getAt(i).Name <> "" Then
			rcount = rcount + 1
			pList(rcount) = allCategories.getAt(i).Name
		End If
	Next i
	ReDim Preserve pList(rcount)
End Sub

Function ChoosePackage(message As String) As Variant
' Present a list of packages for a choice
	Dim packages() As String

	GetPackageList packages	
	package = SelectBox("Package", message, packages)		
	If package < 0 Then
		ChoosePackage = ""
		Exit Function
	End If
	ChoosePackage = packages(package)
End Function

Sub SortClasses(theClasses As ClassCollection, sortedClasses As ClassCollection)
' Sort a list of classes into name and dependency order.
' Expects an empty collection in sorted classes.
	Dim temp As ClassCollection, nameSorted As ClassCollection, supers As ClassCollection
	Dim class1 As Class, class2 As Class
	Dim i As Integer, j As Integer, found As Boolean
	Dim flag() As Boolean

	sortedClasses.RemoveAll

' First sort by name order
	Set temp = New ClassCollection
	Set nameSorted = New ClassCollection
	For i = 1 To theClasses.Count
		temp.Add theClasses.getAt(i)
	Next i
	While temp.Count > 0
		Set class1 = temp.getAt(1)
		For i = 2 To temp.Count
			Set class2 = temp.getAt(i)
			If class1.Name > class2.Name Then
				Set class1 = class2
			End If
		Next i
		temp.Remove class1
		nameSorted.Add class1
	Wend

' Then sort by inheritance/realization/etc.

	Set temp = New ClassCollection
	ReDim flag(nameSorted.Count)
	For i = 1 To nameSorted.Count
		Set class1 = nameSorted.getAt(i)
		Set supers = class1.getSuperclasses()
		found = False
		For j = 1 To supers.Count
			Set class2 = supers.getAt(j)
			If nameSorted.Exists(class2) Then
				found = True
			End If
		Next j
		If Not found And Not flag(i) Then
	    	sortedClasses.Add class1
			FindChildren class1, nameSorted, sortedClasses,flag
			flag(i) = True
		End If
	Next i  
	nameSorted.RemoveAll
End Sub

Sub FindChildren(class0 As Class, nameSorted As ClassCollection, sortedClasses As ClassCollection, flag() As Boolean)
' Find Children of specified class
	Dim supers As ClassCollection
	Dim class1 As Class, class2 As Class
	Dim i As Integer, j As Integer, found As Boolean

	For i = 1 To nameSorted.Count
		Set class1 = nameSorted.getAt(i)
		Set supers = class1.getSuperclasses()
		For j = 1 To supers.Count
			Set class2 = supers.getAt(j)
			If class0.Name = class2.name And flag(i) = false Then
		    	sortedClasses.Add class1
				FindChildren class1, nameSorted, sortedClasses, flag
				flag(i) = True
			End If
		Next j
	Next i
End Sub

Function operationSignature(theOperation As Operation) As String
' Generate an operation signature for this operation
	Dim signature As String
	Dim parameters As ParameterCollection
	Dim param As Parameter
	Dim i As Integer

	signature = ""
	If theOperation.ReturnType <> "" Then
		signature = signature & theOperation.ReturnType
		signature = signature & " "
	End If
	signature = signature & theOperation.Name
	signature = signature & "("
	Set parameters = theOperation.Parameters
	For i = 1 To parameters.Count
		Set param = parameters.getAt(i)
		signature = signature & param.Type
		signature = signature & " "
		signature = signature & param.Name
		If i < parameters.Count	Then
			signature = signature & ", "
		End If
	Next i
	signature = signature & ")"
	operationSignature = signature
End Function

Function noSpaces(st As String) As String
' Remove all spaces from a string
	Dim ns, ch As String
	Dim i As Integer

	ns = ""
	For i = 1 To Len(st)
		ch = Mid(st, i, 1)
		If ch <> " " Then
			ns = ns & ch
		End If
	Next i
	noSpaces = ns
End Function

Function emptyOperation(theOperation As operation) As Boolean
' An empty operation has no documentation or semantics.  This is a bad thing.
  	If theOperation.Documentation = "" And theOperation.Semantics = "" Then
   		MsgBox "The operation, ** " & theOperation.name & " ** does not contain any documentation"
  	 End If
   	emptyOperation = false
End Function


Function operationHasStereotype(theOperation As operation) As Boolean
'Determine whether the operation has a Stereotype
	operationHasStereotype = theOperation.Stereotype <> ""
End Function


Function parameterHasDefaultValue(theParameter As parameter) As Boolean
'Determine whether a parameter has a default value.
	parameterHasDefaultValue = theParameter.InitValue <> ""
End Function


Function emptyClass(theClass As Class) As Boolean
' See if there is anything in the class worth the effort
	Dim allOperations As OperationCollection
	Dim i As Integer

	If theClass.Documentation <> "" Then
		emptyClass = False
		Exit Function
	End If
	Set allOperations = theClass.Operations
	For i = 1 To allOperations.Count
		If Not emptyOperation(allOperations.getAt(i)) Then
			emptyClass = False
			Exit Function
		End If
	Next i
	If theClass.Attributes.Count > 0 Then
		emptyClass = False
		Exit Function
	End If
	emptyClass = True
End Function

Function emptyCategory(theCategory As Category) As Boolean
' See if there is anything in the category worth the effort
' Empty classes are assumed to just be placeholders for
' the real work elsewhere
	Dim allClasses As ClassCollection
	Dim i As Integer

	If theCategory.Documentation <> "" Then
		emptyCategory = False
		Exit Function
	End If
	If theCategory.ClassDiagrams.Count > 0 Then
		emptyCategory = False
		Exit Function
	End If
	Set allClasses = theCategory.Classes
	For i = 1 To allClasses.Count
		If Not emptyClass(allClasses.getAt(i)) Then
			emptyCategory = False
			Exit Function
		End If
	Next i
	emptyCategory = True
End Function

Sub GenerateLaTeXDocHeader(fileNo As Integer)
' Insert any preamble here
End Sub

Sub GenerateLaTeXDocFooter(fileNo As Integer)
' Insert any postamble here
End Sub

Sub GenerateLaTeXWrapper(fileNo As Integer, docFile As String, package As String)
' Print out suitable header information for this document
	Print #fileNo, "\documentclass[dvips,11pt]{article}"
	Print #fileNo, "\usepackage{times}"
	Print #fileNo, "\usepackage{umldoc}"
	Print #fileNo, "\usepackage{elements}"
	Print #fileNo, "\hypersetup{"
	Print #fileNo, "	pdftitle={"; package; "},"
	Print #fileNo, "	pdfsubject={"; package; " UML model documentation},"
	Print #fileNo, "	pdfauthor=\Elementsauthor,"
	Print #fileNo, "	pdfkeywords={UML, documentation, Elements, object model, finance, "; package; "}"
	Print #fileNo, "}"
	Print #fileNo, "\title{"; package; " Package}"
	Print #fileNo, "\author{\Elementsauthor}"
	Print #fileNo, "\date{"; Format$(Date(), "mmmm dd, yyyy"); "}"
	If Not hasCites Then
		Print #fileNo, "% ";
	End If
	Print #fileNo, "\bibliographystyle{elements}"
	Print #fileNo, "\begin{document}"
	Print #fileNo, "\maketitle"
	Print #fileNo, "\tableofcontents"
	If Not hasDiagrams Then
		Print #fileNo, "% ";
	End If
	Print #fileNo, "\listoffigures"
	If Not hasTables Then
		Print #fileNo, "% ";
	End If
	Print #fileNo, "\listoftables"
	Print #fileNo, "\input{"; FileParse$(docFile, 4); "}"
	If Not hasCites Then
		Print #fileNo, "% ";
	End If
	Print #fileNo, "\bibliography{elements}"
	Print #fileNo, "\end{document}"
End Sub

Function MakeInlineDocumentation(theItem As RoseItem) As String
' Grabs any references to external documentation.
	Dim i As Integer, doc As String

	Set allDocs = theItem.ExternalDocuments
   	If theItem.Documentation = "" Then
		doc = ""
	Else
		If instr(1, theItem.Documentation, "\cite{", 1) <= 0 Then
			hasCites = True
		End If
		doc = theItem.Documentation & CRLF
	End If
	MakeInlineDocumentation = doc
End Function

Sub GenerateLaTeXDocumentation(fileNo As Integer, theItem As RoseItem, dtype As String, constraints As String, semantics As String)
' Any documentation and references
	Dim allDocs As ExternalDocumentCollection, theDoc As ExternalDocument
	Dim i As Integer, doc As String

	Set allDocs = theItem.ExternalDocuments
   	If theItem.Documentation = "" And constraints = "" And semantics = "" And allDocs.Count <= 0 Then
		Exit Sub
	End If
	Print #fileNo, "\begin{umldocumentation}"; iif(dtype = "", "", "[" & dtype & "]")
	Print #fileNo, theItem.Documentation
	If semantics <> "" Then
		Print #fileNo, ""
		Print #fileNo, semantics
	End If
	If allDocs.Count > 0 Then
		Print #fileNo, "\begin{umlexternalreferences}"
		For i = 1 To allDocs.Count
			Set theDoc = allDocs.getAt(i)
			If theDoc.isURL() Then
				Print #fileNo, "\umlexternalurl{" & theDoc.URL & "}"
			Else
				Print #fileNo, "\umlexternalfile{" & theDoc.Path & "}"
			End If
		Next i
		Print #fileNo, "\end{umlexternalreferences}"
	End If
	If constraints <> "" Then
		Print #fileNo, "\begin{umlconstraints}"
		Print #fileNo, constraints
		Print #fileNo, "\end{umlconstraints}"
	End If
	Print #fileNo, "\end{umldocumentation}"
	If instr(1, theItem.Documentation, "\cite{", 1) <= 0 Then
		hasCites = True
	End If
	If instr(1, constraints, "\cite{", 1) <= 0 Then
		hasCites = True
	End If
	If instr(1, semantics, "\cite{", 1) <= 0 Then
		hasCites = True
	End If
End Sub

Function MakeLaTeXRoleOptions(theRole As Role) As String
' List a set of role options
	Dim ropt As String

	ropt = ""
	If theRole.Navigable Then
		ropt = ropt & "navigable"
	End If
	If theRole.Aggregate Then
		If ropt <> "" Then
			ropt = ropt & ","
		End If
		ropt = ropt & "aggregate"
	End If
	If ropt <> "" Then
		ropt = "[" & ropt & "]"
	End If
	MakeLaTeXRoleOptions = ropt
End Function

Function emptyAssociation(theAssociation As Association) As Boolean
 'An empty association has no Name
 	emptyAssociation = theAssociation.Name = "" 

End Function

Sub GenerateLaTeXAssociationDocumentation(fileNo As Integer, theAssociation As Association, document As Boolean)
	Dim theRole As Role, allRoles As RoleCollection
	Dim	i As Integer
 	If Not emptyAssociation(theAssociation) Then
		Print #fileNo, "\umlassociation{"; theAssociation.Name; "}"
		Set allRoles = New RoleCollection
		allRoles.Add theAssociation.Role1
		allRoles.Add theAssociation.Role2
		For i = 1 To allRoles.Count
			Set theRole = allRoles.getAt(i)
			Print #fileNo, "\umlrole"; MakeLaTeXRoleOptions(theRole);
			Print #fileNo, "{"; theRole.Name; "}";
			Print #fileNo, "{"; theRole.GetClassName(); "}"; 
			Print #fileNo, "{"; theRole.Cardinality; "}"
		Next i
		If document Then
			GenerateLaTexDocumentation fileNo, theAssociation, "association", theAssociation.Constraints, ""
		End If
  	 End If
End Sub

Sub GenerateLaTexAssociationTable(fileNo As Integer, theCategory As Category)
' Generate a table of associations and roles
	Dim allAssociations As AssociationCollection, theAssociation As Association
	Dim allRoles As RoleCollection, theRole As Role
	Dim i As Integer, j As Integer

	hasTables = True
	Print #fileNo, "\begin{umlassocsummary}"
	Set allAssociations = theCategory.Associations
	For i = 1 To allAssociations.Count
		Set theAssociation = allAssociations.getAt(i)
		GenerateLaTeXAssociationDocumentation fileNo, theAssociation, False
	Next i
	Print #fileNo, "\end{umlassocsummary}"
End Sub

Sub GenerateLaTeXAssociationsDocumentation(fileNo As Integer, theCategory As Category, isMain As Boolean)
' Document any associations in a package
	Dim allAssociations As AssociationCollection, theAssociation As Association
	Dim i As Integer

	Set allAssociations = theCategory.Associations
	If allAssociations.Count > 0 Then
		Print #fileNo, ""
		Print #fileNo, "\begin{umlassociations}"
		GenerateLaTexAssociationTable fileNo, theCategory
		For i = 1 To allAssociations.Count
			Set theAssociation = allAssociations.getAt(i)
			GenerateLaTexAssociationDocumentation fileNo, theAssociation, True
		Next i
		Print #fileNo, "\end{umlassociations}"
	End If
End Sub

Sub GenerateLaTeXOperationDocumentation(fileNo As Integer, theOperation As Operation, opNum As Integer)
' Generate documentation for each operation in this class
	Dim allParameters As ParameterCollection
	Dim theParameter As Parameter
	Dim i As Integer
	Dim nopt As String

	If opNum > 1 Then
		nopt = "[" & CStr(opNum) & "]"
	Else
		nopt = ""
	End If
	If Not operationHasStereotype(theOperation) Then 
		Print #fileNo, "\begin{umloperation}"; nopt; "{"; theOperation.Name; "}"
		Print #fileNo, "\begin{umlpreamble}"
		Print #fileNo, "\umlsignature{"; operationSignature(theOperation); "}"
	Else
		Print #fileNo, "\begin{umloperation}"; nopt; "{"; theOperation.Name; "}"
		Print #fileNo, "\begin{umlpreamble}"
		Print #fileNo, "\umlsignature{<<"; theOperation.Stereotype; ">> "; operationSignature(theOperation); "}"		
	End If
		Set allParameters =  theOperation.Parameters
			If allParameters.Count > 0 Then
				For i = 1 To allParameters.Count
					Set theParameter = allParameters.getAt(i)
					If parameterHasDefaultValue(theParameter) Then
						Print #fileNo, "\umlparameter{"; theParameter.Name;"}{"; theParameter.Type;"}{"; theParameter.Documentation; "}"
						Print #fileNo, "The default value is {";theParameter.InitValue;"}."
					Else
						Print #fileNo, "\umlparameter{"; theParameter.Name;"}{"; theParameter.Type;"}{"; theParameter.Documentation; "}"						
					End If
				Next i
			End If
		If theOperation.Exceptions <> "" Then
			Print #fileNo, "\umlexceptions{"; theOperation.Exceptions; "}"
		End If
		Print #fileNo, "\end{umlpreamble}"
		GenerateLaTeXDocumentation fileNo, theOperation, "operation", "", theOperation.Semantics
		Print #fileNo, "\end{umloperation}"
 End Sub


Sub GenerateLaTeXClassOperationDocumentation(fileNo As Integer, theClass As Class)
' Generate documentation for each operation in this class
' We need to assign index numbers to operations that have more than
' one declaration.
	Dim allOperations As OperationCollection
	Dim theOperation As Operation
	Dim i As Integer, j As Integer
	Dim operationNames() As String, seenCount As Integer, opNum As Integer

	Set allOperations =  theClass.Operations
	If allOperations.Count > 0 Then
		ReDim operationNames(allOperations.Count) As String
		seenCount = 0
		Print #fileNo, ""
		Print #fileNo, "\begin{umloperations}"
		For i = 1 To allOperations.Count
			Set theOperation = allOperations.getAt(i)
			If Not emptyOperation(theOperation) Then
				opNum = 0
				For j = 1 To seenCount
					If operationNames(j) = theOperation.Name Then
						opNum = opNum + 1
					End If
				Next j
				seenCount = seenCount + 1
				operationNames(seenCount) = theOperation.Name
				opNum = opNum + 1
				GenerateLaTeXOperationDocumentation fileNo, theOperation, opNum
			End If
		Next i
		Print #fileNo, "\end{umloperations}"
	End If
End Sub


Sub GenerateLaTeXAttributeDocumentation(fileNo As Integer, theAttribute As Attribute)
' Document the attribute
	Dim aopts As String

	If theAttribute.Static Then
		aopts = "static"
	End If
	If theAttribute.Derived Then
		If aopts <> "" Then
			aopts = aopts & ","
		End If
		aopts = aopts & "derived"
	End If
	If aopts <> "" Then
		aopts = "[" & aopts & "]"
	End If
	Print #1, "\umlattribute"; aopts 
	Print #1, "{"; theAttribute.Name; "}";  
	Print #1, "{"; theAttribute.Type; "}";
	Print #1, "{"; theAttribute.InitValue; "}";
	Print #1, "{"; MakeInlineDocumentation(theAttribute); "}"
End Sub 

Sub GenerateLaTeXClassAttributeDocumentation(fileNo As Integer, theClass As Class)
' Document any attriutes that we have
	Dim allAttributes As AttributeCollection
	Dim theAttribute As Attribute

	Set allAttributes = theClass.Attributes
	If allAttributes.Count > 0 Then
		Print #1, ""
		Print #1, "\begin{umlattributes}"
		For i = 1 To allAttributes.Count
			GenerateLaTeXAttributeDocumentation fileNo, allAttributes.getAt(i)
		Next i
		Print #1, "\end{umlattributes}"
	End If
End Sub


Sub GenerateLaTeXRelationshipDocumentation(fileNo As Integer, theClass As class)
'	Document any relationship information about this class
	Dim allInherits As InheritRelationCollection, theInherit As InheritRelation
	Dim allRealizes As RealizeRelationCollection, theRealize As RealizeRelation
	Dim allInstantiates As InstantiateRelationCollection, theInstantiate As InstantiateRelation
	Dim allClasses As ClassCollection, aClass As Class, xClass As Class
 	Dim allInheritedBy As ClassCollection
	Dim allRealizedBy As ClassCollection
	Dim allInstantiatedBy As ClassCollection
	Dim allAssociateRoles As RoleCollection, theRole As Role
	Dim i As Integer, j As Integer

	Set allInherits = theClass.GetInheritRelations()
	Set allRealizes = theClass.GetRealizeRelations()
	Set allInstantiates = theClass.GetInstantiateRelations()
	Set allInheritedBy = New ClassCollection
	Set allRealizedBy = New ClassCollection
	Set allInstantiatedBy = New ClassCollection
	Set allClasses = RoseApp.CurrentModel.GetAllClasses
	For i = 1 To allClasses.Count
		Set aClass = allClasses.getAt(i)
		Set allInherits = aClass.GetInheritRelations()
		For j = 1 To allInherits.Count
			Set theInherit = allInherits.getAt(j)
			If theInherit.GetSupplierClass().Name = theClass.Name Then
			    Set xClass = theInherit.GetClient().TypeCast(xClass)
				allInheritedBy.Add xClass
			End If
		Next j
		Set allRealizes = aClass.GetRealizeRelations()
		For j = 1 To allRealizes.Count
			Set theRealize = allRealizes.getAt(j)
			If theRealize.GetSupplierClass().Name = theClass.Name Then
			    Set xClass = theRealize.GetClient().TypeCast(xClass)
				allRealizedBy.Add xClass
			End If
		Next j
		Set allInstantiates = aClass.GetInstantiateRelations()
		For j = 1 To allInstantiates.Count
			Set theInstantiate = allInstantiates.getAt(j)
			If theInstantiate.GetSupplierClass().Name = theClass.Name Then
			    Set xClass = theInstantiate.GetClient().TypeCast(xClass)
				allInstantiatedBy.Add xClass
			End If
		Next j
	Next i

	Set allInherits = theClass.GetInheritRelations()
	Set allRealizes = theClass.GetRealizeRelations()
	Set allInstantiates = theClass.GetInstantiateRelations()

	Set allAssociateRoles = theClass.GetAssociateRoles()

	If allInherits.Count > 0 Or allRealizes.Count > 0 Or allInstantiates.Count > 0 Or allInheritedBy.Count > 0 Or allRealizedBy.Count > 0 Or allInstantiatedBy.Count > 0 Or allAssociateRoles.Count > 0 Then
		Print #fileNo, "\begin{umlrelationships}"
		For i = 1 To allInherits.Count
			Set theInherit = allInherits.getAt(i)
			If Not IsNull(theInherit) Then
				Print #fileNo, "\umlinherits{"; theInherit.GetSupplierClass().Name; "}{"; MakeInlineDocumentation(theInherit); "}"
			End If 
		Next i
		For i = 1 To allRealizes.Count
			Set theRealize = allRealizes.getAt(i)
			Print #fileNo, "\umlrealizes{"; theRealize.GetSupplierClass().Name; "}{"; MakeInlineDocumentation(theRealize); "}"
		Next i
		For i = 1 To allInstantiates.Count
			Set theInstantiate = allInstantiates.getAt(i)
			Print #fileNo, "\umlinstantiates{"; theInstantiate.GetSupplierClass().Name; "}{"; MakeInlineDocumentation(theInstantiate); "}"
		Next i
		For i = 1 To allInheritedBy.Count
			Set aClass = allInheritedBy.getAt(i)
			Print #fileNo, "\umlinheritedby{"; aClass.Name; "}{}"
		Next i
		For i = 1 To allRealizedBy.Count
			Set aClass = allRealizedBy.getAt(i)
			Print #fileNo, "\umlrealizedby{"; aClass.Name; "}{}"
		Next i
		For i = 1 To allInstantiatedBy.Count
			Set aClass = allInstantiatedBy.getAt(i)
			Print #fileNo, "\umlinstantiatedby{"; aClass.Name; "}{}"
		Next i
		For i = 1 To allAssociateRoles.Count
			Set theRole = allAssociateRoles.getAt(i)
			Print #fileNo, "\umlassocrelationship"; MakeLaTeXRoleOptions(theRole);
			Print #fileNo, "{"; theRole.GetClassName(); "}";
			Print #fileNo, "{"; theRole.Association.Name; "}";
			Print #fileNo, "{"; theRole.Cardinality; "}"
		Next i
		Print #fileNo, "\end{umlrelationships}"
	End If
End Sub

Sub GenerateLaTeXClassDocumentation(fileNo As Integer, theClass As Class)
' Document a class, along with atrtributes, operations and such
	Dim copt As String
	Dim allParameters As ParameterCollection, theParameter As Parameter
	Dim i As Integer

	copt = ""
	If theClass.Stereotype = "Interface" Then
		copt = "[interface]"
	End If
	Print #fileNo, ""
	Print #fileNo, "\begin{umlclass}"; copt; "{"; theClass.Name; "}" 
	If theClass.Parameters.Count > 0 Then
		Print #fileNo, "\begin{umlpreamble}"
		Set allParameters = theClass.Parameters
		For i = 1 To allParameters.Count
			Set theParameter = allParameters.getAt(i)
			Print #fileNo, "\umlparameter{"; theParameter.Name; "}{"; theParameter.Type; "}{"; theParameter.Documentation; "}"
		Next i
		Print #fileNo, "\end{umlpreamble}"
	End If
	GenerateLaTexDocumentation fileNo, theClass, "class", "", ""
	GenerateLaTeXRelationshipDocumentation fileNo, theClass
	GenerateLaTeXClassAttributeDocumentation fileNo, theClass
	GenerateLaTeXClassOperationDocumentation fileNo, theClass
	Print #fileNo, "\end{umlclass}"
End Sub

Sub GenerateLaTexClassGroupDocumentation(fileNo As Integer, stereotype As String, groupName As String, allClasses As ClassCollection, isMain As Boolean)
' Divide the classes we have into groups of classes by stereotype
	Dim theClass As Class, useClasses As ClassCollection, sortedClasses As ClassCollection
	Dim i As Integer
	Dim gotType As Boolean

	Set useClasses = New ClassCollection
	For i = 1 To allClasses.Count
		Set theClass = allClasses.getAt(i)
		If theClass.Stereotype = stereotype And (isMain Or Not emptyClass(theClass)) Then
			useClasses.Add theClass
		End If
	Next i
	If useClasses.Count > 0 Then
		Set sortedClasses = New ClassCollection
		SortClasses useClasses, sortedClasses
		Print #fileNo, ""
		Print #fileNo, "\umlclassgroup{"; groupName; "}"
		For i = 1 To sortedClasses.Count
			Set theClass = sortedClasses.getAt(i)
			GenerateLaTeXClassDocumentation fileNo, theClass
		Next i
	End If
End Sub

Sub GenerateLaTeXUseCaseDocumentation(fileNo As Integer, theCategory As Category, isMain As Boolean)
	Dim allUseCases As UseCaseCollection, theUseCase As UseCase
	Dim i As Integer

	Set allUseCases = theCategory.UseCases
	If allUseCases.Count > 0 Then
		Print #fileNo, "\begin{umlusecases}"
		For i = 1 To allUseCases.Count
			Set theUseCase = allUseCases.getAt(i)
			Print #fileNo, "\begin{umlusecase}{"; theUseCase.Name; "}"
			GenerateLaTeXDocumentation fileNo, theUseCase, "usecase", "", ""
			Print #fileNo, "\end{umlusecase}"
		Next i
		Print #fileNo, "\end{umlusecases}"
	End If			 
End Sub

Sub GenerateLaTeXClassDiagram(fileNo As Integer, fName As String, theDiagram As ClassDiagram, i As Integer)
' Draw a class diagram in LaTex.
	Dim epsName As String, wmfName As String
	Dim diagramNo As Integer
	Dim lft, rght, tp, bm As Variant
	Dim dopt As String

	lft = 1
	rght = 1
	tp = 1
	bm = 1
	DiagramBounds theDiagram, lft, rght, tp, bm
	epsName = lcase(fName & ".eps")
	wmfName = lcase(mainPathName & "/" & fName & ".wmf")
	theDiagram.ZoomFactor = 100
	theDiagram.Render wmfName
	dopt = iif((rght - lft) > (tp - bm), "[wide]", "")
	Print #fileNo, "\begin{umlclassdiagram}"; dopt; "{"; theDiagram.Name; "}{"; epsName; "}"
	Print #fileNo, "\end{umlclassdiagram}"
	If (i Mod 5) = 0 Then
		Print #fileNo, "\clearpage"
	End If
End Sub

Sub GenerateLaTeXClassDiagrams(fileNo As Integer, theCategory As Category, isMain As Boolean)
' Generate the class diagrams for a category
	Dim allClassDiagrams As ClassDiagramCollection
	Dim theClassDiagram As ClassDiagram
	Dim i As Integer
	Dim fName As String

	Set allClassDiagrams = theCategory.ClassDiagrams
	If allClassDiagrams.Count > 0 Then
		hasDiagrams = True
		For i = 1 To allClassDiagrams.Count
			Set theClassDiagram = allClassDiagrams.getAt(i)
			If theCategory.Name = mainPackageName Then
				fName = noSpaces(theCategory.Name & Str$(i))
			Else
				fName = noSpaces(mainPackageName & "-" & theCategory.Name & Str$(i))	
			End If
			GenerateLaTeXClassDiagram fileNo, fName, theClassDiagram, i
 		Next i
	End If
End Sub

Sub GenerateLaTeXCategoryDocumentation(fileNo As Integer, theCategory As Category, isMain As Boolean)
' Print out suitable category documentation
' The main category gets the full treatment
' Any non-main category gets an abbreviated treatment so that
' Only class extensions or extra doumentation is recorded.
	Dim allClassDiagrams As ClassDiagramCollection
	Dim theClassDiagram As ClassDiagram
	Dim allClasses As ClassCollection
	Dim i As Integer, eopt As String

	If Not isMain And emptyCategory(theCategory) Then
		Exit Sub
	End If
	eopt = iif(isMain, "", "[extension]")
	Print #fileNo, "\begin{umlcategory}"; eopt; "{"; theCategory.Name; "}"
	GenerateLaTeXDocumentation fileNo, theCategory, "category", "", ""
	GenerateLaTeXUseCaseDocumentation fileNo, theCategory, isMain
	Set allClasses = theCategory.Classes
	GenerateLaTeXClassGroupDocumentation fileNo, "Actor", "Actors", allClasses, isMain
	GenerateLaTeXClassGroupDocumentation fileNo, "Interface", "Interfaces", allClasses, isMain
	GenerateLaTeXClassGroupDocumentation fileNo, "Component Interface", "Component Interfaces", allClasses, isMain
	GenerateLaTeXClassGroupDocumentation fileNo, "Service Interface", "Service Interfaces", allClasses, isMain
	GenerateLaTeXClassGroupDocumentation fileNo, "Architectural Service Interface", "Architectural Service Interfaces", allClasses, isMain
	GenerateLaTeXClassGroupDocumentation fileNo, "", "Classes", allClasses, isMain
	GenerateLaTeXClassGroupDocumentation fileNo, "Service", "Services", allClasses, isMain
	GenerateLaTeXClassGroupDocumentation fileNo, "Architectural Service", "Architectural Services", allClasses, isMain
	GenerateLaTeXClassGroupDocumentation fileNo, "Exception", "Exceptions", allClasses, isMain
	GenerateLaTeXClassGroupDocumentation fileNo, "Enumeration", "Enumerations", allClasses, isMain
	GenerateLaTeXAssociationsDocumentation fileNo, theCategory, isMain
	GenerateLaTeXClassDiagrams fileNo, theCategory, isMain
	Print #fileNo, "\end{umlcategory}"
	Print #fileNo, "\clearpage"
End Sub

Sub GenerateLaTeXModelDocumentation()
' Open a file and print out the documentation
	Dim allCategories As CategoryCollection
	Dim theCategory As Category
	Dim i As Integer, fileNo As Integer
	Dim wrapperName As String, docName As String

	wrapperName = mainPathName & "/" & lcase(noSpaces(mainPackageName) & "-package.tex")
	docName = mainPathName & "/" & lcase(noSpaces(mainPackageName) & ".tex")

	fileNo = FreeFile()
	Open docName For Output Access Write As #fileNo
	GenerateLaTeXDocHeader fileNo
	Set allCategories = RoseApp.CurrentModel.RootCategory.Categories
	For i = 1 To allCategories.Count
		Set theCategory = allCategories.GetAt(i)
		If theCategory.Name = mainPackageName Then
			GenerateLaTeXCategoryDocumentation fileNo, theCategory, True
		End If
	Next i
	For i = 1 To allCategories.Count
		Set theCategory = allCategories.GetAt(i)
		If theCategory.Name <> mainPackageName Then
			GenerateLaTeXCategoryDocumentation fileNo, theCategory, False
		End If
	Next i
	GenerateLaTeXDocFooter fileNo
	Close #fileNo

	fileNo = FreeFile()
	Open wrapperName For Output Access Write As #fileNo
	GenerateLaTeXWrapper fileNo, docName, mainPackageName
	Close #fileNo
End Sub

Sub Main
' Generate a LaTeX document describing the (mumble)
	Dim filename As String

   	mainPackageName = ChoosePackage("Main Package")
	If mainPackageName = "" Then
		Exit Sub
	End If 
	filename = SaveFileName$ ("Export Package Documentation", "LaTeX files:*.tex")
	If filename = "" Then
		Exit Sub
	End If
	mainPathName = FileParse$(filename, 2)
	hasDiagrams	= False
	hasTables = False
	hasCites = False
	GenerateLaTeXModelDocumentation
End Sub
