<?php //департаменты и сотрудники
 

error_reporting(-1);
mb_internal_encoding('utf-8');
	

$departmentNames = array("закупок","продаж","рекламы","логистики");

$listOfWorkersDep["закупок"] = array("ме1"=>9,"ме2"=>3,"ме3"=>2,
								"ма1"=>2,"ма2"=>0,"ма3"=>0,
								"ин1"=>5,"ин2"=>0,"ин3"=>0,
								"аа1"=>0,"ан2"=>1,"ан3"=>0);
$listOfWorkersDep["продаж"] = array("ме1"=>12,"ме2"=>0,"ме3"=>0,
								"мар1"=>6,"ма2"=>0,"ма3"=>0,
								"ин1"=>5,"ин2"=>0,"ин3"=>0,
								"ан1"=>3,"ан2"=>2,"ан3"=>0);
$listOfWorkersDep["рекламы"] = array("ме1"=>8,"ме2"=>0,"ме3"=>0,
								"ма1"=>15,"ма2"=>10,"ма3"=>0,
								"ин1"=>2,"ин2"=>0,"ин3"=>0,
								"ан1"=>0,"ан2"=>1,"ан3"=>0);
$listOfWorkersDep["логистики"] = array("ме1"=>13,"мен2"=>5,"ме3"=>0,
								"мар1"=>0,"ма2"=>0,"ма3"=>0,
								"ин1"=>5,"ин2"=>0,"ин3"=>0,
								"ан1"=>0,"ан2"=>1,"ан3"=>0);



/*----------------------------------------------------------------------------*/

class Department 
{
	protected $name;
	protected $listOfWorkers = array();
	protected $numberOfWorkers = 0;
	
	
	public function __construct( $name )					

					
	{
		$this->name = $name;
	}
	
	public function addWorker( Worker $newWorker )								//добавить рабочего
	{
		$this->listOfWorkers[] = $newWorker;
		$this->numberOfWorkers++;
	}
	
	public function getWorkesrGroup( $group, $fromRank, $toRank )				//выбрать группу рабочих
	{
		$workersGroup = array();
		
		foreach( $this->listOfWorkers as $i=>$worker )
		{
			if( ( strtolower(get_class($worker)) == $group ) && ( ( $worker->getRank() >= $fromRank ) && ( $worker->getRank() <= $toRank ) ) )
			{
				$workersGroup[$i] = $worker;
			}
		}
		
		return $workersGroup;
	}
	
	public function getDepartmentChief()										//выбрать начальника департамента
	{
		foreach( $this->listOfWorkers as $i=>$worker )
		{
			if( $worker->getСhief() )
			{
				$chief = $worker;
			}
		}
		return $chief;
	}
	
	public function upWorkersGroupLevel( $group, $fromRank, $toRank, $growth, $percent )	//поднять уровень проценту выбранной группы рабочих
	{
		$workersGroup = $this->getWorkesrGroup( $group, $fromRank, $toRank );
		$workersKeys = array_rand($workersGroup,round($percent*count($workersGroup)/100,0,PHP_ROUND_HALF_UP));
		
		foreach( $workersKeys as $i=>$key )
		{
			$workersGroup[$key]->upRank($growth);
		}
	}
	
	public function setWorkersGroupSalary( $group, $fromRank, $toRank, $newSalary )	//изменить зарплату группе рабочих
	{
		$workersGroup = $this->getWorkesrGroup( $group, $fromRank, $toRank );
		
		foreach( $workersGroup as $i=>$worker )
		{
			$worker->setSalary($newSalary);
		}
	}
	
	public function setWorkersGroupCoffeeConsumptionRate( $group, $fromRank, $toRank, $newCoffeeConsumptionRate ) //изменить потребление кофе группе рабочих
	{
		$workersGroup = $this->getWorkesrGroup( $group, $fromRank, $toRank );
		
		foreach( $workersGroup as $i=>$worker )
		{
			$worker->setCoffeeConsumptionRate( $newCoffeeConsumptionRate );
		}
	}
	
