'''
Created on 22 Sep 2015

@author: pedroribeiro
'''

import Execute, os
from Cheetah.Template import Template
import time
import Conf
from Conf import DFINDER_HOME

class Methods: SDD, FSDD, CSDD, Pair, PairPicking, PairStatic, PairStaticSMT, PairToken, PairTokenSMT, \
Approx, ApproxSMT, LApprox, LApproxSMT, FDR, FDR_C, FDR_POR, DFinderPM, DFinderFP, DFinderLinear = ["SDD", "FSDD", "CSDD", \
    "Pair", "PairPicking", "PairStatic", "PairStaticSMT", "PairToken", "PairTokenSMT", \
    "Approx", "ApproxSMT", "LApprox", "LApproxSMT", "FDR", "FDR_C", "FDR_POR", "DFinderPM", "DFinderFP", "DFinderLinear"]


def create_script(template_file, options, filename):
    
    template = Template(file=template_file)
    template.options = options    
    
    file = open(filename,"w")
    file.write(str(template))
    file.close()
    
def create_script_bip(template_file, options, filename):
    
    template = Template(file=template_file)
    template.options = options    
    
    file = open(filename,"w")
    file.write(str(template))
    file.close()
    
    Execute.TOOL_COMMAND(filename, "bip_log")
    os.remove(filename)
    

    
def execute(method, script_filename, log_filename):
    exe = Execute.FDR4_COMMAND
    if method in [Methods.Pair, Methods.PairPicking, Methods.PairStatic,Methods.PairStaticSMT,
                  Methods.PairToken,Methods.PairTokenSMT,Methods.Approx,Methods.ApproxSMT,
                  Methods.LApprox,Methods.LApproxSMT]:
        exe = Execute.TOOL_COMMAND
    elif method in [Methods.FDR,Methods.FDR_C,Methods.FDR_POR]:
        exe = Execute.FDR4_COMMAND
    elif method in [Methods.SDD]:
        exe = Execute.SDD_COMMAND
    elif method in [Methods.FSDD]:
        exe = Execute.FSDD_COMMAND
    elif method in [Methods.CSDD]:
        exe = Execute.CSDD_COMMAND
    elif method in [Methods.DFinderPM]:
        exe = Execute.DFINDER_PM_COMMAND
    elif method in [Methods.DFinderFP]:
        exe = Execute.DFINDER_FP_COMMAND
    elif method in [Methods.DFinderLinear]:
        exe = Execute.DFINDER_LINEAR_COMMAND
    else:
        assert False
    
    initial_time = time.time()
    exe(script_filename, log_filename)
    final_time = time.time()
    
    result = "inconclusive"
    if method in [Methods.DFinderPM,Methods.DFinderLinear,Methods.DFinderFP]:
        result = check_result_bip(log_filename)
        os.system("rm -rf "+Conf.DFINDER_HOME+"/*.model")
        os.system("rm -rf "+Conf.DFINDER_HOME+"/*.timod")
        os.system("rm -rf "+Conf.DFINDER_HOME+"/output/*")
    else:
        result = check_result(log_filename)
        
    assert result != "inconclusive"
    with open(log_filename,"a") as log_file:
        log_file.write("SUMMARY "+result+" "+str(final_time - initial_time))
    
    
def check_result(log_filename):
    f = open(log_filename,"r")
    for s in f.readlines():
        if(s.find("Passed") != -1):
            f.close()
            return "passed"
        elif(s.find("Failed") != -1):
            f.close()
            return "failed"
        elif(s.find("TIMEOUT") != -1):
            f.close()
            return "timeout"
    return "error"
    
def check_result_bip(log_filename):
    f = open(log_filename,"r")
    for s in f.readlines():
        if(s.find("Found 0 deadlocks") != -1):
            f.close()
            return "passed"
        elif(s.find(": Deadlock #") != -1):
            f.close()
            return "failed"
        elif(s.find("TIMEOUT") != -1):
            f.close()
            return "timeout"
    f.close()
    return "error"
    
def get_summary(log_filename):
    with open(log_filename,"r") as log_file:
        summary_line = log_file.readlines()[-1]
        summary = summary_line.split(" ")
        assert summary[0] == "SUMMARY"
        return (summary[1], summary[2])
    
