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

import coral
DI = coral.lang.XMIDI20
from coral.modeler.extension import *
from coral.modeler import iconcache
from coral.modeler.diagram.degen import DiagramElementGenerator, DiagramElementCreatorExt
from coral import log
logger=log.getLogger("UML14DiagramActions")
import coral

import coral.modeler.diagram.di_support as DISUPP

L = coral.lang.DIML10
SMD = coral.lang.SMD01
# The below import hack is not useful, use L instead
#coral.lang.UML14.__import__(globals())

n = 0
def perpetualEnumerator():
    global n
    n += 1
    return n


class CreateAction( DiagramEditorToolbarEntry ):

    def prepare(self, diagram):
        self.__diagram = diagram

    def __call__(self, hints, parentge):
        return self.doIt(self.__diagram, self.__diagram, hints, parentge)

    def doIt( self, diagram, parent, hints=None, parentge=None ):
        if hints:
            hint1 = hints[0]
            if hint1:
                px = hint1[0]
                py = hint1[1]
            else:
                px = 50
                py = 50


        if parentge:
            model = parentge.semanticModel.element
        else:
            model = diagram.owner.element
        assert model
        
        coral.getTransactionManager().beginModifyCmd()
        try:
            element = self.createModelElement(model,parent)
            if not element:
                return
            deg = DiagramElementGenerator.getExtension(element.__type__())
            if not deg:
                return
            
            de = deg.createDiagramElement(element, xparent=parent)
            if not de:
                return
            de.position = DI.Point(x=px,y=py)
            parent.contained.append(de)
        finally:
            coral.getTransactionManager().endModifyCmd()

    def createModelElement( self, model, parent ):
        raise NotImplemented

    def createEdgeOrNot(self):
        return False

class CreateEdgeAction( CreateAction ):
    def firstType(self):
        raise NotImplemented

    def secondType(self):
        raise NotImplemented
    
    def createEdgeOrNot(self):
        return True

    def doIt(  self, diagram, parent, hints=None, parentge=None ):
        if not hints or not len(hints)==3:
            return
        model = diagram.owner.element
        assert model

        node1 = hints[0]
        node2 = hints[1]
        waypoints = hints[2]

        if ((node1.semanticModel and node1.semanticModel.element) and
            (node2.semanticModel and node2.semanticModel.element)):
            clsf1 = node1.semanticModel.element
            clsf2 = node2.semanticModel.element
            # BUG this checking should be more generic
            if not (clsf1.oclIsKindOf(self.firstType()) and clsf2.oclIsKindOf(self.secondType())):
                logger.debug("Attempt to make illegal edge")
                return
        else:
            logger.debug("Attempt to make illegal edge")
            return

        coral.getTransactionManager().beginModifyCmd()
        try:
            element = self.createModelElement(model,parent, node1, node2)
            if not element:
                return
            deg = DiagramElementGenerator.getExtension(element.__type__())
            if not deg:
                return
            anchor0 = DI.GraphConnector(graphElement=node1)
            anchor1 = DI.GraphConnector(graphElement=node2)
            ## Create the GraphEdge
            de = deg.createDiagramElement(element, xparent=parent, waypoints=waypoints )
            assert de
            de.anchor.append(anchor0)
            de.anchor.append(anchor1)
            parent.contained.append(de)
            if waypoints:
                self.positionEdgeLabels(de, waypoints)
        finally:
            coral.getTransactionManager().endModifyCmd()

    def createModelElement(self, model, parent, ge1, ge2):
        raise NotImplemented

    def positionEdgeLabels(self, graphEdge, waypoints):
        """Positions possible graphNodes below the @graphEdge, using the
        information in @waypoints. May be overriden by subclasses"""
        return

class CreateGraphNodePartAction( CreateAction ):
    def getIcon( cls ):
        return iconcache.getIcon("icons/gnodeparttb","DIML10")
    getIcon = classmethod(getIcon)

    def createModelElement( self, model, parent ):
        c = L.GraphNodePart()
        model.ownedElement.insert(c)
        return c

    def getLabel(self):
        return "GraphNodePart"
    
class CreateGraphEdgePartAction( CreateAction ):
    def getIcon( cls ):
        return iconcache.getIcon("icons/gedgeparttb","DIML10")
    getIcon = classmethod(getIcon)

    def createModelElement( self, model, parent ):
        c = L.GraphEdgePart()
        model.ownedElement.insert(c)
        return c

    def getLabel(self):
        return "GraphEdgePart"
    
class CreateDiagramPartAction( CreateAction ):
    def getIcon( cls ):
        return iconcache.getIcon("icons/diagramparttb","DIML10")
    getIcon = classmethod(getIcon)

    def createModelElement( self, model, parent ):
        c = L.DiagramPart()
        model.ownedElement.insert(c)
        return c

    def getLabel(self):
        return "DiagramPart"
    
class CreateDelegationAction( CreateAction ):
    def getIcon( cls ):
        return iconcache.getIcon("icons/delegationtb","DIML10")
    getIcon = classmethod(getIcon)

    def createModelElement( self, model, parent ):
        c = L.Delegation()
        model.ownedElement.insert(c)
        return c

    def getLabel(self):
        return "Delegation"
    
class CreateContainedAction( CreateEdgeAction ):
    def firstType(self):
        return L.InitialPart

    def secondType(self):
        return L.GraphElementPart

    def positionEdgeLabels(self, graphEdge, waypoints):
        graphEdge.contained[0].position = DISUPP.calcGENameDIPoints(waypoints)

    def createModelElement(self, model, parent, ge1, ge2):
        c = L.Contained()
        c.parent = ge1.semanticModel.element
        c.child = ge2.semanticModel.element
        model.ownedElement.insert(c)
        return c

    def getLabel(self):
        return "Contained"
    
    def getIcon( cls ):
        return iconcache.getIcon("icons/containedtb","DIML10")
    getIcon = classmethod(getIcon)


class CreateSeparatorAction( CreateEdgeAction ):
    def firstType(self):
        return L.Contained

    def secondType(self):
        return L.ConcretePart


    def getLabel(self):
        return "Separator"
    
    def createModelElement(self, model, parent, ge1, ge2):
        c = L.Separator()
        c.contained = ge1.semanticModel.element
        c.subtree = ge2.semanticModel.element
        model.ownedElement.insert(c)
        return c

    def getIcon( cls ):
        return iconcache.getIcon("icons/separatortb","DIML10")
    getIcon = classmethod(getIcon)

class CreateElementToXMIDIMappingAction( CreateEdgeAction ):
    def firstType(self):
        return SMD.ElementDefinition

    def secondType(self):
        return L.InitialPart

    def positionEdgeLabels(self, graphEdge, waypoints):
        graphEdge.contained[0].position = DISUPP.calcGENameDIPoints(waypoints)

    def createModelElement(self, model, parent, ge1, ge2):
        c = L.ElementToXMIDIMapping()
        c.element = ge1.semanticModel.element
        c.root = ge2.semanticModel.element
        model.ownedElement.insert(c)
        return c

    def getLabel(self):
        return "ElementToXMIDIMapping"
    
    def getIcon( cls ):
        return iconcache.getIcon("icons/elemtoxmiditb","DIML10")
    getIcon = classmethod(getIcon)
