<?php

error_reporting(-1);

class Report
{
    private $col1 = 25;
    private $col2 = 15;

    private function padLeft($string, $length)
    {   
        $countSpace = $length - strlen($string); //количество добавляемых в ячейку пробелов  
        return str_repeat(' ',$countSpace) . $string;
    }

    private function padRight($string, $length)
    {
        $countSpace = $length - strlen($string); //количество добавляемых в ячейку пробелов  
        return $string . str_repeat(' ',$countSpace);
    }

    public function writeTable(Company $company)
    {// Заголовок таблицы
        echo $this->padRight("Departmen", $this->col1) .
             $this->padLeft("employe", $this->col2) . 
             $this->padLeft("money", $this->col2) . 
             $this->padLeft("coffee", $this->col2) .
             $this->padLeft("lists", $this->col2) .
             $this->padLeft("money/lists", $this->col2) . "\n\n";

        $departmentsCompany = $company->getDepartments();

        // Сама таблица
        foreach ($departmentsCompany as $departmentCompany) {
            echo $this->padRight($departmentCompany->getName(), $this->col1) .
                 $this->padLeft($departmentCompany->getEmployeCount(), $this->col2) . 
                 $this->padLeft($departmentCompany->getSalary(), $this->col2) . 
                 $this->padLeft($departmentCompany->getCoffeeCount(), $this->col2) .
                 $this->padLeft($departmentCompany->getDocumentsCount(), $this->col2) .
                 $this->padLeft($departmentCompany->getMoneyPerList(), $this->col2) . "\n";
    }
}

}

class Company
{   
    protected $departments = array();//массив депортаментов
    protected $professions = array();//массив профессий

    public function __construct()
    {
        //создаются список профессий востребованных в этой компании b
        $this->professions[] = new Manager();   //  'MN'
        $this->professions[] = new Marketer(); //  'MR'
        $this->professions[] = new Engineer(); //  'EN'
        $this->professions[] = new Analyst();   //  'AN';
    }

    public function createDepartment(string $name, array $employeesData)
    {   
        $employees = array();

        foreach ($employeesData as $employeeStack)
        {     
            $employeCount = $employeeStack[0];
            $employeProfession = $employeeStack[1];
            $employeRang = $employeeStack[2];

            if ($employeCount == "BOSS") {  //Босс у меня это такое количество. Ага, да.

                $employees[] = $this->createEmploye($employeProfession, $employeRang, "BOSS");
            } else {
                for ($i=0; $i < $employeCount; $i++) { 
                    $employees[] = $this->createEmploye($employeProfession, $employeRang);
                }
            } 

        }
        
        $department = new Department($name, $employees); 
   
        $this->departments[] = $department;
                
    }

    public function getDepartments()
    {   
        return $this->departments;
    }

    //приходит заявка на создаваемую профессию. Строчка и цифра например - ('en', 2), то функция делает engineera ранга 2
    public function createEmploye(string $professionName, int $rang, string $isBoss = "NOTBOSS")
    {   

        foreach ($this->professions as $profession) {
            
            //создает работника требуемой профессии. 
            if ($profession->getName() == $professionName) {
                $employe = new Employe($rang, $profession);
                if ($isBoss == "BOSS") {
                    $employe->appointBoss();
                }
            }
        }
        return $employe;
    }
}

class Department
{
    private $name;
    private $employees = array();//массив из работников этого департамента

    //согласно массиву-шаблону создаём работников департаменты и про
    public function __construct(string $name, array $employees)
    {
        $this->name = $name;
        $this->employees = $employees;
    }

    public function getName()
    {
        return $this->name;
    }  

    public function getEmployees()
    {
        return $this->employees;
    }
    
    public function getEmployeCount()
    {
        return count($this->employees);
    }
    
    public function getSalary()
    {
        $salary = 0;
        foreach ($this->employees as  $employe) {
            $salary = $salary + $employe->getSalary();
        }
        return $salary;
    }
    
    public function getCoffeeCount()
    {
        $coffee = 0;
        foreach ($this->employees as  $employe) {
            $coffee = $coffee + $employe->getCoffee();
        }
        return $coffee;
    }
    
    public function getDocumentsCount()
    {
        $listCount = 0;
        foreach ($this->employees as  $employe) {


            $listCount = $listCount + $employe->getDocumentsCount();
        }
        return $listCount;
    }
    
    public function getMoneyPerList()
    {
        if ($this->getDocumentsCount() == 0) {
        }
        return round(($this->getSalary() / $this->getDocumentsCount()), 1);
    }

}

class Employe
{
    private $profession;
    private $employeLevel;
    private $isBoss;

    public function __construct(int $employeLevel, Profession $profession, bool $isBoss = false)
    {
        $this->employeLevel = $employeLevel;
        $this->profession = $profession;
        $this->isBoss = $isBoss;
    }

    public function appointBoss()
    {
        $this->isBoss = true;
    }

    //определяет является ли сотрудник боссом
    public function isBoss()
    { 
        return $this->isBoss;
    }

