#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This file is part of the Coral project.
# Please read the copyright notice in the LICENSE file.

# diml2xmidigen - Generates diagram element generators based on a DIML model
#
# SYNOPSIS
#
# diml2xmidigen [-o outputfile] models
#
#
# DESCRIPTION
#
# models: One or more DIML 1.0 models describing the XMI-DI hierarchy of model elements
# 
# outputfile: The file where the output code is written. If none specified, the output
# is written to stdout.
# 
# diml2xmidigen reads the models describing how the XMI-DI hierarchy should be generated
# and generates diagram element generator classes based on the definitions in the models.
# uml2xmidigen also generates synchronization code to maintain the specified XMI-DI
# hierachy, that can be run from an observer.
#
# OPTIONS
# -h, --help : help 
# -o "outputfile": Writes the output to "outputfile". If omitted, output is directed to stdout
# -p "path": Writes the extensions in Coral, the extension uses "path" as prefix for the generated classes
#
# EXAMPLES
#
# diml2xmidigen -o degen.py ClassDiagram.xml
# 
# AUTHORS
#
# Torbj?Lundkvist 2004-2005
# Coral Team - 2004-08



import coral
import re, string
from coral.lgen.codeartifact import CodeArtifact
import getopt,sys


DI = coral.lang.XMIDI20
DIML = coral.lang.DIML10
CEX = coral.lang.CoralEx10

perpetual = 1
path = []
isOrdered = True

importLanguage=True

def __comparefunction(x,y):
    if x.name>y.name:
        return 1
    return -1


def __elementToString(element):
    p = element.package
    return unicode(p.name)+"."+unicode(p.version)+"."+unicode(p.revision)+"::"+unicode(element.name)

def __genExtEntry(element, importpath):
    assert element
    assert importpath
    
    e = CEX.Addins.DiagramElementCreator(name=unicode(element.name))
    e.path = importpath + "." + unicode(element.name) + "DEG"
    e.element_kind = __elementToString(element)

    return e
    

def __getParentElement(node):
    """ This method returns the parent of a certain class in the class tree. """
    try:
        idx = path.index(node)
    except:
        return path[-1]

    return path[idx-1]

def __buildRetrieve(selection):
    if not (selection.type or selection.parameterType or selection.parameterValue):
        return ""
    else:
        if selection.type and not (selection.parameterType or selection.parameterValue):
            return "element."+unicode(selection.property.name)+".select(lambda x:x.oclIsKindOf("+unicode(selection.type.name)+"))"
        elif not selection.type and selection.parameterType and selection.parameterValue:
            return "element."+unicode(selection.property.name)+".select(lambda x:x."+unicode(selection.parameterType.name)+" "+unicode(selection.operation)+" \""+unicode(selection.parameterValue)+"\"))"
        elif selection.type and selection.parameterType and selection.parameterValue:
            return "element."+unicode(selection.property.name)+".select(lambda x:x.oclIsKindOf("+unicode(selection.type.name)+") and x."+unicode(selection.parameterType.name)+" "+unicode(selection.operation)+" \""+unicode(selection.parameterValue)+"\")"

def __childTypeConstraint(selection):
    if selection.type:
        return ".oclIsKindOf("+unicode(selection.type.name)+")"
    else:
        return ""
        
def __getLinkToElement(thisNode):
    idx = path.index(thisNode)
    assert idx > 0
    prevNode = path[idx-1]
    contained = None
    return __getLinkBetweenElements(thisNode, prevNode)


def __getLinkBetweenElements(deeper, parent):

    for cnt in parent.children:
        if cnt.child == deeper:
            return cnt

    return None


def __getSeparator(node):
    parent = __getParentElement(node)
    cnt = __getLinkBetweenElements(node, parent)
    separator = None
    if cnt:
        separator = cnt.separator
    return separator


def __getSurroundingNodes(node):
    parent = __getParentElement(node)
    childlinks = parent.children
    i=0

    for cl in childlinks:
        child = cl.child
        if child == node:
            break
        i += 1
    first = i
    last = first
    if last == len(childlinks)-1:
        last = -1
    else:
        for idx2 in xrange(last+1, len(childlinks)):
            right = childlinks[idx2].child
            if right.oclIsKindOf(DIML.GraphNodePart) and  right.typeInfo:
                last=idx2
                break
            
    prevnode = childlinks[first-1].child
    nextnode = childlinks[last].child
    
    return first, prevnode, last, nextnode

def __writeContainers(gn, con, ca, firstTime):
    global path, perpetual
    ## Find out which containers need to be found/created to proceed with synch
    oldCon = ""
    for cnt in xrange(1,len(path)):
        curnode = path[cnt]
        
        if firstTime:
            oldCon = "elementGN"
            firstTime = False
        else:
            oldCon = con
        con = "container_" + str(perpetual)
        perpetual += 1
        ca.add(con + ', ' + con+'_idx = searchForSimpleGraphNode(' + oldCon + '.contained, \"' + unicode(curnode.typeInfo) + '\")')
        ca.add("if not "+con+":")
        ca.indent(1)
        link2this = __getLinkToElement(curnode)
        createconstraint = None
        if link2this:
            guard = link2this.guard
            if guard:
                createconstraint = unicode(guard.expression)

        if createconstraint:
            ca.add("if "+createconstraint+":")
            ca.indent(1)
            ca.add(con+' = self.createSimpleGraphNode(\"'+str(curnode.typeInfo)+'\")')
            for p in curnode.diProperty:
                ca.add(con + '.property.insert(DI.Property(key="'+unicode(p.key)+'", value="'+unicode(p.value)+'"))')

            parent = __getParentElement(path[-1])
            childlinks = parent.children
            i=0
            for cl in childlinks:
                child = cl.child
                if child == path[-1]:
                    break
                i += 1
            first = i
            node_index = i

            if i != 0:
                for idx in xrange(i-1, -1,-1):
                    c = childlinks[idx]
                    guard = c.guard
                    if not guard:
                        first = idx
                    else:
                        first -= 1

            if node_index == 0:
                ca.add(oldCon+".contained.insert("+con+",0)")
            else:
                ca.add("ins_pt="+str(first-1))                    
                for idx2 in xrange(first, node_index):
                    ca.add("srch_cn, srch_idx = searchForSimpleGraphNode(" + oldCon + ".contained, \"" + unicode(childlinks[idx2].child.typeInfo) + "\")")
                    ca.add("if srch_idx != -1:")
                    ca.indent(1)
                    ca.add("ins_pt = srch_idx")


                    beforeconstraint = None
                    link2this = __getLinkBetweenElements(childlinks[idx2].child, __getParentElement(path[-1]))
                    if link2this:
                        guard = link2this.guard
                        if guard:
                            beforeconstraint = unicode(guard.expression)

                    if beforeconstraint:
                        ca.indent(-1)
                        ca.add("else:")
                        ca.indent(1)
                        ca.add("if "+beforeconstraint+":")
                        ca.indent(1)
                        ca.add('srch_cn = self.createSimpleGraphNode(\"'+unicode(childlinks[idx2].child.typeInfo)+'\")')
                        for p in childlinks[idx2].child.diProperty:
                            ca.add('srch_cn.property.insert(DI.Property(key="'+unicode(p.key)+'", value="'+unicode(p.value)+'"))')
                        ca.add("ins_pt += 1")
                        ca.add(oldCon+".contained.insert(srch_cn,ins_pt)")
                        ca.indent(-1)
                    ca.indent(-1)

                ca.add(oldCon+".contained.insert("+con+",ins_pt+1)")
            ca.indent(-1)
            ca.add("else:")
            ca.indent(1)
            ca.add("continue")
            ca.indent(-1)
        else:
            ca.add("continue")

        ca.indent(-1)
        if createconstraint:
            ca.add("if "+con+" and not "+createconstraint+":")
            ca.indent(1)
            ca.add(con+".container=None")
            ca.add("continue")
            ca.indent(-1)

    return con, oldCon

