/****************************************************************************/
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
// Copyright (C) 2002-2026 German Aerospace Center (DLR) and others.
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0/
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License 2.0 are satisfied: GNU General Public License, version 2
// or later which is available at
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
/****************************************************************************/
/// @file    RORouteDef.h
/// @author  Daniel Krajzewicz
/// @author  Michael Behrisch
/// @author  Jakob Erdmann
/// @date    Sept 2002
///
// Base class for a vehicle's route definition
/****************************************************************************/
#pragma once
#include <config.h>

#include <string>
#include <iostream>
#include <memory>
#include <utils/common/Named.h>
#include <utils/router/SUMOAbstractRouter.h>
#include "RORoute.h"


// ===========================================================================
// class declarations
// ===========================================================================
class ROEdge;
class OptionsCont;
class ROVehicle;
class OutputDevice;


// ===========================================================================
// class definitions
// ===========================================================================
/**
 * @class RORouteDef
 * @brief Base class for a vehicle's route definition
 *
 * This class resembles what a vehicle knows about his route when being loaded
 *  into a router. Whether it is just the origin and the destination, the whole
 *  route through the network or even a route with alternatives depends on
 *  the derived class.
 */
class RORouteDef : public Named {
public:
    /** @brief Constructor
     *
     * @param[in] id The id of the route
     * @param[in] color The color of the route
     */
    RORouteDef(const std::string& id, const int lastUsed,
               const bool tryRepair, const bool mayBeDisconnected);


    /// @brief Destructor
    virtual ~RORouteDef() {}


    /** @brief Adds a single alternative loaded from the file
        An alternative may also be generated during DUA */
    void addLoadedAlternative(std::shared_ptr<RORoute> alternative) {
        myAlternatives.push_back(alternative);
    }

    /** @brief Adds an alternative loaded from the file */
    void addAlternativeDef(const RORouteDef* alternative);

    /** @brief removes invalid alternatives and raise an error or warning **/
    void validateAlternatives(const ROVehicle* veh, MsgHandler* errorHandler);

    /** @brief Triggers building of the complete route (via
     * preComputeCurrentRoute) or returns precomputed route */
    std::shared_ptr<RORoute> buildCurrentRoute(SUMOAbstractRouter<ROEdge, ROVehicle>& router, SUMOTime begin,
            const ROVehicle& veh) const;

    /** @brief Builds the complete route
     * (or chooses her from the list of alternatives, when existing) */
    void preComputeCurrentRoute(SUMOAbstractRouter<ROEdge, ROVehicle>& router, SUMOTime begin,
                                const ROVehicle& veh) const;

    /** @brief Builds the complete route
     * (or chooses her from the list of alternatives, when existing) */
    bool repairCurrentRoute(SUMOAbstractRouter<ROEdge, ROVehicle>& router, SUMOTime begin,
                            const ROVehicle& veh, ConstROEdgeVector oldEdges, ConstROEdgeVector& newEdges,
                            bool isTrip = false) const;

    /** @brief Adds an alternative to the list of routes
     * and returns the route that was replaced or nullptr
    *
     * (This may be the new route) */
    std::shared_ptr<RORoute> addAlternative(SUMOAbstractRouter<ROEdge, ROVehicle>& router,
                                            const ROVehicle* const, std::shared_ptr<RORoute> current, SUMOTime begin,
                                            MsgHandler* errorHandler);

    const ROEdge* getOrigin() const;
    const ROEdge* getDestination() const;

    std::shared_ptr<const RORoute> getFirstRoute() const {
        if (myAlternatives.empty()) {
            return nullptr;
        }
        return myAlternatives.front();
    }

    std::shared_ptr<const RORoute> getUsedRoute() const {
        return myAlternatives[myLastUsed];
    }

    /** @brief Saves the built route / route alternatives
     *
     * Writes the route into the given stream.
     *
     * @param[in] dev The device to write the route into
     * @param[in] asAlternatives Whether the route shall be saved as route alternatives
     * @return The same device for further usage
     */
    OutputDevice& writeXMLDefinition(OutputDevice& dev, const ROVehicle* const veh,
                                     bool asAlternatives, bool withExitTimes, bool withCost, bool withLength) const;


    /** @brief Returns a deep copy of the route definition.
     *
     * The resulting route definition contains copies of all
     * routes contained in this one
     *
     * @param[in] id The id for the new route definition
     * @param[in] stopOffset The offset time for "until"-stops defined in the original route
     * @return the new route definition
     */
    RORouteDef* copy(const std::string& id, const SUMOTime stopOffset) const;

    /** @brief Returns the sum of the probablities of the contained routes */
    double getOverallProb() const;


    /// @brief whether this route shall be silently discarded
    bool discardSilent() const {
        return myDiscardSilent;
    }


    static void setUsingJTRR() {
        myUsingJTRR = true;
    }

    static void setSkipNew() {
        mySkipNewRoutes = true;
    }

protected:
    /// @brief backtrack to last mandatory edge and route to next mandatory
    static bool backTrack(SUMOAbstractRouter<ROEdge, ROVehicle>& router,
                          ConstROEdgeVector::const_iterator& i, int lastMandatory, const ROEdge* nextMandatory,
                          ConstROEdgeVector& newEdges, const ROVehicle& veh, SUMOTime begin);

protected:
    /// @brief precomputed route for out-of-order computation
    mutable std::shared_ptr<RORoute> myPrecomputed;

    /// @brief Index of the route used within the last step
    mutable int myLastUsed;

    /// @brief The alternatives
    std::vector<std::shared_ptr<RORoute> > myAlternatives;

    /// @brief Information whether a new route was generated
    mutable bool myNewRoute;

    const bool myTryRepair;
    const bool myMayBeDisconnected;

    /// @brief Whether this route should be silently discarded
    mutable bool myDiscardSilent;

    static bool myUsingJTRR;
    static bool mySkipNewRoutes;

private:
    /// @brief Invalidated copy constructor
    RORouteDef(const RORouteDef& src) = delete;

    /// @brief Invalidated assignment operator
    RORouteDef& operator=(const RORouteDef& src) = delete;

};
