#include "geom_objects_view_impl.h"
#include "bbox_intersects_op.h"

#include <yandex/maps/wiki/validator/objects/address_point.h>
#include <yandex/maps/wiki/validator/objects/arrival_point.h>
#include <yandex/maps/wiki/validator/objects/building.h>
#include <yandex/maps/wiki/validator/objects/center.h>
#include <yandex/maps/wiki/validator/objects/edge.h>
#include <yandex/maps/wiki/validator/objects/indoor_level.h>
#include <yandex/maps/wiki/validator/objects/indoor_plan.h>
#include <yandex/maps/wiki/validator/objects/junction.h>
#include <yandex/maps/wiki/validator/objects/road_element.h>
#include <yandex/maps/wiki/validator/objects/parking_controlled_zone.h>
#include <yandex/maps/wiki/validator/objects/parking_lot.h>
#include <yandex/maps/wiki/validator/objects/polyline_feature.h>
#include <yandex/maps/wiki/validator/objects/poi.h>
#include <yandex/maps/wiki/validator/objects/poi_entrance.h>
#include <yandex/maps/wiki/validator/objects/point_feature.h>
#include <yandex/maps/wiki/validator/objects/polygon_feature.h>
#include <yandex/maps/wiki/validator/objects/region.h>
#include <yandex/maps/wiki/validator/objects/road_marking_linear.h>
#include <yandex/maps/wiki/validator/objects/road_marking_point.h>
#include <yandex/maps/wiki/validator/objects/road_marking_polygonal.h>
#include <yandex/maps/wiki/validator/objects/road_surface.h>
#include <yandex/maps/wiki/validator/objects/service_polygon.h>
#include <yandex/maps/wiki/validator/objects/transport_airport.h>
#include <yandex/maps/wiki/validator/objects/transport_metro_exit.h>
#include <yandex/maps/wiki/validator/objects/transport_metro_station.h>
#include <yandex/maps/wiki/validator/objects/transport_element.h>
#include <yandex/maps/wiki/validator/objects/transport_stop.h>
#include <yandex/maps/wiki/validator/objects/transport_operator.h>

#include <maps/libs/geolib/include/spatial_relation.h>
#include <maps/libs/geolib/include/polygon.h>

namespace maps {
namespace wiki {
namespace validator {

namespace gl = maps::geolib3;

template<class Object>
GeomObjectsView<Object>::GeomObjectsView(GeomObjectsView<Object>::Impl* impl)
    : impl_(impl)
{ }

template<class Object>
GeomObjectsView<Object>::~GeomObjectsView() = default;

template<class Object>
void GeomObjectsView<Object>::visit(
        std::function<void(const Object*)> visitor) const
{ impl_->visit(visitor); }

template<class Object>
void GeomObjectsView<Object>::batchVisit(
        std::function<void(const Object*)> visitor,
        size_t batchSize) const
{ impl_->batchVisit(visitor, batchSize); }

template<class Object>
void GeomObjectsView<Object>::batchVisitObjects(
        const std::vector<const Object*>& objects,
        std::function<void(const Object*)> visitor,
        size_t batchSize) const
{ impl_->batchVisitObjects(objects, visitor, batchSize); }

template<class Object>
bool GeomObjectsView<Object>::loaded(TId id) const
{ return impl_->objectIdIndex().contains(id); }

template<class Object>
const Object* GeomObjectsView<Object>::byId(TId id) const
{ return impl_->objectIdIndex().byId(id); }

template<class Object>
std::vector<const Object*>
GeomObjectsView<Object>::byBbox(const gl::BoundingBox& bbox) const
{
    std::vector<const Object*> ret;

    auto queryResult = impl_->spatialIndex().find(bbox);
    if (queryResult.first == queryResult.second) {
        return ret;
    }

    BboxIntersectsOp<typename Object::TGeom> bboxIntersects(bbox);
    for (auto iter = queryResult.first; iter != queryResult.second; ++iter) {
        if (bboxIntersects(iter->geometry())) {
            ret.push_back(iter->value());
        }
    }
    return ret;
}


template class GeomObjectsView<RoadElement>;
template class GeomObjectsView<Center>;
template class GeomObjectsView<AddressPoint>;
template class GeomObjectsView<ArrivalPoint>;
template class GeomObjectsView<Building>;
template class GeomObjectsView<IndoorLevel>;
template class GeomObjectsView<IndoorPlan>;
template class GeomObjectsView<Junction>;
template class GeomObjectsView<Poi>;
template class GeomObjectsView<PoiEntrance>;
template class GeomObjectsView<PointFeature>;
template class GeomObjectsView<PolygonFeature>;
template class GeomObjectsView<Edge>;
template class GeomObjectsView<ParkingControlledZone>;
template class GeomObjectsView<ParkingLot>;
template class GeomObjectsView<PolylineFeature>;
template class GeomObjectsView<Region>;
template class GeomObjectsView<ServicePolygon>;
template class GeomObjectsView<TransportAirport>;
template class GeomObjectsView<TransportMetroExit>;
template class GeomObjectsView<TransportMetroStation>;
template class GeomObjectsView<TransportElement>;
template class GeomObjectsView<TransportStop>;
template class GeomObjectsView<TransportOperator>;
template class GeomObjectsView<RoadSurface>;
template class GeomObjectsView<RoadMarkingPolygonal>;
template class GeomObjectsView<RoadMarkingLinear>;
template class GeomObjectsView<RoadMarkingPoint>;

} // namespace validator
} // namespace wiki
} // namespace maps
