<?php
class Employee
{
const RANK_FIRST = 1.0;
const RANK_SECOND = 1.25;
const RANK_THIRD = 1.5;
const BOSS_PREMIUM = 1.5;
const BOSS_COFFEE_PREMIUM = 2.0;
const BOSS_PAGES_MULTIPLIER = 0;
const PROF_ENGINEER = 'engineer';
const PROF_MANAGER = 'manager';
const PROF_ANALYST = 'analyst';
const PROF_MARKETER = 'marketer';
public $isBoss;
public $rank;
public $profession;
public $baseCoffee;
public $basePages;
public $wageRate;
public function getSalary()
{
if ($this->isBoss)
return self::BOSS_PREMIUM * $this->wageRate * $this->rank;
else return $this->wageRate * $this->rank;
}
public function setWageRate($wageRate)
{
$this->wageRate = $wageRate;
}
public function getPages()
{
if ($this->isBoss) return self::BOSS_PAGES_MULTIPLIER * $this->basePages;
return $this->basePages;
}
public function setBasePages($pages)
{
$this->basePages = $pages;
}
public function getCoffee()
{
if ($this->isBoss) return self::BOSS_COFFEE_PREMIUM * $this->baseCoffee;
return $this->baseCoffee;
}
public function setBaseCoffee($coffee)
{
$this->baseCoffee = $coffee;
}
public function __construct($profession, $rank = 1, $isBoss = false)
{
$this->profession = $profession;
$this->rank = $rank;
$this->isBoss = $isBoss;
switch ($profession) {
case Employee::PROF_MANAGER :
$this->baseCoffee = 20;
$this->basePages = 200;
$this->wageRate = 500;
break;
case Employee::PROF_MARKETER :
$this->baseCoffee = 15;
$this->basePages = 150;
$this->wageRate = 400;
break;
case Employee::PROF_ANALYST :
$this->baseCoffee = 50;
$this->basePages = 5;
$this->wageRate = 800;
break;
case Employee::PROF_ENGINEER :
$this->baseCoffee = 5;
$this->basePages = 50;
$this->wageRate = 200;
break;
default:
throw new Exception('Неизвестная профессия');
}
}
}
class Report
{
public $departmentName;
public $salary;
public $coffee;
public $pages;
public $employeeCount;
}
class Department
{
public $name;
public $employees = array();
public function __construct($name)
{
$this->name = $name;
}
public function getReport()
{
$report = new Report;
foreach ($this->employees as $employee) {
$report->salary += $employee->getSalary();
$report->coffee += $employee->getCoffee();
$report->pages += $employee->getPages();
}
$report->departmentName = $this->name;
$report->employeeCount = count($this->employees); return $report;
}
public function hireEmployee(Employee $employee)
{
$this->employees[] = $employee;
}
public function fireEmployee(Employee $e)
{
foreach ($this->employees as $employee) {
if ($employee != $e) continue;
unset($this->employees[$index]); break;
}
}
}
function hireCrowd(Department $dep, $number, $profession, $rank = 1, $isBoss = false) {
for ($i = 0; $i < $number; $i++) {
$employee = new Employee($profession, $rank, $isBoss);
$dep->hireEmployee($employee);
}
}
class Company
{
public $departments = array(); public function getDepartments()
{
return $this->departments;
}
public $name;
public function __construct($name)
{
$this->name = $name;
}
public function getReport()
{
foreach ($this->departments as $department) {
$report[] = $department->getReport();
}
return $report;
}
public function addDepartment(Department $department)
{
$this->departments[] = $department;
}
public function dismissDepartment(Department $dep)
{
foreach ($this->departments as $department) {
if ($department != $dep) continue;
break;
}
}
}
class ViewHelper
{
public static function printReport(Company $company)
{
echo self::padRight('Департамент');
echo self::padLeft('сотр.');
echo self::padLeft('тугр.');
echo self::padLeft('кофе');
echo self::padLeft('стр.');
echo self::padLeft('тугр./стр.'), "\n";
for ($i=0; $i < 95; $i++) echo '-';
echo "\n";
$reports = $company->getReport();
foreach ($reports as $report) {
echo self::padRight($report->departmentName);
echo self::padLeft($report->employeeCount);
echo self::padLeft($report->salary);
echo self::padLeft($report->coffee);
echo self::padLeft($report->pages);
echo self::padLeft(round($report->salary / $report->pages, 1)); echo "\n";
}
echo self::padRight('Среднее');
echo self::padLeft(self::average($reports, 'employeeCount'));
echo self::padLeft(self::average($reports, 'salary'));
echo self::padLeft(self::average($reports, 'coffee'));
echo self::padLeft(self::average($reports, 'pages'));
echo "\n";
echo self::padRight('Всего');
echo self::padLeft(self::summary($reports, 'employeeCount'));
echo self::padLeft(self::summary($reports, 'salary'));
echo self::padLeft(self::summary($reports, 'coffee'));
echo self::padLeft(self::summary($reports, 'pages'));
echo "\n";
}
private static function summary($reports, $propertyName)
{
for ($i=0, $sum=0; $i < count($reports); $i++) { $sum += $reports[$i]->$propertyName;
}
return $sum;
}
private static function average($reports, $propertyName)
{
$sum = self::summary($reports, $propertyName);
}
private static function padRight($string, $columnSize=20) {
$paddingSize = $columnSize - mb_strlen($string); return $string;
}
private static function padLeft($string, $columnSize=15) {
$paddingSize = $columnSize - mb_strlen($string); $string = str_repeat(' ', $paddingSize) . $string; return $string;
}
}
$procurement = new Department('Отдел закупок');
hireCrowd($procurement, 9, Employee::PROF_MANAGER);
hireCrowd($procurement, 3, Employee::PROF_MANAGER, Employee::RANK_SECOND);
hireCrowd($procurement, 2, Employee::PROF_MANAGER, Employee::RANK_THIRD);
hireCrowd($procurement, 2, Employee::PROF_MARKETER);
hireCrowd($procurement, 1, Employee::PROF_MANAGER, Employee::RANK_SECOND, true);
$selling = new Department('Отдел продаж');
hireCrowd($selling, 12, Employee::PROF_MANAGER);
hireCrowd($selling, 6, Employee::PROF_MARKETER);
hireCrowd($selling, 3, Employee::PROF_ANALYST);
hireCrowd($selling, 2, Employee::PROF_ANALYST, Employee::RANK_SECOND);
hireCrowd($selling, 1, Employee::PROF_MARKETER, Employee::RANK_SECOND, true);
$advertisement = new Department('Отдел рекламы');
hireCrowd($advertisement, 15, Employee::PROF_MARKETER);
hireCrowd($advertisement, 10, Employee::PROF_MARKETER, Employee::RANK_SECOND);
hireCrowd($advertisement, 8, Employee::PROF_MANAGER);
hireCrowd($advertisement, 2, Employee::PROF_ENGINEER);
hireCrowd($advertisement, 1, Employee::PROF_MARKETER, Employee::RANK_THIRD, true);
$logistics = new Department('Отдел логистики');
hireCrowd($logistics, 13, Employee::PROF_MANAGER);
hireCrowd($logistics, 5, Employee::PROF_MANAGER, Employee::RANK_SECOND);
hireCrowd($logistics, 5, Employee::PROF_ENGINEER);
hireCrowd($logistics, 1, Employee::PROF_MANAGER, Employee::RANK_FIRST, true);
$vector = new Company('Вектор');
$vector->addDepartment($procurement);
$vector->addDepartment($selling);
$vector->addDepartment($advertisement);
$vector->addDepartment($logistics);
// Начальные условия
ViewHelper::printReport($vector);
// 1. Антикризисные меры: увольняю 40% инженеров во всех отделах
/*function fireMassive(Department $d, $profession, $amount)
{
$tolalCount = 0;
foreach ($d->employees as $employee) {
if ($employee->profession == $profession) $tolalCount += 1;
}
$toFire = intval(ceil($tolalCount * $amount));
$fired = 0;
foreach ($d->employees as $employee) {
if ($employee->profession != $profession or $employee->isBoss) continue;
if ($fired == $toFire) break;
$d->fireEmployee($employee);
$fired++;
}
}
foreach ($vector->getDepartments() as $department) {
fireMassive($department, Employee::PROF_ENGINEER, 0.4);
}
ViewHelper::printReport($vector);*/
// 2. Антикризисные меры: меняю расходы на аналитиков, делаю аналитиков начальниками
// в тех департаментах, где они есть, иначе не меняю босса
/*foreach ($vector->getDepartments() as $department) {
foreach ($department->employees as $employee) {
if ($employee->profession == Employee::PROF_ANALYST) {
$employee->setWageRate(1100);
$employee->setBaseCoffee(75);
$employee->setBasePages(5);
}
if ($employee->isBoss) {
$oldBoss = $employee;
break;
}
}
if ($oldBoss->profession == Employee::PROF_ANALYST) continue;
$pretendent = null;
foreach ($department->employees as $employee) {
if ($employee->profession != Employee::PROF_ANALYST) continue;
if (!$pretendent or $pretendent->rank < $employee->rank) {
$pretendent = $employee;
}
}
if ($pretendent) {
$oldBossIndex = array_search($oldBoss, $department->employees);
$department->employees[$oldBossIndex]->isBoss = false;
$pretendentIndex = array_search($pretendent, $department->employees);
$department->employees[$pretendentIndex]->isBoss = true;
}
}
ViewHelper::printReport($vector);*/
// 3. Антикризисные меры: повышаю на один ранг половину менеджеров 1 и 2 уровня.
for ($j=0; $j < count($vector->departments); $j++) { $toUpgrade = 0;
foreach ($vector->departments[$j]->employees as $e) {
if ($e->rank == Employee::RANK_FIRST || Employee::RANK_SECOND) {
$toUpgrade++;
}
}
for ($i=0; $i < $toUpgrade; $i++) {
if ($vector->departments[$j]->employees[$i]->rank == Employee::RANK_FIRST) {
$vector->departments[$j]->employees[$i]->rank = Employee::RANK_SECOND;
} elseif ($vector->departments[$j]->employees[$i]->rank == Employee::RANK_SECOND) {
$vector->departments[$j]->employees[$i]->rank = Employee::RANK_THIRD;
}
}
}
ViewHelper::printReport($vector);