#!/usr/bin/env python

import argparse
import fnmatch
import os
import subprocess
import sys

class Options:
    DFSPath = ""
    RandomPath =""
    OutputPath = ""

class Benchmarks(object):
    buggy = ['BoundedAsync', 'German', 'BasicPaxos', 'TwoPhaseCommit', 'Chord', 'MultiPaxos',
               'Raft', 'ChainReplication']

    spDFS = {}
    schSecDFS = {}
    bugFoundDFS = {}

    spRandom = {}
    buggyRandom = {}
    schSecRandom = {}
    bugFoundRandom = {}

def constructTable():
    print("Constructing LaTeX table with static analysis results ...")

    tableString = ""
    tableString += "&\n"
    tableString += "& \multicolumn{4}{c}{\\textbf{CHESS DFS}}\n"
    tableString += "& \multicolumn{3}{c}{\\textbf{\psharp DFS scheduler}}\n"
    tableString += "& \multicolumn{4}{c}{\\textbf{\psharp random scheduler}}\\\\\n"
    tableString += "\cmidrule(lr){3-6}\n"
    tableString += "\cmidrule(lr){7-9}\n"
    tableString += "\cmidrule(lr){10-13}\n"
    tableString += "\n"

    tableString += "& &\n"
    tableString += "& \multicolumn{1}{c}{\\textbf{RD-on}}\n"
    tableString += "& \multicolumn{1}{c}{\\textbf{RD-off}}\n"
    tableString += "& \multirow{2}{*}{\\textbf{Bug}}\n"
    tableString += "& &\n"
    tableString += "& \multirow{2}{*}{\\textbf{Bug}}\n"
    tableString += "& & &\n"
    tableString += "& \multirow{2}{*}{\\textbf{Bug}} \\\\\n"
    tableString += "\cmidrule(lr){4-4}\n"
    tableString += "\cmidrule(lr){5-5}\n"
    tableString += "\n"

    tableString += "\\textbf{Benchmarks}\n"
    tableString += "& \\textbf{\#T}\n"
    tableString += "& \multicolumn{1}{r}{\\textbf{\#SP}}\n"
    tableString += "& \multicolumn{1}{r}{\\textbf{\#Sch/sec}}\n"
    tableString += "& \multicolumn{1}{r}{\\textbf{\#Sch/sec}}\n"
    tableString += "& \multicolumn{1}{r}{\\textbf{found?}}\n"
    tableString += "\n"

    tableString += "& \multicolumn{1}{r}{\\textbf{\#SP}}\n"
    tableString += "& \multicolumn{1}{r}{\\textbf{\#Sch/sec}}\n"
    tableString += "& \multicolumn{1}{r}{\\textbf{found?}}\n"
    tableString += "\n"

    tableString += "& \multicolumn{1}{r}{\\textbf{\#SP}}\n"
    tableString += "& \multicolumn{1}{r}{\\textbf{\%Buggy}}\n"
    tableString += "& \multicolumn{1}{r}{\\textbf{\#Sch/sec}}\n"
    tableString += "& \multicolumn{1}{r}{\\textbf{found?}}\\\\[0.3em]\n"
    tableString += "\n"

    tableString += "\\toprule\n"
    tableString += "\n"

    iteration = 0
    for benchmark in Benchmarks.buggy:
        tableString += benchmark + "\n"
        tableString += "& -\n"
        tableString += "\n"

        tableString += "& \multicolumn{1}{r}{-}\n"
        tableString += "& \multicolumn{1}{r}{-}\n"
        tableString += "& \multicolumn{1}{r}{-}\n"
        tableString += "& \multicolumn{1}{r}{-}\n"
        tableString += "\n"

        tableString += "& \multicolumn{1}{r}{" + Benchmarks.spDFS[benchmark] + "}\n"

        if Benchmarks.bugFoundDFS[benchmark] > 0:
            tableString += "& \multicolumn{1}{r}{-}\n"
        else:
            tableString += "& \multicolumn{1}{r}{" + "{0:.2f}".format(Benchmarks.schSecDFS[benchmark]) + "}\n"

        if Benchmarks.bugFoundDFS[benchmark] > 0:
            tableString += "& \multicolumn{1}{r}{\\cmark}\n"
        else:
            tableString += "& \multicolumn{1}{r}{\\xmark}\n"

        tableString += "& \multicolumn{1}{r}{" + Benchmarks.spRandom[benchmark] + "}\n"
        tableString += "& \multicolumn{1}{r}{" + "{0:.2f}".format(Benchmarks.buggyRandom[benchmark]) + "\%}\n"
        tableString += "& \multicolumn{1}{r}{" + "{0:.2f}".format(Benchmarks.schSecRandom[benchmark]) + "}\n"

        if Benchmarks.bugFoundRandom[benchmark] > 0:
            tableString += "& \multicolumn{1}{r}{\\cmark}\\\\\n"
        else:
            tableString += "& \multicolumn{1}{r}{\\xmark}\\\\\n"

        tableString += "\n"

    Options.OutputPath = os.path.join('Output', 'testing_table.tex')
    tableFile = open(Options.OutputPath, 'w+')
    tableFile.write(tableString)
    tableFile.close()

def aggregateResults():
    Options.DFSPath = os.path.join('.', 'psharp-dfs')
    Options.RandomPath = os.path.join('.', 'psharp-random')

    print("Searching for P# DFS results ...")
    dfsResults = ""
    for file in os.listdir(Options.DFSPath):
        if fnmatch.fnmatch(file, 'results-*.txt'):
            dfsResults = os.path.join('.', 'psharp-dfs', file)
            break

    if (dfsResults == ""):
        print("P# DFS results not found. Have you run the experiments?")
        sys.exit(0)

    print("Parsing P# DFS results ...")
    with open(dfsResults) as f:
        lines = f.readlines()
        for line in lines:
            line = line.replace("{", "")
            line = line.replace("}", "")
            line = line.replace(",", "")
            tokens = line.split(' ')

            for benchmark in Benchmarks.buggy:
                if benchmark in tokens[2]:
                    Benchmarks.spDFS[benchmark] = tokens[11]
                    Benchmarks.bugFoundDFS[benchmark] = int(tokens[15])
                    numSched = int(tokens[13])
                    time = float(tokens[27])
                    Benchmarks.schSecDFS[benchmark] = float(numSched / time)

    print("Searching for P# random results ...")
    randomResults = ""
    for file in os.listdir(Options.RandomPath):
        if fnmatch.fnmatch(file, 'results-*.txt'):
            randomResults = os.path.join('.', 'psharp-random', file)
            break

    if (randomResults == ""):
        print("P# random results not found. Have you run the experiments?")
        sys.exit(0)

    print("Parsing P# random results ...")
    with open(randomResults) as f:
        lines = f.readlines()
        for line in lines:
            line = line.replace("{", "")
            line = line.replace("}", "")
            line = line.replace(",", "")
            tokens = line.split(' ')

            for benchmark in Benchmarks.buggy:
                if benchmark in tokens[2]:
                    Benchmarks.spRandom[benchmark] = tokens[13]
                    Benchmarks.bugFoundRandom[benchmark] = int(tokens[17])
                    numSched = int(tokens[15])
                    time = float(tokens[29])
                    Benchmarks.schSecRandom[benchmark] = float(numSched / time)
                    Benchmarks.buggyRandom[benchmark] = float((int(tokens[17]) * 100.0) / float(numSched))

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Script for aggregating the P# systematic testing results.')
    args = vars(parser.parse_args())

    aggregateResults()
    constructTable()

    print("Done.")

    sys.exit(0)
