#pragma once

#include <yandex/maps/wiki/routing/auto_id_map.h>
#include <yandex/maps/wiki/routing/common.h>
#include <yandex/maps/wiki/routing/condition.h>
#include <yandex/maps/wiki/routing/element.h>
#include <yandex/maps/wiki/routing/route.h>
#include <yandex/maps/wiki/routing/stop.h>

#include <yandex/maps/wiki/graph/edge.h>

#include <map>
#include <set>
#include <vector>

namespace maps {
namespace wiki {
namespace routing {


typedef std::vector<DirectedElementID> Path;


struct CompoundNodeID {
    CompoundNodeID(const TracePoint& tracePoint, const Path& conditionPath);

    TracePoint tracePoint;
    Path conditionPath;
};

bool operator<(const CompoundNodeID& lhs, const CompoundNodeID& rhs);


struct ConditionPosition {
    ConditionPosition(ID conditionId, size_t pathPosition);

    ID conditionId;
    size_t pathPosition;
};

typedef std::vector<ConditionPosition> ConditionPositions;


class ConditionIndex {

public:
    ConditionIndex(const Elements& elements, const Conditions& conditions);

    bool isTurnaboutPossible(const DirectedElementID& id) const;

    bool isForbiddenPath(const Path& path) const;

    Path longestSuffixConditionPrefix(const Path& path) const;

private:
    std::map<
        DirectedElementID,
        ConditionPositions
    > directedElementIdToForbiddenConditionPositions_;

    std::map<ID, Path> idToForbiddenConditionPath_;
    std::set<DirectedElementID> isTurnaboutPossible_;
};


typedef std::map<graph::NodeID, graph::Edges> NodeIdToEdges;

class StaticGraph {

public:
    StaticGraph(
            const Elements& elements,
            const Stops& stops,
            const Conditions& conditions,
            double stopSnapToleranceMeters);

    graph::Edges outEdges(graph::NodeID nodeId);

    const TracePoint& getTracePointByStopId(ID stopId) const;
    const TracePoint& getTracePointByNodeId(graph::NodeID nodeId) const;

    graph::NodeID getNodeId(const TracePoint& tracePoint);
    graph::NodeID getNodeId(const TracePoint& tracePoint, const Path& conditionPath);

    const CompoundNodeID& getCompoundNodeId(graph::NodeID nodeId) const;

private:
    AutoIdMap<CompoundNodeID> nodeIdMap_;
    std::map<ID, TracePoint> stopIdToTracePoint_;
    ConditionIndex conditionIndex_;
    NodeIdToEdges outEdgesByNodeId_;
};

} // namespace routing
} // namespace wiki
} // namespace maps


