#########################################################################
#
# Date: Jun 2003 Author: Daniel Stoffler
#
#    stoffler@scripps.edu
#
# Copyright: Daniel Stoffler and TSRI
#
#########################################################################


import sys, string
from mglutil.regression import testplus

from NetworkEditor.net import Network
from NetworkEditor.simpleNE import NetworkNode
from NetworkEditor.macros import MacroNode, MacroInputNode, MacroOutputNode, \
     MacroNetwork
from time import sleep
from NetworkEditor.simpleNE import NetworkBuilder
from ViPEr.StandardNodes import Pass

ed = None
node1 = None
node2 = None
withThreads = 0 # default is: multi-threading off

# allow for additional user input
if len(sys.argv):
    for myArg in sys.argv[1:]:
        if myArg[:11] == 'withThreads':
            withThreads = int(string.strip(myArg)[-1])


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


def quitEditor():
    ed.master.after(1000, ed.exit_cb )


def pause(sleepTime=0.4):
    ed.master.update()
    sleep(sleepTime)


def test_createAndDestroyMacro():
    """this test adds a macro node to a new network named 'test network1'.
    It then tests if a new network named 'test macro' is created and if a
    Macroinput and a MacroOutputNode are added. Then the MacroNetwork will
    collapse and expanded and finally the entire network gets deleted"""
    net = Network('createAndDestroyMacro')
    ed.addNetwork(net)
    ed.setNetwork(net)

    # add macro node
    node0 = MacroNode(name='test macro')
    net.addNode(node0, 200, 200)

    # test that a MacroNode in the main network has been created
    macronode = net.nodes[0]
    assert isinstance(macronode, MacroNode)

    # test that MacroNode attribute network is set to the main
    # network and that the attribute macroNetwork is set to the MacroNetwork
    assert isinstance(macronode.network, Network)
    assert hasattr(macronode, 'macroNetwork')
    assert isinstance(macronode.macroNetwork, MacroNetwork)
    macronet = macronode.macroNetwork

    # test MacroNetwork name
    assert macronet.name == 'test macro' # same as node0.name

    # test that a MacroInputNode and a MacroOutputNode have been added to the
    # MacroNetwork
    ipnode = macronet.nodes[0]
    opnode = macronet.nodes[1]
    assert isinstance(ipnode, MacroInputNode)
    assert isinstance(opnode, MacroOutputNode)

    # test that MacroInput and MacroOutputNode know about the MacroNode
    assert hasattr(ipnode, 'macroNode')
    assert hasattr(opnode, 'macroNode')

    # test that the macroNetwork know about the MacroInput and MacroOutputNode
    assert hasattr(macronet, 'ipNode')
    assert hasattr(macronet, 'opNode')

    # test that a MacroNetwork can be collapsed
    macronode.shrink()
    pause()
    # assert that the MacroNetwork with the name 'test macro' still exists
    assert 'test macro' in net.editor.networks.keys()
    assert 'createAndDestroyMacro' in net.editor.networks.keys()

    # test that a MacroNetwork can be expanded again
    macronode.expand()
    pause()
    # assert that the MacroNetwork is back in the list
    assert 'test macro' in net.editor.networks.keys()
    assert 'createAndDestroyMacro' in net.editor.networks.keys()

    # shrink macro again
    macronode.shrink()
    pause()
    # delete macro
    net.deleteNodes([macronode])
    # delete network
    ed.deleteNetwork(net)
   

def test_deleteExpandedMacro():
    """This tests if an opended macro network is properly deleted when deleting
    the MacroNode in the main network.
    PLEASE NOTE: DELETING A MAIN NETWORK WITH A MACRO IS NOT POSSIBLE IN VIPER
    BECAUSE WE DISABLE THE 'DELETE' MENU ENTRY."""
    net = Network('deleteExpandedMacro')
    ed.addNetwork(net)
    ed.setNetwork(net)

    # add macro node
    node0 = MacroNode(name='test macro2')
    net.addNode(node0, 200, 200)
    macronode = node0
    macronet = macronode.macroNetwork
    ipnode = macronet.nodes[0]
    opnode = macronet.nodes[1]

    # assert both networks are present
    assert 'deleteExpandedMacro' in net.editor.networks.keys()
    assert 'test macro2' in net.editor.networks.keys()
    pause()
    
    # delete the MacroNode
    net.deleteNodes([macronode])

    # assert the MacroNetwork 'test macro2' is gone
    assert 'test macro2' not in net.editor.networks.keys()
    pause()
    # delete network
    ed.deleteNetwork(net)
    

def test_addPorts():
    """This tests if new ports are created upon connecting nodes to a
    MacroInputNode or a MacroOutputode"""
    net = Network('addPorts')
    ed.addNetwork(net)
    ed.setNetwork(net)

    # add macro node
    node0 = MacroNode(name='test macro3')
    net.addNode(node0, 200, 200)
    macronode = node0
    macronet = macronode.macroNetwork
    ipnode = macronet.nodes[0]
    opnode = macronet.nodes[1]

    # ipnode should have 1 special output port
    # opnode should have 1 special input port
    # macronode should have 0 input/output ports
    assert len(ipnode.outputPorts) == 1
    assert len(opnode.inputPorts) == 1
    assert len(macronode.inputPorts) == 0
    assert len(macronode.outputPorts) == 0

    node1 = Pass()
    macronet.addNode(node1, 150, 150)
    macronet.connectNodes(ipnode, node1, 0, 0)
    macronet.connectNodes(node1, opnode, 0, 0)

    # now, all nodes (except the Pass) should have 1 port more
    assert len(ipnode.outputPorts) == 2
    assert len(opnode.inputPorts) == 2
    assert len(macronode.inputPorts) == 1
    assert len(macronode.outputPorts) == 1
    pause()

    net.deleteNodes([macronode])
    ed.deleteNetwork(net)


