<?php
 
error_reporting(-1);
mb_internal_encoding('utf-8');
 
abstract class Employee 
{
	public $rank;
	public $boss;
 
	public function __construct($rank, $boss)
	{
		$this->boss = $boss;
		$this->rank = $rank;
	}
 
	public function getSalary()
	{
		if ($this->rank == 1){
			$factor = 1;
		}elseif($this->rank == 2){
			$factor = 1.25;
		}elseif($this->rank == 3){
			$factor = 1.5;
		}
		if ($this->boss == true)
		{
			$bossFactor = 1.5;
		}else{
			$bossFactor = 1;
		}
		$salary = $this->getRate() * $factor * $bossFactor;
		return $salary;
	}
 
	public function getCoffe()
	{
		if ($this->boss == true)
		{
			$bossFactor = 2;
		}else{
			$bossFactor = 1;
		}
		$coffe = $this->getBaseCoffe() * $bossFactor;
		return $coffe;
	}
 
	public function getPages()
	{
		if ($this->boss == true)
		{
			$bossFactor = 0;
		}else{
			$bossFactor = 1;
		}
		$pages = $this->getBasePages() * $bossFactor;
		return $pages;
	}
	
	abstract protected function getRate();
	abstract protected function getBaseCoffe();
	abstract protected function getBasePages();
}
 
class Manager extends Employee
{
	public $rate = 500;
	public $coffe = 20;
	public $pages = 200;
	
	public function getRate()
	{
		return $this->rate;
	}
	public function getBaseCoffe()
	{
		return $this->coffe;
	}
	public function getBasePages()
	{
		return $this->pages;
	}
}
 
class Marketer extends Employee
{
	public $rate = 400;
	public $coffe = 15;
	public $pages = 150;
	
	public function getRate()
	{
		return $this->rate;
	}
	public function getBaseCoffe()
	{
		return $this->coffe;
	}
	public function getBasePages()
	{
		return $this->pages;
	}
}
 
class Engineer extends Employee
{
	public $rate = 200;
	public $coffe = 5;
	public $pages = 50;
	
	public function getRate()
	{
		return $this->rate;
	}
	public function getBaseCoffe()
	{
		return $this->coffe;
	}
	public function getBasePages()
	{
		return $this->pages;
	}
}
 
class Analyst extends Employee
{
	public $rate = 800;
	public $coffe = 50;
	public $pages = 5;
	
	public function getRate()
	{
		return $this->rate;
	}
	public function getBaseCoffe()
	{
		return $this->coffe;
	}
	public function getBasePages()
	{
		return $this->pages;
	}
}
 
class Department 
{
	public $departmentName;
	public $employees;
	
	public function __construct($name)
	{
		$this->departmentName = $name;
	}
	
	public function addEmployee($employee)
	{
		if(class_exists($employee[0]))
		{
			$position = preg_split('//u', mb_strtolower($employee[0]), -1, PREG_SPLIT_NO_EMPTY);
			$position[0] = mb_strtoupper($position[0]);
			$position = implode("", $position); 
			$q = array_pop($employee); 
			if ($employee[1] > 0 && $employee[1] < 4)
			{
				if (is_bool($employee[2]))
				{
					for($i=0; $i<$q; $i++)
					{
					$this->employees[] = (new $employee[0]($employee[1], $employee[2]));
					}
				}else{
					throw new Exception("Неправильно указано руководящее положение: {$employee[2]}");
				}
			}else{
				throw new Exception("Неправильно указан ранг: {$employee[1]}");
			}
		}else{
			throw new Exception("Нет такой профессии: {$employee[0]}");
		}
	}
	
	public function fireEmployee($employee)
    {
       $employeeKey = array_search($employee, $this->employees);
       unset ($this->employees[$employeeKey]);
    }
    
    public function findEmployee($position, $boss, $rank)
	{
		$i = 0;
		foreach($this->employees as $employee)
		{
			if(get_class($employee)==$position && $employee->boss == $boss && $employee->rank == $rank)
			{
				return $employee;
			}
		}
	}
 
	public function countEmployees($position)
	{
		$number = array(
			1 => 0,
			2 => 0,
			3 => 0
			);
		foreach($this->employees as $employee)
		{
			if(get_class($employee)==$position)
			{
				$number[$employee->rank] += 1;
			}
		}
		foreach($number as $rank => $quantity)
		{
			if($quantity == 0)
			{
				unset($number[$rank]);
			}
		}
		return $number;
	}
 
