/****************************************************************************/
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
// Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
// This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v2.0
// which accompanies this distribution, and is available at
// http://www.eclipse.org/legal/epl-v20.html
// SPDX-License-Identifier: EPL-2.0
/****************************************************************************/
/// @file    MSVehicle.h
/// @author  Christian Roessel
/// @author  Jakob Erdmann
/// @author  Bjoern Hendriks
/// @author  Daniel Krajzewicz
/// @author  Thimor Bohn
/// @author  Friedemann Wesner
/// @author  Clemens Honomichl
/// @author  Michael Behrisch
/// @author  Axel Wegener
/// @author  Leonhard Luecken
/// @date    Mon, 12 Mar 2001
///
// Representation of a vehicle in the micro simulation
/****************************************************************************/
#ifndef MSVehicle_h
#define MSVehicle_h


// ===========================================================================
// included modules
// ===========================================================================
#include <config.h>

#include <list>
#include <deque>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <memory>
#include "MSGlobals.h"
#include "MSVehicleType.h"
#include "MSBaseVehicle.h"
#include "MSLink.h"
#include "MSLane.h"
#include "MSNet.h"

#define INVALID_SPEED 299792458 + 1 // nothing can go faster than the speed of light! Refs. #2577

// ===========================================================================
// class declarations
// ===========================================================================
class SUMOSAXAttributes;
class MSMoveReminder;
class MSLaneChanger;
class MSVehicleTransfer;
class MSAbstractLaneChangeModel;
class MSStoppingPlace;
class MSChargingStation;
class MSParkingArea;
class MSPerson;
class MSDevice;
class MSEdgeWeightsStorage;
class OutputDevice;
class Position;
class MSContainer;
class MSJunction;
class MSLeaderInfo;
class MSDevice_DriverState;
class MSSimpleDriverState;

// ===========================================================================
// class definitions
// ===========================================================================
/**
 * @class MSVehicle
 * @brief Representation of a vehicle in the micro simulation
 */
class MSVehicle : public MSBaseVehicle {
public:

    /// the lane changer sets myLastLaneChangeOffset
    friend class MSLaneChanger;
    friend class MSLaneChangerSublane;

    /** @class State
     * @brief Container that holds the vehicles driving state (position+speed).
     */
    class State {
        /// @brief vehicle sets states directly
        friend class MSVehicle;
        friend class MSLaneChanger;
        friend class MSLaneChangerSublane;

    public:
        /// Constructor.
        State(double pos, double speed, double posLat, double backPos);

        /// Copy constructor.
        State(const State& state);

        /// Assignment operator.
        State& operator=(const State& state);

        /// Operator !=
        bool operator!=(const State& state);

        /// Position of this state.
        double pos() const {
            return myPos;
        }

        /// Speed of this state
        double speed() const {
            return mySpeed;
        };

        /// Lateral Position of this state (m relative to the centerline of the lane).
        double posLat() const {
            return myPosLat;
        }

        /// back Position of this state
        double backPos() const {
            return myBackPos;
        }

        /// previous Speed of this state
        double lastCoveredDist() const {
            return myLastCoveredDist;
        }


    private:
        /// the stored position
        double myPos;

        /// the stored speed (should be >=0 at any time)
        double mySpeed;

        /// the stored lateral position
        double myPosLat;

        /// @brief the stored back position
        // if the vehicle occupies multiple lanes, this is the position relative
        // to the lane occupied by its back
        double myBackPos;

        /// the speed at the begin of the previous time step
        double myPreviousSpeed;

        /// the distance covered in the last timestep
        /// NOTE: In case of ballistic positional update, this is not necessarily given by
        ///       myPos - SPEED2DIST(mySpeed + myPreviousSpeed)/2,
        /// because a stop may have occurred within the last step.
        double myLastCoveredDist;

    };


    /** @class WaitingTimeCollector
     * @brief Stores the waiting intervals over the previous seconds (memory is to be specified in ms.).
     */
    class WaitingTimeCollector {
        friend class MSVehicle;

        typedef std::list<std::pair<SUMOTime, SUMOTime> > waitingIntervalList;

    public:
        /// Constructor.
        WaitingTimeCollector(SUMOTime memory = MSGlobals::gWaitingTimeMemory);

        /// Copy constructor.
        WaitingTimeCollector(const WaitingTimeCollector& wt);

        /// Assignment operator.
        WaitingTimeCollector& operator=(const WaitingTimeCollector& wt);

        /// Operator !=
        bool operator!=(const WaitingTimeCollector& wt) const;

        /// Assignment operator (in place!)
        WaitingTimeCollector& operator=(SUMOTime t);

        // return the waiting time within the last memory millisecs
        SUMOTime cumulatedWaitingTime(SUMOTime memory = -1) const;

        // process time passing for dt millisecs
        void passTime(SUMOTime dt, bool waiting);

        // maximal memory time stored
        SUMOTime getMemorySize() const {
            return myMemorySize;
        }

        // maximal memory time stored
        const waitingIntervalList& getWaitingIntervals() const {
            return myWaitingIntervals;
        }

    private:
        /// the maximal memory to store
        SUMOTime myMemorySize;

        /// the stored waiting intervals within the last memory milliseconds
        /// If the current (ongoing) waiting interval has begun at time t - dt (where t is the current time)
        /// then waitingIntervalList[0]->first = 0., waitingIntervalList[0]->second = dt
        waitingIntervalList myWaitingIntervals;

        /// append an amount of dt millisecs to the stored waiting times
        void appendWaitingTime(SUMOTime dt);
    };


    /** @enum ChangeRequest
     * @brief Requests set via TraCI
     */
    enum ChangeRequest {
        /// @brief vehicle doesn't want to change
        REQUEST_NONE,
        /// @brief vehicle want's to change to left lane
        REQUEST_LEFT,
        /// @brief vehicle want's to change to right lane
        REQUEST_RIGHT,
        /// @brief vehicle want's to keep the current lane
        REQUEST_HOLD
    };

    /** @brief Constructor
     * @param[in] pars The vehicle description
     * @param[in] route The vehicle's route
     * @param[in] type The vehicle's type
     * @param[in] speedFactor The factor for driven lane's speed limits
     * @exception ProcessError If a value is wrong
     */
    MSVehicle(SUMOVehicleParameter* pars, const MSRoute* route,
              MSVehicleType* type, const double speedFactor);

    /// @brief Destructor.
    virtual ~MSVehicle();


    /// @name insertion/removal
    //@{

    /** @brief Called when the vehicle is removed from the network.
     *
     * Moves along work reminders and
     *  informs all devices about quitting. Calls "leaveLane" then.
     *
     * @param[in] reason why the vehicle leaves (reached its destination, parking, teleport)
     */
    void onRemovalFromNet(const MSMoveReminder::Notification reason);
    //@}



    /// @name interaction with the route
    //@{

    /** @brief Returns whether this vehicle has already arived
     * (reached the arrivalPosition on its final edge)
     */
    bool hasArrived() const;

    /** @brief Replaces the current route by the given one
     *
     * It is possible that the new route is not accepted, if it does not
     *  contain the vehicle's current edge.
     *
     * @param[in] route The new route to pass
     * @param[in] info Information regarding the replacement
     * @param[in] removeStops Whether stops should be removed if they do not fit onto the new route
     * @return Whether the new route was accepted
     */
    bool replaceRoute(const MSRoute* route, const std::string& info, bool onInit = false, int offset = 0, bool addStops = true, bool removeStops = true);

    /** @brief Returns the vehicle's internal edge travel times/efforts container
     *
     * If the vehicle does not have such a container, it is built.
     * @return The vehicle's knowledge about edge weights
     */
    const MSEdgeWeightsStorage& getWeightsStorage() const;
    MSEdgeWeightsStorage& getWeightsStorage();
    //@}


    /// @name Interaction with move reminders
    //@{

    /** @brief Processes active move reminder
     *
     * This method goes through all active move reminder, both those for the current
     *  lane, stored in "myMoveReminders" and those of prior lanes stored in
     *  "myOldLaneMoveReminders" calling "MSMoveReminder::notifyMove".
     *
     * When processing move reminder from "myOldLaneMoveReminders",
     *  the offsets (prior lane lengths) are used, which are stored in
     *  "myOldLaneMoveReminderOffsets".
     *
     * Each move reminder which is no longer active is removed from the container.
     *
     * @param[in] oldPos The position the vehicle had before it has moved
     * @param[in] newPos The position the vehicle has after it has moved
     * @param[in] newSpeed The vehicle's speed within this move
     * @see MSMoveReminder
     */
    void workOnMoveReminders(double oldPos, double newPos, double newSpeed);
    //@}


    /** @brief Returns whether the vehicle is supposed to take action in the current simulation step
     *         Updates myActionStep and myLastActionTime in case that the current simstep is an action step
     *
     *  @param[in] t
     */
    bool checkActionStep(const SUMOTime t);

    /** @brief Resets the action offset for the vehicle
     *
     *  @param[in] timeUntilNextAction time interval from now for the next action, defaults to 0, which
     *             implies an immediate action point in the current step.
     */
    void resetActionOffset(const SUMOTime timeUntilNextAction = 0);


    /** @brief Process an updated action step length value (only affects the vehicle's *action offset*,
     *         The actionStepLength is stored in the (singular) vtype)
     *
     *  @param[in] oldActionStepLength The action step length previous to the update
     *  @param[in] actionStepLength The new action step length (stored in the vehicle's vtype).
     *  @note      The current action step length is updated. This implies an immediate action
     *             point, if the new step length is smaller than the length of the currently running
     *             action interval (the difference between now and the last action time).
     */
    void updateActionOffset(const SUMOTime oldActionStepLength, const SUMOTime newActionStepLength);


