<?php

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


/*
* Introduction
*/
$asciiArt = <<<EOT
 __      ________ _____ _______ ____  _____  
 \ \    / /  ____/ ____|__   __/ __ \|  __ \ 
  \ \  / /| |__ | |       | | | |  | | |__) |
   \ \/ / |  __|| |       | | | |  | |  _  / 
	\  /  | |___| |____   | | | |__| | | \ \ 
	 \/   |______\_____|  |_|  \____/|_|  \_\
EOT;


/*
* General exception class necessary for scalar type hinting.
*/
class WrongDataException extends Exception
{
	private $expectedType;

	public function __construct($expectedType, 
	                            $message = "Wrong data type. Expected ",
	                            $code = 1, 
	                            Exception $previous = null)
	{
		parent::__construct($message, $code, $previous);
		$this->expectedType = $expectedType;
	}
	
	public function __toString()
	{
		return __CLASS__ . "{$this->code}: {$this->message}" . 
		                   "{$this->expectedType}\n" ;
	}
}


/*
* Helper class necessary for an appropriate grid view representation.
*/
class PrettyPrinter
{
	private $head = [
					"col0" => "№",
					"col1" => "департамент",
					"col2" => "Σрабов",
					"col3" => "Σтугриков",
					"col4" => "Σкофе",
					"col5" => "Σстраниц",
					"col6" => "тугриков/страниц"
	             ];
	private $foot = [
					"col0" => " ",
					"col1" => "Итого",
					"col2" => NULL,
					"col3" => NULL,
					"col4" => NULL,
					"col5" => NULL,
					"col6" => NULL
	             ];			 
	private $trail = [];
	private $padder;
	
	private $prettyData = [];
	private $printableResult;
	
	public function __construct($inputArr) 
	{
	    $this->setPadder();
	    $this->setHeadTrials();
	   	
        $enum = range(1, count($inputArr));	
		for($i = 0; $i < count($inputArr); $i++) {
		    $inputArr[$i] = array_merge(["№" => $enum[$i]], $inputArr[$i]);
            $this->fillPrettyData($inputArr[$i]);
		}
		
		$this->setPrintableHeader();
		$this->initFooter($inputArr);
		$this->setPrintableFoot();
		foreach($this->prettyData as $row) {
		    $this->setPrintableResult($row);
		}
	}
	
	private function setPrintableHeader()
	{
	    foreach(array_values($this->head) as $header) {
	        $this->printableResult .= (string)($header);
			$this->printableResult .= " ";
		}
		$this->printableResult .= ("\n" . str_repeat("-", $this->padder) . "\n");
	}
	
	private function setHeadTrials()
	{
	    foreach($this->head as $col=>$str) {
			$this->trail[$col] = mb_strlen($str);
		}							 
	}
	
	private function setPadder()
	{
	    $func = function($value) {
		    return mb_strlen((string)$value);
	    };
	    $this->padder = array_sum(array_map($func, array_values($this->head))) +
				                  count(array_values($this->head)) - 1;
	}
	
	private function fillPrettyData($arr)
	{
	    $func = function($value) {
		    return mb_strlen((string)$value);
	    };
		$dataLens = [];
		$temp = array_combine(array_values($this->trail),
							 array_map($func, array_values($arr)));
		
		foreach($temp as $len1=>$len2) {
			$len = abs($len1 - $len2);
			$data = str_repeat(" ", $len);
			array_push($dataLens, $data);
		}   
		$prettyChunk = array_combine(array_values($arr),
									$dataLens);	
		
		array_push($this->prettyData, $prettyChunk);
	}
	
	private function setPrintableResult($arr)
	{
	    foreach($arr as $data=>$padding) {
		    $res = (string)$data . (string)$padding;
			$this->printableResult .= $res;
			$this->printableResult .= " ";
		}
		$this->printableResult .= ("\n" . str_repeat("-", $this->padder) . "\n");
	}
	
	public function __toString()
	{
	    return $this->printableResult;
	}
	