	public function getEmployees()
	{
		return $this->employees;
	}
 
	public function getDepartmentSalary()
	{
		$departmentSalary = 0;
		foreach($this->employees as $employee)
		{
			$departmentSalary += $employee->getSalary();
		}
		return $departmentSalary;
	}
 
	public function getDepartmentCoffe()
	{
		$departmentCoffe = 0;
		foreach($this->employees as $employee)
		{
			$departmentCoffe += $employee->getCoffe();
		}
		return $departmentCoffe;
	}
 
	public function getDepartmentPages()
	{
		$departmentPages = 0;
		foreach($this->employees as $employee)
		{
			$departmentPages += $employee->getPages();
		}
		return $departmentPages;
	}
 
	public function getSalaryPerPages()
	{
		return round($this->getDepartmentSalary() / $this->getDepartmentPages(), 2);
	}
 
	public function getPersonelAmount()
	{
		return count($this->employees);
	}
}
 
class Company
{
	public $departments;
	
	public function __clone()
    {
        $clones = array();
 
        foreach($this->departments as $department) {
            $department = clone $department;
            $clones[] = $department;
        }
        $this->departments = $clones; 
    }
    
	public function addDepartment($department)
	{
			$this->departments[] = $department;
	}
 
	public function getDepartments()
	{
		return $this->departments;
	}
 
	public function getTotalSalary()
	{
		$salary = 0;
		foreach($this->departments as $department)
		{
			$salary += $department->getDepartmentSalary();
		}
		return $salary;
	}
 
	public function getTotalCoffe()
	{
		$coffe = 0;
		foreach($this->departments as $department)
		{
			$coffe += $department->getDepartmentCoffe();
		}
		return $coffe;
	}
 
	public function getTotalPages()
	{
		$pages = 0;
		foreach($this->departments as $department)
		{
			$pages += $department->getDepartmentPages();
		}
		return $pages;
	}
 
	public function getTotalSalaryPerPages()
	{
		$spp = 0;
		foreach($this->departments as $department)
		{
			$spp += $department->getSalaryPerPages();
		}
		return $spp;
	}
 
	public function getTotalPersonelAmount()
	{
		$quantity = 0;
		foreach($this->departments as $department)
		{
			$quantity += $department->getPersonelAmount();
		}
		return $quantity;
	}
 
	public function departmentCount()
	{
		return count($this->departments);
	}
}
 
function padRight($text, $col)
{
return $text.str_repeat(' ',$col-mb_strlen($text));
}
function padLeft($text, $col)
{
return str_repeat(' ',$col-mb_strlen($text)).$text;
}

$departments[0]=new Department("Закупок");
$departments[1]=new Department("Продаж");
$departments[2]=new Department("Рекламы");
$departments[3]=new Department("Логистики");

$departments[0]->addEmployee(['Manager', 1, false, 9]);
$departments[0]->addEmployee(['Manager', 2, false, 3]);
$departments[0]->addEmployee(['Manager', 3, false, 2]);
$departments[0]->addEmployee(['Marketer', 1, false, 2]);
$departments[0]->addEmployee(['Manager', 2, true, 1]);

$departments[1]->addEmployee(['Manager', 1, false, 12]);
$departments[1]->addEmployee(['Marketer', 1, false, 6]);
$departments[1]->addEmployee(['Analyst', 1, false, 3]);
$departments[1]->addEmployee(['Analyst', 2, false, 2]);
$departments[1]->addEmployee(['Marketer', 2, true, 1]);

$departments[2]->addEmployee(['Marketer', 1, false, 15]);
$departments[2]->addEmployee(['Marketer', 2, false, 10]);
$departments[2]->addEmployee(['Manager', 1, false, 8]);
$departments[2]->addEmployee(['Engineer', 1, false, 2]);
$departments[2]->addEmployee(['Marketer', 3, true, 1]);

$departments[3]->addEmployee(['Manager', 1, false, 13]);
$departments[3]->addEmployee(['Manager', 2, false, 5]);
$departments[3]->addEmployee(['Engineer', 1, false, 5]);
$departments[3]->addEmployee(['Manager', 1, true, 1]);

