<?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->rate * $factor * $bossFactor;
		return $salary;
	}
 
	public function getCoffe()
	{
		if ($this->boss == true)
		{
			$bossFactor = 2;
		}else{
			$bossFactor = 1;
		}
		$coffe = $this->coffe * $bossFactor;
		return $coffe;
	}
 
	public function getPages()
	{
		if ($this->boss == true)
		{
			$bossFactor = 0;
		}else{
			$bossFactor = 1;
		}
		$pages = $this->pages * $bossFactor;
		return $pages;
	}
}
 
class Manager extends Employee
{
	public $rate = 500;
	public $coffe = 20;
	public $pages = 200;
	
	public function getSalary()
	{
		return parent::getSalary();
	}
 
	public function getCoffe()
	{
		return parent::getCoffe();
	}
 
	public function getPages()
	{
		return parent::getPages();
	}
}
 
class Marketer extends Employee
{
	public $rate = 400;
	public $coffe = 15;
	public $pages = 150;
	
	public function getSalary()
	{
		return parent::getSalary();
	}
 
	public function getCoffe()
	{
		return parent::getCoffe();
	}
 
	public function getPages()
	{
		return parent::getPages();
	}
}
 
class Engineer extends Employee
{
	public $rate = 200;
	public $coffe = 5;
	public $pages = 50;
	
	public function getSalary()
	{
		return parent::getSalary();
	}
 
	public function getCoffe()
	{
		return parent::getCoffe();
	}
 
	public function getPages()
	{
		return parent::getPages();
	}
}
 
class Analyst extends Employee
{
	public $rate = 800;
	public $coffe = 50;
	public $pages = 5;
	
	public function getSalary()
	{
		return parent::getSalary();
	}
 
	public function getCoffe()
	{
		return parent::getCoffe();
	}
 
	public function getPages()
	{
		return parent::getPages();
	}
}

class Department 
{
	public $departmentName;
	public $employees;
	
	public function __construct($employees, $departmentName)
	{
		$this->departmentName = $departmentName;
		foreach ($employees as $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{
						echo "Неправильно указано руководящее положение: ";
						die($employee[2]);
					}
				}else{
					echo "Неправильно указан ранг: ";
					die($employee[1]);
				}
			}else{
				echo "Нет такой профессии: ";
				die($employee[0]);
			}
		}
	}
	
	public function countEmployees($position)
	{
		$number = array(
			1 => 0,
			2 => 0,
			3 => 0
			);
		foreach($this->employees as $employee)
		{
			if(get_class($employee)==$position)
			{
				if($employee->rank == 1)
				{
					$number[1]+=1;
				}
				elseif($employee->rank == 2)
				{
					$number[2]+=1;
				}
				elseif($employee->rank == 3)
				{
					$number[3]+=1;
				}
			}
		}
		foreach($number as $key => $value)
		{
			if($value == 0)
			{
				unset($number[$key]);
			}
		}
		return $number;
	}
	
	public function fireEmployees($position, $boss, $quantity, $rank)
	{
		$i = 0;
		foreach($this->employees as $key => $employee)
		{
			if(get_class($employee)==$position && $employee->boss == $boss && $i<$quantity && $employee->rank == $rank)
			{
				unset($this->employees[$key]);
				$i+=1;
			}
		}return $employee;
	}
	
	public function hireEmployees($position, $rank, $boss)
	{
		$this->employees[] = (new $position($rank, $boss));
	}
	
	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 __construct($departments)
	{
		foreach ($departments as $department)
			$this->departments[] = new Department($department[0], $department[1]);
	}

	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($q, $w){
 return implode("", (array_merge(preg_split('//u', $q, 0, PREG_SPLIT_NO_EMPTY), array_fill(0, $w-mb_strlen($q), " "))));
 }
	function padLeft($q, $w){
 return implode("", (array_merge(array_fill(0, $w-mb_strlen($q), " "), preg_split('//u', $q, 0, PREG_SPLIT_NO_EMPTY))));
 }
 
$workers1 = [
['Manager', 1, false, 9],
['Manager', 2, false, 3],
['Manager', 3, false, 2],
['Marketer', 1, false, 2],
['Manager', 2, true, 1]
];

$workers2 = [
['Manager', 1, false, 12],
['Marketer', 1, false, 6],
['Analyst', 1, false, 3],
['Analyst', 2, false, 2],
['Marketer', 2, true, 1]
];

$workers3 = [
['Marketer', 1, false, 15],
['Marketer', 2, false, 10],
['Manager', 1, false, 8],
['Engineer', 1, false, 2],
['Marketer', 3, true, 1]
];

$workers4 = [
['Manager', 1, false, 13],
['Manager', 2, false, 5],
['Engineer', 1, false, 5],
['Manager', 1, true, 1]
];

$departments = [
	[$workers1, "Закупок"],
	[$workers2, "Продаж"],
	[$workers3, "Рекламы"],
	[$workers4, "Логистики"]
	];

$company = new Company($departments);

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" . 
     implode("", array_fill(0, 40, '--')) . "\n";
}else{
	echo padLeft ('Антикризисная мера #'."{$headline}", $col7)."\n";
	echo implode("", array_fill(0, 40, '--')) . "\n";
}
	foreach($company as $departments)
	{
		foreach($departments 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 implode("", array_fill(0, 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);
				$department->fireEmployees("Engineer", false, $firedEngineers, $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);
	}
}

$clone1 = new Company($departments);
$clone2 = new Company($departments);
$clone3 = new Company($departments);

printData($company, 0);
AnticrysisCommittee::firstSolution($clone1);
AnticrysisCommittee::secondSolution($clone2);
AnticrysisCommittee::thirdSolution($clone3);