#pragma once

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

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

#include <string>

namespace maps {
namespace wiki {
namespace topo {

enum class ErrorCode
{
    Unspecified = -1,
    Unsupported,

    // graph restrictions
    SelfIntersection,
    SelfOverlap,

    // Topology restrictions
    InvalidRestrictions,
    TooManyIntersectionsWithNetwork,
    TooManyIntersectionsWithElement,
    DegenerateSegment,
    TooLongSegment,
    DegenerateEdge,
    TooLongEdge,
    MergeOfOverlappedEdgesForbidden,
    NodeDeletionForbidden,

    // unexpected situations
    UnexpectedIntersection,
    AmbiguousSnapping
};

class GeomProcessingError : public maps::LogicError
{
public:
    explicit GeomProcessingError(ErrorCode errorCode)
        : errorCode_(errorCode)
    {}
    GeomProcessingError(ErrorCode errorCode, const std::string& what)
        : maps::LogicError(what)
        , errorCode_(errorCode)
    {}

    ErrorCode errorCode() const { return errorCode_; }

private:
    const ErrorCode errorCode_;
};

std::string errorCodeToString(ErrorCode errorCode);


class GeomProcessingErrorWithLocation : public GeomProcessingError
{
public:
    GeomProcessingErrorWithLocation(
        ErrorCode errorCode,
        const geolib3::Point2& location);

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

private:
    geolib3::Point2 location_;
};


class InvalidFaceError : public maps::LogicError
{
public:
    InvalidFaceError(FaceID faceId, NodeIDVector nodeIds)
        : faceId_(faceId)
        , nodeIds_(std::move(nodeIds))
    {}

    ~InvalidFaceError() noexcept (true) {}

    FaceID faceId() const { return faceId_; }
    const NodeIDVector& nodeIds() const { return nodeIds_; }

private:
    const FaceID faceId_;
    const NodeIDVector nodeIds_;
};

} // namespace topo
} // namespace wiki
} // namespace maps
