#pragma once

#include "configs/categories.h"

#include <yandex/maps/wiki/configs/editor/topology_groups.h>
#include <yandex/maps/wiki/topo/storage.h>

namespace maps {
namespace wiki {

class Junction;
class LinearElement;
class ObjectsCache;
class TopoCache;

class TopoStorage : public topo::Storage {
public:

    TopoStorage(
        const TopologyGroup& topoGroup,
        ObjectsCache& cache);

    virtual ~TopoStorage();

    /// topo::Storage implementation

    virtual topo::NodeIDSet nodeIds(const geolib3::BoundingBox& bbox);
    virtual topo::EdgeIDSet edgeIds(const geolib3::BoundingBox& bbox);

    virtual topo::NodeVector nodes(const topo::NodeIDSet& nodeIds);
    virtual topo::EdgeVector edges(const topo::EdgeIDSet& edgeIds);

    virtual topo::NodeID newNodeId();
    virtual topo::EdgeID newEdgeId();

    virtual topo::IncidencesByNodeMap incidencesByNodes(
        const topo::NodeIDSet& nodeIds);
    virtual topo::IncidencesByEdgeMap incidencesByEdges(
        const topo::EdgeIDSet& edgeIds);

    virtual topo::IncidencesByEdgeMap
    originalIncidencesByEdges(const topo::EdgeIDSet& edgeIds);

    virtual topo::EdgeIDSet incidentEdges(topo::NodeID endNode);
    virtual topo::IncidentNodes incidentNodes(topo::EdgeID edgeId);

    virtual topo::Node node(topo::NodeID id);
    virtual topo::Edge edge(topo::EdgeID id);

    virtual topo::Node createNode(const geolib3::Point2& pos);
    virtual void updateNodePos(topo::NodeID id, const geolib3::Point2& pos);
    virtual void deleteNode(topo::NodeID id);

    virtual topo::Edge createEdge(const geolib3::Polyline2& geom,
        const topo::IncidentNodes& incidentNodes);
    virtual void updateEdgeGeom(topo::EdgeID id,
        const geolib3::Polyline2& geom, const topo::IncidentNodes& incidentNodes);
    virtual void deleteEdge(topo::EdgeID id);

    virtual bool nodeCanBeDeleted(topo::NodeID nodeId);
    virtual bool edgeCanBeDeleted(topo::EdgeID edgeId);

    virtual topo::FacesByEdgeMap facesByEdges(const topo::EdgeIDSet& edgeIds);

    virtual topo::FaceDiff faceDiff(topo::FaceID faceId);

    virtual boost::optional<topo::EdgeIDSet> tryGetFaceEdges(topo::FaceID faceId);
    virtual topo::EdgeIDSet getFaceEdges(topo::FaceID faceId);

private:
    void preloadObjects(const geolib3::BoundingBox& bbox);

    TopologyGroup topoGroup_;
    const StringSet jcToLeRoles_;
    ObjectsCache& cache_;

    std::unique_ptr<TopoCache> topoCache_;
};

} // namespace wiki
} // namespace maps
