#########################################################################
#
# Date: Aug 2003  Authors: Daniel Stoffler, Michel Sanner
#
#       stoffler@scripps.edu
#       sanner@scripps.edu
#
#       The Scripps Research Institute (TSRI)
#       Molecular Graphics Lab
#       La Jolla, CA 92037, USA
#
# Copyright: Daniel Stoffler, Michel Sanner, and TSRI
#
#########################################################################


import sys, os
from time import sleep

from NetworkEditor.net import Network
from NetworkEditor.simpleNE import NetworkNode, NetworkBuilder
from NetworkEditor.Tests.nodes import DialNode, PrintNode, PassNode

from NetworkEditor.Tests import helper

ed = None

def setUp():
    global ed
    ed = NetworkBuilder("test builder1", withShell=0,
                        visibleWidth=400, visibleHeight=300)
    ed.master.update()
    ed.configure(withThreads=0)


def tearDown():
    ed.exit_cb()
    import gc
    gc.collect()


def pause(sleepTime=None):
    if sleepTime is None:
        from NetworkEditor.Tests import pauseLength as sleepTime
    ed.master.update()
    sleep(sleepTime)


##########################
## Tests
##########################

def test_01_configure():
    dict = ed.configure()
    assert len(dict.items()) > 0,\
           "Expected >0, got %s"%len(dict.items())
    
    assert 'withThreads' in dict.keys(),\
           "Dict keys are: %s"%dict.keys()
    ed.configure(withThreads=0)
    assert ed.withThreadsTk.get() == 0,\
           "Expected 0, got %s"%ed.withThreadsTk.get()
    ed.configure(withThreads=1)
    assert ed.withThreadsTk.get() == 1,\
           "Expected 1, got %s"%ed.withThreadsTk.get()
    ed.configure(withThreads=0) # set it back to 0!
    assert ed.withThreadsTk.get() == 0,\
           "Expected 0, got %s"%ed.withThreadsTk.get()

    assert 'colorNodeByLibrary' in dict.keys(),\
           "Dict keys are: %s"%dict.keys()
    oldval = ed.colorNodeByLibraryTk.get()
    ed.configure(colorNodeByLibrary=0)
    assert ed.colorNodeByLibraryTk.get() == 0,\
           "Expected 0, got %s"%ed.colorNodeByLibraryTk.get()
    ed.configure(colorNodeByLibrary=1)
    assert ed.colorNodeByLibraryTk.get() == 1,\
           "Expected 1, got %s"%ed.colorNodeByLibraryTk.get()
    ed.configure(colorNodeByLibrary=oldval) # set it back to user specified val
    assert ed.colorNodeByLibraryTk.get() == oldval,\
           "Expected %s, got %s"%(oldval,ed.colorNodeByLibraryTk.get() )

    assert 'flashNodesWhenRun' in dict.keys(),\
           "Dict keys are: %s"%dict.keys()
    oldval = ed.flashNodesWhenRunTk.get()
    ed.configure(flashNodesWhenRun=0)
    assert ed.flashNodesWhenRunTk.get() == 0,\
           "Expected 0, got %s"%ed.flashNodesWhenRunTk.get()
    ed.configure(flashNodesWhenRun=1)
    assert ed.flashNodesWhenRunTk.get() == 1,\
           "Expected 1, got %s"%ed.flashNodesWhenRunTk.get()
    ed.configure(flashNodesWhenRun=oldval) # set it back to user specified val
    assert ed.flashNodesWhenRunTk.get() == oldval,\
           "Expected %s, got %s"%(oldval, ed.flashNodesWhenRunTk.get())