def test_deletePorts():
    """This tests if new ports that were created upon connecting nodes to a
    MacroInputNode or a MacroOutputode are getting destroyed if the connection
    is destroyed"""
    net = Network('deletePorts')
    ed.addNetwork(net)
    ed.setNetwork(net)

    # add macro node
    node0 = MacroNode(name='test macro3')
    net.addNode(node0, 200, 200)
    macronode = node0
    macronet = macronode.macroNetwork
    ipnode = macronet.nodes[0]
    opnode = macronet.nodes[1]

    # add pass node and connect 
    node1 = Pass()
    macronet.addNode(node1, 150, 150)
    macronet.connectNodes(ipnode, node1, 0, 0)
    macronet.connectNodes(node1, opnode, 0, 0)
    pause()

    # now delete the connection to MacroInputNode
    c = node1.inputPorts[0].connections[0]
    macronet.deleteConnections([c])
    pause()
    # macroinputnode should now have only 1 outputport
    assert len(ipnode.outputPorts) == 1
    # macronode should have 0 inputports
    assert len(macronode.inputPorts) == 0

    # delete the connection to MacroOutputNode
    c = node1.outputPorts[0].connections[0]
    macronet.deleteConnections([c])
    pause()
    # macrooutputnode should now have only 1 inputport
    assert len(opnode.inputPorts) == 1
    # macronode should have 0 outputports
    assert len(macronode.outputPorts) == 0

    net.deleteNodes([macronode])
    ed.deleteNetwork(net)


def test_deleteMacroConnections():
    """This tests if connections to the Macro node are destroyed when
    connections inside the macronet to the ip and op node are destroyed"""
    net = Network('deleteMacroConnections')
    ed.addNetwork(net)
    ed.setNetwork(net)

    # add macro node
    node0 = MacroNode(name='test macro4')
    net.addNode(node0, 200, 200)
    macronode = node0
    macronet = macronode.macroNetwork
    ipnode = macronet.nodes[0]
    opnode = macronet.nodes[1]

    # add pass node and connect 
    node1 = Pass()
    macronet.addNode(node1, 150, 150)
    macronet.connectNodes(ipnode, node1, 0, 0)
    macronet.connectNodes(node1, opnode, 0, 0)
    node0.shrink()
    pause()

    # connect pass nodes in the main network to the macro node
    pass1 = Pass()
    net.addNode(pass1, 50, 50)
    pass2 = Pass()
    net.addNode(pass2, 50, 250)
    net.connectNodes(pass1, node0, 0, 0)
    net.connectNodes(node0, pass2, 0, 0)
    pause()

    # now delete the pass node in the macro network
    node0.expand()
    macronet.deleteNodes([node1])
    pause()
    assert len(pass1.outputPorts[0].connections) == 0
    assert len(pass2.inputPorts[0].connections) == 0
    node0.shrink()
    pause()
    
    net.deleteNodes([macronode])
    ed.deleteNetwork(net)



def test_deleteOneOfTwoConnections():
    """If 2 or more nodes connect to the same macro ip or op node, the
    port of the ip or op node should NOT be deleted"""
    net = Network('deleteOneofTwoConnections')
    ed.addNetwork(net)
    ed.setNetwork(net)

    # add macro node
    node0 = MacroNode(name='test macro5')
    net.addNode(node0, 200, 200)
    macronode = node0
    macronet = macronode.macroNetwork
    ipnode = macronet.nodes[0]
    opnode = macronet.nodes[1]

    # add pass node and connect 
    node1 = Pass()
    macronet.addNode(node1, 150, 150)
    macronet.connectNodes(ipnode, node1, 0, 0)
    macronet.connectNodes(node1, opnode, 0, 0)
    pause()


    # add second pass node and connect 
    node2 = Pass()
    macronet.addNode(node2, 250, 150)
    macronet.connectNodes(ipnode, node2, 1, 0)
    # no new outputport has been created
    assert len(ipnode.outputPorts) == 2
    pause()

    # now delete the second pass node in the macro network
    macronet.deleteNodes([node2])
    pause()
    # no port should have been deleted
    assert len(ipnode.outputPorts) == 2
    assert len(macronode.inputPorts) == 1
    # connection should still be there
    assert len(node1.inputPorts[0].connections) == 1
    node0.shrink()
    pause()
    
    net.deleteNodes([macronode])
    ed.deleteNetwork(net)


def test_whoIsCurrentNetwork():
    """add 2 macros into the main network, expand both, go to the second
macronetwork and shrink it. We should end up in the main network and not
in the macronetwork of the first macro."""
    net = Network('whoIsCurrentNetwork')
    ed.addNetwork(net)
    ed.setNetwork(net)
    # add macro node1
    node1 = MacroNode(name='macro1')
    net.addNode(node1, 200, 200)
    # add macro node2
    node2 = MacroNode(name='macro2')
    net.addNode(node2, 250, 200)
    node1.expand()
    node2.expand()
    # are we in macronetwork of node2?
    ed.setNetwork(node2.macroNetwork)
    pause()
    assert ed.currentNetwork.name == 'macro2'
    # shrink node2
    node2.shrink()
    pause()
    assert ed.currentNetwork.name == 'whoIsCurrentNetwork'
    net.deleteNodes([node1, node2])
    ed.deleteNetwork(net)


harness = testplus.TestHarness( __name__,
                                connect = startEditor,
                                funs = testplus.testcollect( globals()),
                                disconnect = quitEditor
                                )

if __name__ == '__main__':
    print harness
    sys.exit( len( harness))