	public function dismissWorkersGroup( $group, $fromRank, $toRank, $percent )	//удалить процент выбранной группы рабочих, преимущественно низкоуровневых
	{																			//руководителей не увольнять
		$workersGroup = $this->getWorkesrGroup( $group, $fromRank, $toRank );
		$workerForDismiss = round($percent*count($workersGroup)/100,0,PHP_ROUND_HALF_UP);
		
		for( $i = $fromRank; $i <= $toRank; $i++ )
		{
			$workersGroup = $this->getWorkesrGroup( $group, $i, $i );
			
			foreach( $workersGroup as $num=>$worker )
			{
				if ( !$worker->getСhief() )
				{	
					unset($this->listOfWorkers[$num]);
					$workerForDismiss--;
					$this->numberOfWorkers--;
				}
				if ( $workerForDismiss == 0)
				{
					break;
				}
			}
			if ( $workerForDismiss == 0)
			{
				break;
			}
		}
	}
	
	public function changeChief( $professionOfNewChief )						//заменить руководителя на работника выбранной профессии самого высокого ранга
	{
		$chief = $this->getDepartmentChief();
		if( !(strtolower(get_class($chief)) == $professionOfNewChief) )
		{
			
			$workersGroup = $this->getWorkesrGroup( $professionOfNewChief, 1, 3 );
			
			$maxRank = 0;
			foreach( $workersGroup as $i=>$worker)
			{
				if( $worker->getRank() > $maxRank )
				{
					$maxRank = $worker->getRank();
					$newChief = $worker;
				}
			}
			if( $maxRank != 0 )
			{
				$chief->removeFromChief();
				$newChief->makeChief();
			}
		}
	}
	
	public function getName()													//название департамента
	{
		return $this->name;
	}
	
	public function getWorkersInfos()											//получить информацию о рабочих
	{
		foreach( $this->listOfWorkers as $number=>$worker )
		{
			$worker->getInfos();
		}
	}
	
	public function getTotalWorkers()											//получить число рабочих
	{
		return $this->numberOfWorkers;
	}
	
	public function getTotalSalary()											//получить общие расходы на зарплату
	{
		$totalSalary = 0;
		foreach( $this->listOfWorkers as $number=>$worker )
		{
			$totalSalary += $worker->getSalary();
		}
		return $totalSalary;
	}
	
	public function getTotalCoffeeConsumption()									//получить расход кофе
	{
		$totalCoffee = 0;
		foreach( $this->listOfWorkers as $number=>$worker )
		{
			$totalCoffee += $worker->getCoffeeConsumption();
		}
		return $totalCoffee;
	}
	
	public function getTotalProduction()										//получить общую продукцию
	{
		$totalProduction = 0;
		
		foreach( $this->listOfWorkers as $number=>$worker )
		{
			$totalProduction += $worker->getProduction();
		}
		
		return $totalProduction;
	}

	public function getDepartmentInfos()										//получить информацию о департаменте
	{
		return array($this->name,
					$this->getTotalWorkers(),
					$this->getTotalSalary(),
					$this->getTotalCoffeeConsumption(),
					$this->getTotalProduction(),
					round($this->getTotalSalary()/$this->getTotalProduction(),2));
	}
}

/*----------------------------------------------------------------------------*/

abstract class 	Worker
{
	protected $department;	
	protected $rank;
	protected $isChief;
	protected $baseSalary;
	protected $coffeeConsumptionRate;
	protected $productionPerMount;
	protected $productionType;
	
	public function __construct( Department $department, $rank, $chief )
	{
		$this->department = $department->getName();
		$this->rank = $rank;
		$this->isChief = $chief;
		$department->addWorker($this);
	}
	
	public function upRank($growth)												//поднять ранг рабочего
	{
		if ( $this->rank+$growth<=3 )
		{
			$this->rank += $growth;
		}
	}
	
	public function makeChief()
	{
		$this->isChief = true;
	}
	
	public function removeFromChief()
	{
		$this->isChief = false;
	}

	public function setSalary($newSalary)										//изменить зарплату
	{
		$this->baseSalary = $newSalary;
	}
	