def test_02_addDeleteNetwork():
    assert len(ed.networks) == 1,\
           "Expected 1, got %s"%len(ed.networks)
    net = Network('test network')
    ed.addNetwork(net)
    pause()
    assert len(ed.networks) == 2,\
           "Expected 2, got %s"%len(ed.networks)
    assert 'test network' in ed.networks.keys(),\
           "ed.networks.keys are: %s"%ed.networks.keys()
    assert net in ed.networks.values(),\
           "ed.networks.values are: %s"%ed.networks.values()
    ed.deleteNetwork(net)
    pause()
    assert len(ed.networks) == 1,\
           "Expected 1, got %s"%len(ed.networks)
    assert 'test network' not in ed.networks.keys(),\
           "ed.networks.keys are: %s"%ed.networks.keys()


def test_03_renameNetwork():
    net = Network('test network')
    ed.addNetwork(net)
    pause()
    assert net.name == 'test network',\
           "Expected 'test network', got '%s'"%net.name
    # now rename
    net.rename('test network renamed')
    pause()
    assert net.name == 'test network renamed',\
           "Expected 'test network renamed', got '%s'"%net.name
    assert net.name in ed.networks,\
           "ed.networks contains: %s"%ed.networks
    assert 'test network' not in ed.networks,\
           "ed.networks contains: %s"%ed.networks


def test_04_addNode():
    net = ed.currentNetwork
    assert len(ed.currentNetwork.rootNodes) == 0,\
           "Expected 0, got %s"%len(ed.currentNetwork.rootNodes)
    node = NetworkNode('Test Node')
    net.addNode(node, 100, 50)
    pause()
    assert len(ed.currentNetwork.rootNodes) == 1,\
           "Expected 1, got %s"%len(ed.currentNetwork.rootNodes)
    assert node in ed.currentNetwork.nodes,\
           "ed.currentNetwork.nodes contains: %s"%ed.currentNetwork.nodes


def test_05_renameNode():
    net = ed.currentNetwork
    node = NetworkNode('Test Node')
    net.addNode(node, 100, 50)
    pause()
    node.rename('operator1')
    pause()
    assert node.name == 'operator1',\
           "Expected 'operator1', got '%s'"%node.name


def test_06_deleteNode():
    net = ed.currentNetwork
    assert len(ed.currentNetwork.nodes) == 0,\
           "Expected 0, got %s"%len(ed.currentNetwork.nodes)
    node = NetworkNode('Test Node')
    net.addNode(node, 100, 50)
    assert len(ed.currentNetwork.nodes) == 1,\
           "Expected 1, got %s"%len(ed.currentNetwork.nodes)
    ed.currentNetwork.deleteNodes([node])
    assert len(ed.currentNetwork.nodes) == 0,\
           "Expected 0, got %s"%len(ed.currentNetwork.nodes)


def test_07_selectUnselectNode():
    net = ed.currentNetwork
    node = NetworkNode('Test Node')
    net.addNode(node, 100, 50)
    pause()
    assert node.selected == 0, "Expected 0, got %s"%node.selected
    node.select()
    assert node.selected == 1, "Expected 1, got %s"%node.selected 
    pause()
    node.deselect()
    assert node.selected == 0, "Expected 0, got %s"%node.selected
    pause()


def test_08_selectUnselectNodes():
    net = ed.currentNetwork
    node1 = NetworkNode('node1')
    net.addNode(node1, 50, 50)
    node2 = NetworkNode('node2')
    net.addNode(node2, 50, 150)
    node3 = NetworkNode('node3')
    net.addNode(node3, 150, 50)
    node4 = NetworkNode('node4')
    net.addNode(node4, 150, 150)
    pause()
    nodes=ed.currentNetwork.nodes
    for n in nodes:
        ed.currentNetwork.selectNodes([n])
    assert len(nodes) == len(ed.currentNetwork.selectedNodes),\
           "Expexted %s, got %s"%(
        len(nodes),len(ed.currentNetwork.selectedNodes) )
    pause()

    nodes=ed.currentNetwork.nodes
    for n in nodes:
        ed.currentNetwork.deselectNodes([n])
    assert len(ed.currentNetwork.selectedNodes) == 0,\
           "Expected 0, got %s"%len(ed.currentNetwork.selectedNodes)
    pause()

    
