#!/usr/bin/python
#
#  File: helena-generate-config
#
#  Parse arguments from the command line and generate the appropriate
#  C configuration file.
#

import datetime
from datetime import date
from datetime import datetime
from datetime import time
import os
import re
import socket
import sys
import xml.dom.minidom

VERSION = "3.0"
DATE    = "November 29, 2017"

#  actions
EXPLORE     = "EXPLORE"
SIMULATE    = "SIMULATE"
BUILD_GRAPH = "BUILD-GRAPH"
CHECK       = "CHECK"

#  search algorithms
BFS         = "BFS"
DFS         = "DFS"
DBFS        = "DBFS"
DDFS        = "DDFS"
RWALK       = "RWALK"
DELTA_DDD   = "DELTA-DDD"
TARJAN      = "TARJAN"

#  trace types
FULL        = "FULL"
EVENTS      = "EVENTS"
STATE       = "STATE"

#  property types
LTL         = "LTL"
STATE       = "STATE"
DEADLOCK    = "DEADLOCK"

#  options
GENERAL_OPTS = ("General options",
                [ "h", "V", "v", "N", "g", "b", "p", "md", "wp" ])
SEARCH_OPTS = ("Search and storage options",
               [ "A", "t", "W", "R", "cs" ])
REDUCTION_OPTS = ("Reduction techniques",
                  [ "H", "P", "i" ])
LIMIT_OPTS = ("Limit options",
              [ "ml", "tl", "sl" ])
MODEL_OPTS = ("Model options",
              [ "d", "a", "r", "L", "m" ])
OUTPUT_OPTS = ("Output options",
               [ "o", "tr" ])
OPTION_TYPES = [
    GENERAL_OPTS,
    SEARCH_OPTS,
    REDUCTION_OPTS,
    LIMIT_OPTS,
    MODEL_OPTS,
    OUTPUT_OPTS ]