def __gen_xmidi(self, selfstring, gn, ca, metaclass, containerstring):
    """ This method generates the createDiagramElement method. """
    global perpetual
    nodename = "node_" + str(perpetual)
    perpetual += 1

    # create diagram element with children
    byExt = False
    if gn.oclIsKindOf(DIML.Delegation):
        byExt = True
        ca.add("if "+selfstring+":")
        ca.indent(1)
        ca.add("ext = DiagramElementGenerator.getExtension("+selfstring+".__type__())")
        ca.add("if ext:")
        ca.indent(1)
        ca.add(nodename + " = ext.createDiagramElement("+selfstring+", xparent="+containerstring+", container="+containerstring+")")
        ca.indent(-2)
    elif gn.oclIsKindOf(DIML.GraphNodePart):
        # Create a graphnode, use defaultsize from the model if given.
        # Position is taken from the action.
        if gn.typeInfo:
            ca.add(nodename + " = self.createSimpleGraphNode(\""+unicode(gn.typeInfo)+"\", container="+containerstring+")")
            for p in gn.diProperty:
                ca.add(nodename + '.property.insert(DI.Property(key="'+unicode(p.key)+'", value="'+unicode(p.value)+'"))')
        else:
            if bool(gn.skipXMIDICreation):
                ca.add(nodename+" = None")
            else:
                if gn.mapping:
                    ca.add(nodename + " = self.createGraphNode("+selfstring+", **kwargs)")
                else:
                    ca.add(nodename + " = self.createGraphNode("+selfstring+")")
                for p in gn.diProperty:
                    ca.add(nodename + '.property.insert(DI.Property(key="'+unicode(p.key)+'", value="'+unicode(p.value)+'"))')
            
    elif gn.oclIsKindOf(DIML.GraphEdgePart):
        # Create a graphEdge, with arguments taken from the action
        ca.add(nodename + " = self.createGraphEdge("+selfstring+", **kwargs)")
        for p in gn.diProperty:
            ca.add(nodename + '.property.insert(DI.Property(key="'+unicode(p.key)+'", value="'+unicode(p.value)+'"))')

    ss = selfstring
    
    extra_indent = 0
    if not gn.oclIsKindOf(DIML.Delegation):
        for contained in gn.children:
            child = contained.child
            extra_indent = 0
            separator = contained.separator
            # Insert constraints
            guard = contained.guard
            if guard:
                extra_indent += 1
                ca.add("if " + unicode(guard.expression) + ":")
                ca.indent(1)
            # which property are we refering to
            selection = contained.selection 
            if selection:
                separator = contained.separator
                # insert separators between the elements
                if separator:
                    idx_name = "idx_" + str(perpetual)
                    perpetual += 1
                    ca.add(idx_name + " = 0")

                # get the property of the abstract element
                ca.add("attr = getattr(" + selfstring + ", \"" + unicode(selection.property.name) +"\")")

                # check if the property is a list or not
                if selection.property.multiplicity_upper == 1:
                    childtypeconstraint = __childTypeConstraint(selection)
                    ss = "self_" + str(perpetual)
                    perpetual += 1
                    ca.add(ss+"=attr")
                    if childtypeconstraint:
                        ca.add("if "+ss+" and "+ss+childtypeconstraint+":")
                        ca.indent(1)
                        extra_indent += 1
                    
                else:
                    # it is a list
                    ss = "self_" + str(perpetual)
                    perpetual += 1
                    ca.add("for " + ss + " in attr:")
                    extra_indent += 1
                    ca.indent(1)
                    # retrieve is a more specific constraint that tells us which elements should have a graphnode
                    retrievestring = __buildRetrieve(selection)
                    if retrievestring:
                        ca.add("if "+ss+" in "+unicode(retrievestring)+":")
                        ca.indent(1)
                        extra_indent += 1

            ## Create graphnodes recursevily      
            c = __gen_xmidi(self, ss, child, ca, metaclass, nodename)

            if separator:
                # do not add a separator after the last element
                if retrievestring:
                    ca.add("if " + idx_name + " != len("+unicode(retrievestring)+")-1:")
                else:
                    ca.add("if " + idx_name + " != len(attr)-1:")
                ca.indent(1)
                sep_name = __gen_xmidi(self, ss, separator.subtree, ca, metaclass, nodename)
                ca.add(nodename + ".contained.append(" + sep_name + ")")
                ca.indent(-1)
                ca.add(idx_name + " += 1")

            # reset the indentation
            ca.indent(-extra_indent)

    return nodename


