#include <vector>
#include <memory>
#include <iostream>


using namespace std;


using Money = int;
using Factor = double;
using Id = int;

class HRSystem;
class Staff;
using UStaff = unique_ptr<Staff>;

class Observer {
public:
    virtual void update() = 0;
};

class HRSystem {
public:
    HRSystem() : staffId_(0), baseSalary_(4242) {}

    UStaff createEmployee(Factor factor); //nowy pracownik etatowy, zwraca Id
    UStaff createTrainee();  //nowy stazysta, zwraca Id
    UStaff createManager(Factor factor);  //nowy kierownik, zwraca Id

    Money getBaseSalary() const { return baseSalary_; }
    void setBaseSalary(Money m) {
        baseSalary_ = m;
        for(Observer* o : obs_) { o->update(); }
    }
private:
    void reg(Observer* o) { obs_.push_back(o); }
    int staffId_;
    Money baseSalary_;

    vector<Observer*> obs_;

};


//hierarchia osob zatrudnionych
class Staff : public Observer {
public:
    Staff(HRSystem& owner, Id id, Factor f = 1.0) : owner_(owner), id_(id), factor_(f)  {
        salary_ = static_cast<Money>(owner_.getBaseSalary() * factor_);
    }

    Money getSalary() const { return salary_; }
    void setSalary(Money m) { salary_ = m; }
    virtual ~Staff() {}
protected:
    HRSystem& owner_;
    Id id_;

    void update() { salary_ = owner_.getBaseSalary() * factor_; }

private:
    Factor factor_;
    Money salary_;
};

class Employee : public Staff {
public:
    Employee(HRSystem& owner, Id id, Factor factor) : Staff(owner, id, factor) {}
};

class Trainee : public Staff {
public:
    Trainee(HRSystem& owner, Id id) : Staff(owner, id){}

};

class Manager : public Staff {
public:
    Manager(HRSystem& owner, Id id, Factor factor) : Staff(owner, id, factor) {}
    void addSubordinate(const Employee* e);
private:
    vector<const Employee*> sub_;
};

UStaff HRSystem::createEmployee(Factor factor) {
    Id id = ++staffId_;
    UStaff s =  make_unique<Employee>(*this, id, factor);
    reg(s.get());
    return s;
}

UStaff HRSystem::createTrainee() {
    Id id = ++staffId_;
    UStaff s =  make_unique<Trainee>(*this, id);
    reg(s.get());
    return s;
}

UStaff HRSystem::createManager(Factor factor) {
    Id id = ++staffId_;
    UStaff s = make_unique<Manager>(*this, id, factor);
    reg(s.get());
    return s;
}




int main() {
    HRSystem hr;
    vector<UStaff> staff;
    staff.push_back( hr.createEmployee(1.0) );
    staff.push_back( hr.createTrainee() );
    staff.push_back( hr.createManager(1.5) );

    hr.setBaseSalary(5000);

    for(const UStaff& s : staff ) {
        cout << s->getSalary() << endl;
    }
    return 0;
}
