# Source code for pypdevs.tracer

    # Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at
    # McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #    http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.

    class Tracers(object):
        """
        Interface for all tracers
        """
        def __init__(self):
            """
            Constructor
            """
            self.tracers = []
            self.tracers_init = []
            self.uid = 0

        def registerTracer(self, tracer, server, recover):
            """
            Register a tracer, so that it will also receive all transitions.

            :param tracer: tuple of the form (file, classname, [args])
            :param server: the server object to be able to make remote calls
            :param recover: whether or not this is a recovered registration (used during checkpointing)
            """
            loc = {}
            try:
                exec("from pypdevs.tracers.%s import %s" % (tracer[0], tracer[1]), {}, loc)
            except:
                exec("from %s import %s" % (tracer[0], tracer[1]), {}, loc)
            self.tracers.append(loc[tracer[1]](self.uid, server, *tracer[2]))
            # self.tracers.append(eval("%s(%i, server, *%s)" % (tracer[1],
            #                                                   self.uid,
            #                                                   tracer[2])))
            self.tracers_init.append(tracer)
            self.uid += 1
            self.tracers[-1].startTracer(recover)

        def hasTracers(self):
            """
            Checks whether or not there are any registered tracers

            :returns: bool
            """
            return len(self.tracers) > 0

        def getByID(self, uid):
            """
            Gets a tracer by its UID

            :param uid: the UID of the tracer to return
            :returns: tracer
            """
            return self.tracers[uid]

        def stopTracers(self):
            """
            Stop all registered tracers
            """
            for tracer in self.tracers:
                tracer.stopTracer()

        def tracesUser(self, time, aDEVS, variable, value):
            """
            Perform all tracing actions for a user imposed modification. This is NOT supported by default DEVS, so we don't require tracers to handle this either.

            :param time: the time at which the modification happend; this will be the termination time of the previous simulation run and **not** the time at which the timeAdvance was recomputed!
            :param aDEVS: the atomic DEVS model that was altered
            :param variable: the variable that was altered (as a string)
            :param value: the new value of the variable
            """
            for tracer in self.tracers:
                try:
                    tracer.traceUser(time, aDEVS, variable, value)
                except AttributeError:
                    # Some tracers choose to ignore this event
                    pass

        def tracesInit(self, aDEVS, t):
            """
            Perform all tracing actions for an initialisation

            :param aDEVS: the model that was initialised
            :param t: the time at which the initialisation should be logged
            """
            if aDEVS.full_name is None:
                return
            for tracer in self.tracers:
                tracer.traceInit(aDEVS, t)

        def tracesInternal(self, aDEVS):
            """
            Perform all tracing actions for an internal transition

            :param aDEVS: the model that transitioned
            """
            if aDEVS.full_name is None:
                return
            for tracer in self.tracers:
                tracer.traceInternal(aDEVS)

        def tracesExternal(self, aDEVS):
            """
            Perform all tracing actions for an external transition

            :param aDEVS: the model that transitioned
            """
            if aDEVS.full_name is None:
                return
            for tracer in self.tracers:
                tracer.traceExternal(aDEVS)

        def tracesConfluent(self, aDEVS):
            """
            Perform all tracing actions for a confluent transition

            :param aDEVS: the model that transitioned
            """
            if aDEVS.full_name is None:
                return
            for tracer in self.tracers:
                tracer.traceConfluent(aDEVS)