def __gen_xmidi_synch_multi(self, selfstring, gn, ca, metaclass, containerstring, synchproperty):
    """ This method generates the synchronization of a compartment shared
    by two or more property synchronizations. It also synchronizes all simple
    graphnodes, i.e. adds or removes them whenever the mapped constraint
    specifies so. The method is non-recursive, and attempts to preserve all
    existing graphnodes. """
    
    global perpetual

    ss = selfstring
    ca.add("idx = 0")
    for contained in gn.children:
        child = contained.child
        extra_indent = 0
        separator = contained.separator

        nodeconstraint = ""
        nodeproperty = ""
        retrievestring = ""
        # Insert constraints
        guard = contained.guard
        if guard:
            nodeconstraint = unicode(guard.expression)
        # which property are we refering to
        selection = contained.selection
        if selection:
            nodeproperty = selection.property
            separator = contained.separator
            retrievestring = __buildRetrieve(selection)
            childtypeconstraint = __childTypeConstraint(selection)

        if child.oclIsKindOf(DIML.Delegation):
            if nodeconstraint:
                ca.add("if "+nodeconstraint+":")
                extra_indent += 1
                ca.indent(1)
            ca.add("attr = getattr("+selfstring+", \""+unicode(nodeproperty.name)+"\")")
            singleslot = bool(nodeproperty.multiplicity_upper == 1)
            # check if the property is a list or not
            if singleslot:
                ss = "self_" + str(perpetual)
                perpetual += 1
                ca.add(ss+"=attr")

            else:
                # it is a list
                ss = "self_" + str(perpetual)
                perpetual += 1
                ca.add("for " + ss + " in attr:")
                extra_indent += 1
                ca.indent(1)

            if singleslot:
                if childtypeconstraint:
                    ca.add("if "+ss+" and "+ss+childtypeconstraint+":")
                else:
                    ca.add("if "+ss+":") 
            else:
                if retrievestring:
                    ca.add("if "+ss+" and "+ss+" in "+retrievestring+":")
                else:
                    ca.add("if "+ss+":")
            ca.indent(1)

            if singleslot:
                ca.add("if len(old_di)!=0 and len(old_di)>idx and not hasattr(old_di[idx].semanticModel, \"typeInfo\") and old_di[idx].semanticModel.element == "+ss+":")
                ca.indent(1)
                ca.add("idx += 1")
                ca.indent(-1)
                if nodeproperty == synchproperty:
                    ca.add("elif len(old_di)==0 or len(old_di)>=idx or not hasattr(old_di[idx].semanticModel, \"typeInfo\") and old_di[idx].semanticModel.element != "+ss+":")
                    ca.indent(1)
                    ca.add("ext = DiagramElementGenerator.getExtension("+ss+".__type__())")
                    ca.add("if ext:")
                    ca.indent(1)
                    newnode = "node_" + str(perpetual)
                    perpetual += 1
                    ca.add(newnode+" = ext.createDiagramElement("+ss+", xparent="+containerstring+")")
                    ca.add("old_di.insert("+newnode+",idx)")
                    if gn.oclIsKindOf(DIML.GraphEdgePart):
                        ca.add("if "+ containerstring +".oclIsKindOf(DI.GraphEdge) and len("+containerstring+".waypoints) >= 2:")
                        ca.indent(1)
                        ca.add(newnode+".position.x = ("+containerstring+".waypoints[0].x+"+containerstring+".waypoints[-1].x)/2")
                        ca.add(newnode+".position.y = ("+containerstring+".waypoints[0].y+"+containerstring+".waypoints[-1].y)/2-20")
                        ca.indent(-1)
                    ca.add("idx += 1")
                    ca.indent(-2)
                    if nodeconstraint:
                        ca.indent(-2)
                        extra_indent -= 1
                    else:
                        ca.indent(-1)
                    ca.add("else:")
                    ca.indent(1)
                    ca.add("if len(old_di)!=0 and len(old_di)>idx and not hasattr(old_di[idx].semanticModel, \"typeInfo\") and old_di[idx].semanticModel.element in old_am:")
                    ca.indent(1)
                    ca.add("old_di.drop_index(idx)")
                    ca.indent(-1)
            else:
                ca.add("if len(old_di)!=0 and len(old_di)>idx and not hasattr(old_di[idx].semanticModel, \"typeInfo\") and old_di[idx].semanticModel.element in attr:")
                ca.indent(1)
                ca.add("idx += 1")
                ca.indent(-1)
                if nodeproperty == synchproperty:
                    ca.add("elif len(old_di)==0 or len(old_di)>=idx or not hasattr(sm, \"typeInfo\") and sm.element not in attr:" )
                    ca.indent(1)
                    ca.add("ext = DiagramElementGenerator.getExtension("+ss+".__type__())")
                    ca.add("if ext:")
                    ca.indent(1)
                    newnode = "node_" + str(perpetual)
                    perpetual += 1
                    ca.add(newnode+" = ext.createDiagramElement("+ss+", xparent="+containerstring+")")
                    ca.add("old_di.insert("+newnode+",idx)")
                    if gn.oclIsKindOf(DIML.GraphEdgePart):
                        ca.add("if "+ containerstring +".oclIsKindOf(DI.GraphEdge) and len("+containerstring+".waypoints) >= 2:")
                        ca.indent(1)
                        ca.add(newnode+".position.x = ("+containerstring+".waypoints[0].x+"+containerstring+".waypoints[-1].x)/2")
                        ca.add(newnode+".position.y = ("+containerstring+".waypoints[0].y+"+containerstring+".waypoints[-1].y)/2-20")
                        ca.indent(-1)
                    ca.add("idx += 1")
                    ca.indent(-2)

            ca.indent(-1)
            ca.indent(-extra_indent)
            ca.add("")

        elif child.oclIsKindOf(DIML.GraphNodePart) and child.typeInfo:
            newnode = "node_"+str(perpetual)
            perpetual += 1
            if nodeconstraint:
                ca.add("if "+nodeconstraint+":")
                ca.indent(1)
                extra_indent += 1
            ca.add("if len(old_di)!=0 and len(old_di)>idx and hasattr(old_di[idx].semanticModel, \"typeInfo\") and old_di[idx].semanticModel.typeInfo == \""+unicode(child.typeInfo)+"\":")
            ca.indent(1)
            ca.add("idx += 1")
            ca.indent(-1)
            ca.add("else:")
            ca.indent(1)
            ca.add(newnode +" = self.createSimpleGraphNode(\""+unicode(child.typeInfo)+"\")")
            for p in child.diProperty:
                ca.add(newnode + '.property.insert(DI.Property(key="'+unicode(p.key)+'", value="'+unicode(p.value)+'"))')
            ca.add("old_di.insert("+newnode+",idx)")
            ca.add("idx += 1")
            ca.indent(-1)

            if nodeconstraint:
                ca.indent(-1)
                ca.add("else:")
                ca.indent(1)
                ca.add("if len(old_di)!=0 and len(old_di)>idx and hasattr(old_di[idx].semanticModel, \"typeInfo\") and old_di[idx].semanticModel.typeInfo == \""+unicode(child.typeInfo)+"\":")
                ca.indent(1)
                ca.add(newnode+" = old_di[idx]")
                ca.add("old_di.remove("+newnode+")")
                ca.indent(-1)

            ca.indent(-extra_indent)
            ca.add("")

    ca.add("for e in xrange(idx, len(old_di)):")
    ca.indent(1)
    ca.add("old_di[e].container = None")
    ca.indent(-1)
    ca.add("")


def __gen_leading_nodes(gn, ca):
    """ The child containeds of a ConcretePart can point to ConcreteParts
    and Delegations. This method creates the leading GraphNodes before a
    Delegation, to make sure all nodes are present before attaching
    subtrees from a Delegation. """
    
    global perpetual

    ca.add("idx = 0")
    for contained in gn.children:
        child = contained.child
        extra_indent = 0
 
        nodeconstraint = ""
 
        # Insert constraints
        guard = contained.guard
        if guard:
            nodeconstraint = unicode(guard.expression)
 
        if child.oclIsKindOf(DIML.Delegation):
            break
        elif child.oclIsKindOf(DIML.GraphNodePart) and child.typeInfo:
            newnode = "node_"+str(perpetual)
            perpetual += 1
            if nodeconstraint:
                ca.add("if "+nodeconstraint+":")
                ca.indent(1)
                extra_indent += 1
            ca.add("if len(old_di)!=0 and len(old_di)>idx and hasattr(old_di[idx].semanticModel, \"typeInfo\") and old_di[idx].semanticModel.typeInfo == \""+unicode(child.typeInfo)+"\":")
            ca.indent(1)
            ca.add("idx += 1")
            ca.indent(-1)
            ca.add("else:")
            ca.indent(1)
            ca.add(newnode +" = self.createSimpleGraphNode(\""+unicode(child.typeInfo)+"\")")
            for p in child.diProperty:
                ca.add(newnode + '.property.insert(DI.Property(key="'+unicode(p.key)+'", value="'+unicode(p.value)+'"))')
            ca.add("old_di.insert("+newnode+",idx)")
            ca.add("idx += 1")
            ca.indent(-1)

            if nodeconstraint:
                ca.indent(-1)
                ca.add("else:")
                ca.indent(1)
                ca.add("if len(old_di)!=0 and len(old_di)>idx and hasattr(old_di[idx].semanticModel, \"typeInfo\") and old_di[idx].semanticModel.typeInfo == \""+unicode(child.typeInfo)+"\":")
                ca.indent(1)
                ca.add(newnode+" = old_di[idx]")
                ca.add("old_di.remove("+newnode+")")
                ca.indent(-1)

            ca.indent(-extra_indent)
            ca.add("start_idx = idx-1")
            ca.add("")


def __gen_trailing_nodes(gn, ca):
    """ The child containeds of a ConcretePart can point to ConcreteParts
    and Delegations. This method creates the trailing GraphNodes before a
    Delegation, to make sure all nodes are present after attaching
    subtrees from a Delegation. """
    
    global perpetual

    ca.add("lidx = len(old_di)")

    reversed = []
    
    for contained in gn.children:
        reversed.insert(0, contained)
        
    for cnt in reversed:
        child = cnt.child
        extra_indent = 0
 
        nodeconstraint = ""
 
        # Insert constraints
        guard = cnt.guard
        if guard:
            nodeconstraint = unicode(guard.expression)
 
        if child.oclIsKindOf(DIML.Delegation):
            break
        elif child.oclIsKindOf(DIML.GraphNodePart) and child.typeInfo:
            newnode = "node_"+str(perpetual)
            perpetual += 1
            if nodeconstraint:
                ca.add("if "+nodeconstraint+":")
                ca.indent(1)
                extra_indent += 1
            ca.add("if len(old_di)!=0 and len(old_di)>(lidx-1) and hasattr(old_di[lidx-1].semanticModel, \"typeInfo\") and old_di[lidx-1].semanticModel.typeInfo == \""+unicode(child.typeInfo)+"\":")
            ca.indent(1)
            ca.add("lidx -= 1")
            ca.indent(-1)
            ca.add("else:")
            ca.indent(1)
            ca.add(newnode +" = self.createSimpleGraphNode(\""+unicode(child.typeInfo)+"\")")
            for p in child.diProperty:
                ca.add(newnode + '.property.insert(DI.Property(key="'+unicode(p.key)+'", value="'+unicode(p.value)+'"))')
            ca.add("old_di.insert("+newnode+",lidx)")
            ca.add("lidx -= 1")
            ca.indent(-1)

            if nodeconstraint:
                ca.indent(-1)
                ca.add("else:")
                ca.indent(1)
                ca.add("if len(old_di)!=0 and len(old_di)>(lidx-1) and hasattr(old_di[lidx-1].semanticModel, \"typeInfo\") and old_di[lidx-1].semanticModel.typeInfo == \""+unicode(child.typeInfo)+"\":")
                ca.indent(1)
                ca.add(newnode+" = old_di[lidx-1]")
                ca.add("old_di.remove("+newnode+")")
                ca.indent(-1)

            ca.indent(-extra_indent)
            ca.add("")


