<?php
    //С крипа берет начало каждый класс. Надо будет сделать абстрактным
    abstract class Creep
    {
    	//Базовые данные. потом стоит изменить к ним доступ
    	protected $tier;
    	protected $isBig;
     
    	//Давать доступ только через конструктор
    	public function __construct($tier, $isBig){
    		$this->tier = $tier;
    		$this->isBig = $isBig;
    	}
    	
    	//Забить базовую ставку
    	public function setSalary($num){
    		$this->salary = $num;
    	}
    	
    	//Забить потребление
    	public function setThirst($num){
    		$this->thirst = $num;
    	}
    	
    	//Забиваем является ли крип боссом
    	public function setBigGuy($num){
    		$this->isBig = $num;
    	}
    	
    	//Забиваем тип крипа
    	public function setTier($num){
    		$this->tier = $num;
    	}
     
    	//Выводит зарплату
    	public function countTierSalary(){
    		$salary = $this->salary;
    		switch($this->tier){
    			case 2 : 
    				$salary += $salary * 0.25;
    				break;
    			case 3 :
    				$salary += $salary * 0.5;
    				break;
    		}
    		//Если крип- босс, то поднимаем оплату
    		if($this->isBig == 1){
    			$salary += $salary * 0.5;
    		}
    		return $salary;
    	}
     
    	//Выводит потребление
    	public function countCreepThirst(){
    		$thirst = $this->thirst;
    		if($this->isBig == 1){
    			$thirst += $thirst * 0.5;
    		}
    		return $thirst;
    	}
     
    	//Выводит выхлоп
    	public function countCreepOutput(){
    		$output = $this->output;
    		if($this->isBig == 1){
    			$output = 0;
    		}
    		return $output;
    	}
    	
    	//Выводит является ли крип боссом
    	public function getBossAligment(){
    		return $this->isBig;
    	}
    	
    	//Выводит тип крипа
    	public function getCreepTier(){
    		return $this->tier;
    	}
    }
     
    //Менеджеры
    class Manager extends Creep
    {
    	protected $salary = 500;
    	protected $thirst = 20;
    	protected $output = 200;
    }
     
    //Маркетологи
    class Marketer extends Creep
    {
    	protected $salary = 400;
    	protected $thirst = 15;
    	protected $output = 150;
    }
     
    //Инженеры
    class Engeneer extends Creep
    {
    	protected $salary = 200;
    	protected $thirst = 5;
    	protected $output = 15;
    }
     
    //Аналитики
    class Analyst extends Creep
    {
    	protected $salary = 800;
    	protected $thirst = 50;
    	protected $output = 5;
    }
     
    //Абстрактный департамент, с него пойдут 4 департамента
    abstract class Department
    {
    	//массив с работниками записанный строками
    	protected $textArray = array();
    	
    	//Конструктор для ввода массива с работниками строкой
    	public function __construct(array $a){
    		$this->textArray = $a;
    	}
    	
    	//Массив сотрудников
    	protected $listOfCreeps = array();
     
    	//Метод, записывающий работника в массив
    	public function fillListOfCreeps(){
    		
    		foreach($this->textArray as $vorkers){
	
				//Выводит кол-во работников одного типа и вида
				if(is_numeric(mb_substr($vorkers, 1, 1))){
					$numberOfCreeps = intval(mb_substr($vorkers, 0, 1)) * 10 + intval(mb_substr($vorkers, 1, 1));
				}else{
					$numberOfCreeps = mb_substr($vorkers, 0, 1);
				}

				//проверяет является ли боссом
				$isBoss = (is_numeric(mb_substr($vorkers, -1))) ? 0 : 1;

				//Выводим тип работника
				if($isBoss == 0){
				$creepType = mb_substr($vorkers, -1);
				}else{
					$creepType = mb_substr($vorkers, -2, 1);
				}
				
				//Создаем работников
				if(intval($numberOfCreeps) < 10){
					$creepOffice = mb_substr($vorkers, 1, 2);
				}else{
					$creepOffice = mb_substr($vorkers, 2, 2);
				}
				switch($creepOffice){
					case 'me' : 
						$worker = new Manager(intval($creepType), $isBoss);
						break;
					case 'ma' : 
						$worker = new Marketer(intval($creepType), $isBoss);
						break;
					case 'en' : 
						$worker = new Engeneer(intval($creepType), $isBoss);
						break;
					case 'an' : 
						$worker = new Analyst(intval($creepType), $isBoss);
						break;
				}
	
				//Забиваем массив с работниками массивами с работниками одного вида и типа
				$this->listOfCreeps[] = array_fill(0, intval($numberOfCreeps), $worker);
			}
    	}
     
    	//Метод, выводящий кол-во сотрудников в департаменте
    	public function countNumberOfCreeps(){
    		$creepCount = 0;
    		foreach($this->listOfCreeps as $creepMultiplier){
    			$creepCount += count($creepMultiplier);
    		}
    		return $creepCount;
    	}
     
    	//Метод, выводящий расходы на зарплату
    	public function countSalary(){
    		$sum = 0;
    		foreach($this->listOfCreeps as $creepMultiplier){
    			foreach($creepMultiplier as $creep){
    				$sum += $creep->countTierSalary();
    			}
    		}
    		return $sum;
    	}
     
    	//Метод, выводящий потребление кофе
    	public function countThirst(){
    		$sum = 0;
    		foreach($this->listOfCreeps as $creepMultiplier){
    			foreach($creepMultiplier as $creep){
    				$sum += $creep->countCreepThirst();
    			}
    		}
    		return $sum;
    	}
     
    	//Метод, выводящий кол-во страниц 
    	public function countNumOfPages(){
    		$sum = 0;
    		foreach($this->listOfCreeps as $creepMultiplier){
    			foreach($creepMultiplier as $creep){
    				$sum += $creep->countCreepOutput();
    			}
    		}
    		return $sum;
    	}
     
    	//Средний расход тугриков на страницу
    	public function countCharge(){
    		$charge = $this->countSalary() / $this->countNumOfPages();
    		return floor($charge);
    	}
     
     	//Выводим название департамента
    	public function getName(){
    		return $this->name;
    	}
    	
    	//Первая антикризисная мера
    	public function cutSomeEngeneersHeads(){
    		
    		//Посчитаем общее кол-во инженеров не боссов
    		$commonSum = 0;
    		
    		foreach($this->listOfCreeps as $creepMultiplier){
    			foreach($creepMultiplier as $creep){
    				if($creep instanceof Engeneer && $creep->getBossAligment() != 1){
    					$commonSum++;
    				}
    			}
    		}
    		
    		//Дергаем инженеров как банкомат завещал
    		$numberOfVictims = $commonSum * 0.4;
    		
    		for($i = 0; $i < ceil($numberOfVictims); $i++){
    			//Стоит четыре, т.к. тип крипа не может быть выше третьего уровня
    			$tier = 4;
    			
    			$victim = array();
    			
    			//Перебираю массив с массивами с работниками
    			foreach($this->listOfCreeps as $multiplierKey => $creepMultiplier){
    				foreach($creepMultiplier as $key => $creep){
    					//Ищем жертву с наименьшим значением типа и записываем его ключи в массив
    					if($creep instanceof Engeneer && $creep->getBossAligment() != 1 && $tier > $creep->getCreepTier()){
    						$tier = $creep->getCreepTier();
    						$victim[0] = $multiplierKey;
    						$victim[1] = $key;
    					}
    				}
    			}
    			
    			//Вытаскиваем жертву из массива
    			unset($this->listOfCreeps[$victim[0]][$victim[1]]);
    		}
    	}
    	
    	//Вторая антикризисная писулька
    	public function careBoutAnalysts(){
    		
    		//Меняем базовую ставку и потребление кофе
    		Analyst::setSalary(1100);
    		Analyst::setThirst(75);
    					
    		//Перебираем массив с работниками для поиска аналистов
    		foreach($this->listOfCreeps as $creepMultiplier){
    			foreach($creepMultiplier as $creep){
    				//Если босс не аналист, то опускаем его и ставим нового аналиста во главу
    				if(!$creep instanceof Analyst && $creep->getBossAligment() == 1){
    					$creep->setBigGuy(0);
    					$this->listOfCreeps[] = array_fill(0, 1, new Analyst(3, 1));
    				}
    			}
    		}
    	}
    	
    	//Третий антикризисный метод пошел
    	public function promoteLowerTierManagers(){
    		//Считаю общее кол-во манеджеров 1 и 2 типа
    		$sum1Tier = 0;
    		$sum2Tier = 0;
    		foreach($this->listOfCreeps as $creepMultiplier){
    			foreach($creepMultiplier as $creep){
    				if($creep instanceof Manager && $creep->getCreepTier() == 1){
    					$sum1Tier++;
    				}elseif($creep instanceof Manager && $creep->getCreepTier() == 2){
    					$sum2Tier++;
    				}
    			}
    		}
    		
    		//Кол-во кандидатов на повышение
    		$half1Tier = ceil($sum1Tier);
    		$half2Tier = ceil($sum2Tier);
    		
    		//Перебираю массив, увеличивая тип заданного менеджера
    		foreach($this->listOfCreeps as $creepMultiplier){
    			foreach($creepMultiplier as $creep){
    				//Повышаем половину менеджеров первого ранга
    				if($creep instanceof Manager && $creep->getCreepTier() == 1){
    					if($half1Tier == 0){
    						continue;
    					}else{
    						$newTier = $creep->getCreepTier() + 1;
    						$creep->setTier($newTier);
    						$half1Tier--;
    					}
    				}
    				
    				//Повышаем половину менеджеров второго ранга
    				if($creep instanceof Manager && $creep->getCreepTier() == 2){
    					if($half2Tier == 0){
    						continue;
    					}else{
    						$newTier = $creep->getCreepTier() + 1;
    						$creep->setTier($newTier);
    						$half2Tier--;
    					}
    				}
    				
    				//Если обе полусуммы равны нулю, то останавливаем обход
    				if($half2Tier == 0 && $half1Tier == 0){
    					break;
    				}
    			}
    		}
    	}		
    }
     
    //Отдел закупок
    class Procurement extends Department
    {
    	protected $name = 'Закупок';
    }
     
    //Отдел продаж
    class Selling extends Department
    {
    	protected $name = 'Продаж';
    }
     
    //Отдел рекламы
    class Marketing extends Department
    {
    	protected $name = 'Рекламы';
    }
     
    //Отдел логистики
    class Logistics extends Department
    {
    	protected $name = 'Логистики';
    }
    
    //Создаю класс компании
    class Company
    {
    	//Массив со всеми департаментами
    	private $fullList = array();
     
    	//Доступ к массиву
    	public function addDepartment(Department $department){
    		$this->fullList[] = $department;
    	}
     
    	//получить массив
    	public function getListOfDepartments(){
    		return $this->fullList;
    	}
     
    	//Общее кол-во работников
    	public function getNumOfCreeps(){
    		$sum = 0;
    		foreach($this->fullList as $department){
    			$sum += $department->countNumberOfCreeps();
    		}
    		return $sum;
    	}
     
    	//Общие затраты на зп
    	public function getFinalSalary(){
    		$sum = 0;
    		foreach($this->fullList as $department){
    			$sum += $department->countSalary();
    		}
    		return $sum;
    	}
     
    	//Всего кофе выжрали
    	public function getFinalThirst(){
    		$sum = 0;
    		foreach($this->fullList as $department){
    			$sum += $department->countThirst();
    		}
    		return $sum;
    	}
     
    	//Всего выхлопа
    	public function getFinalOutput(){
    		$sum = 0;
    		foreach($this->fullList as $department){
    			$sum += $department->countNumOfPages();
    		}
    		return $sum;
    	}
     
    	//Затраты на страничку
    	public function getFinalCharge(){
    		$charge = $this->getFinalSalary() / $this->getFinalOutput();
    		return floor($charge);
    	}
    	
    	//Функция для вывода таблички
    	public function printTable(){
    		
		    //Выводим табличку
		    echo padRight('Департамент'). padLeft('сотр.'). padLeft('денег').
		    padLeft('кофе'). padLeft('стр.'). padLeft('кпд'). "\n";
		     
		    foreach($this->getListOfDepartments() as $department){
		    	echo padRight($department->getName()). padLeft($department->countNumberOfCreeps()). 
		    	padLeft($department->countSalary()). padLeft($department->countThirst()).
		    	padLeft($department->countNumOfPages()). padLeft($department->countCharge()). "\n";
		    }
		     
		    echo padRight('Итого'). padLeft($this->getNumOfCreeps()). padLeft($this->getFinalSalary()).
		    padLeft($this->getFinalThirst()). padLeft($this->getFinalOutput()).
		    padLeft($this->getFinalCharge());
    		
    	}
    }
    
    //Функция для забивания строки пробелами справа
	    	function padRight($string){
	     
	    	//Ширина колонки
	    	$column = 13;
	     
	    	$length = mb_strlen(strval($string));
	    	$numOfPads = $column - $length;
	    	$filledColumn = strval($string). str_repeat(" ", $numOfPads);
	    	echo $filledColumn;
		    }
		     
		    //Функция для забивания строки пробелами справа
		    function padLeft($string){
		     
		    	//Ширина колонки
		    	$column = 13;
		     
		    	$length = mb_strlen(strval($string));
		    	$numOfPads = $column - $length;
		    	$filledColumn = str_repeat(" ", $numOfPads). strval($string);
		    	echo $filledColumn;
		    }
     
    //Создаю департаменты
    $procurementArray = array('9me1', '3me2', '2me3', '2ma1', '1me2b');
    $procurement = new Procurement($procurementArray);
    $procurement->fillListOfCreeps();
    
    $sellingArray = array('12me1', '6ma1', '3an1', '2an2', '1ma2b');
    $selling = new Selling($sellingArray);
    $selling->fillListOfCreeps();
    
    $marketingArray = array('15ma1', '10ma2', '8me1', '2en1', '1ma3b');
    $marketing = new Marketing($marketingArray);
    $marketing->fillListOfCreeps();
    
    $logisticsArray = array('13me1', '5me2', '5en1', '1me1b');
    $logistics = new Logistics($logisticsArray);
    $logistics->fillListOfCreeps();
    
    //Создаю вектор
    $vector = new Company;
     
    //Забиваю департаменты
    $vector->addDepartment($procurement);
    $vector->addDepartment($selling);
    $vector->addDepartment($marketing);
    $vector->addDepartment($logistics);
    
    $vector->printTable();
    
    //Проба первой антикризисной меры
    $test1Logistics = new Logistics($logisticsArray);
    $test1Logistics->fillListOfCreeps();
    $test1Logistics->cutSomeEngeneersHeads();
    
    $test1Marketing = new Marketing($marketingArray);
    $test1Marketing->fillListOfCreeps();
    $test1Marketing->cutSomeEngeneersHeads();
    
    $test1Procurement = new Procurement($procurementArray);
    $test1Procurement->fillListOfCreeps();
    $test1Procurement->cutSomeEngeneersHeads();
    
    $test1Selling = new Selling($sellingArray);
    $test1Selling->fillListOfCreeps();
    $test1Selling->cutSomeEngeneersHeads();
    
    $test1Vector = new Company;
    
    $test1Vector->addDepartment($test1Procurement);
    $test1Vector->addDepartment($test1Selling);
	$test1Vector->addDepartment($test1Marketing);
    $test1Vector->addDepartment($test1Logistics);
    
    echo "\n\nПервые антикризисные меры, рубим инженеров, смотрим как они корчатся\n\n";
    $test1Vector->printTable();
    
    //Проба второй антикризисной меры
    $test2Logistics = new Logistics($logisticsArray);
    $test2Logistics->fillListOfCreeps();
    $test2Logistics->careBoutAnalysts();
    
    $test2Marketing = new Marketing($marketingArray);
    $test2Marketing->fillListOfCreeps();
    $test2Marketing->careBoutAnalysts();
    
    $test2Procurement = new Procurement($procurementArray);
    $test2Procurement->fillListOfCreeps();
    $test2Procurement->careBoutAnalysts();
    
    $test2Selling = new Selling($sellingArray);
    $test2Selling->fillListOfCreeps();
    $test2Selling->careBoutAnalysts();
    
    $test2Vector = new Company;
    
    $test2Vector->addDepartment($test2Procurement);
    $test2Vector->addDepartment($test2Selling);
	$test2Vector->addDepartment($test2Marketing);
    $test2Vector->addDepartment($test2Logistics);
    
    echo "\n\nВторые антикризисные меры, растим и плодим аналистов, смотрим как они добреют\n\n";
    $test2Vector->printTable();
    
    //Проба третьей антикризисной меры
    $test3Logistics = new Logistics($logisticsArray);
    $test3Logistics->fillListOfCreeps();
    $test3Logistics->promoteLowerTierManagers();
    
    $test3Marketing = new Marketing($marketingArray);
    $test3Marketing->fillListOfCreeps();
    $test3Marketing->promoteLowerTierManagers();
    
    $test3Procurement = new Procurement($procurementArray);
    $test3Procurement->fillListOfCreeps();
    $test3Procurement->promoteLowerTierManagers();
    
    $test3Selling = new Selling($sellingArray);
    $test3Selling->fillListOfCreeps();
    $test3Selling->promoteLowerTierManagers();
    
    $test3Vector = new Company;
    
    $test3Vector->addDepartment($test3Procurement);
    $test3Vector->addDepartment($test3Selling);
	$test3Vector->addDepartment($test3Marketing);
    $test3Vector->addDepartment($test3Logistics);
    
    echo "\n\nТретьи антикризисные меры, выращиваем мелких менеджеров\n\n";
    $test3Vector->printTable();   