<?php
header("Content-Type: text/plain");
mb_internal_encoding('utf-8');
 
//  ООП. Вектор департаменты и сотрудники
 
// Класс сотрудника
class Employee {
 
    public $id      = "";   // id   
    private $rank    = 1;    // ранг
    private $chief   = 0;    // статус руководителя
    private $profession;     // профессия
 
    // Коофициенты зарплаты для ранга
    private $xRang = array (1 => '1',
                                 2 => '1.25',
                                 3 => '1.5');
    // Коофициенты зарплаты для начальников
    private $xChiefSalary = array (0 => '1',
                                  1 => '1.5');
    // Коофициенты потребления кофе для начальников
    private $xChiefCoffee = array (0 => '1',
                                  1 => '2');
    // Коофициенты продуктивности для начальников
    private $xChiefProduct = array (0 => '1',
                                1 => '0');
 
    public function __construct ($id){
        $this->id = $id;
    }    
    // Присвоение профессии сотруднику
    public function setProfession ($profession) {
        $this->profession = $profession;
    }
    // Присвоение ранга сотруднику
    public function setRank ($rank) {
        $this->rank = $rank;
    }
    // Присвоение статуса начальник
    public function setСhief ($chief) {
        $this->chief = $chief;
    }
    // Расчет зарплаты
    public function getSalary () {
        // Профессия
        $profession = $this->profession;
        // Ставка по профессии
        $salaryRate = $profession->salaryRate;
        // Вычисляем коэффициент согласно рангу сотрудника
        $tmpxRang = $this->xRang[$this->rank];        
        // Вычисляем коэффициент для начальника
        $tmpxChiefSalary = $this->xChiefSalary[$this->chief];
        // Расчет зарплаты
        $salary = $salaryRate * $tmpxRang * $tmpxChiefSalary;
 
        return $salary;
    }
    // Расчет потребления кофе
    public function getCoffee () {
        // Профессия
        $profession = $this->profession;
        // Потребление кофе по профессии
        $coffeeRate = $profession->coffeeRate;
        // Вычисляем коэффициент для начальника
        $tmpxChiefCoffee = $this->xChiefCoffee[$this->chief];
        // Расчет потребления кофе
        $coffee = $coffeeRate * $tmpxChiefCoffee;
 
        return $coffee;
    }
    // Расчет продуктивности
    public function getProduct () {
        // Профессия
        $profession = $this->profession;
        // Продуктивность по профессии
        $productRate = $profession->product;
        // Вычисляем коэффициент для начальника
        $tmpxChiefProduct = $this->xChiefProduct[$this->chief];
        // Расчет продуктивности
        $product = $productRate * $tmpxChiefProduct;
 
        return $product;
    }    
}
 
// Абстрактный класс профессии
abstract class Profession {
    public $name = "";      // название       
    public $salaryRate;     // ставка
    public $coffeeRate;     // результат работы
    public $product;        // производительность        
}
 
// Класс менджер
class Manager extends Profession {    
    public $name            = "Manager";          
    public $salaryRate      = 500;
    public $coffeeRate      = 20;
    public $product         = 200;  
}
 
// Класс маркетолог
class Marketer extends Profession { 
    public $name            = "Marketer";      
    public $salaryRate      = 400;
    public $coffeeRate      = 15;
    public $product         = 150;
}
 
// Класс инженер
class Engineer extends Profession { 
    public $name            = "Engineer";  
    public $salaryRate      = 200;
    public $coffeeRate      = 5;
    public $product         = 50;
}
 
// Класс аналитик
class Analyst extends Profession { 
    public $name            = "Analyst";     
    public $salaryRate      = 800;
    public $coffeeRate      = 50;
    public $product         = 5;
}
 
// Класс департамента
class Departament {
 
    public $name = "";            // название   
    private $employees = array(); // сотрудники
 
