import unittest
import sys
import os

from utils import execute, kill, run_file, run_barebone
sys.path.append("interface/HUTN")
from hutn_compiler.compiler import main as do_compile

def model_compile(filename):
    return do_compile(filename, "interface/HUTN/grammars/modelling.g", "M")

def conformance_call(operation, model, metamodel):
    return [
            "output",
                "call",
                    "access", "resolve", str(operation),
                    3,
                    "call", "access", "resolve", "import_node", 1, "const", "models/example_M", False,
                    "const", str(model),
                    "const", str(metamodel),
                False,
            True,
            ]

def conformance_check(node):
    return [
            "output",
                "call",
                    "access", "resolve", "conformance_scd",
                    1,
                    "call", "access", "resolve", "import_node", 1, "const", str(node), False,
                    False,
                True,
            ]

class TestConstructorsModelsCompiled(unittest.TestCase):
    def test_constructors_petrinets(self):
        commands = ["initialize_SCD", "models/SimpleClassDiagrams"] + \
                   model_compile("integration/code/petrinets.mvc") + \
                   ["exit", 1] + conformance_check("models/PetriNets") + ["return", False]
        self.assertTrue(run_barebone(commands, ["OK"], 4))

    def test_constructors_petrinet_instance(self):
        commands = ["initialize_SCD", "models/SimpleClassDiagrams"] + \
                   model_compile("integration/code/petrinets.mvc") + \
                   model_compile("integration/code/my_petrinet.mvc") + \
                   ["exit", 1] + conformance_check("models/my_petrinet") + ["return", False]
        self.assertTrue(run_barebone(commands, ["OK"], 4))

    def test_constructors_petrinet_full(self):
        commands = ["initialize_SCD", "models/SimpleClassDiagrams"] + \
                   model_compile("integration/code/my_petrinet_with_MM.mvc") + \
                   ["exit", 1] + conformance_check("models/my_petrinet") + ["return", False]
        self.assertTrue(run_barebone(commands, ["OK"], 4))

    def test_constructors_petrinets_constraints(self):
        commands = ["initialize_SCD", "models/SimpleClassDiagrams"] + \
                   model_compile("integration/code/petrinets_constraints.mvc") + \
                   ["exit", 1] + conformance_check("models/PetriNets") + ["return", False]
        self.assertTrue(run_barebone(commands, ["OK"], 4))

    def test_constructors_petrinet_instance_constraints(self):
        commands = ["initialize_SCD", "models/SimpleClassDiagrams"] + \
                   model_compile("integration/code/petrinets_constraints.mvc") + \
                   model_compile("integration/code/my_petrinet.mvc") + \
                   ["exit", 1] + conformance_check("models/my_petrinet") + ["return", False]
        self.assertTrue(run_barebone(commands, ["OK"], 4))

    def test_constructors_petrinet_full_constraints(self):
        commands = ["initialize_SCD", "models/SimpleClassDiagrams"] + \
                   model_compile("integration/code/my_petrinet_with_MM_and_constraints.mvc") + \
                   ["exit", 1] + conformance_check("models/my_petrinet") + ["return", False]
        self.assertTrue(run_barebone(commands, ["OK"], 4))

    def test_constructors_petrinet_invalids(self):
        commands = ["initialize_SCD", "models/SimpleClassDiagrams"] + \
                   model_compile("integration/code/several_petrinets.mvc") + \
                   ["exit", 1] + \
                   conformance_check("models/valid_petrinet") + \
                   conformance_check("models/invalid_petrinet_1") + \
                   conformance_check("models/invalid_petrinet_2") + \
                   conformance_check("models/invalid_petrinet_3") + \
                   conformance_check("models/invalid_petrinet_4") + \
                   conformance_check("models/invalid_petrinet_5") + \
                   conformance_check("models/invalid_petrinet_6") + \
                   conformance_check("models/invalid_petrinet_7") + \
                   ["return", False]
        self.assertTrue(run_barebone(commands, ["OK", 
                    "Natural does not have a positive or zero value at p1.tokens",
                    "Natural does not have a positive or zero value at p2t.weight",
                    "Destination of model edge not typed by source of type: wrong_p2t",
                    "Source of model edge not typed by source of type: wrong_t2p",
                    "Lower cardinality violation for outgoing edge of type Place_tokens at p1",
                    "Lower cardinality violation for outgoing edge of type P2T_weight at p2t",
                    "Natural has no integer value at p1.tokens"], 4))