def test_09_refreshNetwork():
    net = Network('test network')
    ed.addNetwork(net)
    node1 = helper.makeAndAddNode(net, 'Dial', 'dial', 100, 50)
    pause()
    node2 = helper.makeAndAddNode(net, 'Print', 'print', 100, 200)
    net.connectNodes(node1, node2, 0, 0)
    pause()
    # measure length on menu
    # asking the an index larger than the length of the menu returns the last
    # valide index
    length = node1.menu.index(1000)
    ed.refreshNet_cb()
    pause()
    # make sure menu length has not changed
    assert node1.menu.index(1000) == length,\
           "Expected %s, got %s"%(node1.menu.index(1000), length)


def test_10_addPorts(wait=1):
    # all default values
    net = ed.currentNetwork
    node1 = NetworkNode('node1')
    net.addNode(node1, 100, 50)
    pause()
    p = node1.addInputPort()
    p = node1.addInputPort(name='secondPort', balloon='Hello there',
                           required=False, datatype='int')
    p = node1.addOutputPort()
    p = node1.addOutputPort(name='Noname', datatype='None')
    if wait:
        pause()


def test_11_addConnection():
    net = ed.currentNetwork
    test_10_addPorts(wait=0)
    node1 = ed.currentNetwork.nodes[0]

    node2 = NetworkNode('node2')
    net.addNode(node2, 50, 150)
    p = node2.addInputPort()
    assert len(ed.currentNetwork.rootNodes) == 2,\
           "Expected 2, got %s"%len(ed.currentNetwork.rootNodes)
    pause()
    
    conn1 = ed.currentNetwork.connectNodes(node1, node2, 0, 0)
    assert len(ed.currentNetwork.rootNodes) == 1,\
           "Expected 1, got %s"%len(ed.currentNetwork.rootNodes)
    assert node2.isRootNode == 0, "Expected 0, got %s"%node2.isRootNode
    assert node1.isRootNode == 1, "Expected 1, got %s"%node1.isRootNode
    pause()
    
    conn1.highlight()
    pause()
    
    conn1.unhighlight()
    pause()

    ed.currentNetwork.selectNodes([node1])
    pause()

    ed.currentNetwork.selectNodes([node2])
    pause()

    ed.currentNetwork.clearSelection()
    pause()
    
    node3 = NetworkNode('node3')
    net.addNode(node3, 100, 150)

    p = node3.addInputPort()
    conn2 = ed.currentNetwork.connectNodes(node1, node3, 1, 0,
                                           mode='straight')
    pause()

    node4 = NetworkNode('node4')
    net.addNode(node4, 170, 120)
    
    p = node4.addInputPort()
    conn3 = ed.currentNetwork.connectNodes(node1, node4, 1, 0,
                                           mode='angles', smooth=1)
    pause()

    # move the sub-network made of the selected nodes
    ed.currentNetwork.selectNodes([node1,node4])
    canvas = ed.currentNetwork.canvas

    # find out connections with 2, 1 and no node selected
    net = ed.currentNetwork
    co2, co1, no1 = net.getConnections(net.selectedNodes)
    halfSelConn = co1 # connections with only 1 node selected
    #print co1
    for i in range(30):
        # selected nodes and connections between them have a tag 'selected'
        canvas.move('selected', 2, 0)
        # we need to update the connection between selected nodes and
        # unselected ones
        for c in halfSelConn:
            c.updatePosition()

        canvas.update()


def test_12_showHideGUI():
    ed.hideGUI()
    pause()

    ed.showGUI()
    pause()
    