	public function setCoffeeConsumptionRate($newCoffeeConsumptionRate)			//изменить потребление кофе
	{
		$this->coffeeConsumptionRate = $newCoffeeConsumptionRate;
	}
		
	public function getRank()													//получить ранг рабочего
	{
		return $this->rank;
	}
	
	public function getСhief()													//узнать начальник ли это рабочий
	{
		return $this->isChief;
	}
	
	public function getCoffeeConsumption()										//получить потребление кофе
	{
		if ( $this->isChief )
		{
			$coffee = $this->coffeeConsumptionRate*2;
		}
		else
		{
			$coffee = $this->coffeeConsumptionRate;
		}
		return $coffee;
	}
	
	public function getSalary()													//получить зарплату рабочего
	{
		switch( $this->rank )
		{
			case 1:
				$salary = $this->baseSalary;
				break;
			case 2:
				$salary = $this->baseSalary*1.25;
				break;
			case 3: 
				$salary = $this->baseSalary*1.5;
				break;
		}
		
		if( $this->isChief )
		{
			$salary*= 1.5;
		}
		
		return $salary;
	}
	
	public function getProduction()												//получить проудкцию рабочего
	{
		return $this->productionPerMount;
	}
	
	public function getInfos()													//получить информацию о рабочем
	{
		echo $this->rank;
		echo "-го уровня "; 
		if ($this->isChief)
		{
			echo "и начальник ";
		}
		echo "департамента ";
		echo $this->department;
		echo ", зарплата ";
		echo $this->getSalary();
		echo " тугриков в месяц, выпивает ";
		echo $this->getCoffeeConsumption();
		echo " литров кофе в месяц\n";
	}
}

/*----------------------------------------------------------------------------*/

class Manager extends Worker
{
	protected $coffeeConsumptionRate = 20;
	protected $baseSalary = 500;
	protected $productionPerMount = 200;
	protected $productionType = "страница отчёта";

	public function getInfos()
	{
		echo "Менеджер ";
		parent::getInfos();
	}
}

/*----------------------------------------------------------------------------*/

class Marketer extends Worker
{
	protected $coffeeConsumptionRate = 15;
	protected $baseSalary = 400;
	protected $productionPerMount = 150;
	protected $productionType = "страница отчёта";
	
	public function getInfos()
	{
		echo "Маркетолог ";
		parent::getInfos();
	}
}

/*----------------------------------------------------------------------------*/

class Engineer extends Worker
{
	protected $coffeeConsumptionRate = 5;
	protected $baseSalary = 200;
	protected $productionPerMount = 50;
	protected $productionType = "страница чертёжа";
	
	public function getInfos()
	{
		echo "Инженер ";
		parent::getInfos();
	}
}

/*----------------------------------------------------------------------------*/

class Analyst extends Worker
{
	protected $coffeeConsumptionRate = 50;
	protected $baseSalary = 800;
	protected $productionPerMount = 5;
	protected $productionType = "стратегическое исследование";
	
	public function getInfos()
	{
		echo "Аналитик ";
		parent::getInfos();
	}
}

/*----------------------------------------------------------------------------*/

function padLeft( $string,$columns )
{
	return str_repeat(" ",$columns-mb_strlen($string)).$string;
}

function printInfos( $arrayOfSomething,$columns )
{
	foreach( $arrayOfSomething as $number=>$data )
	{
		echo padLeft( $data,$columns );
	}
	echo "\n";
}


function printTotalResults( $departmentList )
{
	printInfos(array("Департамент","Работников","Зарплата","Расход кофе","Результат(стр)","Расход на стр"),15);

	foreach( $departmentList as $i=>$department )
	{
		$arrayOfInfos[$i] = $department->getDepartmentInfos();
		printInfos($arrayOfInfos[$i],15);
	}
	
	$totalInfos = array("итого",0,0,0,0,0);
	
	foreach( $arrayOfInfos as $key=>$data )
	{
		for( $i=1;$i<6;$i++ )
		{
			$totalInfos[$i] += $data[$i];
		}
	}
	
	$totalInfos[5] = round($totalInfos[2]/$totalInfos[4],2);
	printInfos($totalInfos,15);
}

