<?php

error_reporting(-1);

abstract class Employee
{
	public $rank;
    public $boss;

    public $salary = array(
    	0 => 400,                 // Marketer
    	1 => 800,                 // Analyst
    	2 => 500,                 // Manager
    	3 => 200                  // Engineer
    );
    public $coffee = array(
    	0 => 15,
    	1 => 50,
    	2 => 20,
    	3 => 5 
    );
    public $reports = array(
    	0 => 150,
    	1 => 5,
    	2 => 200,
    	3 => 50 
    );

    public function __construct( int $rank, int $boss)
    {
        $this->rank = $rank;        
        $this->boss = $boss;
    }

    public function distributing(int $rank, int $boss)
    {

    	if ($rank == 2) {
    	    $coefficient = 1.25;     // метод для определения дальнейшего
        } elseif ($rank == 3) {      // коэффициента умножения зарплаты
    	    $coefficient = 1.5;      // исходя из ранга сотрудника
        } else {
        	$coefficient = 1;
        }

        if ($boss == 1) {
        	
            $coefficient *= 2;
        }

         return $coefficient;
    }

    public function bossORNot(int $boss)
    {
    	if ($boss == 1) {
            
            $forBoss = 0;
    	    return $forBoss;     // метод исключительно для того, чтобы в случае с 
                                 // боссом обнулить количество написанных отчётов для него
        } else {

        	$forBoss = 1;
    	    return $forBoss;
        }
    }
}

class Marketer extends Employee
{
    public function getSalary(array $salary, int $coefficient)
    {
	    $getSalary = $salary[0] * $coefficient;
	    return $getSalary;
    }
    public function getCoffee(array $coffee, int $coefficient)   // тут всё вроде понятно, 3 метода для  
    {                                                            // вычисления зар. платы, кофе и отчётов
    	$getCoffee = $coffee[0] * $coefficient;                  // правда мне не нравится то, что по сути для
    	return $getCoffee;                                       // всех 4 должностей написан один и тот же код
    }                                                            // может чёт в абстрактный стоит вынести?
    public function getReports(array $reports, int $forBoss)
    {
    	$getReports = $reports[0] * $forBoss;
    	return $getReports;
    }	
}

class Analyst extends Employee
{
	public function getSalary(array $salary, int $coefficient)
    {
	    $getSalary = $salary[1] * $coefficient;
	    return $getSalary;
    }
    public function getCoffee(array $coffee, int $coefficient)
    {
    	$getCoffee = $coffee[1] * $coefficient;
    	return $getCoffee;
    }
    public function getReports(array $reports, int $forBoss)
    {
    	$getReports = $reports[1] * $forBoss;
    	return $getReports;
    }	
}

class Manager extends Employee
{
	public function getSalary(array $salary, int $coefficient)
    {
	    $getSalary = $salary[2] * $coefficient;
	    return $getSalary;
    }
    public function getCoffee(array $coffee, int $coefficient)
    {
    	$getCoffee = $coffee[2] * $coefficient;
    	return $getCoffee;
    }
    public function getReports(array $reports, int $forBoss)
    {
    	$getReports = $reports[2] * $forBoss;
    	return $getReports;
    }	
}

class Engineer extends Employee
{
	public function getSalary(array $salary, int $coefficient)
    {

	    $getSalary = $salary[3] * $coefficient;
	    return $getSalary;
    }
    public function getCoffee(array $coffee, int $coefficient)
    {

    	$getCoffee = $coffee[3] * $coefficient;
    	return $getCoffee;
    }
    public function getReports(array $reports, int $forBoss)
    {

    	$getReports = $reports[3] * $forBoss;
    	return $getReports;
    }	
}

$departments = array(                           // просто массив со всеми отделами
                                                // и кол-вом сотрудников разных должностей и ранга в них
	0 => array(  // Закупки
		"ме1" => 9,
		"ме2" => 3,
		"ме3" => 2,
		"ма1" => 2,
		"директорМе2" => 1
    ),
    1 => array(  // Продажи
    	"ме1" => 12,
    	"ма1" => 6,
    	"ан1" => 3,
    	"ан2" => 2,
    	"директорМа2" => 1
    ),

    2 => array(  // Реклама
    	"ме1" => 8,
    	"ма1" => 15,
    	"ма2" => 10,
    	"ин1" => 2,
    	"директорМа3" => 1
    ),

    3 => array(  // Логистика
    	"ме1" => 13,
    	"ме2" => 5,
    	"ин1" => 5,
    	"директорМе1" => 1
    )   
);

function padLeft($string, $length) {

	$amount = iconv_strlen($string);
    $difference = $length - $amount;
    $whitespaces = str_repeat(' ', $difference);     // для таблиц
    $leftSide = $whitespaces . $string;

	return $leftSide;
}

function padRight($string, $length) {

	$amount = iconv_strlen($string);
    $difference = $length - $amount;
    $whitespaces = str_repeat(" ", $difference);
    $rightSide = $string . $whitespaces;

	return $rightSide;

}

