from __future__ import print_function

import sys
import random
import time
import os
import math
from collections import defaultdict
import sut as SUT


def main():
    R = random.Random()

    repeats = 0

    pid = str(os.getpid())

    depth = int(sys.argv[1])

    sut = SUT.sut()

    taken = defaultdict(lambda: 0)
    takenClass = defaultdict(lambda: 0)
    allTaken = defaultdict(lambda: 0)
    allTakenClass = defaultdict(lambda: 0)
    # takenPath = defaultdict(lambda: 0)
    takenFull = {}

    start = time.time()
    lastEpoch = 0

    count = 0
    sut.standardSwarm(R)
    print(sut.swarmConfig())
    totalPaths = int(math.pow(len(sut.actions()), depth))
    print(totalPaths, "UPPER BOUND ON POSSIBLE TESTS")
    while count < totalPaths:
        sut.restart()
        path = []
        i = 0
        count += 1
        while len(path) < depth:
            possible = sut.actions()
            possible = sorted(possible,
                              key=lambda act: (
                                  allTakenClass[sut.actionClass(act)],
                                  allTaken[act[0]],
                                  takenClass[(sut.actionClass(act), i)],
                                  taken[(act[0], i)]))

            a = None
            for act in possible:
                if act[1]():
                    a = act
                    break
            a = sut.randomEnabled(R)
            if a is None:
                print("DEADLOCK!")
                break
            path.append(a)
            # takenPath[sut.captureReplay(path)] += 1
            taken[(a[0], i)] += 1
            takenClass[(sut.actionClass(a), i)] += 1
            allTaken[(a[0])] += 1
            allTakenClass[sut.actionClass(a)] += 1
            ok = sut.safely(a)
            if not ok:
                print("FALIURE IN TEST", count)
                sut.saveTest(path, "failure.exhaust." + pid + ".test")
                sut.prettyPrintTest(path)
                print(sut.failure())
                sys.exit(255)
            if not "--noCheck" not in sys.argv:
                okCheck = sut.check()
                if not okCheck:
                    print("PROPERTY VIOLATION IN TEST", count)
                    sut.saveTest(path, "failure.exhaust." + pid + ".test")
                    sut.prettyPrintTest(path)
                    print(sut.failure())
                    sys.exit(255)
            i += 1
        if "--ultraVerbose" in sys.argv:
            print("=" * 25)
            sut.prettyPrintTest(path)
        p = sut.captureReplay(path)
        if p in takenFull:
            repeats += 1
        takenFull[p] = True
        epoch = int((time.time() - start) / 2)
        if epoch > lastEpoch:
            lastEpoch = epoch
            print(time.time() - start, "ELAPSED", count, "TESTS", repeats, "REPEATS", end=' ')
            if "--noCover" not in sys.argv:
                print("[", len(sut.allStatements()), "stmts", len(sut.allBranches()), "branches ]", end=' ')
            print()
            if "--verbose" in sys.argv:
                print("*" * 50)
                print("PATH #", count)
                sut.prettyPrintTest(path)
                print()
                print("COUNTS:")
                print("=" * 20)
                for c in sorted(
                        list(
                            allTakenClass.keys()),
                        key=lambda ac: allTakenClass[ac]):
                    print(c, allTakenClass[c])
                print("=" * 20)
                for a in sorted(
                        list(
                            allTaken.keys()),
                        key=lambda act: allTaken[act]):
                    print(a, allTaken[a])

    print(repeats, "TOTAL REPEATED TESTS", len(takenFull), "DISTINCT TESTS")


main()
