"""
Copyright 2016 Open Networking Foundation (ONF)

Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>

    TestON is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.

    TestON is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with TestON.  If not, see <http://www.gnu.org/licenses/>.
"""

"""
Wrapper functions for CHOtest
Author: you@onlab.us
"""
def __init__( self ):
    self.default = ''


def installHostIntents():
    """
    Install one host intent for each combination of hosts in the topology
    """
    import itertools
    import time

    hostCombos = list( itertools.combinations( main.hostMACs, 2 ) )
    intentIdList = []
    for i in xrange( 0, len( hostCombos ), int( main.numCtrls ) ):
        pool = []
        for cli in main.CLIs:
            if i >= len( hostCombos ):
                break
            t = main.Thread( target=cli.addHostIntent,
                             threadID=main.threadID,
                             name="addHostIntent",
                             args=[ hostCombos[ i ][ 0 ],
                                    hostCombos[ i ][ 1 ] ] )
            pool.append( t )
            t.start()
            i = i + 1
            main.threadID = main.threadID + 1
        for thread in pool:
            thread.join()
            intentIdList.append( thread.result )

    return intentIdList


def installPointIntents():
    """
    Install one point intent for each permutation of devices in the topology
    """
    import itertools
    import time

    if main.prefix == 2:
        # Spine-leaf topology is a special case
        for i in range( len( main.hostMACs ) ):
            main.MACsDict[ main.deviceDPIDs[ i + 10 ] ] = main.hostMACs[ i ].split( '/' )[ 0 ]
        deviceCombos = list( itertools.permutations( main.deviceDPIDs[ 10: ], 2 ) )
    else:
        deviceCombos = list( itertools.permutations( main.deviceDPIDs, 2 ) )
    intentIdList = []
    time1 = time.time()
    for i in xrange( 0, len( deviceCombos ), int( main.numCtrls ) ):
        pool = []
        for cli in main.CLIs:
            if i >= len( deviceCombos ):
                break
            t = main.Thread( target=cli.addPointIntent,
                             threadID=main.threadID,
                             name="addPointIntent",
                             args=[ deviceCombos[ i ][ 0 ],
                                    deviceCombos[ i ][ 1 ],
                                    1, 1, '',
                                    main.MACsDict.get( deviceCombos[ i ][ 0 ] ),
                                    main.MACsDict.get( deviceCombos[ i ][ 1 ] ) ] )
            pool.append( t )
            t.start()
            i = i + 1
            main.threadID = main.threadID + 1
        for thread in pool:
            thread.join()
            intentIdList.append( thread.result )
    time2 = time.time()
    main.log.info( "Time taken for adding point intents: %2f seconds" % ( time2 - time1 ) )

    return intentIdList


def checkIntents():
    """
    Check if all the intents are in INSTALLED state
    """
    import time

    intentResult = main.TRUE
    for i in range( main.intentCheck ):
        if i != 0:
            main.log.warn( "Verification failed. Retrying..." )
        main.log.info( "Waiting for onos to install intents..." )
        time.sleep( main.checkIntentsDelay )

        intentResult = main.TRUE
        for e in range( int( main.numCtrls ) ):
            main.log.info( "Checking intents on CLI %s" % ( e + 1 ) )
            intentResultIndividual = main.CLIs[ e ].checkIntentState( intentsId=main.intentIds )
            if not intentResultIndividual:
                main.log.warn( "Not all intents installed on ONOS%s" % ( e + 1 ) )
            intentResult = intentResult and intentResultIndividual
        if intentResult:
            break
    if not intentResult:
        main.log.info( "**** Intent Summary ****\n" + str( main.ONOScli1.intents( jsonFormat=False, summary=True ) ) )

    return intentResult


def checkPingall( protocol="IPv4" ):
    """
    Verify ping across all hosts
    """
    import time

    pingResult = main.TRUE
    for i in range( main.numPings ):
        if i != 0:
            main.log.warn( "Pingall failed. Retrying..." )
            main.log.info( "Giving ONOS some time..." )
            time.sleep( main.pingSleep )

        pingResult = main.Mininet1.pingall( protocol=protocol, timeout=main.pingTimeout )
        if pingResult:
            break

    return pingResult


def checkLinkEvents( linkEvent, linkNum ):
    """
    Verify link down/up events are correctly discovered by ONOS
    linkNum: the correct link number after link down/up
    """
    import time

    linkResult = main.TRUE
    for i in range( main.linkCheck ):
        if i != 0:
            main.log.warn( "Verification failed. Retrying..." )
            main.log.info( "Giving ONOS some time..." )
            time.sleep( main.linkSleep )

        linkResult = main.TRUE
        for e in range( int( main.numCtrls ) ):
            main.log.info( "Checking link number on ONOS%s" % ( e + 1 ) )
            linkResultIndividual = main.CLIs[ e ].checkStatus( main.numMNswitches,
                                                               str( linkNum ) )
            if not linkResultIndividual:
                main.log.warn( "Link %s not discovered by ONOS%s" % ( linkEvent, ( e + 1 ) ) )
            linkResult = linkResult and linkResultIndividual
        if linkResult:
            break

    return linkResult
