#pragma once

#include "../common.h"
#include "../topology_data.h"
#include "../utils/topology_data_proxy.h"
#include "../utils/sync.h"

namespace maps {
namespace wiki {
namespace topology_fixer {

using NodeIdToFaceIds = std::map<NodeId, OrderedIdSet>;

class FaceGapRemover {
public:
    FaceGapRemover(
            double maxGapWidth,
            double maxGapLengthFactor)
        : maxGapWidth_(maxGapWidth)
        , maxGapLengthFactor_(maxGapLengthFactor)
    {}

    void operator()(TopologyData& data, FaceLocker& locker, ThreadPool& pool) const;

private:
    class Batch {
    public:
        Batch(
                utils::TopologyDataProxy& data,
                FaceLocker& locker,
                NodeIdToFaceIds nodeIdToFaceIds,
                double maxGapWidth,
                double maxGapLengthFactor)
            : data_(data)
            , locker_(locker)
            , nodeIdToFaceIds_(std::move(nodeIdToFaceIds))
            , maxGapWidth_(maxGapWidth)
            , maxGapLengthFactor_(maxGapLengthFactor)
        {}

        void operator () ()
        {
            try {
                doWork();
            } catch (const maps::Exception& e) {
                ERROR() << e;
                throw;
            } catch (const std::exception& e) {
                ERROR() << e.what();
                throw;
            }
        }

    private:
        void doWork();

        void processEdges(
            NodeId commonNodeId,
            EdgeId edgeId1, FaceId faceId1, EdgeId edgeId2, FaceId faceId2);

        utils::TopologyDataProxy& data_;
        FaceLocker& locker_;
        NodeIdToFaceIds nodeIdToFaceIds_;
        double maxGapWidth_;
        double maxGapLengthFactor_;
    };

    double maxGapWidth_;
    double maxGapLengthFactor_;
};

} // namespace topology_fixer
} // namespace wiki
} // namespace maps
