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

import coral
DI = coral.lang.XMIDI20
L = coral.lang.UML14
from coral.modeler.diagram.ui import *

from coral import log
logger=log.getLogger("UML14 UI")

import coral.modeler.diagram.di_support as DISUPP

## This is the correct place for UML1.4 specific user interfaces

class ReferencedUI(DiagramElementUI):

    def _isRefd(self):
        modelcontainer = DISUPP.findUpwardsModelElement(self.graphElement.container)
        if (not modelcontainer
            or modelcontainer.oclIsKindOf(L.Package)
            or modelcontainer.oclIsKindOf(L.Component)):
            return True
        else:
            return False
    
    def movable( self ):
        return self._isRefd()

    def resizable(self):
        return self._isRefd()



#
# ClassDiagrams
#

class MajorElementUI(DiagramElementUI):
    
    def reparent(self, element, parent):
        assert element != parent
	assert parent
        element.namespace = parent
        
class MinorElementUI(DiagramElementUI):

    def reparent(self, element, parent):
        assert parent
        element.owner = parent


class StereotypeUI(DiagramElementUI):

    def movable(self):
        cnt = self.graphElement.container
        if cnt and cnt.semanticModel and cnt.semanticModel.oclIsKindOf(DI.SimpleSemanticModelElement) and cnt.semanticModel.typeInfo=="StereotypeCompartment":
            return False
        else:
            return True

    def resizable(self):
        cnt = self.graphElement.container
        if cnt and cnt.semanticModel and cnt.semanticModel.oclIsKindOf(DI.SimpleSemanticModelElement) and cnt.semanticModel.typeInfo=="StereotypeCompartment":
            return False
        else:
            return True

class ClassUI(ReferencedUI):

    def acceptChild(self, element):
        if element and (element.oclIsKindOf(L.Attribute) or element.oclIsKindOf(L.Operation)):
            return True
        return False

    def reparent(self, element, parent):
        assert element != parent
	assert parent
        element.namespace = parent
        


class PackageUI(MajorElementUI):

    def acceptChild(self, element):
        if element and element.oclIsKindOf(L.ModelElement):
            return True
        return False

class AttributeUI(MinorElementUI):
    pass

class OperationUI(MinorElementUI):
    pass

class NameUI( DiagramElementUI ):

    def movable(self):
        return self.__actAsName()

    def selectable(self):
        return self.__actAsName()

    def __actAsName(self):
        element = DISUPP.findUpwardsModelElement(self.graphElement)
        if element.oclIsKindOf(L.AssociationEnd):
            return True
        else:
            if self.graphElement.container and self.graphElement.container.oclIsKindOf(DI.GraphEdge):
                return True
            else:
                return False

class CommentLinkUI(DiagramElementUI):

    def selectable(self):
        return True

    def relinkable(self):
        return False
    

class AssociationUI(DiagramElementUI):

    def accepts(self, element):
        if element and element.oclIsKindOf(L.Classifier):
            return True
        logger.debug("Element rejected by association")
        return False

    def relink(self, ass, cls, end):
        """
        relink associations between classifiers
        ass is the association to be relinked
        cls is the classifier to witch the association should be relinked
        end is an integer 0 or 1 to tell witch end of the association should be relinked
        """

        ass.connection[end].participant = cls

    def resizable(self):
        return False

    def reparent(self, element, parent):
        assert element != parent
	assert parent
        element.namespace = parent
            
class DependencyUI(DiagramElementUI):

    def accepts(self, element):
        if element and element.oclIsKindOf(L.ModelElement):
            return True
        logger.debug("Element rejected by dependency")
        return False

    def relink(self, dep, cls, end):
        """
        relink dependencys between modelelements
        dep is the dependency to be relinked
        cls is the modelelemnt to witch the edge should be relinked
        end is an integer 0 or 1 to tell witch end of the dependency should be relinked
        """
        if end==0:
            dep.client[0] = cls
        else:
            dep.supplier[0] = cls

    def reparent(self, element, parent):
        assert element != parent
	assert parent
        element.namespace = parent
        
            