/*----------------------------------------------------------------------------*/


$departmentList = array();
foreach( $departmentNames as $i=>$name )
{
	$departmentList[$name] = new Department($name);
}

foreach( $departmentNames as $i=>$name )										//вносим работников в департаменты
{
	$workers = $listOfWorkersDep[$name];
	foreach( $workers as $key=>$num)
	{
		if ( $num > 0 )
		{
			switch($key)
			{
				case "ме1":
					for ( $i=0;$i<$num;$i++ )
					{
						new Manager( $departmentList[$name], 1, false );
					}
					break;
				case "ме2":
					for ( $i=0;$i<$num;$i++ )
					{
						new Manager( $departmentList[$name], 2, false );
					}
					break;
				case "ме3":
					for ( $i=0;$i<$num;$i++ )
					{
						new Manager( $departmentList[$name], 3, false );
					}
					break;
				case "ма1":
					for ( $i=0;$i<$num;$i++ )
					{
						new Marketer( $departmentList[$name], 1, false );
					}
					break;
				case "ма2":
					for ( $i=0;$i<$num;$i++ )
					{
						new Marketer( $departmentList[$name], 2, false );
					}
					break;
				case "ма3":
					for ( $i=0;$i<$num;$i++ )
					{
						new Marketer( $departmentList[$name], 3, false );
					}
					break;
				case "ин1":
					for ( $i=0;$i<$num;$i++ )
					{
						new Engineer( $departmentList[$name], 1, false );
					}
					break;
				case "ин2":
					for ( $i=0;$i<$num;$i++ )
					{
						new Engineer( $departmentList[$name], 2, false );
					}
					break;
				case "ин3":
					for ( $i=0;$i<$num;$i++ )
					{
						new Engineer( $departmentList[$name], 3, false );
					}
					break;
				case "ан1":
					for ( $i=0;$i<$num;$i++ )
					{
						new Analyst( $departmentList[$name], 1, false );
					}
					break;
				case "ан2":
					for ( $i=0;$i<$num;$i++ )
					{
						new Analyst( $departmentList[$name], 2, false );
					}
					break;
				case "ан3":
					for ( $i=0;$i<$num;$i++ )
					{
						new Analyst( $departmentList[$name], 3, false );
					}
					break;
			}
		}
	}
}

//добавляем начальников департаментов
new Manager( $departmentList["закупок"], 2, true );
new Marketer( $departmentList["продаж"], 2, true );
new Marketer( $departmentList["рекламы"], 3, true );
new Manager( $departmentList["логистики"], 1, true );


echo "Начальные данные:\n\n";
printTotalResults( $departmentList );


foreach( $departmentList as $i=>$department )									
{ 
	$newDepartmentList[$i] = clone $department;
}
foreach( $newDepartmentList as $i=>$department )								//увольняем 40% инженеров начина с самых низкоранговых
{ 
	$department->dismissWorkersGroup( "engineer", 1, 3, 40 );		
}
echo "\n\nУволить 40% инженеров\n\n";
printTotalResults( $newDepartmentList );


foreach( $departmentList as $i=>$department )									
{ 
	$newDepartmentList[$i] = clone $department;
}
foreach( $newDepartmentList as $i=>$department )								//поднимаем зарплату и расход кофе всем аналитикам, ставим на должность босса аналитика
{ 																				
	$department->setWorkersGroupSalary("analyst",1,3,1100);
	$department->setWorkersGroupCoffeeConsumptionRate("analyst",1,3,75);
	$department->changeChief("analyst");	
}
echo"\n\nПоднять зарплату аналитикам, сделать аналитика боссом::\n\n";
printTotalResults( $newDepartmentList );


foreach( $departmentList as $i=>$department )									
{ 
	$newDepartmentList[$i] = clone $department;
}
foreach( $newDepartmentList as $i=>$department )								//поднимаем уровень 50-ти процентам всех менеджеров 1-го и 2-го уровней на 1
{ 
	$department->upWorkersGroupLevel("manager",1,2,1,50);
}
echo"\n\nПоднять уровень менеджерам:\n\n";
printTotalResults( $newDepartmentList );





