#include <yandex/maps/wiki/geom_tools/conversion.h>
#include <maps/libs/common/include/exception.h>

#include <maps/libs/geolib/include/conversion.h>
#include <maps/libs/geolib/include/distance.h>

#include <geos/geom/LineString.h>
#include <geos/geom/Coordinate.h>

namespace maps {
namespace wiki {
namespace geom_tools {

template <>
geolib3::Polyline2 convert<GeosGeometry, geolib3::Polyline2>(const GeosGeometry& geom)
{
    const geos::geom::LineString* ls = dynamic_cast<const geos::geom::LineString*>(&geom);
    REQUIRE(ls, "Geom is not LineString");

    geolib3::PointsVector points;
    points.reserve(ls->getNumPoints());

    for (size_t i = 0; i < ls->getNumPoints(); ++i) {
        const geos::geom::Coordinate& p = ls->getCoordinateN(i);
        points.emplace_back(p.x, p.y);
    }

    return geolib3::Polyline2(std::move(points));
}

namespace {

constexpr double MAX_LATITUDE = 89;

}

double correctGeoDistanceToMerc(
    double geoDistance,
    const geolib3::Point2& pointMerc)
{
    ASSERT(geolib3::mercator2GeoPoint(pointMerc).y() <= MAX_LATITUDE);
    return geolib3::toMercatorUnits(geoDistance, pointMerc);
}

double correctMercDistanceToGeo(
    double mercDistance,
    const geolib3::Point2& pointMerc)
{
    ASSERT(geolib3::mercator2GeoPoint(pointMerc).y() <= MAX_LATITUDE);
    return geolib3::toMeters(mercDistance, pointMerc);
}

geolib3::BoundingBox makeVicinityBboxMerc(
    const geolib3::Point2& centerMerc,
    double halfDistGeo)
{
    double halfDistMerc = correctGeoDistanceToMerc(halfDistGeo, centerMerc);
    return geolib3::BoundingBox(centerMerc, halfDistMerc * 2, halfDistMerc * 2);
}

} // namespace geom_tools
} // namespace wiki
} // namespace maps