    /** @brief Compute safe velocities for the upcoming lanes based on positions and
     * speeds from the last time step. Also registers
     * ApproachingVehicleInformation for all links
     *
     * This method goes through the best continuation lanes of the current lane and
     * computes the safe velocities for passing/stopping at the next link as a DriveProcessItem
     *
     * Afterwards it checks if any DriveProcessItem should be discarded to avoid
     * blocking a junction (checkRewindLinkLanes).
     *
     * Finally the ApproachingVehicleInformation is registered for all links that
     * shall be passed
     *
     * @param[in] t The current timeStep
     * @param[in] ahead The leaders (may be 0)
     * @param[in] lengthsInFront Sum of vehicle lengths in front of the vehicle
     */
    void planMove(const SUMOTime t, const MSLeaderInfo& ahead, const double lengthsInFront);

    /** @brief Register junction approaches for all link items in the current
     * plan */
    void setApproachingForAllLinks(const SUMOTime t);


    /** @brief Executes planned vehicle movements with regards to right-of-way
     *
     * This method goes through all DriveProcessItems in myLFLinkLanes in order
     * to find a speed that is safe for all upcoming links.
     *
     * Using this speed the position is updated and the vehicle is moved to the
     * next lane (myLane is updated) if the end of the current lane is reached (this may happen
     * multiple times in this method)
     *
     * The vehicle also sets the lanes it is in-lapping into and informs them about it.
     * @return Whether the vehicle has moved to the next edge
     */
    bool executeMove();

    /** @brief calculates the distance covered in the next integration step given
     *         an acceleration and assuming the current velocity. (gives different
     *         results for different integration methods, e.g., euler vs. ballistic)
     *  @param[in] accel the assumed acceleration
     *  @return distance covered in next integration step
     */
    double getDeltaPos(const double accel) const;


    /// @name state setter/getter
    //@{

    /** @brief Get the vehicle's position along the lane
     * @return The position of the vehicle (in m from the lane's begin)
     */
    double getPositionOnLane() const {
        return myState.myPos;
    }

    /** @brief Get the distance the vehicle covered in the previous timestep
     * @return The distance covered in the last timestep (in m)
     */
    double getLastStepDist() const {
        return myState.lastCoveredDist();
    }

    /** @brief Get the vehicle's front position relative to the given lane
     * @return The front position of the vehicle (in m from the given lane's begin)
     */
    double getPositionOnLane(const MSLane* lane) const;

    /** @brief Get the vehicle's position relative to the given lane
     * @return The back position of the vehicle (in m from the given lane's begin)
     * @note It is assumed that this function is only called for a vehicle that has
     *       a relation to the lane which makes it 'directly' relevant for
     *       car-following behavior on that lane, i.e., either it occupies part of the
     *       lanes surface (regular or partial vehicle for the lane), or (for the sublane
     *       model) it issued a maneuver reservation for a lane change.
     */
    double getBackPositionOnLane(const MSLane* lane) const;

    /** @brief Get the vehicle's position relative to its current lane
     * @return The back position of the vehicle (in m from the current lane's begin)
     */
    double getBackPositionOnLane() const {
        return getBackPositionOnLane(myLane);
    }

    /** @brief Get the vehicle's lateral position on the lane
     * @return The lateral position of the vehicle (in m relative to the
     * centerline of the lane)
     */
    double getLateralPositionOnLane() const {
        return myState.myPosLat;
    }

    void setLateralPositionOnLane(double posLat) {
        myState.myPosLat = posLat;
    }

    /** @brief Get the vehicle's lateral position on the lane:
     * @return The lateral position of the vehicle (in m distance between right
     * side of vehicle and ride side of the lane it is on
     */
    double getRightSideOnLane() const;

    /** @brief Get the minimal lateral distance required to move fully onto the lane at given offset
     * @return The lateral distance to be covered to move the vehicle fully onto the lane (in m)
     */
    double lateralDistanceToLane(const int offset) const;

    /// @brief return the amount by which the vehicle extends laterally outside it's primary lane
    double getLateralOverlap() const;
    double getLateralOverlap(double posLat) const;

    /** @brief Get the vehicle's lateral position on the edge of the given lane
     * (or its current edge if lane == 0)
     * @return The lateral position of the vehicle (in m distance between right
     * side of vehicle and ride side of edge
     */
    double getRightSideOnEdge(const MSLane* lane = 0) const;

    /** @brief Get the vehicle's lateral position on the edge of the given lane
     * (or its current edge if lane == 0)
     * @return The lateral position of the vehicle (in m distance between center
     * of vehicle and ride side of edge
     */
    double getCenterOnEdge(const MSLane* lane = 0) const;

    /** @brief Get the offset that that must be added to interpret
     * myState.myPosLat for the given lane
     *  @note This means that latOffset + myPosLat should give the relative shift of the vehicle's center
     *        wrt the centerline of the given lane.
     */
    double getLatOffset(const MSLane* lane) const;

    /** @brief Returns the vehicle's current speed
     * @return The vehicle's speed
     */
    double getSpeed() const {
        return myState.mySpeed;
    }


    /** @brief Returns the vehicle's speed before the previous time step
     * @return The vehicle's speed before the previous time step
     */
    double getPreviousSpeed() const {
        return myState.myPreviousSpeed;
    }


    /** @brief Returns the vehicle's acceleration in m/s
     *         (this is computed as the last step's mean acceleration in case that a stop occurs within the middle of the time-step)
     * @return The acceleration
     */
    double getAcceleration() const {
        return myAcceleration;
    }

    /// @brief get apparent deceleration based on vType parameters and current acceleration
    double getCurrentApparentDecel() const;

    /** @brief Returns the vehicle's action step length in millisecs,
     *         i.e. the interval between two action points.
     * @return The current action step length in ms.
     */
    SUMOTime getActionStepLength() const {
        return myType->getActionStepLength();
    }

    /** @brief Returns the vehicle's action step length in secs,
     *         i.e. the interval between two action points.
     * @return The current action step length in s.
     */
    double getActionStepLengthSecs() const {
        return myType->getActionStepLengthSecs();
    }


    /** @brief Returns the time of the vehicle's last action point.
     * @return The time of the last action point
     */
    SUMOTime getLastActionTime() const {
        return myLastActionTime;
    }

    //@}



    /// @name Other getter methods
    //@{

    /** @brief Returns the slope of the road at vehicle's position
     * @return The slope
     */
    double getSlope() const;


    /** @brief Return current position (x/y, cartesian)
     *
     * If the vehicle's myLane is 0, Position::INVALID.
     * @param[in] offset optional offset in longitudinal direction
     * @return The current position (in cartesian coordinates)
     * @see myLane
     */
    Position getPosition(const double offset = 0) const;


    /** @brief Return the (x,y)-position, which the vehicle would reach
     *         if it continued along its best continuation lanes from the current
     *         for a distance of offset m.
     * @param offset
     * @return (x,y)-Position
     * @see getPosition()
     */
    Position getPositionAlongBestLanes(double offset) const;


    /** @brief Returns the lane the vehicle is on
     * @return The vehicle's current lane
     */
    MSLane* getLane() const {
        return myLane;
    }


    /** @brief Returns the maximal speed for the vehicle on its current lane (including speed factor and deviation,
     *         i.e., not necessarily the allowed speed limit)
     * @return The vehicle's max speed
     */
    double
    getMaxSpeedOnLane() const {
        if (myLane != 0) {
            return myLane->getVehicleMaxSpeed(this);
        } else {
            return myType->getMaxSpeed();
        }
    }


    /** @brief Returns the information whether the vehicle is on a road (is simulated)
     * @return Whether the vehicle is simulated
     */
    inline bool isOnRoad() const {
        return myAmOnNet;
    }


    /** @brief Returns whether the current simulation step is an action point for the vehicle
     * @return Whether the vehicle has an action point in the current step.
     */
    inline bool isActive() const {
        return myActionStep;
    }

    /** @brief Returns whether the next simulation step will be an action point for the vehicle
     * @return Whether the vehicle has scheduled an action point for the next step.
     */
    inline bool isActionStep(SUMOTime t) const {
        return (t - myLastActionTime) % getActionStepLength() == 0;
//        return t%getActionStepLength() == 0; // synchronized actions for all vehicles with identical actionsteplengths
    }


    /** @brief Returns the information whether the front of the vehicle is on the given lane
     * @return Whether the vehicle's front is on that lane
     */
    bool isFrontOnLane(const MSLane* lane) const;


    /** @brief Returns the starting point for reroutes (usually the current edge)
     *
     * This differs from *myCurrEdge only if the vehicle is on an internal edge or
     *  very close to the junction
     * @return The rerouting start point
     */
    const MSEdge* getRerouteOrigin() const;


    /** @brief Returns the SUMOTime waited (speed was lesser than 0.1m/s)
     *
     * The value is reset if the vehicle moves faster than 0.1m/s
     * Intentional stopping does not count towards this time.
     * @return The time the vehicle is standing
     */
    SUMOTime getWaitingTime() const {
        return myWaitingTime;
    }