function createEmployees()
{
	$allEmployees = array();                // делаю двуслойный массив, распределяю всех по отделам
	$buying = array();                      // тут нет никакой проверки правильности внесения сотрудников,
                                            // остаётся лишь внимательно ориентироваться на массив $departments
    $manager1 = new Manager(1, 0);          // и в соответствии с ним переносить должностя
    $manager2 = new Manager(2, 0);
    $manager3 = new Manager(3, 0);
    $marketer1 = new Marketer(1, 0);
    $directorMe2 = new Manager(2, 1);

    array_push($buying, $manager1, $manager2, $manager3, $marketer1, $directorMe2);

    $selling = array();

    $manager1 = new Manager(1, 0);
    $marketer1 = new Marketer(1, 0);
    $analyst1 = new Analyst(1, 0);
    $analyst2 = new Analyst(2, 0);
    $directorMar2 = new Marketer(2, 1);

    array_push($selling, $manager1, $marketer1, $analyst1, $analyst2, $directorMar2);

    $ads = array();

    $manager1 = new Manager(1, 0);
    $marketer1 = new Marketer(1, 0);
    $marketer2 = new Marketer(2, 0);
    $engineer1 = new Engineer(1, 0);
    $directorMar3 = new Marketer(3, 1);

    array_push($ads, $manager1, $marketer1, $marketer2, $engineer1, $directorMar3);

    $logistics = array();

    $manager1 = new Manager(1, 0);
    $manager2 = new Manager(2, 0);
    $engineer1 = new Engineer(1, 0);
    $directorMa1 = new Manager(1, 1);

    array_push($logistics, $manager1, $manager2, $engineer1, $directorMa1);

    array_push($allEmployees, $buying, $selling, $ads, $logistics);

    return $allEmployees;

}

$employees = createEmployees();

function getAll (array $employees, array $departments)
{
    $getIt = array();

    $buying = array();          
    $selling = array();         
    $ads = array();              
    $logistics = array();
    $average = array();
    $total = array();

    $averageSum = 0;
    $averageS = 0;
    $averageC = 0;
    $averageSh = 0;
    $averageP = 0;

    array_push($getIt, $buying, $selling, $ads, $logistics, $average, $total);                             
    // снова двойной масси с распределением по отделам

    for ($i=0; $i < 4; $i++) { 

    	$howMuch = array();
    	$salary = array();
    	$coffee = array();
    	$sheets = array();

    	foreach ($departments[$i] as $amount) {

            array_push($howMuch, $amount);
        }
                                                             
        foreach ($employees[$i] as $employee) { // считаю зарплату, кофе, и отчёты для каждого отдела

        	array_push($salary, $employee->getSalary($employee->salary, $employee->distributing($employee->rank, $employee->boss)));

        	array_push($coffee, $employee->getCoffee($employee->coffee, $employee->distributing($employee->rank, $employee->boss)));

        	array_push($sheets, $employee->getReports($employee->reports, $employee->bossORNot($employee->boss)));  
        }

        for ($a=0; $a < count($howMuch); $a++) { 

        	$salary[$a] *= $howMuch[$a];   // каждое из значений помножаю на соответствующее
        	$coffee[$a] *= $howMuch[$a];   // количество сотрудников в данном отделе на данном ранге
        	$sheets[$a] *= $howMuch[$a]; 

        }

        $sum = array_sum($howMuch);
        $forRounding = array_sum($salary) / array_sum($sheets);
        $perSheet = round($forRounding, 1);

        $averageSum += $sum;
        $averageS += array_sum($salary);  // для дальнейшего показания средних рез-тов и всего вместе
        $averageC += array_sum($coffee);  // собираю в конце каждого цикла значения 
        $averageSh += array_sum($sheets); // изначально вообще не задумывал собирать эти значения
        $averageP += $perSheet;           // именно в этой функции, да и сейчас как-то это стрёмно
                                          // выглядит, я считаю
        array_push($getIt[$i], $sum, array_sum($salary), array_sum($coffee), array_sum($sheets), $perSheet);
    }

    array_push($getIt[4], $averageSum / 4, $averageS / 4, $averageC / 4, $averageSh / 4, $averageP / 4);
    array_push($getIt[5], $averageSum, $averageS, $averageC, $averageSh, $averageP);

    // я так уверенно поставил цифры 4 и 5 в верхние пуши потому, что заведомо знаю что под
    // этими ключами у меня будут средние и полные значения
    // так быть вообще не должно, тут хоть что тронешь и всё нахуй развалится, это всё из-за того
    // что я решил средние значения получать именно здесь
    return $getIt;
}


$getIt = getAll($employees, $departments);

echo padRight("Департамент", 30) . 
     padLeft("Сотр.", 10) . 
     padLeft("Тугр.", 10) .
     padLeft("Кофе", 10) .                               // ну и тут уже формируется полная таблица
     padLeft("Стр.", 10) . 
     padLeft("Тугр./стр.", 10) . "\n\n";

$names = array("Закупки","Продажи","Реклама","Логистика", "Среднее", "Всего");

$onAverage = array();
$buying = array();          
$selling = array();         
$ads = array();              
$logistics = array();

array_push($onAverage, $buying, $selling, $ads, $logistics);
   
for ($i=0; $i < count($names); $i++) {

    echo padRight($names[$i], 30);

	foreach ($getIt[$i] as $value) {

   	echo padLeft($value, 10);

    }

   	echo "\n";
}
  
?>