def createIsMinorElement( mapping, ca ):
    """ Every DEG class gets a isMinorElement method. All
    mappings for a metaclass returns a value, default in
    DIML 1.0 is false"""
    
    ca.add("return "+str(bool(mapping.isMinorElement)))


def createAcceptsConnectors( mapping, ca ):
    """ Every DEG class gets a acceptsConnectors method. All
    mappings for a metaclass returns a value, default in
    DIML 1.0 is false"""
    ca.add("return "+str(bool(mapping.acceptsConnectors)))

def createSuitableDiagrams( mapping, ca ):
    """ Creates the suitableDiagrams method for the DEG classes,
    whose graphElements can be put in a diagram. """
    
    value = "["
    idx = 0
    for d in mapping.suitableDiagrams:
        value += '\"'+unicode(d)+'\"'
        if idx < (len(mapping.suitableDiagrams)-1):
            value += ", "
        idx += 1
    value += "]"
    ca.add("return " + value)


def createSynchronizeContents(self, selfstring, gn, ca, metaclass, property=None, contained=None):
    """ This method generates the synchronizeContents method. """
    global perpetual, isOrdered, path
    nodename = "node_" + str(perpetual)
    perpetual += 1
    firstTime = True
    noXMI=None
    proxyconnectors = None
    if gn.oclIsKindOf(DIML.GraphNodePart):
        noXMI = bool(gn.skipXMIDICreation)
        proxyconnectors = gn.proxyConnector
    
    ## This block generates the link-synchronisation of the "easier" graphedges
    if gn.oclIsKindOf(DIML.GraphEdgePart):

        node_index = 0
        if len(gn.connector) == 2:
            
            for conn in gn.connector:
                if conn.nextProperty:
                    continue
                ca.add("if property == \""+ unicode(conn.property.name) + "\""+":")
                ca.indent(1)
                ca.add("new_di = []")
                ca.add("if new_am:")
                ca.indent(1)
                mult = ""
                if conn.property.multiplicity_upper != 1:
                    mult = "[0]"
                ca.add("new_di = new_am"+ mult  +".xmidi_get_graphelements()")
                ca.indent(-1)
                ca.add("if len(elementGN.anchor)>1:")
                ca.indent(1)
                ca.add("if elementGN.anchor["+str(node_index)+"].graphElement in new_di:")
                ca.indent(1)
                ca.add("continue")
                ca.indent(-1)
                ca.add("if len(elementGN.anchor["+str(node_index)+"].graphEdge) == 1:")
                ca.indent(1)
                ca.add("elementGN.anchor["+str(node_index)+"].__resetAttrs__()")
                ca.indent(-1)
                ca.add("else:")
                ca.indent(1)
                ca.add("elementGN.anchor.drop_index("+str(node_index)+")")
                ca.indent(-2)
                ca.add("if new_di:")
                ca.indent(1)
                ca.add("all_di = geInDiagram(new_di, elementGN.__getRoot__())")
                ca.add("for di in all_di:")
                ca.indent(1)
                ca.add("ext = DiagramElementGenerator.getExtension(new_am"+mult+".__type__())")
                ca.add("if ext and not ext.acceptsConnectors(di.semanticModel.element, xparent=di.container):")
                ca.indent(1)
                ca.add("continue")
                ca.indent(-1)
                ca.add("if len(elementGN.anchor) == 2: continue")
                ca.add("if len(elementGN.anchor) == 2 and elementGN.anchor["+str(node_index)+"].graphElement == di:")
                ca.indent(1)
                ca.add("continue")
                ca.indent(-1)
                ca.add("gc = DI.GraphConnector(graphElement = di)")
                ca.add("elementGN.anchor.insert(gc, "+str(node_index)+")")
                ca.indent(-3)
                ca.add("")
                node_index +=1

        elif len(gn.connector) == 1:

            for conn in gn.connector:
                if conn.nextProperty:
                    continue
                ca.add("if property == \""+ unicode(conn.property.name) + "\""+":")
                ca.indent(1)
                ca.add("idx = -1")
                ca.add("for end in new_am:")
                ca.indent(1)
                ca.add("idx += 1")
                ca.add("new_di = []")
                ca.add("new_di = end.xmidi_get_graphelements()")
                ca.add("if len(elementGN.anchor)>1:")
                ca.indent(1)
                ca.add("if elementGN.anchor[idx].graphElement in new_di:")
                ca.indent(1)
                ca.add("continue")
                ca.indent(-1)
                ca.add("if len(elementGN.anchor[idx].graphEdge) == 1:")
                ca.indent(1)
                ca.add("elementGN.anchor[idx].__resetAttrs__()")
                ca.indent(-1)
                ca.add("else:")
                ca.indent(1)
                ca.add("elementGN.anchor.drop_index(idx)")
                ca.indent(-2)
                ca.add("if new_di:")
                ca.indent(1)
                ca.add("all_di = geInDiagram(new_di, elementGN.__getRoot__())")
                ca.add("for di in all_di:")
                ca.indent(1)
                ca.add("ext = DiagramElementGenerator.getExtension(new_am[end].__type__())")
                ca.add("if ext and not ext.acceptsConnectors(di.semanticModel.element, xparent=di.container):")
                ca.indent(1)
                ca.add("continue")
                ca.indent(-1)
                ca.add("if len(elementGN.anchor) == 2: continue")
                ca.add("if len(elementGN.anchor) == 2  and elementGN.anchor[idx].graphElement == gnode:")
                ca.indent(1)
                ca.add("continue")
                ca.indent(-1)
                ca.add("gc = DI.GraphConnector(graphElement = di)")
                ca.add("elementGN.anchor.insert(gc, idx)")
                ca.indent(-4)
                ca.add("")
        else:
            assert 0, "Connector multiplicity allows only 1 or 2 connectors"

    if gn.oclIsKindOf(DIML.GraphNodePart) and gn.proxyConnector:
        for pconn in gn.proxyConnector:
            ca.add("if property == \""+ unicode(pconn.nextProperty.name) + "\""+":")
            ca.indent(1)
            ca.add("new_di = []")
            ca.add("if new_am:")
            ca.indent(1)
            ca.add("new_di = new_am.xmidi_get_graphelements()")
            ca.indent(-1)
            ca.add("if element.__parent__():")
            ca.indent(1)
            ca.add("prop = element.__parent__().__getSlotByName__(\"connection\").getProperty().getOppositeProperty().getName()")
            ca.add("op2con = element.__getSlotByName__(prop)[0]")
            ca.add("xmi_edges = op2con.xmidi_get_graphelements()")
            ca.add("for edge in xmi_edges:")
            ca.indent(1)
            ca.add("if elementGN.__getRoot__() == edge.__getRoot__():")
            ca.indent(1)
            ca.add("end=1")
            ca.add("if op2con.connection[0] == element:")
            ca.indent(1)
            ca.add("end=0")
            ca.indent(-1)
            ca.add("if len(edge.anchor)>1:")
            ca.indent(1)
            ca.add("if edge.anchor[end].graphElement in new_di:")
            ca.indent(1)
            ca.add("continue")
            ca.indent(-1)
            ca.add("if len(edge.anchor[end].graphEdge) == 1:")
            ca.indent(1)
            ca.add("edge.anchor[end].__resetAttrs__()")
            ca.indent(-1)
            ca.add("else:")
            ca.indent(1)
            ca.add("edge.anchor.drop_index(end)")
            ca.indent(-2)
            ca.add("if new_di:")
            ca.indent(1)
            ca.add("all_di = geInDiagram(new_di, edge.__getRoot__())")
            ca.add("for gnode in all_di:")
            ca.indent(1)
            ca.add("ext = DiagramElementGenerator.getExtension(new_am.__type__())")
            ca.add("if ext and not ext.acceptsConnectors(gnode.semanticModel.element, xparent=gnode.container):")
            ca.indent(1)
            ca.add("continue")
            ca.indent(-1)
            ca.add("if len(edge.anchor) == 2: continue")
            ca.add("if len(edge.anchor) == 2  and edge.anchor[end].graphElement == gnode:")
            ca.indent(1)
            ca.add("continue")
            ca.indent(-1)
            ca.add("new_gnode=gnode")
            ca.add("break")
            ca.indent(-1)
            ca.add("edge.anchor.insert(DI.GraphConnector(graphElement=new_gnode),end)")
            ca.indent(-2)
            ca.add("else:")
            ca.indent(1)
            ca.add("continue")
            ca.indent(-3)
            ca.add("")
            ca.indent(-1)

    if gn.oclIsKindOf(DIML.GraphNodePart) and contained and contained.selection:

        con = ""
        ca.indent(1)

        ## Find out which containers need to be found/created to proceed with synch
        con, oldCon = __writeContainers(gn, con, ca, firstTime)
        if not con:
            con = "elementGN"
        ca.add("old_di = " + con + ".contained")

        c = __gen_xmidi_synch_multi(self, "element", path[-1], ca, metaclass, con,property)
        ca.indent(-1)
        ca.add("")
        return

            
    if gn.oclIsKindOf(DIML.Delegation):

        con = ""
        ca.indent(1)
        ## Find out which containers need to be found/created to proceed with synch
        con, oldCon = __writeContainers(gn, con, ca, firstTime)

        if isOrdered:

            if not con:
                con = "elementGN"
                oldCon = "elementGN"
                
            first, prevnode, last, nextnode = __getSurroundingNodes(gn)

            #check for separator
            separator = __getSeparator(gn)


            ca.add("existing = {}")
            ca.add("for xmidi in " + con+ ".contained:")
            ca.indent(1)
            ca.add("existing[xmidi.semanticModel.element] = xmidi")
            ca.indent(-1)
            ca.add("old_di = " + con + ".contained")

            if first != 0:
                ca.add("start_cont , start_idx = searchForSimpleGraphNode(old_di, \""+ str(prevnode.typeInfo) +"\")")
            else:
                ca.add("start_idx = -1")

            # check position of the right bound-node
            if last != -1:
                ca.add("end_cont , end_idx = searchForSimpleGraphNode(old_di, \""+ str(nextnode.typeInfo) +"\")")
            else:
                ca.add("end_idx = len(old_di)")

            # kill old elements
            ca.add("")
            ca.add("nodes2kill = []")
            ca.add("for i in xrange(start_idx+1, end_idx):")
            ca.indent(1)
            ca.add("sm = old_di[i].semanticModel")
            ca.add("elem = sm.element")
            # This makes sure graphnodes belonging to deleted elements are removed
            ca.add("if (elem and elem not in elements2be) or (not hasattr(sm, \"typeInfo\") and sm.element is None):")
            ca.indent(1)
            ca.add("nodes2kill.append(old_di[i])")
            # remove old separators in the same run
            if separator:
                ca.indent(-1)
                ca.add("if hasattr(sm, \"typeInfo\") and sm.typeInfo == \""+str(separator.subtree.typeInfo)+"\":")
                ca.indent(1)
                ca.add("nodes2kill.append(old_di[i])")                

            ca.indent(-2)
            ca.add("for e in nodes2kill:")
            ca.indent(1)
            ca.add("old_di.remove(e)")
            ca.indent(-1)                    

            # add the new elements    
            ca.add("node_idx = start_idx")
            ca.add("for i in elements2be:")
            ca.indent(1)
            ca.add("node_idx += 1")
            ca.add("if existing.has_key(i):")
            ca.indent(1)
            ca.add("if node_idx < len(old_di):")
            ca.indent(1)
            ca.add("if old_di[node_idx].semanticModel.element != i:")
            ca.indent(1)
            ca.add("old_di.remove(existing[i])")
            ca.indent(-1)
            ca.add("else:")
            ca.indent(1)
            ca.add("continue")
            ca.indent(-3)
            ca.add(nodename + " = DiagramElementGenerator.getExtension(i.__type__()).createDiagramElement(i, xparent="+con+")")
            ca.add("old_di.insert(" + nodename + ", node_idx)")
            ca.add("")
            ca.indent(-1)



            # add new separators (we will want to reuse the old, don't we)
            if separator:
                ca.add("for i in xrange(len(elements2be)-1):")
                ca.indent(1)
                ca.add("sep = self.createSimpleGraphNode(\""+str(separator.subtree.typeInfo)+"\")")
                for p in separator.subtree.diProperty:
                    ca.add('sep.property.insert(DI.Property(key="'+unicode(p.key)+'", value="'+unicode(p.value)+'"))')
                ca.add("old_di.insert(sep, start_idx+2*(i+1))")
                ca.indent(-1)
            ca.add("")

            ca.indent(-1)

        else: ## The property to synchronize is unordered
            # Kill dead graphnodes
            if not con:
                con="elementGN"
                oldCon="elementGN"

            #check for separator
            separator=__getSeparator(gn)

            ## 'old_di' is the collection of the contained graphnodes
            ca.add("old_di="+con+".contained")



            ## Remove separators and orphaned graphnodes
            ca.add("for xmidi in old_di:")
            ca.indent(1)
            ca.add("sm = xmidi.semanticModel")
            ca.add("if not hasattr(sm, \"typeInfo\") and sm.element is None:")
            ca.indent(1)
            ca.add("old_di.remove(xmidi)")
            ca.indent(-1)

            if separator:
                ca.add("if hasattr(sm, \"typeInfo\") and sm.typeInfo == \""+str(separator.subtree.typeInfo)+"\":")
                ca.indent(1)
                ca.add("old_di.remove(xmidi)")
                ca.indent(-1)

            ca.indent(-1)

            parent = path[-1]
            childlinks = parent.children

            delegations = childlinks.select(lambda x: x.child.oclIsKindOf(DIML.Delegation))

            synch_multiple_props = False

            if len(delegations) > 1:
                ## This generates a thorough synchronization that checks all involved Delegations
                c = __gen_xmidi_synch_multi(self, "element", parent, ca, metaclass, con,property)
                synch_multiple_props = True
                ## All other cases should be possible to solve by similar means as with ordered slots

            if synch_multiple_props:
                ca.indent(-1)
                ca.add("")
                return
            
            first, prevnode, last, nextnode = __getSurroundingNodes(gn)

            if first != 0:
                #ca.add("start_cont , start_idx = searchForSimpleGraphNode(old_di, \""+ unicode(prevnode.typeInfo) +"\")")
                #ca.add("## alt:")
                __gen_leading_nodes(__getParentElement(gn), ca)
            else:
                ca.add("start_idx = -1")

