#pragma once

#include <maps/libs/geolib/include/point.h>
#include <yandex/maps/wiki/common/geom.h>
#include <yandex/maps/wiki/common/misc.h>
#include <yandex/maps/wiki/revision/revisionid.h>
#include <yandex/maps/wiki/configs/editor/fwd.h>

#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/optional.hpp>

#include <pqxx/pqxx>

#include <cstddef>
#include <string>
#include <list>
#include <set>
#include <vector>
#include <map>
#include <memory>

namespace maps::wiki {

using namespace configs::editor;

typedef revision::DBID TOid;
typedef revision::DBID TId;
typedef revision::DBID TBranchId;
typedef revision::UserID TUid;
typedef unsigned short TZoom;
typedef revision::RevisionID TRevisionId;
typedef revision::DBID TCommitId;
typedef int TDirection;
typedef geolib3::Point2 TGeoPoint;
typedef geolib3::Point2 TMercatorPoint;
typedef std::list<std::string> StringList;
typedef std::vector<std::string> StringVec;
typedef std::set<std::string> StringSet;
typedef std::map<std::string, std::string> StringMap;
typedef std::set<TRevisionId> RevisionIds;
typedef std::set<TOid> TOIds;
typedef std::set<TCommitId> TCommitIds;
typedef std::multimap<std::string, std::string> StringMultiMap;
typedef common::Geom Geom;
typedef common::GeometryPtr GeometryPtr;
typedef common::GeosGeometryPtr GeosGeometryPtr;
typedef common::SpatialRefSystem SpatialRefSystem;
typedef common::StringSet StringSet;

const size_t badIndex = size_t(-1);

static const std::string s_emptyString;

//TODO: Should we use global constanst wich are defined by libs/common/geom?
static const std::string s_geojsonGeomTypeNamePoint = "Point";
static const std::string s_geojsonGeomTypeNameLine = "LineString";
static const std::string s_geojsonGeomTypeNamePolygon = "Polygon";

enum class AccessMode { ReadWrite, ReadOnly };

const TZoom MAX_ZOOM = 23;
const size_t DOUBLE_FORMAT_PRECISION = 12;


typedef std::string Token;

class GeoObject;
typedef std::shared_ptr<GeoObject> ObjectPtr;

using ObjectPredicate = std::function<bool(const GeoObject*)>;

//database
typedef pqxx::transaction_base Transaction;

template< typename Container >
Container split(const std::string& str, char delimiter=' ')
{
    Container res;
    boost::split(res, str, [delimiter](char c) { return c == delimiter; });
    if (res.size() ==  1 && res.begin()->empty()) {
        return Container();
    }
    return res;
}

template< typename Container >
Container splitCast(const std::string& str, char delimiter=' ')
{
    Container res;
    if (str.empty()) {
        return res;
    }
    StringList parts;
    boost::split(parts, str, [delimiter](char c) { return c == delimiter; });
    std::insert_iterator<Container> it(res, res.end());
    for (const std::string& s : parts) {
        (*it) = boost::lexical_cast<typename Container::value_type>(s);
    }
    return res;
}

using std::make_unique;

} // namespace maps::wiki
