#pragma once

#include <yandex/maps/wiki/topo/common.h>

#include <maps/libs/geolib/include/point.h>
#include <maps/libs/geolib/include/polyline.h>


#include <vector>


namespace maps {
namespace wiki {
namespace topo {
namespace index {


class SpatialIndex {
public:
    virtual ~SpatialIndex() = default;

    /**
     * Build / update methods
     */

    /// Add new or update existing node geom.
    virtual void addNode(NodeID id, const geolib3::Point2& pos) = 0;

    /// Add new or update existing edge geom.
    virtual void addEdge(EdgeID id, const geolib3::Polyline2& geom) = 0;

    /// Remove references to node with @param id.
    virtual void deleteNode(NodeID id) = 0;

    /// Remove references to node with @param id.
    virtual void deleteEdge(EdgeID id) = 0;

    /**
     * Queries.
     */

    /// @return id of closest node to a given @param point
    ///   if there is any within @param maxDistance, or none otherwise.
    virtual OptionalNodeID nodeAt(const geolib3::Point2& point,
        double maxDistance,
        const NodeIDSet& ignoredNodeIds = NodeIDSet()) const = 0;

    /// @return id of closest edge to a given @param point
    ///   if there is any within @param maxDistance, or none otherwise.
    virtual boost::optional<EdgeID> edgeAt(const geolib3::Point2& point,
        double maxDistance,
        const EdgeIDSet& ignoredEdgeIds = EdgeIDSet()) const = 0;

    /// @return ids of all nodes lying within @param distance
    ///   from @param point
    virtual NodeIDVector nearestNodes(const geolib3::Point2& point,
        double distance,
        const NodeIDSet& ignoredNodeIds = NodeIDSet()) const = 0;

    /// @return ids of all edges lying within @param distance
    ///   from @param point
    virtual EdgeIDVector nearestEdges(const geolib3::Point2& point,
        double distance,
        const EdgeIDSet& ignoredEdgeIds = EdgeIDSet()) const = 0;

    /// @return ids of all edges lying within @param distance
    ///   from @param polyline
    virtual EdgeIDVector nearestEdges(const geolib3::Polyline2& polyline, double distance,
        const EdgeIDSet& ignoredEdgeIds = EdgeIDSet()) const = 0;

    /// @return ids of all nodes lying within @param distance
    ///   from @param polyline
    virtual NodeIDVector nearestNodes(const geolib3::Polyline2& polyline,
        double distance,
        const NodeIDSet& ignoredNodeIds = NodeIDSet()) const = 0;

    /// @return ids of all edges intersecting @param polyline
    virtual EdgeIDVector intersectingEdges(const geolib3::Polyline2& polyline)
        const = 0;
};

} // namespace maps::wiki::topo::index
} // namespace maps::wiki::topo
} // namespace maps::wiki
} // namespace maps
