#! /usr/bin/env python
# -*- coding: utf-8 -*-

import pdb
import dpr
from pdb.pattern import Pattern, toPattern
from pdb.command import Command, CommandOutputParser

class DprcPatternGenerator(object):
    def __init__(self, model, query, MAX):
        self.model = model
        self.query = query
        self.MAX = MAX


    def _generate_abstract_model(self):
        print "removing irrelevant clocks from simple constraints"
        cmd = Command("SAFEABS -c %s" % self.model)
        irr_clocks = cmd.parser.irrelevant_clocks
        Command("ABSTRACTOR -o %s %s > test.ta" % (self.model, irr_clocks))

        print "removing safe variables"
        cmd = Command("SAFEABS test.ta")
        safe_vars = cmd.parser.safe_vars
        Command("ABSTRACTOR -o test.ta %s > model.abs" % safe_vars)
        Command("rm -f test.ta")

        return toPattern(irr_clocks.split() + safe_vars.split())


    def _check_fast_reachable(self):
        cmd = Command("MCTA -o3 -h3 %s %s" % ("model.abs", self.query), runtime=self.MAX)
        self.fast_reachable = cmd.parser.states > 0
        if self.fast_reachable:
            self.shortest = cmd.parser.trace
            if self.shortest == 0: # abstraction is correct wrt query
                print "Property: not satisfied"
                exit(0)
        return self.fast_reachable

    
    def generate_pattern(self):
        abstract = self._generate_abstract_model()
        if self._check_fast_reachable():
            abstract += toPattern(self._try_clock_removing("model.abs"))
            Command("ABSTRACTOR -f model.pdb %s -o %s > model.abs" % (self.query, " ".join(abstract)))
        else:
            print "switching to original dpr"
            abstract += Pattern(filename="model.abs") - dpr.version_L("model.abs", self.query)

        return Pattern(self.model) - toPattern(abstract)


    def _build_pdb(self, abstract):
        pattern = Pattern(self.model) - toPattern(abstract)
        pdb_builder = pdb.PDBBuilder()
        return pdb_builder.gen_pdb(self.model, self.query, pattern)


    def _determine_irrelevant_clocks(self, abstraction, params):
        abstract = []
        assert self.shortest

        clocks_to_check = Command("SAFEABS -r %s" % abstraction)
        for clock in clocks_to_check.parser.relevant_clocks.split():
            Command("ABSTRACTOR %s %s %s > temp-1.ta" % (params, abstraction, clock))
            out = Command("MCTA -o3 -h3 temp-1.ta %s" % self.query, runtime=self.MAX)
            Command("rm -f temp-1.ta")
            new_trace = out.parser.trace
            if new_trace == self.shortest:
                abstract.append(clock)
        return abstract


    def _try_clock_removing(self, abstraction):
        abstract = self._determine_irrelevant_clocks(abstraction, "-o")
        if not abstract:
            abstract = self._determine_irrelevant_clocks(abstraction, "-o -w")
        return abstract


if __name__ == "__main__":
    import sys

    model = sys.argv[1]
    query = sys.argv[2]

    dprc = DprcPatternGenerator(model, query)
    pdb = dprc.generate_pdb()

    cmd = Command("MCTA -o3 -h4 --pdb=%s %s %s" % (pdb, model, query))
    print "Property:", cmd.parser.property
    if cmd.parser.property == "satisfied":
        print "search %7.2f s" % (cmd.parser.sys_time + cmd.parser.usr_time)
        print "states: %8d, time: %7.2f, trace: %7d" % (cmd.parser.states, cmd.parser.usr_time + cmd.parser.sys_time, cmd.parser.trace)