##            # check position of the right bound-node
##            if last != -1:
##                ca.add("end_cont , end_idx = searchForSimpleGraphNode(old_di, \""+ unicode(nextnode.typeInfo) +"\")")
##            else:
##                ca.add("end_idx = len(old_di)")


            ca.add("existing = {}")
            ca.add("for xmidi in " + con+ ".contained:")
            ca.indent(1)
            ca.add("existing[xmidi.semanticModel.element] = xmidi")
            ca.indent(-1)
            ca.add('nodes = getListOfReparentedGNs(elementGN)')
            
            ca.add("node_idx = start_idx + 1")
            ca.add("for i in elements2be:")
            ca.indent(1)
            ca.add("if existing.has_key(i):")
            ca.indent(1)
            ca.add("node_idx += 1")
            ca.add("continue")
            ca.indent(-1)

            if len(childlinks) == 1:
                ca.add(nodename+" = None")
                ca.add('for n in nodes:')
                ca.indent(1)
                ca.add('cdi, x, y = n')
                ca.add('if cdi.semanticModel.element == i:')
                ca.indent(1)
                ca.add(nodename+' = cdi')

                ca.add('ps_x, ps_y = coral.XMIDI_GlobalToLocalPosition('+con+', x, y)')
                ca.add('if cdi.oclIsKindOf(DI.GraphEdge):')
                ca.indent(1)
                ca.add('cdi.position.x = 0')
                ca.add('cdi.position.y = 0')
                ca.indent(-1)
                ca.add('else:')
                ca.indent(1)
                ca.add(nodename+'.position.x = ps_x')
                ca.add(nodename+'.position.y = ps_y')
                ca.indent(-1)
                ca.add('break')
                ca.indent(-2)
                ca.add("if not "+nodename+":")
                ca.indent(1)
                ca.add("ext = DiagramElementGenerator.getExtension(i.__type__())")
                if contained and contained.guard and contained.guard.expression:
                    ca.add("if ext and ext.isMinorElement(element=i, xparent="+con+"):")
                else:
                    ca.add("if ext:")
                ca.indent(1)
                ca.add(nodename + " = ext.createDiagramElement(i, xparent="+con+")")
                ca.indent(-2)
                
            else: ## The default way to insert graphnodes in the compartment
                ca.add("ext = DiagramElementGenerator.getExtension(i.__type__())")
                ca.add("if ext:")
                ca.indent(1)
                ca.add(nodename + " = ext.createDiagramElement(i, xparent="+con+")")
                ca.indent(-1)

            ca.add("if " +nodename+ ":" )
            ca.indent(1)


            # If parent (directly above) is a GraphEdge,
            # give a default position to children that are _not_ simple compartments etc.
            parent_node = __getParentElement(gn)

            if parent_node.oclIsKindOf(DIML.GraphEdgePart):
                ca.add("if "+ con +".oclIsKindOf(DI.GraphEdge) and len("+con+".waypoints) >= 2:")
                ca.indent(1)
                ca.add(nodename+".position.x = ("+con+".waypoints[0].x+"+con+".waypoints[-1].x)/2")
                ca.add(nodename+".position.y = ("+con+".waypoints[0].y+"+con+".waypoints[-1].y)/2-20")
                ca.indent(-1)
            ## End default position-code

            ca.add("old_di.insert(" + nodename + ", node_idx )")
            ca.add("node_idx += 1")
            ca.indent(-2)

            # remove XMIDI, whose elements are deleted
            ca.add("for i in existing.keys():")
            ca.indent(1)
            ## Different removal strategy for slots 0..1 and 0..*

            if property.multiplicity_upper == 1:
                ca.add("if i is None or i==new_am:")
                ca.indent(1)
                ca.add("continue")
                ca.indent(-1)
                ca.add("if i in old_am:")
                ca.indent(1)
                ca.add("old_di.remove(existing[i])")
                ca.indent(-2)
            else:
                ca.add("if i is None or i in new_am:") ## Do not delete simple diagram elements
                ca.indent(1)
                ca.add("continue")
                ca.indent(-1)
                ca.add("if i in old_am and i not in new_am:")
                ca.indent(1)
                ca.add("old_di.remove(existing[i])")
                ca.indent(-2)

            ## Add start and endnodes and separators

            if separator:
                ca.add("for i in xrange(len(elements2be)-1):")
                ca.indent(1)
                ca.add('sep = self.createSimpleGraphNode("'+separator.subtree.typeInfo+'")')
                ca.add('old_di.insert(sep,start_idx+2*(i+1))')
                for p in separator.subtree.diProperty:
                    ca.add('sep.property.insert(DI.Property(key="'+unicode(p.key)+'", value="'+unicode(p.value)+'"))')
                ca.indent(-1)

            if last != -1:
                __gen_trailing_nodes(__getParentElement(gn), ca)
                    
            ca.indent(-1)
            ca.add("")


    ## Should the graphnode not be a childelement (indicated with a '?'), recurse to the next level
    
    # The associations tell us what child elements the GraphElement should have 
    ss = selfstring
    i=0
    if not gn.oclIsKindOf(DIML.Delegation):
        for cont in gn.children:
            i += 1
            child = cont.child

            ## When we reach the top, reset path
            if gn.oclIsKindOf(DIML.GraphNodePart) or gn.oclIsKindOf(DIML.GraphEdgePart):
                if gn.mapping:
                    path = [gn]
                else:
                    if gn not in path:
                        path.append(gn)

            # Get the information from the Contained
            synch_indent = 0            

            if child.oclIsKindOf(DIML.Delegation):

                selection = cont.selection
                if selection:
                    property = selection.property
                    propstr = 'if property == "' + unicode(property.name) + '":'
                    ca.add(propstr)
                    ca.indent(1)
                    synch_indent += 1

                    ca.add("elements2be = []")
                    if property.multiplicity_upper == 1:
                        ca.add("if new_am:")
                        ca.indent(1)
                        synch_indent += 1
                        ca.add("child=new_am")
                    else:
                        ca.add("for child in new_am:")
                        ca.indent(1)
                        synch_indent += 1

                    # retrieve is a more specific constraint that tells us which elements should have a graphnode
                    retrievestring = __buildRetrieve(selection)
                    childtypeconstraint = __childTypeConstraint(selection)

                    if property.multiplicity_upper == 1:
                        if childtypeconstraint:
                            ca.add("if child"+childtypeconstraint+":")
                            ca.indent(1)
                            synch_indent += 1
                    else:
                        if retrievestring:
                            ca.add("if child in "+retrievestring+":")
                            ca.indent(1)
                            synch_indent += 1
                    ca.add("elements2be.append(child)")

                    # check if the property is ordered or not
                    if bool(property.isOrdered):
                        isOrdered = True
                    else:
                        isOrdered = False

                # reset the extra indentation
                ca.indent(-synch_indent)
            elif child.oclIsKindOf(DIML.GraphNodePart):
                selection = cont.selection
                if selection:
                    property = selection.property
                    propstr = 'if property == "' + unicode(property.name) + '":'
                    ca.add(propstr)
                    ca.indent(1)
                    synch_indent += 1
                ca.indent(-synch_indent)
            # collect information recursively      
            createSynchronizeContents(self, ss, child, ca, metaclass, property, contained=cont)

            ## Remove the last container when we have gone through all subtrees
            if i==len(gn.children) and gn==path[-1]:
                del path[-1]

