# Source code for pypdevsbbl.tracers.ProfileTracer

    #  Copyright 2020 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.

    """Makes up a profile of a simulation run.

    This file contains the tracer that can analyze the performance and throughput of
    the messages traveling through a model during simulation.
    """

    from pypdevsbbl.tracers import BaseTracer

    class ProfileTracer(BaseTracer):
        """Traces all the coming and going of messages and transitions.

        The output file is in CSV-format and contains two tables, separated with a
        newline. For all DEVS blocks that underwent transitions, a summary of the
        counts of the internal, external and confluent ones. For all connections, an
        overview will be presented of the amount of messages that passed over these
        connections. Finally, a total for all values will be given as well.

        Args:
            uid:                A unique identifier for distributed simulation.
                                Will be set automatically.
            server:             The server that runs the distributed simulation.
                                Will be set automatically.
            filename (str):     The name of the file to write the results to. When
                                ``None``, the console output will be used instead.
        """
        def __init__(self, uid, server, filename):
            super().__init__(uid, server, filename)
            self.connections = {}
            self.internal = {}
            self.external = {}
            self.confluent = {}

        def stopTracer(self):
            full = set(self.internal.keys()) | set(self.external.keys()) | set(self.confluent.keys())
            self.trace("Name,Internal,External,Confluent\n")
            for i in full:
                self.trace(i, self.internal.get(i, 0), self.external.get(i, 0), self.confluent.get(i, 0), sep=',', end='\n')
            self.trace("TOTAL", sum(self.internal.values()), sum(self.external.values()),
                       sum(self.confluent.values()), sep=',', end='\n')
            self.trace("\nOutport,Inport,Count\n")
            for pair in self.connections:
                self.trace(*pair, self.connections[pair], sep=',', end='\n')
            self.trace("TOTAL", "", sum(self.connections.values()), sep=',', end='\n')
            super().stopTracer()

        def traceInternal(self, aDEVS):
            name = aDEVS.getModelFullName()
            self.internal.setdefault(name, 0)
            self.internal[name] += 1

            output = aDEVS.my_output
            for port in output:
                for oport in port.outline:
                    if oport.type() == 'INPORT':
                        name = (port.getPortFullName(), oport.getPortFullName())
                        self.connections.setdefault(name, 0)
                        self.connections[name] += 1

        def traceExternal(self, aDEVS):
            name = aDEVS.getModelFullName()
            self.external.setdefault(name, 0)
            self.external[name] += 1

        def traceConfluent(self, aDEVS):
            name = aDEVS.getModelFullName()
            self.confluent.setdefault(name, 0)
            self.confluent[name] += 1