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

import coral
from coral.modeler.diagram.degen import DiagramElementGenerator, CannotAttachChildException, IgnoreThisXMIDICreation
DI = coral.lang.XMIDI20
from coral.modeler.coralmodeler import CoralModeler
from coral.log import getLogger
_log=getLogger("coral.modeler.modeler")


def __getFirstSuitableExtension(elementdefinition):
    r = DiagramElementGenerator.getExtension(elementdefinition)
    if r:
        return r
    for superclass in elementdefinition.getAllSuperclasses():
        # return as soon as we find the first suitable extension
        r = DiagramElementGenerator.getExtension(superclass)
        if r:
            return r

    return None

# The task is to create XMIDI elements corresponding to model
# elements, and attach them properly together.  Then, Coral can simply
# layout and show the diagram.

def xmidibuilder(abstract_model, parent_xmidi):
    coral.getTransactionManager().beginModifyCmd()
    try:
        e_type2ext={}
        __attachChildren(abstract_model, parent_xmidi, e_type2ext)
        __addConnectors(abstract_model, parent_xmidi, e_type2ext)
        
    finally:
        coral.getTransactionManager().endModifyCmd()

def xmidibuilder_myself_also(abstract_model, parent_xmidi, position=None):
    coral.getTransactionManager().beginModifyCmd()
    try:
        e_type2ext={}
        if parent_xmidi.oclIsKindOf(DI.Diagram):
            parent = parent_xmidi.owner.element.__type__()
        else:
            parent = parent_xmidi.semanticModel.element.__type__()
        assert parent
        e_type2ext[parent] = __getFirstSuitableExtension(parent)
        __attachChildren2(abstract_model, e_type2ext[parent],
                          parent_xmidi, e_type2ext, _position=position)
        __addConnectors2(abstract_model, e_type2ext)
        
    finally:
        coral.getTransactionManager().endModifyCmd()


def __attachChildren(abstract_model, parent_xmi, e_type2ext):          
    """Creates any children of abstract_model and puts them
    as children of parent_xmi. If a child cannot be created, that
    cone is ignored, otherwise we recursively call this same routine.
    Note that the abstract_model itself is not added."""

    amt = abstract_model.__type__()
    if not e_type2ext.has_key(amt):
        e_type2ext[amt] = __getFirstSuitableExtension(amt)
    am_ext = e_type2ext[amt]

    # BUG This is not correct XMIDI building.
    
    # Now extract all the children from the parent    
    for s in abstract_model.__all_slots__():
        p = s.getProperty()
        if not p.isComposition():
            continue
        if p.getTarget().isDatatypeDefinition():
            continue
        for child in s:
            __attachChildren2(child, am_ext, parent_xmi, e_type2ext)

def __attachChildren2(child, am_ext, parent_xmi, e_type2ext, _position=None):
    assert not child.oclIsKindOf(DI.DiagramElement)
    if not e_type2ext.has_key(child.__type__()):
        e_type2ext[child.__type__()] = __getFirstSuitableExtension(child.__type__())

    child_ext=e_type2ext[child.__type__()]
    if not child_ext:
        _log.debug("Couldn't find extension for %s", str(child))
        return
    
    assert parent_xmi
    assert child_ext

    # First we try to call the parent extensions create and attach to child
    child_xmi=None
    try:
        if not am_ext:
            raise CannotAttachChildException
        
        child_xmi = am_ext.createAndAttachChild(parent_xmi, child, child_ext)
    except CannotAttachChildException:
        try:
            # If that doesn't succeed then we do it the other way around
            child_xmi = child_ext.createAndAttachToParent(child,parent_xmi, position=_position)
        except IgnoreThisXMIDICreation:
            #__attachChildren(child, parent_xmi, e_type2ext)
            assert 0

def __addConnectors(abstract_model, parent_xmi, e_type2ext):          
    # The parent is a graphelement which should contain other elements
    # This routine creates graphelements and connects them correctly
    am_list=[abstract_model]
    while am_list:
        next_level={}
        for am in am_list:
            # Now extract all the children from the parent    

            for s in am.__all_slots__():
                p = s.getProperty()
                if not p.isComposition():
                    continue
                if p.getTarget().isDatatypeDefinition():
                    continue
                for child in s:
                    __addConnectors2(child, e_type2ext)
                    next_level[child]=True

        am_list=next_level.keys()

def __addConnectors2(child, e_type2ext):
    assert not child.oclIsKindOf(DI.DiagramElement)
    if not e_type2ext.has_key(child.__type__()):
        e_type2ext[child.__type__()] = __getFirstSuitableExtension(child.__type__())
        
    child_ext=e_type2ext[child.__type__()]
    if not child_ext:
        _log.debug("Couldn't find extension for %s", str(child))
        return

    child_ext.attachGraphConnector(child)
