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


using namespace std;


using Money = int;
using Id = int;

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

class HRSystem {
public:
    HRSystem() : staffId_(0) {}
    void noticeBonus(Id id) { bonuses_.push_back(id); }

    Id addEmployee(Money salary, int seniority); //nowy pracownik etatowy, zwraca Id
    Id addTrainee();  //nowy stazysta, zwraca Id
    Id addManager(Money salary, int seniority);  //nowy kierownik, zwraca Id

    const vector<UStaff>& getStaff() const { return staff_; }
private:
    int staffId_;
    vector<UStaff> staff_;
    vector<Id> bonuses_;

};

//hierarchia osob zatrudnionych
class Staff {
public:
    Staff(HRSystem& owner, Id id) : owner_(owner), id_(id){}
    virtual Money calcBonus() const = 0;
    virtual ~Staff() {}
protected:
    HRSystem& owner_;
    Id id_;
};

class Employee : public Staff {
public:
    Employee(HRSystem& owner, Id id, Money salary, int seniority) : Staff(owner, id), salary_(salary), seniority_(seniority){}
    virtual Money calcBonus() const {
        owner_.noticeBonus(id_);
        return salary_ * seniority_ / 100;
    }
private:
    Money salary_;
    int seniority_; //lata pracy
};

class Trainee : public Staff {
public:
    Trainee(HRSystem& owner, Id id) : Staff(owner, id){}
    virtual Money calcBonus() const {
        owner_.noticeBonus(id_);
        return 0; //no bonus for Trainee
    }
};

class Manager : public Staff {
public:
    Manager(HRSystem& owner, Id id, Money salary, int seniority) : Staff(owner, id), salary_(salary), seniority_(seniority){}
    virtual Money calcBonus() const {
        owner_.noticeBonus(id_);
        return salary_;
    }
private:
    Money salary_;
    int seniority_; //lata pracy
};

//better NVI
// class Staff {
// public:
//     Staff(HRSystem& owner, Id id) : owner_(owner), id_(id) {}
//     Money calcBonus() const {
//         owner_.noticeBonus(id_);
//         return doCalcBonus();
//     }
//     virtual ~Staff() {}
// private:
//     virtual Money doCalcBonus() const = 0;
//     HRSystem& owner_;
//     Id id_;
// };

// class Employee : public Staff {
// public:
//     Employee(HRSystem& owner, Id id, Money salary, int seniority) : Staff(owner, id), salary_(salary), seniority_(seniority) {}
// private:
//     virtual Money doCalcBonus() const { return salary_ * seniority_ / 100; }

//     Money salary_;
//     int seniority_; //lata pracy
// };

// class Trainee : public Staff {
// public:
//     Trainee(HRSystem& owner, Id id) : Staff(owner, id) {}
//     virtual Money doCalcBonus() const { return 0; } //no bonus for Trainee 
// };

// class Manager : public Staff {
// public:
//     Manager(HRSystem& owner, Id id, Money salary, int seniority) : Staff(owner, id), salary_(salary), seniority_(seniority) {}
// private:
//     virtual Money doCalcBonus() const { return salary_; }
//     Money salary_;
//     int seniority_; //lata pracy
// };
//*********

Id HRSystem::addEmployee(Money salary, int seniority) {
    Id id = ++staffId_;
    staff_.push_back(make_unique<Employee>(*this, id, salary, seniority) );
    return id;
}

Id HRSystem::addTrainee() {
    Id id = ++staffId_;
    staff_.push_back(make_unique<Trainee>(*this, id) );
    return id;
}

Id HRSystem::addManager(Money salary, int seniority) {
    Id id = ++staffId_;
    staff_.push_back(make_unique<Manager>(*this, id, salary, seniority) );
    return id;
}




int main() {
    HRSystem hr;
    hr.addEmployee(4200, 2);
    hr.addTrainee();
    hr.addManager(7500, 10);

    const vector<UStaff>& v = hr.getStaff();
    for(const UStaff& s : v ) {
        cout << s->calcBonus() << endl;
    }
    return 0;
}