	private function initFooter($arr)
	{
	    $allWorkers = 0;
		$allCoffee = 0;
		$allSalary = 0;
		$allPages = 0;
		$allAvg = [];
		
		foreach($arr as $subarr) {
		    $cur_vals = array_values($subarr);
			$allWorkers += $cur_vals[2];
			$allSalary += $cur_vals[3];
			$allCoffee += $cur_vals[4];
			$allPages += $cur_vals[5];
			array_push($allAvg, $cur_vals[6]);
		}
		
		$this->foot["col2"] = $allWorkers;
		$this->foot["col3"] = $allSalary;
		$this->foot["col4"] = $allCoffee;
		$this->foot["col5"] = $allPages;
		$this->foot["col6"] = array_sum($allAvg) / count($allAvg);
	}
	
	private function setPrintableFoot()
	{
	    $this->fillPrettyData($this->foot);
	}
}


/*
* Helper class necessary for parsing input data and producing associative array.
* Example:
* INPUT: ["9*ме1", "3*ме2"]
* RESULT:  ["менеджер" => ["ранг" => "1" "количество" => "9"]], [(int) => ["ранг" => "2" "количество" => "3"]]
* It is possible to add new PCRE => workers relations throug "addNewTypeRel($rel)" method.
* Example: addNewTypeRel(["дв" => "дворник"])
*/
class InitDataParser
{
    private $temp = 0;
   	private $depInit = [];
	private $depBoss = [];
	
	private static $reAmt = "(\d+)(\×)";
	private static $reType = ["ан", "ин", "ма", "ме"];
	private static $reRank = "(\d+)";
	
	/*
	* RESULT:
	* "/(\d+)(\×)(ан|ин|ма|ме)(\d+)/ui"
	*/
	private $pattern; 
	/*
	* RESULT:
	* "/(\d+)\×)(ан|ин|ма|ме)(\d+)/ui"
	*/
	private $bossPattern;
	
	private static $typesDispatcher = [
									"ан" => "аналитик",
									"ин" => "инженер",
									"ма" => "маркетолог",
									"ме" => "менеджер"
			   		                  ];

	public function __construct($inputArr, $boss)
    {
	    $this->initRePatterns();
	    
		if(!is_array($inputArr)) {
		    throw new WrongDataException("array");
		}
		
		if(!is_string($boss)) {
		    throw new WrongDataException("string");
		}
		
		foreach($inputArr as $single) {
		    if(!is_string($single)) {
			    throw new WrongDataException("string");
			}
			$this->parseInit($single);
			
			if($boss) {
			    $this->parseBoss($boss);
			}
		}
	}	
	
	private function initRePatterns()
	{
	    $this->pattern = "/" . self::$reAmt . 
	                     "(" . implode("|", self::$reType) . ")" . 
					     self::$reRank . "/ui";
		$this->bossPattern = "/" . 
		                     "(" . implode("|", self::$reType) . ")" .
	                         self::$reRank . "/ui"; 
	}
							   
	private function parseInit($shorty)
	{
	    if(preg_match($this->pattern, $shorty, $matches)) {
		    //var_dump($matches);
			$amt = $matches[1];
			$workType = $matches[3];
			$rank = $matches[4];
		} else {
		    throw new Exception("Wrong format.");
		}
		
		if(!in_array(self::$typesDispatcher[$workType], array_keys($this->depInit))) {
			$this->depInit[self::$typesDispatcher[$workType]] = [
															"ранг" => (int)$rank,
															"количество" => (int)$amt
														  ];
		} else {
		    $part = [
						"ранг" => (int)$rank,
						"количество" => (int)$amt
					];
			
            /*
			* We should somehow get over array_key duplications.	
			* Therefore following code is going to check the type of array_keys.
			* This following checking succids only in case if type is "int".
            * Random bottom boundary should guarantee that it would be greater than
            * amt of specializiatons (e.g. managers, analysts).			
			*/			
			$bottom = rand(100, 10000);
			if ($this->temp !== $bottom) {
			    $this->depInit[$bottom] = $part;
			} else {
			    $this->depInit[$bottom + 1] = $part;
			}
			$this->temp = $bottom;
		}
	}
	
	private function parseBoss($str) 
	{
	    if(preg_match($this->bossPattern, $str, $matches)) {
			$workType = $matches[1];
			$rank = $matches[2];
		} else {
		    throw new Exception("Wrong format.");
		}
		$this->depBoss = [
							"квалификация" => self::$typesDispatcher[$workType],
							"ранг" => (int)$rank						   
		                 ]; 
	}
	
	public function getMatchedDepInit() 
	{
	    return $this->depInit;
	}
	
	public function getMatchedDepBoss() 
	{
	    return $this->depBoss;
	}
	
