<?php
abstract class Room
{
/**
* @var Room[] list of all rooms
*/
protected static $rooms = null;
/**
* @var int id for this room
*/
private $locationId;
/**
* @var string name of this room
*/
private $locationName;
protected static function init()
{
if (self::$rooms !== null)
return;
/* get all rooms */
self::$rooms = [];
$ret = Database::simpleQuery(
'SELECT lr.locationid, lr.managerip, lr.tutoruuid, lr.roomplan, m.clientip as tutorip
FROM location_roomplan lr
LEFT JOIN machine m ON (lr.tutoruuid = m.machineuuid)');
foreach ($ret as $row) {
$room = self::loadSingleRoom($row);
if ($room === null)
continue;
self::$rooms[$room->locationId] = $room;
}
foreach (self::$rooms as $room) {
$room->sanitize();
}
}
/**
* Instantiate ComposedRoom or MachineGroup depending on contents of $row
* @param array $row DB row from location_roomplan.
* @return ?Room Room instance, null on error
*/
private static function loadSingleRoom(array $row): ?Room
{
$locations = Location::getLocationsAssoc();
settype($row['locationid'], 'int');
if (!isset($locations[$row['locationid']]))
return null;
if ($locations[$row['locationid']]['isleaf'])
return new SimpleRoom($row);
return new ComposedRoom($row, false);
}
/**
* Get array of all rooms with room plan
* @return Room[]
*/
public static function getAll(): array
{
self::init();
return self::$rooms;
}
/**
* Get room instance for given location
* @param int $locationId room to get
* @return ?Room requested room, false if not configured or not found
*/
public static function get(int $locationId): ?Room
{
if (self::$rooms === null) {
$room = Database::queryFirst(
'SELECT lr.locationid, lr.managerip, lr.tutoruuid, lr.roomplan, m.clientip as tutorip
FROM location_roomplan lr
LEFT JOIN machine m ON (lr.tutoruuid = m.machineuuid)
WHERE lr.locationid = :lid', ['lid' => $locationId]);
if ($room === false)
return null;
$room = self::loadSingleRoom($room);
if ($room === null)
return null;
// If it's a leaf room we probably don't need any other rooms, return it
if ($room->isLeaf())
return $room;
// Otherwise init the full tree so we can resolve composed rooms later
self::init();
}
if (isset(self::$rooms[$locationId]))
return self::$rooms[$locationId];
return null;
}
public function __construct($row)
{
$locations = Location::getLocationsAssoc();
$this->locationId = (int)$row['locationid'];
$this->locationName = $locations[$this->locationId]['locationname'];
}
/**
* @return int number of machines in this room
*/
abstract public function machineCount(): int;
/**
* Size of this room, returned by reference.
*
* @param int|null $width OUT width of room
* @param int|null $height OUT height of room
*/
abstract public function getSize(?int &$width, ?int &$height);
/**
* Get clients in this room in .ini format for PVS.
* Adjusted so the top/left client is at (0|0), which
* is further adjustable with $offX and $offY.
*
* @param int $i offset for indexing clients
* @param int $offX positional X offset for clients
* @param int $offY positional Y offset for clients
* @return string|false
*/
abstract public function getIniClientSection(int &$i, int $offX = 0, int $offY = 0);
/**
* Get clients in this room as array.
* Adjusted so the top/left client is at (0|0), which
*is further adjustable with $offX and $offY.
*/
abstract public function getShiftedArray(int $offX = 0, int $offY = 0): ?array;
/**
* @return string|false IP address of manager.
*/
abstract public function getManagerIp();
/**
* @return string|false IP address of tutor client.
*/
abstract public function getTutorIp();
/**
* @return bool true if this is a simple/leaf room, false for composed rooms.
*/
abstract public function isLeaf(): bool;
/**
* @return bool should this room be skipped from output? true for empty SimpleRoom or disabled ComposedRoom.
*/
abstract public function shouldSkip(): bool;
/**
* Sanitize this room's data.
*/
abstract protected function sanitize();
/**
* @return string get room's name.
*/
public function locationName(): string
{
return $this->locationName;
}
/**
* @return int get room's id.
*/
public function locationId(): int
{
return $this->locationId;
}
}