#include <set>
#include <iostream>
#include <memory>

class Node;
typedef std::shared_ptr<Node> NodePtr;
class Node {
  struct NodeComp {
      bool operator()(const NodePtr& p1, const NodePtr& p2) const
      {
          return p1->getID() < p2->getID();
      }
  };
  int id;
  std::set<NodePtr, NodeComp> neighbors;
public:
  Node() {}
  Node(int newID) : id(newID) {}
  int getID() const { return id; }
  void addNeighbor(NodePtr newNode) 
  {
      neighbors.insert(newNode);
  }
  const std::set<NodePtr, NodeComp>& getNeighbors() const
  {
      return neighbors;
  }
  bool isNeighbor(int searchID) const
  {
      return neighbors.count(std::make_shared<Node>(searchID));
  }
};

int main()
{

  NodePtr n0 = std::make_shared<Node>(0);
  NodePtr n1 = std::make_shared<Node>(1);
  NodePtr n2 = std::make_shared<Node>(2);
  std::cout << n0->getID() << " adding neighbor " << n1->getID() << '\n';
  n0->addNeighbor(n1);
  std::cout << n0->getID() << " adding neighbor " << n2->getID() << '\n';
  n0->addNeighbor(n2);
  std::cout << n1->getID() << " adding neighbor " << n0->getID() << '\n';
  n1->addNeighbor(n0);
  std::cout << n2->getID() << " adding neighbor " << n1->getID() << '\n';
  n2->addNeighbor(n1);
  std::cout << n2->getID() << " adding neighbor " << n1->getID() << '\n';
  n2->addNeighbor(n1);

  int id = n0->getID();
  auto neighbors = n0->getNeighbors();
  std::cout << id << " has " << neighbors.size() << " neighbors. They are: \n";

  for (auto nb = neighbors.begin(); nb != neighbors.end() ; nb++)
  {
    auto neighborsList = (*nb)->getNeighbors();
    std::cout << "   " << (*nb)->getID() << ", which has " << neighborsList.size() << " neighbors: ";
    for(auto i = neighborsList.begin(); i!=neighborsList.end(); ++i)
        std::cout << (*i)->getID() << ' ';
    std::cout << '\n';
  }
  std::cout << std::boolalpha 
       << "is 0 a neighbor of 1? " << n1->isNeighbor(0) << '\n'
       << "is 1 a neighbor of 0? " << n0->isNeighbor(1) << '\n'
       << "is 2 a neighbor of 0? " << n0->isNeighbor(2) << '\n'
       << "is 3 a neighbor of 0? " << n0->isNeighbor(3) << '\n';
}
