#pragma once

#include "common.h"

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

namespace maps {
namespace wiki {
const double STRONG_CALCULATION_TOLERANCE = geolib3::EPS * 0.5;
const double CALCULATION_TOLERANCE = 0.001;

geolib3::Polyline2 geomToPolyline(const Geom& geom);
geolib3::Point2 center(const Geom& geom);
Geom polylineToGeom(const geolib3::Polyline2& geom);

geolib3::Point2 geomToPoint(const Geom& geom);
Geom pointToGeom(const geolib3::Point2& geom);

geolib3::BoundingBox boundingBox(const Geom& geom);


enum class AntiMeridianId { East, West };

enum class AntiMeridianAdjustPolicy { Adjust, Ignore };

struct AntiMeridianAdjustResult
{
    Geom geom;
    AntiMeridianId id;
};

/**
 * Throw ERR_GEOMETRY_INTERSECTS_180_MERIDIAN if object overlaps with
 *   Anti-Meridiane or moves across it to other hemisphere.
 * Throw INVALID_GEOMETRY_MAX_LENGTH if geom bounds are too big.
 * Throw INVALID_GEOMETRY if adjustment is done but result does not validate.
 */

/**
 * Adjusts coords to one hemisphere in regard to Anti-Meridian (180).
 * Applies for polyline or polygon coordinate sequence.
 */
void
adjustToAntiMeridian(geos::geom::CoordinateSequence* coords, double tolerance);

/**
 * Returns result if geom touches Anti-Meridian (180).
 * Geometry coordinates are adjusted to Anti-Meridian position.
 * Applies for polyline or polygon geom.
 */
boost::optional<AntiMeridianAdjustResult>
adjustToAntiMeridian(const Geom& geom, double tolerance);

/**
 * Adjusts new point object position to same hemisphere as its old position.
 * Applies when newPos is within tolerance from Anti-Meridian.
 */
geolib3::Point2
adjustToAntiMeridian(
    const geolib3::Point2& oldPos, const geolib3::Point2& newPos, double tolerance);

/**
 * Adjusts point object position to given hemisphere.
 * Applies when pos is within tolerance from Anti-Meridian.
 */
geolib3::Point2
adjustToAntiMeridian(
    AntiMeridianId id, const geolib3::Point2& pos, double tolerance);

void tryFixRing(std::vector<geos::geom::Coordinate>& points);

} // namespace wiki
} // namespace maps
