summaryrefslogblamecommitdiffstats
path: root/modules-available/roomplanner/inc/pvsgenerator.inc.php
blob: d7f9610604c483d43c34af72b909016f6b8b7b17 (plain) (tree)
1
2
3
4
5
6
7
8







                  




















                                                                                                                                           
 


                                                                                          
                                           


                                                                            
                                                             
                                                  

                 






                                                                                         

         





                                                                               






                                                                           


                                     













                                                              
                                   

         





                                                                                      





































                                                                                                               





                                                               






                                                                                                

                                                              





























                                                                                                   

 
<?php

define('X', 0);
define('Y', 1);

class PvsGenerator
{

	public static function generate()
	{

		if (!Module::isAvailable('locations')) {
			die('sorry, but the locations module is required');
		}


		/* get all rooms */
		$rooms = array();
		$ret = Database::simpleQuery(
			'SELECT l.locationid, l.locationname, lr.managerip, lr.tutoruuid, m.clientip as tutorip '
			. 'FROM location l '
			. 'INNER JOIN location_roomplan lr ON (l.locationid = lr.locationid)'
			. 'LEFT JOIN machine m ON (lr.tutoruuid = m.machineuuid)');
		while ($row = $ret->fetch(PDO::FETCH_ASSOC)) {
			if (Location::isLeaf($row['locationid'])) { // TODO: This creates extra queries, optimize?
				$row['locationname'] = str_replace(',', ';', $row['locationname']); // comma probably not the best sep here
				$rooms[] = $row;
			}
		}

		/* collect names and build room blocks - filter empty rooms while at it */
		$roomNames = array();
		$roomBlocks = '';
		foreach ($rooms as $room) {
			$roomBlock = PvsGenerator::generateRoomBlock($room);
			if ($roomBlock === false)
				continue; // Room nonexistent or empty
			$roomNames[] = $room['locationname'];
			$roomBlocks .= $roomBlock;
		}

		/* output room plus [General]-block */
		return "[General]\n"
		. 'rooms=' . implode(', ', $roomNames) . "\n"
		. "allowClientQuit=False\n" // TODO: configurable
		. "showLockDesktopButton=True\n" // TODO: Make this configurable (or not)
		. "\n\n"
		. $roomBlocks;
	}

	/**
	 * Generate .ini section for specific room.
	 *
	 * @param $room array room/location data as fetched from db
	 * @return string|bool .ini section for room, or false if room is empty
	 */
	private static function generateRoomBlock($room)
	{
		$out = '[' . $room['locationname'] . "]\n";


		/* find all clients in that room */
		$machines = PvsGenerator::getMachines($room['locationid']);
		if (empty($machines))
			return false;

		/* manager */
		$mgr = $room['managerip'];
		$tutor = $room['tutorip'];
		if ($mgr) {
			$out .= 'mgrIP=' . $mgr . "\n";
		}
		/* tutor */
		if ($tutor) {
			$out .= 'tutorIP=' . $tutor . "\n";
		}

		/* grid */
		$out .= PvsGenerator::generateGrid($machines);

		return $out . "\n";
	}

	/**
	 * Generate grid size information and client position data for given clients.
	 *
	 * @param $machines array list of clients
	 * @return string grid and position data as required for a room's .ini section
	 */
	private static function generateGrid($machines)
	{
		$out = "";

		/* this is a virtual grid, we first need this to do some optimizations */
		$grid = array();
		/* add each contained client with position and ip */
		foreach ($machines as $machine) {
			$grid[$machine['clientip']] = [$machine['gridCol'], $machine['gridRow']];
		}
		/* find bounding box */
		PvsGenerator::boundingBox($grid, $minX, $minY, $maxX, $maxY);
		$clientSizeX = 4; /* TODO: optimize */
		$clientSizeY = 4; /* TODO: optimize */
		$sizeX = max($maxX - $minX + $clientSizeX, 1); /* never negative */
		$sizeY = max($maxY - $minY + $clientSizeY, 1); /* and != 0 to avoid divide-by-zero in pvsmgr */

		/* zoom all clients into bounding box */
		foreach ($grid as $ip => $pos) {
			$newX = $grid[$ip][X] - $minX;
			$newY = $grid[$ip][Y] - $minY;
			$grid[$ip] = [$newX, $newY];
		}

		$out .= "gridSize=@Size($sizeX $sizeY)\n";
		$out .= "clientSize=@Size($clientSizeX $clientSizeY)\n";
		$out .= "client\\size=" . count($grid) . "\n";

		$i = 1;
		foreach ($grid as $ip => $pos) {
			$out .= "client\\" . $i . "\\ip=$ip\n";
			$out .= "client\\" . $i++ . "\\pos=@Point(" . $pos[X] . ' ' . $pos[Y] . ")\n";
		}

		return $out;

	}

	/**
	 * Get all clients for given room with IP and position.
	 *
	 * @param $roomid int locationid of room
	 * @return array
	 */
	private static function getMachines($roomid)
	{
		$ret = Database::simpleQuery(
			'SELECT clientip, position FROM machine WHERE locationid = :locationid',
			['locationid' => $roomid]);

		$machines = array();

		while ($row = $ret->fetch(PDO::FETCH_ASSOC)) {
			$position = json_decode($row['position'], true);

			$machine = array();
			$machine['clientip'] = $row['clientip'];
			$machine['gridRow'] = $position['gridRow'];
			$machine['gridCol'] = $position['gridCol'];
			$machine['tutor'] = false; /* TODO: find out if machine is default tutor */
			$machine['manager'] = false; /* TODO: find out if machine is manager */

			$machines[] = $machine;
		}

		return $machines;

	}

	private static function boundingBox($grid, &$minX, &$minY, &$maxX, &$maxY)
	{
		$minX = PHP_INT_MAX; /* PHP_INT_MIN is only avaiable since PHP 7 */
		$maxX = ~PHP_INT_MAX;
		$minY = PHP_INT_MAX;
		$maxY = ~PHP_INT_MAX;

		foreach ($grid as $pos) {
			$minX = min($minX, $pos[X]);
			$maxX = max($maxX, $pos[X]);
			$minY = min($minY, $pos[Y]);
			$maxY = max($maxY, $pos[Y]);
		}
	}

}