    public function __construct ($name){
        $this->name = $name;
    }
    // Прием сотрудника на работу
    public function setEmployee ($employee){
        $this->employees[] = $employee;
    }
    // Расчет количества сотрудников
    public function countEmployees (){
        return count($this->employees);
    }
    // Расходы на зарплату
    public function getTotalSalary (){
        $totalSalary = 0;     // сумарная зарплата         
        // Для каждого сотрудника
        foreach ($this->employees as $employee) {
            // Запрашиваем зп у сотрудника и суммируем результат
            $totalSalary += $employee->getSalary ();
        }
        return $totalSalary;
    }
    // Рассход кофе
    public function getTotalCoffee (){
        $totalCoffee = 0;     // сумарное потребление кофе         
        // Для каждого сотрудника
        foreach ($this->employees as $employee) {
            // Запрашиваем потребление кофе у сотрудника  и суммируем результат
            $totalCoffee += $employee->getCoffee ();
        }
        return $totalCoffee;
    }
    // Суммарная производительность
    public function getTotalProduct (){
        $totalProduct = 0;     // сумарная продуктивность         
        // Для каждого сотрудника
        foreach ($this->employees as $employee) {
            // Запрашиваем продуктивность у сотрудника и суммируем результат
            $totalProduct += $employee->getProduct ();
        }
        return $totalProduct;
    }
    // Средний расход тугриков на одну страницу
    public function getAvrCostPerProduct (){
        // Средняя стоимость 1 страницы = суммарная зарплата / сумарное количество страниц
        $avrCostPerProduct = round($this->getTotalSalary () / $this->getTotalProduct () , 2) ;
 
        return $avrCostPerProduct;  
    }
}
 
// Класс компании
class Company {
 
    public $name = ""; // название       
    public $departaments = array(); // департаменты 
 
    public function __construct($name)
    {
        $this->name = $name;
    } 
    // Добавление департамента в компанию
    public function setNewDepartament ($departament) {
        // Имя департамента в массиве для обращения
        $depName = $departament->name;
        // Добавляем объект департмент в массив $departaments
        $this->departaments[$depName] = $departament;
    }    
 
     // Сумарное количество работников
    public function getTotalEmployees (){
        $totalEmployees = 0;
        // Для каждого департамента
        foreach ($this->departaments as $departament) {
            // Сумируем работников всех департаментов
            $totalEmployees += $departament->countEmployees();
        }
        return $totalEmployees;
    }
    // Расходы на зарплату в сумме
    public function getTotalSalary (){    
        $salary = 0;
        // Для каждого департамента
        foreach ($this->departaments as $departament) {
            // Сумируем зп всех департаментов
            $salary += $departament->getTotalSalary();
        }
        return $salary;
    }
 
    // Рассход кофе в сумме
    public function getTotalCoffee (){
        $coffee = 0;
        // Для каждого департамента
        foreach ($this->departaments as $departament) {
            // Суммируем расход кофе у департаментов
            $coffee += $departament->getTotalCoffee();
        }
        return $coffee;
    }
 
    // Суммарная производительность
    public function getTotalProduct (){
        $product = 0;
        // Для каждого департамента
        foreach ($this->departaments as $departament) {
            // Суммируем производительность каждого департамента
            $product += $departament->getTotalProduct();;
        }
        return $product;    
    }
    // Среднее количество работников по департаментам
    public function getAvrEmployees (){
        // Среднее количество работников = суммарное кол-во работников / кол-во департаментов
        $avrEmployees = round($this->getTotalEmployees () / count($this->departaments)) ;
 
        return $avrEmployees;
    }
    // Средняя зарплата по департаментам
    public function getAvrSalary (){
        // Средняя зарплата = суммарная зарплата / кол-во департаментов
        $avrSalary = round($this->getTotalSalary () / count($this->departaments), 2) ;
 
        return $avrSalary;
    }
    // Среднее потребление кофе по департаментам
    public function getAvrCoffee (){
        // Среднее потребление кофе = суммарная потребление кофе / кол-во департаментов
        $avrCoffee = round($this->getTotalCoffee () / count($this->departaments), 2) ;
 
        return $avrCoffee;
    }
    // Средняя производительность по департаментам
    public function getAvrProduct (){
        // Средняя производительность = суммарная производительность / кол-во департаментов
        $avrProduct = round($this->getTotalProduct () / count($this->departaments), 2) ;
 
        return $avrProduct;
    }
    // Средний расход тугриков на одну страницу по департаментам
    public function getAvrCostPerProduct (){
        $avrCostPerProduct = 0;
        // Для каждого департамента
        foreach ($this->departaments as $departament) {            
            // Сумируем средний расход
            $avrCostPerProduct += $departament->getAvrCostPerProduct();
        }
        // Средняя стоимость 1 страницы = cредняя стоимость всех департ  / кол-во департаментов
        $avrCostPerProduct = round($avrCostPerProduct / count($this->departaments) , 2);
 
        return $avrCostPerProduct;
    }
 
}
 