def createAttachConnectors( gn, ca ):
    ca.add("def attachGraphConnector( self, element ):")
    ca.indent(1)
    # Collect the edges
    ca.add('edges = element.xmidi_get_graphelements()')
    ca.add("ends=[]")
    #ends=""
    # Collect the indexes
    for conn in gn.connector:
        prop = conn.property
        if prop and prop.multiplicity_upper == 1:
            ca.add("ends.append(element."+unicode(prop.name)+")")
        else:
            ca.add("ends += element."+unicode(prop.name))
        next_property = conn.nextProperty
    ca.add("for edge in edges:")
    ca.indent(1)
    ca.add("for end in ends:")
    ca.indent(1)
    # decide to which graphnodes we should connect the edges
    if next_property:
        ca.add('nodes = end.'+unicode(next_property.name)+'.xmidi_get_graphelements()')
    else:
        ca.add('nodes = end.xmidi_get_graphelements()')
    ca.add("for node in nodes:")
    ca.indent(1)
    ca.add("if findDiagramOfElement(node) != findDiagramOfElement(edge):")
    ca.indent(1)
    ca.add("continue")
    ca.indent(-1)
    if next_property:
        ca.add("ext = DiagramElementGenerator.getExtension(end."+unicode(next_property.name)+".__type__())")
    else:
        ca.add("ext = DiagramElementGenerator.getExtension(end.__type__())")

    ca.add("if ext and not ext.acceptsConnectors(node.semanticModel.element, xparent=node.container):")
    ca.indent(1)
    ca.add("continue")
    ca.indent(-1)
    
    ca.add("gc = node.anchorage.select(lambda x: edge in x.graphEdge)")
    # Check if the graphnode already has connectors for the edge
    ca.add("if len(gc) >= 1:")
    ca.indent(1)
    ca.add("continue")
    ca.indent(-1)
    ca.add("")
    # else add one
    ca.add("connector = DI.GraphConnector(graphElement=node, position=DI.Point())")
    ca.add("if len(edge.anchor) < 2:")
    ca.indent(1)
    ca.add("edge.anchor.append(connector)")
    ca.add("break")
    ca.indent(-5)
    ca.add("")

    