    /** @brief Returns the SUMOTime lost (speed was lesser maximum speed)
     *
     * @note Intentional stopping does not count towards this time.
    // @note speedFactor is included so time loss can never be negative.
    // The value is that of a driver who compares his travel time when
    // the road is clear (which includes speed factor) with the actual travel time.
    // @note includes time lost due to low departSpeed and decelerating/accelerating for planned stops
     * @return The time the vehicle lost due to various effects
     */
    SUMOTime getTimeLoss() const {
        return TIME2STEPS(myTimeLoss);
    }


    /** @brief Returns the SUMOTime waited (speed was lesser than 0.1m/s) within the last t millisecs
     *
     * @return The time the vehicle was standing within the configured memory interval
     */
    SUMOTime getAccumulatedWaitingTime() const {
        return myWaitingTimeCollector.cumulatedWaitingTime(MSGlobals::gWaitingTimeMemory);
    }

    /** @brief Returns the number of seconds waited (speed was lesser than 0.1m/s)
     *
     * The value is reset if the vehicle moves faster than 0.1m/s
     * Intentional stopping does not count towards this time.
     * @return The time the vehicle is standing
     */
    double getWaitingSeconds() const {
        return STEPS2TIME(myWaitingTime);
    }


    /** @brief Returns the number of seconds waited (speed was lesser than 0.1m/s) within the last millisecs
     *
     * @return The time the vehicle was standing within the last t millisecs
     */

    double getAccumulatedWaitingSeconds() const {
        return STEPS2TIME(getAccumulatedWaitingTime());
    }

    /** @brief Returns the time loss in seconds
     */
    double getTimeLossSeconds() const {
        return myTimeLoss;
    }


    /** @brief Returns the vehicle's direction in radians
     * @return The vehicle's current angle
     */
    double getAngle() const {
        return myAngle;
    }


    /** @brief Returns the vehicle's direction in radians
     * @return The vehicle's current angle
     */
    Position getVelocityVector() const {
        return Position(std::cos(myAngle) * myState.speed(), std::sin(myAngle) * myState.speed());
    }
    //@}

    /// @brief compute the current vehicle angle
    double computeAngle() const;

    /// @brief Set a custom vehicle angle in rad, optionally updates furtherLanePosLat
    void setAngle(double angle, bool straightenFurther = false);

    /** @brief Sets the action steplength of the vehicle
     *
     * @param actionStepLength New value
     * @param resetActionOffset whether the action offset should be reset to zero,
     *        i.e., the next action step should follow immediately.
     */
    void setActionStepLength(double actionStepLength, bool resetActionOffset = true);

    /** Returns true if the two vehicles overlap. */
    static bool overlap(const MSVehicle* veh1, const MSVehicle* veh2) {
        if (veh1->myState.myPos < veh2->myState.myPos) {
            return veh2->myState.myPos - veh2->getVehicleType().getLengthWithGap() < veh1->myState.myPos;
        }
        return veh1->myState.myPos - veh1->getVehicleType().getLengthWithGap() < veh2->myState.myPos;
    }

    /** Returns true if vehicle's speed is below 60km/h. This is only relevant
        on highways. Overtaking on the right is allowed then. */
    bool congested() const {
        return myState.mySpeed < double(60) / double(3.6);
    }


    /** @brief "Activates" all current move reminder
     *
     * For all move reminder stored in "myMoveReminders", their method
     *  "MSMoveReminder::notifyEnter" is called.
     *
     * @param[in] reason The reason for changing the reminders' states
     * @param[in] enteredLane The lane, which is entered (if applicable)
     * @see MSMoveReminder
     * @see MSMoveReminder::notifyEnter
     * @see MSMoveReminder::Notification
     */
    void activateReminders(const MSMoveReminder::Notification reason, const MSLane* enteredLane = 0);

    /** @brief Update when the vehicle enters a new lane in the move step.
     *
     * @param[in] enteredLane The lane the vehicle enters
     * @param[in] onTeleporting Whether the lane was entered while being teleported
     * @return Whether the vehicle's route has ended (due to vaporization, or because the destination was reached)
     */
    bool enterLaneAtMove(MSLane* enteredLane, bool onTeleporting = false);



    /** @brief Update when the vehicle enters a new lane in the emit step
     *
     * @param[in] enteredLane The lane the vehicle enters
     * @param[in] pos The position the vehicle was inserted into the lane
     * @param[in] speed The speed with which the vehicle was inserted into the lane
     * @param[in] posLat The lateral position the vehicle was inserted into the lane
     * @param[in] notification The cause of insertion (i.e. departure, teleport, parking)
     */
    void enterLaneAtInsertion(MSLane* enteredLane, double pos, double speed, double posLat,
                              MSMoveReminder::Notification notification);

    /** @brief set tentative lane and position during insertion to ensure that
     * all cfmodels work (some of them require veh->getLane() to return a valid lane)
     * Once the vehicle is sucessfully inserted the lane is set again (see enterLaneAtInsertion)
     */
    void setTentativeLaneAndPosition(MSLane* lane, double pos, double posLat = 0);

    /** @brief Update when the vehicle enters a new lane in the laneChange step.
     *
     * @param[in] enteredLane The lane the vehicle enters
     */
    void enterLaneAtLaneChange(MSLane* enteredLane);


    /** @brief Update of members if vehicle leaves a new lane in the lane change step or at arrival. */
    void leaveLane(const MSMoveReminder::Notification reason, const MSLane* approachedLane = 0);

    /** @brief Check whether the drive items (myLFLinkLanes) are up to date,
     *         and update them if required.
     *  @note  This is the case if a lane change was completed.
     *         Only the links corresponding to the drive items are updated to the
     *         corresponding parallel links.
     */
    void updateDriveItems();

    /** @brief Get the distance and direction of the next upcoming turn for the vehicle (within its look-ahead range)
     *  @return The first entry of the returned pair is the distance for the upcoming turn, the second is the link direction
     */
    const std::pair<double, LinkDirection>& getNextTurn() {
        return myNextTurn;
    }


    MSAbstractLaneChangeModel& getLaneChangeModel();
    const MSAbstractLaneChangeModel& getLaneChangeModel() const;

    const std::vector<MSLane*>& getFurtherLanes() const {
        return myFurtherLanes;
    }

    const std::vector<double>& getFurtherLanesPosLat() const {
        return myFurtherLanesPosLat;
    }


    /// @brief whether this vehicle has its back (and no its front) on the given edge
    bool onFurtherEdge(const MSEdge* edge) const;

    /// @name strategical/tactical lane choosing methods
    /// @{

    //
    /** @struct LaneQ
     * @brief A structure representing the best lanes for continuing the current route starting at 'lane'
     */
    struct LaneQ {
        /// @brief The described lane
        MSLane* lane;
        /// @brief The overall length which may be driven when using this lane without a lane change
        double length;
        /// @brief The length which may be driven on this lane
        double currentLength;
        /// @brief The overall vehicle sum on consecutive lanes which can be passed without a lane change
        double occupation;
        /// @brief As occupation, but without the first lane
        double nextOccupation;
        /// @brief The (signed) number of lanes to be crossed to get to the lane which allows to continue the drive
        int bestLaneOffset;
        /// @brief Whether this lane allows to continue the drive
        bool allowsContinuation;
        /* @brief Longest sequence of (normal-edge) lanes that can be followed without a lane change
         * The 'length' attribute is the sum of these lane lengths
         * (There may be alternative sequences that have equal length)
         * It is the 'best' in the strategic sense of reducing required lane-changes
         */
        std::vector<MSLane*> bestContinuations;
    };

    /** @brief Returns the description of best lanes to use in order to continue the route
     * @return The LaneQ for all lanes of the current edge
     */
    const std::vector<LaneQ>& getBestLanes() const;

    /** @brief computes the best lanes to use in order to continue the route
     *
     * The information is rebuilt if the vehicle is on a different edge than
     *  the one stored in "myLastBestLanesEdge" or "forceRebuild" is true.
     *
     * Otherwise, only the density changes on the stored lanes are adapted to
     *  the container only.
     *
     * A rebuild must be done if the vehicle leaves a stop; then, another lane may become
     *  the best one.
     *
     * If no starting lane ("startLane") is given, the vehicle's current lane ("myLane")
     *  is used as start of best lanes building.
     *
     * @param[in] forceRebuild Whether the best lanes container shall be rebuilt even if the vehicle's edge has not changed
     * @param[in] startLane The lane the process shall start at ("myLane" will be used if ==0)
     */
    void updateBestLanes(bool forceRebuild = false, const MSLane* startLane = 0);


    /** @brief Returns the best sequence of lanes to continue the route starting at myLane
     * @return The bestContinuations of the LaneQ for myLane (see LaneQ)
     */
    const std::vector<MSLane*>& getBestLanesContinuation() const;


    /** @brief Returns the best sequence of lanes to continue the route starting at the given lane
     * @return The bestContinuations of the LaneQ for the given lane (see LaneQ)
     */
    const std::vector<MSLane*>& getBestLanesContinuation(const MSLane* const l) const;

    /* @brief returns the current signed offset from the lane that is most
     * suited for continuing the current route (in the strategic sense of reducing lane-changes)
     * - 0 if the vehicle is one it's best lane
     * - negative if the vehicle should change to the right
     * - positive if the vehicle should change to the left
     */
    int getBestLaneOffset() const;

    /// @brief update occupation from MSLaneChanger
    void adaptBestLanesOccupation(int laneIndex, double density);

    /// @}

    /// @brief repair errors in vehicle position after changing between internal edges
    void fixPosition();