// Регистрируем Vector Inc на Сейшельских островах
$vector = new Company('Vector');
 
// Создаем классы департаментов 
$purchDep = new Departament('Департамент закупок');
$salesDep = new Departament('Департамент продаж');
$advDep = new Departament('Департамент рекламы');
$logDep = new Departament('Департамент логистики');
 
// Записываем департменты в реестр компании
$vector->setNewDepartament($purchDep);
$vector->setNewDepartament($salesDep);
$vector->setNewDepartament($advDep);
$vector->setNewDepartament($logDep);
 
// Создаем классы профессий
$me = new Manager();
$ma = new Marketer();
$en = new Engineer();
$an = new Analyst();
 
// Добавляем профессии в масив для последующего создания сотрудников пачкой
$professions['me'] = $me;
$professions['ma'] = $ma;
$professions['en'] = $en;
$professions['an'] = $an;
 
// Лист вакансий: департамент => группы вакансий: профессияРанг статус_начальника => кол-во
$vacancies = array(
                    'Департамент закупок' => array('me1'=>'9', 'me2'=>'3', 'me3'=>'2', 'ma1'=>'2', 'me2 1'=>'1'),
                    'Департамент продаж' => array('me1'=>'12', 'ma1'=>'6', 'an1'=>'3', 'an2'=>'2', 'ma2 1'=>'1'),
                    'Департамент рекламы' => array('ma1'=>'15', 'ma2'=>'10', 'me1'=>'8', 'en1'=>'2', 'ma3 1'=>'1'),
                    'Департамент логистики' => array('me1'=>'13', 'me2'=>'5', 'en1'=>'5', 'me1 1'=>'1')
                  );
 
// Создание сотрудников
function creationEmployees ($vacancies, $professions, $vector) {
    // Список сотрудников, чтобы не разбежались
    $employees = array ();    
    // Для каждого департамента
    foreach ($vacancies as $depName => $vacancyGroup) { 
 
        // Для каждой группы вакансий
        foreach ($vacancyGroup as $vacancyName => $vacancyQuantity) {
 
            // Достаем название профессии из вакансии 
            $profession = mb_substr ($vacancyName, 0, 2);
            // Достаем ранг из вакансии
            $rank = mb_substr ($vacancyName, 2, 1);
            // Достаем статус начальника из вакансии
            $chief = mb_substr ($vacancyName, 4, 1);
            $chief = ($chief==NULL)? 0 : 1; // если статус не определен явно, считаем что 0
 
            // Создаем столько сотрудников, сколько вакансий в группе
            for ($id = 1; $id <= $vacancyQuantity; $id++) {
                // Создаем сотрудника
                $employees[$id] = new Employee($id); 
 
                // Назначаем профессию согласно текущей вакансии
                $employees[$id]->setProfession($professions[$profession]); 
                // Писваиваем ранг
                $employees[$id]->setRank($rank);
                // Присваиваем статус начальника
                $employees[$id]->setСhief($chief);
 
                // Находим нужный департамент в компании
                $departament = $vector->departaments[$depName];
                // Добавляем сотрудника в этот департамент
                $departament->setEmployee($employees[$id]);
            }
        }
    }
}
 
// Запускаем пакетное создание и распределение сотрудников
creationEmployees ($vacancies, $professions, $vector);
 
/*  Вывод таблицы результатов   */
 
// Класс строки таблицы
class TableTr {
    public $str = "";         // строка
    //private $caption = 0;   // является ли строка заголовком 
 
    // Ширина колонок
    public $length = 15;
 
    // Добавление пробелов слева
    public function padLeft($string, $length) {
        // Разница между переданной строкой и шириной колонки
        $lenghtDifference = $length-mb_strlen($string);
        // Проверка на отрицательное значение при вычитании
        if ($lenghtDifference >= 0) {
            // Заполняем разницу пробелами 
            $string = str_repeat(" ", $lenghtDifference) . $string;    
        } else {
            // Если таки отрицательное, обрезаем край строки до ширины колонки
            $string = mb_substr ($string, 0, $length);
        }
        return $string;
    }
 
