summaryrefslogblamecommitdiffstats
path: root/modules-available/locationinfo/frontend/doorsign.html
blob: eb15c9d0763a32b45b1c2145d38a5d1523b10195 (plain) (tree)
1
2
3
4
5
6
7
8
9
               




         
                                                
 
         












                                                                             


                                                                                                         
















































                                                                                                    

                                     


















                                               

                                    





































                                                
                                               














































































































































                                                                    







                                                                































                                                                                                                              




                                                                                                 
                         
                                        

                   













                                                                                   


                                                                                                             
                                             


                                                                            
                                          
                                
                                                                                                




                                                            



                                                                                                                    
 











                                                                                                                                                  
 






                                                                                             
 


                                                                            
 

                                                                                       
                                         
 


                                                                                                                             

                                                       
                                                                                   



                                 























                                                                                                                 
                                                                                                                     























                                                                                                               




                                                                        
                   




                                                                                            

                         






                                                                                              
 


                                                                                          

                                               






                                                                                     
 
                                                                      








                                                                                                     

                                                                           

                                              
                                                   

                                              
                                                   

                                               
                                                                  


                                                                                                          


                                                       
                                                                                        

                                                          
                                                                                           
 
                                                                      

 
                                                                                    
                                                                              
                                                                                                        

                                                                                         
                                                                                                           
                                                          

                                                                                                                      

                                                          
                                                               
 

                                                                                      

                                 






                                                                                                                   



                                                                                  






                                                                                                                   




                                                                                  







                                                                                                                   





                                                                                  


                                                                                                                     
 

                                                                                                   
 

                                                                     
 



                                                                                                   
                                 

                                                             

                         

                                                      
                         
                                                          

                 
                                   
                                     




                                                                                 

                                                 





                                                                                           


                                                                                        
                                 


                                                                                     




                                                                     



                                                                                                        

                                                     


                                                                          
                                 

                         
                                                  


                                                         

                                                              

                                                 
                         





                                                                          
                                                           
                   

                                                     
                                    


                                                     




                                                   
                                                                              
                                                   
                                              
                                                  
                                                                  

                                              

                                                        
                                                       
                                                                  


                                                                          

                                                                                







                                                                                  
                                                  
                                    















                                                                                                                   
                                                                  









                                                                                                                        
                                                                                          

                                                                                                                                  
                                                                                                                                                  



















                                                                                                                                     


                   








                                                                      
                                                                             
                                                  
                                                            






                                                          


                                                                                                               

                                                                                               


                                          
                                                

                                         

















                                                                                                                                    

                                       

                                                 
                                                               


                                                                           






                                                                                                                                    







                                                                                   



                                                 
                                                            




                                                                                           

                                               

                                                  




























                                                                                                                   





                                                                                         


                                                                                                    





                                                            




                                                                                                                
                                         
                                                       

                                                                                                                  



                                 

                                                    

                                                                                                        
                                                    


                                                     





                                                                                            

                                       










                                                                                                                                           

                                                      

                                                                          
                                                                            
                                                                                           



                                                                                                      

                                                       










                                                                                
                                                     

                                       





                                                                                                                                           

                                                                                          

                                 
                                                                                                                                   




                                                                                      
                                                   





                                                                                                                       
                                                                             


























                                                                                                                      




                                                                                             









                                                                                              

                                  



                                                               
                                       















                                                                                           
                                         


                                             
                                              










                                                                     
                                           
                                               
                                             
                                                     










                                                                                                             



                                                         
                                                              
                         
                                    









                                                                
                                                             
                                                                   


                                                                 
                                                              

                                                                        















                                                                          

                                                            
                                               











                                                                                                            



                                                         
                                                              
                         
                                    











                                                                                                      
                                                  













                                                                                  

                                                                                                                                                                 
                                                                    
                                                                   

                                                                               

                                                                                                                                                               
                                                                    
                                                               






                                                                                                     

                                                          

                                                    
                                                      








                                                                                                               
                                                 




                                                                                                
                                     




                                                                                                       

                                                                                                                          



                                                      
                                       






                                                                                                         
                                







                                                                                                       
                                                                          

                                                      




                                                                                                                  
                         


                                                                    
                                                     

                                                                                                                                 

                                                           


                                                                                           
                                         

                                                                                                                                                  




                                     


                                                                            
                                                            
                                                                  
                                                                                                 


















                                                                                                            
                                                                                                                                       
                                                  


                                                
                                                     






                                                           

                   
                                                               


                                            








                                                                                      

                                       
 
                                                                  

                                                                 













                                                                        


























                                                                    
                                                   




                                                                                                                    
                                                 

                                                  

                                                                                               






                                                                                          
                                                     




                                                                        
                                                     












                                                                                              
                                                                                                                                                 













                                                                                                                                                      
                                                                                 







                                                                                                                                                  
                                                                                                           






















                                                                                                                                                  



                                                                                                          













                                                                            
                                                                           






                                                    
                   
                                       
                                
                                                                                                       



                                                            



                                                                                                        
                                                                                 
                                                                                                  
                                         



                                 





















































                                                                                                     





















                                                                                                           
                                                                      
                                                                                           
                                                                                                                                
                                                  


                                                                                                                     

                                                                                                                         
                                         
                                 
                         




                                                                                                     
                                          




                                                             
                                                                       
                                                                
                                                      
                                                             
                                                                       

                                                                                        
                                                                                       
                                                 
                                                                                        




                                                                                                

                                                      














                                                                                               
                                                                                

                                                                   

                                                                                     

                                 
                                     










                                                                      

                                                                                             










                                                                                                  





















                                                                                                  

                                 
                                                            

                 


                                             

                   
                                                         
                   














                                                                                                                    
                                                   

                                                        
                                 

                                                         

                 





                                                                                            





                 
<!DOCTYPE html>
<!--

parameter

required:
    uuid: [integer] panel id, see in admin panel

optional:
    lang:[en,de] set the language
    mode:[1,2,3,4] sets the displaying
        1: Calendar & Room
        2: only Calendar
        3: only Room
        4: Calendar & Room alternately
    daystoshow:[1,2,3,4,5,6,7] sets how many days the calendar shows
    scale:[10-90] scales the calendar and Roomplan in mode 1
    switchtime:[1-120] sets the time between switchen in mode 4  (in seconds)
    calupdate: Time the calender querys for updates,in minutes.
    roomupdate: Time the PCs in the room gets updated,in seconds.
    rotation:[0-3] rotation of the roomplan
    vertical:[true] only mode 1, sets the calendar above the roomplan
    scaledaysauto: [true] if true it finds automaticly the daystoshow parameter depending on display size

