#!/usr/bin/env python
#
# This tests the creation of an Association
# between two Classes which are both in one Package.
#
# The bug was that the waypoints[1:-1] were offset by
# the Package's global X and Y coordinates.
#
#
import coral
import time
import qt
from coral.modeler import modeler
from coral.modeler.util import fake_events
from coral.modeler.diagram import di_support as DISUPP

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

mw = modeler.ModelerWindow()
mw.main(loop=0)

p = coral.loadDocument("pkg_with_two_classes.xml")

all = coral.Set()

for r in p.contents():
    all.unionWith(r.__getAllParts__())

def get(coll, name):
    def samename(elem):
        try:
            return elem.name == name
        except:
            return False
    t = coll.select(samename)
    assert len(t) == 1
    return t[0]
    


model = get(all, "M1")

d = model.__getSlotByOppositeName__(DI.Uml1SemanticModelBridge, "element").diagram[0]

assert d.oclIsKindOf(DI.Diagram)

#
# Find the class to move
#
#
def getClass(coll, name, diagram):
    c = get(coll, name)
    x_cs = c.__getSlotByOppositeName__(DI.Uml1SemanticModelBridge, "element").graphElement
    for x_c in x_cs:
        if DISUPP.findDiagramOfElement(x_c) == d:
            return c, x_c
    return c, None

p1, x_p1 = getClass(all, "P1", d)
c1, x_c1 = getClass(all, "C1", d)
c2, x_c2 = getClass(all, "C2", d)

assert p1
assert c1
assert c2
assert x_p1
assert x_c1
assert x_c2

#
# Display diagram
#
dv = mw.displayDiagram(d)
feg = fake_events.FakeMouse(mw, dv)

#
# Activate the association creation gesture
#
feg.activateAction("ClassDiagram_CreateAssociationAction")
time.sleep(1)

## NB: BodyCompartment in x_p1 is the place where the points are relative to
x_p1_x, x_p1_y = DISUPP.localToGlobalPosition(x_p1.contained[1], 0, 0)
x_c1_x, x_c1_y = DISUPP.localToGlobalPosition(x_c1, 0, 0)
x_c2_x, x_c2_y = DISUPP.localToGlobalPosition(x_c2, 0, 0)

x1 = x_c1_x + 30
y1 = x_c1_y + 30
x2 = x_c2_x + 30
y2 = x_c2_y + 30

#
# Create the association by
# - clicking C1,
# - moving down (waypoint 1)
# - moving right (waypoint 2)
# - moving up and clicking finally on C2
#
SPEED = 3
feg.click(x1, y1)
feg.move(x1, y1 + 150, SPEED)
feg.click()
WP1 = feg.x(), feg.y()
feg.move(x2 + 30, y1 + 150, SPEED)
feg.click()
WP2 = feg.x(), feg.y()
feg.move(x2 + 30, y2 + 30, SPEED)
feg.click()

time.sleep(2)
# Now we should have an association.
# Check its coordinates!
print "WP1 global ", WP1
print "WP2 global ", WP2

WP1 = (WP1[0] - x_p1_x, WP1[1] - x_p1_y)
WP2 = (WP2[0] - x_p1_x, WP2[1] - x_p1_y)
print "WP1 local  ", WP1
print "WP2 local  ", WP2

assert len(model.ownedElement.select(lambda x: x.oclIsKindOf(L.Association))) == 0
ass = p1.ownedElement.select(lambda x: x.oclIsKindOf(L.Association))[0]
assert ass
assert ass.connection[0].participant == c1
assert ass.connection[1].participant == c2

x_ass = ass.__getSlotByOppositeName__(DI.Uml1SemanticModelBridge, "element").graphElement[0]
assert x_ass

print "Association/GraphEdge waypoints:"
for p in x_ass.waypoints:
    print p.x, p.y
print "--"

epsilon = 5  # For some reason, there's a small discrepancy in the Y coordinate

assert WP1[0] == x_ass.waypoints[1].x
assert abs(WP1[1] - x_ass.waypoints[1].y) < epsilon

assert WP2[0] == x_ass.waypoints[2].x
assert abs(WP2[1] - x_ass.waypoints[2].y) < epsilon
