#pragma once

#include <maps/libs/geolib/include/distance.h>
#include <maps/libs/geolib/include/point.h>
#include <maps/libs/geolib/include/polyline.h>
#include <maps/libs/geolib/include/bounding_box.h>
#include <maps/libs/geolib/include/conversion.h>
#include <maps/libs/geolib/include/spatial_relation.h>

#include <algorithm>
#include <limits>
#include <utility>

namespace maps {

namespace geolib3 {

class Direction2;
class Polygon2;

}

namespace wiki {
namespace validator {
namespace utils {

geolib3::BoundingBox boundingBox(const geolib3::PointsVector& points);

bool isPointInsideRing(
        const geolib3::Point2& point,
        const geolib3::PointsVector& ring);

double ccwAngle(const geolib3::Direction2& from, const geolib3::Direction2& to);

double intersectionLength(
        const geolib3::PolylinesVector& polylines,
        const geolib3::Polygon2& polygon);

template<class Geometry>
double mercatorDistanceRatio(const Geometry& geom)
{
    double latitude = geolib3::mercator2GeoPoint(geom.boundingBox().center()).y();
    return cos(latitude * M_PI / 180);
}

template<class GeomInputIterator>
double distance(
        const geolib3::Point2& point,
        GeomInputIterator begin,
        GeomInputIterator end)
{
    double result = std::numeric_limits<double>::infinity();

    while (begin != end) {
        result = std::min(result, geolib3::distance(point, *begin));
        ++begin;
    }

    return result;
}

template<class GeomInputIterator>
double distance(
        const geolib3::Point2& point,
        std::pair<GeomInputIterator, GeomInputIterator> range)
{ return distance(point, range.first, range.second); }


template <class Geometry, class AnotherGeometry>
bool intersects(const Geometry& geom, const AnotherGeometry& anotherGeom)
{ return geolib3::spatialRelation(geom, anotherGeom, geolib3::Intersects); }


template <class Geometry, class AnotherGeometry>
bool contains(const Geometry& geom, const AnotherGeometry& anotherGeom)
{ return geolib3::spatialRelation(geom, anotherGeom, geolib3::Contains); }

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