#pragma once

#include "spatial_index.h"

#include <unordered_map>

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

class PlainIndex : public SpatialIndex {
public:
    PlainIndex() {}

    virtual void addNode(NodeID id, const geolib3::Point2& pos);
    virtual void addEdge(EdgeID id, const geolib3::Polyline2& geom);
    virtual void deleteNode(NodeID id);
    virtual void deleteEdge(EdgeID id);

    virtual OptionalNodeID nodeAt(const geolib3::Point2& point,
        double maxDistance,
        const NodeIDSet& ignoredNodeIds = NodeIDSet()) const;

    virtual OptionalEdgeID edgeAt(const geolib3::Point2& point, double maxDistance,
        const EdgeIDSet& ignoredEdgeIds = EdgeIDSet()) const;

    virtual NodeIDVector nearestNodes(const geolib3::Point2& point, double distance,
        const NodeIDSet& ignoredNodeIds = NodeIDSet()) const;

    virtual EdgeIDVector nearestEdges(const geolib3::Point2& point, double distance,
        const EdgeIDSet& ignoredEdgeIds = EdgeIDSet()) const;

    virtual EdgeIDVector nearestEdges(const geolib3::Polyline2& polyline, double distance,
        const EdgeIDSet& ignoredEdgeIds = EdgeIDSet()) const;

    virtual NodeIDVector nearestNodes(const geolib3::Polyline2& polyline, double distance,
        const NodeIDSet& ignoredNodeIds = NodeIDSet()) const;

    virtual EdgeIDVector intersectingEdges(const geolib3::Polyline2& polyline) const;

private:
    typedef std::unordered_map<NodeID, geolib3::Point2> NodeMap;
    typedef std::unordered_map<EdgeID, geolib3::Polyline2> EdgeMap;

    template <class ObjectsMap, class IDSet>
    boost::optional<typename ObjectsMap::key_type>
    objectAtPoint(
        const ObjectsMap& objects,
        const geolib3::Point2& point,
        double maxDistance,
        const IDSet& ignoredObjectIds) const;

    template <class ObjectsMap, class IDSet, class SearchGeometry, class ResultVector>
    ResultVector
    nearestObjects(
        const ObjectsMap& objects,
        const SearchGeometry& geom,
        double distance,
        const IDSet& ignoredObjectIds) const;

    NodeMap nodes_;
    EdgeMap edges_;
};

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

#define YANDEX_MAPS_WIKI_TOPO_PLAIN_INDEX_INL
#include "plain_index_inl.h"
#undef YANDEX_MAPS_WIKI_TOPO_PLAIN_INDEX_INL