$company = new Company;
foreach ($departments as $department)
{
$company->addDepartment($department);
}

function printData($company, $headline)
{
$col1 = 20;
$col2 = 8;
$col3 = 12;
$col4 = 12;
$col5 = 12;
$col6 = 12;
$col7 = 50;
if($headline == 0){
echo padRight("Департамент", $col1) .
     padLeft("сотр.", $col2) . 
     padLeft("тугр.", $col3) . 
     padLeft("кофе", $col4) .
     padLeft("стр.", $col5) .
     padLeft("тугр./стр.", $col6) . "\n" . 
     str_repeat("==", 40) . "\n";
}else{
	echo padLeft ('Антикризисная мера #'."{$headline}", $col7)."\n";
	echo  str_repeat("==", 40) . "\n";
}
	foreach($company->getDepartments() as $department)
	{
		echo padRight($department->departmentName, $col1) .
		padLeft($department->getPersonelAmount(), $col2) . 
		padLeft($department->getDepartmentSalary(), $col3) . 
		padLeft($department->getDepartmentCoffe(), $col4) . 
		padLeft($department->getDepartmentPages(), $col5) .
		padLeft($department->getSalaryPerPages(), $col6) . "\n" ;
		
    }echo str_repeat("==", 40) . "\n";
 
    echo padRight('Среднее', $col1) .
         padLeft($company->getTotalPersonelAmount()/$company->departmentCount(), $col2) . 
         padLeft($company->getTotalSalary()/$company->departmentCount(), $col3) . 
         padLeft($company->getTotalCoffe()/$company->departmentCount(), $col4) . 
         padLeft($company->getTotalPages()/$company->departmentCount(), $col5) .
         padLeft($company->getTotalSalaryPerPages()/$company->departmentCount(), $col6) . "\n" ;
 
    echo padRight('Всего', $col1) .
         padLeft($company->getTotalPersonelAmount(), $col2) . 
         padLeft($company->getTotalSalary(), $col3) . 
         padLeft($company->getTotalCoffe(), $col4) .
         padLeft($company->getTotalPages(), $col5) .
         padLeft($company->getTotalSalaryPerPages(), $col6)."\n\n";
}
 
 
 
class AnticrysisCommittee
{
	
	
	static public function firstSolution($company)
	{
		foreach($company->getDepartments() as $department)
		{
			$engineerQuantity = $department->countEmployees("Engineer");
			foreach($engineerQuantity as $rank => $quantity)
			{
				$firedEngineers = ceil($quantity*0.4);
				for($i = 0; $i < $firedEngineers; $i++)
				{
       			$department->fireEmployee($department->findEmployee("Engineer", false, $rank));
				}
			}
		}
		printData($company, 1);
	}
 
	static public function secondSolution($company)
	{
		foreach($company->getDepartments() as $department)
		{
			$i = 0;
			$analystQuantity = $department->countEmployees("Analyst");
			if ($analystQuantity != NULL)
			{
				foreach($department->getEmployees() as $employee)
				{
					if(get_class($employee)=="Analyst")
					{
						$employee->rate = 1100;
						$employee->coffe = 75;
 
						if(max(array_flip($analystQuantity)) == $employee->rank && $employee->boss == false && $i<1)
						{
							$employee->boss = true;
							$i+=1;
						}
						if(max(array_flip($analystQuantity)) > $employee->rank && $employee->boss == true)
						{
							$employee->boss = false;
						}
					}
					elseif($employee->boss == true)
					{
						$employee->boss = false;
					}
				}
			}
		}
		printData($company,2);
	}
 
	static public function thirdSolution($company)
	{
		foreach($company->getDepartments() as $department)
		{
			foreach($department->getEmployees() as $employee)
			{
				if(get_class($employee)=="Manager" && $employee->rank < 3)
				{
					$employee->rank = $employee->rank + 1;
					
				}
			}
		}
		printData($company, 3);
	}
}

$company1 = clone $company;
$company2 = clone $company;
$company3 = clone $company;

printData($company, 0);

AnticrysisCommittee::firstSolution($company1);
AnticrysisCommittee::secondSolution($company2);
AnticrysisCommittee::thirdSolution($company3);