def createSynchronizeDiagram( self, selfstring, mapping, ca, metaclass):
    """The createSynchronizeDiagram creates mappings for diagrams. """
    dp = mapping.root
    if dp.oclIsKindOf(DIML.DiagramPart):
        ca.indent(-2)
        ca.add("if diagrams:")
        ca.indent(1)
        for cont in dp.children:
            # Get the information from the Contained
            selection = cont.selection
            prop = selection.property
            if prop:
                ca.add('if property =="' + unicode(prop.name) + '":')
                ca.indent(1)
            ca.add("elements2be = []")
            ca.add("for child in new_am:")
            ca.indent(1)
            # check for childconstraint
            retrieve  = __buildRetrieve(selection)
            if retrieve:
                ca.add("if child in "+retrieve+":")
                ca.indent(1)
            ca.add("elements2be.append(child) ")
            ca.indent(-1)
            ca.add("for d in diagrams:")
            ca.indent(1)
            ca.add("nodes = getListOfReparentedGNs(d)")
            ca.add("existing = {}")
            ca.add("for di in d.contained:")
            ca.indent(1)
            ca.add("existing[di.semanticModel.element] = di")
            ca.indent(-1)
            ca.add("for i in elements2be:")
            ca.indent(1)
            ca.add("if existing.has_key(i):")
            ca.indent(1)
            ca.add("continue")
            ca.indent(-1)
            ca.add("ge=None")
            ca.add("for n in nodes:")
            ca.indent(1)
            ca.add("cdi, x, y = n")
            ca.add("if cdi.semanticModel.element == i:")
            ca.indent(1)
            ca.add("ge = cdi")
            ca.add("if ge.oclIsKindOf(DI.GraphEdge):")
            ca.indent(1)
            ca.add("ge.position.x = 0")
            ca.add("ge.position.y = 0")
            ca.indent(-1)
            ca.add("else:")
            ca.indent(1)
            ca.add("ge.position.x = x")
            ca.add("ge.position.y = y")
            ca.indent(-1)
            ca.indent(-1)
            ca.add("if ge:")
            ca.indent(1)
            ca.add("d.contained.append(ge)")
            ca.indent(-2)
            ca.add("if not ge:")
            ca.indent(1)
            ca.add("createit = False")
            ca.add("gns = i.xmidi_get_graphelements()")
            ca.add("for gn in gns:")
            ca.indent(1)
            ca.add("if findDiagramOfElement(gn) != d:")
            ca.indent(1)
            ca.add("createit = True")
            ca.indent(-2)
            ca.add("if createit or not gns:")
            ca.indent(1)
            ca.add("ext = DiagramElementGenerator.getExtension(i.__type__())")
            ca.add("if ext and ext.isMinorElement(i,xparent=d):")
            ca.indent(1)
            ca.add("ge = ext.createDiagramElement(i, xparent=d)")
            ca.indent(-1)
            ca.add("if ge:")
            ca.indent(1)
            ca.add("if ge.oclIsKindOf(DI.GraphNode):")
            ca.indent(1)
            ca.add("ge.position.x = 50")
            ca.add("ge.position.y = 50")
            ca.indent(-1)
            ca.add("d.contained.append(ge)")
            ca.indent(-4)

            ca.indent(-1)
                            
  