    //расчёт зарплаты сотрудника
    public function getSalary()
    {
        $rateMoneyProfession = $this->profession->getMoneyRate(); //узнаём коэфициент зарплаты для его професси
        $rateLevel = $this->employeLevel * 0.25 + 0.75; //узнаём коэфициент зарплаты для его ранга
        if ($this->isBoss())
        {                  //является ли сотрудник боссом департамента
            $bossRate = 1.5;                 //и устанавливаем соответствующую ставку
        } else {
            $bossRate = 1;
        }
        return $rateMoneyProfession * $rateLevel * $bossRate;
    }

    //расчёт потребления кофе сотрудником
    public function getCoffee()
    {
        $cofeeRate = $this->profession->getCoffeeRate(); //узнаём коэфициент потребления кофе для его професси
        
        if ($this->isBoss()) {                 //является ли сотрудник боссом департамента
            $bossRate = 2;                  //и устанавливаем соответствующее поглощение кофе для босса
        } else {
            $bossRate = 1;
        }
        return $cofeeRate * $bossRate;
    }

    public function getDocumentsCount()
    {
        $documentsCount = $this->profession->getDocumentsCount();
        if ($this->isBoss()) {                     //является ли сотрудник боссом департамента
            $bossRate = 0;                      //босс не занимается бумагами
        } else {
            $bossRate = 1;                      //если простой работник то придётся заниматся чертежами отчётами и т.п.
        }
        return $bossRate * $documentsCount;
    }

}

abstract class Profession
{
    private $name;
    private $moneyRate;
    private $coffeeRate;
    private $documentsCount;

    abstract function getDocumentsCount();
    
    abstract function getName();

    abstract function getCoffeeRate();

    abstract function getMoneyRate();
}

Class Manager Extends Profession
{
    private $name = 'MN';
    private $documentsCount = 200; //Манагер делает 200 листов отчёта
    private $moneyRate = 500;
    private $coffeeRate = 20;

    public function getName()
    {
        return $this->name;
    }

    public function getCoffeeRate()
    {
        return $this->coffeeRate;
    }

    public function getMoneyRate()
    {
        return $this->moneyRate;
    }

    public function getDocumentsCount()
    {
        return $this->documentsCount;
    }

}

Class Marketer Extends Profession
{
    private $name = 'MR';
    private $documentsCount = 150; //Маркетёр делает 150 листов отчёта
    private $moneyRate = 400;
    private $coffeeRate = 15;

    public function getName()
    {
        return $this->name;
    }
    public function getCoffeeRate()
    {
        return $this->coffeeRate;
    }
    public function getMoneyRate()
    {
        return $this->moneyRate;
    }

    public function getDocumentsCount()
    {
        return $this->documentsCount;
    }
}

Class Engineer Extends Profession
{
    private $name = 'EN';
    private $documentsCount = 50; //Инжинер делает 50 листов чертежей и проектов
    private $moneyRate = 200;
    private $coffeeRate = 5;

    public function getName()
    {
        return $this->name;
    }
    public function getCoffeeRate()
    {
        return $this->coffeeRate;
    }
    public function getMoneyRate()
    {
        return $this->moneyRate;
    }

    public function getDocumentsCount()
    {
        return $this->documentsCount;
    }
}

Class Analyst Extends Profession
{
    private $name = 'AN';
    private $documentsCount = 5; //Аналист делает 5 листов исследований
    private $moneyRate = 800;
    private $coffeeRate = 50;

    public function getName()
    {
        return $this->name;
    }
    public function getCoffeeRate()
    {
        return $this->coffeeRate;
    }
    public function getMoneyRate()
    {
        return $this->moneyRate;
    }

    public function getDocumentsCount()
    {
        return $this->documentsCount;
    }
}

// создаётсяя компания
$company = new Company();

/*массивы для формирования сотрудников отдело и т.п.
    первая цифра в ячейке массива - колличество сотрудников. буква b означает босса
    (mn-Manager mr-Marketer en-Engineer an-Analyst) - ранг сотрудника
    цифра в третьей ячеке - ранг сортудников
*/
$name='Department of Procurement';   
$employeesData=[[ 9, 'MN', 1],   [3, 'MN', 2],   [2, 'MN', 3], [2, 'MR', 1], ["BOSS", 'MN', 2]];
$company->createDepartment($name, $employeesData);

$name='Department of Sales';    
$employeesData=[[12, 'MR', 1],   [6, 'MR', 2],   [3, 'AN', 2], [2, 'AN', 2], ["BOSS", 'MR', 2]]; 
$company->createDepartment($name, $employeesData); 

$name='Department of Advertising';   
$employeesData=[[15, 'MR', 1],   [10, 'MR', 2],  [8, 'MN', 1], [2, 'EN', 1], ["BOSS", 'MR', 3]];
$company->createDepartment($name, $employeesData);  
 

$name='Department of Logistics'; 
$employeesData=[[13, 'MN', 1],   [5, 'MN', 2],   [5, 'EN', 1], ["BOSS", 'MN', 1]];
$company->createDepartment($name, $employeesData);


$report= new Report();
$report->writeTable($company);