    /** @brief Returns the vehicle's car following model definition
     *
     * This is simply a wrapper around the vehicle type's car-following
     *  model retrieval for a shorter access.
     *
     * @return The vehicle's car following model definition
     */
    inline const MSCFModel& getCarFollowModel() const {
        return myType->getCarFollowModel();
    }

    /** @brief Returns the vehicle driver's state
     *
     * @return The vehicle driver's state
     *
     */

    std::shared_ptr<MSSimpleDriverState> getDriverState() const;


    /** @brief Returns the vehicle's car following model variables
     *
     * @return The vehicle's car following model variables
     */
    inline MSCFModel::VehicleVariables* getCarFollowVariables() const {
        return myCFVariables;
    }

    /// @name vehicle stops definitions and i/o
    //@{

    /** @class Stop
     * @brief Definition of vehicle stop (position and duration)
     */
    class Stop {
    public:
        Stop(const SUMOVehicleParameter::Stop& par) : pars(par) {}
        /// @brief The edge in the route to stop at
        MSRouteIterator edge;
        /// @brief The lane to stop at
        const MSLane* lane = nullptr;
        /// @brief (Optional) bus stop if one is assigned to the stop
        MSStoppingPlace* busstop = nullptr;
        /// @brief (Optional) container stop if one is assigned to the stop
        MSStoppingPlace* containerstop = nullptr;
        /// @brief (Optional) parkingArea if one is assigned to the stop
        MSParkingArea* parkingarea = nullptr;
        /// @brief (Optional) charging station if one is assigned to the stop
        MSStoppingPlace* chargingStation = nullptr;
        /// @brief The stop parameter
        const SUMOVehicleParameter::Stop pars;
        /// @brief The stopping duration
        SUMOTime duration = -1;
        /// @brief whether an arriving person lets the vehicle continue
        bool triggered = false;
        /// @brief whether an arriving container lets the vehicle continue
        bool containerTriggered = false;
        /// @brief Information whether the stop has been reached
        bool reached = false;
        /// @brief The number of still expected persons
        int numExpectedPerson = 0;
        /// @brief The number of still expected containers
        int numExpectedContainer = 0;
        /// @brief The time at which the vehicle is able to board another person
        SUMOTime timeToBoardNextPerson = 0;
        /// @brief The time at which the vehicle is able to load another container
        SUMOTime timeToLoadNextContainer = 0;
        /// @brief Whether this stop was triggered by a collision
        bool collision = false;
        /// @brief the maximum time at which persons may board this vehicle
        SUMOTime endBoarding = SUMOTime_MAX;

        /// @brief Write the current stop configuration (used for state saving)
        void write(OutputDevice& dev) const;

        /// @brief return halting position for upcoming stop;
        double getEndPos(const SUMOVehicle& veh) const;

        /// @brief get a short description for showing in the gui
        std::string getDescription() const;

    private:
        /// @brief Invalidated assignment operator
        Stop& operator=(const Stop& src);

    };


    /** @brief Adds a stop
     *
     * The stop is put into the sorted list.
     * @param[in] stop The stop to add
     * @return Whether the stop could be added
     */
    bool addStop(const SUMOVehicleParameter::Stop& stopPar, std::string& errorMsg, SUMOTime untilOffset = 0, bool collision = false,
                 MSRouteIterator* searchStart = 0);

    /** @brief replace the current parking area stop with a new stop with merge duration
     */
    bool replaceParkingArea(MSParkingArea* parkingArea, std::string& errorMsg);

    /** @brief get the upcoming parking area stop or nullptr
     */
    MSParkingArea* getNextParkingArea();

    /** @brief get the current  parking area stop or nullptr */
    MSParkingArea* getCurrentParkingArea();

    /** @brief Returns whether the vehicle has to stop somewhere
     * @return Whether the vehicle has to stop somewhere
     */
    bool hasStops() const {
        return !myStops.empty();
    }

    /** @brief Whether this vehicle is equipped with a MSDriverState
     */
    inline bool hasDriverState() const {
        return myDriverState != nullptr;
    }

    /** @brief Returns whether the vehicle is at a stop
     * @return Whether the vehicle has stopped
     */
    bool isStopped() const;

    /// @brief Returns the remaining stop duration for a stopped vehicle or 0
    SUMOTime remainingStopDuration() const;

    /** @brief Returns whether the vehicle stops at the given stopping place */
    bool stopsAt(MSStoppingPlace* stop) const;

    /** @brief Returns whether the vehicle stops at the given edge */
    bool stopsAtEdge(const MSEdge* edge) const;

    /** @brief Returns whether the vehicle will stop on the current edge
     */
    bool willStop() const;

    //// @brief Returns whether the vehicle is at a stop and on the correct lane
    bool isStoppedOnLane() const;

    /** @brief Returns whether the vehicle is stopped and must continue to do so */
    bool keepStopping(bool afterProcessing = false) const;

    /** @brief Returns the remaining time a vehicle needs to stop due to a
     * collision. A negative value indicates that the vehicle is not stopping due to a collision (or at all)
     */
    SUMOTime collisionStopTime() const;

    /** @brief Returns whether the vehicle is parking
     * @return whether the vehicle is parking
     */
    bool isParking() const;

    /** @brief Returns the information whether the vehicle is fully controlled via TraCI
     * @return Whether the vehicle is remote-controlled
     */
    bool isRemoteControlled() const;

    /** @brief Returns the information whether the vehicle is fully controlled via TraCI
     * within the lookBack time
     */
    bool wasRemoteControlled(SUMOTime lookBack = DELTA_T) const;

    /// @brief return the distance to the next stop or doubleMax if there is none.
    double nextStopDist() const {
        return myStopDist;
    }

    /** @brief Returns whether the vehicle is on a triggered stop
     * @return whether the vehicle is on a triggered stop
     */
    bool isStoppedTriggered() const;

    /** @brief return whether the given position is within range of the current stop
     */
    bool isStoppedInRange(const double pos, const double tolerance) const;
    /// @}

    int getLaneIndex() const;

    /**
     * Compute distance that will be covered, if the vehicle moves to a given position on its route,
     * starting at its current position.
     * @param destPos:  position on the destination edge that shall be reached
     * @param destEdge: destination edge that shall be reached
     * @return      distance from the vehicles current position to the destination position,
     *          or a near infinite real value if the destination position is not contained
     *          within the vehicles route or the vehicle is not active
     */
    double getDistanceToPosition(double destPos, const MSEdge* destEdge) const;


    /** @brief Processes stops, returns the velocity needed to reach the stop
     * @return The velocity in dependance to the next/current stop
     * @todo Describe more detailed
     * @see Stop
     * @see MSStoppingPlace
     * @see MSStoppingPlace
     */
    double processNextStop(double currentVelocity);

    /** @brief Returns the leader of the vehicle looking for a fixed distance.
     *
     * If the distance is not given it is calculated from the brake gap.
     * The gap returned does not include the minGap.
     * @param dist    up to which distance to look for a leader
     * @return The leading vehicle together with the gap; (0, -1) if no leader was found.
     */
    std::pair<const MSVehicle* const, double> getLeader(double dist = 0) const;

    /** @brief Returns the time gap in seconds to the leader of the vehicle on the same lane.
     *
     * If the distance is too big -1 is returned.
     * The gap returned takes the minGap into account.
     * @return The time gap in seconds; -1 if no leader was found or speed is 0.
     */
    double getTimeGapOnLane() const;

    /// @name Emission retrieval
    //@{

    /** @brief Returns CO2 emission of the current state
     * @return The current CO2 emission
     */
    double getCO2Emissions() const;


    /** @brief Returns CO emission of the current state
     * @return The current CO emission
     */
    double getCOEmissions() const;


    /** @brief Returns HC emission of the current state
     * @return The current HC emission
     */
    double getHCEmissions() const;


    /** @brief Returns NOx emission of the current state
     * @return The current NOx emission
     */
    double getNOxEmissions() const;


    /** @brief Returns PMx emission of the current state
     * @return The current PMx emission
     */
    double getPMxEmissions() const;


    /** @brief Returns fuel consumption of the current state
    * @return The current fuel consumption
    */
    double getFuelConsumption() const;


    /** @brief Returns electricity consumption of the current state
    * @return The current electricity consumption
    */
    double getElectricityConsumption() const;


    /** @brief Returns noise emissions of the current state
     * @return The noise produced
     */
    double getHarmonoise_NoiseEmissions() const;
    //@}

    /// @name Interaction with persons
    //@{

    /** @brief Adds a passenger
     * @param[in] person The person to add
     */
    void addPerson(MSTransportable* person);

    /// @name Interaction with containers
    //@{

    /** @brief Adds a container
     * @param[in] container The container to add
     */
    void addContainer(MSTransportable* container);

    /// @name Access to bool signals
    /// @{