def test_13_deleteConnection():
    net = ed.currentNetwork
    node1 = helper.makeAndAddNode(net, nType='Dial', name='dial', posx=100, posy=50)
    node2 = helper.makeAndAddNode(net, nType='Print', name='print', posx=100, posy=200)
    pause()
    net.connectNodes(node1, node2, 0, 0)
    pause()
    assert len(node1.outputPorts[0].connections) == 1,\
           "Expected 1, got %s"%len(node1.outputPorts[0].connections)
    assert len(node2.inputPorts[0].connections) == 1,\
           "Expected 1, got %s"%len(node2.inputPorts[0].connections)

    con = node1.outputPorts[0].connections[0]
    ed.currentNetwork.deleteConnections([con])
    pause()
    assert len(node1.outputPorts[0].connections) == 0,\
           "Expected 0, got %s"%len(node1.outputPorts[0].connections)
    assert len(node2.inputPorts[0].connections) == 0,\
           "Expected 0, got %s"%len(node2.inputPorts[0].connections)


def test_14_deleteSelectedNodes():
    net = ed.currentNetwork
    node1 = NetworkNode('node1')
    net.addNode(node1, 50, 50)
    node2 = NetworkNode('node2')
    net.addNode(node2, 50, 150)
    node3 = NetworkNode('node3')
    net.addNode(node3, 150, 50)
    node4 = NetworkNode('node4')
    net.addNode(node4, 150, 150)
    pause()

    nodes=ed.currentNetwork.nodes
    for n in nodes:
        ed.currentNetwork.selectNodes([n])
    pause()
    ed.currentNetwork.deleteNodes(ed.currentNetwork.selectedNodes)
    pause()
    assert len(ed.currentNetwork.nodes) == 0,\
           "Expected 0, got %s"%len(ed.currentNetwork.nodes)
    

def test_15_addCodeToNode():
    # set code of node to output 42, then run node and check if this worked
    net = ed.currentNetwork
    node1 = NetworkNode('Test Code')
    net.addNode(node1, 50, 50)
    p = node1.addOutputPort(name='output')
    pause()
    # set code
    node1.setFunction("def doit(self):\n  i=0\n  i=i+42\n"+\
                      "  self.outputData(output=i)\n")

    # run network
    ed.currentNetwork.run()
    node1.network.waitForCompletion()
    
    # test that node has run the code and output 42
    assert node1.outputPorts[0].data == 42,\
           "Expected 42, got %s"%node1.outputPorts[0].data 
    pause()


def test_16_posxposy():
    # test that a node with no widget is added at the correct location
    net = ed.currentNetwork
    node1 = helper.makeAndAddNode(net, nType='Pass', name='pass', posx=142, posy=143)
    assert node1.posx == 142, "Expected 142, got %s"%node1.posx
    assert node1.posy == 143, "Expected 143, got %s"%node1.posy
    # test that a node with a widget bound to the node is also added where
    # we expect it
    node2 = helper.makeAndAddNode(net, nType='Dial', name='dial', posx=231, posy=301)
    assert node2.posx == 231, "Expected 231, got %s"%node2.posx
    assert node2.posy == 301, "Expected 301, got %s"%node2.posy

    
def test_17__moveNode():
    # test that a node with no widget is added at the correct location
    net = ed.currentNetwork
    node1 = helper.makeAndAddNode(net, nType='Pass', name='pass', posx=142, posy=143)
    pause()
    node1.move(0,0, absolute=True)
    pause()
    # moved node to 0, 0
    assert node1.posx == 0, "Expected 0, got %s"%node1.posx
    assert node1.posy == 0, "Expected 0, got %s"%node1.posy
    node1.move(10,12, absolute=False) #move +10x, +12y
    pause()
    assert node1.posx == 10, "Expected 10, got %s"%node1.posx
    assert node1.posy == 12, "Expected 12, got %s"%node1.posy


def test_18_moveSubGraph():
    # move entire subgraph
    net = ed.currentNetwork
    node1, node2, node3 = helper.buildSmallNetwork(net)
    oldposx = node1.posx
    pause()
    for i in range(40):
        node1.network.moveSubGraph( [node1, node2, node3], 1, 1)
        node1.network.canvas.update()
    assert node1.posx - oldposx == 40,\
           "Expected 40, got %s"%node1.posx - oldposx