def helpMessage(o):
    if   o in [ "h", "help" ]:
        return """-h[=opt], --help[=opt]

Prints help and exit.  If an option is provided, a specific help
message for this option is printed.  If opt=FULL a detailed help for
all options is printed."""
    elif o in [ "V", "version" ]:
        return """-V, --version

Prints the version number and exit."""
    elif o in [ "v", "verbose" ]:
        return """-v, --verbose

Be verbose."""
    elif o in [ "N", "action" ]:
        return """-N=ACTION, --action=ACTION

Indicate the action performed on the model.  ACTION must have one of
the following values:
* EXPLORE - Explore the state space of the model and then prints some
   statistics.  This is the default.
* SIMULATE - Start interactive simulation mode.  You can then navigate
   through the reachability graph of the model. A simple command
   language is provided.  Once the simulation is started, type help to
   see the list of commands.
* BUILD-GRAPH - Build the reachability graph of the model using
   algorithm DELTA-DDD (see option algo) and store it on disk.  This
   graph can then be analyzed using the helena-graph tool.
* CHECK-prop - Check whether or not property prop (which must be a
   property defined in the model file) is verified."""
    elif o in [ "g", "progress" ]:
        return """-g=LEVEL, --progress=LEVEL

LEVEL can take one of these three values:
* no-compile - Helena stops after the generation of source files.
* no-check - Helena launches compilation but does not launches the
  search.
* no-report - Helena launches the search but does not print any
  report."""
    
    elif o in [ "b", "observer" ]:
        return """-b[={0|1}], --observer[={0|1}]

Activate/deactivate the observer thread that prints some progression
informations during the search.  It is turned on by default."""  
    elif o in [ "p", "property-file" ]:
        return """-p=FILE, --property-file=FILE

File FILE contains the definition of the property to check (specified
with option --action=CHECK-prop).  By default, if the input file of
the model is model.lna, Helena will look into model.prop.lna for the
property definition."""
    elif o in [ "md", "model-directory" ]:
        return """-md=DIRECTORY, --model-directory=DIRECTORY

All generated files such as source files are put in directory
DIRECTORY (instead of ~/.helena/models/lna/my-net)."""
    elif o in [ "A", "algo" ]:
        return """-A=ALGO, --algo=ALGO

Sets search algorithm used to explore the state space.  Available
algorithms are:

* DFS - The state space is explored using a depth-first search.  This
   is the default.
* BFS - The state space is explored using a breadth-first search.
* DELTA-DDD - The state space is explored using a parallel
   breadth-first search based on state compression.
* RWALK - A random walk is used.  The principle is to randomly select
   at each state an enabled transition, execute it and reiterate this
   process.  The walk is reinitiated each time a deadlock state is
   met.  If no limit is specified (e.g., option --state-limit) the
   search will last forever."""
    elif o in [ "t", "hash-size" ]:
        return """-t=N, --hash-size=N

Set to 2^N the size of the hash table which stores the set of
reachable states.  The default value is 22.  """
    elif o in [ "W", "workers" ]:
        return """-W=N, --workers=N

Set to N the number of working threads that will perform the
search."""
    elif o in [ "R", "random-succs" ]:
        return """-R[={0|1}], --random-succs[={0|1}]

Activate/deactivate randomised successor selection.  This is only
valid if algorithm DFS is used.  This option is useful if the
counter-example produced is too long.  Using randomisation can often
produce a smaller counter-example."""
    elif o in [ "cs", "candidate-set-size" ]:
        return """-cs=N, --candidate-set-size=N

Set the candidate set size of algorithm DELTA-DDD.  100000 is the
default value.  Increasing it may consume more memory but can fasten
the search."""
    elif o in [ "H", "hash-compaction" ]:
        return """-H[={0|1}], --hash-compaction[={0|1}]

Activate/deactivate hash compaction.  Its principle is to only store a
hash signature of each visited state.  In case of hash conflict,
Helena will not necessarily explore the whole state space and may
report that no error has been found whereas one could exist."""
    elif o in [ "P", "partial-order" ]:
        return """-P[={0|1}], --partial-order[={0|1}]}

Activate/deactivate partial-order reduction.  This reduction limits
the exploration of multiple paths that are redundant with respect to
the desired property.  This causes some states to be never explored
during the search.  The reductions done depend on the property
verified.  If there is no property checked, the reduction done only
preserves the existence of deadlock states."""
    elif o in [ "i", "proviso" ]:
        return """-i[={0|1}], --proviso[={0|1}]}

Activate/deactivate the proviso of partial-order reduction.  It is
turned on by default if a property (different from deadlock absence)
is analysed."""
#    elif o in [ "E", "edge-lean" ]:
#        return """-E[={0|1}], --edge-lean[={0|1}]
#
#Activate/deactivate edge-lean reduction.  This one allows to prune
#some arcs of the reachability graph, hence reducing the search
#time."""
    elif o in [ "ml", "memory-limit" ]:
        return """-ml=N, --memory-limit=N

The memory used by Helena is limited to N megabytes.  When this limit
is reached the search stops as soon as possible."""
    elif o in [ "tl", "time-limit" ]:
        return """-tl=N, --time-limit=N

The search time is limited to N seconds.  When this limit is reached
the search stops as soon as possible."""
    elif o in [ "sl", "state-limit" ]:
        return """-sl=N, --state-limit=N

As soon as N states have been processed the search is stopped as soon
as possible."""
    elif o in [ "d", "define" ]:
        return """-d=SYMBOL-NAME, --define=SYMBOL-NAME

Define preprocessor symbol SYMBOL-NAME in the net."""
    elif o in [ "a", "capacity" ]:
        return """-a=N, --capacity=N

The default capacity of places is set to N."""
    elif o in [ "r", "run-time-checks" ]:
        return """-r[={0|1}], --run-time-checks[={0|1}]

Activate/deactivate run time checks such as: division by 0,
expressions out of range, capacity of places exceeded, ...  If this
option is not activated, and such an error occurs during the analysis,
Helena may either crash, either produce wrong results."""
    elif o in [ "L", "link" ]:
        return """-L=OBJECT-FILE, --link=OBJECT-FILE

Add file OBJECT-FILE to the files linked by Helena when compiling the
net.  Please consult user guide for further help on this option."""
    elif o in [ "m", "parameter" ]:
        return """-m=PARAM=VAL, --parameter=PARAM=VAL

This gives value VAL (an integer) to net parameter PARAM."""
    elif o in [ "o", "report-file" ]:
        return """-o=FILE, --report-file=FILE

An XML report file is created by Helena once the search terminated.
It contains some informations such as the result of the search, or
some statistics."""
    elif o in [ "tr", "trace-type" ]:
        return """-tr=TYPE, --trace-type=TYPE

Specify the type of trace (i.e., counter-example) displayed.  TYPE
must take one of these three values:
* FULL - The full trace is displayed.
* EVENTS - Only the sequence of events, the initial and the final
   faulty states are displayed.  Intermediary states are not
   displayed.
* STATE - Only the faulty state reached is displayed.  No information
   on how this state can be reached is therefore available."""
    elif o in [ "wp", "with-papi" ]:
        return """-wp[={0|1}], --with-papi[={0|1}]

Activate/deactivate the use of the PAPI (Performance Application
Programming Interface, see http://icl.utk.edu/papi/) to print
additional statistics at the end of the search."""
#    elif o in [ "hs", "shmem-heap-size" ]:
#        return None
#    elif o in [ "mf", "machine-file" ]:
#        return None
    raise Exception