    /** @enum Signalling
     * @brief Some boolean values which describe the state of some vehicle parts
     */
    enum Signalling {
        /// @brief Everything is switched off
        VEH_SIGNAL_NONE = 0,
        /// @brief Right blinker lights are switched on
        VEH_SIGNAL_BLINKER_RIGHT = 1,
        /// @brief Left blinker lights are switched on
        VEH_SIGNAL_BLINKER_LEFT = 2,
        /// @brief Blinker lights on both sides are switched on
        VEH_SIGNAL_BLINKER_EMERGENCY = 4,
        /// @brief The brake lights are on
        VEH_SIGNAL_BRAKELIGHT = 8,
        /// @brief The front lights are on (no visualisation)
        VEH_SIGNAL_FRONTLIGHT = 16,
        /// @brief The fog lights are on (no visualisation)
        VEH_SIGNAL_FOGLIGHT = 32,
        /// @brief The high beam lights are on (no visualisation)
        VEH_SIGNAL_HIGHBEAM = 64,
        /// @brief The backwards driving lights are on (no visualisation)
        VEH_SIGNAL_BACKDRIVE = 128,
        /// @brief The wipers are on
        VEH_SIGNAL_WIPER = 256,
        /// @brief One of the left doors is opened
        VEH_SIGNAL_DOOR_OPEN_LEFT = 512,
        /// @brief One of the right doors is opened
        VEH_SIGNAL_DOOR_OPEN_RIGHT = 1024,
        /// @brief A blue emergency light is on
        VEH_SIGNAL_EMERGENCY_BLUE = 2048,
        /// @brief A red emergency light is on
        VEH_SIGNAL_EMERGENCY_RED = 4096,
        /// @brief A yellow emergency light is on
        VEH_SIGNAL_EMERGENCY_YELLOW = 8192
    };


    /** @brief modes for resolving conflicts between external control (traci)
     * and vehicle control over lane changing. Each level of the lane-changing
     * hierarchy (strategic, cooperative, speedGain, keepRight) can be controlled
     * separately */
    enum LaneChangeMode {
        LC_NEVER      = 0,  // lcModel shall never trigger changes at this level
        LC_NOCONFLICT = 1,  // lcModel may trigger changes if not in conflict with TraCI request
        LC_ALWAYS     = 2   // lcModel may always trigger changes of this level regardless of requests
    };


    /// @brief modes for prioritizing traci lane change requests
    enum TraciLaneChangePriority {
        LCP_ALWAYS        = 0,  // change regardless of blockers, adapt own speed and speed of blockers
        LCP_NOOVERLAP     = 1,  // change unless overlapping with blockers, adapt own speed and speed of blockers
        LCP_URGENT        = 2,  // change if not blocked, adapt own speed and speed of blockers
        LCP_OPPORTUNISTIC = 3   // change if not blocked
    };


    /** @brief Switches the given signal on
     * @param[in] signal The signal to mark as being switched on
     */
    void switchOnSignal(int signal) {
        mySignals |= signal;
    }


    /** @brief Switches the given signal off
     * @param[in] signal The signal to mark as being switched off
     */
    void switchOffSignal(int signal) {
        mySignals &= ~signal;
    }


    /** @brief Returns the signals
     * @return The signals' states
     */
    int getSignals() const {
        return mySignals;
    }


    /** @brief Returns whether the given signal is on
     * @param[in] signal The signal to return the value of
     * @return Whether the given signal is on
     */
    bool signalSet(int which) const {
        return (mySignals & which) != 0;
    }
    /// @}


    /// @brief whether the vehicle may safely move to the given lane with regard to upcoming links
    bool unsafeLinkAhead(const MSLane* lane) const;

    /// @brief decide whether the vehicle is passing a minor link or has comitted to do so
    bool passingMinor() const;



    /** @brief Returns the uninfluenced velocity
     *
     * If no influencer exists (myInfluencer==0) the vehicle's current speed is
     *  returned. Otherwise the speed returned from myInfluencer->getOriginalSpeed().
     * @return The vehicle's velocity as it would without an influence
     * @see Influencer::getOriginalSpeed
     */
    double getSpeedWithoutTraciInfluence() const;

    /**
     * reroute the vehicle to the new parking area, updating routes and passengers/containers associated trips
     * @param parkingAreaID    id of the new parking area
     */
    bool rerouteParkingArea(const std::string& parkingAreaID, std::string& errorMsg);

    /**
     * schedule a new stop for the vehicle; each time a stop is reached, the vehicle
     * will wait for the given duration before continuing on its route
     * @param lane     lane on wich to stop
     * @param startPos start position on the given lane at wich to stop
     * @param endPos   end position on the given lane at wich to stop
     * @param duration waiting time duration
     * @param until    time step at which the stop shall end
     * @param parking  a flag indicating whether the traci stop is used for parking or not
     * @param triggered a flag indicating whether the traci stop is triggered or not
     * @param containerTriggered a flag indicating whether the traci stop is triggered by a container or not
     */
    bool addTraciStop(MSLane* const lane, const double startPos, const double endPos, const SUMOTime duration, const SUMOTime until,
                      const bool parking, const bool triggered, const bool containerTriggered, std::string& errorMsg);

    /**
     * schedule a new stop for the vehicle; each time a stop is reached, the vehicle
     * will wait for the given duration before continuing on its route
     * @param stopId    bus or container stop id
     * @param duration waiting time duration
     * @param until    time step at which the stop shall end
     * @param parking   a flag indicating whether the traci stop is used for parking or not
     * @param triggered a flag indicating whether the traci stop is triggered or not
     * @param containerTriggered a flag indicating whether the traci stop is triggered by a container or not
     * @param stoppingPlaceType a flag indicating the type of stopping place
     */
    bool addTraciStopAtStoppingPlace(const std::string& stopId, const SUMOTime duration, const SUMOTime until, const bool parking,
                                     const bool triggered, const bool containerTriggered, const SumoXMLTag stoppingPlaceType, std::string& errorMsg);

    /**
    * returns the next imminent stop in the stop queue
    * @return the upcoming stop
    */
    Stop& getNextStop();

    /**
    * returns the list of stops not yet reached in the stop queue
    * @return the list of upcoming stops
    */
    std::list<Stop> getMyStops();

    /**
    * resumes a vehicle from stopping
    * @return true on success, the resuming fails if the vehicle wasn't parking in the first place
    */
    bool resumeFromStopping();


    /// @brief update a vector of further lanes and return the new backPos
    double updateFurtherLanes(std::vector<MSLane*>& furtherLanes,
                              std::vector<double>& furtherLanesPosLat,
                              const std::vector<MSLane*>& passedLanes);

    /// @brief get bounding rectangle
    PositionVector getBoundingBox() const;

    /// @brief get bounding polygon
    PositionVector getBoundingPoly() const;

    /** @enum ManoeuvreType
     *  @brief  flag identifying which, if any, manoeuvre is in progress
     */
    enum ManoeuvreType {
        /// @brief Manoeuvre into stopping place
        MANOEUVRE_ENTRY,
        /// @brief Manoeuvre out of stopping place
        MANOEUVRE_EXIT,
        /// @brief not manouevring
        MANOEUVRE_NONE
    };

    /// @brief accessor function to myManoeuvre equivalent
    /// @note Setup of exit manoeuvre is invoked from MSVehicleTransfer
    bool setExitManoeuvre();
    /// @brief accessor function to myManoeuvre equivalent
    void setManoeuvreType(const MSVehicle::ManoeuvreType mType);

    /// @brief accessor function to myManoeuvre equivalent
    bool manoeuvreIsComplete() const;
    /// @brief accessor function to myManoeuvre equivalent
    MSVehicle::ManoeuvreType getManoeuvreType() const;


    /** @class Manoeuvre
      * @brief  Container for manouevering time associated with stopping.
      *
      *  Introduced to cater for lane blocking whilst entering stop/leaving stop
      *   and assure that emissions during manoeuvre are included in model
      */
    class Manoeuvre {

    public:
        /// Constructor.
        Manoeuvre();

        /// Copy constructor.
        Manoeuvre(const Manoeuvre& manoeuvre);

        /// Assignment operator.
        Manoeuvre& operator=(const Manoeuvre& manoeuvre);

        /// Operator !=
        bool operator!=(const Manoeuvre& manoeuvre);

        /// @brief Setup the entry manoeuvre for this vehicle (Sets completion time and manoeuvre type)
        bool configureEntryManoeuvre(MSVehicle* veh);

        /// @brief Setup the myManoeuvre for exiting (Sets completion time and manoeuvre type)
        bool configureExitManoeuvre(MSVehicle* veh);

        /// @brief Configure an entry manoeuvre if nothing is configured - otherwise check if complete
        bool entryManoeuvreIsComplete(MSVehicle* veh);

        /// @brief Check if specific manoeuver is ongoing and whether the completion time is beyond currentTime
        bool
        manoeuvreIsComplete(const ManoeuvreType checkType) const;

        /// @brief Check if any manoeuver is ongoing and whether the completion time is beyond currentTime
        bool
        manoeuvreIsComplete() const;

        /// @brief Accessor for manoeuvre angle
        int getManoeuvreAngle() const;

        /// @brief Accessor (get) for manoeuvre type
        MSVehicle::ManoeuvreType getManoeuvreType() const;

        /// @brief Accessor (set) for manoeuvre type
        void setManoeuvreType(const MSVehicle::ManoeuvreType mType);

    private:
        /// @brief  The name of the vehicle associated with the Manoeuvre  - for debug output
        std::string myManoeuvreVehicleID;

        /// @brief  The name of the stop associated with the Manoeuvre  - for debug output
        std::string myManoeuvreStop;

        /// @brief Time at which the Manoeuvre for this stop started
        SUMOTime myManoeuvreStartTime;

        /// @brief Time at which this manoeuvre should complete
        SUMOTime myManoeuvreCompleteTime;

        /// @brief Manoeuvre type - currently entry, exit or none
        ManoeuvreType myManoeuvreType;

        // @brief Angle (degrees) through which manoeuver will turn vehicle - used to determine manouevre timing
        int myManoeuvreAngle;
    };

    // Current or previous (completed) manoeuvre
    Manoeuvre myManoeuvre;