class AbstractionUI(DiagramElementUI):

    def accepts(self, element):
        if element and element.oclIsKindOf(L.ModelElement):
            return True
        logger.debug("Element rejected by abstraction")
        return False

    def relink(self, abs, cls, end):
        """
        relink abstractions between modelelements
        abs is the abstraction to be relinked
        cls is the modelelement to which the edge should be relinked
        end is an integer 0 or 1 to tell witch end of the abstraction should be relinked
        """
        if end==0:
            abs.client[0] = cls
        else:
            abs.supplier[0] = cls

    def reparent(self, element, parent):
        assert element != parent
	assert parent
        element.namespace = parent

class ObjectUI(DiagramElementUI):
    
    def acceptDrop(self, element):
        return element.oclIsKindOf(L.Classifier)

    def onDrop(self, element, parent):

        if element.oclIsKindOf(L.Classifier):
            parent.classifier.append(element)
            
            
class LinkUI(DiagramElementUI):

    def accepts(self, element):
        if element and element.oclIsKindOf(L.Instance):
            return True
        logger.debug("Element rejected by link")
        return False

    def relink(self, lnk, cls, end):
        """
        relink links between instances
        lnk is the link to be relinked
        cls is the instance to witch the edge should be relinked
        end is an integer 0 or 1 to tell witch end of the dependency should be relinked
        """

        ### Poseidon seems to reverse waypoints in Links
        ### But that's wrong according to XMI-DI 2.0 section 8.1
        ### end = 1 - end
        lnk.connection[end].instance = cls
        if end==0:
            lnk.owner_at_Link = cls

    def relinkable(self):
        return True

    def reparent(self, element, parent):
        assert element != parent
	assert parent
        element.namespace = parent
        

class GeneralizationUI(DiagramElementUI):

    def accepts(self, element):
        if element and element.oclIsKindOf(L.GeneralizableElement):
            return True
        logger.debug("Element rejected by generalization")
        return False

    def relink(self, gen, cls, end):
        """
        relink generalizations between generalizableelements
        gen is the generalization to be relinked
        cls is the generalizableelement to witch the generalization should be relinked
        end is an integer 0 or 1 to tell witch end of the generalization should be relinked
        """
        relation = None
        
        if end==0:
            relation = gen.parent
        else:
            relation = gen.child
        
        if cls==relation:
            logger.debug("Attempt to relink generalization failed")
            return
        
        if end==0:
            gen.child = cls
        else:
            gen.parent = cls 

    def reparent(self, element, parent):
        assert element != parent
	assert parent
        element.namespace = parent
        
class TransitionUI(DiagramElementUI):

    def accepts(self, element):
        if element and element.oclIsKindOf(L.StateVertex):
            return True
        logger.debug("Element rejected by transition")
        return False

    def relink(self, trans, sv, end):
        """
        relink transitions between statevertices
        trans is the transition to be relinked
        sv is the statevertex to which the edge should be relinked
        end is an integer 0 or 1 to tell witch end of the dependency should be relinked
        """
        if end==0:
            trans.source = sv
        else:
            trans.target = sv


class ActorUI(MajorElementUI):
    pass

class InterfaceUI(MajorElementUI):

    def acceptChild(self, element):
        if element.oclIsKindOf(L.Operation):
            return True
        return False

class ComponentUI(MajorElementUI):
    pass

#
# State Machines
#
class CompositeStateUI(DiagramElementUI):
    ## Needs more support from reparent algo, diagram owner != its parent
##    def acceptChild(self, element):
##        print "#"*20,"testing accept"
##        modelcontainer = DISUPP.findUpwardsModelElement(self.graphElement.container)
##        concurrent = False
##        if modelcontainer:
##            concurrent = modelcontainer.isConcurrent
##        print element
##        if element and (element.oclIsKindOf(StateVertex)) and not concurrent:
##            print "Accepts"
##            return True
##        return False

##    def reparent(self, element, parent):
##        print "Calling reparent"
##        assert parent
##        element.container = parent

    def __isRegion(self):
        cnt = self.graphElement.container

        hasRgnCmp =  cnt and cnt.semanticModel and cnt.semanticModel.oclIsKindOf(DI.SimpleSemanticModelElement) and cnt.semanticModel.typeInfo=="RegionCompartment"
        return (hasRgnCmp or self.graphElement.semanticModel.element.isRegion)
    
    def movable(self):
        return (not self.__isRegion())

    def resizable(self):

        return (not self.__isRegion())
    
class SimpleStateUI( ReferencedUI ):
    pass


class CallActionUI( ReferencedUI ):
    pass

