#pragma once

#include <maps/libs/json/include/builder.h>
#include <maps/libs/common/include/exception.h>
#include <maps/libs/geolib/include/polygon.h>

#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include <pqxx/pqxx>

#include <string>
#include <sstream>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <cstdint>
#include <vector>
#include <list>

namespace maps {

typedef int64_t DBID;
typedef std::vector<std::string> Strings;
typedef std::unordered_set<std::string> StringSet;
typedef std::unordered_map<std::string, std::string> StringMap;

struct Params;

class JsonFileAttributes {
public:
    JsonFileAttributes(const Params& params, pqxx::transaction_base& tr);
    void write(json::ObjectBuilder& builder) const;
private:
    std::unordered_map<std::string, std::string> attributes_;
};

bool isPqxxArray(const std::string& value);

std::vector<DBID> parseDBIDArray(const std::string& value);
std::vector<DBID> parseUniqueDBIDArray(const std::string& value);

pqxx::result workExec(pqxx::transaction_base& tr, const std::string& query);
std::vector<DBID> loadIds(pqxx::transaction_base& tr, const std::string& query);
void setSearchPath(pqxx::transaction_base& tr, const std::string& schema);

template <typename Iter>
std::string
valuesToString(Iter begin, Iter end)
{
    ASSERT(begin != end);

    std::ostringstream os;
    os << *begin;
    while (++begin != end) {
        os << ',' << *begin;
    }
    return os.str();
}

template <typename Cont>
std::string
valuesToString(const Cont& cont)
{
    return valuesToString(cont.begin(), cont.end());
}

template <typename Ids>
std::string expandSqlTemplate(const std::string& templ, const Ids& ids)
{
    return str(boost::format(templ) % ("(" + valuesToString(ids) + ")"));
}

} //namespace maps