	public static function addNewTypeRel($rel) 
	{
	    self::$typesDispatcher = array_merge(self::$typesDispatcher, $rel);
		array_push(self::$reType, array_keys($rel)[0]);
	}
}

/*
* General class for all the employees, holding data and operations general for all subclasses.
*/
abstract class Worker
{
    protected $salary;
	protected $coffeeAmount;
	protected $rank;
	protected $bossHonors = [];
	protected $workDone;
	
    public function getSalary()
    {
	    return $this->salary + $this->salary * ($this->rank / 100);
    }
    
    public function setSalary($num)
    {
    	if(is_numeric($num)) {
    		$this->salary = (int)$num;
    	} else {
    		throw new WrongDataException("int");
    	}
    	
    }
    
	public function getCoffee()
	{
	    return $this->coffeeAmount;
	}
	
	public function setCoffee($amount)
	{
	    if(is_numeric($amount)) {
		    $this->coffeeAmount = (int)$amount;
		} else {
		    throw new WrongDataException("int");
		}
	}
	
	public function getRank()
    {
    	return $this->rank;
    }
    
    public function setRank($num)
    {
	    if(is_numeric($num)) {
    		$this->rank = (int)$num;
    	} else {
    		throw new WrongDataException("int");
    	}
    	
    }
    
 	public function getWorkResults()
	{
	    return $this->workDone;
	}
	
	public function setWorkResults($num)
	{
		if(is_numeric($num)) {
			$this->workDone = (int)$num;
		} else {
			throw new WrongDataException("int");
		}
	}

    public function isBoss()
	{
	    if(!empty($this->bossHonors)) {
		    return true;
		} 
		return false;
	}
	
	public function getBossSalary()
	{
        $baseSalary = $this->salary + $this->salary * ($this->rank / 100);
		return $baseSalary + $baseSalary * ($this->bossHonors["зарплата"] / 100); 
	}
	
	public function getBossCoffee()
	{
	    return $this->coffeeAmount * $this->bossHonors["кофе"];
	}
	
	public function getBossWork()
	{
	    return $this->bossHonors["страницы"];
	}
	
	public function setBossHonors($honors)
	{
	    $this->bossHonors = $honors;
	}
}


class Manager extends Worker
{
	
}


class Analyst extends Worker
{
    
}


class Engineer extends Worker
{
    
}


class Marketer extends Worker
{

}


class Accountant extends Worker
{

}


/*
* Factory class that uses dispatchers to initialize a "Worker" subclasses' object.
*/
class WorkersCreator
{
    /*
	* Workers' condition's dispatchers.
	*/
	protected static $commonRanks = [1 => 0, 2 => 25, 3 => 50];
	protected static $condsDispatcher = [
								"аналитик" => 
								[
									"зарплата" => 800,
									"ранги" => NULL,
									"кофе" => 50,
									"страницы" => 5				 
								],	
								"инженер" => 
								[
									"зарплата" => 200,
									"ранги" => NULL,
									"кофе" => 5,
									"страницы" => 50				 
								],								 
								"менеджер" => 
								[
									"зарплата" => 500,
									"ранги"  => NULL,
									"кофе" => 20,
									"страницы" => 200
								],
								"маркетолог" => 
								[
									"зарплата" => 400,
									"ранги" => NULL,
									"кофе" => 15,
									"страницы" => 150				 
								],		
                                ];
    protected static $clsDispatcher = [   
									"аналитик" => "Analyst",
									"инженер" => "Engineer",
									"маркетолог" => "Marketer",
									"менеджер" => "Manager",
							    ];
	/*
	* Boss's honor's dispatcher.
	*/
	protected static $genHonors = [
								"зарплата" => 50,
								"кофе" => 2,
								"страницы" => 0  
	                        ]; 
    protected static $bossConds = [];
	
	/*
	* Array, populated with "Worker" subclasses' objects.
	*/
	protected $depWorkers = [];

	public function __construct($inDepInit, $inBoss)
    {
	    if(!is_array($inDepInit)) {
    		throw new WrongDataException("array");
		}
		if(!is_string($inBoss)) {
		    throw new WrongDataException("string");
		}
		
		$parsedWorkers = new InitDataParser($inDepInit, $inBoss);
		$depInit = $parsedWorkers->getMatchedDepInit();
		$boss = $parsedWorkers->getMatchedDepBoss();
		
		self::initRanks();
		
		if (!empty($boss)) {
		    $bossConds["привилегии"] = self::$genHonors;
		    self::$bossConds = array_merge($bossConds, $boss);
			$short = $boss["квалификация"];
		    $this->initBoss($short);
		}	
		
		$this->initDepWorkers($depInit);
	}
	
