#pragma once

#include "common.h"
#include "relation_infos.h"

#include <boost/noncopyable.hpp>

namespace maps {
namespace wiki {

class ObjectsCache;
class RelationObject;
class GeoObjectCollection;

class RelationsManager : public boost::noncopyable
{
public:
    explicit RelationsManager(ObjectsCache& cache);

    void loadRelations(RelationType type, const TOIds& ids);
    void loadRelations(RelationType type, const TOIds& ids, const StringSet& roleIds);

    void loadRelations(RelationType type, const std::map<TOid, StringSet>& oidsToRolesMap);

    void loadRelations(RelationType type, TOid id, RelativesLimit limit);
    void loadRelations(RelationType type, TOid id, const StringSet& roleIds, RelativesLimit limit);

    void createRelation(TOid masterId, TOid slaveId, const std::string& roleId);
    void deleteRelation(TOid masterId, TOid slaveId, const std::string& roleId);

    void updateRelations(const GeoObjectCollection& relations);

    const std::vector<const RelationObject*>& cachedRelations(RelationType type, TOid id) const;

    bool isRelationExists(TOid masterId, TOid slaveId, const std::string& roleId) const;

private:
    void loadRelationsWithCumulativeLimit(RelationType type, GeoObject& object,
        const StringSet& roleIds, size_t limit);
    void loadRelationsWithPerRoleLimit(RelationType type, GeoObject& object, size_t limit);
    void loadRelationsWithPerRoleLimit(RelationType type, GeoObject& object,
        const StringSet& roleIds, size_t limit);

    void processRelations(RelationType type, GeoObjectCollection& relations);

    ObjectsCache& cache_;

    struct RelationKey
    {
        RelationKey(const RelationObject* obj);
        RelationKey(
            TOid masterId, TOid slaveId,
            const std::string& roleId,
            const std::string& masterCategoryId,
            const std::string& slaveCategoryId);

        bool operator < (const RelationKey& other) const;

        const TOid masterId;
        const TOid slaveId;
        const std::string roleId;
        const std::string masterCategoryId;
        const std::string slaveCategoryId;
    };

    std::map<RelationKey, const RelationObject*> cachedRelations_;
    std::map<TOid, std::vector<const RelationObject*>> cachedMasterRelations_;
    std::map<TOid, std::vector<const RelationObject*>> cachedSlaveRelations_;
};

} // namespace wiki
} // namespace maps