def size_summary(main_folder, experiment_name,  bip_filename):
    size_summary_filename = os.path.join(main_folder,"size_summary.txt")
    size_summary_file = open(size_summary_filename,"a")
    bip_file = open(bip_filename,"r")
    size_summary_file.write("Experiment "+experiment_name+"\n") 
    
    started = False
    rule_line = [""]
    while rule_line[0] != "R":
        rule_line = bip_file.readline().split(' ')
        
    size_summary_file.write("#rules: "+rule_line[1])
     
    while True:
        component_name_line = bip_file.readline().strip('\n')
        if component_name_line == "": break
        
        states_line = bip_file.readline().strip('\n')
        transitions_line = bip_file.readline().strip('\n')
        size_summary_file.write(component_name_line+ " #S "+states_line+" #T "+transitions_line+"\n")
        
    bip_file.close()
    size_summary_file.close()
    
    
def myformat(n_char,text): return ("{:<"+str(n_char)+"}").format(text)
def myflot(text): return "{:.2f}".format(text)



def run(main_folder, template_folder, methods, prop, experiments, create_scripts=False, run_scripts=False, email=False):
    main_folder = os.path.abspath(main_folder)
    print "Beginning experiment on " + main_folder
    
    if not os.path.exists(main_folder):
        os.makedirs(main_folder)
        
    result_table_file = os.path.join(main_folder,"results_table.txt")
    FNULL = open(os.devnull,"w")
    FNULL.write("")
    try:
        with open(result_table_file,"w") as result_table:
        
            result_table.write(myformat(14,"Example"))
            result_table.write(myformat(6,"& N"))
        
            for method in methods:
                result_table.write(myformat(14,"& "+method))
                method_folder = os.path.join(main_folder,method)
                if not os.path.exists(method_folder):
                    os.makedirs(method_folder)
        
            for experiment in experiments:
                example_name = experiment[0]
                template_name = experiment[1]
                n_range = experiment[2]
                methods_excluded = experiment[3]
                
                for n in n_range:
                    result_table.write(" \\\\ \n")
                    result_table.write(myformat(14,example_name))
                    result_table.write(myformat(6,"& "+str(n)))
                    
                    for method in methods:
                        if method in methods_excluded:
                            result_table.write(myformat(14,"& +"))
                            continue
                        template_file = os.path.join(template_folder,template_name+".template")
                        script_name = example_name+"_N"+str(n)
                        print "Experiment: " + method +" "+ script_name
                        
                        if create_scripts:
                            script_filename = os.path.join(main_folder,method,script_name+".csp")
                            if method in [Methods.DFinderPM,Methods.DFinderFP, Methods.DFinderLinear]:
                                csp_script_filename = script_filename
                                script_filename = os.path.join(main_folder,method,script_name+".bip")
                                if not os.path.exists(script_filename): 
                                    create_script_bip(template_file, {"n" : n , "method" : method}, csp_script_filename);
                                    if method in [Methods.DFinderPM]:
					#print "Here"
                                        size_summary(main_folder,example_name+" N_"+str(n),"bip_log")
					#print "Out"
                            else:
                                if not os.path.exists(script_filename): 
                                    create_script(template_file, {"n" : n , "method" : method, "property" : prop}, script_filename)
                        
                            log_filename = os.path.join(main_folder,method,script_name+".log")
                            
                            if run_scripts and not os.path.exists(log_filename): 
                                execute(method,script_filename,log_filename)
                                
                            summary = get_summary(log_filename)
                            result = summary[0]
                            execution_time = summary[1]
                            print " -> "+result+" in "+ str(execution_time)
                            if result == "timeout": 
                                result_table.write(myformat(14,"& *"))
                            elif result == "failed":
                                result_table.write(myformat(14,"& -"))
                            elif result == "passed":
                                result_table.write(myformat(14,"& "+str(myflot(float(execution_time)))))
                            elif result == "error":
                                result_table.write(myformat(14,"& err"))
                            else:
                                assert False
                        else:
                            print "script exists"
                            
                    result_table.flush()
                            
        FNULL.close()
        print "End"
    except Exception as e:
        print "Exception"
        print e
        
    
