<?php
error_reporting(-1);
header("Content-Type: text/plain; charset=utf-8");
mb_internal_encoding('utf-8');


class Antycrisis
{
	static function setAnticrisysProgram1($organisation) {

		$askEngineer = function ($worker) {
			return (get_class($worker) == "Engineer");
		};
		
		$askLeader = function($worker) {
			return ($worker->leader != 1);
		};

		foreach ($organisation->departments as $dep) {
			$allEngineers = array_filter($dep->workers, $askEngineer);
			$targetAmount = ceil(count($allEngineers) * 0.4);
			$notLeaderEngineers = array_filter($allEngineers, $askLeader);
			$targetEngineers = array_slice($notLeaderEngineers, 0, $targetAmount);
			foreach ($targetEngineers as $name => $fireHim) {
				$dep->fireEmployee($fireHim);
			}
		}
	}

	static function setAnticrisysProgram3($organisation) {

		$askManager = function($worker) {
   			return ((get_class($worker) == "Manager") and ($worker->rank != 3));
		};

        foreach ($organisation->departments as $dep) {

        	$managers1_2 = array_filter($dep->workers, $askManager);
        	$targetAmount = ceil(count($managers1_2) * 0.5);
        	$targetManagers = array_slice($managers1_2, 0, $targetAmount);

        	foreach ($targetManagers as $luckyMan){
        		$luckyMan->riseRank();
        	}
        	
        }
    }

}

    
class Organisation //содержит методы для подсчета общих и средних параметров по конторе
{
    protected $name;
    public $departments = array();
     
    public function __construct($name)
    {
        $this->name = $name;
    }
     
     
    public function countTotalWorkers()
    {
        $totalWorkers = 0;
        foreach($this->departments as $unit) {
            $totalWorkers += $unit->countDepWorkers();
        }
        return $totalWorkers;
    }
     
    public function countAveregeWorkers()
    {
        return $this->countTotalWorkers() / count($this->departments);
    }
     
    public function countTotalCoffe()
    {
        $companyCoffe = 0;
        foreach ($this->departments as $dep) {
            $companyCoffe += $dep->countDepCoffe();
        }
        return $companyCoffe;
    }
     
    public function countTotalSalary()
    {
        $companySalary = 0;
        foreach ($this->departments as $dep) {
            $companySalary += $dep->countDepSalary();
        }
        return $companySalary;
    }
     
    public function countTotalDocs()
    {
        $companyDocs = 0;
        foreach ($this->departments as $dep) {
            $companyDocs += $dep->countDepDocs();
        }
        return $companyDocs;
    }
     
     
    public function countAveregeCoffe()
    {
        return $this->countTotalCoffe() / count($this->departments);
    }
     
    public function countAveregeSalary()
    {
        return $this->countTotalSalary() / count($this->departments);
    }
     
    public function countAveregeDocs()
    {
        return $this->countTotalDocs() / count($this->departments);
    }
     
    public function countTotalEfficiency()
    {
        $companyEfficiency = 0;
        foreach ($this->departments as $dep) {
            $companyEfficiency += $dep->countDepEfficiency();
        }
        return $companyEfficiency;
    }
     
    public function countAveregeEfficiency()
    {
        return $this->countTotalEfficiency() / count($this->departments);
    }
        
}
     
class Department
{
    protected $name;
    public $workers = array();
     
    public function __construct($name)
    {
        $this->name = $name;
    }
    
    public function fireEmployee($employee)
    {
    	foreach ($this->workers as $num => $worker) {

    		//var_dump($num);
    		//var_dump($worker);
    		if ($employee === $worker) {
    			unset($this->workers[$num]);
    		}
    	}
    }
 
    public function addEmployee($employee)
    {
        if (is_array($employee)) {
            $this->workers = array_merge($this->workers, $employee);
        } else {
            $this->workers[] = $employee;
        }
    }
     
    public function getName()
    {
        return $this->name;
    }
     