	private static function initRanks()
	{
	    foreach(array_keys(self::$condsDispatcher) as $title) {
		    self::$condsDispatcher[$title]["ранги"] = self::$commonRanks;
		}
	}
	
	private function initDepWorkers($depInit)
	{
	    $cls = self::$clsDispatcher;
		$cond = self::$condsDispatcher;

        for ($i = 0; $i < count(array_keys($depInit)); $i++) {		
			$shortName = array_keys($depInit)[$i];
						
			// Explicit and silent converting of ints to previous string value. 
			// This tricky way helps excluding key duplicates in an array.
			if (!is_string($shortName)) {
			    $shortName = $temp;
			} else {
			    $temp = $shortName; 
			}
			$tempRank = array_values($depInit)[$i]["ранг"];
			$rank = $cond[$shortName]["ранги"][$tempRank];
			$limit = array_values($depInit)[$i]["количество"];
			if (in_array($shortName, array_keys($cls)) && in_array($shortName, array_keys($cond))) {
				$this->initWorkersClass($cls[$shortName], $cond[$shortName], $rank, $limit);
			} else {
				throw new Exception("String doesn't match to class");
			}
		}
	}
	
	protected function initWorkersClass($workerCls, $workersCond, $rank, $limit)
    {
	    for($i = 0; $i < $limit; $i++) {
    		$worker = new $workerCls;
			$worker->setSalary($workersCond["зарплата"]);
			$worker->setCoffee($workersCond["кофе"]);
			$worker->setRank($rank);
    		$worker->setWorkResults($workersCond["страницы"]);
    		array_push($this->depWorkers, $worker);
    	}
    }
    
	public function initBoss($short)
	{
	    $cls = self::$clsDispatcher;
		$cond = self::$condsDispatcher;
	    if (in_array($short, array_keys($cls))) {
		    $bossCls = $cls[$short];
			$basicConds = $cond[$short];
		} else {
		    throw new Exception("String doesn't match to class");
		}
		
	    $boss = new $bossCls;
		$boss->setSalary($basicConds["зарплата"]);
		$tempRank = self::$bossConds["ранг"];
		$boss->setRank($cond[$short]["ранги"][$tempRank]);
		$boss->setCoffee($cond[$short]["кофе"]);
		$boss->setBossHonors(self::$bossConds["привилегии"]);
		
		array_push($this->depWorkers, $boss);
	}
	
	public static function addClassRel($title, $classname) 
	{
	    self::$clsDispatcher[$title] = $classname;
	}
	
	public static function addCondRel($title, $cond)
	{
	    self::$condsDispatcher[$title] = $cond;
	}
		
	public static function changeSalary($victim, $newVal)
	{
	    self::$condsDispatcher[$victim]["зарплата"] = $newVal;
	}
	
	public static function changeBossRank($newVal)
	{
	    self::$bossConds["ранг"] = $newVal;
	}
}


/*
* Additional functionality provides ways to generate and fecth statistical data
* (e.g. total department salary).
*/
class Department extends WorkersCreator
{
    private $totalSalary = [];
	private $totalCoffeeAmount = [];
	private $totalWorkDone = [];
	private $statData = [];
	
	private static $depName;
	
	function __construct($inDepInit, $inBoss, $depName)
	{
	    if(!is_string($depName)) {
		    throw new WrongDataException("string");
		}
	    self::$depName = $depName;
		
		parent::__construct($inDepInit, $inBoss);		
	    		
		$this->fillTotals();
		$this->initStatData();
	}
	
	public function fillTotals()
	{
		foreach($this->depWorkers as $worker) {
			if(!is_object($worker)) {
				throw new WrongDataException("object");
				break;
			}  
			if($worker->isBoss()) {
			    array_push($this->totalSalary, $worker->getBossSalary());
				array_push($this->totalCoffeeAmount, $worker->getBossCoffee());
				array_push($this->totalWorkDone, $worker->getBossWork());
		    } else {
			    array_push($this->totalCoffeeAmount, $worker->getCoffee());
				array_push($this->totalWorkDone, $worker->getWorkResults());
			    array_push($this->totalSalary, $worker->getSalary());
			}
		}
	}
	
