#!/usr/bin/env python
import coral
from coral import modeler
from coral.modeler.modeler import *
from coral.modeler.diagram import xmidi_diagrams
from coral.modeler.diagram.degen import searchForSimpleGraphNode

## The main point with this test is that the InternalTransitionCompartment,
## should synchronize properly, meaning that the entry, doActivity and exit
## actions always should show up in the same order. Entry, if present, always
## before doActivity, and so on.

## Getting this to work in generated code is quite tricky, since all the
## three properties fight over the same container.


m=ModelerWindow()
m.main(loop=0)

L = coral.lang.UML14
DI = coral.lang.XMIDI20

tm = coral.getTransactionManager()

tm.beginModifyCmd()
try:
    prj=coral.Project()
    
    sm=L.StateMachine()
    model = L.Model()
    sm.__setProject__(prj)
    model.__setProject__(prj)
    topstate = L.CompositeState()
    sm.top = topstate
    
    ## Create a StateDiagram from the model
    cd = xmidi_diagrams.createDiagram(prj,owner_elem=sm,typeinfo="StateDiagram")
    assert cd
    
finally:
    tm.endModifyCmd()

m.getDiagramEditorManager().editorSet.notifyFocusOn(cd)
m.processEvents()

assert len(topstate.subvertex) == 0
assert len(cd.contained) == 0

## Create a composite state
s1 = L.SimpleState(name="S1")

tm.beginModifyCmd()
try:
    topstate.subvertex.insert(s1)
finally:
    tm.endModifyCmd()

assert len(topstate.subvertex) == 1
assert len(cd.contained) == 1

x_s1 = s1.xmidi_get_graphelements()[0]

assert x_s1

assert len(x_s1.contained) == 3

itc = x_s1.contained[2]

assert itc

assert len(itc.contained) == 0

## Now the fun starts

## First, add a doActivity

a1 = L.CallAction(name="A1", namespace=model)
a2 = L.CallAction(name="A2", namespace=model)
a3 = L.CallAction(name="A3", namespace=model)

tm.beginModifyCmd()
try:
    s1.doActivity = a2
finally:
    tm.endModifyCmd()

assert s1.doActivity
assert len(itc.contained) == 1

x_a2 = a2.xmidi_get_graphelements()[0]

assert x_a2
assert x_a2 in itc.contained

## Now we add the exit
tm.beginModifyCmd()
try:
    s1.exit = a3
finally:
    tm.endModifyCmd()

assert s1.doActivity
assert s1.exit
assert len(itc.contained) == 2

x_a3 = a3.xmidi_get_graphelements()[0]

assert x_a3
assert x_a2 == itc.contained[0]
assert x_a3 == itc.contained[1]

## Then we add the entry
tm.beginModifyCmd()
try:
    s1.entry = a1
finally:
    tm.endModifyCmd()

assert s1.entry
assert s1.doActivity
assert s1.exit
assert len(itc.contained) == 3

x_a1 = a1.xmidi_get_graphelements()[0]

assert x_a1
assert x_a1 == itc.contained[0]
assert x_a2 == itc.contained[1]
assert x_a3 == itc.contained[2]


## Clear the .exit
## Now we add the exit
tm.beginModifyCmd()
try:
    s1.exit = None
finally:
    tm.endModifyCmd()

assert s1.entry
assert s1.doActivity
assert not s1.exit

assert not a3.xmidi_get_graphelements()

assert len(itc.contained) == 2
assert x_a1 == itc.contained[0]
assert x_a2 == itc.contained[1]

## Now, we are dealing with association, so properties
## can refer to the same elements

# Exit uses same action as doActivity
tm.beginModifyCmd()
try:
    s1.exit = a2
finally:
    tm.endModifyCmd()


assert s1.entry
assert s1.doActivity
assert s1.exit
assert len(itc.contained) == 3



assert len(a2.xmidi_get_graphelements()) == 2
assert x_a1 == itc.contained[0]
assert itc.contained[0].semanticModel.element == a1
assert itc.contained[1].semanticModel.element == a2
assert itc.contained[2].semanticModel.element == a2


## Kill a2
tm.beginModifyCmd()
try:
    a2.__resetAttrs__()
finally:
    tm.endModifyCmd()


assert s1.entry
assert not s1.doActivity
assert not s1.exit
assert len(itc.contained) == 1

## Assign .exit
tm.beginModifyCmd()
try:
    s1.exit = a3
finally:
    tm.endModifyCmd()


assert s1.entry
assert not s1.doActivity
assert s1.exit
assert len(itc.contained) == 2



assert len(a1.xmidi_get_graphelements()) == 1
assert len(a3.xmidi_get_graphelements()) == 1

assert x_a1 == itc.contained[0]
assert itc.contained[0].semanticModel.element == a1
assert itc.contained[1].semanticModel.element == a3