    public function countDepWorkers()
    {
        return count($this->workers);
    }
     
    public function countDepCoffe()
    {
        $totalDepCoffe = 0;
        foreach ($this->workers as $worker) {
            $totalDepCoffe += $worker->getCoffeUsage();
        }
        return $totalDepCoffe;
    }
     
    public function countDepSalary()
    {
        $totalDepSalary = 0;
        foreach ($this->workers as $worker) {
            $totalDepSalary += $worker->getSalary();
        }
        return $totalDepSalary;
    }
     
    public function countDepDocs()
    {
        $totalDepDocs = 0;
        foreach ($this->workers as $worker) {
            $totalDepDocs += $worker->getDocs();
        }
        return $totalDepDocs;
    }
     
    function countDepEfficiency()
    {
        return $this->countDepSalary() / $this->countDepDocs();
    }
     
}
     
class Employee
{
    public $rank;
    public $leader;
    protected $defaultSalary;
    protected $defaultCoffeUsage;
    protected $defaultDocs;
     
    public function __construct($rank, $leader) {
        $this->rank = $rank;
        $this->leader = $leader;
    }

    public function riseRank()
    {
    	if ($this->rank == 1 or $this->rank == 2) {
    		$this->rank++;
    	}
    }

    public function getSalary()
    {
        if ($this->rank == 2) {
            $rankBonus = 1.25;
        } elseif ($this->rank == 3) {
            $rankBonus = 1.5;
        } else {
            $rankBonus = 1;
        }
     
        if ($this->leader == true) {
            $leaderBonus = 1.5;
        } else {
            $leaderBonus = 1;
        }
        return $this->defaultSalary * $rankBonus * $leaderBonus;
    }
     
    public function getCoffeUsage()
    {
        if ($this->leader) {
            return $this->defaultCoffeUsage * 2;
        } else {
            return $this->defaultCoffeUsage;
        }
    }
     
    public function getDocs()
    {
        if ($this->leader) {
            return 0;
        } else {
            return $this->defaultDocs;
        }
    }
}
     
class Manager extends Employee
{
    protected $defaultSalary = 500;
    protected $defaultCoffeUsage = 20;
    protected $defaultDocs = 200;
}
     
class MarketGuy extends Employee
{
    protected $defaultSalary = 400;
    protected $defaultCoffeUsage = 15;
    protected $defaultDocs = 150;
}
     
class Engineer extends Employee
{
    protected $defaultSalary = 200;
    protected $defaultCoffeUsage = 5;
    protected $defaultDocs = 50;
}
     
class Analyst extends Employee
{
    protected $defaultSalary = 800;
    protected $defaultCoffeUsage = 50;
    protected $defaultDocs = 5;
}
     
     
class Factory
{
    static function createEmployee($amount, $class, $rank, $leader) 
    {
        $employees = array();
        for($i=1; $i<=$amount; $i++ ) {
            $employees[] = new $class($rank, $leader);
        }
        return $employees;
    }
     
}
     
    //создаю организацию:
$vector = new Organisation("Вектор");
     
    //департаменты
    $purchase = new Department("Департамент закупок");
    //заполняю планктоном
    $purchase->addEmployee(Factory::createEmployee(9, "Manager", 1, false));
    $purchase->addEmployee(Factory::createEmployee(3, "Manager", 2, false));
    $purchase->addEmployee(Factory::createEmployee(2, "Manager", 3, false));
    $purchase->addEmployee(Factory::createEmployee(2, "MarketGuy", 1, false));
    $purchase->addEmployee(Factory::createEmployee(1, "Manager", 2, true));
    $vector->departments[] = $purchase; //добавляю созданный департамент в организацию
     
    $sales = new Department("Департамент продаж");
    $sales->addEmployee(Factory::createEmployee(12, "Manager", 1, false));
    $sales->addEmployee(Factory::createEmployee(16, "MarketGuy", 1, false));
    $sales->addEmployee(Factory::createEmployee(3, "Analyst", 1, false));
    $sales->addEmployee(Factory::createEmployee(2, "Analyst", 2, false));
    $sales->addEmployee(Factory::createEmployee(1, "MarketGuy", 2, true));
    $vector->departments[] = $sales;
     
    $advertising = new Department("Департамент рекламы");
    $advertising->addEmployee(Factory::createEmployee(15, "MarketGuy", 1, false));
    $advertising->addEmployee(Factory::createEmployee(10, "MarketGuy", 2, false));
    $advertising->addEmployee(Factory::createEmployee(8, "Manager", 1, false));
    $advertising->addEmployee(Factory::createEmployee(2, "Engineer", 1, false));
    $advertising->addEmployee(Factory::createEmployee(1, "MarketGuy", 3, true));
    $vector->departments[] = $advertising;
     
    $logistics = new Department("Департамент логистики");
    $logistics->addEmployee(Factory::createEmployee(13, "Manager", 1, false));
    $logistics->addEmployee(Factory::createEmployee(5, "Manager", 2, false));
    $logistics->addEmployee(Factory::createEmployee(5, "Engineer", 1, false));
    $logistics->addEmployee(Factory::createEmployee(1, "Manager", 1, true));
    $vector->departments[] = $logistics;
     
     
     

     
function padLeft ($string, $length) {
    $strLength = mb_strlen($string);
    $num = $length - $strLength - 1;
    if ($num < 0) {
    	$num = 0;
    }
    $spases = str_repeat(" ", $num);
    $string = "|" . $spases . $string;
    return $string;
}
     
function padRight ($string, $length) {
    $strLength = mb_strlen($string);
    $num = $length - $strLength;
    if ($num < 0) {
	    $num = 0;
    }
    $spases = str_repeat(" ", $num);
    $string .= $spases;
    return $string;
}
    

    //echo "<pre>";
function makeReport($vector){

	$col1 = 23;
    $col2 = 13;
    $col3 = 13;

	echo padRight("Департамент", $col1) .
	    padLeft("сотрудников", $col2) .
	    padLeft("тугрики", $col3) .
	    padLeft("кофе", $col3) .
	    padLeft("документы", $col2) .
	    padLeft("тугр./документы", $col1) .
	    "\n";
	     
	echo "--------------------------------------------------------------------------------\n";
	     
	foreach ($vector->departments as $dep) {
	    echo padRight($dep->getName(), $col1) .
		    padLeft($dep->countDepWorkers(), $col2) .
	    	padLeft($dep->countDepSalary(), $col3) .
	    	padLeft($dep->countDepCoffe(), $col3) .
	    	padLeft($dep->countDepDocs(), $col2) .
	    	padLeft($dep->countDepEfficiency(), $col1) .
	    	"\n";
	}
	     
	echo "--------------------------------------------------------------------------------\n";
	     
	echo padRight("Среднее", $col1) .
	    padLeft($vector->countAveregeWorkers(), $col2) .
	    padLeft($vector->countAveregeSalary(), $col3) .
	    padLeft($vector->countAveregeCoffe(), $col3) .
	    padLeft($vector->countAveregeDocs(), $col2) .
	    padLeft($vector->countAveregeEfficiency(), $col1) .
	    "\n" ;
	     
	echo padRight("Всего", $col1) .
	    padLeft($vector->countTotalWorkers(), $col2) .
	    padLeft($vector->countTotalSalary(), $col3) .
	    padLeft($vector->countTotalCoffe(), $col3) .
	    padLeft($vector->countTotalDocs(), $col2) .
	    "|\n\n\n";

}

makeReport($vector);


echo "Применение 1го антикризисного метода:\n\n";
Antycrisis::setAnticrisysProgram1($vector);

//echo "Применение 3го антикризисного метода:\n\n";
//Antycrisis::setAnticrisysProgram3($vector);




makeReport($vector);