# This file was automatically generated by SWIG (https://www.swig.org).
# Version 4.1.0
#
# Do not make changes to this file unless you know what you are doing - modify
# the SWIG interface file instead.

from sys import version_info as _swig_python_version_info
# Import the low-level C/C++ module
if __package__ or "." in __name__:
    from . import _ltsmin
else:
    import _ltsmin

try:
    import builtins as __builtin__
except ImportError:
    import __builtin__

_swig_new_instance_method = _ltsmin.SWIG_PyInstanceMethod_New
_swig_new_static_method = _ltsmin.SWIG_PyStaticMethod_New

def _swig_repr(self):
    try:
        strthis = "proxy of " + self.this.__repr__()
    except __builtin__.Exception:
        strthis = ""
    return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)


def _swig_setattr_nondynamic_instance_variable(set):
    def set_instance_attr(self, name, value):
        if name == "this":
            set(self, name, value)
        elif name == "thisown":
            self.this.own(value)
        elif hasattr(self, name) and isinstance(getattr(type(self), name), property):
            set(self, name, value)
        else:
            raise AttributeError("You cannot add instance attributes to %s" % self)
    return set_instance_attr


def _swig_setattr_nondynamic_class_variable(set):
    def set_class_attr(cls, name, value):
        if hasattr(cls, name) and not isinstance(getattr(cls, name), property):
            set(cls, name, value)
        else:
            raise AttributeError("You cannot add class attributes to %s" % cls)
    return set_class_attr


def _swig_add_metaclass(metaclass):
    """Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass"""
    def wrapper(cls):
        return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy())
    return wrapper


class _SwigNonDynamicMeta(type):
    """Meta class to enforce nondynamic attributes (no new attributes) for a class"""
    __setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__)


import spot.impl
SHARED_PTR_DISOWN = _ltsmin.SHARED_PTR_DISOWN
class model(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    __swig_destroy__ = _ltsmin.delete_model
    load = _swig_new_static_method(_ltsmin.model_load)
    kripke_raw = _swig_new_instance_method(_ltsmin.model_kripke_raw)
    kripkecube = _swig_new_instance_method(_ltsmin.model_kripkecube)
    state_size = _swig_new_instance_method(_ltsmin.model_state_size)
    state_variable_name = _swig_new_instance_method(_ltsmin.model_state_variable_name)
    state_variable_type = _swig_new_instance_method(_ltsmin.model_state_variable_type)
    type_count = _swig_new_instance_method(_ltsmin.model_type_count)
    type_name = _swig_new_instance_method(_ltsmin.model_type_name)
    type_value_count = _swig_new_instance_method(_ltsmin.model_type_value_count)
    type_value_name = _swig_new_instance_method(_ltsmin.model_type_value_name)

# Register model in _ltsmin:
_ltsmin.model_swigregister(model)

import spot
import spot.aux
import sys
import subprocess
import os.path
import re

def load(filename):
# Compile promela model with Spins by end, even if it would be done in model.load,
# so we can capture the output of the compilation regardless of the Jupyter version.
# (Older Jupyter version to not send the output to the notebook, and newer versions
# do it asynchronously in a way that make testing quite hard.)
  if filename.endswith('.pm') or filename.endswith('.pml') or filename.endswith('.prom'):
    dst = os.path.basename(filename) + '.spins'
    if not os.path.exists(dst) or (os.path.getmtime(dst) < os.path.getmtime(filename)):
      p = subprocess.run(['spins', filename], stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT,
                         universal_newlines=True)
      if p.stdout: print(re.sub(r'^\s*\[\.*\s*\]\n', '', p.stdout,
                                flags=re.MULTILINE), file=sys.stderr)
      if p.stderr: print(p.stderr, file=sys.stderr)
      p.check_returncode()
      filename = dst
  return model.load(filename)

@spot._extend(model)
class model:
  def kripke(self, ap_set, dict=spot._bdd_dict,
	      dead=spot.formula_ap('dead'),
	      compress=2):
    s = spot.atomic_prop_set()
    for ap in ap_set:
      s.insert(spot.formula_ap(ap))
    return self.kripke_raw(s, dict, dead, compress)

  def info(self):
    res = {}
    ss = self.state_size()
    res['state_size'] = ss
    res['variables'] = [(self.state_variable_name(i),
			 self.state_variable_type(i)) for i in range(ss)]
    tc = self.type_count()
    res['types'] = [(self.type_name(i),
		     [self.type_value_name(i, j)
		      for j in range(self.type_value_count(i))])
		     for i in range(tc)]
    return res

  def __repr__(self):
    res = "ltsmin model with the following variables:\n";
    info = self.info()
    for (var, t) in info['variables']:
      res += '  ' + var + ': ';
      type, vals = info['types'][t]
      if vals:
        res += str(vals)
      else:
        res += type
      res += '\n';
    return res

def require(*tools):
    """
    Exit with status code 77 if the required tool is not installed.

    This function is mostly useful in Spot test suite, where 77 is a
    code used to indicate that some test should be skipped.
    """
    import shutil
    for tool in tools:
        if tool == "divine":
            if shutil.which("divine") == None:
                print("divine not available", file=sys.stderr)
                sys.exit(77)
            try:
                out = subprocess.check_output(['divine', 'compile', '--help'],
                                              stderr=subprocess.STDOUT)
            except (subprocess.CalledProcessError):
                print("divine does not understand 'compile --help'",
                       file=sys.stderr)
                sys.exit(77)
            if b'LTSmin' not in out:
                print("divine available but no support for LTSmin",
                       file=sys.stderr)
                sys.exit(77)
        elif tool == "spins":
            if shutil.which("spins") == None:
                print("spins not available", file=sys.stderr)
                sys.exit(77)
        else:
            raise ValueError("unsupported argument for require(): " + tool)


# Load IPython specific support if we can.
try:
# Load only if we are running IPython.
    __IPYTHON__

    from IPython.core.magic import Magics, magics_class, cell_magic
    import os
    import tempfile

    @magics_class
    class EditDVE(Magics):

        @cell_magic
        def dve(self, line, cell):
            if not line:
               raise ValueError("missing variable name for %%dve")
            with spot.aux.tmpdir():
               with tempfile.NamedTemporaryFile(dir='.', suffix='.dve') as t:
                   t.write(cell.encode('utf-8'))
                   t.flush()

                   try:
                       p = subprocess.run(['divine', 'compile',
                                             '--ltsmin', t.name],
                                            stdout=subprocess.PIPE,
                                            stderr=subprocess.PIPE,
                                            universal_newlines=True)
                       if p.stdout: print(p.stdout)
                       if p.stderr: print(p.stderr, file=sys.stderr)
                       p.check_returncode()
                       self.shell.user_ns[line] = load(t.name + '2C')
                   finally:
                       spot.aux.rm_f(t.name + '.cpp')
                       spot.aux.rm_f(t.name + '2C')

    @magics_class
    class EditPML(Magics):

        @cell_magic
        def pml(self, line, cell):
            if not line:
               raise ValueError("missing variable name for %%pml")
            with spot.aux.tmpdir():
               with tempfile.NamedTemporaryFile(dir='.', suffix='.pml') as t:
                   t.write(cell.encode('utf-8'))
                   t.flush()
                   try:
                       self.shell.user_ns[line] = load(t.name)
                   finally:
                       spot.aux.rm_f(t.name + '.spins.c')
                       spot.aux.rm_f(t.name + '.spins')

    ip = get_ipython()
    ip.register_magics(EditDVE)
    ip.register_magics(EditPML)

except (ImportError, NameError):
    pass