-->
<html lang="de">
<meta name="viewport" content="width=device-width, initial-scale=1.0" charset="utf-8">
<head>
	<title>DoorSign</title>
	<script type='text/javascript' src='../../../script/jquery.js'></script>
	<script type='text/javascript' src='../../js_jqueryui/clientscript.js'></script>
	<link rel='stylesheet' type='text/css' href='../../js_jqueryui/style.css'/>
	<link rel='stylesheet' type='text/css' href='jquery-week-calendar/jquery.weekcalendar.css'/>

	<script type='text/javascript' src="jquery-week-calendar/jquery.weekcalendar.js"></script>
	<style type='text/css'>

		body {
			font-family: "Lucida Grande", Helvetica, Arial, Verdana, sans-serif;
			margin: 0;
			width: 100%;
			height: 100%;
			float: left;
			box-sizing: border-box;

			background-color: #cacaca;
			overflow: hidden;
			position: absolute;
			display: table;

		}

		.row {
			background-color: #404040;
			box-shadow: 0 0.1875rem 0.375rem rgba(0, 0, 0, 0.25);
			margin-bottom: 4px;

			width: 100%;

		}

		.header {
			display: table;
			color: white;
			padding: 0;
			height: 8vw;

		}

		.progressbar {
			width: 0px;
			height: 2px;
			position: absolute;
			background-color: red;
			bottom: 0px;
			z-index: 100;
		}

		.font {
			display: table-cell;
			vertical-align: middle;
			font-size: 3vw;
			font-weight: bold
		}

		.courseText {
			text-align: center;
		}

		.row::after {
			content: "";
			clear: both;
			display: block;
		}

		[class|="col"] {
			float: left;
			padding: 0;
			box-sizing: border-box;
		}

		.col-1 {
			width: 33%;
		}

		.col-2 {
			width: 33%;
		}

		.roomLayoutDesign {
			position: relative;
			float: left;
			boxSizing: border-box;
		}

		.roompadding {
			float: left;
			position: relative;
		}

		.room {
			position: relative;
			background-color: white;
			width: 100%;
			height: 100%;
			overflow: hidden;
			border-width: 1px;
			border-color: darkgrey;
			border-style: solid;

		}

		.calendar {
			float: left;
			padding: 0;
			box-sizing: border-box;
			background: linear-gradient(#cccccc, white);

		}

		.free-busy-busy {
			background: grey;
		}

		.ui-widget-content {
			color: white;
		}

		.wc-header {
			background-color: #404040;
			font-weight: bold;
		}

		.ui-state-default {
			text-shadow: none;
		}

		.square {
			display: table;
			float: right;
			padding: 0;
			width: 8vw;
			height: 8vw;
		}

		.FreeSeatsFont {
			display: table-cell;
			vertical-align: middle;
			font-size: 6vw;
			color: white;
			top: 0;
			margin: 0 auto;
			position: relative;
			text-align: center;
			font-weight: bold;
			overflow: visible;
		}

		.PCImgDiv {
			position: absolute;
			left: 0;
			bottom: 0;
			display: inline-block;

		}

		.OverlayDiv {
			position: absolute;
			left: 0;
			bottom: 0;
			width: 100%;
			height: 100%;
			display: table;
		}

		.pcImg {
			position: absolute;
			left: 0;
			top: 0;
			width: 100%;
			height: 100%;

		}

		.overlay {
			position: relative;
			width: 50%;
			height: 50%;
			opacity: 0.5;
			float: left;
			z-index: 5;
		}

		.overlay-rollstuhl {
			width: 25%;
			height: 50%;
			background-color: white;
			opacity: 0.5;
			float: left;
		}

		.wc-scrollable-grid {

		}

		.ui-widget-content .ui-state-active {
			font-weight: bold;
			color: black;
		}

		.wc-container {
			font-weight: bold;
		}

		.wc-today {
			background-color: white;
		}

		.wc-time-header-cell {
			background-color: #eeeeee;
			border: none;
		}

		.ui-corner-all {
			moz-border-radius-bottomright: 0;
			webkit-border-bottom-right-radius: 0;
			-khtml-border-bottom-right-radius: 0;
			border-bottom-right-radius: 0;

			moz-border-radius-topright: 0;
			webkit-border-top-right-radius: 0;
			-khtml-border-top-right-radius: 0;
			border-top-right-radius: 0;

			moz-border-radius-bottomleft: 0;
			webkit-border-bottom-left-radius: 0;
			-khtml-border-bottom-left-radius: 0;
			border-bottom-left-radius: 0;

			moz-border-radius-topleft: 0;
			webkit-border-left-right-radius: 0;
			-khtml-border-left-right-radius: 0;
			border-top-left-radius: 0;
		}

		.wc-scrollable-grid .wc-day-column-first {
			border-style: solid;

		}

		[class*="wc-day-"] {
			border-color: grey;
		}


	</style>
	<script type='text/javascript'>

		var rooms = {};
		var lastRoomUpdate = 0;
		var lastCalendarUpdate = 0;
		var lastSwitchTime = 0;
		var globalConfig = {};
		var roomIds = [];
		var panelUuid = false;
		var supportSvg = typeof SVGRect !== "undefined";
		// TODO: Get languages from slx-admin
		var translation = {
			"en": {
				"room": "Room",
				"closed": "Closed",
				"free": "Free",
				"shortDays": ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
				"longDays": ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
				"to": "to"

			},
			"de": {
				"room": "Raum",
				"closed": "Geschlossen",
				"free": "Frei",
				"shortDays": ["Son", "Mon", "Die", "Mit", "Don", "Frei", "Sam"],
				"longDays": ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
				"to": "bis"
			},
			"pt": {
				"room": "Quarto",
				"closed": "Fechado",
				"free": "Livre",
				"shortDays": ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Se', 'Sáb'],
				"longDays": ['Domingo', 'Segunda-feira', 'Terça-feira', 'Quarta-feira', 'Quinta-feira',
					'Sexta-feira', 'Sábado'],
				"to": "para"

			}
		};


		$(document).ready(function () {
			var uuid = getUrlParameter("uuid");
			if (!uuid) {
				console.log('No panel uuid given');
				$("body").empty().append($('<h1>').text('No panel UUID given.'));
				return;
			}
			getConfig(uuid);
		});

		/**
		 * Display given error message and try reloading page once a minute
		 */
		function fatalError(message) {
			$('body').empty().append($('<h1>').text(message));
			window.setInterval(function () {
				$.ajax('/').done(function () {
					window.location.reload(true);
				}).fail(function () {
					$('body').append('...');
				});
			}, 60000);
		}


		/**
		 * Downloads the config of a room, also reloads the page if the config hase changed over time
		 * @param uuid ID of the room
		 * @param room Room Object, only needed if it already exists
		 */

		function getConfig(uuid) {
			$.ajax({
				url: "../../../api.php?do=locationinfo&get=config&uuid=" + uuid,
				dataType: 'json',
				cache: false,
				timeout: 30000,
				success: function (result) {

					if (!result.locations || result.locations.constructor !== Array) {
						fatalError("Requested panel doesn't contain locations / not array");
						return;
					}

					var fetchedRooms = result.locations.filter(function (x) {
						// filter out if no numeric id, or id already present, or already got 4 locations
						if (typeof(x.id) !== 'number' || x.id <= 0 || roomIds.indexOf(x.id) !== -1 || roomIds.length >= 4)
							return false;
						roomIds.push(x.id);
						return true;
					});

					if (roomIds.length === 0) {
						fatalError("List of location ids is empty");
						return;
					}

					var time = new Date(result.time);
					if (isNaN(time.getTime()) || time.getYear() < 2010) {
						time = new Date();
					}
					SetUpDate(time);
					delete result.time;
					delete result.locations;

					globalConfig = result;
					sanitizeGlobalConfig();
					lastRoomUpdate = MyDate().getTime();

					for (var i = 0; i < fetchedRooms.length; ++i) {
						var r = addRoom(fetchedRooms[i]);
					}

					initRooms();
					// TODO: Check for changed config using get=timestamp and reload whole page on change
					panelUuid = uuid;

				}, error: function () {
					fatalError('Could not fetch panel config');
				}
			})
		}

		const PARAM_STRING = 1;
		const PARAM_INT = 2;
		const PARAM_BOOL = 3;

		/**
		 * Read given parameter from URL, replacing it in the config object if present.
		 * @param config object config object
		 * @param property string name of property in object, URL param of same name is being checked
		 * @param paramType int one of PARAM_STRING, PARAM_INT, PARAM_BOOL
		 * @param intScaleFactor int optional scale factor that will be applied if paramType == PARAM_INT
		 */
		function setRoomConfigFromUrl(config, property, paramType, intScaleFactor) {
			var val = getUrlParameter(property);
			if (val === true || val === false)
				return;
			if (paramType === PARAM_STRING) {
				config[property] = val;
			} else if (paramType === PARAM_INT) {
				config[property] = parseInt(val);
				if (intScaleFactor) {
					config[property] *= intScaleFactor;
				}
			} else if (paramType === PARAM_BOOL) {
				val = val.toLowerCase();
				config[property] = val.length > 0 && val !== 'false' && val !== 'off' && val !== '0';
			} else {
				console.log('Invalid paramType: ' + paramType);
			}
		}

		/**
		 * Put given numeric config property in range min..max (both inclusive),
		 * if not in range, set to default.
		 * @param config - object config object
		 * @param property - string config property
		 * @param min int - min allowed value (inclusive)
		 * @param max int - max allowed value (inclusive)
		 * @param defaultval - default value to use if out of range
		 * @param scaleFactor int - optional scale factor to apply
		 */
		function putInRange(config, property, min, max, defaultval, scaleFactor) {
			var v = config[property];
			if (!scaleFactor) {
				scaleFactor = 1;
			}
			if (!v || !isFinite(v) || isNaN(v) || v < min * scaleFactor || v > max * scaleFactor) {
				config[property] = defaultval * scaleFactor;
			}
		}

		/**
		 * gets Additional Parameters from the URL, and from the
		 * downloaded json.
		 * also makes sure parameters are in a given range
		 */
		function sanitizeGlobalConfig() {
			if (globalConfig) {
				globalConfig.switchtime = globalConfig.switchtime * 1000;
				globalConfig.calupdate = globalConfig.calupdate * 60 * 1000;
				globalConfig.roomupdate = globalConfig.roomupdate * 1000;
			}

			setRoomConfigFromUrl(globalConfig, 'mode', PARAM_INT);
			setRoomConfigFromUrl(globalConfig, 'calupdate', PARAM_INT, 60 * 1000);
			setRoomConfigFromUrl(globalConfig, 'roomupdate', PARAM_INT, 1000);
			setRoomConfigFromUrl(globalConfig, 'daystoshow', PARAM_INT);
			setRoomConfigFromUrl(globalConfig, 'scaledaysauto', PARAM_BOOL);
			setRoomConfigFromUrl(globalConfig, 'vertical', PARAM_BOOL);
			setRoomConfigFromUrl(globalConfig, 'eco', PARAM_BOOL);

			setRoomConfigFromUrl(globalConfig, 'scale', PARAM_INT);
			setRoomConfigFromUrl(globalConfig, 'rotation', PARAM_INT);
			setRoomConfigFromUrl(globalConfig, 'switchtime', PARAM_INT, 1000);

			// parameter validation
			putInRange(globalConfig, 'switchtime', 5, 120, 6, 1000);
			putInRange(globalConfig, 'scale', 10, 90, 50);
			putInRange(globalConfig, 'daystoshow', 1, 7, 7);
			putInRange(globalConfig, 'roomupdate', 15, 5 * 60, 60, 1000);
			putInRange(globalConfig, 'calupdate', 1, 60, 30, 60 * 1000);
			putInRange(globalConfig, 'mode', 1, 4, 1);
			putInRange(globalConfig, 'rotation', 0, 3, 0);

			$('html').attr('lang', globalConfig.language);
		}

		/**
		 * generates the Room divs and calls the needed functions depending on the rooms mode
		 */
		function initRooms() {

			var width = "100%";
			var height = "100%";
			var hasMode4 = (globalConfig.mode === 4);
			if (roomIds.length === 2 || roomIds.length === 4) {
				width = "50%";
			}
			if (roomIds.length === 3) {
				width = "33%";
			}
			if (roomIds.length === 4) {
				height = "50%";
			}
			for (var t = 0; t < roomIds.length; t++) {
				var headers;
				var rid = roomIds[t];
				var text = "<div class='roompadding' id='roompadding_" + rid + "'></div>";
				$("body").append(text);


				var obj = document.getElementById("roompadding_" + rid);
				obj.style.height = height;
				obj.style.width = width;
				text = "<div class='room'   id ='room_" + rid + "'></div>";

				$("#roompadding_" + rid).append(text);


				text = "<div id='header_" + rid + "' class='row'>" +
						"<div class='header col-2'>" +
						"<div class='font' id='roomHeader_" + rid + "'></div>" +
						"</div>" +
						"<div class='col-1 courseText header'>" +
						"<div class='font' id='courseHeading_" + rid + "'></div>" +
						"</div>" +
						"<div class='square .col-2' id='square_" + rid + "'>" +
						"<div class='FreeSeatsFont' id='freeSeatsHeader_" + rid + "'></div>" +
						"</div>" +
						"</div>";
				$("#room_" + rid).append(text);

				if (rooms[rid].name !== null) {
					$("#roomHeader_" + rid).text(rooms[rid].name);
				}

				if (roomIds.length === 2) {
					document.getElementById("square_" + rid).style.width = "6vw";
					document.getElementById("square_" + rid).style.height = "6vw";
					document.getElementById("roomHeader_" + rid).style.fontSize = "1.8vw";
					document.getElementById("freeSeatsHeader_" + rid).style.fontSize = "4.5vw";
					document.getElementById("courseHeading_" + rid).style.fontSize = "1.8vw";
					headers = document.getElementsByClassName('header');
					for (var j = 0; j < headers.length; j++) {
						headers[j].style.height = "6vw";
					}
				}
				if (roomIds.length === 3) {
					document.getElementById("square_" + rid).style.width = "4vw";
					document.getElementById("square_" + rid).style.height = "4vw";
					document.getElementById("roomHeader_" + rid).style.fontSize = "1.2vw";
					document.getElementById("freeSeatsHeader_" + rid).style.fontSize = "2.5vw";
					document.getElementById("courseHeading_" + rid).style.fontSize = "1.2vw";
					headers = document.getElementsByClassName('header');
					for (var j = 0; j < headers.length; j++) {
						headers[j].style.height = "4vw";
					}

				}
				if (roomIds.length === 4) {
					document.getElementById("square_" + rid).style.width = "4vw";
					document.getElementById("square_" + rid).style.height = "4vw";
					document.getElementById("roomHeader_" + rid).style.fontSize = "1.5vw";
					document.getElementById("freeSeatsHeader_" + rid).style.fontSize = "2.5vw";
					document.getElementById("courseHeading_" + rid).style.fontSize = "1.5vw";

					headers = document.getElementsByClassName('header');
					for (var j = 0; j < headers.length; j++) {
						headers[j].style.height = "4vw";
					}
				}


				if (globalConfig.mode === 1) {
					setUpCalendar(globalConfig.scale + "%", globalConfig.daystoshow, rooms[rid]);
					initRoomLayout(rooms[rid]);

				} else if (globalConfig.mode === 2) {
					setUpCalendar("100%", globalConfig.daystoshow, rooms[rid]);

				} else if (globalConfig.mode === 3) {
					initRoomLayout(rooms[rid]);

				} else if (globalConfig.mode === 4) {
					setUpCalendar("100%", globalConfig.daystoshow, rooms[rid]);
					initRoomLayout(rooms[rid]);
					hasMode4 = true;
				}
				SetOpeningTimes(rooms[rid]);
				UpdateRoomHeader(rooms[rid]);
			}

			if (hasMode4) {
				generateProgressBar();
			}
			setInterval(mainUpdateLoop, 1000);
		}

		var timeSteps = 10;
		var lastDate = false;
		/**
		 * Main Update loop, this loop runs every 1 seconds and calls all
		 * function which should be called periodically
		 */
		function mainUpdateLoop() {
			var date = MyDate();
			var now = date.getTime();
			// check ervery 10 sec if rooms need new calendar data or room data
			// groups request

			if (timeSteps > 9) {
				timeSteps = 0;

				if (lastCalendarUpdate + globalConfig.calupdate < now) {
					lastCalendarUpdate = now;
					queryCalendars();
				}
				if (lastRoomUpdate + globalConfig.roomupdate < now) {
					lastRoomUpdate = now;
					queryRooms();
				}
			}


			// switches calendar and roomlayout in mode 4
			if (globalConfig.mode === 4 && lastSwitchTime + globalConfig.switchtime < now) {
				doSwitch = true;
				lastSwitchTime = now;
			}

			for (var property in rooms) {
				if (rooms[property].state.end) {
					// Updating All room Headers
					UpdateRoomHeader(rooms[property]);
				}
			}

			// reload site at midnight
			var today = date.getDate();
			if (lastDate !== false) {
				if (lastDate !== today) {
					location.reload(true);
				}
			} else {
				lastDate = today;
			}
			timeSteps++;

		}

		/**
		 *  Generates a room Object and adds it to the rooms array
		 *  @param roomData Config Json of the room
		 */
		function addRoom(roomData) {
			var now = MyDate().getTime();
			var room = {
				id: roomData.id,
				name: roomData.name,
				config: globalConfig,
				timetable: null,
				currentEvent: null,
				nextEventEnd: null,
				timeTilFree: null,
				state: null,
				rawOpeningTimes: roomData.openingtime || null,
				openingTimes: null,
				openTimes: 24,
				currentfreePcs: 0,
				layout: roomData.machines || null,
				freePcs: 0,
				resized: true,
				lastCalendarUpdate: now,
				lastRoomUpdate: now,
				getState: function () {
					if (this.state === null) {
						ComputeCurrentState(this);
						return this.state;
					}
					if (this.state.end) {
						if (this.state.end < MyDate()) {
							ComputeCurrentState(this);
						}
					}
					return this.state;
				}


			};
			rooms[roomData.id] = room;
			return room;
		}

		/**
		 *  inilizes the Calendar for an room
		 *  @param percent Percentages of how mucht width the Calendar div should get (only used in mode 1)
		 *  @param daysToShow How many days the calendar should show
		 *  @param room Room Object
		 */
		function setUpCalendar(percent, daysToShow, room) {
			generateCalendarDiv(percent, room);
			var $calendar = $("#calendar_" + room.id).weekCalendar({
				timeslotsPerHour: 1,
				timeslotHeight: 30,
				daysToShow: daysToShow,
				height: function ($calendar) {
					var height = $(window).height();
					if (roomIds.length == 4) {
						height = height / 2;
					}

					height = height - document.getElementById('header_' + room.id).clientHeight - 5;
					if (room.config.mode == 1 && room.config.vertical) {
						height = height * (room.config.scale / 100)
					}
					return height;
				},
				eventRender: function (calEvent, $event) {
					if (calEvent.end.getTime() < MyDate().getTime()) {
						$event.css("backgroundColor", "#aaa");
						$event.find(".time").css({"backgroundColor": "#999", "border": "1px solid #888"});
					} else if (calEvent.end.getTime() > MyDate().getTime() && calEvent.start.getTime() < MyDate().getTime()) {
						$event.css("backgroundColor", "#25B002");
						$event.find(".time").css({"backgroundColor": "#25B002", "border": "1px solid #888"});
					}
				},
				date: MyDate(),
				dateFormat: "j.n",
				timeFormat: "G:i",
				scrollToHourMillis: 500,
				use24Hour: true,
				readonly: true,
				showHeader: false,
				hourLine: true,
				shortDays: t("shortDays", room.config.language),
				longDays: t("longDays", room.config.language),
				buttons: false,
				timeSeparator: " " + t("to", room.config.language) + " ",
				startOnFirstDayOfWeek: false,
				displayFreeBusys: true,
				defaultFreeBusy: {free: false}
			});
		}

		/**
		 * Generates the Calendar Div, depending on it's width
		 * @param width width of the Calendar Div
		 * @param room Room Object
		 */

		function generateCalendarDiv(width, room) {
			var div = document.createElement("div");
			div.id = "calendar_" + room.id;
			div.className = "calendar";
			if (room.config.vertical && room.config.mode === 1) {
				width = 100 + "%";
				$(div).css('float', "none");
			}
			div.style.width = width;
			//document.body.appendChild(div);
			$("#room_" + room.id).append(div);

		}

		const OT_DAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
		const OT_KEYS = ['HourOpen', 'HourClose', 'MinutesOpen', 'MinutesClose'];

		/**
		 * sets the opening Time in the calendar plugin and saves it in the room object
		 * @param room Room Object
		 */

		function SetOpeningTimes(room) {
			var opening = 24;
			var close = 0;
			var i;
			if (room.rawOpeningTimes && typeof(room.rawOpeningTimes) === 'object') {
				// TODO: wtf! we have three(!) formats for storing the opening times (DB, API, now this one) - WHY!?
				var parsedOpenings = room.rawOpeningTimes;
				room.state = null;
				room.openingTimesCalendar = [];
				room.openingTimes = [];
				for (i = 0; i < OT_DAYS.length; ++i) {
					room.openingTimes.push(filterOpeningTimesDay(parsedOpenings[OT_DAYS[i]]));
				}
				delete room.rawOpeningTimes;
			}
			if (!room.openingTimes) {
				scaleCalendar(room);
				return;
			}
			if (room.config.mode === 3) {
				// Calendar is not displayed, don't need to do additional work
				return;
			}
			var now = MyDate();
			for (i = 0; i < 7; i++) {
				var tmp = room.openingTimes[i];
				for (var d = 0; d < tmp.length; d++) {
					var day = getNextDayOfWeek(now, i);
					if (room.openingTimesCalendar) {
						room.openingTimesCalendar.push({
							"start": new Date(day.getFullYear(), day.getMonth(), day.getDate(),
									tmp[d]['HourOpen'], tmp[d]['MinutesOpen']),
							"end": new Date(day.getFullYear(), day.getMonth(),
									day.getDate(), tmp[d]['HourClose'], tmp[d]['MinutesClose']),
							"free": true
						});
					}
					if (tmp[d]['HourOpen'] < opening) {
						opening = tmp[d]['HourOpen'];
					}
					if (tmp[d]['HourClose'] >= close) {
						close = tmp[d]['HourClose'];
						if (tmp[d]['MinutesClose'] !== 0) {
							close++;
						}
					}
				}
			}
			if (opening === 24 && close === 0) {
				opening = 0;
				close = 24;
			}
			room.openTimes = close - opening;
			$('#calendar_' + room.id).weekCalendar("option", "businessHours", {
				start: opening,
				end: close,
				limitDisplay: true
			});
			scaleCalendar(room);
		}

		/**
		 * Filter out invalid opening time entries from given array,
		 * also make sure all the values are of type number (int)
		 *
		 * @param {Array} arr
		 * @return {Array} list of valid opening times
		 */
		function filterOpeningTimesDay(arr) {
			if (!arr || arr.constructor !== Array) return [];
			return arr.map(function (el) {
				if (!el || typeof el !== 'object') return null;
				for (var i = 0; i < OT_KEYS.length; ++i) {
					el[OT_KEYS[i]] = toInt(el[OT_KEYS[i]]);
					if (isNaN(el[OT_KEYS[i]])) return null;
				}
				return el;
			}).filter(function (el) {
				if (!el) return false;
				if (el.HourOpen < 0 || el.HourOpen > 23) return false;
				if (el.HourClose < 0 || el.HourClose > 23) return false;
				if (el.HourClose < el.HourOpen) return false;
				if (el.MinutesOpen < 0 || el.MinutesOpen > 59) return false;
				if (el.MinutesClose < 0 || el.MinutesClose > 59) return false;
				if (el.HourOpen === el.HourClose && el.MinutesClose < el.MinutesOpen) return false;
				return true;
			});
		}

		/**
		 * querys the Calendar data
		 * @param ids ID'S of rooms to query as string, for e.g.: "5,17,8" or "5"
		 */
		function queryCalendars() {
			if (!panelUuid) return;
			var url = "../../../api.php?do=locationinfo&get=calendar&uuid=" + panelUuid;
			$.ajax({
				url: url,
				dataType: 'json',
				cache: false,
				timeout: 30000,
				success: function (result) {
					if (result && result.constructor === Array) {
						var l = result.length;
						for (var i = 0; i < l; i++) {
							updateCalendar(result[i].calendar, rooms[result[i].id]);
						}
					}
				}, error: function () {
					// Retry in 5 minutes (300 seconds)
					lastCalendarUpdate = MyDate().getTime() + globalConfig.calupdate + 300000;
				}
			});
		}

		const SEVEN_DAYS = 7 * 86400 * 1000;

		/**
		 * applays new calendar data to the calendar plugin and also saves it to the room object
		 * @param {Array} json Calendar data
		 * @param room Room Object
		 */
		function updateCalendar(json, room) {
			if (!room) {
				console.log("Error: No room for calendar data");
				return;
			}
			if (!json || json.constructor !== Array) {
				console.log("Error: Calendar data was empty or malformed.");
				return;
			}
			var now = MyDate().getTime();
			json = json.filter(function (el) {
				if (!el.title || !el.start || !el.end) return false;
				var s = new Date(el.start).getTime();
				var e = new Date(el.end).getTime();
				if (isNaN(s) || isNaN(e) || Math.abs(s - now) > SEVEN_DAYS || Math.abs(e - now) > SEVEN_DAYS) return false;
				return true;
			});
			if (json.length === 0) {
				console.log('Notice: Calendar has no current events for ' + room.name);
			}
			try {
				room.timetable = json;
				if (room.config.mode !== 3) {
					// TODO: Check if they're the same
					var cal = $('#calendar_' + room.id);
					cal.weekCalendar('option', 'data', {events: json});
					cal.weekCalendar("refresh");
					cal.weekCalendar("option", "defaultFreeBusy", {free: false});
					cal.weekCalendar("updateFreeBusy", room.openingTimesCalendar);
				}
				room.state = null;
				UpdateRoomHeader(room);
			} catch (e) {
				console.log("Error: Couldnt add calendar data");
				console.log(e);
			}
		}

		/**
		 * scales calendar, called once on create and on window resize
		 * @param room Room Object
		 */
		function scaleCalendar(room) {
			if (room.config.mode === 3) {
				return;
			}
			var cal = $('#calendar_' + room.id);
			var columnWidth = document.getElementById("calendar_" + room.id).getElementsByClassName("wc-day-1")[0].clientWidth;

			if (room.config.scaledaysauto) {
				var result = (cal.weekCalendar("option", "daysToShow") * columnWidth) / 100;
				result = parseInt(Math.min(Math.max(Math.abs(result), 1), 7));
				if (result !== cal.weekCalendar("option", "daysToShow")) {
					cal.weekCalendar("option", "daysToShow", result);
				}
			}
			if (((!room.config.scaledaysauto) || cal.weekCalendar("option", "daysToShow") === 1) && columnWidth < 85) {
				cal.weekCalendar("option", "useShortDayNames", true);
			} else {
				cal.weekCalendar("option", "useShortDayNames", false);
			}
			var clientHeight = $(window).height();
			if (roomIds.length === 4) {
				clientHeight = clientHeight / 2;
			}

			clientHeight = clientHeight - document.getElementById('header_' + room.id).clientHeight
					- document.getElementsByClassName("wc-time-column-header")[0].clientHeight - 2;

			if (room.config.mode === 1 && room.config.vertical) {

				clientHeight = clientHeight * (room.config.scale / 100);
				clientHeight -= 22;
			}
			clientHeight -= 6;
			var height = clientHeight / (room.openTimes * cal.weekCalendar("option", "timeslotsPerHour"));


			if (height < 30) {
				height = 30;
			}
			// Scale calendar font
			if (height > 120) {
				cal.weekCalendar("option", "textSize", 28);
			}
			else if (height > 100) {
				cal.weekCalendar("option", "textSize", 24);
			} else if (height > 80) {
				cal.weekCalendar("option", "textSize", 22);
			} else if (height > 70) {
				cal.weekCalendar("option", "textSize", 20);
			} else if (height > 60) {
				cal.weekCalendar("option", "textSize", 14);
			} else {
				cal.weekCalendar("option", "textSize", 13);
			}
			cal.weekCalendar("option", "timeslotHeight", height);
			if (room.timetable) {
				cal.weekCalendar("option", "data", {events: room.timetable});
				cal.weekCalendar('refresh');
			}
			if (room.openingTimesCalendar) {
				cal.weekCalendar("updateFreeBusy", room.openingTimesCalendar);
			}
			cal.weekCalendar("resizeCalendar");
			cal.weekCalendar("scrollToHour");

		}

		/**
		 *  used for countdown
		 * computes the time difference between 2 Date objects
		 * @param {Date} a
		 * @param {Date} b
		 * @param room Room Object
		 * @returns time string
		 */
		function GetTimeDiferenceAsString(a, b, room) {
			if (!a || !b) {
				return "";
			}
			var milliseconds = a.getTime() - b.getTime();
			var seconds = Math.floor((milliseconds / 1000) % 60);
			milliseconds -= seconds * 1000;
			var minutes = Math.floor((milliseconds / (1000 * 60)) % 60);
			milliseconds -= minutes * 1000 * 60;
			var hours = Math.floor((milliseconds / (1000 * 60 * 60)) % 24);

			var days = Math.floor((milliseconds / (1000 * 60 * 60 * 24)) % 31);
			if (seconds < 10) {
				seconds = "0" + seconds;
			}
			if (minutes < 10) {
				minutes = "0" + minutes;
			}
			if (days !== 0) {
				// dont show?
				return "";
			}
			if (room.config.eco) {
				return hours + ":" + minutes;
			}
			return hours + ":" + minutes + ":" + seconds;
		}

		/**
		 * returns next closing time of a given room
		 * @param room
		 * @returns Date Object of next closing
		 */
		function GetNextClosing(room) {
			var now = MyDate();
			var day = now.getDay();
			var bestdate = false;
			for (var a = 0; a < 7; a++) {
				var tmp = room.openingTimes[(day + a) % 7];
				if (!tmp) continue;
				for (var i = 0; i < tmp.length; i++) {
					var closeDate = getNextDayOfWeek(now, (day + a) % 7);
					closeDate.setHours(tmp[i].HourClose);
					closeDate.setMinutes(tmp[i].MinutesClose);
					closeDate.setSeconds(0);
					if (closeDate > now) {
						if (!IsOpen(new Date(closeDate.getTime() + 1800000), room)) {
							if (!bestdate || bestdate > closeDate) {
								bestdate = closeDate;
							}
						}
					}
				}
				if (bestdate) return bestdate;
			}
			return null;
		}


		/**
		 * checks if a room is on a given date/time open
		 * @param date Date Object
		 * @param room Room object
		 * @returns bool for open or not
		 */
		function IsOpen(date, room) {
			if (!room.openingTimes) return false;
			var tmp = room.openingTimes[date.getDay()];
			if (!tmp) return false;
			var openDate = new Date(date.getTime());
			var closeDate = new Date(date.getTime());
			for (var i = 0; i < tmp.length; i++) {
				openDate.setHours(tmp[i].HourOpen);
				openDate.setMinutes(tmp[i].MinutesOpen);
				closeDate.setHours(tmp[i].HourClose);
				closeDate.setMinutes(tmp[i].MinutesClose);
				if (openDate < date && closeDate > date) {
					return true;
				}
			}
			return false;
		}


		/**
		 * Retruns next Opening
		 * @param room Room Object
		 * @returns bestdate Date Object of next opening
		 */
		function GetNextOpening(room) {
			if (!room.openingTimes) return null;
			var now = MyDate();
			var day = now.getDay();
			var bestdate = false;
			for (var dow = 0; dow < 7; dow++) {
				var tmp = room.openingTimes[(day + dow) % 7];
				if (!tmp) continue;
				for (var i = 0; i < tmp.length; i++) {
					var openDate = getNextDayOfWeek(now, (day + dow) % 7);
					openDate.setHours(tmp[i].HourOpen);
					openDate.setMinutes(tmp[i].MinutesOpen);
					if (openDate > now) {
						if (!IsOpen(new Date(openDate.getTime() - 1800000), room)) {
							if (!bestdate || bestdate > openDate) {
								bestdate = openDate;
							}
						}
					}
				}
				if (bestdate) return bestdate;
			}
			return null;
		}


		/**
		 * Sets the free PCs number in the right corner and updates the sqare color acordingly
		 * @param id Room id
		 * @param seats Number of free PC's in the room
		 */
		function SetFreeSeats(id, seats) {
			if (seats > 0) {
				$("#freeSeatsHeader_" + id).text(seats);
				$("#square_" + id).css('background-color', '#00dd10');
			} else if (seats === -1) {
				$("#freeSeatsHeader_" + id).text("");
				$("#square_" + id).css('background-color', 'red');
			} else {
				$("#freeSeatsHeader_" + id).text("0");
				$("#square_" + id).css('background-color', 'red');
			}
		}

		/**
		 * Updates the Header of an Room
		 * @param room Room Object
		 */
		function UpdateRoomHeader(room) {
			var tmp = room.getState();
			if (tmp.state === "closed") {
				$("#courseHeading_" + room.id).text(t("closed", room.config.language) + " " + GetTimeDiferenceAsString(tmp.end, MyDate(), room));
				SetFreeSeats(room.id, room.freePcs);
			} else if (tmp.state === "CalendarEvent") {
				$("#courseHeading_" + room.id).text(tmp.title);
				SetFreeSeats(room.id, -1);
			} else if (tmp.state === "Free") {
				$("#courseHeading_" + room.id).text(t("free", room.config.language) + " " + GetTimeDiferenceAsString(tmp.end, MyDate(), room));
				SetFreeSeats(room.id, room.freePcs);
			} else if (tmp.state === "FreeNoEnd") {
				$("#courseHeading_" + room.id).text(t("free", room.config.language));
				SetFreeSeats(room.id, room.freePcs);
			}
		}

		/**
		 * computes state of a room, states are:
		 * closed, FreeNoEnd, Free, CalendarEvent.
		 * @param room Object
		 */
		function ComputeCurrentState(room) {
			if (!IsOpen(MyDate(), room)) {
				room.state = {state: "closed", end: GetNextOpening(room), title: "", next: ""};

				return;
			}
			var closing = GetNextClosing(room);

			var event = getNextEvent(room.timetable);

			// no event and no closing
			if (!closing && !event) {
				room.state = {state: "FreeNoEnd", end: "", title: "", next: ""};
				return;
			}

			// no event so closing is next
			if (!event) {
				room.state = {state: "Free", end: closing, title: "", next: "closing"};
				return;
			}

			// event is at the moment
			if ((!closing || event.start.getTime() < closing.getTime()) && event.start.getTime() < MyDate()) {
				room.state = {state: "CalendarEvent", end: event.end, title: event.title, next: ""};
				return;
			}

			// no closing so event is next
			if (!closing) {
				room.state = {state: "Free", end: event.start, title: "", next: "event"};
				return;
			}

			// event sooner then closing
			if (event.start.getTime() < closing) {
				room.state = {state: "Free", end: event.start, title: "", next: "event"};
			} else {
				room.state = {state: "Free", end: closing, title: "", next: "closing"};
			}

		}


		/**
		 * returns next event from a given json of events
		 * @param calEvents Json which contains the calendar data.
		 * @returns event next Carlendar Event
		 */
		function getNextEvent(calEvents) {
			if (!calEvents) return null;
			if (calEvents.constructor !== Array) {
				console.log('getNextEvent called with something not array: ' + typeof(calEvents));
				return null;
			}
			var event;
			var now = MyDate();
			for (var i = 0; i < calEvents.length; i++) {
				//event is now active
				if (calEvents[i].start.getTime() < now.getTime() && calEvents[i].end.getTime() > now.getTime()) {
					return calEvents[i];
				}
				//first element to consider
				if (!event) {
					if (calEvents[i].start.getTime() > now.getTime()) {
						event = calEvents[i];
					}
				} else if (calEvents[i].start.getTime() > now.getTime() && event.start.getTime() > calEvents[i].start.getTime()) {
					event = calEvents[i];
				}
			}
			return event;
		}

		/**
		 * Skip to next upcoming day matching the given day of week.
		 */
		function getNextDayOfWeek(date, dayOfWeek) {
			var resultDate = new Date(date.getTime());
			resultDate.setDate(date.getDate() + (7 + dayOfWeek - date.getDay()) % 7);
			return resultDate;
		}
		/*
       /========================================== Room Layout =============================================
       */


		var picSizeX = 3.8;
		var picSizeY = 3;

		/**
		 * Generates the RoomLayout Div
		 * @param width The width the RoomLayout should have (in percent).
		 * @param room Room Object
		 */
		function generateRoomLayoutDiv(width, room) {
			var div = document.createElement("div");
			div.id = "roomLayout_" + room.id;
			div.className = "roomLayoutDesign";
			if ((room.config.vertical && room.config.mode === 1) || (room.config.mode === 3) || (room.config.mode === 4)) {
				width = 100 + "%";
			}

			div.style.width = width;
			if (room.config.mode === 4) {
				div.style.display = "none";
			}
			//document.body.appendChild(div);
			$("#room_" + room.id).append(div);


		}

		/**
		 * Main function for generating the Room Layout
		 * @param layout Layout Json
		 * @param room Room Object
		 */
		function initRoomLayout(room) {
			var maxX = false, maxY = false;
			var minX = false, minY = false;
			var xDifference, yDifference;
			var x, y;

			generateRoomLayoutDiv((100 - globalConfig.scale) + "%", room);
			var layout = room.layout;
			if (layout === null || !layout.length) {
				return;
			}

			rotateRoom(globalConfig.rotation, layout);

			for (var i = 0; i < layout.length; i++) {
				x = layout[i].x = parseInt(layout[i].x);
				y = layout[i].y = parseInt(layout[i].y);
				if (isNaN(x) || isNaN(y)) continue;
				if (minX === false || x < minX) {
					minX = x;
				}
				if (minY === false || y < minY) {
					minY = y;
				}
				if (maxX === false || x > maxX) {
					maxX = x;
				}
				if (maxY === false || y > maxY) {
					maxY = y;
				}
			}

			xDifference = maxX - minX;
			yDifference = maxY - minY;

			room.xDifference = xDifference;
			room.yDifference = yDifference;
			room.minX = minX;
			room.minY = minY;
			room.maxX = maxX;
			room.maxY = maxY;

			generateOffsetAndScale(room);
			setUpRoom(room, layout);
			scaleRoom(room);
			UpdatePc(layout, room);

		}

		/**
		 * Computes offsets and scaling's for the RoomLayout
		 * @param room Room Object
		 */
		function generateOffsetAndScale(room) {

			var clientHeight = $(window).height();
			if (roomIds.length === 4) {
				clientHeight = clientHeight / 2;
			}

			clientHeight = clientHeight - document.getElementById('header_' + room.id).clientHeight - 5;

			if (roomIds.length > 1) {
				clientHeight -= 5;
			}
			if (globalConfig.vertical && globalConfig.mode === 1) {
				clientHeight = clientHeight * (1 - (globalConfig.scale / 100));
			}
			var roomLayout = document.getElementById('roomLayout_' + room.id);

			var clientWidth = roomLayout.clientWidth;
			//roomLayout.style.height = clientHeight + "px";

			var scaleX;
			if (room.xDifference !== 0) {
				scaleX = clientWidth / room.xDifference;
			} else {
				scaleX = clientWidth;
			}
			var scaleY;
			if (room.yDifference !== 0) {
				scaleY = clientHeight / room.yDifference;
			} else {
				scaleY = clientHeight;
			}
			var scaleYs = (clientHeight - (picSizeY * scaleY)) / room.yDifference;
			var scaleXs = (clientWidth - (picSizeX * scaleX)) / room.xDifference;
			if (scaleYs <= 0) {
				scaleYs = 9999;
			}
			if (scaleXs <= 0) {
				scaleXs = 9999;
			}

			room.scale = Math.min(scaleYs, scaleY, scaleXs, scaleX, (clientHeight * 0.9) / picSizeY, (clientWidth * 0.9) / picSizeX);
			room.xOffset = 0 - room.minX;
			room.yOffset = 0 - room.minY;
			room.xOffset += ((1 / 2 * (clientWidth - (((room.maxX + room.xOffset) * room.scale) + picSizeX * room.scale))) / room.scale);
			room.yOffset += ((1 / 2 * (clientHeight - (((room.maxY + room.yOffset) * room.scale) + picSizeY * room.scale))) / room.scale);
		}


		/**
		 * adds images for each pc to Room Layout
		 * @param room Room Object
		 * @param layout Layout json
		 */
		function setUpRoom(room, layout) {
			for (var i = 0; i < layout.length; i++) {
				if (!isNaN(layout[i].y) && !isNaN(layout[i].x)) {
					var text = "<div class= 'PCImgDiv'  id ='layout_PC_div_" + room.id + "_" + layout[i].id + "'>" +

							"<div class= 'OverlayDiv' id ='layout_PC_overlay_" + room.id + "_" + layout[i].id + "'>" +
							"</div>" +
							"<img class= 'pcImg' id ='layout_PC_" + room.id + "_" + layout[i].id + "'> </img>" +
							"</div>";

					$('#roomLayout_' + room.id).append(text);
					if (layout[i].overlay && layout[i].overlay.constructor === Array) {
						for (var a = 0; a < layout[i].overlay.length; a++) {
							addOverlay($('#layout_PC_overlay_' + room.id + "_" + layout[i].id), layout[i].overlay[a]);
						}
					}
				}
			}
		}

		/**
		 * Adds an overlay to an div(here the PC's shown in the RoomLayout).
		 * @param object Object where the overlay should be added
		 * @param overlayName name of the overlay (image name without ending)
		 */
		function addOverlay(object, overlayName) {
			var a = [".svg", ".png", "jpg"];
			var imgname;
			for (var i = 0; i < a.length; a++) {
				if (imageExists("img/overlay/" + overlayName + a[i])) {
					imgname = "img/overlay/" + overlayName + a[i];
					break;
				}

			}
			if (!imgname) return; // No image found on server, do nothing
			var $text = $("<img>");
			$text.addClass('overlay').attr('src', imgname).addClass("overlay-" + overlayName);
			object.append($text);
		}


		var imgExists = {};

		/**
		 * checks if images exists on the webserver(chaches it also)
		 * @param image_url Path to the image
		 */
		function imageExists(image_url) {
			if (!imgExists.hasOwnProperty(image_url)) {
				var http = new XMLHttpRequest();
				http.open('HEAD', image_url, false);
				http.send();
				imgExists[image_url] = http.status === 200;
			}
			return imgExists[image_url];

		}

		/**
		 * Querys Pc states
		 */
		function queryRooms() {
			$.ajax({
				url: "../../../api.php?do=locationinfo&get=machines&uuid=" + panelUuid,
				dataType: 'json',
				cache: false,
				timeout: 30000,
				success: function (result) {
					if (!result || result.constructor !== Array) {
						console.log('Warning: get=machines didnt return array');
						return;
					}
					for (var i = 0; i < result.length; i++) {
						UpdatePc(result[i].machines, rooms[result[i].id]);
					}
				}
			})
		}

		/**
		 * Updates the PC's (images) in the room layout. Also Updates how many pc's are free.
		 * @param update Update Json from query for one(!) room
		 * @param room Room object
		 */
		function UpdatePc(update, room) {
			if (!room) {
				console.log('Got room update for unknown room, ignored.');
				return;
			}
			if (!update || update.constructor !== Array) {
				console.log('Update data is not array for room ' + room.name);
				console.log(update);
				return;
			}
			var freePcs = 0;
			for (var i = 0; i < update.length; i++) {
				var $imgobj = $("#layout_PC_" + room.id + "_" + update[i].id);

				var img;
				var color;
				// Pc free
				if (update[i].pcState === "IDLE") {
					img = "img/pc_free";
					color = 'green';
					freePcs++;
					// Pc in use
				} else if (update[i].pcState === "OCCUPIED") {
					img = "img/pc_used";
					color = 'red';
					// PC off
				} else if (update[i].pcState === "OFF") {
					img = "img/pc_off";
					color = 'black';
					freePcs++;
					// Must be defect
				} else {
					img = "img/pc_defect";
					color = 'black';
				}

				if (supportSvg) {
					if (room.config.eco) {
						img = img + "_eink";
					}
					$imgobj.attr('src', img + ".svg");
				} else {
					$imgobj.css('background-color', color);
				}

			}
			room.freePcs = freePcs;
			UpdateRoomHeader(room);
		}

		/**
		 * Adjust pc coordinate depending on room rotation
		 * @param r Rotation, from 0 - 3 (int)
		 * @param layout Layout json
		 */
		function rotateRoom(r, layout) {
			for (var z = 0; z < r; z++) {
				for (var i = 0; i < layout.length; i++) {
					var x = parseInt(layout[i].x);
					var y = parseInt(layout[i].y);
					layout[i].x = y;
					layout[i].y = -x;
				}
			}
		}

		/**
		 * Positions the computer images in the roomLayout div accoring to ther potion and div size
		 * @param room Room object
		 */
		function scaleRoom(room) {
			for (var i = 0; i < room.layout.length; i++) {
				if (!isNaN(room.layout[i].y) && !isNaN(room.layout[i].x)) {
					var tmp = document.getElementById("layout_PC_div_" + room.id + "_" + room.layout[i].id);
					if (tmp) {
						tmp.style.width = (picSizeX * room.scale);
						tmp.setAttribute("style", "width:" + (picSizeX * room.scale) + "px");
						tmp.style.height = (picSizeY * room.scale) + "px";
						tmp.style.left = ((room.layout[i].x + room.xOffset) * room.scale) + "px";
						tmp.style.top = ((room.layout[i].y + room.yOffset) * room.scale) + "px";
					}
				}
			}
		}

		/*
       /========================================== Misc =============================================
       */
		var resizeTimeout = false;

		// called when browser window changes size
		// scales calendar and room layout acordingly

		$(window).resize(function () {
			if (resizeTimeout) clearTimeout(resizeTimeout);
			resizeTimeout = setTimeout(function () {
				resizeTimeout = false;
				for (var property in rooms) {
					rooms[property].resized = true;
					if (rooms[property].config.mode !== null) {
						if (rooms[property].config.mode !== 3) {
							scaleCalendar(rooms[property]);
						}
						if (rooms[property].config.mode !== 2) {
							generateOffsetAndScale(rooms[property]);
							scaleRoom(rooms[property]);
						}
					}
				}
				SetProgressBarSpeed();
			}, 200);
		});


		/**
		 * returns parameter value from the url
		 *  @param sParam
		 *  @returns value for given parameter
		 */
		var getUrlParameter = function getUrlParameter(sParam) {
			var sPageURL = decodeURIComponent(window.location.search.substring(1)),
					sURLVariables = sPageURL.split('&'),
					sParameterName,
					i;

			for (i = 0; i < sURLVariables.length; i++) {
				sParameterName = sURLVariables[i].split('=', 2);

				if (sParameterName[0] === sParam) {
					if (sParameterName.length === 1) return true;
					return sParameterName[1];
				}
			}
			return false;
		};

		/**
		 * Function for translation
		 * @param toTranslate key which we wan't to translate
		 * @param lang languages in which should be translated
		 * @returns r translated string
		 */
		function t(toTranslate, lang) {

			var r;
			if (!lang || !translation[lang] || !translation[lang][toTranslate]) {
				r = translation['en'][toTranslate] || 'missing';
			} else {
				r = translation[lang][toTranslate];
			}
			return r;
		}


		/**
		 * Used in Mode 4, switches given room from Timetable to Roomlayout and vice versa
		 * @param room
		 */
		function switchLayouts() {
			for (var roomKey in rooms) {
				var room = rooms[roomKey];
				if (room.config.mode !== 4) continue;
				var car = document.getElementById("calendar_" + room.id);
				var roomLayout = document.getElementById("roomLayout_" + room.id);

				if (car.style.display === "none") {
					roomLayout.style.display = "none";
					car.style.display = "block";
					if (room.resized) {
						scaleCalendar(room);
						room.resized = false;
					}
				} else {
					car.style.display = "none";
					roomLayout.style.display = "block";
					if (room.resized) {
						generateOffsetAndScale(room);
						scaleRoom(room);
						room.resized = false;
					}
				}
			}
			lastSwitchTime = MyDate().getTime();
		}

		var $pbar = false;
		var pbarTimer = false;
		const PX_PER_SEC_TARGET = 10;

		/**
		 * adds a progressbar (id) used in mode 4
		 */
		function generateProgressBar() {
			if ($pbar) return;
			$pbar = $('<div id="progressBar" class="progressbar">');
			$('body').append($pbar);
			SetProgressBarSpeed()
		}

		function SetProgressBarSpeed() {
			if (!$pbar || !globalConfig.switchtime) return;
			if (pbarTimer) clearInterval(pbarTimer);
			var pxPerMSec = $('body').width() / globalConfig.switchtime;
			var interval = Math.max(1 / (pxPerMSec / PX_PER_SEC_TARGET), 100);
			pbarTimer = setInterval(function () {
				var width = ((MyDate().getTime() - lastSwitchTime) / globalConfig.switchtime) * 100;
				if (width < 0) width = 0;
				if (width >= 100) {
					width = 100;
					switchLayouts();
				}
				$pbar.width(width + '%');
			}, interval);
		}

		function toInt(str) {
			var t = typeof str;
			if (t === 'number') return str | 0;
			if (t === 'string') return parseInt(str.replace(/^0+([^0])/, '$1'));
			return NaN;
		}

	</script>
</head>
<body>
</body>
</html>