    /** @class Influencer
      * @brief Changes the wished vehicle speed / lanes
      *
      * The class is used for passing velocities or velocity profiles obtained via TraCI to the vehicle.
      * The speed adaptation is controlled by the stored speedTimeLine
      * Additionally, the variables myConsiderSafeVelocity, myConsiderMaxAcceleration, and myConsiderMaxDeceleration
      * control whether the safe velocity, the maximum acceleration, and the maximum deceleration
      * have to be regarded.
      *
      * Furthermore this class is used to affect lane changing decisions according to
      * LaneChangeMode and any given laneTimeLine
      */
    class Influencer {
    private:

        /// @brief A static instance of this class in GapControlState deactivates gap control
        ///        for vehicles whose reference vehicle is removed from the road network
        class GapControlVehStateListener : public MSNet::VehicleStateListener {
            /** @brief Called if a vehicle changes its state
             * @param[in] vehicle The vehicle which changed its state
             * @param[in] to The state the vehicle has changed to
             * @param[in] info Additional information on the state change
             * @note This deactivates the corresponding gap control when a reference vehicle is removed.
             */
            void vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& info = "");
        };


        /// @brief Container for state and parameters of the gap control
        struct GapControlState {
            GapControlState();
            virtual ~GapControlState();
            /// @brief Static initalization (adds vehicle state listener)
            static void init();
            /// @brief Static cleanup (removes vehicle state listener)
            static void cleanup();
            /// @brief Start gap control with given params
            void activate(double tauOriginal, double tauTarget, double additionalGap, double duration, double changeRate, double maxDecel, const MSVehicle* refVeh);
            /// @brief Stop gap control
            void deactivate();
            /// @brief Original value for the desired headway (will be reset after duration has expired)
            double tauOriginal;
            /// @brief Current, interpolated value for the desired time headway
            double tauCurrent;
            /// @brief Target value for the desired time headway
            double tauTarget;
            /// @brief Current, interpolated value for the desired space headway
            double addGapCurrent;
            /// @brief Target value for the desired space headway
            double addGapTarget;
            /// @brief Remaining duration for keeping the target headway
            double remainingDuration;
            /// @brief Rate by which the current time and space headways are changed towards the target value.
            ///        (A rate of one corresponds to reaching the target value within one second)
            double changeRate;
            /// @brief Maximal deceleration to be applied due to the adapted headway
            double maxDecel;
            /// @brief reference vehicle for the gap - if it is null, the current leader on the ego's lane is used as a reference
            const MSVehicle* referenceVeh;
            /// @brief Whether the gap control is active
            bool active;
            /// @brief Whether the desired gap was attained during the current activity phase (induces the remaining duration to decrease)
            bool gapAttained;
            /// @brief The last recognized leader
            const MSVehicle* prevLeader;
            /// @brief Time of the last update of the gap control
            SUMOTime lastUpdate;
            /// @brief cache storage for the headway increments of the current operation
            double timeHeadwayIncrement, spaceHeadwayIncrement;

            /// @brief stores reference vehicles currently in use by a gapController
            static std::map<const MSVehicle*, GapControlState*> refVehMap;

        private:
            static GapControlVehStateListener vehStateListener;
        };
    public:
        /// @brief Constructor
        Influencer();

        /// @brief Destructor
        ~Influencer();

        /// @brief Static initalization
        static void init();
        /// @brief Static cleanup
        static void cleanup();

        /** @brief Sets a new velocity timeline
         * @param[in] speedTimeLine The time line of speeds to use
         */
        void setSpeedTimeLine(const std::vector<std::pair<SUMOTime, double> >& speedTimeLine);

        /** @brief Activates the gap control with the given parameters, @see GapControlState
         */
        void activateGapController(double originalTau, double newTimeHeadway, double newSpaceHeadway, double duration, double changeRate, double maxDecel, MSVehicle* refVeh = nullptr);

        /** @brief Deactivates the gap control
         */
        void deactivateGapController();

        /** @brief Sets a new lane timeline
         * @param[in] laneTimeLine The time line of lanes to use
         */
        void setLaneTimeLine(const std::vector<std::pair<SUMOTime, int> >& laneTimeLine);

        /** @brief Adapts lane timeline when moving to a new lane and the lane index changes
         * @param[in] indexShift The change in laneIndex
         */
        void adaptLaneTimeLine(int indexShift);

        /** @brief Sets a new sublane-change request
         * @param[in] latDist The lateral distance for changing
         */
        void setSublaneChange(double latDist);

        /// @brief return the current speed mode
        int getSpeedMode() const;

        /// @brief return the current lane change mode
        int getLaneChangeMode() const;

        /// @brief return the current routing mode
        int getRoutingMode() const {
            return myRoutingMode;
        }
        SUMOTime getLaneTimeLineDuration();

        SUMOTime getLaneTimeLineEnd();

        /** @brief Applies stored velocity information on the speed to use.
         *
         * The given speed is assumed to be the non-influenced speed from longitudinal control.
         *  It is stored for further usage in "myOriginalSpeed".
         * @param[in] currentTime The current simulation time
         * @param[in] speed The undisturbed speed
         * @param[in] vSafe The safe velocity
         * @param[in] vMin The minimum velocity
         * @param[in] vMax The maximum simulation time
         * @return The speed to use
         */
        double influenceSpeed(SUMOTime currentTime, double speed, double vSafe, double vMin, double vMax);

        /** @brief Applies gap control logic on the speed.
         *
         * The given speed is assumed to be the non-influenced speed from longitudinal control.
         *  It is stored for further usage in "myOriginalSpeed".
         * @param[in] currentTime The current simulation time
         * @param[in] veh The controlled vehicle
         * @param[in] speed The undisturbed speed
         * @param[in] vSafe The safe velocity
         * @param[in] vMin The minimum velocity
         * @param[in] vMax The maximum simulation time
         * @return The speed to use (<=speed)
         */
        double gapControlSpeed(SUMOTime currentTime, const SUMOVehicle* veh, double speed, double vSafe, double vMin, double vMax);

        /** @brief Applies stored LaneChangeMode information and laneTimeLine
         * @param[in] currentTime The current simulation time
         * @param[in] currentEdge The current edge the vehicle is on
         * @param[in] currentLaneIndex The index of the lane the vehicle is currently on
         * @param[in] state The LaneChangeAction flags as computed by the laneChangeModel
         * @return The new LaneChangeAction flags to use
         */
        int influenceChangeDecision(const SUMOTime currentTime, const MSEdge& currentEdge, const int currentLaneIndex, int state);


        /** @brief Return the remaining number of seconds of the current
         * laneTimeLine assuming one exists
         * @param[in] currentTime The current simulation time
         * @return The remaining seconds to change lanes
         */
        double changeRequestRemainingSeconds(const SUMOTime currentTime) const;

        /** @brief Returns whether junction priority rules shall be respected
         * @return Whether junction priority rules be respected
         */
        inline bool getRespectJunctionPriority() const {
            return myRespectJunctionPriority;
        }


        /** @brief Returns whether red lights shall be a reason to brake
         * @return Whether red lights shall be a reason to brake
         */
        inline bool getEmergencyBrakeRedLight() const {
            return myEmergencyBrakeRedLight;
        }


        /// @brief Returns whether safe velocities shall be considered
        bool considerSafeVelocity() const {
            return myConsiderSafeVelocity;
        }

        /** @brief Sets speed-constraining behaviors
         * @param[in] value a bitset controlling the different modes
         */
        void setSpeedMode(int speedMode);

        /** @brief Sets lane changing behavior
         * @param[in] value a bitset controlling the different modes
         */
        void setLaneChangeMode(int value);

        /** @brief Sets routing behavior
         * @param[in] value an enum value controlling the different modes
         */
        void setRoutingMode(int value) {
            myRoutingMode = value;
        }

        /** @brief Returns the originally longitudinal speed to use
         * @return The speed given before influence or -1 if no influence is active
         */
        double getOriginalSpeed() const;

        void setRemoteControlled(Position xyPos, MSLane* l, double pos, double posLat, double angle, int edgeOffset, const ConstMSEdgeVector& route, SUMOTime t);

        SUMOTime getLastAccessTimeStep() const {
            return myLastRemoteAccess;
        }

        void postProcessRemoteControl(MSVehicle* v);

        /// @brief return the speed that is implicit in the new remote position
        double implicitSpeedRemote(const MSVehicle* veh, double oldSpeed);

        /// @brief return the change in longitudinal position that is implicit in the new remote position
        double implicitDeltaPosRemote(const MSVehicle* veh);

        bool isRemoteControlled() const;

        bool isRemoteAffected(SUMOTime t) const;

        void setSignals(int signals) {
            myTraCISignals = signals;
        }

        int getSignals() const {
            return myTraCISignals;
        }

        double getLatDist() const {
            return myLatDist;
        }

        void resetLatDist() {
            myLatDist = 0.;
        }

        bool ignoreOverlap() const {
            return myTraciLaneChangePriority == LCP_ALWAYS;
        }

        SUMOAbstractRouter<MSEdge, SUMOVehicle>& getRouterTT(const int rngIndex) const;

    private:
        /// @brief The velocity time line to apply
        std::vector<std::pair<SUMOTime, double> > mySpeedTimeLine;

        /// @brief The lane usage time line to apply
        std::vector<std::pair<SUMOTime, int> > myLaneTimeLine;

        /// @brief The gap control state
        std::shared_ptr<GapControlState> myGapControlState;

        /// @brief The velocity before influence
        double myOriginalSpeed;

