#pragma once

#include "types.h"
#include "intersector.h"

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

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

#include <boost/optional.hpp>

#include <ostream>
#include <memory>
#include <vector>


namespace maps {
namespace wiki {
namespace topo {
namespace geom {

std::ostream& operator<<(std::ostream& out, const SplitPolyline& polyline);

template <class TObject>
std::ostream& operator<<(std::ostream& out, const std::vector<TObject>& objects)
{
    out << "[";
    for (const auto& object: objects) {
        out << " " << object;
    }
    return out << " ]";
}

template <class TObject>
std::ostream& operator<<(std::ostream& out, const std::shared_ptr<TObject>& shared)
{
    if (shared) {
        return out << shared.get() << ":" << *shared;
    } else {
        return out << "null";
    }
}

template <class TObject>
std::ostream& operator<<(std::ostream& out, const boost::optional<TObject>& optional)
{
    if (optional) {
        return out << *optional;
    } else {
        return out << "?";
    }
}

std::ostream& operator<<(std::ostream& out, const SplitPoint& point);
std::ostream& operator<<(std::ostream& out, const SnapPoint& point);

std::ostream& operator<<(std::ostream& out, const SplitPolyline& polyline);
std::ostream& operator<<(std::ostream& out, const SnapPolyline& polyline);

std::ostream& operator<<(std::ostream& out, const SourceEdgeID& sourceEdgeId);

std::ostream& operator<<(std::ostream& out, const SplitEdgeEventData&);
std::ostream& operator<<(std::ostream& out, const Intersector::Events& events);


} // namespace geom
} // nemaspace topo
} // nemaspace wiki

namespace geolib3 {

std::ostream& operator<<(std::ostream& out, const Point2& point);
std::ostream& operator<<(std::ostream& out, const Segment2& segment);
std::ostream& operator<<(std::ostream& out, const Polyline2& polyline);

} // namespace geolib3
} // namespace maps
