#pragma once

#include "polygonal_adapters.h"
#include "cut_line.h"

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

#include <maps/libs/common/include/exception.h>

#include <list>

namespace maps {
namespace wiki {
namespace geom_tools {

class PolygonCutterError : public maps::Exception {
public:
    explicit PolygonCutterError(const geolib3::Point2& location)
        : location_(location)
    {}

    PolygonCutterError(const geolib3::Point2& location, const std::string& what)
        : maps::Exception(what)
        , location_(location)
    {}

    const geolib3::Point2& location() const { return location_; }

private:
    geolib3::Point2 location_;
};

class PolygonCutter {
public:
    explicit PolygonCutter(const CutLine& cutLine)
        : cutLine_(cutLine)
    {}

    const CutLine& cutLine() const { return cutLine_; }

    struct Result {
        GeolibPolygonVector less;
        GeolibPolygonVector greater;
    };

    boost::optional<Result> operator () (const geolib3::Polygon2& polygon) const;

private:
    struct RingCutResult {
        std::list<geolib3::PointsVector> lessBorders;
        std::list<geolib3::PointsVector> greaterBorders;
    };

    // less or greater
    RingAdapter adjustRingCoords(const RingAdapter& ring, Relation relation) const;

    RingCutResult cutRing(const RingAdapter& ring) const;

    std::list<RingAdapter> restoreRings(
        const std::list<geolib3::PointsVector>& borders, Relation relation) const;

    boost::optional<GeolibPolygonVector>
    buildPolygons(RingList&& shells, RingList&& holes) const;

    CutLine cutLine_;
};

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