    // Добавление пробелов справа
    public function padRight($string, $length) {
        // Разница между переданной строкой и шириной колонки
        $lenghtDifference = $length-mb_strlen($string);
        // Проверка на отрицательное значение при вычитании
        if ($lenghtDifference >= 0) {
            // Заполняем разницу пробелами 
            $string .= str_repeat(" ", $lenghtDifference);   
        } else {
            // Если таки отрицательное, обрезаем край строки до ширины колонки
            $string = mb_substr ($string, 0, $length);
        }
        return $string;
    }
 
    // Делаем горизонтальную черту
    public function drawHr($length, $columns) {
        $string = str_repeat("-", $length * $columns);
        return $string;
    }    
 
    // Конструктор принимает массив строк с статус заголовка
    public function __construct ($strs, $caption) {
        // Количество колонок
        $columns=0; // счетчик колонок
        foreach ($strs as $str) {
            // Первая колонка
            if (mb_strlen( $this->str)==0) {
                // Добавляем пробелы справа
                $this->str .= "\n" . $this->padRight($str, $this->length);
            // Остальные колонки
            } else {
                // Добавляем пробелы слева
                $this->str .= $this->padLeft($str, $this->length);                
            }
           $columns++;
        }
        // Если строка заголовок
        if ($caption==1) {
            // Добаляем горизонтальное поддчеркивание снизу, длина колонки * кол-во колонок
            $this->str .= "\n" . $this->drawHr($this->length, $columns);
        }        
    }
}
// Класс таблицы
class Table {
    public $tableTrs = array (); // массив строк
 
    // Добавление строк в таблицу
    public function setTableTr ($tableTr) {
        $this->tableTrs[] = $tableTr;
    }
    // Печать таблицы
    public function printTable () {
        foreach($this->tableTrs as $tableTr) {
            echo "{$tableTr->str}";
        }
    } 
}
// Создаем таблицу
$table = new Table();
 
// Заголовок таблицы
$tableCaption = array ("Департамент",
                       "сотр.",
                       "тугр.",
                       "кофе",
                       "стр.",
                       "тугр./стр..");
// Создаем строку
$tableTrC = new TableTr ($tableCaption, 1);
// Добавляем строку в таблицу
$table->setTableTr($tableTrC); 
 
// Выводим статистику по департаментам
// Каждый департамент строка
foreach ($vector->departaments as $departament) {
   unset($strs); // обнуляем массив
    // Заполняем массив строк
    $strs[] = mb_convert_case(mb_substr($departament->name, 12), MB_CASE_TITLE, "UTF-8");
    $strs[] = $departament->countEmployees();
    $strs[] = $departament->getTotalSalary();
    $strs[] = $departament->getTotalCoffee();
    $strs[] = $departament->getTotalProduct();
    $strs[] = $departament->getAvrCostPerProduct();
 
    // Создаем новую строку
    $tableTr = new TableTr ($strs, 0);
    // Добавляем строку в таблицу
    $table->setTableTr($tableTr); 
}
 
// Пустая строка
unset($strs); // обнуляем массив
$strs[] = ' ';
// Создаем новую строку
$tableTrAvr = new TableTr ($strs, 0);
// Добавляем строку в таблицу
$table->setTableTr($tableTrAvr);
 
// Среднее для всей компании
unset($strs); // обнуляем массив
// Заполняем массив строк
$strs[] = 'Среднее';
$strs[] = $vector->getAvrEmployees();
$strs[] = $vector->getAvrSalary();
$strs[] = $vector->getAvrCoffee();
$strs[] = $vector->getAvrProduct();
$strs[] = $vector->getAvrCostPerProduct();
 
// Создаем новую строку
$tableTrAvr = new TableTr ($strs, 0);
// Добавляем строку в таблицу
$table->setTableTr($tableTrAvr);
 
 
// Всего для всей компании
unset($strs); // обнуляем массив
// Заполняем массив строк
$strs[] = 'Всего';
$strs[] = $vector->getTotalEmployees();
$strs[] = $vector->getTotalSalary();
$strs[] = $vector->getTotalCoffee();
$strs[] = $vector->getTotalProduct();
 
// Создаем новую строку
$tableTrAvr = new TableTr ($strs, 0);
// Добавляем строку в таблицу
$table->setTableTr($tableTrAvr);
 
// Выводим таблицу на печать
$table->printTable();

?>