#include<boost/shared_ptr.hpp>
#include<boost/weak_ptr.hpp>
#include<map>
#include<list>
#include<iostream>
#include<stdint.h>
using namespace std;
using namespace boost;

class Employee {
    public:
        Employee(uint64_t id, string name);
        virtual void print() const;
        uint64_t getId();
        const string &getName() const;
        virtual const string getTitle() const;
	uint64_t getSalary();
	void setSalary(uint64_t s);
    private:
        uint64_t id_;
        const string name_;
	uint64_t salary_;
};
Employee::Employee(uint64_t id, string name)
    : id_(id), name_(name), salary_(0)
{ }
void Employee::print() const {
    cout << getTitle() << ":" << endl;
    cout << "    " << name_ << endl;
}
uint64_t Employee::getId() { return id_; }
const string &Employee::getName() const { return name_; }
const string Employee::getTitle() const { return "Basic Employee"; }
uint64_t Employee::getSalary() { return salary_; }
void Employee::setSalary(uint64_t s) { salary_ = s; }

class Manager : public Employee {
    public:
        Manager(uint64_t id, string name);
        virtual void print() const;
        void add_report(shared_ptr<Employee> emp);
        virtual const string getTitle() const;
    protected:
        list<shared_ptr<Employee> > direct_reports_;
};
Manager::Manager(uint64_t id, string name)
    : Employee(id, name)
{}
void Manager::print() const {
    cout << getTitle() << ":" << endl;
    cout << "\t" << getName() << endl;
    cout << "\t" << "Supervises:" << endl;
    if (direct_reports_.empty()) {
        cout << "\t\tNobody" << endl;
    } else {
        list<shared_ptr<Employee> >::const_iterator it;
        for(it = direct_reports_.begin(); it != direct_reports_.end(); it++) {
            cout << "\t\t\t" << (*it)->getTitle() << " " << (*it)->getName() << endl;
        }
    }
}
const string Manager::getTitle() const { return "Manager"; }
void Manager::add_report(shared_ptr<Employee> e) {
    direct_reports_.push_back(e);
}

class President : public Manager {
    public:
        President(uint64_t id, string name);
        virtual const string getTitle() const;
};
President::President(uint64_t id, string name) : Manager(id, name) {}
const string President::getTitle() const { return "President"; }

class Developer : public Employee {
    public:
        Developer(uint64_t id, string name);
        virtual void print() const;
        virtual const string getTitle() const;
};
Developer::Developer(uint64_t id, string name)
    : Employee(id, name)
{}
void Developer::print() const {
    cout << getTitle() << ":" << endl;
    cout << "\t" << getName() << endl;
}
const string Developer::getTitle() const { return "Developer"; }

struct lt_employee
{
    bool operator()(const shared_ptr<Employee> &e1, const shared_ptr<Employee> &e2)
    {
        return e1->getId() < e2->getId();
    }
};

struct lt_uint64
{
    bool operator()(const uint64_t &a, const uint64_t &b)
    {
        return a < b;
    }
};

int main(int argc, char** argv) {
    map<uint64_t,shared_ptr<const Employee>,lt_uint64> db;
    map<uint64_t,shared_ptr<const Employee>,lt_uint64>::iterator it;

    shared_ptr<Manager> hank(new President(0,"Hank"));
    db[0] = hank;
    shared_ptr<Manager> steve(new Manager(1,"Steve"));
    db[1] = steve;
    hank->add_report(steve);
    shared_ptr<Employee> colin(new Developer(2,"Colin"));
    steve->add_report(colin);
    db[2] = colin;
    shared_ptr<Employee> aryan(new Developer(3,"Aryan"));
    steve->add_report(aryan);
    db[3] = aryan;

    for(it = db.begin(); it != db.end(); it++) {
        (*it).second->print();
    }




    return 0;
}