#pragma once

#include "common.h"

#include <yandex/maps/wiki/configs/editor/common.h>

namespace maps {
namespace wiki {

class GeoObject;
class ObjectsCache;
class SlaveInfo;

class TableValues
{
public:
    bool empty() const
    { return rows_.empty(); }
    size_t numRows() const
    { return rows_.size(); }
    const StringMultiMap& values(size_t row) const
    { return rows_[row]; }
    StringMultiMap keyColumnsValues(size_t row, const AttrDefPtr& attrDef) const;

    //! Return first value of column in a row
    const std::string& value(size_t row, const std::string& column) const
    {
        auto val = rows_[row].find(column);
        return (val == rows_[row].end()) ? s_emptyString : val->second;
    }

    void addRow(StringMultiMap&& rowColumnValues)
    { rows_.emplace_back(std::move(rowColumnValues)); }

    /**
    * Return rows, grouped by columns
    * keeping original row indexes
    */
    typedef std::multimap< StringVec, std::pair<size_t, StringMultiMap> > GroupedRows;
    GroupedRows groupBy(const StringSet& columns)const
    {
        GroupedRows groups;
        for (size_t r = 0; r < rows_.size(); ++r) {
            StringVec key;
            for (const auto& column : columns) {
                StringMultiMap::const_iterator rowColVal = rows_[r].find(column);
                key.push_back(rowColVal != rows_[r].end() ? rowColVal->second : "");
            }
            groups.insert(std::make_pair(key, std::make_pair(r, rows_[r])));
        }
        return groups;
    }
    bool contains(const TableValues& other) const;
    bool equal(const TableValues& other) const { return contains(other) && other.contains(*this);}

private:
    std::vector<StringMultiMap> rows_;
};

class TableAttributesValues
{
public:
    bool empty() const { return tableAttributesValues_.empty(); }

    void clear() { tableAttributesValues_.clear(); }

    void add(const std::string& attrId, TableValues&& tableValues);
    const TableValues& find(const std::string& attrId) const;
    StringSet attrNames() const;

private:
    std::map<std::string, TableValues> tableAttributesValues_;
};

void readTableAttributesFromSlaveInfos(ObjectsCache& cache, TOid objectId);
void writeTableAttributesToSlaveInfos(ObjectsCache& cache, TOid objectId);

bool
areTableAttrsEqual(ObjectPtr obj1, ObjectPtr obj2);

void
validateTableValuesSize(
    const AttrDefPtr& attrDef, const TableValues& tableValues,
    const std::string& attributeId);

} // namespace wiki
} // namespace maps