	public function getTotalSalary() 
	{
	    return array_sum($this->totalSalary);
	}
	
	public function getTotalPages()
	{
	    return array_sum($this->totalWorkDone);
	}
		
    public function getTotalCoffee() 	
	{
	    return array_sum($this->totalCoffeeAmount);
	}
	
	public function countDepWorkers()
	{
	    return count($this->depWorkers);
	}
	
	public function initStatData()
	{
	    $this->statData["Департамент"] = self::$depName;
		$this->statData["Всего рабов"] = $this->countDepWorkers();
	    $this->statData["Общая з/п"] = $this->getTotalSalary();
		$this->statData["Всего кофе"] = $this->getTotalCoffee();
		$this->statData["Всего страниц"] = $this->getTotalPages();
		$this->statData["Тугриков на страницу"] = number_format(($this->getTotalSalary() / 
		                                                         $this->getTotalPages()), 3);
	}
	
	public function getStatData()
	{
	    return $this->statData;
	}
	
	public function getWorkers()
	{
	    return $this->depWorkers;
	}
	
	public static function addNewWorkerType($newWorker)
	{
	    $title = $newWorker[0];
		$clsname = $newWorker[1];
		$shortTitle = $newWorker[2];
		$conds = $newWorker[3];
		
		if(!is_string($title) || !is_string($clsname) || !is_string($shortTitle)) {
		    throw new WrongDataException("string");
		}
		
		if(!is_array($conds)) {
		    throw new WrongDataException("array");
		}
	    
	    parent::addClassRel($title, $clsname);
		parent::addCondRel($title, $conds);
		InitDataParser::addNewTypeRel([$shortTitle => $title]);
	}
	
	public static function changeWorkerCond($newConds)
	{
	    $victim = $newConds[0];
		$condKey = $newConds[1];
		$newVal = $newConds[2];
		
		if(!is_string($victim) || !is_string($condKey)) {
		    throw new WrongDataException("string");
		}
		
		if(!is_numeric($newVal)) {
		    throw new WrongDataException("int");
		}
	    
		switch ($condKey) {
		    case "зарплата":
			    parent::changeSalary($victim, $newVal);
				break;
			default:
                throw new Exception("Not implemented yet.");
		}
	}
	
	public function setNewWorkers($arr)
	{
	    $this->depWorkers = $arr;
	}
	
	
	public function __clone()
	{
	    //$this->depName = $this->depName;
	    $this->totalSalary = [];
		$this->totalCoffeeAmount = [];
		$this->totalWorkDone = [];
		$this->statData = [];
	}
	
	public function addWorker($title, $amt, $rank)
	{
	    //var_dump($title);
	    $cls = parent::$clsDispatcher[$title];
	    $conds = parent::$condsDispatcher[$title];
		$rank = $conds["ранги"][$rank];
		//var_dump($rank);
	    $this->initWorkersClass($cls, $conds, $rank, $amt);
		//initWorkersClass($workerCls, $workersCond, $rank, $limit)
	}
}


/*
* Testing of general initialization and basic structure.
*/
function testingBasic() 
{
	$purchaseDepInput = ["9×ме1", "3×ме2", "2×ме3", "2×ма1"];
	$purchaseDepBossInput = "ме2";
	$purchaseDepName = "покупок";
	
    $saleDepInput = ["12×ме1", "6×ма1", "3×ан1", "2×ан2"];
	$saleDepBossInput = "ма2";
	$saleDepName = "продаж";
	
	$adsDepInput = ["15×ма1", "10×ма2", "8×ме1", "2×ин1"];
	$adsDepBossInput = "ма3";
	$adsDepName = "рекламы";
	
	$logisticsDepInput = ["13×ме1", "5×ме2", "5×ин1"];
	$logisticsDepBossInput = "ме1";
	$logisticsDepName = "логистики";
	
	$purchaseDep = new Department($purchaseDepInput, $purchaseDepBossInput, $purchaseDepName);
	$saleDep = new Department($saleDepInput, $saleDepBossInput, $saleDepName);
	$adsDep = new Department($adsDepInput, $adsDepBossInput, $adsDepName);
    $logisticsDep = new Department($logisticsDepInput, $logisticsDepBossInput, $logisticsDepName);
    
	
	$purchaseDepData = $purchaseDep->getStatData();
	$saleDepData = $saleDep->getStatData();
	$adsDepData = $adsDep->getStatData();
	$logisticsDepData = $logisticsDep ->getStatData();
	
	$allDeps = [$purchaseDepData, $saleDepData, $adsDepData, $logisticsDepData];
	
	$data = new PrettyPrinter($allDeps);
	echo $data;
}


