/*
 * Created on 18.08.2004
 */

package de.renew.engine.common;

import org.apache.log4j.Logger;

import de.renew.engine.events.SimulationEvent;
import de.renew.engine.events.TraceEvent;
import de.renew.engine.thread.SimulationThreadPool;
import de.renew.net.NetInstance;
import de.renew.net.PlaceInstance;
import de.renew.net.TransitionInstance;
import de.renew.simulatorontology.simulation.StepIdentifier;


/**
 * Logs simulation events to loggers named according to the net and
 * the net element they are related to.
 *
 * @author Sven Offermann
 */
public class SimulatorEventLogger {

    /**
     * Constructor for SimulatorEventLogger
     */
    public SimulatorEventLogger() {}

    /**
     * The prefix used to create names for the loggers
     * to log the simulation output. For example, a logger
     * for a net named "untitled" will write the trace messages
     * to the logger named SIM_LOG_PREFIX + ".untitled".
     **/
    public static final String SIM_LOG_PREFIX = "simulation";


    /**
     * static method for debug logging messages produced during the
     * simulation of petri nets
     *
     * @param trace a SimulatorTrace object
     */
    public static void log(SimulatorEvent trace) {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        getLogger(trace).debug(trace);
    }

    /**
     * static method for debug logging messages produced during the
     * simulation of petri nets
     *
     * @param logObject a SimulationEvent object
     */
    public static void log(SimulationEvent logObject) {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        try {
            log(new SimulatorEvent(logObject));
        } catch (Exception e) {
            // cant create simulator event. 
        }
    }

    /**
     * static method for debug logging messages produced during the
     * simulation of petri nets
     *
     * @param stepIdentifier the current step identifier
     * @param logObject      a SimulationEvent object
     */
    public static void log(StepIdentifier stepIdentifier, SimulationEvent logObject) {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        log(new SimulatorEvent(stepIdentifier, logObject));
    }

    /**
     * static method for debug logging messages produced during the
     * simulation of petri nets
     *
     * @param stepIdentifier the current step identifier
     * @param logObject      a SimulationEvent object
     * @param pInstance      the PlaceInstance the event is related to
     */
    public static void log(
        StepIdentifier stepIdentifier, SimulationEvent logObject, PlaceInstance pInstance)
    {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        log(new SimulatorEvent(stepIdentifier, logObject, pInstance));
    }

    /**
     * static method for debug logging messages produced during the
     * simulation of petri nets
     *
     * @param stepIdentifier the current step identifier
     * @param logObject      a SimulationEvent object
     * @param tInstance      the TransitionInstance the event is related to
     */
    public static void log(
        StepIdentifier stepIdentifier, SimulationEvent logObject, TransitionInstance tInstance)
    {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        log(new SimulatorEvent(stepIdentifier, logObject, tInstance));
    }

    /**
     * static method for debug logging messages produced during the
     * simulation of petri nets
     *
     * @param stepIdentifier the current step identifier
     * @param logObject      a SimulationEvent object
     * @param nInstance      the NetInstance the event is related to
     */
    public static void log(
        StepIdentifier stepIdentifier, SimulationEvent logObject, NetInstance nInstance)
    {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        log(new SimulatorEvent(stepIdentifier, logObject, nInstance));
    }

    /**
     * static method for debug logging messages produced during the
     * simulation of petri nets
     *
     * @param logObject a String object
     */
    public static void log(String logObject) {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        try {
            log(new SimulatorEvent(new TraceEvent(logObject)));
        } catch (Exception e) {
            // cant create simulator event. 
        }
    }

    /**
     * static method for debug logging messages produced during the
     * simulation of petri nets
     *
     * @param stepIdentifier the current step identifier
     * @param logObject      a String object
     */
    public static void log(StepIdentifier stepIdentifier, String logObject) {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        log(new SimulatorEvent(stepIdentifier, new TraceEvent(logObject)));
    }

    /**
     * static method for debug logging messages produced during the
     * simulation of petri nets
     *
     * @param stepIdentifier the current step identifier
     * @param logObject      a String object
     * @param pInstance      the PlaceInstance the event is related to
     */
    public static void log(
        StepIdentifier stepIdentifier, String logObject, PlaceInstance pInstance)
    {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        log(new SimulatorEvent(stepIdentifier, new TraceEvent(logObject), pInstance));
    }

    /**
     * static method for debug logging messages produced during the
     * simulation of petri nets
     *
     * @param stepIdentifier the current step identifier
     * @param logObject      a String object
     * @param tInstance      the TransitionInstance the event is related to
     */
    public static void log(
        StepIdentifier stepIdentifier, String logObject, TransitionInstance tInstance)
    {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        log(new SimulatorEvent(stepIdentifier, new TraceEvent(logObject), tInstance));
    }

    /**
     * static method for debug logging messages produced during the
     * simulation of petri nets
     *
     * @param stepIdentifier the current step identifier
     * @param logObject      a String object
     * @param nInstance      the NetInstance the event is related to
     */
    public static void log(StepIdentifier stepIdentifier, String logObject, NetInstance nInstance) {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        log(new SimulatorEvent(stepIdentifier, new TraceEvent(logObject), nInstance));
    }


    /**
     * gets the logger for the SimulatorTrace object
     *
     * @param trace a SimulatorTraceObject
     * @return the Logger for the SimulatorTrace object
     */
    private static Logger getLogger(SimulatorEvent trace) {
        // build logger Name
        StringBuilder loggerName = new StringBuilder(SIM_LOG_PREFIX);
        if (trace.getNetInstance() != null) {
            loggerName.append(".");
            loggerName.append(trace.getNetInstance().getNet().getName());

            if (trace.getNetElementInstance() != null) {
                Object element = trace.getNetElementInstance();
                if (element instanceof TransitionInstance transitionInstance) {
                    loggerName.append(".");
                    loggerName.append(transitionInstance.getTransition().toString());
                } else if (element instanceof PlaceInstance placeInstance) {
                    loggerName.append(".");
                    loggerName.append(placeInstance.getPlace().toString());
                }
            }
        }

        return Logger.getLogger(loggerName.toString());
    }
}