def gen_xmidi(element):
    global perpetual, importLanguage, ca


    mappings = element.__getSlotByOppositeName__(DIML.ElementToXMIDIMapping, "element")
    
    mappings_no_guard = [m for m in mappings if not m.contextGuard and not m.root.oclIsKindOf(DIML.DiagramPart)]
    assert len(mappings_no_guard) <= 1, "Not allowed to have many optional variations of craetion without guards"
    mapping_with_guards = [m for m in mappings if m.contextGuard and not m.root.oclIsKindOf(DIML.DiagramPart)]

    diagram_mapp = [m for m in mappings if m.root.oclIsKindOf(DIML.DiagramPart)]

    all_mappings = mapping_with_guards+mappings_no_guard
    assert len(all_mappings) > 0
    
    # Get the language
    lang = element.package
    ver = lang.version
    rev = lang.revision
    
    classname=unicode(element.name)
    metaclass = element

    #assert lang.getElement(classname)

    # Import the language only the first time this is run
    if importLanguage:
        ca.add("coral.lang."+unicode(lang.name)+unicode(ver)+unicode(rev)+".__import__(globals())")
        ca.add("")
        importLanguage = False

    # the name of the class
    ca.add("class "+classname+"DEG( DiagramElementCreatorExt ):")
    ca.add("")
    ca.indent(1)
    
    # begin createDiagramElement
    ca.add("def createDiagramElement( self, element, xparent=None, **kwargs):")
    ca.indent(1)
    ca.add("xparent_element = findUpwardsModelElement(xparent)")
    if len(all_mappings) == 1 and not all_mappings[0].contextGuard:
        top = all_mappings[0].root
        ## Only one variation of creation
        the_ss = __gen_xmidi(element, "element", top, ca, metaclass, "None")
        ca.add("return "+the_ss)
        ca.indent(-1)
        ca.add("")
        perpetual = 1
    else:
        first = 0
        ## Several options 
        for context in all_mappings:
            condition = ""
            if context.contextGuard:
                condition = unicode(context.contextGuard.expression)
            if condition:
                top = context.root
                if first == 0:
                    ca.add("if "+condition+":")
                else:
                    ca.add("elif "+condition+":")
                ca.indent(1)
                the_ss=__gen_xmidi(element, "element", top, ca, metaclass, "None")
                ca.add("return "+the_ss)
                ca.indent(-1)
            else:
                top = context.root
                ca.add("else:")
                ca.indent(1)
                the_ss=__gen_xmidi(element, "element", top, ca, metaclass, "None")
                ca.add("return "+the_ss)
                ca.indent(-1)
            first += 1
            perpetual = 1
        ca.indent(-1)
        ca.add("")
    # end createDiagramElement






    # begin isMinorElement
    ca.add("def isMinorElement( self, element=None, xparent=None):")
    ca.indent(1)
    ca.add("xparent_element = findUpwardsModelElement(xparent)")
    if len(all_mappings) == 1 and not all_mappings[0].contextGuard:

        createIsMinorElement(all_mappings[0], ca)
        ca.indent(-1)
        ca.add("")
    else:
        first = 0
        ## Several options 
        for context in all_mappings:
            condition = ""
            if context.contextGuard:
                condition = unicode(context.contextGuard.expression)
            if condition:
                top = context.root
                if first == 0:
                    ca.add("if "+condition+":")
                else:
                    ca.add("elif "+condition+":")
                ca.indent(1)
                createIsMinorElement(context, ca)
                ca.indent(-1)
            else:
                top = context.root
                ca.add("else:")
                ca.indent(1)
                createIsMinorElement(context, ca)
                ca.indent(-1)
            first += 1
            perpetual = 1
        ca.indent(-1)
        ca.add("")
    # end isMinorElement


    # begin acceptsConnectors
    ca.add("def acceptsConnectors( self, element, xparent=None):")
    ca.indent(1)
    ca.add("xparent_element = findUpwardsModelElement(xparent)")
    if len(all_mappings) == 1 and not all_mappings[0].contextGuard:

        createAcceptsConnectors(all_mappings[0], ca)
        ca.indent(-1)
        ca.add("")
    else:
        first = 0
        ## Several options 
        for context in all_mappings:
            condition = ""
            if context.contextGuard:
                condition = unicode(context.contextGuard.expression)
            if condition:
                top = context.root
                if first == 0:
                    ca.add("if "+condition+":")
                else:
                    ca.add("elif "+condition+":")
                ca.indent(1)
                createAcceptsConnectors(context, ca)
                ca.indent(-1)
            else:
                top = context.root
                ca.add("else:")
                ca.indent(1)
                createAcceptsConnectors(context, ca)
                ca.indent(-1)
            first += 1
            perpetual = 1
        ca.indent(-1)
        ca.add("")
    # end acceptsConnectors


    # begin suitableDiagrams
    ca.add("def suitableDiagrams( self, element=None, xparent=None):")
    ca.indent(1)
    ca.add("xparent_element = findUpwardsModelElement(xparent)")
    if len(all_mappings) == 1 and not all_mappings[0].contextGuard:

        createSuitableDiagrams(all_mappings[0], ca)
        ca.indent(-1)
        ca.add("")
    else:
        first = 0
        ## Several options 
        for context in all_mappings:
            condition = ""
            if context.contextGuard:
                condition = unicode(context.contextGuard.expression)
            if condition:
                top = context.root
                if first == 0:
                    ca.add("if "+condition+":")
                else:
                    ca.add("elif "+condition+":")
                ca.indent(1)
                createSuitableDiagrams(context, ca)
                ca.indent(-1)
            else:
                top = context.root
                ca.add("else:")
                ca.indent(1)
                createSuitableDiagrams(context, ca)
                ca.indent(-1)
            first += 1
            perpetual = 1
        ca.indent(-1)
        ca.add("")
    # end suitableDiagrams


    # begin synchronizeContents
    ca.add("def synchronizeContents(self, element, property, old_am, new_am):")
    ca.indent(1)
    ca.add('elementGNs = element.xmidi_get_graphelements()')
    ca.add('diagrams = element.xmidi_get_diagrams()')
    noXMI = False
    for context in all_mappings:
        if context.root.oclIsKindOf(DIML.GraphNodePart):
            if bool(context.root.skipXMIDICreation):
                noXMI=True
    if noXMI:
        ca.add("by_new_am = False")
        ca.add("if not elementGNs and new_am:")
        ca.indent(1)
        ca.add("by_new_am = True")
        ca.add("elementGNs = new_am.xmidi_get_graphelements()")
        ca.indent(-1)
    ca.add("if len(elementGNs)>0:")
    ca.indent(1)
    ca.add("for elementGN in elementGNs:")
    ca.indent(1)
    ca.add("xparent = elementGN.container")
    ca.add("xparent_element = findUpwardsModelElement(xparent)")
    ca.add("")
    if len(all_mappings) == 1 and not all_mappings[0].contextGuard:
        ## One way to synchronize
        createSynchronizeContents( element, "element", top, ca, metaclass)
        if diagram_mapp:
            createSynchronizeDiagram( element, "element", diagram_mapp[0], ca, metaclass)
        ca.indent(-3)
        ca.add("")
    else:
        first = 0
        ## Several ways to synchronize
        for context in all_mappings:
            condition = ""
            if context.contextGuard:
                condition = unicode(context.contextGuard.expression)
            if condition:
                top = context.root
                if first == 0:
                    ca.add("if "+condition+":")
                else:
                    ca.add("elif "+condition+":")
                ca.indent(1)
                ca.add("pass") ## This is ugly, but we might not need to do anything in the synchronisation
                createSynchronizeContents( element, "element", top, ca, metaclass)
            else:
                top = context.root
                ca.add("else:")
                ca.indent(1)
                ca.add("pass")
                createSynchronizeContents( element, "element", top, ca, metaclass)
            ca.indent(-1)
            first += 1

        if diagram_mapp:
            createSynchronizeDiagram( element, "element", diagram_mapp[0], ca, metaclass)

        ca.indent(-3)
        ca.add("")
    # end synchronizeContents

    # begin attachConnectors
    node = None
    for m in all_mappings:
        node = m.root
        
    if node.oclIsKindOf(DIML.GraphEdgePart):
        createAttachConnectors(node, ca)
    # end attachConnectors

    # begin createAndAttachToParent
    #createAttachToParent(element,ca)
    # end createAndAttachToParent
    ca.indent(-1)
    perpetual = 1
    return ca


def usage():
    print "Usage: uml2xmidigen [-o outputfile] inputmodels"
    print "    inputmodels: the name(s) of your MODEL2XMIDI model(s)"
    print "options:\n -h, --help : display this help"
    print "-o \"outputfile\": the filename for the output"
    print "-p \"importpath\": the python path of the output classes"

def main(arguments):
    global ca
    try:
        opts, args = getopt.gnu_getopt(arguments, "ho:p:", ["help"])
        
    except getopt.GetoptError:
        # print help information and exit:
        usage()
        sys.exit(2)
    if len(args) < 1:
        usage()
        sys.exit(2)

    output = None
    path = None 

    for o, a in opts:
        if o in ("-h", "--help"):
            usage()
            sys.exit()
        if o in ("-o"):
            output = a
        if o in ("-p"):
            path = a
            
    inputmodels = args

    
    ca = CodeArtifact()
    ca.setIndentString("    ")
    ca.add("# -*- coding: utf-8 -*-")
    ca.add("## This file is generated by uml2xmidigen")
    ca.add("## All changes made in this file will be lost")
    ca.add("")    
    ca.add("from coral.modeler.diagram.degen import DiagramElementCreatorExt, CannotAttachChildException, IgnoreThisXMIDICreation")
    ca.add("from coral.modeler.diagram.degen import DiagramElementGenerator, searchForSimpleGraphNode, geInDiagram, getListOfReparentedGNs")
    ca.add("import coral")
    ca.add("DI = coral.lang.XMIDI20")
    ca.add("from coral.modeler.diagram.di_support import findUpwardsModelElement, findDiagramOfElement")
    ca.add("from coral import log")
    ca.add('logger=log.getLogger("UML2DI Degen")')

    ca.add("import coral")
    
    prj = coral.Project()
    extm = CEX.Package(name="manifest")
    extm.__setProject__(prj)
    degen = CEX.Package(name="degen", owner=extm)
        



    # Then create DEG:s for all the classes in the models
    for modelfile in inputmodels:
        ca.add("")
        ca.add("######   "+unicode(modelfile)+"   ######")
        ca.add("")
        metaclasses=[]

        st = coral.loadDocument(modelfile)
        model = st.contents().select(lambda x:x.oclIsKindOf(DIML.MappingModel))[0]

        all_mappings = model.ownedElement.select(lambda x:x.oclIsKindOf(DIML.ElementToXMIDIMapping))

        for m in all_mappings:
            if m.element not in metaclasses:
                metaclasses.append(m.element)

        metaclasses.sort(__comparefunction)

        for metacls in metaclasses:
            gen_xmidi(metacls)
            if path:
                e = __genExtEntry(metacls,path)
                degen.ownedElement.append(e)

    # Save output to specified file
    if output:
        ca.dump(output)
    else:
        ca.dump_fd(sys.stdout)

    if path:
        prj.setFilename("degen.mnf.xmi")
        coral.saveDocument(prj)


if __name__=='__main__':
    import sys
    main(sys.argv[1:])
