<?php
 
 /**
 * input.php
 */

$input = [
	// count, profession, grade, [chief]
	
	'Purchasing' => [
		[9, Employee::MANAGER, 1],
		[3, Employee::MANAGER, 2],
		[2, Employee::MANAGER, 3],
		[2, Employee::MARKETER, 1],
		[1, Employee::MANAGER, 2, true]
	],

	'Sales' => [
		[12, Employee::MANAGER, 1],
		[6, Employee::MARKETER, 1],
		[3, Employee::ANALYST, 1],
		[2, Employee::ANALYST, 2],
		[1, Employee::MARKETER, 2, true]
	],


	'Advertising' => [
		[15, Employee::MARKETER, 1],
		[10, Employee::MARKETER, 2],
		[8, Employee::MANAGER, 1],
		[2, Employee::ENGINEER, 1],
		[1, Employee::MARKETER, 3, true]
	],


	'Logistics' => [
		[13, Employee::MANAGER, 1],
		[5, Employee::MANAGER, 2],
		[5, Employee::ENGINEER, 1],
		[1, Employee::MANAGER, 1, true]
	]

];

 /**
 * classes.php
 */
 
 class Company {
	protected array $departments;
	protected int $numOfDepts;

	public function __construct(array $departments) {
		$this->departments = $departments;
		$this->numOfDepts = count($departments);
	}

	public function getDepartments(): array {
		return $this->departments;
	}

	public function getTotalStaff(): int {
		$staff = 0;
		foreach ($this->departments as $dept) {
			$staff += $dept->getStaffNumber();
		}
		return $staff;
	}

	public function getTotalLaborCost() {
		$cost = 0;
		foreach ($this->departments as $dept) {
			$cost += $dept->getLaborCost();
		}
		return $cost;
	}

	public function getTotalCoffeeDrunk() {
		$amount = 0;
		foreach ($this->departments as $dept) {
			$amount += $dept->getCoffeeDrunk();
		}
		return $amount;
	}

	public function getTotalPagesProduced(): int {
		$pages = 0;
		foreach ($this->departments as $dept) {
			$pages += $dept->getPagesProduced();
		}
		return $pages;
	}

	public function getTotalCostPerPage() {
		$cost = 0;
		foreach ($this->departments as $dept) {
			$cost += $dept->getCostPerPage();
		}
		return $cost;
	}

	public function getAverageStaff() {
		$staff = 0;
		foreach ($this->departments as $dept) {
			$staff += $dept->getStaffNumber();
		}
		return $staff / $this->numOfDepts;
	}

	public function getAverageLaborCost() {
		$cost = 0;
		foreach ($this->departments as $dept) {
			$cost += $dept->getLaborCost();
		}
		return $cost / $this->numOfDepts;
	}

	public function getAverageCoffeeDrunk() {
		$amount = 0;
		foreach ($this->departments as $dept) {
			$amount += $dept->getCoffeeDrunk();
		}
		return $amount / $this->numOfDepts;
	}

	public function getAveragePagesProduced() {
		$pages = 0;
		foreach ($this->departments as $dept) {
			$pages += $dept->getPagesProduced();
		}
		return $pages / $this->numOfDepts;
	}

	public function getAverageCostPerPage() {
		$cost = 0;
		foreach ($this->departments as $dept) {
			$cost += $dept->getCostPerPage();
		}
		return $cost / $this->numOfDepts;
	}
}

class Department {
	protected string $name;
	protected array $staff;

	public function __construct(string $name, array $employees) {
		$this->name = $name;
		$this->staff = [];
		foreach ($employees as $empGroup) {
			$empQuantity = $empGroup[0];
			$empType = $empGroup[1];
			$empGrade = $empGroup[2]; // 1
			$empChief = isset($empGroup[3]) ? true : false;
			for ($c = 0; $c < $empQuantity; $c++) {
				$this->staff[] = new $empType($empGrade, $empChief);
			}
		}
	}

	public function getDeptName(): string {
		return $this->name;
	}

	public function getStaffNumber(): int {
		$staffNumber = count($this->staff);
		return $staffNumber;
	}

	public function getLaborCost(): int {
		$aggregateCost = 0;
		foreach ($this->staff as $employee) {
			$aggregateCost += $employee->getActualPay();
		}
		return $aggregateCost;
	}

	public function getCoffeeDrunk(): int {
		$totalCoffeeDrunk = 0;
		foreach ($this->staff as $employee) {
			$totalCoffeeDrunk += $employee->getActualCoffeeConsumption();
		}
		return $totalCoffeeDrunk;
	}

	public function getPagesProduced() {
		$totalPagesProduced = 0;
		foreach ($this->staff as $employee) {
			$totalPagesProduced += $employee->getActualPaperworkProduced();
		}
		return $totalPagesProduced;
	}