def test_19_refreshNetWithSpecialPorts():
    # this tests if we can refresh a network with a node with special
    # ports visible
    net = ed.currentNetwork
    node1 = helper.makeAndAddNode(net, nType='Pass', name='pass', posx=43, posy=48)
    node1.showSpecialPorts()
    pause()
    node1.hideSpecialPorts()
    

def test_20_hideSpecialPortsWhileConnected():
    # this tests if connections are deleted when special ports are hidden,
    # which were connected 
    # add 2 nodes, show special ports, create connection
    net = ed.currentNetwork
    node1 = helper.makeAndAddNode(net, nType='Dial', name='dial', posx=21, posy=40)
    node2 = helper.makeAndAddNode(net, nType='Pass', name='pass', posx=153, posy=149)
    node1.showSpecialPorts()
    node2.showSpecialPorts()
    node1.network.specialConnectNodes(node1, node2, "trigger", "runNode")
    pause()
    # test if a special connections was created
    assert len(node1.specialOutputPorts[0].connections) ,\
           "Expected >0, got %s"%len(node1.specialOutputPorts[0].connections)
    # now hide special ports of second node, this should delete the connection
    node2.hideSpecialPorts()
    pause()
    # test if connection is gone
    assert len(node1.specialOutputPorts[0].connections) == 0,\
           "Expected 0, got %s"%len(node1.specialOutputPorts[0].connections)


def test_21_paramPanelSetImmediate():
    """Test some aspects of the paramPanel immediate flag"""
    net = ed.currentNetwork
    node = helper.makeAndAddNode(net, nType='Pass',posx=21, posy=40)
    node.paramPanel.show()
    pause()
    # at this state, the node should not be modified
    assert node._modified == False, "Expected False, got %s"%node._modified
    # the default value of immediate of the paramPanel should be True
    assert node.paramPanel.immediateTk.get() in [1,True],\
           "Expected True or 1, got %s"%node.paramPanel.immediateTk.get()
    # now we set the immediate to False, the node should be modified then
    node.paramPanel.setImmediate(immediate=1, tagModified=True)
    assert node._modified == True, "Expected True, got %s"%node._modified
    assert node.paramPanel.immediateTk.get() == 1,\
           "Expected 1, got %s"%node.paramPanel.immediateTk.get()
    # set value to 1
    node.paramPanel.setImmediate(immediate=0, tagModified=True)
    assert node.paramPanel.immediateTk.get() == 0,\
           "Expected 0, got %s"%node.paramPanel.immediateTk.get()
    

def test_22_paramPanelSetImmediateSaveLoad():
    """Test if we can set paramPanel immediate to 1, save and restore, and
    the immediate in the paramPanel is still 1."""
    net = ed.currentNetwork
    node = helper.makeAndAddNode(net, nType='Pass',posx=21, posy=40)
    node.paramPanel.show()
    pause()
    # the default value of immediate of the paramPanel should be True
    assert node.paramPanel.immediateTk.get() in [1,True],\
           "Expected True or 1, got %s"%node.paramPanel.immediateTk.get()
    # set the immediate to False
    node.paramPanel.setImmediate(immediate=1, tagModified=True)
    # save network
    # make sure there is no such file
    os.system("rm -f tmpParamPanel_net.py*")
    # save the file
    ed.saveNetwork('tmpParamPanel_net.py')
    # and delete the network
    ed.deleteNetwork(ed.currentNetwork)
    # load the file
    pause()
    ed.loadNetwork('tmpParamPanel_net.py')
    node = ed.currentNetwork.nodes[0]
    assert node.paramPanel.immediateTk.get() == 1,\
           "Expected 1, got %s"%node.paramPanel.immediateTk.get()
    #and clean up
    os.system("rm -f tmpParamPanel_net.py*")
   
    