        /// @brief The requested lateral change
        double myLatDist;

        /// @brief Whether influencing the speed has already started
        bool mySpeedAdaptationStarted;

        /// @brief Whether the safe velocity shall be regarded
        bool myConsiderSafeVelocity;

        /// @brief Whether the maximum acceleration shall be regarded
        bool myConsiderMaxAcceleration;

        /// @brief Whether the maximum deceleration shall be regarded
        bool myConsiderMaxDeceleration;

        /// @brief Whether the junction priority rules are respected
        bool myRespectJunctionPriority;

        /// @brief Whether red lights are a reason to brake
        bool myEmergencyBrakeRedLight;

        Position myRemoteXYPos;
        MSLane* myRemoteLane;
        double myRemotePos;
        double myRemotePosLat;
        double myRemoteAngle;
        int myRemoteEdgeOffset;
        ConstMSEdgeVector myRemoteRoute;
        SUMOTime myLastRemoteAccess;

        /// @name Flags for managing conflicts between the laneChangeModel and TraCI laneTimeLine
        //@{
        /// @brief lane changing which is necessary to follow the current route
        LaneChangeMode myStrategicLC;
        /// @brief lane changing with the intent to help other vehicles
        LaneChangeMode myCooperativeLC;
        /// @brief lane changing to travel with higher speed
        LaneChangeMode mySpeedGainLC;
        /// @brief changing to the rightmost lane
        LaneChangeMode myRightDriveLC;
        /// @brief changing to the prefered lateral alignment
        LaneChangeMode mySublaneLC;
        //@}
        ///* @brief flags for determining the priority of traci lane change requests
        TraciLaneChangePriority myTraciLaneChangePriority;

        // @brief the signals set via TraCI
        int myTraCISignals;

        ///@brief routing mode (see TraCIConstants.h)
        int myRoutingMode;

    };


    /** @brief Returns the velocity/lane influencer
     *
     * If no influencer was existing before, one is built, first
     * @return Reference to this vehicle's speed influencer
     */
    Influencer& getInfluencer();

    const Influencer* getInfluencer() const;

    bool hasInfluencer() const {
        return myInfluencer != nullptr;
    }

    /// @brief allow TraCI to influence a lane change decision
    int influenceChangeDecision(int state);

    /// @brief sets position outside the road network
    void setRemoteState(Position xyPos);

    /// @brief departure position where the vehicle fits fully onto the edge (if possible)
    double basePos(const MSEdge* edge) const;

    /// @brief compute safe speed for following the given leader
    double getSafeFollowSpeed(const std::pair<const MSVehicle*, double> leaderInfo,
                              const double seen, const MSLane* const lane, double distToCrossing) const;

    /// @brief get a numerical value for the priority of the  upcoming link
    static int nextLinkPriority(const std::vector<MSLane*>& conts);

    /// @brief whether the given vehicle must be followed at the given junction
    bool isLeader(const MSLink* link, const MSVehicle* veh) const;

    // @brief get the position of the back bumper;
    const Position getBackPosition() const;

    /// @name state io
    //@{

    /// Saves the states of a vehicle
    void saveState(OutputDevice& out);

    /** @brief Loads the state of this vehicle from the given description
     */
    void loadState(const SUMOSAXAttributes& attrs, const SUMOTime offset);
    //@}

protected:

    double getSpaceTillLastStanding(const MSLane* l, bool& foundStopped) const;

    /// @name Interaction with move reminders
    ///@{

    /** @brief Adapts the vehicle's entering of a new lane
     *
     * All offsets already stored in "myOldLaneMoveReminderOffsets" are increased by the
     *  length that has been left. All still active move reminders from "myMoveReminders"
     *  are put into "myOldLaneMoveReminders" and the offset to the last lane is added to
     *  "myOldLaneMoveReminderOffsets" for each of these.
     *
     * Move reminder from the given lane are set into "myMoveReminders".
     *
     * "myLane" must still be the left lane!
     *
     * @param[in] enteredLane
     * @see MSMoveReminder
     * @see MSLane::getMoveReminder
     */
    void adaptLaneEntering2MoveReminder(const MSLane& enteredLane);
    ///@}


    /** @brief This method iterates through the driveprocess items for the vehicle
     *         and adapts the given in/out parameters to the appropriate values.
     *
     *  @param[in/out] vSafe The maximal safe (or admissible) velocity.
     *  @param[in/out] vSafeMin The minimal safe (or admissible) velocity (used her for ensuring the clearing of junctions in time).
     *  @param[in/out] vSafeMinDist The distance to the next link, which should either be crossed this step, or in front of which the vehicle need to stop.
     */
    void processLinkApproaches(double& vSafe, double& vSafeMin, double& vSafeMinDist);


    /** @brief This method checks if the vehicle has advanced over one or several lanes
     *         along its route and triggers the corresponding actions for the lanes and the vehicle.
     *         and adapts the given in/out parameters to the appropriate values.
     *
     *  @param[out] passedLanes Lanes, which the vehicle touched at some moment of the executed simstep
     *  @param[out] moved Whether the vehicle did move to another lane
     *  @param[out] emergencyReason Reason for a possible emergency stop
     */
    void processLaneAdvances(std::vector<MSLane*>& passedLanes, bool& moved, std::string& emergencyReason);


    /** @brief Check for speed advices from the traci client and adjust the speed vNext in
     *         the current (euler) / after the current (ballistic) simstep accordingly.
     *
     *  @param[in] vSafe The maximal safe (or admissible) velocity as determined from stops, junction approaches, car following, lane changing, etc.
     *  @param[in] vNext The next speed (possibly subject to traci influence)
     *  @return updated vNext
     */
    double processTraCISpeedControl(double vSafe, double vNext);


    /** @brief Erase passed drive items from myLFLinkLanes (and unregister approaching information for
     *         corresponding links). Further, myNextDriveItem is reset.
     *  @note  This is called in planMove() if the vehicle has no actionstep. All items until the position
     *         myNextDriveItem are deleted. This can happen if myNextDriveItem was increased in processLaneAdvances()
     *         of the previous step.
     */
    void removePassedDriveItems();

    /** @brief Updates the vehicle's waiting time counters (accumulated and consecutive)
     */
    void updateWaitingTime(double vNext);

    /** @brief Updates the vehicle's time loss
     */
    void updateTimeLoss(double vNext);

    /// @brief whether the vehicle is a train that can reverse its direction at the current point in its route
    bool canReverse(double speedThreshold = SUMO_const_haltingSpeed) const;

    /** @brief sets the braking lights on/off
     */
    void setBrakingSignals(double vNext) ;

    /** @brief sets the blue flashing light for emergency vehicles
     */
    void setBlinkerInformation();

    /** @brief sets the blue flashing light for emergency vehicles
     */
    void setEmergencyBlueLight(SUMOTime currentTime);

    /// updates LaneQ::nextOccupation and myCurrentLaneInBestLanes
    void updateOccupancyAndCurrentBestLane(const MSLane* startLane);

    /** @brief Returns the list of still pending stop edges
     * also returns the first and last stop position
     */
    const ConstMSEdgeVector getStopEdges(double& firstPos, double& lastPos) const;

    /// @brief return list of route indices for the remaining stops
    std::vector<std::pair<int, double> > getStopIndices() const;

    /// @brief get distance for coming to a stop (used for rerouting checks)
    double getBrakeGap() const;

    /// @brief ensure that a vehicle-relative position is not invalid
    Position validatePosition(Position result, double offset = 0) const;

    /// @brief register vehicle for drawing while outside the network
    virtual void drawOutsideNetwork(bool /*add*/) {};

    /// @brief The time the vehicle waits (is not faster than 0.1m/s) in seconds
    SUMOTime myWaitingTime;
    WaitingTimeCollector myWaitingTimeCollector;

    /// @brief the time loss in seconds due to driving with less than maximum speed
    double myTimeLoss;

    /// @brief This Vehicles driving state (pos and speed)
    State myState;

    /// @brief This vehicle's driver state @see MSDriverState
    MSDevice_DriverState* myDriverState;

    /// @brief The flag myActionStep indicates whether the current time step is an action point for the vehicle.
    bool myActionStep;
    /// @brief Action offset (actions are taken at time myActionOffset + N*getActionStepLength())
    ///        Initialized to 0, to be set at insertion.
    SUMOTime myLastActionTime;



    /// The lane the vehicle is on
    MSLane* myLane;

    MSAbstractLaneChangeModel* myLaneChangeModel;

    const MSEdge* myLastBestLanesEdge;
    const MSLane* myLastBestLanesInternalLane;

    /* @brief Complex data structure for keeping and updating LaneQ:
     * Each element of the outer vector corresponds to an upcoming edge on the vehicles route
     * The first element corresponds to the current edge and is returned in getBestLanes()
     * The other elements are only used as a temporary structure in updateBestLanes();
     */
    std::vector<std::vector<LaneQ> > myBestLanes;

    /* @brief iterator to speed up retrieval of the current lane's LaneQ in getBestLaneOffset() and getBestLanesContinuation()
     * This is updated in updateOccupancyAndCurrentBestLane()
     */
    std::vector<LaneQ>::iterator myCurrentLaneInBestLanes;

    static std::vector<MSLane*> myEmptyLaneVector;

    /// @brief The vehicle's list of stops
    std::list<Stop> myStops;

    /// @brief The current acceleration after dawdling in m/s
    double myAcceleration;

    /// @brief the upcoming turn for the vehicle
    /// @todo calculate during plan move
    std::pair<double, LinkDirection> myNextTurn;

    /// @brief The information into which lanes the vehicle laps into
    std::vector<MSLane*> myFurtherLanes;
    /// @brief lateral positions on further lanes
    std::vector<double> myFurtherLanesPosLat;

    /// @brief State of things of the vehicle that can be on or off
    int mySignals;

    /// @brief Whether the vehicle is on the network (not parking, teleported, vaporized, or arrived)
    bool myAmOnNet;

    /// @brief Whether this vehicle is registered as waiting for a person (for deadlock-recognition)
    bool myAmRegisteredAsWaitingForPerson;

    /// @brief Whether this vehicle is registered as waiting for a container (for deadlock-recognition)
    bool myAmRegisteredAsWaitingForContainer;

    bool myHaveToWaitOnNextLink;

    /// @brief the angle in radians (@todo consider moving this into myState)
    double myAngle;

    /// @brief distance to the next stop or doubleMax if there is none
    double myStopDist;

    /// @brief amount of time for which the vehicle is immune from collisions
    SUMOTime myCollisionImmunity;

    mutable Position myCachedPosition;

    /// @brief time at which the current junction was entered
    SUMOTime myJunctionEntryTime;
    SUMOTime myJunctionEntryTimeNeverYield;
    SUMOTime myJunctionConflictEntryTime;