def printHelpShort():
    print """usage: helena [options] my-net.lna
 
 General options
   -h   --help[=opt]
   -V   --version
   -v   --verbose
   -N   --action={EXPLORE|SIMULATE|BUILD-GRAPH|CHECK-prop}
   -g   --progress={no-compile|no-check|no-report}
   -b   --observer[={0|1}]
   -p   --property-file=FILE
   -md  --model-directory=DIRECTORY
   -wp  --with-papi[={0|1}]
 
 Search and storage options
   -A   --algo={BFS|DFS|DELTA-DDD|RWALK}
   -t   --hash-size=N
   -W   --workers=N
   -R   --random-succs[={0|1}]
   -cs  --candidate-set-size=N
 
 Reduction techniques
   -H   --hash-compaction[={0|1}]
   -P   --partial-order[={0|1}]
   -i   --proviso[={0|1}]
 
 Limit options
   -ml  --memory-limit=N
   -tl  --time-limit=N
   -sl  --state-limit=N
 
 Model options
   -d   --define=SYMBOL-NAME
   -a   --capacity=N
   -r   --run-time-checks[={0|1}]
   -L   --link=OBJECT-FILE
   -m   --parameter=p=N
 
 Output options
   -o   --report-file=FILE-NAME
   -tr  --trace-type={FULL|EVENTS|STATE}"""


def printHelpMD():
    print """# Helena help

This document describes Helena options.

General usage is:
```
helena [options] my-net.lna
```"""
    for title, opts in OPTION_TYPES:
        print
        print "## " + title
        for o in opts:
            print
            print "### " + helpMessage(o)

def printVersion():
    print "helena " + VERSION + " --- " + DATE
        

def exitWithError(err):
    print >> sys.stderr, "error: " + err
    exit(1)

def parseArgument(arg):
    S = re.search
    if S("^-(-)?[a-zA-Z\-]+(=.+)?$", arg):
        l = arg.split("=", 1)
        if len(l) == 2:
            return (l[0], l[1])
        else:
            return (l[0], None)
    else:
        return (None, None)

