#include <vector>
#include <utility>
#include <algorithm>
#include <string>
#include <map>
#include <set>


class GameDatabase {
 public:
  GameDatabase() = default;

  void Insert(ObjectId id, string name, size_t x, size_t y) {
    if (objects_container.end() != objects_container.find(id)) {
      obj_sorted_by_name[objects_container[id].name].erase(id);
      obj_sorted_by_pos[{objects_container[id].x,
      objects_container[id].y}].erase(id);
    }
    obj_sorted_by_name[name].insert(id);
    obj_sorted_by_pos[{x, y}].insert(id);
    objects_container[id] = { id, name, x, y };
  }
  void Remove(ObjectId id) {
    if (objects_container.end() != objects_container.find(id)) {
      obj_sorted_by_name[objects_container[id].name].erase(id);
      obj_sorted_by_pos[{ objects_container[id].x,
      objects_container[id].y }].erase(id);
      objects_container.erase(id);
    }
  }
  vector<GameObject> DataByName(string name) {
    std::vector<GameObject> res;
    if (obj_sorted_by_name.end() != obj_sorted_by_name.find(name)) {
      for (auto i = obj_sorted_by_name[name].begin();
      i != obj_sorted_by_name[name].end(); i++)
        res.push_back(objects_container[*i]);
    }
    return res;
  }
  vector<GameObject> DataByPosition(size_t x, size_t y) {
    std::vector<GameObject> res;
    if (obj_sorted_by_pos.end() != obj_sorted_by_pos.find({ x, y })) {
      for (auto i = obj_sorted_by_pos[{ x, y }].begin();
      i != obj_sorted_by_pos[{ x, y }].end(); i++)
        res.push_back(objects_container[*i]);
    }
    return res;
  }
  vector<GameObject> Data() const {
    std::vector<GameObject> res;
    for (auto i = objects_container.begin();
    i != objects_container.end(); i++)
      res.push_back(i->second);
    return res;
  }

 protected:
    struct byIdDecrease {
      bool operator()(const ObjectId& lhs,
      const ObjectId& rhs) const {
        return lhs > rhs;
      }
    };
  std::map < ObjectId, GameObject, byIdDecrease > objects_container;
  std::map < std::string, std::set < ObjectId, byIdDecrease>>
  obj_sorted_by_name;
  std::map < std::pair<size_t, size_t >, std::set < ObjectId,
  byIdDecrease>> obj_sorted_by_pos;
};