protected:

    /// @brief Drive process items represent bounds on the safe velocity
    ///        corresponding to the upcoming links.
    /// @todo: improve documentation
    struct DriveProcessItem {
        MSLink* myLink;
        double myVLinkPass;
        double myVLinkWait;
        bool mySetRequest;
        SUMOTime myArrivalTime;
        double myArrivalSpeed;
        SUMOTime myArrivalTimeBraking;
        double myArrivalSpeedBraking;
        double myDistance;
        double accelV;
        bool hadStoppedVehicle;
        double availableSpace;

        DriveProcessItem(MSLink* link, double vPass, double vWait, bool setRequest,
                         SUMOTime arrivalTime, double arrivalSpeed,
                         SUMOTime arrivalTimeBraking, double arrivalSpeedBraking,
                         double distance,
                         double leaveSpeed = -1.) :
            myLink(link), myVLinkPass(vPass), myVLinkWait(vWait), mySetRequest(setRequest),
            myArrivalTime(arrivalTime), myArrivalSpeed(arrivalSpeed),
            myArrivalTimeBraking(arrivalTimeBraking), myArrivalSpeedBraking(arrivalSpeedBraking),
            myDistance(distance),
            accelV(leaveSpeed), hadStoppedVehicle(false), availableSpace(0) {
            assert(vWait >= 0 || !MSGlobals::gSemiImplicitEulerUpdate);
            assert(vPass >= 0 || !MSGlobals::gSemiImplicitEulerUpdate);
        };


        /// @brief constructor if the link shall not be passed
        DriveProcessItem(double vWait, double distance, double _availableSpace = 0) :
            myLink(0), myVLinkPass(vWait), myVLinkWait(vWait), mySetRequest(false),
            myArrivalTime(0), myArrivalSpeed(0),
            myArrivalTimeBraking(0), myArrivalSpeedBraking(0),
            myDistance(distance),
            accelV(-1), hadStoppedVehicle(false), availableSpace(_availableSpace) {
            assert(vWait >= 0 || !MSGlobals::gSemiImplicitEulerUpdate);
        };


        inline void adaptLeaveSpeed(const double v) {
            if (accelV < 0) {
                accelV = v;
            } else {
                accelV = MIN2(accelV, v);
            }
        }
        inline double getLeaveSpeed() const {
            return accelV < 0 ? myVLinkPass : accelV;
        }
    };

    /// Container for used Links/visited Lanes during planMove() and executeMove.
    // TODO: Consider making LFLinkLanes a std::deque for efficient front removal (needs refactoring in checkRewindLinkLanes()...)
    typedef std::vector< DriveProcessItem > DriveItemVector;

    /// @brief container for the planned speeds in the current step
    DriveItemVector myLFLinkLanes;

    /// @brief planned speeds from the previous step for un-registering from junctions after the new container is filled
    DriveItemVector myLFLinkLanesPrev;

    /** @brief iterator pointing to the next item in myLFLinkLanes
    *   @note  This is updated whenever the vehicle advances to a subsequent lane (see processLaneAdvances())
    *          and used for inter-actionpoint actualization of myLFLinkLanes (i.e. deletion of passed items)
    *          in planMove().
    */
    DriveItemVector::iterator myNextDriveItem;

    /// @todo: documentation
    void planMoveInternal(const SUMOTime t, MSLeaderInfo ahead, DriveItemVector& lfLinks, double& myStopDist, std::pair<double, LinkDirection>& myNextTurn) const;

    /// @brief runs heuristic for keeping the intersection clear in case of downstream jamming
    void checkRewindLinkLanes(const double lengthsInFront, DriveItemVector& lfLinks) const;

    /// @brief unregister approach from all upcoming links
    void removeApproachingInformation(const DriveItemVector& lfLinks) const;


    /// @brief estimate leaving speed when accelerating across a link
    inline double estimateLeaveSpeed(const MSLink* const link, const double vLinkPass) const {
        // estimate leave speed for passing time computation
        // l=linkLength, a=accel, t=continuousTime, v=vLeave
        // l=v*t + 0.5*a*t^2, solve for t and multiply with a, then add v
        return MIN2(link->getViaLaneOrLane()->getVehicleMaxSpeed(this),
                    getCarFollowModel().estimateSpeedAfterDistance(link->getLength(), vLinkPass, getVehicleType().getCarFollowModel().getMaxAccel()));
    }


    /* @brief adapt safe velocity in accordance to a moving obstacle:
     * - a leader vehicle
     * - a vehicle or pedestrian that crosses this vehicles path on an upcoming intersection
     * @param[in] leaderInfo The leading vehicle and the (virtual) distance to it
     * @param[in] seen the distance to the end of the current lane
     * @param[in] lastLink the lastLink index
     * @param[in] lane The current Lane the vehicle is on
     * @param[in,out] the safe velocity for driving
     * @param[in,out] the safe velocity for arriving at the next link
     * @param[in] distToCrossing The distance to the crossing point with the current leader where relevant or -1
     */
    void adaptToLeader(const std::pair<const MSVehicle*, double> leaderInfo,
                       const double seen, DriveProcessItem* const lastLink,
                       const MSLane* const lane, double& v, double& vLinkPass,
                       double distToCrossing = -1) const;

    /* @brief adapt safe velocity in accordance to multiple vehicles ahead:
     * @param[in] ahead The leader information according to the current lateral-resolution
     * @param[in] latOffset the lateral offset for locating the ego vehicle on the given lane
     * @param[in] seen the distance to the end of the current lane
     * @param[in] lastLink the lastLink index
     * @param[in] lane The current Lane the vehicle is on
     * @param[in,out] the safe velocity for driving
     * @param[in,out] the safe velocity for arriving at the next link
     */
    void adaptToLeaders(const MSLeaderInfo& ahead,
                        double latOffset,
                        const double seen, DriveProcessItem* const lastLink,
                        const MSLane* const lane, double& v, double& vLinkPass) const;

    /// @brief checks for link leaders on the given link
    void checkLinkLeader(const MSLink* link, const MSLane* lane, double seen,
                         DriveProcessItem* const lastLink, double& v, double& vLinkPass, double& vLinkWait, bool& setRequest,
                         bool isShadowLink = false) const;

    /// @brief checks for link leaders of the current link as well as the parallel link (if there is one)
    void checkLinkLeaderCurrentAndParallel(const MSLink* link, const MSLane* lane, double seen,
                                           DriveProcessItem* const lastLink, double& v, double& vLinkPass, double& vLinkWait, bool& setRequest) const;


    // @brief return the lane on which the back of this vehicle resides
    const MSLane* getBackLane() const;

    /** @brief updates the vehicles state, given a next value for its speed.
     *         This value can be negative in case of the ballistic update to indicate
     *         a stop within the next timestep. (You can call this a 'hack' to
     *         emulate reasoning based on accelerations: The assumed constant
     *         acceleration a within the next time step is then a = (vNext - vCurrent)/TS )
     *  @param[in] vNext speed in the next time step
     */
    void updateState(double vNext);


    /// @brief decide whether the given link must be kept clear
    bool keepClear(const MSLink* link) const;

    /// @brief decide whether a red (or yellow light) may be ignore
    bool ignoreRed(const MSLink* link, bool canBrake) const;


    /// @brief check whether all stop.edge MSRouteIterators are valid and in order
    bool haveValidStopEdges() const;

private:
    /* @brief The vehicle's knowledge about edge efforts/travel times; @see MSEdgeWeightsStorage
     * @note member is initialized on first access */
    mutable MSEdgeWeightsStorage* myEdgeWeights;

    /// @brief The per vehicle variables of the car following model
    MSCFModel::VehicleVariables* myCFVariables;

    /// @brief An instance of a velocity/lane influencing instance; built in "getInfluencer"
    Influencer* myInfluencer;



private:
    /// @brief invalidated default constructor
    MSVehicle();

    /// @brief invalidated copy constructor
    MSVehicle(const MSVehicle&);

    /// @brief invalidated assignment operator
    MSVehicle& operator=(const MSVehicle&);

    MSEdgeWeightsStorage& _getWeightsStorage() const;

};


#endif

/****************************************************************************/