/*
* Testing of addition of new employee and 
* testing of changes made to analyst's inital conditions. 
*/
function testingAddedChanges() 
{
    /*
	* New Worker type - Accountant. And his/her conditions.
	*/
	$accConds = [					
	                "зарплата" => 300,
				    "ранги" => NULL,
					"кофе" => 10,
					"страницы" => 25
				];	
	
	$newWorker = ["бухгалтер", "Accountant", "бу", $accConds];
	   
	/*
	* Let's reduce analysts salary to 100 T.  
	*/
	$crisis = ["аналитик", "зарплата", 700];
	
	
	$saleDepInputBef = ["12×ме1", "6×ма1", "3×ан1", "2×ан2"];
	$saleDepBossInputBef = "ма2";
	$saleDepNameBef = "продаж";
	$saleDepBef = new Department($saleDepInputBef, $saleDepBossInputBef, $saleDepNameBef);
	$before = $saleDepBef->getTotalSalary();
	
	echo "\n";
	echo "Тестирование добавления нового рабочего. Бухгалтер: з.п => 300, кол-во => 3\n";
	echo "На дворе кризис. Срежем з/п аналитиков до 700 у.е.\n";
	echo "\n";
	
	Department::addNewWorkerType($newWorker);
	Department::changeWorkerCond($crisis);
	
	$testDepInput = ["12×ме1", "6×ма1", "3×ан1", "2×ан2", "3×бу1"];
	$testDepBoss = "ма2";
	$testDepName = "тестовый";
	
	$saleDepInput = ["12×ме1", "6×ма1", "3×ан1", "2×ан2"];
	$saleDepBossInput = "ма2";
	$saleDepName = "продаж";
	
	$testDep = new Department($testDepInput, $testDepBoss, $testDepName);
	$saleDep = new Department($saleDepInput, $saleDepBossInput, $saleDepName);
	
	$testDepData = $testDep->getStatData();
	$saleDepData = $saleDep->getStatData();
	
	$data = new PrettyPrinter([$testDepData, $saleDepData]);
	
	$newWorkerTest = $testDep->getTotalSalary() - $saleDep->getTotalSalary();
    $crisisTest = $saleDepBef->getTotalSalary()	- $saleDep->getTotalSalary();
	
	echo $data . "\n";
	echo "Результаты разниц до и после.\n";
	echo "Верно: 1. 300*3 = 900"; 
	echo "       2. 100*3 + 100*2 + 100*(25/100)*2 = 550\n";
	echo "1. Σтугриков (тестовый) - " . "Σтугриков (продаж) "  . "= " . "{$newWorkerTest}\n";
	echo "2. Σтугриков (до кризиса) - " . "Σтугриков (после) "  . "= " . "{$crisisTest}\n";
}


class CrisisModel
{
    private $allDeps;
	private $newModelWorkers = [];
	private $purchaseDep;
	private $saleDep;
	private $adsDep;
	private $logisticsDep;
	private $newDeps = [];
	private $newStatData = [];
	
	public function __construct($model) 
	{
	    $this->initBase();
			    
	    if($model === 1) {
		    foreach($this->allDeps as $depWorkers) {
			    $this->tryModel1($depWorkers);
			}
		} elseif($model === 2) {
		    foreach($this->allDeps as $depWorkers) {
			    $this->tryModel2($depWorkers);
			}
		} elseif($model === 3) {
		    //var_dump(count($this->allDeps));
		    foreach($this->allDeps as $depWorkers) {
			    $this->tryModel3($depWorkers);
			}
		}
		$this->setNewWorkers($this->newModelWorkers);
        $this->setNewStatData();	
        $this->showModel();		
	}
	