	public function getCostPerPage() {
		$pages = $this->getPagesProduced();
		$laborCost = $this->getLaborCost();
		return round($laborCost / $pages, 2);
	}
}

abstract class Employee {
	const MANAGER = "Manager";
	const MARKETER = "Marketer";
	const ENGINEER = "Engineer";
	const ANALYST = "Analyst";

	protected int $grade;
	protected $baseRate;
	protected bool $chief;
	protected $baseCoffeeConsumption;
	protected int $basePaperworkProduced;

	public function __construct(int $grade, bool $chief = false) {
		$this->grade = $grade;
		$this->chief = $chief;
	}

	public function getActualPay() {
		$rate = $this->baseRate;
		if ($this->grade == 2) {
			$rate *= 1.25;
		} elseif ($this->grade == 3) {
			$rate = $rate * 1.5;
		}

		return $this->chief ? $rate * 2 : $rate;
	}

	public function getActualCoffeeConsumption() {
		return $this->chief ? $this->baseCoffeeConsumption * 2 : $this->baseCoffeeConsumption;
	}

	public function getActualPaperworkProduced(): int {
		return $this->chief ? 0 : $this->basePaperworkProduced;	
	}
}

class Manager extends Employee {
	protected $baseRate = 500;
	protected $baseCoffeeConsumption = 20;
	protected int $basePaperworkProduced = 200;
}

class Marketer extends Employee {
	protected $baseRate = 400;
	protected $baseCoffeeConsumption = 15;
	protected int $basePaperworkProduced = 150;
}

class Engineer extends Employee {
	protected $baseRate = 200;
	protected $baseCoffeeConsumption = 5;
	protected int $basePaperworkProduced = 50;
}

class Analyst extends Employee {
	protected $baseRate = 800;
	protected $baseCoffeeConsumption = 50;
	protected int $basePaperworkProduced = 5;
}
 
  /**
 * padstring.php
 */
 
 function padString($string, $length, $side = "right", $pad = " ") {
	if (strlen($string) == $length) {
		return $string;
	} else {
		$charsNeeded = $length - strlen($string);
		$padding = str_repeat($pad, $charsNeeded);
		$side == "right" ? ($string = $string . $padding) : ($string = $padding . $string);
		return $string;
	}
}

 /**
 * main.php
 */
 
include('classes.php');
include('input.php');
include('padstring.php');

function getDepartments(array $input): array {
	$departments = [];

	foreach ($input as $department => $employees) {
		$departments[] = new Department($department, $employees);
	}

	return $departments;
}

function printReport(array $departments) {
	$company = new Company($departments);
	$firstCol = 20;
	$regCol = 15;

	echo padString('DEPARTMENT', $firstCol) . padString('STAFF', $regCol, 'left') . padString('LABOR COST', $regCol, 'left') . padString('COFFEE DRUNK', $regCol, 'left') . padString('PAGES', $regCol, 'left') . padString('COST PER PAGE', $regCol, 'left') . "\n";
	echo padString('=', $firstCol, 'right', '=') . padString('=', $regCol, 'left', '=') . padString('=', $regCol, 'left', '=') . padString('=', $regCol, 'left', '=') . padString('=', $regCol, 'left', '=') . padString('=', $regCol, 'left', '=') . "\n";

	foreach ($company->getDepartments() as $department) {
		echo padString($department->getDeptName(), $firstCol) . padString($department->getStaffNumber(), $regCol, 'left') . padString($department->getLaborCost(), $regCol, 'left') . padString($department->getCoffeeDrunk(), $regCol, 'left') . padString($department->getPagesProduced(), $regCol, 'left') . padString($department->getCostPerPage(), $regCol, 'left') . "\n";
	}

	echo padString('=', $firstCol, 'right', '=') . padString('=', $regCol, 'left', '=') . padString('=', $regCol, 'left', '=') . padString('=', $regCol, 'left', '=') . padString('=', $regCol, 'left', '=') . padString('=', $regCol, 'left', '=') . "\n";

	echo padString('TOTAL', $firstCol) . padString($company->getTotalStaff(), $regCol, 'left') . padString($company->getTotalLaborCost(), $regCol, 'left') . padString($company->getTotalCoffeeDrunk(), $regCol, 'left') . padString($company->getTotalPagesProduced(), $regCol, 'left') . padString($company->getTotalCostPerPage(), $regCol, 'left') . "\n";

	echo padString('AVERAGE', $firstCol) . padString($company->getAverageStaff(), $regCol, 'left') . padString($company->getAverageLaborCost(), $regCol, 'left') . padString($company->getAverageCoffeeDrunk(), $regCol, 'left') . padString($company->getAveragePagesProduced(), $regCol, 'left') . padString($company->getAverageCostPerPage(), $regCol, 'left') . "\n";

}

$departments = getDepartments($input);

printReport($departments);