def parseCheckArgument(val):
    if val.upper() == "CHECK":
        return (True, None)
    else:
        S = re.search
        if not(S("^CHECK-", val.upper())):
            return (False, None)
        else:
            l = val.split("-")
            if len(l) <> 2:
                return (False, None)
            else:
                return (True, l[1])

class Config:        

    def __init__(self):
        self.language = None
        self.verbose = False
        self.version = False
        self.partialOrder = False
        self.proviso = False
        self.dynamicPartialOrder = False
        self.hashCompaction = False
        self.edgeLean = False
        self.withPapi = False
        self.randomSuccs = False
        self.withObserver = True
        self.workers = 1
        self.capacity = 1
        self.memoryLimit = 0
        self.timeLimit = 0
        self.stateLimit = 0
        self.algo = DFS
        self.traceType = FULL
        self.directory = None
        self.symbols = []
        self.action = EXPLORE
        self.runTimeChecks = True
        self.inFile = None
        self.inFileExt = None
        self.prop = None
        self.propFile = None
        self.propType = None
        self.propositions = []
        self.parameters = []
        self.hashSize = 22
        self.bfsQueueBlockSize = 10 ** 4
        self.dfsStackBlockSize = 10 ** 4
        self.rwalkMaxDepth = 10 ** 3
        self.shmemHeapSize = 10 ** 6
        self.candidateSetSize = 10 ** 5
        self.maxTraceLength = 1000

    #  correct inconsistencies in received arguments
    def correct(self):
        if self.action == BUILD_GRAPH:
            self.algo = DELTA_DDD
            self.prop = ""
            self.workers = 1
        elif self.action == CHECK and self.propType == LTL:
            self.algo = DFS
            self.edgeLean = False
            if self.traceType == STATE:
                self.traceType = EVENTS
        elif self.action == SIMULATE:
            self.runTimeChecks = True
        if self.algo == DBFS:
            self.traceType = STATE

        #  hash compaction not available for random walk and delta-ddd
        self.hashCompaction = self.hashCompaction and self.algo not in [
            RWALK, DELTA_DDD ]

        #  partial order reduction not available for random walk,
        #  delta-ddd and distributed algoritms
        self.partialOrder = self.partialOrder and self.algo not in [
            RWALK, DELTA_DDD, DDFS, DBFS ]

        #  same for edge-lean reduction
        self.edgeLean = self.edgeLean and self.algo not in [
            RWALK, DELTA_DDD, DDFS, DBFS ]

        #  random successors selection only available for DFS and DDFS
        self.randomSuccs = self.randomSuccs and self.algo in [
            DFS, DDFS ]

    def openFile(self, name, mode):
        if self.directory is None:
            return open(name, mode)
        else:
            return open(self.directory + os.sep + name, mode)

    def generateConfigFile(self):
        
        f = self.openFile("config.h", "w")
        W = f.write
        
        W("#ifndef LIB_CONFIG\n")
        W("#define LIB_CONFIG\n")
        W("\n")
        
        now = datetime.now()
        model = ""
        self.language = self.inFileExt[1:].lower()
        if self.language == "lna":
            languageLong = "Helena"
        elif self.language == "pnml":
            languageLong = "Petri net"
        elif self.language == "dve":
            languageLong = "DVE"
            (model, _) = os.path.splitext(os.path.basename(self.inFile))
            if model == "":
                model = "model"
        prop = self.prop
        if prop is None:
            prop = ""
        if self.partialOrder and not self.proviso:
            self.proviso = self.propType is not None and \
                           self.propType != DEADLOCK
            
        params = [
            ("ACTION_BUILD_GRAPH", self.action == BUILD_GRAPH),
            ("ACTION_CHECK_LTL", self.action == CHECK and self.propType == LTL),
            ("ACTION_CHECK_SAFETY", self.action == CHECK and
             self.propType in [ STATE, DEADLOCK]),
            ("ACTION_CHECK", self.action == CHECK),
            ("ACTION_EXPLORE", self.action == EXPLORE),
            ("ACTION_SIMULATE", self.action == SIMULATE),
            ("ALGO_BFS", self.algo == BFS),
            ("ALGO_DBFS", self.algo == DBFS),
            ("ALGO_DDFS", self.algo == DDFS),
            ("ALGO_DELTA_DDD", self.algo == DELTA_DDD),
            ("ALGO_DFS", self.algo == DFS),
            ("ALGO_RWALK", self.algo == RWALK),
            ("ALGO_TARJAN", self.algo == TARJAN),
            ("BFS_QUEUE_BLOCK_SIZE", self.bfsQueueBlockSize),
            ("DATE", "\"" + now.strftime("%B, %d, %Y at %H:%M:%S") + "\""),
            ("DELTA_DDD_CAND_SET_SIZE", self.candidateSetSize),
            ("DELTA_DDD_STORAGE", self.algo == DELTA_DDD),
            ("DFS_STACK_BLOCK_SIZE", self.dfsStackBlockSize),
            ("DISTRIBUTED", self.algo in [ DBFS, DDFS ]),
            ("DYNAMIC_POR", self.dynamicPartialOrder),
            ("EDGE_LEAN", self.edgeLean),
            ("FILE_PATH", "\"" + os.path.realpath(self.inFile) + "\""),
            ("GRAPH_FILE", "\"graph.dat\""),
            ("HASH_COMPACTION", self.hashCompaction),
            ("HASH_SIZE_BITS", self.hashSize),
            ("HASH_SIZE_M", pow(2, self.hashSize) - 1),
            ("HASH_SIZE", pow(2, self.hashSize)),
            ("HASH_STORAGE", self.algo not in [ DELTA_DDD, RWALK ]),
            ("LANGUAGE", "\"" + languageLong + "\""),
            ("LANGUAGE_DVE", self.language == "dve"),
            ("LANGUAGE_LNA", self.language == "lna"),
            ("LANGUAGE_PNML", self.language == "pnml"),
            ("MAX_MEMORY", self.memoryLimit),
            ("MAX_STATE", self.stateLimit),
            ("MAX_TIME", self.timeLimit),
            ("MAX_TRACE_LENGTH", self.maxTraceLength),
            ("MEMORY_LIMITED", self.memoryLimit != 0),
            ("MODEL_HAS_GRAPH_ROUTINES", self.language == "lna"),
            ("MODEL_NAME", "\"" + model + "\""),
            ("NO_WORKERS", self.workers),
            ("PARALLEL", self.workers > 1),
            ("POR", self.partialOrder),
            ("PROPERTY", "\"" + prop + "\""),
            ("PROVISO", self.proviso),
            ("RANDOM_SUCCS", self.randomSuccs),
            ("REPORT_FILE", "\"report.xml\""),
            ("RG_REPORT_FILE", "\"rg-report.xml\""),
            ("RWALK_MAX_DEPTH", self.rwalkMaxDepth),
            ("SHMEM_HEAP_SIZE", self.shmemHeapSize),
            ("STATE_LIMITED", self.stateLimit != 0),
            ("TIME_LIMITED", self.timeLimit != 0),
            ("TRACE_EVENTS", self.traceType == EVENTS),
            ("TRACE_FULL", self.traceType == FULL),
            ("TRACE_STATE", self.traceType == STATE),
            ("WITH_OBSERVER", self.withObserver),
            ("WITH_PAPI", self.withPapi)
        ]
        
        for (p, v) in params:
            if type(v) == bool:
                W("#define CFG_" + p + " " + ("1" if v else "0") + "\n")
            elif type(v) in [ float, int ]:
                W("#define CFG_" + p + " " + str(v) + "\n")
            elif type(v) == str:
                W("#define CFG_" + p + " " + v + "\n")
            else:
                raise Exception
        W("\n#endif  /*  LIB_CONFIG  */\n")
        f.close()

    def handleNumericalOption(self, attr, val):
        try:
            if val is None:
                return False
            i = int(val)
            setattr(self, attr, i)
            return True
        except ValueError:
            return False

    def handleStringOption(self, attr, val):
        if val is None:
            return False
        else:
            if attr is not None:
                setattr(self, attr, val)
            return True

    def handleEnumOption(self, attr, val, okVal):
        if val is None:
            return False
        if val.upper() in okVal:
            if attr is not None:
                setattr(self, attr, val.upper())
            return True
        else:
            return False
        
    def parseFromCommandLine(self):
        for arg in sys.argv[1 : len(sys.argv) - 2]:
            recognized = True
            (opt, val) = parseArgument(arg)

            #  options with no value
            if   (opt, val) in [ ("-v", None), ("--verbose", None) ]:
                self.verbose = True
            elif (opt, val) in [ ("-V", None), ("--version", None) ]:
                printVersion()
                exit(0)
            elif (opt, val) in [ ("-h", None), ("--help", None) ]:
                printHelpShort()
                exit(0)
                
            #  boolean options
            elif opt in [ "-b", "--observer" ]:
                self.withObserver = (val is None) or val == "1"
            elif opt in [ "-P", "--partial-order" ]:
                self.partialOrder = (val is None) or val == "1"
            elif opt in [ "-i", "--proviso" ]:
                self.proviso = (val is None) or val == "1"
            elif opt in [ "-D", "--dynamic-partial-order" ]:
                self.dynamicPartialOrder = (val is None) or val == "1"
            #elif opt in [ "-E", "--edge-lean" ]:
            #    self.edgeLean = (val is None) or val == "1"
            elif opt in [ "-r", "--run-time-checks" ]:
                self.runTimeChecks = (val is None) or val == "1"
            elif opt in [ "-H", "--hash-compaction" ]:
                self.hashCompaction = (val is None) or val == "1"
            elif opt in [ "-R", "--random-succs" ]:
                self.randomSuccs = (val is None) or val == "1"
            elif opt in [ "-wp", "--with-papi" ]:
                self.withPapi = (val is None) or val == "1"

            #  numerical options
            elif opt in [ "-W", "--workers" ]:
                recognized = self.handleNumericalOption("workers", val)
                if self.workers == 0:
                    recognized = False
            elif opt in [ "-a", "--capacity" ]:
                recognized = self.handleNumericalOption("capacity", val)
            elif opt in [ "-cs", "--candidate-set-size" ]:
                recognized = self.handleNumericalOption("candidateSetSize",
                                                        val)
            #elif opt in [ "-hs", "--shmem-heap-size" ]:
            #    recognized = self.handleNumericalOption("shmemHeapSize", val)
            elif opt in [ "-t", "--hash-size" ]:
                recognized = self.handleNumericalOption("hashSize", val)
                if self.hashSize > 32:
                    self.hashSize = 32
            elif opt in [ "-ml", "--memory-limit" ]:
                recognized = self.handleNumericalOption("memoryLimit", val)
            elif opt in [ "-tl", "--time-limit" ]:
                recognized = self.handleNumericalOption("timeLimit", val)
            elif opt in [ "-sl", "--state-limit" ]:
                recognized = self.handleNumericalOption("stateLimit", val)

            #  string options
            elif opt in [ "-h", "--help" ]:
                if val == "FULL":
                    printHelpMD()
                else:
                    try:
                        msg = helpMessage(val)
                        if msg is None:
                            msg = "No help for option " + val + ".  Sorry."
                        print msg
                    except:
                        exitWithError(val + " is not a valid option")
                exit(0)
            elif opt in [ "-d", "--define" ]:
                recognized = self.handleStringOption(None, val)
                if recognized:
                    self.symbols.append(val)
            elif opt in [ "-L", "--link" ]:
                recognized = self.handleStringOption("link", val)
            elif opt in [ "-p", "--property-file" ]:
                recognized = self.handleStringOption("propertyFile", val)
            elif opt in [ "-o", "--report-file" ]:
                recognized = self.handleStringOption("reportFile", val)
            elif opt in [ "-m", "--parameter" ]:
                recognized = self.handleStringOption(None, val)
                if recognized:
                    l = val.split("=")
                    recognized = len(l) == 2
                    if recognized:
                        self.parameters.append(val)

            #  enum options
            elif opt in [ "-A", "--algo" ]:
                recognized = self.handleEnumOption \
                             ("algo", val, [BFS, DBFS, DFS, DDFS, \
                                            DELTA_DDD, RWALK, TARJAN])
            elif opt in [ "-tr", "--trace-type" ]:
                recognized = self.handleEnumOption \
                             ("traceType", val, [FULL, EVENTS, STATE])
            elif opt in [ "-N", "--action" ]:
                self.prop = None
                recognized = self.handleEnumOption \
                             ("action", val, [SIMULATE, EXPLORE, BUILD_GRAPH])
                if not recognized:
                    (recognized, p) = parseCheckArgument(val)
                    if recognized:
                        self.action = CHECK
                        self.prop = p

            #  option that are handled directly by the helena script
            elif opt in [ "-md", "--model-directory" ]:
                recognized = True
            #elif opt in [ "-mf", "--machine-file" ]:
            #    recognized = True
            elif opt in [ "-g", "--progress" ]:
                recognized = True

            #  does not match any option
            else:
                recognized = False
                val = None

            if not recognized:
                if val is not None:
                    err = "invalid value for option " + opt + ": " + val
                else:
                    err = "invalid option: " + arg
                exitWithError(err)
        if len(sys.argv) >= 2:
            self.inFile = sys.argv[len(sys.argv) - 2]
            (f, self.inFileExt) = os.path.splitext(self.inFile)
            self.language = self.inFileExt[1:].lower()
            if self.propFile is None:
                self.propFile = f + ".prop" + self.inFileExt
        if len(sys.argv) >= 3:
            self.directory = sys.argv[len(sys.argv) - 1]

    def generatePropertyCode(self):
        f = self.openFile("prop.h", "w")
        f.write("#define state_check_property(now, en) FALSE\n")
        f.close()
        self.openFile("prop.c", "w").close()
        if self.action == CHECK and self.language == "dve":
            self.propType = LTL
        elif self.action == CHECK and self.language == "lna":
            if self.prop is None:
                exitWithError("property name excepted for action check")
            cmd = "helena-generate-property "
            cmd = cmd + " " + self.prop + " " + self.propFile
            if self.directory is None:
                cmd = cmd + " ."
            else:
                cmd = cmd + " " + self.directory
            if os.system(cmd):
                exit(1)
            else:
                f = self.openFile("PROPERTY", "r")
                lines = f.readlines()
                f.close()
                i = 0
                for prop in lines:
                    p = prop.replace("\n", "")
                    if i == 0:
                        self.propType = p
                    else:
                        self.propositions.append(prop)
                    i = i + 1
                path = "PROPERTY"
                if self.directory is not None:
                    path = self.directory + os.sep + path
                os.remove(path)

    def outputModelOptions(self):
        opts = []
        opts.append("--capacity=" + str(self.capacity))
        if self.runTimeChecks:
            opts.append("--run-time-checks=1")
        else:
            opts.append("--run-time-checks=0")
        for prop in self.propositions:
            opts.append("--proposition=" + prop)
        for sym in self.symbols:
            opts.append("--define=" + sym)
        for param in self.parameters:
            opts.append("--parameter=" + param)
        f = open("model-options", "w")
        for o in opts:
            f.write(" " + o)
        f.close()

if __name__ == "__main__":
    C = Config()
    C.parseFromCommandLine()
    C.generatePropertyCode()
    C.correct()
    C.generateConfigFile()
    C.outputModelOptions()
    exit(0)