	private function initBase()
	{
	    $purchaseDepInput = ["9×ме1", "3×ме2", "2×ме3", "2×ма1"];
		$purchaseDepBossInput = "ме2";
		$purchaseDepName = "покупок";
		
		$saleDepInput = ["12×ме1", "6×ма1", "3×ан1", "2×ан2"];
		$saleDepBossInput = "ма2";
		$saleDepName = "продаж";
		
		$adsDepInput = ["15×ма1", "10×ма2", "8×ме1", "2×ин1"];
		$adsDepBossInput = "ма3";
		$adsDepName = "рекламы";
		
		$logisticsDepInput = ["13×ме1", "5×ме2", "5×ин1"];
		$logisticsDepBossInput = "ме1";
		$logisticsDepName = "логистики";
		
		$this->purchaseDep = new Department($purchaseDepInput, $purchaseDepBossInput, $purchaseDepName);
		$this->saleDep = new Department($saleDepInput, $saleDepBossInput, $saleDepName);
		$this->adsDep = new Department($adsDepInput, $adsDepBossInput, $adsDepName);
		$this->logisticsDep = new Department($logisticsDepInput, $logisticsDepBossInput, $logisticsDepName);
		
		$this->allDeps = [$this->purchaseDep, $this->saleDep, $this->adsDep, $this->logisticsDep];
    }
	
	public function tryModel1($dep)
	{
	    $depWorkers = $dep->getWorkers();
	    $lim = count($depWorkers);
		$limit = 0;
	    foreach($depWorkers as $worker) {
		    if(get_class($worker) === "Engineer") {
			    $limit++;
			}
		}
		foreach($depWorkers as $worker) {
		    if(get_class($worker) === "Engineer" && $worker->isBoss() === false) {
			    unset($depWorkers[array_search($worker, $depWorkers)]);
			}
		}
		array_push($this->newModelWorkers, $depWorkers);
	}
	
	public function tryModel2($dep)
	{
	    $depWorkers = $dep->getWorkers();
		foreach($depWorkers as $worker) {
		    if(get_class($worker) === "Analyst") {
			    $worker->setSalary(1100);
				$worker->setCoffee(75);
			}
		}
		array_push($this->newModelWorkers, $depWorkers);
	}
	
	public function tryModel3($dep) 
	{
	    $depWorkers = $dep->getWorkers();
		$rankOne = [];
		$rankTwo = [];
		foreach($depWorkers as $worker) {
		    if(get_class($worker) === "Manager" && $worker->isBoss() === false) {
			    if($worker->getRank() === 0) {
				    array_push($rankOne, $worker);
				} elseif($worker->getRank() === 25) {
				    array_push($rankTwo, $worker);
				} 
			}
		}	
		$lim1 = round(count($rankOne)/2);
		$dep->addWorker("менеджер", $lim1, 2);
		$lim2 = round(count($rankTwo)/2);
		$dep->addWorker("менеджер", $lim2, 3);
		//var_dump($lim1);
		//var_dump($lim2);
		//var_dump(count($depWorkers));
		//var_dump(count($dep->getWorkers()));
		array_push($this->newModelWorkers, $dep->getWorkers());
	}
		
	public function setNewWorkers($newArr)
	{
	    $newPD = clone $this->purchaseDep;
		$newPD->setNewWorkers($newArr[0]);
		$newPD->fillTotals();
		$newSD = clone $this->saleDep;
		$newSD->setNewWorkers($newArr[1]);
		$newSD->fillTotals();
		$newAD = clone $this->adsDep;
		$newAD->setNewWorkers($newArr[2]);
		$newAD->fillTotals();
		$newLD = clone $this->logisticsDep;
		$newLD->setNewWorkers($newArr[3]);
		$newLD->fillTotals();
		$this->newDeps = [$newPD, $newSD, $newAD, $newLD];
	}
	
	public function setNewStatData()
	{
	    foreach($this->newDeps as $dep) {
		    $dep->initStatData();
		    array_push($this->newStatData, $dep->getStatData());
		}
	}
	
	public function showModel()
	{
	    $data = new PrettyPrinter($this->newStatData);
        echo $data;		
	}
} 


echo "{$asciiArt}";
echo "\n\n";
testingBasic();
testingAddedChanges(); 
echo "\n\n";
echo "Подборка моделей антикризисных ситуаций\n";
echo "Начальные данные вывведены в 1 таблице\n";
echo "\n\n";
$crisisModel1 = new CrisisModel(1);
$crisisModel2 = new CrisisModel(2);
$crisisModel3 = new CrisisModel(3);
