/**
 * Clones the array and returns the clone
 * @return Array clone
 * @type Array
 */
Array.prototype.clone = function() {
	var newData = new Array();
	
	for (var i = 0; i < this.length; i++) {
		newData.push(this[i]);
	}
	
	return newData;
}

/**
 * Returns the index of the given element
 * @return The index of the given element
 * @type Number
 */
Array.prototype.indexOf = function(element) {
	for (var i = 0; i < this.length; i++) {      
		if (this[i] == element) {
			return i;
		}
	}

	return -1;
}
/**
 * Cookie module
 * @constructor
 * @author Cser Dániel, Horvath 'Koko' Kornel
 */
function CookieManager() {
	
	/**
	 * Pointer to this
	 * @type CookieManager
	 */
	var self = this;
	
    /**
     * Sets the cookie
     * @param String Name of cookie
     * @param String Value of cookie
     */
    this.set = function(key, value) {
		var today = new Date();
		var expire = new Date();
		
		expire.setTime(today.getTime() + (3600000 * 24 * 30));
		
		document.cookie = key + "=" + escape(value) + ";expires=" + expire.toGMTString();
    }
	
    /**
     * Returns the specified cookie
     * @param String Name of cookie
     * @return Found cookie
     * @type String
     */
    this.get = function(key) {
		var start = document.cookie.indexOf(key + "=");
		var len = start + key.length + 1;
		
		if ( start == -1 || ( ! start && key != document.cookie.substring(0, key.length))) {
		    return "";
		}
		
		var end = document.cookie.indexOf(";", len);
		
		if (end == -1) {
		    end = document.cookie.length;
		}
		
		return unescape(document.cookie.substring(len, end));;
    }
	
    /**
     * Removes the specified cookie
     * @param String Name of cookie
     */
    this.remove = function(key) {
		if (self.get(key)) {
		    document.cookie = key + "=; expires=Thu, 10-Jan-88 00:00:02 GMT";
		    document.cookie = key + "=; expires=Thu, 10-Jan-88 00:00:02 GMT; path=/";
		}
    }
	
	/**
	 * Checks for remember user flag
	 */
    this.checkRemember = function() {
	var remember = self.get("remember");
	if (! remember && remember != "yes") {
	    return;
	}
		
	var sId = self.get("sId");
	if (sId) {
	    engine.eventManager.invoke(new Event(self, EventManager.EVENT_USER_PRELOGIN, { "sId": sId }));
	}
    }
    
}
/**
 * DragAndDrop handler class
 * @param Object DOM object to move
 * @param Object DOM object to move with
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function DragAndDrop(dndMover, dndBox) {
	
	var box;
	
	var mover;
	
	var lastMouseX;
	
	var lastMouseY;

	function start(e) {
		e = (e != undefined ? e : window.event);
		
		lastMouseX = e.clientX;
		lastMouseY = e.clientY;
		
		document.onmousemove = drag;
		document.onmouseup = end;

		return false;
	}

	function drag(e) {
		e = (e != undefined ? e : window.event);
		
		var nx = parseInt(box.style.left) + (e.clientX - lastMouseX);
		var ny = parseInt(box.style.top) + (e.clientY - lastMouseY);

		box.style.left = nx + "px";
		box.style.top = ny + "px";
		lastMouseX = e.clientX;
		lastMouseY = e.clientY;
		
		return false;
	}

	function end() {
		document.onmousemove = null;
		document.onmouseup = null;
	}

	//Initialize
	box = dndBox;
	box.style.left = "0px";
	box.style.top = "0px";
	
	mover = check(dndMover) ? dndMover : dndBox;
	
	mover.onmousedown = start;
	
}
/**
 * Engine main class
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function Engine() {
	
	/**
	 * Error handler module
	 * @type Log
	 */
	this.log = null;
	
	/**
	 * CommGate module
	 * @type CommGate
	 */
	this.commGate = null;
	
	/**
	 * TemplateManager module
	 * @type TemplateMananger
	 */
	this.templateManager = null;
	
	/**
	 * EventManager module
	 * @type EventManager
	 */
	this.eventManager = null;
	
	/**
	 * HistoryManager module
	 * @type HistoryManager
	 */
	this.historyManager = null;
	
	/**
	 * DialogManager module
	 * @type DialogManager
	 */
	this.dialogManager = null;
	
	/**
	 * CookieManager module
	 * @type CookieManager
	 */
	this.cookieManager = null;
	
	/**
	 * ToolTip module
	 * @type ToolTip
	 */
	this.tooltip = null;
	
	/**
	 * Initializes Engine
	 */
	this.init = function() {
		this.log = new Log();
		this.commGate = new CommGate();
		this.templateManager = new TemplateManager();
		this.eventManager = new EventManager();
		this.historyManager = new HistoryManager();
		this.dialogManager = new DialogManager();
		this.cookieManager = new CookieManager();
		this.tooltip = new ToolTip();
	}
	
}
/**
 * Manages location changes.
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function HistoryManager() {
	
	/**
	 * Storage map
	 * @type Map
	 */
	var storage;
	
	/**
	 * Current location hash
	 * @type String
	 */
	var currentLocation;
	
	/**
	 * Whether to ignore the actual location change
	 * @type Boolean
	 */
	var ignoreLocationChange;
	
	/**
	 * IE variable
	 * @type Boolean
	 */
	var ieAtomicLocationChange;
	
	/**
	 * Pointer to this
	 * @type HistoryManager
	 */
	var self = this;
	
	/**
	 * Adds a manual location change.
	 * @param String Location hash
	 * @param mixed Data of change
	 */
	this.listenLayoutReload = function(event) {
		var data = event.getData().toObject();
		
		if (data.tabId == undefined || data.subId == undefined) {
			data.extend(esuli.tab.getIds(data.module + "_" + (data.levelId != undefined ? data.levelId : data.page)));
		}
		
		var prevLocation = storage.get(storage.size() - 1);
		
		if (check(prevLocation) && (prevLocation.toMap().equalsTo(data.toMap()))) {
			return;
		}
		
		var newLocation = storage.size();
		
		storage.put(newLocation, data);
		
		ignoreLocationChange = ieAtomicLocationChange = true;
		
		currentLocation = newLocation;
		
		window.location.hash = currentLocation;
		
		if (isInternetExplorer()) {
			$("DhtmlHistoryFrame").src = "iframe_history_1_5.html?" + newLocation;
		}
		
		ieAtomicLocationChange = false;
	}
	
	/**
	 * Check for location changes.
	 */
	function checkLocation() {
		if (isInternetExplorer() == false) {
			if (ignoreLocationChange == true) {
				ignoreLocationChange = false;
				return;
			}
			
			if (ieAtomicLocationChange == true) {
				return;
			}
		}
		
		var hash = self.getCurrentLocation();
		
		if (hash == currentLocation) {
			return;
		}
		
		ieAtomicLocationChange = true;
		
		if (isInternetExplorer() == true) {
			if (getIFrameHash() != hash) {
				$("DhtmlHistoryFrame").src = "blank.html?" + hash;
			} else {
				return;
			}
		}
		
		currentLocation = hash;
		ieAtomicLocationChange = false;
		
		fireHistoryEvent(hash);
	}
	
	/**
	 * Returns hash value of hidden iframe
	 * @return Hash value of hidden iframe
	 * @type String
	 */
	function getIFrameHash() {
		var hash = String($("DhtmlHistoryFrame").contentWindow.document.location.search);
		
		if (hash.length == 1 && hash.charAt(0) == "?") {
			return "";
		} else if (hash.length >= 2 && hash.charAt(0) == "?") {
			return hash.substring(1);
		} else {
			return hash;
		}
	}
	
	/**
	 * Removes leading hash from location
	 * @param String Hash value
	 * @return Corrected hash value
	 * @type String
	 */
	function removeHash(hash) {
		if (hash == null || hash == undefined) {
			return null;
		} else if ((hash == "") || (hash.length == 1 && hash.charAt(0) == "#")) {
			return "";
		} else if (hash.length > 1 && hash.charAt(0) == "#") {
			return hash.substring(1);
		} else {
			return hash;
		}
	}
	
	/**
	 * This function is called when the hidden iframe has been reloaded.
	 * @param String Location string
	 */
	this.iframeLoaded = function(newLocation) {
		if (ignoreLocationChange == true) {
			ignoreLocationChange = false;
			return;
		}
		
		var hash = String(newLocation.search);
		
		if (hash.length == 1 && hash.charAt(0) == "?") {
			hash = "";
		} else if (hash.length >= 2 && hash.charAt(0) == "?") {
			hash = hash.substring(1);
		}
		
		window.location.hash = hash;
		
		fireHistoryEvent(hash);
	}
	
	/**
	 * Returns current location hash
	 * @return Current location hash
	 * @type String
	 */
	this.getCurrentLocation = function() {
		return removeHash(window.location.hash);
	}
	
	/**
	 * Calls listener.
	 * @param String Hash value
	 */
	function fireHistoryEvent(hash) {
		var data = storage.get(hash);
		
		if (! check(data)) {
			return;
		}
		
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_NAV_CHANGE, data.toMap()));
	}
	
	/**
	* Detects if the browser is IE
	 * @return True when browser is IE
	 * @type Boolean
	 */
	function isInternetExplorer() {
		return (document.all && navigator.userAgent.toLowerCase().indexOf('msie') != -1 ? true : false);
	}
	
	//Initialize
	currentLocation = self.getCurrentLocation();
	
	//create storage
	storage = new Map();
	
	engine.eventManager.addListener(EventManager.EVENT_LAYOUT_RELOAD, this);
	
	if (isInternetExplorer()) {
		try {
			document.body.innerHTML += engine.templateManager.getTemplate("history_iframe").process({ initialHash: currentLocation });
		} catch(e) {
			//TODO: Log error
		}
		
		ignoreLocationChange = true;
		
		if (storage.containsKey("DhtmlHistory_pageLoaded") == false) {
			storage.put("DhtmlHistory_pageLoaded", true);
		} else {
			fireHistoryEvent(currentLocation);
		}
	} else {
		if (storage.containsKey("Dhtml_pageLoaded") == false) {
			ignoreLocationChange = true;
			storage.put("Dhtml_pageLoaded", true);
		} else {
			ignoreLocationChange = false;
			fireHistoryEvent(currentLocation);
		}
	}
	
	setInterval(checkLocation, 100);
	
}
/**
 * Iterates through a set.
 * @constructor
 * @param Array Data array
 * @author Horvath 'Koko' Kornel
 */
function Iterator(iteratorData) {
	
	/**
	 * Iteratable array
	 * @type Array
	 */
	var data;
	
	/**
	 * Shows the actual member's index
	 * @type Number
	 */
	var actual;
	
	/**
	 * Whether set has more elements or not
	 * @return True when it has more elements
	 * @type boolean
	 */
	this.hasNext = function() {
		if (data[actual + 1]) {
			return true;
		}
		
		return false;
	}
	
	/**
	 * Returns the next element of the set
	 */
	this.next = function() {
		return data[++actual];
	}
	
	//Initialize
	if (! iteratorData || ! (iteratorData instanceof Array)) {
		return;
	}
	
	data = iteratorData;
	actual = -1;
	
}
/**
 * Manages exception handling
 * @constructor
 * @author CsD, Horvath 'Koko' Kornel
 */
function Log() {
	
	 /**
      * Array contains exceptions
      * @type Array
      */
	 var aException = new Array();
	
	 /**
      * Array contains logs
      * @type Array
      */
     var aLog = new Array();	

     /**
      * Max log size before send
      * @type Number
      */
     var maxLog = 10;

     /**
      * Level which must be logged
      * @type String
      */
     var level = "INFO";

    /**
     * Firebug log is allowed only in Firefox
     * @type Boolean
     */
    var isFirefox = false;

    /**
     * Returns the index of the function
     * @param String Name of function
     * @return The index of the function
     * @type Number
     */
	function getIndex(pFunctionName) {
		for (var i = 0; i < aException.length; i++) {
			if (aException[i].functionName == pFunctionName) {
				return i;
			}
		}
		
		return -1;
	}
	
	/**
     * Returns the first exception of the given function
     * @param String Name of function
     * @return The first exception of the given function
     * @type Error
     */
	function getExceptionByName(pFunctionName) {
		var index = getIndex(pFunctionName);
		
		if (index > -1) {
			return aException[index];
		}
		
		return null;
	}
	
	
	/**
     * Stores exception
     * @param String Name of file
     * @param String Name of function
     * @param Error Exception object
     */
	this.addException = function(pFileName, pFunctionName, pE) {
		pE.fileName = pFileName;
		pE.functionName = pFunctionName;
		
		//IE4
		if (document.all) {
			pE.number = pE.number & 0xFFFF;
		}
		
		aException.push(pE);
	}
	
	/**
     * Stores log
	 * Levels: 
	 * NONE: None
	 * ERROR: Errors
	 * INFO: Informations
	 * DEBUG: Development
	 * MUST: Must
	 * @param String Name of file
	 * @param String Name of function
	 * @param String Level of log
	 * @param String Message of exception
     */
	this.addLog = function(pFileName, pFunctionName, pLevel, pText) {
		if (
			(pLevel != "MUST") && (
				(pLevel == "ERROR" && level == "NONE") ||
				(pLevel == "INFO" && (level == "ERROR" || level == "NONE")) ||	
        		(pLevel == "DEBUG" && (level == "INFO" ||  level == "ERROR" || level == "NONE"))
			)
		) {
			return;
		}

		aLog.push({fileName: pFileName, functionName: pFunctionName, level: pLevel, description: pText});
		sendLog();
	}
	
	/**
	 * Sends log to server
	 */
	function sendLog() {
		//Log kiakpcsolva
		return;
		if (aLog.length < maxLog) {
			return;
		}
		
  		var now = new Date();
  		var dateStr = now.getFullYear() + "." + now.getMonth() + "." + now.getDate() + " " + now.getHours() + ":" + now.getMinutes();
  		var log = dateStr;
  		
		for (var i = 0; i < aLog.length; i++) {
			if (aLog[i].level == "INFO") {
				log += "  |  " + aLog[i].description;
			} else {
				log += "  |  " + aLog[i].level + " " + aLog[i].fileName + " " + aLog[i].functionName + " " + aLog[i].description;
			}
		}
		
		engine.commGate.send([ new CommGateRequest("REQ_LOG", [ log ], function() { alert("OK"); }) ]);

		aLog = new Array();
	}

	/**
     * Does nothing
     */
	this.writeException = function(pFunctionName) {
		var tmp = "";
		
		var e = getExceptionByName(pFunctionName);
		
		if (e) {
			tmp = e.toString();
			
			for (key in e) {
  				tmp += "\n\n" + key + ": " + e[key];
			}
		} else {
			tmp = pFunctionName + ": nem volt exception";
		}
	}
	
	/**
     * Bad
     */
	this.clearException = function(pFunctionName) {
		if(! pFunctionName || pFunctionName == "all") {
			aException = new Array();
		} else {
			var index = getIndex(pFunctionName);
			
			if (index > -1) {
				aException.splice(index, 1);
			}
		}
	}
	
	/**
	 * Detect Firefox
	 */
	function detectFirefox() {
		var appName = navigator.appName;
		var userA = navigator.userAgent;
		
		if(appName.indexOf('Netscape') != -1) {
			var space = userA.lastIndexOf(' ');
			var slash = userA.lastIndexOf('/');
			var browserType = userA.substring(space, slash);
			if(browserType.indexOf('Firefox') != -1) {
				isFirefox = true;
				if(allowFireBugLog) {
					console.info("FireBug Log is enabled!");
				}
			}
		}
	}
	
	/**
	 * FireBug Log 
	 * Example: 
	 *
	 * engine.log.fireBugLog("time","","","Logging time");
	 * engine.log.fireBugLog("group","","","Group 1");
	 * engine.log.fireBugLog("info", "common.js", "init()", "This is in Group 1");
	 * engine.log.fireBugLog('log', 'common.js', 'init()', [Array, DimensionArray, ObjectArray]);
	 * engine.log.fireBugLog("group","","","Sub group 1");
	 * engine.log.fireBugLog("info", "common.js", "init()", "This is in Sub group 1");
	 * engine.log.fireBugLog('dirxml', '', '', document.getElementById('headerBodyCenterLeft'));
	 * engine.log.fireBugLog("groupEnd","","","Sub group 1");
	 * engine.log.fireBugLog("groupEnd","","","Group 1");
	 * engine.log.fireBugLog("timeEnd","","","Logging time");
	 * 
	 * @param String Type of log
	 * @param String Filename where function is
	 * @param String Name of function
	 * @param Object Parameters
	 */
	this.fireBugLog = function(pType, pFile, pFunction, pParameters) {
	
	    if(!("console" in window) || !("firebug" in console)) {
		var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
		window.console = {};
		for (var i = 0; i < names.length; ++i) {
		    window.console[names[i]] = function() {};
		}
	    }
	    
		if(allowFireBugLog) {
			var basic = pFile + " | " + pFunction;
			if(!pParameters) {
				 pParameters = "";
			} else {
				basic += " | ";
			}
			
			switch(pType) {
				case "log":
				case "info":
				case "warn":
				case "error":
					console[pType](basic, pParameters);
					break;
					
				case "time":
				case "timeEnd":
				case "group":
				case "groupEnd":
				case "dir":
				case "dirxml":
					console[pType](pParameters);
					break;
					
				default:
					console.error("FireBug Log Error! Unknown FireBug log type: " + pType);
					break;
			}
		} else {
			return;
		}
	}
	
	//detectFirefox();
}
/**
 * Converts object's properties to Map, except functions
 * @return Converted object
 * @type Map
 */
Object.prototype.toMap = function() {
	var map = new Map();
	
	for (var key in this) {
		if (typeof(this[key]) != "function") {
			map.put(key, this[key]);
		}
	}
	
	return map;
}

/**
 * Collection used to store data by key-value pairs.
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function Map() {
	
	/**
	 * Data holding maps elements
	 * @type Array
	 */
	var data;
	
	/**
	 * Pointer to this
	 * @type Map
	 */
	var self = this;
	
	/**
	 * Put a value by a given key. If the key already exists, it will be overridden.
	 * @param String Key of data
	 * @param mixed Value of data
	 */
	this.put = function(elementKey, elementValue) {
		for (var i = 0; i < data.length; i++) {
			if (data[i].getKey() == elementKey) {
				data[i].setValue(elementValue);
				return;
			}
		}
		
		data.push(new MapElement(elementKey, elementValue));
	}
	
	/**
	 * Returns value by a given key.
	 * @param String Key of value
	 * @return Found value
	 * @type mixed
	 */
	this.get = function(elementKey) {
		for (var i = 0; i < data.length; i++) {
			if (data[i].getKey() == elementKey) {
				return data[i].getValue();
			}
		}
		
		return null;
	}
	
	/**
	 * Returns true when key is exists in the map
	 * @param String Key of value
	 * @return True when key exists
	 * @type boolean
	 */
	this.containsKey = function(elementKey) {
		for (var i = 0; i < data.length; i++) {
			if (data[i].getKey() == elementKey) {
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * Returns true when value is exists in the map
	 * @param mixed Value
	 * @return True when value exists
	 * @type boolean
	 */
	this.containsValue = function(elementValue) {
		for (var i = 0; i < data.length; i++) {
			if (data[i].getValue() == elementValue) {
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * Returns the keyset of thew map
	 * @return Keyset of the map
	 * @type Set
	 */
	this.keys = function() {
		var set = new Set();
		
		for (var i = 0; i < data.length; i++) {
			set.add(data[i].getKey());
		}
		
		return set;
	}
	
	/**
	 * Returns the keyset of thew map
	 * @return Keyset of the map
	 * @type Array
	 */
	this.keysArray = function() {
		var array = new Array();
		
		for (var i = 0; i < data.length; i++) {
			array.push(data[i].getKey());
		}
		
		return array;
	}
	
	/**
	 * Returns the valueset of the map
	 * @return Valueset of the map
	 * @type Set
	 */
	this.values = function() {
		var set = new Set();
		
		for (var i = 0; i < data.length; i++) {
			set.add(data[i].getValue());
		}
		
		return set;
	}
	
	/**
	 * Returns the valueset of the map
	 * @return Valueset of the map
	 * @type Array
	 */
	this.valuesArray = function() {
		var array = new Array();
		
		for (var i = 0; i < data.length; i++) {
			array.push(data[i].getValue());
		}
		
		return array;
	}
	
	/**
	 * Removes an element by the given key
	 * @param String key
	 */
	this.remove = function(elementKey) {
		var newData = new Array();
		
		for (var i = 0; i < data.length; i++) {
			if (data[i].getKey() != elementKey) {
				newData.push(data[i]);
			}
		}
		
		data = newData;
	}
	
	/**
	 * Empties the map
	 */
	this.clear = function() {
		data = new Array();
	}
	
	/**
	 * Returns true when map is empty
	 * @return True when map is empty
	 * @type boolean
	 */
	this.isEmpty = function() {
		return data.length == 0;
	}
	
	/**
	 * Returns the size of the map
	 * @return Size of the map
	 * @type Number
	 */
	this.size = function() {
		return data.length;
	}
	
	/**
	 * Converts map to object
	 * @return Converted map
	 * @type Object
	 */
	this.toObject = function() {
		var obj = new Object();
		
		for (var i = 0; i < data.length; i++) {
			obj[data[i].getKey()] = data[i].getValue();
		}
		
		return obj;
	}
	
	/**
	 * Sorts contained elements by the given function
	 * @param Function Function used to sort
	 */
	this.sort = function(sortBy) {
		data = data.sort(sortBy);
	}
	
	/**
	 * Calls callback on every element of the map
	 * @param Function Callback function
	 */
	this.map = function(callback) {
		for (var i = 0; i < data.length; i++) {
			callback(data[i].getValue());
		}
	}
	
	/**
	 * Returns true if keys and values of maps are equal
	 * @return True if keys and values of maps are equal
	 * @type Boolean
	 */
	this.equalsTo = function(otherMap) {
		if (! checkType(otherMap, Map)) {
			return false;
		}
		
		if (! self.keys().equalsTo(otherMap.keys()) || ! self.values().equalsTo(otherMap.values())) {
			return false;
		}
		
		return true;
	}
	
	/**
	 * Returns the next element relative to the given
	 * @param mixed Key of element
	 * @return The next element relative to the given
	 * @type mixed
	 */
	this.nextElement = function(elementKey) {
		for (var i = 0; i < data.length; i++) {
			if (data[i].getKey() == elementKey) {
				return (data[i + 1] != undefined ? data[i + 1].getValue() : null);
			}
		}
		
		return null;
	}
	
	/**
	 * Returns the previous element relative to the given
	 * @param mixed Key of element
	 * @return The previous element relative to the given
	 * @type mixed
	 */
	this.prevElement = function(elementKey) {
		for (var i = 0; i < data.length; i++) {
			if (data[i].getKey() == elementKey) {
				return (data[i - 1] != undefined ? data[i - 1].getValue() : null);
			}
		}
		
		return null;
	}
	
	//Initialize
	data = new Array();
	
	/**
	 * Internal class for holding a key-value pair
	 * @param String Key of element
	 * @param mixed Value of element
	 */
	function MapElement(elementKey, elementValue) {
		
		/**
		 * Key of element
		 * @type String
		 */
		var key = elementKey;
		
		/**
		 * Value of element
		 * @type mixed
		 */
		var value = elementValue;
		
		/**
		 * Return the key of element
		 * @return Key of element
		 * @type String
		 */
		this.getKey = function() {
			return key;
		}
		
		/**
		 * Returns the value of element
		 * @return Value of element
		 * @type mixed
		 */
		this.getValue = function() {
			return value;
		}
		
		/**
		 * Set the new value of element
		 * @param mixed New value
		 */
		this.setValue = function(elementValue) {
			value = elementValue;
		}
		
	}
	
}
/**
 * Creates object's creation code
 * @return Creation code
 * @type String
 */
Object.prototype.serialize = function() {
	var source = "";
	
	switch(this.constructor) {
		
		case Boolean:
			source += "(new Boolean(" + this + "))";
			break;
		
		case Number:
			source += "(new Number(" + this + "))";
			break;
		
		case String:
			source += "(new String(\"" + this + "\"))";
			break;
		
		case Date:
			source += "(new Date(" + this.getTime() + "))";
			break;
		
		case Error().constructor:
			source += "(new Error(\"" + this.message + "\", \"" + this.fileName + "\", " + this.lineNumber + "))";
			break;
		
		case Function:
			source += "(" + this.toString() + ")";
			break;
		
		case Array:
			var objSrc = new Array();
			
			for (var i = 0; i < this.length; i++) {
				if (typeof(this[i]) == "function") {
					continue;
				}
				
				if (typeof(this[i]) == "object" && this[i] != null) {
					var obj = this[i];
					objSrc.push(obj.serialize());
				} else if (typeof(this[i]) == "string") {
					objSrc.push("\"" + this[i] + "\"");
				} else {
					objSrc.push(this[i] + "");
				}
			}
			
			source += "[ " + objSrc.join(", ") + " ]";
			break;
		
		default:
			var objSrc = new Array();
			
			for (var i in this) {
				if (typeof(this[i]) == "function") {
					continue;
				}
				
				if (typeof(this[i]) == "object") {
					var obj = this[i];
					objSrc.push(i + ": " + obj.serialize());
				} else if (typeof(this[i]) == "string") {
					objSrc.push(i + ": \"" + this[i] + "\"");
				} else {
					objSrc.push(i + ": " + this[i]);
				}
			}
			
			source += "{ " + objSrc.join(", ") + " }";
			break;
	}
	
	return source;
}

/**
 * Extends this object with other object
 * @param Object Object to extend this object with
 * @return Self
 * @type Object
 */
Object.prototype.extend = function(otherObject) {
	for (var key in otherObject) {
		this[key] = otherObject[key];
	}
	
	return this;
}
/**
 * Handles an array which can have only one instance of an object at the same time. It
 * supports some handler method and an iterator object.
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function Set() {
	
	/**
	 * The array
	 * @type Array
	 */
	var data;
	
	/**
	 * Pointer to this
	 * @type Set
	 */
	var self = this;
	
	/**
	 * Adds the element to the array when it is not already member of this set.
	 * @param mixed Element to add
	 */
	this.add = function(element) {
		for (var i = 0; i < data.length; i++) {
			if (data[i] == element) {
				return;
			}
		}
		
		data.push(element);
	}
	
	/**
	 * Shows if the given element is already member of this set.
	 * @param mixed Element to inspect
	 * @return True when it is
	 * @type boolean
	 */
	this.contains = function(element) {
		for (var i = 0; i < data.length; i++) {
			if (data[i] == element) {
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * Removes the given element when it is already member of this set.
	 * @param mixed Element to remove
	 */
	this.remove = function(element) {
		var newData = new Array();
		
		for (var i = 0; i < data.length; i++) {
			if (data[i] != element) {
				newData.push(data[i]);
			}
		}
		
		data = newData;
	}
	
	/**
	 * Clears the set.
	 */
	this.clear = function() {
		data = new Array();
	}
	
	/**
	 * Returns true if set is empty.
	 * @return True if set is empty
	 * @type boolean
	 */
	this.isEmpty = function() {
		return data.length == 0;
	}
	
	/**
	 * Returns the size of the set.
	 * @return Size of the set
	 * @type Number
	 */
	this.size = function() {
		return data.length;
	}
	
	/**
	 * Returns a new Iterator based on this set.
	 * @return New Iterator
	 * @type Iterator
	 */
	this.iterator = function() {
		return new Iterator(data);
	}
	
	/**
	 * Returns a clone of the set array
	 * @return Clone of the set array
	 * @type Array
	 */
	this.toArray = function() {
		return data;
	}
	
	/**
	 * Returns true if elements of sets are equal
	 * @return True if elements of sets are equal
	 * @type Boolean
	 */
	this.equalsTo = function(otherSet) {
		if (! checkType(otherSet, Set)) {
			return false;
		}
		
		if (data.length != otherSet.size()) {
			return false;
		}
		
		var it = new Iterator(data);
		var otherIt = otherSet.iterator();
		
		var element;
		var otherElement;
		
		while (it.hasNext()) {
			element = it.next();
			otherElement = otherIt.next();
			
			if (typeof(element) == "object" && typeof(otherElement) == "object") { //both objects
				if (! (String(element.serialize()) == String(otherElement.serialize()))) {
					return false;
				}
			} else if (
				(typeof(element) == "object" && typeof(otherElement) != "object") ||
				(typeof(element) != "object" && typeof(otherElement) == "object")
			) { //one of them is object
				return false;
			} else { //none of them are object
				if (element != otherElement) {
					return false;
				}
			}
		}
		
		return true;
		
	}
	
	//Initialize
	data = new Array()
	
}
/**
 * Trimms whitespaces from the beginning and from the end of the string,
 * removes doublespaces
 * @return Trimmed string
 * @type String
 */
String.prototype.trim = function() {
	var trimmed = new String(" " + this.toString() + " ");
	
	//remove double spaces
	while (trimmed.match(/  /)) {
		trimmed = trimmed.replace(/  /g, " ");
	}
	
	//remove leading spaces
	while (trimmed.charAt(0) == " ") {
		trimmed = trimmed.substr(1);
	}
	
	//remove trailing spaces
	while (trimmed.charAt(trimmed.length - 1) == " ") {
		trimmed = trimmed.substr(0, trimmed.length - 1);
	}
	
	return trimmed;
}
/**
 * ToolTip
 * @constructor
 * @author Morr
 */
function ToolTip() {
    /**
     * Global ToolTip configuration object.
     * For each of the following config variables there exists a command, which is
     * just the variablename in uppercase, to be passed to Tip() or TagToTip() to
     * configure tooltips individually. Individual commands override global
     * configuration. Order of commands is arbitrary.
     * Example: onMouseOver="Tip('Tooltip text', LEFT, true, BGCOLOR, '#FF9900', FADEIN, 400);"
     * @type Object
     */
	var config = new Object();
	
    /**
     * false or true - recommended: false once you release your page to the public
     * @type Boolean
     */
	var tt_Debug = true;

    /**
     * Allows to (temporarily) suppress tooltips, e.g. by providing the user with a button that sets this global variable to false
     * @type Boolean
     */
	var tt_Enabled = true;

    /**
     * false or true - if true, the script is capable of converting HTML elements to tooltips
     * @type Boolean
     */
	var TagsToTip = true;

    /**
     * false or true - tooltip above mousepointer?
     * @type Boolean
     */
	config. Above = false;

    /**
     * Background color
     * @type String
     */
	config. BgColor = ( engine.cookieManager.get("interface") == 'T-Online' ? '#e7e7e7' : '#11a2cf' );

    /**
     * Path to background image, none if empty string ''
     * @type String
     */
	config. BgImg = '';

    /**
     * Border color
     * @type String
     */
	config. BorderColor = ( engine.cookieManager.get("interface") == 'T-Online' ? '#666666' : '#004c79' );

    /**
     * Any permitted CSS value, but I recommend 'solid', 'dotted' or 'dashed'
     * @type String
     */
	config. BorderStyle = 'solid';

    /**
     * Border width
     * @type Number
     */
	config. BorderWidth = 1;

    /**
     * false or true - center the tip horizontally below (or above) the mousepointer
     * @type Boolean
     */
	config. CenterMouse = false;

    /**
     * false or true - close tooltip if the user clicks somewhere
     * @type Boolean
     */
	config. ClickClose = false;

    /**
     * false or true - closebutton in titlebar
     * @type Boolean
     */
	config. CloseBtn = false;

    /**
     * [Background, text, hovered background, hovered text] - use empty strings '' to inherit title colors
     * @type Array
     */
	config. CloseBtnColors = ['#990000', '#FFFFFF', '#DD3333', '#FFFFFF'];

    /**
     * Close button text (may also be an image tag)
     * @type String
     */
	config. CloseBtnText = '&nbsp;X&nbsp;';

    /**
     * When converting a HTML element to a tooltip, copy only the element's content, rather than converting the element by its own
     * @type Boolean
     */
	config. CopyContent = true;

    /**
     * Time span in ms until tooltip shows up
     * @type Number
     */
	config. Delay = 400;


/* Ezt majd mindegyikkel végig kell csinálni */
config. Duration		= 0 		// Time span in ms after which the tooltip disappears; 0 for infinite duration
config. FadeIn			= 0 		// Fade-in duration in ms, e.g. 400; 0 for no animation
config. FadeOut 		= 0
config. FadeInterval	= 30		// Duration of each fade step in ms (recommended: 30) - shorter is smoother but causes more CPU-load
config. Fix 			= null		// Fixated position - x- an y-oordinates in brackets, e.g. [210, 480], or null for no fixation
config. FollowMouse		= true		// false or true - tooltip follows the mouse
config. FontColor		= ( engine.cookieManager.get("interface") == 'T-Online' ? '#666666' : '#ffffff' );
config. FontFace		= 'Verdana,Geneva,sans-serif'
config. FontSize		= '8pt' 	// E.g. '9pt' or '12px' - unit is mandatory
config. FontWeight		= 'normal'	// 'normal' or 'bold';
config. Left			= false 	// false or true - tooltip on the left of the mouse
config. OffsetX 		= 14		// Horizontal offset of left-top corner from mousepointer
config. OffsetY 		= 8 		// Vertical offset
config. Opacity 		= 100		// Integer between 0 and 100 - opacity of tooltip in percent
config. Padding 		= 3 		// Spacing between border and content
config. Shadow			= false 	// false or true
config. ShadowColor 	= '#C0C0C0'
config. ShadowWidth 	= 5
config. Sticky			= false 	// Do NOT hide tooltip on mouseout? false or true
config. TextAlign		= 'left'	// 'left', 'right' or 'justify'
config. Title			= ''		// Default title text applied to all tips (no default title: empty string '')
config. TitleAlign		= 'left'	// 'left' or 'right' - text alignment inside the title bar
config. TitleBgColor	= ''		// If empty string '', BorderColor will be used
config. TitleFontColor	= '#ffffff'	// Color of title text - if '', BgColor (of tooltip body) will be used
config. TitleFontFace	= ''		// If '' use FontFace (boldified)
config. TitleFontSize	= ''		// If '' use FontSize
config. Width			= 250 		// Tooltip width; 0 for automatic adaption to tooltip content

    /**
     * Container DIV, outer title & body DIVs, inner title & body TDs,
     * closebutton SPAN, shadow DIVs, and IFRAME to cover windowed elements in IE
     * @type Array
     */
	var tt_aElt = new Array(10);

    /**
     * Caches and enumerates config data for currently active tooltip
     * @type Array
     */
	var tt_aV = new Array();

    /**
     * Inner tooltip text or HTML
     * @type String
     */
	var tt_sContent;

	var tt_scrlX = 0, tt_scrlY = 0;

	var tt_musX, tt_musY;
	
	var tt_over;

    /**
     * Position, width and height of currently displayed tooltip
     * @type Number
     */
	var tt_x, tt_y, tt_w, tt_h;

    /**
     * ToolTip
     */
	this.Tip = function() {
		tt_Tip( arguments, null );
	}

    /**
     * Convert HTML element to tooltip
     */
	this.TagToTip = function() {
		if( TagsToTip ) {
			var t2t = $( arguments[0] );
			if( t2t )
				tt_Tip( arguments, t2t );
		}
	}

	function tt_Extension() {
		tt_ExtCmdEnum();
		tt_aExt[tt_aExt.length] = this;
		return this;
	}

    /**
     * Set ToolTip position
     */
	function tt_SetTipPos( x, y ) {
		var css = tt_aElt[0].style;
	
		tt_x = x;
		tt_y = y;
		css.left = x + "px";
		css.top = y + "px";
		if( tt_ie56 ) {
			var ifrm = tt_aElt[tt_aElt.length - 1];
			if( ifrm ) {
				ifrm.style.left = css.left;
				ifrm.style.top = css.top;
			}
		}
	}

    /**
     * Hide ToolTip
     */
	this.tt_Hide = function() {
		tt_Hide();
	}

	function tt_Hide() {
		if( tt_db && tt_iState ) {
			if( tt_iState & 0x2 ) {
				tt_aElt[0].style.visibility = "hidden";
				tt_ExtCallFncs(0, "Hide");
			}
			tt_tShow.EndTimer();
			tt_tHide.EndTimer();
			tt_tDurt.EndTimer();
			tt_tFade.EndTimer();
			if( !tt_op && !tt_ie ) {
				tt_tWaitMov.EndTimer();
				tt_bWait = false;
			}
			if( tt_aV[CLICKCLOSE] )
				tt_RemEvtFnc( document, "mouseup", tt_HideInit );
			tt_AddRemOutFnc( false );
			tt_ExtCallFncs( 0, "Kill" );
			// In case of a TagToTip tooltip, hide converted DOM node and
			// re-insert it into document
			if(tt_t2t && !tt_aV[COPYCONTENT]) {
				tt_t2t.style.display = "none";
				tt_MovDomNode(tt_t2t, tt_aElt[6], tt_t2tDad);
			}
			tt_iState = 0;
			tt_over = null;
			tt_ResetMainDiv();
			if(tt_aElt[tt_aElt.length - 1])
				tt_aElt[tt_aElt.length - 1].style.display = "none";
		}
	}

    /**
     * get Div width
     */
	function tt_GetDivW( el ) {
		return( el ? ( el.offsetWidth || el.style.pixelWidth || 0 ) : 0 );
	}

    /**
     * get Div height
     */
	function tt_GetDivH( el ) {
		return( el ? ( el.offsetHeight || el.style.pixelHeight || 0 ) : 0 );
	}

    /**
     * get scroll x
     */
	function tt_GetScrollX() {
		return( window.pageXOffset || ( tt_db ? ( tt_db.scrollLeft || 0 ) : 0 ) );
	}

    /**
     * get scroll y
     */
	function tt_GetScrollY() {
		return( window.pageYOffset || ( tt_db ? ( tt_db.scrollTop || 0 ) : 0 ) );
	}

    /**
     * get client width
     */
	function tt_GetClientW() {
		return( document.body && ( typeof( document.body.clientWidth ) != tt_u ) ? document.body.clientWidth
				: ( typeof( window.innerWidth ) != tt_u ) ? window.innerWidth
				: tt_db ? ( tt_db.clientWidth || 0 )
				: 0 );
	}

    /**
     * get client height
     */
	function tt_GetClientH() {
		return( document.body && ( typeof( document.body.clientHeight ) != tt_u ) ? document.body.clientHeight
				: ( typeof( window.innerHeight ) != tt_u ) ? window.innerHeight
				: tt_db ? ( tt_db.clientHeight || 0 )
				: 0 );
	}

    /**
     * get event x
     */
	function tt_GetEvtX( e ) {
		return ( e ? ( ( typeof( e.pageX ) != tt_u ) ? e.pageX : ( e.clientX + tt_scrlX ) ) : 0 );
	}

    /**
     * get event y
     */
	function tt_GetEvtY(e) {
		return ( e ? ( ( typeof( e.pageY ) != tt_u ) ? e.pageY : ( e.clientY + tt_scrlY ) ) : 0 );
	}

    /**
     * add event
     */
	function tt_AddEvtFnc( el, sEvt, PFnc ) {
		if( el ) {
			if( el.addEventListener )
				el.addEventListener( sEvt, PFnc, false );
			else
				el.attachEvent( "on" + sEvt, PFnc );
		}
	}

    /**
     * remove event
     */
	function tt_RemEvtFnc( el, sEvt, PFnc ) {
		if( el ) {
			if( el.removeEventListener )
				el.removeEventListener( sEvt, PFnc, false );
			else
				el.detachEvent( "on" + sEvt, PFnc );
		}
	}

    /**
     * Array of extension objects
     * @type Array
     */
	var tt_aExt = new Array();

    /**
     * Browser flags
     */
	var tt_db, tt_op, tt_ie, tt_ie56, tt_bBoxOld;

	var tt_body;

    /**
     * Opacity support: 1=IE, 2=Khtml, 3=KHTML, 4=Moz, 5=W3C
     * @type Number
     */
	var tt_flagOpa;

    /**
     * Maximum x and y position
     */
	var tt_maxPosX, tt_maxPosY;

    /**
     * Tooltip active |= 1, shown |= 2, move with mouse |= 4
     * @type Number
     */
	var tt_iState = 0;

    /**
     * Currently applied opacity
     */
	var tt_opa;

    /**
     * Tip above mouse (or ABOVE tip below mouse)
     */
	var tt_bJmpVert;

    /**
     * Tag converted to tip, and its parent element in the document
     */
	var tt_t2t, tt_t2tDad;

    /**
     * The tag from which Opera has removed the href attribute
     */
	var tt_elDeHref;

    /**
     * Timer
     * @type Number
     */
	var tt_tShow = new Number(0), tt_tHide = new Number(0), tt_tDurt = new Number(0),
		tt_tFade = new Number(0), tt_tWaitMov = new Number(0);

    /**
     * Timer
     * @type Boolean
     */
	var tt_bWait = false;

	var tt_u = "undefined";

    /**
     * initialize ToolTip
     */
	function tt_Init() {
		tt_MkCmdEnum();
		// Send old browsers instantly to hell :-)
		if( !tt_Browser() || !tt_MkMainDiv() )
			return;
		tt_IsW3cBox();
		tt_OpaSupport();
		tt_AddEvtFnc( document, "mousemove", tt_Move );
		// In Debug mode we search for TagToTip() calls in order to notify
		// the user if they've forgotten to set the TagsToTip config flag
		if( TagsToTip || tt_Debug )
			tt_SetOnloadFnc();
		tt_AddEvtFnc( window, "scroll",
			function() {
				tt_scrlX = tt_GetScrollX();
				tt_scrlY = tt_GetScrollY();
				if(tt_iState && !( tt_aV[STICKY] && ( tt_iState & 2 ) ) )
					tt_HideInit();
			} );
		// Ensure the tip be hidden when the page unloads
		tt_AddEvtFnc( window, "unload", tt_Hide );
		tt_Hide();
	}

    /**
     * Creates command names by translating config variable names to upper case
     */
	function tt_MkCmdEnum() {
		var n = 0;
		for( var i in config )
			eval( "window." + i.toString().toUpperCase() + " = " + n++ );
		tt_aV.length = n;
	}

    /**
     * Browser check
     */
	function tt_Browser() {
		var n, nv, n6, w3c;
	
		n = navigator.userAgent.toLowerCase(),
		nv = navigator.appVersion;
		tt_op = ( document.defaultView && typeof( eval( "w" + "indow" + "." + "o" + "p" + "er" + "a" ) ) != tt_u );
		tt_ie = n.indexOf( "msie" ) != -1 && document.all && !tt_op;
		if( tt_ie ) {
			var ieOld = ( !document.compatMode || document.compatMode == "BackCompat" );
			tt_db = !ieOld ? document.documentElement : ( document.body || null );
			if( tt_db )
				tt_ie56 = parseFloat( nv.substring( nv.indexOf( "MSIE" ) + 5 ) ) >= 5.5
						&& typeof document.body.style.maxHeight == tt_u;
		} else {
			tt_db = document.documentElement || document.body ||
					( document.getElementsByTagName ? document.getElementsByTagName( "body" )[0]
					: null );
			if( !tt_op ) {
				n6 = document.defaultView && typeof document.defaultView.getComputedStyle != tt_u;
				w3c = !n6 && document.getElementById;
			}
		}
		tt_body = ( document.getElementsByTagName ? document.getElementsByTagName( "body" )[0]
					: ( document.body || null ) );
		if( tt_ie || n6 || tt_op || w3c ) {
			if(tt_body && tt_db) {
				if( document.attachEvent || document.addEventListener )
					return true;
			} else
				tt_Err( "tooltip.js must be included INSIDE the body section,"
						+ " immediately after the opening <body> tag." );
		}
		tt_db = null;
		return false;
	}

    /**
     * Make main Div
     */
	function tt_MkMainDiv() {
		// Create the tooltip DIV
		if( tt_body.insertAdjacentHTML )
			tt_body.insertAdjacentHTML( "afterBegin", tt_MkMainDivHtm() );
		else if( typeof tt_body.innerHTML != tt_u && document.createElement && tt_body.appendChild )
			tt_body.appendChild( tt_MkMainDivDom() );
		// FireFox Alzheimer bug
/*		
		if( window.tt_GetMainDivRefs && tt_GetMainDivRefs() )
			return true;
*/
		if( tt_GetMainDivRefs() )
			return true;
		tt_db = null;
		return false;
	}

    /**
     * Make main Div Html
     */
	function tt_MkMainDivHtm() {
		return( '<div id="WzTtDiV"></div>' +
				( tt_ie56 ? ('<iframe id="WzTtIfRm" src="javascript:false" scrolling="no" frameborder="0" style="filter:Alpha(opacity=0);position:absolute;top:0px;left:0px;display:none;"></iframe>' )
				: '' ) );
	}

    /**
     * Make main Div Dom
     */
	function tt_MkMainDivDom() {
		var el = document.createElement( "div" );
		if( el )
			el.id = "WzTtDiV";
		return el;
	}

    /**
     * Get main Div references
     */
	function tt_GetMainDivRefs() {
		tt_aElt[0] = $( "WzTtDiV" );
		if( tt_ie56 && tt_aElt[0] ) {
			tt_aElt[tt_aElt.length - 1] = $( "WzTtIfRm" );
			if( !tt_aElt[tt_aElt.length - 1] )
				tt_aElt[0] = null;
		}
		if( tt_aElt[0] ) {
			var css = tt_aElt[0].style;
	
			css.visibility = "hidden";
			css.position = "absolute";
			css.overflow = "hidden";
			return true;
		}
		return false;
	}

    /**
     * Reset main Div
     */
	function tt_ResetMainDiv() {
		var w = ( window.screen && screen.width ) ? screen.width : 10000;
	
		tt_SetTipPos( -w, 0 );
		tt_aElt[0].innerHTML = "";
		tt_aElt[0].style.width = ( w - 1 ) + "px";
	}


	function tt_IsW3cBox() {
		var css = tt_aElt[0].style;
	
		css.padding = "10px";
		css.width = "40px";
		tt_bBoxOld = ( tt_GetDivW( tt_aElt[0] ) == 40 );
		css.padding = "0px";
		tt_ResetMainDiv();
	}


	function tt_OpaSupport() {
		var css = tt_body.style;
	
		tt_flagOpa = ( typeof( css.filter ) != tt_u ) ? 1
					: ( typeof( css.KhtmlOpacity ) != tt_u ) ? 2
					: ( typeof( css.KHTMLOpacity ) != tt_u ) ? 3
					: ( typeof( css.MozOpacity ) != tt_u ) ? 4
					: ( typeof( css.opacity ) != tt_u ) ? 5
					: 0;
	}


	function tt_SetOnloadFnc() {
		tt_AddEvtFnc( document, "DOMContentLoaded", tt_HideSrcTags );
		tt_AddEvtFnc( window, "load", tt_HideSrcTags );
		if( tt_body.attachEvent )
			tt_body.attachEvent( "onreadystatechange",
				function() {
					if( tt_body.readyState == "complete" )
						tt_HideSrcTags();
				} );
		if(/WebKit|KHTML/i.test( navigator.userAgent ) )
		{
			var t = setInterval( function() {
						if(/loaded|complete/.test( document.readyState ) )
						{
							clearInterval( t );
							tt_HideSrcTags();
						}
					}, 10 );
		}
	}


	function tt_HideSrcTags() {
		if( !window.tt_HideSrcTags || window.tt_HideSrcTags.done )
			return;
		window.tt_HideSrcTags.done = true;
		if( !tt_HideSrcTagsRecurs( tt_body ) )
			tt_Err( "To enable the capability to convert HTML elements to tooltips,"
					+ " you must set TagsToTip in the global tooltip configuration"
					+ " to true." );
	}


	function tt_HideSrcTagsRecurs( dad ) {
		var a, ovr, asT2t;
	
		// Walk the DOM tree for tags that have an onmouseover attribute
		// containing a TagToTip('...') call.
		// (.childNodes first since .children is bugous in Safari)
		a = dad.childNodes || dad.children || null;
		for( var i = a ? a.length : 0; i; )
		{--i;
			if( !tt_HideSrcTagsRecurs( a[i] ) )
				return false;
			ovr = a[i].getAttribute ? a[i].getAttribute( "onmouseover" )
					: ( typeof a[i].onmouseover == "function" ) ? a[i].onmouseover
					: null;
			if( ovr ) {
				asT2t = ovr.toString().match(/TagToTip\s*\(\s*'[^'.]+'\s*[\),]/);
				if( asT2t && asT2t.length ) {
					if( !tt_HideSrcTag(asT2t[0] ) )
						return false;
				}
			}
		}
		return true;
	}


	function tt_HideSrcTag( sT2t ) {
		var id, el;
	
		// The ID passed to the found TagToTip() call identifies an HTML element
		// to be converted to a tooltip, so hide that element
		id = sT2t.replace(/.+'([^'.]+)'.+/, "$1");
		el = $( id );
		if( el ) {
			if( tt_Debug && !TagsToTip )
				return false;
			else
				el.style.display = "none";
		} else
			tt_Err( "Invalid ID\n'" + id + "'\npassed to TagToTip()."
					+ " There exists no HTML element with that ID." );
		return true;
	}


	function tt_Tip( arg, t2t ) {
		if( !tt_db )
			return;
		if( tt_iState )
			tt_Hide();
		if( !tt_Enabled )
			return;
		tt_t2t = t2t;
		if( !tt_ReadCmds( arg ) )
			return;
		tt_iState = 0x1 | 0x4;
		tt_AdaptConfig1();
		tt_MkTipContent( arg );
		tt_MkTipSubDivs();
		tt_FormatTip();
		tt_bJmpVert = false;
		tt_maxPosX = tt_GetClientW() + tt_scrlX - tt_w - 1;
		tt_maxPosY = tt_GetClientH() + tt_scrlY - tt_h - 1;
		tt_AdaptConfig2();
		// We must fake the first mousemove in order to ensure the tip
		// be immediately shown and positioned
		tt_Move();
		tt_ShowInit();
	}


	function tt_ReadCmds( a ) {
		var i;
	
		// First load the global config values, to initialize also values
		// for which no command has been passed
		i = 0;
		for( var j in config )
			tt_aV[i++] = config[j];
		// Then replace each cached config value for which a command has been
		// passed (ensure the # of command args plus value args be even)
		if( a.length & 1 ) {
			for(i = a.length - 1; i > 0; i -= 2)
				tt_aV[a[i - 1]] = a[i];
			return true;
		}
		tt_Err( "Incorrect call of Tip() or TagToTip().\n"
				+ "Each command must be followed by a value." );
		return false;
	}


	function tt_AdaptConfig1() {
		tt_ExtCallFncs( 0, "LoadConfig" );
		// Inherit unspecified title formattings from body
		if( !tt_aV[TITLEBGCOLOR].length )
			tt_aV[TITLEBGCOLOR] = tt_aV[BORDERCOLOR];
		if( !tt_aV[TITLEFONTCOLOR].length )
			tt_aV[TITLEFONTCOLOR] = tt_aV[BGCOLOR];
		if( !tt_aV[TITLEFONTFACE].length )
			tt_aV[TITLEFONTFACE] = tt_aV[FONTFACE];
		if( !tt_aV[TITLEFONTSIZE].length )
			tt_aV[TITLEFONTSIZE] = tt_aV[FONTSIZE];
		if( tt_aV[CLOSEBTN] ) {
			// Use title colors for non-specified closebutton colors
			if( !tt_aV[CLOSEBTNCOLORS] )
				tt_aV[CLOSEBTNCOLORS] = new Array( "", "", "", "" );
			for(var i = 4; i;)
			{--i;
				if( !tt_aV[CLOSEBTNCOLORS][i].length )
					tt_aV[CLOSEBTNCOLORS][i] = ( i & 1 ) ? tt_aV[TITLEFONTCOLOR] : tt_aV[TITLEBGCOLOR];
			}
			// Enforce titlebar be shown
			if( !tt_aV[TITLE].length )
				tt_aV[TITLE] = " ";
		}
		// Circumvents broken display of images and fade-in flicker in Geckos < 1.8
		if( tt_aV[OPACITY] == 100 && typeof tt_aElt[0].style.MozOpacity != tt_u && !Array.every )
			tt_aV[OPACITY] = 99;
		// Smartly shorten the delay for fade-in tooltips
		if( tt_aV[FADEIN] && tt_flagOpa && tt_aV[DELAY] > 100 )
			tt_aV[DELAY] = Math.max( tt_aV[DELAY] - tt_aV[FADEIN], 100 );
	}


	function tt_AdaptConfig2() {
		if( tt_aV[CENTERMOUSE] )
			tt_aV[OFFSETX] -= ( ( tt_w - ( tt_aV[SHADOW] ? tt_aV[SHADOWWIDTH] : 0 ) ) >> 1 );
	}

    /**
     * Expose content globally so extensions can modify it
     */
	function tt_MkTipContent(a) {
		if( tt_t2t ) {
			if( tt_aV[COPYCONTENT] )
				tt_sContent = tt_t2t.innerHTML;
			else
				tt_sContent = "";
		} else
			tt_sContent = a[0];
		tt_ExtCallFncs( 0, "CreateContentString" );
	}


	function tt_MkTipSubDivs() {
		var sCss = 'position:relative;margin:0px;padding:0px;border-width:0px;left:0px;top:0px;line-height:normal;width:auto;',
		sTbTrTd = ' cellspacing=0 cellpadding=0 border=0 style="' + sCss + '"><tbody style="' + sCss + '"><tr><td ';
	
		tt_aElt[0].innerHTML =
			( ''
			+ ( tt_aV[TITLE].length ?
				( '<div id="WzTiTl" style="position:relative;z-index:1;">'
				+ '<table id="WzTiTlTb"' + sTbTrTd + 'id="WzTiTlI" style="' + sCss + '">'
				+ tt_aV[TITLE]
				+ '</td>'
				+ ( tt_aV[CLOSEBTN] ?
					( '<td align="right" style="' + sCss
					+ 'text-align:right;">'
					+ '<span id="WzClOsE" style="padding-left:2px;padding-right:2px;'
					+ 'cursor:' + ( tt_ie ? 'hand' : 'pointer' )
					+ ';" onmouseover="tt_OnCloseBtnOver(1)" onmouseout="tt_OnCloseBtnOver(0)" onclick="tt_HideInit()">'
					+ tt_aV[CLOSEBTNTEXT]
					+ '</span></td>')
					: '' )
				+ '</tr></tbody></table></div>' )
				: '' )
			+ '<div id="WzBoDy" style="position:relative;z-index:0;">'
			+ '<table' + sTbTrTd + 'id="WzBoDyI" style="' + sCss + '">'
			+ tt_sContent
			+ '</td></tr></tbody></table></div>'
			+ ( tt_aV[SHADOW]
				? ( '<div id="WzTtShDwR" style="position:absolute;overflow:hidden;"></div>'
					+ '<div id="WzTtShDwB" style="position:relative;overflow:hidden;"></div>' )
				: '' )
			);
		tt_GetSubDivRefs();
		// Convert DOM node to tip
		if( tt_t2t && !tt_aV[COPYCONTENT] ) {
			// Store the tag's parent element so we can restore that DOM branch
			// once the tooltip is hidden
			tt_t2tDad = tt_t2t.parentNode || tt_t2t.parentElement || tt_t2t.offsetParent || null;
			if( tt_t2tDad ) {
				tt_MovDomNode( tt_t2t, tt_t2tDad, tt_aElt[6] );
				tt_t2t.style.display = "block";
			}
		}
		tt_ExtCallFncs( 0, "SubDivsCreated" );
	}


	function tt_GetSubDivRefs() {
		var aId = new Array( "WzTiTl", "WzTiTlTb", "WzTiTlI", "WzClOsE", "WzBoDy", "WzBoDyI", "WzTtShDwB", "WzTtShDwR" );
	
		for( var i = aId.length; i; --i )
			tt_aElt[i] = $(aId[i - 1]);
	}

	function tt_FormatTip() {
		var css, w, iOffY, iOffSh;
	
		//--------- Title DIV ----------
		if( tt_aV[TITLE].length ) {
			css = tt_aElt[1].style;
			css.background = tt_aV[TITLEBGCOLOR];
			css.paddingTop = ( tt_aV[CLOSEBTN] ? 2 : 0 ) + "px";
			css.paddingBottom = "1px";
			css.paddingLeft = css.paddingRight = tt_aV[PADDING] + "px";
			css = tt_aElt[3].style;
			css.color = tt_aV[TITLEFONTCOLOR];
			css.fontFamily = tt_aV[TITLEFONTFACE];
			css.fontSize = tt_aV[TITLEFONTSIZE];
			css.fontWeight = "bold";
			css.textAlign = tt_aV[TITLEALIGN];
			// Close button DIV
			if( tt_aElt[4] ) {
				css.paddingRight = ( tt_aV[PADDING] << 1 ) + "px";
				css = tt_aElt[4].style;
				css.background = tt_aV[CLOSEBTNCOLORS][0];
				css.color = tt_aV[CLOSEBTNCOLORS][1];
				css.fontFamily = tt_aV[TITLEFONTFACE];
				css.fontSize = tt_aV[TITLEFONTSIZE];
				css.fontWeight = "bold";
			}
			if( tt_aV[WIDTH] > 0 )
				tt_w = tt_aV[WIDTH] + ( ( tt_aV[PADDING] + tt_aV[BORDERWIDTH] ) << 1 );
			else {
				tt_w = tt_GetDivW( tt_aElt[3] ) + tt_GetDivW( tt_aElt[4] );
				// Some spacing between title DIV and closebutton
				if( tt_aElt[4] )
					tt_w += tt_aV[PADDING];
			}
			// Ensure the top border of the body DIV be covered by the title DIV
			iOffY = -tt_aV[BORDERWIDTH];
		} else {
			tt_w = 0;
			iOffY = 0;
		}
	
		//-------- Body DIV ------------
		css = tt_aElt[5].style;
		css.top = iOffY + "px";
		if( tt_aV[BORDERWIDTH] ) {
			css.borderColor = tt_aV[BORDERCOLOR];
			css.borderStyle = tt_aV[BORDERSTYLE];
			css.borderWidth = tt_aV[BORDERWIDTH] + "px";
		}
		if( tt_aV[BGCOLOR].length )
			css.background = tt_aV[BGCOLOR];
		if( tt_aV[BGIMG].length )
			css.backgroundImage = "url(" + tt_aV[BGIMG] + ")";
		css.padding = tt_aV[PADDING] + "px";
		css.textAlign = tt_aV[TEXTALIGN];
		// TD inside body DIV
		css = tt_aElt[6].style;
		css.color = tt_aV[FONTCOLOR];
		css.fontFamily = tt_aV[FONTFACE];
		css.fontSize = tt_aV[FONTSIZE];
		css.fontWeight = tt_aV[FONTWEIGHT];
		css.background = "";
		css.textAlign = tt_aV[TEXTALIGN];
		if( tt_aV[WIDTH] > 0 )
			w = tt_aV[WIDTH] + ( ( tt_aV[PADDING] + tt_aV[BORDERWIDTH] ) << 1 );
		else
			// We measure the width of the body's inner TD, because some browsers
			// expand the width of the container and outer body DIV to 100%
			w = tt_GetDivW( tt_aElt[6]) + ( ( tt_aV[PADDING] + tt_aV[BORDERWIDTH] ) << 1 );
		if( w > tt_w )
			tt_w = w;
	
		//--------- Shadow DIVs ------------
		if( tt_aV[SHADOW] ) {
			tt_w += tt_aV[SHADOWWIDTH];
			iOffSh = Math.floor( ( tt_aV[SHADOWWIDTH] * 4 ) / 3 );
			// Bottom shadow
			css = tt_aElt[7].style;
			css.top = iOffY + "px";
			css.left = iOffSh + "px";
			css.width = ( tt_w - iOffSh - tt_aV[SHADOWWIDTH] ) + "px";
			css.height = tt_aV[SHADOWWIDTH] + "px";
			css.background = tt_aV[SHADOWCOLOR];
			// Right shadow
			css = tt_aElt[8].style;
			css.top = iOffSh + "px";
			css.left = ( tt_w - tt_aV[SHADOWWIDTH] ) + "px";
			css.width = tt_aV[SHADOWWIDTH] + "px";
			css.background = tt_aV[SHADOWCOLOR];
		} else
			iOffSh = 0;
	
		//-------- Container DIV -------
		tt_SetTipOpa( tt_aV[FADEIN] ? 0 : tt_aV[OPACITY] );
		tt_FixSize( iOffY, iOffSh );
	}


    /**
     * Fixate the size so it can't dynamically change while the tooltip is moving.
     */
	function tt_FixSize( iOffY, iOffSh ) {
		var wIn, wOut, i;
	
		tt_aElt[0].style.width = tt_w + "px";
		tt_aElt[0].style.pixelWidth = tt_w;
		wOut = tt_w - ( ( tt_aV[SHADOW] ) ? tt_aV[SHADOWWIDTH] : 0 );
		// Body
		wIn = wOut;
		if( !tt_bBoxOld )
			wIn -= ( ( tt_aV[PADDING] + tt_aV[BORDERWIDTH] ) << 1 );
		tt_aElt[5].style.width = wIn + "px";
		// Title
		if( tt_aElt[1] ) {
			wIn = wOut - ( tt_aV[PADDING] << 1 );
			if( !tt_bBoxOld )
				wOut = wIn;
			tt_aElt[1].style.width = wOut + "px";
			tt_aElt[2].style.width = wIn + "px";
		}
		tt_h = tt_GetDivH( tt_aElt[0] ) + iOffY;
		// Right shadow
		if( tt_aElt[8] )
			tt_aElt[8].style.height = ( tt_h - iOffSh ) + "px";
		i = tt_aElt.length - 1;
		if( tt_aElt[i] ) {
			tt_aElt[i].style.width = tt_w + "px";
			tt_aElt[i].style.height = tt_h + "px";
		}
	}


	function tt_DeAlt( el ) {
		var aKid;
	
		if( el.alt )
			el.alt = "";
		if( el.title )
			el.title = "";
		aKid = el.childNodes || el.children || null;
		if( aKid ) {
			for( var i = aKid.length; i; )
				tt_DeAlt( aKid[--i] );
		}
	}


	function tt_OpDeHref( el ) {
		// This hack removes the annoying native tooltips over links in Opera
		if( !tt_op )
			return;
		if( tt_elDeHref )
			tt_OpReHref();
		while( el ) {
			if( el.hasAttribute( "href" ) ) {
				el.t_href = el.getAttribute( "href" );
				el.t_stats = window.status;
				el.removeAttribute( "href" );
				el.style.cursor = "hand";
				tt_AddEvtFnc( el, "mousedown", tt_OpReHref );
				window.status = el.t_href;
				tt_elDeHref = el;
				break;
			}
			el = el.parentElement;
		}
	}


	function tt_ShowInit() {
		tt_tShow.Timer( "engine.tooltip.tt_Show()", tt_aV[DELAY], true );
		if( tt_aV[CLICKCLOSE] )
			tt_AddEvtFnc( document, "mouseup", tt_HideInit );
	}
	
	
	function tt_OverInit( e ) {
		tt_over = e.target || e.srcElement;
		tt_DeAlt( tt_over );
		tt_OpDeHref( tt_over );
		tt_AddRemOutFnc( true );
	}

    /**
     * Show the ToolTip
     */
	this.tt_Show = function() {
		var css = tt_aElt[0].style;
	
		// Override the z-index of the topmost wz_dragdrop.js D&D item
		css.zIndex = Math.max( ( window.dd && dd.z ) ? ( dd.z + 2 ) : 0, 1010);
		if( tt_aV[STICKY] || !tt_aV[FOLLOWMOUSE] )
			tt_iState &= ~0x4;
		if( tt_aV[DURATION] > 0 )
			tt_tDurt.Timer( "tt_HideInit()", tt_aV[DURATION], true );
		tt_ExtCallFncs( 0, "Show" )
		css.visibility = "visible";
		tt_iState |= 0x2;
		if( tt_aV[FADEIN] )
			tt_Fade( 0, 0, tt_aV[OPACITY], Math.round(tt_aV[FADEIN] / tt_aV[FADEINTERVAL] ) );
		tt_ShowIfrm();
	}


	function tt_ShowIfrm() {
		if( tt_ie56 ) {
			var ifrm = tt_aElt[tt_aElt.length - 1];
			if( ifrm ) {
				var css = ifrm.style;
				css.zIndex = tt_aElt[0].style.zIndex - 1;
				css.display = "block";
			}
		}
	}


	function tt_Move( e ) {
		e = window.event || e;
		if( e ) {
			tt_musX = tt_GetEvtX( e );
			tt_musY = tt_GetEvtY( e );
		}
		if( tt_iState ) {
			if( !tt_over && e )
				tt_OverInit( e );
			if( tt_iState & 0x4 ) {
				// Protect some browsers against jam of mousemove events
				/*
				if( !tt_op && !tt_ie ) {
					if( tt_bWait )
						return;
					tt_bWait = true;
					tt_tWaitMov.Timer( "tt_bWait = false;", 1, true );
				}
				*/
				if( tt_aV[FIX] ) {
					tt_iState &= ~0x4;
					tt_SetTipPos(tt_aV[FIX][0], tt_aV[FIX][1]);
				} else if( !tt_ExtCallFncs( e, "MoveBefore" ) )
					tt_SetTipPos( tt_PosX(), tt_PosY() );
				tt_ExtCallFncs( [tt_musX, tt_musY], "MoveAfter" )
			}
		}
	}


	function tt_PosX() {
		var x;
	
		x = tt_musX;
		if( tt_aV[LEFT] )
			x -= tt_w + tt_aV[OFFSETX] - ( tt_aV[SHADOW] ? tt_aV[SHADOWWIDTH] : 0 );
		else
			x += tt_aV[OFFSETX];
		// Prevent tip from extending past right/left clientarea boundary
		if( x > tt_maxPosX )
			x = tt_maxPosX;
		return( ( x < tt_scrlX) ? tt_scrlX : x );
	}


	function tt_PosY() {
		var y;
	
		// Apply some hysteresis after the tip has snapped to the other side of the
		// mouse. In case of insufficient space above and below the mouse, we place
		// the tip below.
		if( tt_aV[ABOVE] && ( !tt_bJmpVert || tt_CalcPosYAbove() >= tt_scrlY + 16 ) )
			y = tt_DoPosYAbove();
		else if( !tt_aV[ABOVE] && tt_bJmpVert && tt_CalcPosYBelow() > tt_maxPosY - 16 )
			y = tt_DoPosYAbove();
		else
			y = tt_DoPosYBelow();
		// Snap to other side of mouse if tip would extend past window boundary
		if( y > tt_maxPosY )
			y = tt_DoPosYAbove();
		if( y < tt_scrlY )
			y = tt_DoPosYBelow();
		return y;
	}


	function tt_DoPosYBelow() {
		tt_bJmpVert = tt_aV[ABOVE];
		return tt_CalcPosYBelow();
	}
	
	
	function tt_DoPosYAbove() {
		tt_bJmpVert = !tt_aV[ABOVE];
		return tt_CalcPosYAbove();
	}
	
	
	function tt_CalcPosYBelow() {
		return( tt_musY + tt_aV[OFFSETY] );
	}


	function tt_CalcPosYAbove() {
		var dy = tt_aV[OFFSETY] - ( tt_aV[SHADOW] ? tt_aV[SHADOWWIDTH] : 0 );
		if( tt_aV[OFFSETY] > 0 && dy <= 0 )
			dy = 1;
		return( tt_musY - tt_h - dy );
	}


	function tt_OnOut() {
		tt_AddRemOutFnc( false );
		if( !( tt_aV[STICKY] && ( tt_iState & 0x2 ) ) )
			tt_HideInit();
	}


	function tt_HideInit() {
		tt_ExtCallFncs( 0, "HideInit" );
		tt_iState &= ~0x4;
		if( tt_flagOpa && tt_aV[FADEOUT] ) {
			tt_tFade.EndTimer();
			if( tt_opa ) {
				var n = Math.round( tt_aV[FADEOUT] / ( tt_aV[FADEINTERVAL] * ( tt_aV[OPACITY] / tt_opa ) ) );
				tt_Fade( tt_opa, tt_opa, 0, n );
				return;
			}
		}
		tt_tHide.Timer( "engine.tooltip.tt_Hide();", 1, false );
	}


	function tt_OpReHref() {
		if( tt_elDeHref ) {
			tt_elDeHref.setAttribute( "href", tt_elDeHref.t_href );
			tt_RemEvtFnc( tt_elDeHref, "mousedown", tt_OpReHref );
			window.status = tt_elDeHref.t_stats;
			tt_elDeHref = null;
		}
	}


	function tt_Fade( a, now, z, n ) {
		if( n ) {
			now += Math.round( ( z - now ) / n );
			if( ( z > a ) ? ( now >= z ) : ( now <= z ) )
				now = z;
			else
				tt_tFade.Timer( "tt_Fade("
								+ a + "," + now + "," + z + "," + ( n - 1 )
								+ ")",
								tt_aV[FADEINTERVAL],
								true );
		}
		now ? tt_SetTipOpa( now ) : tt_Hide();
	}


	function tt_SetTipOpa( opa ) {
	// To circumvent the opacity nesting flaws of IE, we set the opacity
	// for each sub-DIV separately, rather than for the container DIV.
		tt_SetOpa( tt_aElt[5].style, opa );
		if( tt_aElt[1] )
			tt_SetOpa( tt_aElt[1].style, opa );
		if( tt_aV[SHADOW] ) {
			opa = Math.round(opa * 0.8);
			tt_SetOpa( tt_aElt[7].style, opa );
			tt_SetOpa( tt_aElt[8].style, opa );
		}
	}


	function tt_OnCloseBtnOver( iOver ) {
		var css = tt_aElt[4].style;
	
		iOver <<= 1;
		css.background = tt_aV[CLOSEBTNCOLORS][iOver];
		css.color = tt_aV[CLOSEBTNCOLORS][iOver + 1];
	}


	function tt_Int( x ) {
		var y;
	
		return( isNaN(y = parseInt( x ) ) ? 0 : y );
	}


	function tt_AddRemOutFnc( bAdd ) {
	// Adds or removes the document.mousemove or HoveredElem.mouseout handler
	// conveniently. Keeps track of those handlers to prevent them from being
	// set or removed redundantly.
		var PSet = bAdd ? tt_AddEvtFnc : tt_RemEvtFnc;
	
		if( bAdd != tt_AddRemOutFnc.bOn ) {
			PSet( tt_over, "mouseout", tt_OnOut );
			tt_AddRemOutFnc.bOn = bAdd;
			if( !bAdd )
				tt_OpReHref();
		}
	}


	tt_AddRemOutFnc.bOn = false;
	Number.prototype.Timer = function( s, iT, bUrge ) {
		if( !this.value || bUrge )
			this.value = window.setTimeout( s, iT );
	}


	Number.prototype.EndTimer = function() {
		if( this.value ) {
			window.clearTimeout( this.value );
			this.value = 0;
		}
	}


	function tt_SetOpa( css, opa ) {
		tt_opa = opa;
		if( tt_flagOpa == 1 ) {
			// Hack for bugs of IE:
			// A DIV cannot be made visible in a single step if an opacity < 100
			// has been applied while the DIV was hidden.
			// Moreover, in IE6, applying an opacity < 100 has no effect if the
			// concerned element has no layout (position, size, zoom, ...).
			if( opa < 100 ) {
				var bVis = css.visibility != "hidden";
				css.zoom = "100%";
				if( !bVis )
					css.visibility = "visible";
				css.filter = "alpha(opacity=" + opa + ")";
				if( !bVis )
					css.visibility = "hidden";
			} else
				css.filter = "";
		} else {
			opa /= 100.0;
			switch( tt_flagOpa ) {
			case 2:
				css.KhtmlOpacity = opa; break;
			case 3:
				css.KHTMLOpacity = opa; break;
			case 4:
				css.MozOpacity = opa; break;
			case 5:
				css.opacity = opa; break;
			}
		}
	}


	function tt_MovDomNode( el, dadFrom, dadTo ) {
		if( dadFrom )
			dadFrom.removeChild( el );
		if( dadTo )
			dadTo.appendChild( el );
	}


	function tt_Err( sErr ) {
		if( tt_Debug )
			alert( "Tooltip Script Error Message:\n\n" + sErr );
	}


	function tt_ExtCmdEnum() {
		var s;
	
		// Add new command(s) to the commands enum
		for( var i in config ) {
			s = "window." + i.toString().toUpperCase();
			if( eval( "typeof(" + s + ") == tt_u" ) ) {
				eval( s + " = " + tt_aV.length );
				tt_aV[tt_aV.length] = null;
			}
		}
	}


	function tt_ExtCallFncs( arg, sFnc ) {
		var b = false;
		for( var i = tt_aExt.length; i; )
		{--i;
			var fnc = tt_aExt[i]["On" + sFnc];
			// Call the method the extension has defined for this event
			if( fnc && fnc( arg ) )
				b = true;
		}
		return b;
	}

	tt_Init();
}
/**
 * Gate of communication/command between JavaScript and the server.
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function CommGate() {
	
	/**
	 * Path to PHP processor
	 * Set by config.js
	 * @type String
	 */
	//CommGate.URL = "engine/php/main1_5.php";
	
	/**
	 * Random seed to prevent browser caching
	 * @type Number
	 */
	var randomSeed = Math.floor(Math.random() * (10001));
	
	/**
	 * Pointer to this
	 * @type CommGate
	 */
	var self = this;
	
	/**
	 * Encodes special characters
	 * @param String Text to encode
	 * @return Encoded text
	 * @type String
	 */
	function encodeSpecialChars(text) {
		if (! check(text)) {
			return "";
		}
		
		text = new String(text);
		
	    //Convert double apostrophe
	    text = text.replace(/"/g, "*#22*");
		
		//Convert single apostrophes 
		text = text.replace(/'/g, "*#27*");
		text = text.replace(/`/g, "*#27*");
		text = text.replace(/´/g, "*#27*");
		text = text.replace(/‘/g, "*#27*");
		text = text.replace(/’/g, "*#27*");
		text = text.replace(/,/g, "*#2c*");
		text = text.replace(/\{/g, "*#7b*");
		text = text.replace(/\}/g, "*#7d*");
		text = text.replace(/\[/g, "*#5b*");
		text = text.replace(/\]/g, "*#5d*");
		text = text.replace(/\n/g, "*#0a*");
		text = text.replace(/\t/g, "*#09*");
		text = text.replace(/\\/g, "*#5c*");
	    
	    return text;
	}
	
	/**
	 * Decodes special characters
	 * @param String Text to decode
	 * @return Decoded text
	 * @type String
	 */
	function decodeSpecialChars(text) {
	    if (! check(text)) {
			return "";
		}
		
		text = new String(text);
		
	    text = text.replace(/\*#28\*/g, "(");
	    text = text.replace(/\*#29\*/g, ")");
	    text = text.replace(/\*#5b\*/g, "[");
		text = text.replace(/\*#5d\*/g, "]");
	    text = text.replace(/\*#0a\*/g, "\r");
	    text = text.replace(/\*#22\*/g, "\"");
	    text = text.replace(/\*#27\*/g, "'");
	    text = text.replace(/\*#2c\*/g, ",");
	    text = text.replace(/\*#7b\*/g, "{");
	    text = text.replace(/\*#7d\*/g, "}");
	    text = text.replace(/\*#09\*/g, "\t");
	    text = text.replace(/\*\#\*/g, " ");
	    text = text.replace(/\*#5c\*/g, "\\");
	    text = text.replace(/\*#3b\*/g, ";");
	    text = text.replace(/\*#0d\*/g, "\n");
	    
	    return text;
	}
	
	/**
	 * Encodes command or command array.
	 * @param mixed Command or command array
	 * @throws When commandArray is null
	 * @return Encoded command or command array
	 * @type mixed
	 */
	function encodeCommandArray(commandArray) {
		if (typeof(commandArray) == "undefined") {
			throw new Error("CommGate.encodeCommandArray(): Invalid parameters.");
		}
		
		if (commandArray instanceof Array) {
			for (var i = 0; i < commandArray.length; i++) {
				commandArray[i] = encodeCommandArray(commandArray[i]);
			}
			
			return commandArray;
		} else {
			return encodeSpecialChars(commandArray);
		}
	}

	/**
	 * Decodes command or command array.
	 * @param mixed Command or command array
	 * @throws When commandArray is null
	 * @return Decoded command or command array
	 * @type mixed
	 */
	function decodeCommandArray(commandArray) {
		if (typeof(commandArray) == "undefined") {
			throw new Error("CommGate.decodeCommandArray(): Invalid parameters.");
		}
		
		if (commandArray instanceof Array) {
			for (var i = 0; i < commandArray.length; i++) {
				commandArray[i] = decodeCommandArray(commandArray[i]);
			}
			
			return commandArray;
		} else {
			return decodeSpecialChars(commandArray);
		}
	}
	
	/**
	 * Packs commands into a command cube
	 * @param Array Command array
	 * @throws When commands is null
	 * @throws When commands is not an array
	 * @throws When commands is an empty array
	 * @throws When one of the commands is not an CommGateRequest
	 * @return Command cube
	 * @type Array
	 */
	function packCommandArray(commands) {
		if (! checkType(commands, Array) || commands.length == 0) {
			throw new Error("CommGate.packCommandArray(): Invalid parameters.");
		}
		
		var cube = new Array(); //command cube
		cube[0] = new Array(); //command level of the cube
		var dataLevel;
		
		for (var i = 0; i < commands.length; i++) {
			//check it
			if (! checkType(commands[i], CommGateRequest)) {
				throw new Error("CommGate.packCommandArray(): Invalid parameters.");
			}
			
			//add command level
			cube[0].push([i].concat(commands[i].getCommandLine()));
			
			//add data level
			dataLevel = commands[i].getDataLevel();
			for (var j = 0; j < dataLevel.length; j++) {
				cube.push(dataLevel[j]);
			}
		}
		
		return cube;
	}
	
	/**
	 * Unpacks command cube into a command array
	 * @param Array Command cube
	 * @throws When cube is null
	 * @throws When cube is not an array
	 * @return Command array
	 * @type Array
	 */
	function unpackCommandArray(cube) {
		if (! checkType(cube, Array) || cube.length == 0) {
			throw new Error("CommGate.unpackCommandArray(): Invalid parameters.");
		}
		
		var commands = new Array();
		
		for (var i = 0; i < cube[0].length; i++) {
			var command = cube[0][i];
			
			var commandId = command[0];
			var commandCommand = command[1];
			var commandData = null;
			
			if (commandCommand == "RES_DATA" && check(command[2]) && check(cube[command[2]])) {
				commandData = cube[command[2]];
			}
			
			if (commands[commandId] == undefined) {
				commands[commandId] = new Array();
			}
			
			commands[commandId].push(new CommGateResponse(command, commandData));
		}
		
		return commands;
	}
	
	/**
	 * Called when response has been received 
	 * @param Array Request command array
	 * @param Array Response command array
	 */
	function receive(request, response) {
		for (var i = 0; i < request.length; i++) {
			var callback = request[i].getCallback();
			
			if (typeof(callback) == "function" && response[i]) {
				try {
					callback(response[i]);
				} catch(e) {
					//TODO: Log
				}
			}
		}
	}
	
	/**
	 * Sends command request through the gate.
	 * @param Array Array containing CommGateRequests
	 * @throws When commands is null
	 * @throws When commands is not an Array
	 * @throws When commands array is empty
	 * @throws When one of the commands is not a CommGateRequest
	 * @throws When XMLHttpRequest object cannot be created.
	 * @throws When request cannot be sent
	 */
	this.send = function(commands) {
        glLog.fireBugLog("log", "CommGate.js", "send()", "1");
		if (! checkType(commands, Array) || commands.length == 0) {
            glLog.fireBugLog("log", "CommGate.js", "send()", "Error: invalid parameters 1");
			throw new Error("CommGate.send(): Invalid parameters.");
		}
		
		for (var i = 0; i < commands.length; i++) {
			if (! checkType(commands[i], CommGateRequest)) {
            	glLog.fireBugLog("log", "CommGate.js", "send()", "Error: invalid parameters 2");
				throw new Error("CommGate.send(): Invalid parameters.");
			}
		}

        glLog.fireBugLog("log", "CommGate.js", "send()", "2");
		var xmlHttpRequest = createXmlHttpRequest();
        glLog.fireBugLog("log", "CommGate.js", "send()", "3");

		xmlHttpRequest.open("POST", CommGate.URL, true);
		xmlHttpRequest.onreadystatechange = function() {
			if (xmlHttpRequest.readyState == 4) {
				if (xmlHttpRequest.status != 200) {
                       glLog.fireBugLog("log", "CommGate.js", "send()", "Error: status != 200");
				} else {
					try {
        				glLog.fireBugLog("log", "CommGate.js", "send()", "receiving response");
						receive(commands, unpackCommandArray(decodeCommandArray(eval(xmlHttpRequest.responseText))));
        				glLog.fireBugLog("log", "CommGate.js", "send()", "received response");	
					} catch(e) {
						alert( e.message);
						//TODO: Log
					}
				}
			}
		}
		
        glLog.fireBugLog("log", "CommGate.js", "send()", "Sending request.");
		xmlHttpRequest.send(encodeCommandArray(packCommandArray(commands)).serialize());
        glLog.fireBugLog("log", "CommGate.js", "send()", "Request sent.");
	}
	
	/**
	 * Sends command request with the leading parameterized HAVE_SESSION command through the gate.
	 * @param Array Array containing CommGateRequests
	 * @throws When commands is null
	 * @throws When commands is not an Array
	 * @throws When commands array is empty
	 * @throws When one of the commands is not a CommGateRequest
	 * @throws When XMLHttpRequest object cannot be created.
	 * @throws When request cannot be sent
	 */
	this.sendWithSession = function(commands) {
		if (! checkType(commands, Array) || commands.length == 0) {
			throw new Error("CommGate.send(): Invalid parameters.");
		}
		
		return self.send([ new CommGateRequest("HAVE_SESSION", [ esuli.user.getSessionId() ], null) ].concat(commands));
	}
	
	/**
	 * Sends command request through the gate and returns the response.
	 * @param Array Array containing CommGateRequests
	 * @throws When commands is null
	 * @throws When commands is not an Array
	 * @throws When commands array is empty
	 * @throws When one of the commands is not a CommGateRequest
	 * @throws When XMLHttpRequest object cannot be created.
	 * @throws When request cannot be sent
	 * @return Command response
	 * @type Array
	 */
	this.get = function(commands) {
		if (! checkType(commands, Array) || commands.length == 0) {
			throw new Error("CommGate.get(): Invalid parameters.");
		}
		
		for (var i = 0; i < commands.length; i++) {
			if (! checkType(commands[i], CommGateRequest)) {
				throw new Error("CommGate.get(): Invalid parameters.");
			}
		}
		
		var xmlHttpRequest = createXmlHttpRequest();
		xmlHttpRequest.open("POST", CommGate.URL, false);
		xmlHttpRequest.send(encodeCommandArray(packCommandArray(commands)).serialize());
		
		if (xmlHttpRequest.status != 200) {
			throw new Error("CommGate.get(): Orbital error, page not found.");
		}
		
		return unpackCommandArray(decodeCommandArray(eval(xmlHttpRequest.responseText)));
	}
	
	/**
	 * Sends command request with the leading parameterized HAVE_SESSION command through the gate and returns the response.
	 * @param Array Array containing CommGateRequests
	 * @throws When commands is null
	 * @throws When commands is not an Array
	 * @throws When commands array is empty
	 * @throws When one of the commands is not a CommGateRequest
	 * @throws When XMLHttpRequest object cannot be created.
	 * @throws When request cannot be sent
	 * @return Command response
	 * @type Array
	 */
	this.getWithSession = function(commands) {
		if (! checkType(commands, Array) || commands.length == 0) {
			throw new Error("CommGate.getWithSession(): Invalid parameters.");
		}
		
		return self.get([ new CommGateRequest("HAVE_SESSION", [ esuli.user.getSessionId() ], null) ].concat(commands));
	}
	
	/**
	 * Returns a file content by a given URL
	 * @param String URL of file
	 * @throws When URL is null
	 * @throws When XMLHttpRequest object cannot be created.
	 * @return File content
	 * @type String
	 */
	this.getStringByUrl = function(url) {
		if (! check(url) || url.length == 0) {
			throw new Error("CommGate.getStringByUrl(): Invalid parameters.");
		}
		
		var xmlHttpRequest = createXmlHttpRequest();
		xmlHttpRequest.open('GET', url + "?random=" + randomSeed, false);
		xmlHttpRequest.send(null);
		
		if (xmlHttpRequest.status != 200) {
			//TODO: Log error
			return;
		}
		
		return xmlHttpRequest.responseText;
	}
	
	/**
	 * Creates and returns a new XMLHttpRequest object
	 * @throws When XMLHttpRequest object cannot be created.
	 * @return XMLHttpRequest object
	 * @type XMLHttpRequest
	 */
	function createXmlHttpRequest() {
		if (window.XMLHttpRequest) {
        	glLog.fireBugLog("log", "CommGate.js", "createXmlHttpRequest()", "Firefox, XMLHttpRequest");
			var xmlHttpRequest = new XMLHttpRequest ();
		} else if (window.ActiveXObject) {
			try {
        		glLog.fireBugLog("log", "CommGate.js", "createXmlHttpRequest()", "Msxml2.XMLHTTP");
				var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
			} catch(e) {
				try {
        			glLog.fireBugLog("log", "CommGate.js", "createXmlHttpRequest()", "Microsoft.XMLHTTP");
					var xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");
				} catch (e) { }
			}
		}
		
		if (! xmlHttpRequest) {
        	glLog.fireBugLog("log", "CommGate.js", "createXmlHttpRequest()", "Error:  Couldn't create XMLHttpRequest object.");
			throw new Error("CommGate.createXmlHttpRequest(): Couldn't create XMLHttpRequest object.");
		}
		
		return xmlHttpRequest;
	}
	
}
/**
 * Command class for CommGate request
 * @constructor
 * @param String Command
 * @param Array Command line parameters
 * @param Function Callback function
 * @author Horvath 'Koko' Kornel
 */
function CommGateRequest(command, params, requestCallback) {
	
	/**
	 * Callback function
	 * @type Function
	 */
	var callback;
	
	/**
	 * Command
	 * @type String
	 */
	var commandLine;
	
	/**
	 * Data
	 * @type Array
	 */
	var dataLevel;

    /**
     * InternalData
     * @type Array
     */
    var internalData = new Array();
	
	/**
	 * Sets callback function
	 * @param Function Callback function
	 */
	this.setCallback = function(requestCallback) {
		callback = requestCallback;
	}
	
	/**
	 * Returns callback function
	 * @return Callback function
	 * @type Function
	 */
	this.getCallback = function() {
		return callback;
	}
	
	/**
	 * Sets the command
	 * @param String Command
	 * @param Array Command line parameters
	 */
	this.setCommand = function(command, params) {
		commandLine = (params instanceof Array ? [String(command)].concat(params) : [String(command)]);
	}
	
	/**
	 * Returns created command line
	 * @return Command line
	 * @type Array
	 */
	this.getCommandLine = function() {
		return commandLine;
	}
	
	/**
	 * Adds a new data level to the request
	 * @param Array New data level to add
	 */
	this.addDataLevel = function(data) {
		if (data != null && data != undefined && data instanceof Array) {
			dataLevel.push(data);
		}
	}
	
	/**
	 * Returns data level
	 * @return Data level
	 * @type Array
	 */
	this.getDataLevel = function() {
		return dataLevel;
	}
	
	//Initialize
	if (command && params && requestCallback) {
		commandLine = (params instanceof Array ? [command].concat(params) : [command]);
		callback = requestCallback;
	} else if (command && params) {
		commandLine = (params instanceof Array ? [command].concat(params) : [command]);
	}
	
	dataLevel = new Array();
	
}
/**
 * Command class for CommGate response.
 * @constructor
 * @param Array Command line array
 * @param Array Data array
 * @author Horvath 'Koko' Kornel
 */
function CommGateResponse(command, data) {
	
	/**
	 * Command line
	 * @type Array
	 */
	var commandLine = command;
	
	/**
	 * Data level
	 * @type Array
	 */
	var dataLevel = data || null;
	
	/**
	 * Returns command line
	 * @return Command line
	 * @type Array
	 */
	this.getCommandLine = function() {
		return commandLine;
	}
	
	/**
	 * Returns data level as it is
	 * @return Data level as it is
	 * @type Array
	 */
	this.getDataAsArray = function() {
		return dataLevel;
	}
	
	/**
     * Converts JSON data matrix to an array of objects with the properties of column names.
     * Example: 
     * dataLevel = [
     *   ["EMAIL", "NAME", "ROLE"],
     *   ["koko@steery.com", "Koko", "Master"],
     *   ["johnny@steery.com", "Johnny", "SubMaster"]
     * ];
     *
     * return = [
     *   {email: "koko@steery.com", name: "Koko", role: "Master"},
     *   {email: "johnny@steery.com", name: "Johnny", role: SubMaster}
     * ];
     *
     * @returns Converted array
     * @type Array
     */
    this.getDataAsObjectArray = function() {
		var ret = new Array();
		var obj;
		
		for (var i = 1; i < dataLevel.length; i++) {
		    obj = new Object();
		    
		    for (var col = 0; col < dataLevel[i].length; col++) {
		        obj[dataLevel[0][col].toLowerCase()] = dataLevel[i][col];
		    }
		    
		    ret.push(obj);
		}
		
		return ret;
    }
	
}
/**
 * Represents an element in the dialog queue
 * @param String Message
 * @param String Type
 * @param Array Callbacks
 * @param Array Captions
 */
function Dialog(dialogMessage, dialogType, dialogCallbacks, dialogCaptions) {
	
	/**
	 * Message
	 * @type String
	 */
	var message;
	
	/**
	 * Type
	 * @type Number
	 */
	var type;
	
	/**
	 * Callbacks
	 * @type Array
	 */
	var callbacks;
	
	/**
	 * Captions
	 * @type Array
	 */
	var captions;
	
	/**
	 * OK constant for captions and callbacks
	 * @type Number
	 */
	Dialog.OK = 0;
	
	/**
	 * YES constant for captions and callbacks
	 * @type Number
	 */
	Dialog.YES = 1;
	
	/**
	 * NO constant for captions and callbacks
	 * @type Number
	 */
	Dialog.NO = 2;
	
	/**
	 * Returns message
	 * @return Message
	 * @type String
	 */
	this.getMessage = function() {
		return message;
	}
	
	/**
	 * Sets message
	 * @param String Message
	 */
	this.setMessage = function(dialogMessage) {
		if (! dialogMessage) {
			//TODO: Log error
			return;
		}
		
		message = String(dialogMessage);
	}
	
	/**
	 * Returns type
	 * @return Type
	 * @type Number
	 */
	this.getType = function() {
		return type;
	}
	
	/**
	 * Sets type
	 * @param Number Type
	 */
	this.setType = function(dialogType) {
		if (! dialogType) {
			//TODO: Log error
			return;
		}
		
		type = Number(dialogType);
	}
	
	/**
	 * Returns the requested callback
	 * @param Number Which callback
	 * @return Requested callback
	 * @type String
	 */
	this.getCallback = function(callbackType) {
		//az összes callback állítása esetén ez nem tömb, ezért ezzel csak az x karaktert adja vissza,
		//mivel String tömbként kezeli, így ez vizsgálni és kezelni kell
		//return callbacks[Number(callbackType)];
		if( callbacks instanceof Array )
			return callbacks[Number(callbackType)];	
		else
			return callbacks;
	}
	
	/**
	 * Sets the given callback
	 * @param Number Which callback
	 * @param Function Callback function
	 */
	this.setCallback = function(callbackType, dialogCallback) {
		if (! callbackType || ! dialogCallback) {
			//TODO: Log error
			return;
		}
		
		callbacks[Number(callbackType)] = dialogCallback;
	}
	
	/**
	 * Sets all callbacks
	 * @param Array Callback array
	 */
	this.setCallbacks = function(dialogCallbacks) {
		if (! dialogCallbacks || ! dialogCallbacks instanceof Array) {
			//TODO: Log error
			return;
		}
		
		callbacks = dialogCallbacks;
	}
	
	/**
	 * Returns the requested caption
	 * @param Number Which caption
	 * @return Requested caption
	 * @type String
	 */
	this.getCaption = function(captionType) {
		return captions[Number(captionType)];
	}
	
	/**
	 * Sets the given caption
	 * @param Number Which caption
	 * @param String Caption
	 */
	this.setCaption = function(captionType, dialogCaption) {
		if (! captionType || ! dialogCaption) {
			//TODO: Log error
			return;
		}
		
		captions[Number(captionType)] = String(dialogCaption);
	}
	
	/**
	 * Sets all captions
	 * @param Array Captions array
	 */
	this.setCaptions = function(dialogCaptions) {
		if (! dialogCaptions || ! dialogCaptions instanceof Array) {
			//TODO: Log error
			return;
		}
		
		captions = dialogCaptions;
	}
	
	//Initialize
	message = dialogMessage || "";
	type = dialogType || "";
	callbacks = dialogCallbacks || [null, null, null];
	captions = dialogCaptions || ["Ok", "Igen", "Nem"];
	
}
/**
 * Dialog window manager class.
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function DialogManager() {
	
	/**
	 * DialogBox width size
	 * @type integer
	 */
	var width = 500;
	
	/**
	 * DialogBox height size
	 * @type integer
	 */
	var height = 350;

	/**
	 * Array of disabled selects
	 * @type Array
	 */
	var disabledSelects;
	
	/**
	 * Queue array
	 * @type Array
	 */
	var queue;
	
	/**
	 * Running state
	 * @type Boolean
	 */
	var running;
	
	/**
	 * Adds a new task
	 * @param Dialog Dialog to add
	 */
	this.add = function(dialog) {
		//when this is a progress or there's no progress in the queue
		queue.push(dialog);
		//return when already displaying or there's nothing to display
		if (running) {
			return;
		}
		
		//start showing
		this.running = true;
	    
	    //disable active selects
		var allSelects = document.getElementsByTagName("select");
		for (i = 0; i < allSelects.length; i++) {
    		if (allSelects[i].disabled == false) {
    			disabledSelects[i] = allSelects[i];
    			disabledSelects[i].disabled = true;
    		}
			allSelects[i].style.visibility = 'hidden';
    	}
	    
	    //hider div
	    var pageSize = getPageSize();
	    setOpacity( $("DialogBackground"), 0.3 );
	    $("DialogBackground").style.height = pageSize.pageHeight+'px';
	    $("DialogBackground").style.display = "block";
	    
	    //dialog box
	    getWindow( height, width );
	    
	    //start showing
	    show();
	}
	
	/**
	 * Shows a task
	 */
	function show() {
		try {
			window.scrollBy(0, 0);
		    engine.templateManager.processTemplate("dialog_" + queue[0].getType(), { dialog: queue[0] }, "Content");
		} catch(e) {
			//TODO: Log error
		}
	}
	
	/**
	 * One task ended
	 * @param Number Result code
	 */
	this.done = function(result) {
		if (queue.length == 0 || result == null || result == undefined) {
			//TODO: Log error
			return;
		}
		
		var fn = queue[0].getCallback(result);
		if (typeof(fn) == "function") {
			try {
				fn();
			} catch(e) {
				//TODO: Log error
			}
		}
	    //remove first element
	    queue.shift();
	    //when this was the last one in queue
	    if (queue.length == 0) {
	    	running = false;
	    	
			//hide dialog and bakground
			$("DialogBackground").style.display = "none";
			$("DialogBox").style.display = "none";
			$("Content").innerHTML = "";
			//enable all disabled selects and clear the array holding them
	    	for (var i = 0; i < disabledSelects.length; i++) {
		    	disabledSelects[i].disabled = false;
				disabledSelects[i].style.visibility = 'visible';
	    	}
	    	
	    	disabledSelects = new Array();
			
		    return;
	    }
	    show();
	}
	
	/**
	 *
	 */
	this.showBackground = function() {
		var pageSize = getPageSize();
	    setOpacity( $("DialogBackground"), 0.3 );
	    $("DialogBackground").style.height = pageSize.pageHeight + 'px';
	    $("DialogBackground").style.display = "block";
		return;
	}
	
	/**
	 *
	 */
	this.hideBackground = function() {
		$("DialogBackground").style.display = "none";
		return;
	}
	
	/**
	* set DialogBackground style
	* @param htmlObject 
	* @param opacity value
	*/
	function setOpacity(element, value) {
	    if (typeof element == 'string')
		element= $(element);
	    if (value == 1) {
		element.style.opacity = (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0 ;
		if(/MSIE/.test(navigator.userAgent) && !window.opera)
		    element.style.filter = element.style.filter.replace(/alpha\([^\)]*\)/gi,'');
	    } else {
		if(value < 0.00001) value = 0;
		    element.style.opacity = value;
		if(/MSIE/.test(navigator.userAgent) && !window.opera)
		    element.style.filter = element.style.filter.replace(/alpha\([^\)]*\)/gi,'') + 'alpha(opacity='+value*100+')';
	    }
	    return element;
	}
	
	
	/**
	* set DialogBox style and position
	* @param box height
	* @param box width
	*/
	function getWindow(height, width) {
	    var DialogBox = $("DialogBox");
	    var pageSize = getPageSize();
	    var pos = realOffset(document.body);
	    
	    DialogBox.style.top = (pageSize.windowHeight/2 - height/2 + pos[1])+'px';
	    DialogBox.style.left = (pageSize.windowWidth/2 - width/2 + pos[0])+'px';
	    
	    DialogBox.style.display = "block";
	}
	
	/**
	* set DialogBox real position
	* @return top, left size
	* @type Array
	*/
	function realOffset(element) {
	    var valueT = 0, valueL = 0;
	    do {
		valueT += element.scrollTop  || 0;
		valueL += element.scrollLeft || 0;
		element = element.parentNode;
	    } while (element);
	    return [valueL, valueT];
	}
	
	
	/**
	* get page, widow, scroll height and width size 
	* @return size data
	* @type object
	*/
	function getPageSize() {
	    var xScroll, yScroll;
            if (window.innerHeight && window.scrollMaxY) {
		xScroll = document.body.scrollWidth;
		yScroll = window.innerHeight + window.scrollMaxY;
	    } else if (document.body.scrollHeight > document.body.offsetHeight) {
		xScroll = document.body.scrollWidth;
		yScroll = document.body.scrollHeight;
	    } else {
		xScroll = document.body.offsetWidth;
		yScroll = document.body.offsetHeight;
	    }
	    
	    var windowWidth, windowHeight;
	    if (self.innerHeight) {
		windowWidth = self.innerWidth;
		windowHeight = self.innerHeight;
	    } else if (document.documentElement && document.documentElement.clientHeight) {
		windowWidth = document.documentElement.clientWidth;
		windowHeight = document.documentElement.clientHeight;
	    } else if (document.body) {
		windowWidth = document.body.clientWidth;
		windowHeight = document.body.clientHeight;
	    }
	    
	    if(yScroll < windowHeight) {
		pageHeight = windowHeight;
	    } else {
		pageHeight = yScroll;
	    }
            if(xScroll < windowWidth) {
	        pageWidth = windowWidth;
	    } else {
		pageWidth = xScroll;
	    }
	    return {
		'pageWidth':pageWidth,
		'pageHeight':pageHeight,
		'windowWidth':windowWidth,
		'windowHeight':windowHeight,
		'yScroll':yScroll,
		'xScroll':xScroll
	    }
	}
	
	//Initialize
	disabledSelects = new Array();
	queue = new Array();
	running = false;
	
}
/**
 * Event class for EventManager
 * @constructor
 * @param Object Event invoker
 * @param String Event type
 * @author Horvath 'Koko' Kornel
 */
function Event(eventInvoker, eventType, eventData) {
	
	/**
	 * Type of event
	 * @type string
	 */
	var type;
	
	/**
	 * Invoker of event
	 * @type Object
	 */
	var invoker;
	
	/**
	 * Data of event
	 * @type Map
	 */
	var data;
	
	/**
	 * Pointer to this
	 * @type Event
	 */
	var self = this;
	
	/**
	 * Returns the type of the event
	 * @return The type of the event
	 * @type string
	 */
	this.getType = function() {
		return type;
	}
	
	/**
	 * Sets the type of the event
	 * @param String The type of the event
	 */
	this.setType = function(eventType) {
		type = String(eventType);
	}
	
	/**
	 * Returns the invoker of the event
	 * @return The invoker of the event
	 * @type Object
	 */
	this.getInvoker = function() {
		return invoker;
	}
	
	/**
	 * Sets the invoker of the event
	 * @param Object The invoker of the event
	 */
	this.setInvoker = function(eventInvoker) {
		invoker = eventInvoker;
	}
	
	/**
	 * Return event data by key
	 * @param String Key
	 * @return Value
	 * @type mixed
	 */
	this.get = function(key) {
		return data.get(String(key));
	}
	
	/**
	 * Puts event data
	 * @param String Key
	 * @param mixed Value 
	 */
	this.put = function(key, value) {
		data.put(String(key), value)
	}
	
	/**
	 * Returns data map
	 * @return Data map
	 * @type Map
	 */
	this.getData = function() {
		return data;
	}
	
	/**
	 * Sets data map
	 * @param Map Data map
	 */
	this.setData = function(eventData) {
		if (! check(eventData)) {
			return;
		}
		
		if (eventData instanceof Map) {
			data = eventData;
		} else if (typeof(eventData) == "object") {
			data = eventData.toMap();
		}
	}
	
	//Initialize
	type = (check(eventType) ? String(eventType) : "");
	invoker = (check(eventInvoker) ? eventInvoker : null);
	if (check(eventData)) {
		if (eventData instanceof Map) {
			data = eventData;
		} else if (typeof(eventData) == "object") {
			data = eventData.toMap();
		} else {
			data = new Map();
		}
	} else {
		data = new Map();
	}
	
}
/**
 * Manages JavaScript module events.<br/>
 * <br/>
 * Register event listener<br/>
 * engine.eventManager.addListener(EventManager.EVENT_LAYOUT_RELOAD, this);<br/>
 * <br/>
 * Unregister event listener<br/>
 * engine.eventManager.removeListener(EventManager.EVENT_LAYOUT_RELOAD, this);<br/>
 * <br/>
 * Send event<br/>
 * var event = new Event(this, EventManager.EVENT_LAYOUT_RELOAD);<br/>
 * event.put("id", 1);<br/>
 * <br/>
 * engine.eventManager.invoke(event);<br/>
 *<br/>
 * Receive event<br/>
 * this.listenMenuChange = function(event) {<br/>
 *     var invokerOfEvent = event.getInvoker();<br/>
 *     var typeOfEvent = event.getType();<br/>
 *     var id = event.get("id");<br/>
 * }
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function EventManager() {
	
	/**
	 * Listeners array
	 * @type Map
	 */
	var listeners;
	
	/**
	 * Event executor
	 * @type EventExecutor
	 */
	var executor;
	
	/**
	 * NavChange event type constant
	 * @type String
	 */
	EventManager.EVENT_NAV_CHANGE = "NavChange";

	/**
	 * User prelogin event type constant
	 * @type String
	 */
	EventManager.EVENT_USER_PRELOGIN = "UserPrelogin";

	/**
	 * User login event type constant
	 * @type String
	 */
	EventManager.EVENT_USER_LOGIN = "UserLogin";
	
	/**
	 * User profile loaded event type constant
	 * @type String
	 */
	EventManager.EVENT_PROFILE_LOADED = "ProfileLoaded";
	
	/**
	 * UserChange event type constant
	 * @type String
	 */
	EventManager.EVENT_USER_CHANGE = "UserChange";
	
	/**
	 * LayoutReload event type constant
	 * @type String
	 */
	EventManager.EVENT_LAYOUT_RELOAD = "LayoutReload";
	
	/**
	 * Lesson loaded event type constant
	 * @type String
	 */
	EventManager.EVENT_LESSON_LOADED = "LessonLoaded";

    /**
     * Level loaded event type constant
     * @type String
     */
    EventManager.EVENT_LEVEL_LOADED = "LevelLoaded";
	
	/**
	 * Add a listener of given event-type to the list
	 * @param String Type of event to listen for
	 * @param Object Object which wants to listen for the specified event type
	 */
	this.addListener = function(type, listener) {
		if (! listeners.containsKey(type)) {
			listeners.put(type, new Set());
		}
		
		listeners.get(type).add(listener);
	}
	
	/**
	 * Removes a listener of given event-type from the list
	 * @param String Type of event to listen for
	 * @param Object Object to remove
	 */
	this.removeListener = function(type, listener) {
		if (! listeners.containsKey(type)) {
			return;
		}
		
		listeners.get(type).remove(listener);
	}
	
	/**
	 * Invokes an event of the specified type with the data
	 * @param Event Event object
	 */
	this.invoke = function(event) {
		if (! listeners.containsKey(event.getType())) {
			return;
		}
		
		//engine.log.addLog("EventManager.js", "invoke", "INFO", "event: " + event.getType() + " " + event.getData().toObject().serialize() );
		engine.log.fireBugLog('log', 'EventManager.js', 'invoke',  "event: " + event.getType() + " " + event.getData().toObject().serialize() );

		var it = listeners.get(event.getType()).iterator();
		var listener;
		var fn;
		
		while (it.hasNext()) {
			listener = it.next();
			
			if (listener != event.getInvoker()) {
				fn = listener["listen" + event.getType()];
				executor.add(fn, event);
			}
		}
	}
	
	/**
	 * Event executor class. Dispatches event serially in a new thread.
	 * @constructor
	 * @author Horvath 'Koko' Kornel
	 */
	function EventExecutor() {
		
		/**
		 * Array to hold events and listener functions
		 * @type Array
		 */
		var events;
		
		/**
		 * Is already running
		 * @type Boolean
		 */
		var running;
		
		/**
		 * Adds a new event to the executor
		 * @param Function Listener function
		 * @param Event Event to dispatch
		 */
		this.add = function(listener, event) {
			events.push({ listener: listener, event: event});
			//engine.log.fireBugLog('log', 'User.js', 'listenProfileLoaded', 'For event: ' + event + ' ' + ' adding listener: ' + listener);
			if (running == false) {
				running = true;
				setTimeout(process, 1);
			}
		}
		
		/**
		 * Dispatches one event and recalls itself in a new thread when there are processable events
		 */
		function process() {
			var event = events.shift();

			try {
				event.listener(event.event);
			} catch(e) {
				//alert('EventManager process error: ' + e.message );//TODO: Log error
			}
			
			if (events.length > 0) {
				setTimeout(process, 1);
			} else {
				running = false;
			}
		}
		
		//Initialize
		events = new Array();
		running = false;
		
	}
	
	//Initialize
	listeners = new Map();
	executor = new EventExecutor();
	
}
/**
 * Make test
 *
 * @constructor
 *
 * @author CsD
 */		
function CPreTest( pName ){
	/**	 * A példány nevét tároljuk benne.	 *	 * @type string	 */
	this.name = pName;
	
	var NS4 = (document.layers)? 1 : 0;
	var IE4 = (document.all)? 1 : 0;
	var W3C = (document.getElementById)? 1 : 0;
	
	var actualFile = "";
	var actualLine = "";
	var aFile = new Array();
	var resultTest = new Array();
	var aCommand = new Array();
	var waitcount = 0;
	
	/**	 * Hívásával kezdődik a tesztelés, ellenőrzi, hogy van-e forgatókönyv kiválasztva, ha igen
	 * elindítja a teszt futtatását a process függvény hívásával	 */	
	 this.startTest = function ()
	{
		if( aFile.length == 0 )
			alert("Nincs forgatókönyv!");
		else
		{
			this.process(0,0);
			//writeResult();
		}
	}
	
	/**	 * Lefuttatja, az összes forgatókönyv összes parancsát, amennyiben olyan parancshoz ér, amiben
	 * olyan objektumot próbálunk elérni, ami nem elérhető, akkor 2 másodpercenként újra próbálja
	 * 1 percen keresztül, ha ez idő alatt sem elérhető az objektum, akkor a következő utasításra ugrik
	 * 	 * 	 * @param Number megmondja, hányadik file-tól (forgatókönyvtől) folytassa a feldolgozást	 * @param Number megmondja, hogy a forgatókönyv melyik sorától folytassa a feldolgozást	 * 	 */
	this.process = function ( pFileIndex, pLineIndex )
	{
		for( var q = pFileIndex; q < aFile.length; q++)
			{
				//csak akkor kell a parancstömbnek értéket adni, ha a aktuális feldolgozása befejeződött
				if( aCommand.length == 0 || pLineIndex >= aCommand.length )
					aCommand = setCommandArray( aFile[q] );
					
				count = 0;
				
				//a forgatókönyvek első sora csak általános leírás
				if( pLineIndex == 0 )
				{
					actualLine = 1;
					addResult( "--- " + aCommand[0] + " ---" );
					start = 1;
				}
				else
					start = pLineIndex;
				
				for( k = start; k < aCommand.length; k++)
				{
					actualLine = k + 1;
					actaulCommand = getCommand( aCommand[k] );
					
					//ha a feldolgozandó utasításban objektum szerepel, és még nem próbáltuk
					//30-nál többször elérni, akkor teszteljük, hogy létezik-e
					if( actaulCommand[1] != "script" && waitcount < 30 )
					{
						testobj = setObject( actaulCommand[1] );
						if( testobj )
							waitcount = 0;
						else
						{
							waitcount++;
							setTimeout(this.name + ".process(" + q + "," + k + ");", 2000);
							return;
						}
					}
					else if(actaulCommand[1] != "script" && waitcount == 30)
					{
						waitcount = 0;
						addResult( actaulCommand[1] + ": az objektum nem elérhető!" );
						continue;
					}
					
					if( actaulCommand[0] == "fill" )
						res = fillCommand( actaulCommand[1], actaulCommand[2] );
					else if( actaulCommand[0] == "verify" )
						res = verifyCommand( actaulCommand[1], actaulCommand[2], actaulCommand[3] );
					else if( actaulCommand[0] == "do" )
						res = doCommand( actaulCommand[1], actaulCommand[2]);
					else
						res = actaulCommand[0] + ": ismeretlen utasítás"
					
					addResult( res );
				}
				addResult( "---  futtatás vége  ---" );
			}
	}
	
	
	/**	 * a forgatókönyvek soronkénti feldolgozásának eredményeit, egy tárolótömbbe helyezi,
	 * illetve kiírja a tesztelés eredményét tartalmazó frame-be	 * 	 * @param string tartalmazza az aktuális sor futatásának eredményét	 * 	 */
	function addResult( pRes )
	{
		var tmp = new Array( actualFile, actualLine, pRes );
		resultTest.push( tmp );
		
		var obj = setObject( "resultdiv", "result" );
		obj.innerHTML = obj.innerHTML + "<br/>" + actualFile + " :: " + actualLine + " -> " + pRes;
	}
	
	/**	 * a tesztelés eredményeit tartalmazó tömb összes elemét alert-al kiiratja	 */
	function writeResult()
	{
		var sAlert = "Teszt eredménye:";
		for( q = 0; q < resultTest.length; q++)
			sAlert += "\n" + resultTest[q][0] + "::" + resultTest[q][1] + " -> " + resultTest[q][2];
			
		alert( sAlert ); 
	}
	
	/**	 * verify parancs esetén az ellenőrzés végrehajtása, miszerint, adott objektum tartalmazza-e
	 * az adott karakterláncot	 * 	 * @param string a vizsgálni kívánt objektum neve	 * @param string szöveg, amit az objektumnak tartalmaznia kell
	 * @param string amennyiben az objektum nem tartalmazza az adott szöveget, akkor ez a hibaüzen írodik az eredménybe	 * 	 * @returns a verify parancs végrehajtásának eredményét adja vissza	 * @type string	 */
	function verifyCommand( pObjName, pRequired, pWrongText )
	{
		var sReturn = "";
		var obj = setObject( pObjName );
		
		if( obj )
		{
			if( obj.innerHTML != "" )
				sText = new String(obj.innerHTML);
			else
				sText = new String(obj.value);
			
			pos = sText.indexOf( pRequired );
	
			if( pos == -1 )
				sReturn = pWrongText;
			else
				sReturn = "Ellenőrzés rendben";
		}
		else
			sReturn = pObjName + ": az objektum nem létezik a harctéren";
		
		return sReturn;
	}
	
	/**	 * do parancs végrehajtása, miszerint, adott objektum adott eventjenek meghívása, 
	 * vagy script esetén az adott string futtatása eval-al	 * 	 * @param string objektum neve, vagy javascript futtatása esetén "script"	 * @param string objektum esetén, annak egy eventje, script esetén a javascript kód	 * 	 * @returns a do parancs végrehajtásának eredményét adja vissza	 * @type string	 */
	function doCommand( pParam, pWhat )
	{
	try
	{
		var sReturn = "";
		if( pParam == "script" )
		{
			res = pWhat;
			pWhat = "";
			//ha futtatni kívánt javascriptben szerepel a document.getElementById
			//mivel másik frame-be történik a futtatás, ezért elé kell tenni a 
			//fram elérését: parent.esuli.document.......
			pos = res.indexOf( "document.getElementById" );
			while( pos != -1 )
			{
				tmp = res.substring(pos+23);
				pWhat = res.substring(0,pos) + "parent.esuli.document.getElementById";
				res = tmp;
				pos = res.indexOf( "document.getElementById" );
			}
			pWhat += res;
			
			eval("parent.esuli." + pWhat);
			sReturn = "Script lefutott";
		}
		else
		{
			var sEvalText = "";
			if( W3C )
				sEvalText = "parent.esuli.document.getElementById('" + pParam + "')";
			else if( NS4 )
				sEvalText = "parent.esuli.document.layers['" + pParam + "']";
			else
				sEvalText = "parent.esuli.window.opener.document.all['" + pParam + "']";
				
			sEvalText += "." + pWhat + "();";
			
			eval(sEvalText);
			sReturn = "Event lefutott";
		}
		return sReturn;
	}
	catch(e)
	{
		return e.toString();
	}
	}
	
	/**	 * fill parancs végrehajtása, miszerint, adott objektumnak értéket ad	 * 	 * @param string objektum neve, vagy javascript futtatása esetén "script"	 * @param string értéke, amit az objektum kap	 * 	 * @returns a fill parancs végrehajtásának eredményét adja vissza	 * @type string	 */
	function fillCommand( pObjName, pObjValue )
	{
		var sReturn = "";
		var obj = setObject( pObjName );
		if( obj )
		{
			pObjValue = leftTrim(pObjValue);
			obj.value = pObjValue;
			sReturn = "rendben";
		}
		else
			sReturn = pObjName + ": az objektum nem létezik a harctéren";
			
		return sReturn;
	}
	
	function leftTrim(sString)	{		while (sString.substring(0,1) == ' ')		{			sString = sString.substring(1, sString.length);		}		return sString;	}
	
	/**	 * a forgatókönyv adott sorát bontja szét parancsra és paraméterekre	 * 	 * @param string forgatókönyv egy sora, amit szétbont parancsra és paraméterekre	 * 	 * @returns a szétszedett sor részei tömbe rendezve	 * @type Array	 */
	function getCommand( pLine )
	{
		var aReturn = new Array("Hibás parancs", "", "");
		pLine = leftTrim( pLine );
		tmp = pLine.indexOf("(");
		tmp2 = pLine.lastIndexOf(")"); 
		if( tmp != -1 && tmp2 != -1)
		{
			aReturn[0] = pLine.substring( 0, tmp );
			content = leftTrim( pLine.substring( tmp+1, tmp2 ) );
			q = 0;
			while( content.length != 0)
			{
				tmp = content.indexOf(",");
				tmp2 = content.indexOf("'"); 
				if( tmp2 != -1 && tmp2 < tmp )
				{
					tmps1 = content.substring( tmp2 + 1 );
					tmp3 = tmps1.indexOf( "'" );
					tmps2 = tmps1.substring( tmp3 + 1 );
					tmp = tmps2.indexOf(",");
					if( tmp != -1 )
						tmp += tmp2 + tmp3 + 2;
				}
				if( tmp != -1 )
				{
					aReturn[++q] = content.substring( 0, tmp );
					content = content.substring( tmp+1 );
				}
				else
				{
					aReturn[++q] = content;
					content = "";
				}
				tmp3 = aReturn[q].indexOf("'");
				if( tmp3 != -1 )
					aReturn[q] = aReturn[q].substring( tmp3 + 1, aReturn[q].length -1 );
			}
		}
		return aReturn;
	}

	/**	 * forgatókönyv file hozzáadása a feldolgozáshoz, egy tároló tömbe teszi, ha még nincs benne	 * 	 * @param string forgatókönyv file neve	 */
	this.addFile = function ( pFileName )
	{
		var must = true;
		for( q = 0; q < aFile.length; q++ )
		{
			if( pFileName == aFile[q] )
			{
				must = false;
				break;
			}
		}
		
		if( must )
			aFile.push( pFileName );
	}
	
	/**	 * forgatókönyv file törlése a tároló tömbből	 * 	 * @param string forgatókönyv file neve	 */
	this.removeFile = function ( pFileName )
	{
		var must = -1;
		for( q = 0; q < aFile.length; q++ )
		{
			if( pFileName == aFile[q] )
			{
				must = q;
				break;
			}
		}
		
		if( must > -1 )
			aFile.splice( must, 1 );
	}
	
	/**	 * a futtatandó forgatókönyv file-ok listáját gyűjti össze	 * 	 * @returns a fileok listája	 * @type String	 */
	this.getFileList = function ( )
	{
		var sReturn = "A file-ok listája:";
		for( q = 0; q < aFile.length; q++ )
			sReturn += "\n" + aFile[q];
		
		return sReturn;
	}
	
	/**	 * objektum név és frame-beli helyük alapján begyűjti az objektumot
	 *
	 * @param string az objektum neve
	 * @param az objektum melyik frame-ben szerepel	 * 	 * @returns objektum	 * @type Object	 */
	function setObject( pName, pFrame )
	{
	try
	{
		if( pFrame == "result" )
			obj = parent.result.document.getElementById(pName);
		else
		{
			if( W3C )
				obj = parent.esuli.document.getElementById(pName);
			else if( NS4 )
				obj = parent.esuli.document.layers[pName];
			else
				obj = parent.esuli.window.opener.document.all[pName];
		}
		
		return obj;
	}
	catch(e)
	{
		addResult( pName + ": az objektum nem létezik a harctéren" );
		return null;
	}
	}
	
	
	/**	 * a forgatókönyv neve alapján annak tartalmát lekéri, majd tartalmát soronként tömbe szervezi
	 *
	 * @param string forgatókönyv file neve	 * 	 * @returns a forgatókönyv sorait tömbbe rendezve	 * @type Array	 */
	function setCommandArray( pFileName )
	{
		actualFile = pFileName;
		var fileContent = new String(getFileContent ( "test/" + actualFile ) );
		
		return fileContent.split("\n");
	}
	
	/**	 * url alapján egy file tartalmát beolvassa
	 *
	 * @param string url	 * 	 * @returns a file tartalma	 * @type String	 */
	function getFileContent ( url )
	{
    	var req = false;
    	// For Safari, Firefox, and other non-MS browsers
    	if ( window.XMLHttpRequest )
    	{
			try
			{
	    		req = new XMLHttpRequest();
			}
			catch (e)
			{
	    		req = false;
			}
    	}
    	else if ( window.ActiveXObject )
    	{
    		// For Internet Explorer on Windows
			try
			{
	    		req = new ActiveXObject("Msxml2.XMLHTTP");
			}
			catch (e)
			{
	    		try
	    		{
					req = new ActiveXObject("Microsoft.XMLHTTP");
    	    	}
    	    	catch (e)
    	    	{
					req = false;
	    		}
			}
    	}
    	
    	if ( req )
    	{
    		// Synchronous request, wait till we have it all
			req.open('GET', url, false);
        	req.send(null);
        	return req.responseText;
    	}
    	else 
    		return "hiba: nem sikerült a file tartalmát kiolvasni";
	}
}
/**
 * Default parser used to parse template
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
var DefaultParser = {
	
	/**
	 * Object containing statements
	 * @type Object
	 */
	statements: {
		"if":      { delta: 1,  prefix: "if (", suffix: ") {\n", minParams: 1 },
		
		"elseif":  { delta: 0,  prefix: "} else if (", suffix: ") {\n" },
		
		"else":    { delta: 0,  prefix: "} else {\n" },
		
		"/if":     { delta: -1, prefix: "}\n" },
		
		"for":     {
			delta: 1,
			
			prefix: function(parameters) {
				if (parameters[1] != "in") {
					throw new TemplateParseError("Error parsing template " + name + ", loop with bad parameters: " + parameters.join(" ") + ".");
				}
				
				return [
					"if (typeof(_FORS) == \"undefined\" || ! _FORS.length) {\n  var _FORS = [];\n}\n",
					"_FORS.push(0);\n",
					"if (typeof(" + parameters[2] + ") != \"undefined\" && " + parameters[2] + " instanceof Array) {\n",
					"  var " + parameters[0] + "Array = " + parameters[2] + ";\n",
					"  for (var " + parameters[0] + "Iterator = 0; " + parameters[0] + "Iterator < " + parameters[0] + "Array.length; " + parameters[0] + "Iterator++) {\n",
					"    var " + parameters[0] + " = " + parameters[0] + "Array[" + parameters[0] + "Iterator];\n",
					"    _FORS[_FORS.length - 1]++;\n"].join("");
			},
			
			minParams: 3
		},
		
		"forelse": { delta: 0,  prefix: "  }\n}\n if (_FORS[_FORS.length - 1] == 0) {\n  if (true) {\n" },
		
		"/for":    { delta: -1, prefix: "  }\n}\n" },
		
		"eat":     { delta: 1, prefix: "/*\n" },
		
		"/eat":    { delta: -1, prefix: "*/\n" },
		
		"include": {
			delta: 0,
			
			prefix: function(parameters) {
				var templateName = parameters.shift();
				var templateWith = parameters.shift();
				
				if (templateWith != "with") {
					throw new TemplateParseError("Error parsing template " + name + ", include with bad parameters: " + parameters.join(" ") + ".");
				}
				
				return "_OUT.push(engine.templateManager.getTemplate(" + templateName + ").process({ " + parameters.join(" ") + " }));\n";
			},
			
			minParams: 3 }
	},
	
	/**
	 * Object containing modifiers
	 * @type Object
	 */
	modifiers: {
		//Eats the whole string
		"eat":        function(s) { return ""; },
		
		//Upper-cases string
		"upperCase":  function(s) { return String(s).toUpperCase(); },
		
		//Lower-cases string
		"lowerCase":  function(s) { return String(s).toLowerCase(); },
		
		//Return first param if that is not a nullstring, second param else
		"default":    function(s1, s2) { return String(s1).length > 0 ? s1 : s2; },
		
		//Upper-cases first characters of every word
		"capitalize": function(s) {
			var words = String(s).split(" ");
			var capitalized = [];
			
			for (var i = 0; i < words.length; i++) {
				capitalized.push(this["ucFirst"](words[i]));
			}
			
			return capitalized.join(" ");
		},
		
		//Upper-cases first character
		"ucFirst":    function(s) {
			var oldStr = String(s);
			var newStr = String(oldStr[0]).toUpperCase();
			
			for (var i = 1; i < oldStr.length; i++) {
				newStr += oldStr[i];
			}
			
			return newStr;
		},
		
		//Lower-cases first character
		"lcFirst":    function(s) {
			var oldStr = String(s);
			var newStr = String(oldStr[0]).toLowerCase();
			
			for (var i = 0; i < oldStr.length; i++) {
				newStr += oldStr[i];
			}
			
			return newStr;
		},
		
		//Trims whitespaces form the beginning and end of the string
		"trim":       function(s) { return String(s).replace(/^\s+|\s+$/, ''); }
	}
	
}
/**
 * Represents a parsed template
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function Template(templateName, tmpl, templateParser) {
	
	/**
	 * Template source
	 * @type String
	 */
	var source;
	
	/**
	 * Parsed string
	 * @type String
	 */
	var template;
	
	/**
	 * Name of template
	 * @type String
	 */
	var name;
	
	/**
	 * Template parser object
	 * @type Object
	 */
	var parser;
	
	/**
	 * Temp variable to check the number of start/end tags
	 * @type Number
	 */
	var delta;
	
	/**
	 * Parses the whole template and return the parsed and eval'd code
	 * @param String Template to parse
	 * @throws TemplateParseError on template parsing errors
	 * @return Parsed template
	 * @type String
	 */
	function parse(tmpl) {
		tmpl = new String(tmpl);
		
		tmpl = tmpl.replace(/\t/g, "    "); //convert \t to four spaces
		tmpl = tmpl.replace(/\r\n/g, "\n"); //convert windows line delimiters to unix style
		tmpl = tmpl.replace(/\r/g, "\n"); //convert macosx line delimiters to unix style
		
		var actualPos = -1;
		var parsed = ["function evalTmpl(_OUT, _CONTEXT, _MODIFIERS) { with (_CONTEXT) {\n"];
		
		while (actualPos + 1 < tmpl.length) {
			var statementStart = tmpl.indexOf("{", actualPos);
			
			if (statementStart < 0) {
				break;
			}
			
			var statementEnd = tmpl.indexOf("}", statementStart + 1);
			
			if (statementEnd < 0) {
				break;
			}
			
			if (tmpl.charAt(statementStart - 1) == "$") { //expression which will be shown
				parseText(parsed, tmpl.substring(actualPos, statementStart - 1));
				parseExpression(parsed, tmpl.substring(statementStart + 1, statementEnd));
			} else { //statement
				parseText(parsed, tmpl.substring(actualPos, statementStart));
				parseStatement(parsed, tmpl.substring(statementStart + 1, statementEnd));
			}
			
			actualPos = statementEnd + 1;
		}
		
		if (delta != 0) {
			throw new TemplateParseError("Error parsing template " + name + ", tag start/end tags number are not the same.");
		}
		
		//last piece of text
		parseText(parsed, tmpl.substring(actualPos, tmpl.length));
		
		parsed.push("} }");
		
		eval(parsed.join(""));
		
		return evalTmpl;
	}
	
	/**
	 * Parses the text
	 * @param Array Array to push results
	 * @param String Text to parse
	 */
	function parseText(out, text) {
		if (! text && text.length == 0) {
			return "";
		}
		
		var nlPrefix = 0; //index to first non-newline in prefix.
	    var nlSuffix = text.length - 1; //index to first non-space/tab in suffix.
	    
	    while (nlPrefix < text.length && text.charAt(nlPrefix) == "\n") {
	    	nlPrefix++;
	    }
	    
	    while (nlSuffix >= 0 && (text.charAt(nlSuffix) == " " || text.charAt(nlSuffix) == "\t")) {
	    	nlSuffix--;
	    }
	    
	    if (nlSuffix < nlPrefix) {
	    	nlSuffix = nlPrefix;
	    }
	    
	    var lines = text.substring(nlPrefix, nlSuffix + 1).split("\n");
	    
	    for (var i = 0; i < lines.length; i++) {
			out.push("_OUT.push(\"" + lines[i].replace(/"/g, "\\\"") + "\");\n");
			
			if (i < lines.length - 1) {
	            out.push('_OUT.push("\\n");\n');
	        }
		}
	}
	
	/**
	 * Parses the expressions
	 * @param Array Array to push results
	 * @param String Expression to parse
	 * @throws TemplateParseError on template parsing errors
	 */
	function parseExpression(out, expression) {
		if (! expression && expression.length == 0) {
			return "";
		}
		
		var modifiers = expression.split("|");
		expression = modifiers.shift();
		
		var expr = expression;
		var parts;
		var modifier;
		
		for (var i = 0; i < modifiers.length; i++) {
			parts = modifiers[i].split(":");
			modifier = parts.shift();
			
			if (parser.modifiers[modifier] == null) {
				throw new TemplateParseError("Error parsing template " + name + ", no such modifier: " + modifier + ".");
			}
			
			expr = "_MODIFIERS[\"" + modifier + "\"](" + expr + (parts.length > 0 ? ", " + parts[0].replace(/"/g, "\"") : "") + ")";
		}
		
		out.push("_OUT.push(" + expr + ");\n");
	}
	
	/**
	 * Parses the statements
	 * @param Array Array to push results
	 * @param String Statements to parse
	 * @throws TemplateParseError on template parsing errors
	 */
	function parseStatement(out, stmt) {
		if (! stmt && stmt.length == 0) {
			return;
		}
		
		parameters = stmt.split(" ");
		statement = parameters.shift();
		
		statement = parser.statements[statement];
		
		if (statement == null) {
			parseText(out, stmt);
		}
		
		delta += statement.delta;
		
		if (delta < 0) {
			throw new TemplateParseError("Error parsing template " + name + ", fewer start tags then end tags.");
		}
		
		if (statement.minParams != null && statement.minParams > parameters.length) {
			throw new TemplateParseError("Error parsing template " + name + ", too few parameters.");
		}
		
		if (typeof(statement.prefix) == "function") {
			out.push(statement.prefix(parameters));
		} else {
			out.push(statement.prefix);
		}
		
		if (statement.suffix != null) {
			out.push(parameters.join(" "));
			out.push(statement.suffix);
		}
	}
	
	/**
	 * Processes the template with the given context
	 * @param Object Context of template
	 * @throws TemplateProcessError template on processing errors
	 * @return Ready-to-use template
	 * @type String
	 */
	this.process = function(context) {
		if (! context || ! template) {
			return "";
		}
		
		var processed = [];
		
		try {
			template(processed, context, parser.modifiers);
		} catch(e) {
			throw new TemplateProcessError(e.message, e.fileName, e.lineNumber, e.stack);
		}
		
		return processed.join("");
	}
	
	/**
	 * Returns HTML source
	 * @return HTML source
	 * @type String
	 */
	this.getSource = function() {
		return source;
	}
	
	//Initialize
	if (! tmpl || ! templateName || tmpl.length == 0 || templateName.length == 0) {
		return null;
	}
	
	if (templateParser != null) {
		parser = templateParser;
	} else {
		parser = DefaultParser;
	}
	
	name = templateName;
	delta = 0;
	source = new String(tmpl);
	template = parse(tmpl);
	
}
/**
 * Loads and caches templates.
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function TemplateManager() {
	
	/**
	 * Base dir of templates.
	 * Set in config.js
	 * @type String
	 */
	//TemplateManager.URL = "ajax/1_5/templates/";
	
	/**
	 * Map to store templates
	 * @type Map
	 */
	var templates;
	
	/**
	 * Corrects the name of template
	 */
	function correctName(templateName) {
		return String(templateName).toLowerCase();
	}
	
	/**
	 * Returns the template and loads it when necessary
	 * @param String Name of template
	 * @throws On parsing errors
	 * @return Template
	 * @type Template
	 */
	function get(templateName) {
		templateName = correctName(templateName);
		if (! templates.containsKey(templateName)) {
			if (! check(TemplateManager.URL)) {
				//TODO: Log error
				return null;
			}
			
			var templateUrl = TemplateManager.URL + templateName.replace(/_/g, "/") + ".tmpl";
			
			try {
				var templateData = engine.commGate.getStringByUrl(templateUrl);
			} catch (e) {
				throw new TemplateParseError("TemplateHandler.get(): Couldn't read file " + templateUrl + ".");
			}
			templates.put(templateName, new Template(templateName, templateData));
		}
		return templates.get(templateName);
	}
	
	/**
	 * Returns the given template
	 * @param String Name of template
	 * @throws On parsing errors
	 * @return Template
	 * @type Template
	 */
	this.getTemplate = function(templateName) {
		return get(templateName);
	}
	
	/**
	 * Processes the given template with the given context, then puts it into the given DOM object
	 * @param String Name of template
	 * @param Object Template context
	 * @param String Id of DOM object to put the template
	 * @throws On parsing errors
	 */
	this.processTemplate = function(templateName, templateData, domId) {
		$(domId).innerHTML = get(templateName).process(templateData);
	}
	
	//Initialize
	templates = new Map();
	
}
/**
 * Represents a template parsing error.
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function TemplateParseError(message, fileName, lineNumber, stack) {
	
	/**
	 * Message of error
	 * @type String
	 */
	this.message = message;
	
	/**
	 * Name of the file where the error occured
	 * @type String
	 */
	this.fileName = fileName;
	
	/**
	 * Number of line where the error occured
	 * @type String
	 */
	this.lineNumber = lineNumber;
	
	/**
	 * Stact trace of error
	 * @type Object
	 */
	this.stack = stack;
	
	/**
	 * Name of error
	 * @type String
	 */
	this.name = "TemplateParseError";
	
}
/**
 * Represents a template processing error.
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function TemplateProcessError(message, fileName, lineNumber, stack) {
	
	/**
	 * Message of error
	 * @type String
	 */
	this.message = message;
	
	/**
	 * Name of the file where the error occured
	 * @type String
	 */
	this.fileName = fileName;
	
	/**
	 * Number of line where the error occured
	 * @type String
	 */
	this.lineNumber = lineNumber;
	
	/**
	 * Stact trace of error
	 * @type Object
	 */
	this.stack = stack;
	
	/**
	 * Name of error
	 * @type String
	 */
	this.name = "TemplateProcessError";
	
}
/**
 * Prototype.js style getElementById
 * @param String Id of DOM object
 * @return Found DOM object
 * @type Object
 */
function $(id) {
	return document.getElementById(id);
}

/**
 * Check if the variable is not null and is defined
 * @param mixed Variable to check
 * @return True if it's OK
 * @type Boolean
 */
function check(variable) {
	return (variable != null && variable != undefined);
}

/**
 * Check if the variable is not null and is defined and is instanceof type
 * @param mixed Variable to check
 * @return True if it's OK
 * @type Boolean
 */
function checkType(variable, type) {
	return (variable != null && variable != undefined && variable instanceof type);
}
/**
 * ContentManager module in esuli
 * @constructor
 * @author Johnny, Gábor, Horvath 'Koko' Kornel, Morr
 */
function ContentManager() {
    
    /**
     * Last visited page
     * @type Object
     */
    var lastPage = { module: "staticPageManager", page: "static_home" };
    
    /**
     * Page loading sequence
     * @type Number
     */
    var seq = 0;
    
    /**
     * Pointer to this
     * @type ContentManager
     */
    var self = this;
    
	/**
	 * Switch page
 	 * @param Object
 	 */
	function switchPage(pageRequest) {
		seq++;
    	
		var module = pageRequest.get("module");
		var dataContent = "";
		
		if (esuli[module] == undefined || esuli[module].getPage == undefined) {
			//TODO: Log error
			alert("Page creator module " + module + " not exists in esuli.");
			throw new Error("Page creator module " + module + " not exists in esuli.");
		}

		try {
			dataContent = esuli[module].getPage(pageRequest.getData());
			lastPage = pageRequest.getData();
		} catch(e) {
			//TODO: Log error
			alert(e.message);
			throw new Error("Creating page with module " + module + " was unsuccessful, because: " + e.message);
		}
		
		// Get content divs
		var bodySales = $('bodySales');
		
		var bodyTop = $('bodyTop');
		
		var bodyLeft = $('bodyLeft');
		var bodyLeftTopContent = $('bodyLeftTopContent');
		var bodyLeftContent = $('bodyLeftContent');
		var bodyLeftBottomContent = $('bodyLeftBottomContent');
		
		var bodyCenter = $('bodyCenter');
		var bodyCenterTopContent = $('bodyCenterTopContent');
		var bodyCenterContent = $('bodyCenterContent');
		var bodyCenterBottomContent = $('bodyCenterBottomContent');
		
		var bodyRight = $('bodyRight');
		var bodyRightTopContent = $('bodyRightTopContent');
		var bodyRightContent = $('bodyRightContent');
		var bodyRightBottomContent = $('bodyRightBottomContent');
		
		var bodyBottom = $('bodyBottom');
		
		// Clear them All
		bodySales.innerHTML = '&nbsp;';
		
		bodyTop.innerHTML = '&nbsp;';
		
		bodyLeftTopContent.innerHTML = '&nbsp;';
		bodyLeftContent.innerHTML = '&nbsp;';
		bodyLeftBottomContent.innerHTML = '&nbsp;';
		
		bodyCenterTopContent.innerHTML = '&nbsp;';
		bodyCenterContent.innerHTML = '&nbsp;';
		bodyCenterBottomContent.innerHTML = '&nbsp;';
		
		bodyRightTopContent.innerHTML = '&nbsp;';
		bodyRightContent.innerHTML = '&nbsp;';
		bodyRightBottomContent.innerHTML = '&nbsp;';
		
		bodyBottom.innerHTML = '&nbsp;';
		
		// Fill sales
		bodySales.style.display = 'none';
		bodySales.innerHTML = '&nbsp;';
		
		// Fill top
		if(dataContent.top) {
			bodyTop.style.display = 'block';
			bodyTop.style.height = dataContent.topHeight ? dataContent.topHeight : '1%';
			bodyTop.innerHTML = dataContent.top ? dataContent.top : '&nbsp;';
		} else {
			bodyTop.style.display = 'none';
		}
		
		// Fill left	
		if(dataContent.left || dataContent.leftTop || dataContent.leftBottom) {
			bodyLeft.style.display = 'block';
			bodyLeft.style.width = dataContent.leftWidth ? dataContent.leftWidth : '0px';
			bodyLeftContent.style.display = dataContent.left ? 'block' : 'none';
			bodyLeftContent.innerHTML = dataContent.left ? dataContent.left : '&nbsp;';
			bodyLeftTopContent.style.display = dataContent.leftTop ? 'block' : 'none';
			bodyLeftTopContent.innerHTML = dataContent.leftTop ? dataContent.leftTop : '&nbsp;';
			bodyLeftBottomContent.style.display = dataContent.leftBottom ? 'block' : 'none';
			bodyLeftBottomContent.innerHTML = dataContent.leftBottom ? dataContent.leftBottom : '&nbsp;';
		} else {
			bodyLeft.style.display = 'none';
		}
		
		// Fill center
		if(dataContent.center || dataContent.centerTop || dataContent.centerBottom) {
			bodyCenter.style.display = 'block';
			bodyCenter.style.width = dataContent.centerWidth ? dataContent.centerWidth : '0px';
			bodyCenterContent.style.display = dataContent.center ? 'block' : 'none';
			bodyCenterContent.innerHTML = dataContent.center ? dataContent.center : '&nbsp;';
			bodyCenterTopContent.style.display = dataContent.centerTop ? 'block' : 'none';
			bodyCenterTopContent.innerHTML = dataContent.centerTop ? dataContent.centerTop : '&nbsp;';
			bodyCenterBottomContent.style.display = dataContent.centerBottom ? 'block' : 'none';
			bodyCenterBottomContent.innerHTML = dataContent.centerBottom ? dataContent.centerBottom : '&nbsp;';
		} else {
			bodyCenter.style.display = 'none';
		}
		
		// Gadgets 
		var subName;
    	
		if (pageRequest.get("tabId")) {
	    	subName = esuli.tab.getSubMenuName(pageRequest.get("tabId"), pageRequest.get("subId"));
		} else {
			subName = esuli.tab.getSubMenuName(esuli.tab.activeTabId, esuli.tab.activeSubMenuId);
		}
		
		var gadgets = esuli.gadgetManager.getGadgets();
		if(gadgets.length > 0 && !pageRequest.get("lessonId")) {
			if(!dataContent.right) {
				dataContent.right = '';
			}
			for (var i = 0; i < gadgets.length; i++ ) {
				if(gadgets[i].getTab().toString() == subName || gadgets[i].getTab() == engine.cookieManager.get("agent")) {
					dataContent.right += engine.templateManager.getTemplate('gadget_' + esuli.gadgetManager.getTemplateName(gadgets[i].getType())).process({gadget: gadgets[i], content: gadgets[i].getContent()});
				}
			}
		}
		
		// Fill right		
		if(dataContent.right || dataContent.rightTop || dataContent.rightBottom) {
			bodyRight.style.display = 'block';
			bodyRight.style.width = dataContent.rightWidth ? dataContent.rightWidth : '0px';
			bodyRightContent.style.display = dataContent.right ? 'block' : 'none';
			bodyRightContent.innerHTML = dataContent.right ? dataContent.right : '&nbsp;';
			bodyRightTopContent.style.display = dataContent.rightTop ? 'block' : 'none';
			bodyRightTopContent.innerHTML = dataContent.rightTop ? dataContent.rightTop : '&nbsp;';
			bodyRightBottomContent.style.display = dataContent.rightBottom ? 'block' : 'none';
			bodyRightBottomContent.innerHTML = dataContent.rightBottom ? dataContent.rightBottom : '&nbsp;';
		} else {
			bodyRight.style.display = 'none';
		}
		
		// Fill Bottom
		if(dataContent.bottom) {
			bodyBottom.style.display = 'block';
			bodyBottom.style.height = dataContent.bottomHeight ? dataContent.bottomHeight : '1%';
			bodyBottom.innerHTML = dataContent.bottom ? dataContent.bottom : '&nbsp;';
		} else {
			bodyBottom.style.display = 'none';
		}
		
		// Statisztika
		if( $("sendPageToStatistics") ) {
			esuli.statistics.sendPageToStatistics();
		}
		
		// Set content end
		esuli.staticContent.setContentEnd();
		if(pageRequest.get("lessonId")) {
			setTimeout("esuli.staticContent.setContentEnd();", 500);
		}
	}
    
	/**
 	 * Elkapja LayoutReload eseményt
 	 * @param event Object
	 */
	this.listenLayoutReload = function(event) {
		switchPage(event);
	}
    
	/**
 	 * NavChange esemény figyelő
 	 * @param Object
 	 */
	this.listenNavChange = function(event) {
		switchPage(event);
	}
    
	/**
 	 * Visszaadja az utolsó megjelenített oldalt 
 	 * @return utolsó layout
	 * @type String
	 */
	this.getLastPage = function() {
		return lastPage;
	}
    
	/**
 	 * Returns page loading sequence
	 * @return Page loading sequence
	 * @type Number
	 */
	this.getSeq = function() {
		return seq;
	}
    
	//Initialize
	engine.eventManager.addListener(EventManager.EVENT_NAV_CHANGE, this);
	engine.eventManager.addListener(EventManager.EVENT_LAYOUT_RELOAD, this);	
}
/**
 * Esuli main class
 * @constructor
 */
function Esuli() {
	
	/**
	 * staticContent module
	 * @type StaticContent
	 */
	this.staticContent = null;
	
	/**
	 * preFunction module
	 * @type PreFunction
	 */
	var preFunction = null;
	
	/**
	 * tooltip module
	 * @type tooltip
	 */
	this.toolTip = null;
	
	/**
	 * User module
	 * @type User
	 */
	this.user = null;
	
	/**
	 * Tab module
	 * @type TabMain
	 */
	this.tab = null;
	
	/**
	 * GadgetManager module
	 * @type Gadget
	 */
	this.gadgetManager = null;
	
	/**
	 * statistics module
	 * @type statistics
	 */
	this.statistics = null;
	
	/**
	 * ContentManager module
	 * @type ContentManager
	 */
	this.contentManager = null;
	
	/**
	 * StaticPageManager module
	 * @type StaticPageManager
	 */
	this.staticPageManager = null;
	
	/**
	 * Workbook module
	 * @type Workbook
	 */
	this.workbook = null;
	
	/**
	 * MessageManager module
	 * @type MessageManager
	 */
	this.messageManager = null;
	
	/**
	 * Classroom module
	 * @type Classroom
	 */
	this.classroom = null;
	
	/**
	 * Applet module
	 * @type Applet
	 */
	this.applet = null;
	
	/**
	 * Shopping module
	 * @type Shopping
	 */
	this.shopping = null;
	
	/**
	 * sales module
	 * @type Sales
	 */
	this.sales = null;
	
	/**
	 * dateSelector module
	 * @type dateSelector
	 */
	this.dateSelector = null;
	
	/**
	 * recorder module
	 * @type recorder
	 */
	this.recorder = null;
	
	/**
	 * faq module
	 * @type faq
	 */
	this.faq = null;
	
	/**
	 * Initialize Esuli (not logged in)
	 */
	this.pre_init = function() {
		this.staticContent = new StaticContent();
		this.preFunction = new PreFunction();
		
		$('DialogPreLoading').style.display = 'none';
		$('DialogBackground').style.display = 'none';
       if ( engine.cookieManager.get("sId") ) {
            $('preNormalLogin').style.display = 'none';
            $('preAutoLogin').style.display = 'block';
        }
        else {
            $('preAutoLogin').style.display = 'none';
            $('preNormalLogin').style.display = 'block';
        }

		this.toolTip = new ToolTipND();
		this.user = new User();

/*		
		// smartyException.js
		var checkRemember = true;
		var reload = esuli.staticContent.getReload();
		if( reload.length > 0 && reload != "" ) {
			for( var i = 0; i < dontLoginRemember.length; i++ ) {
				if( dontLoginRemember[i] == reload ) {
					checkRemember = false;
					break;
				}
			}
		}
		if(checkRemember) {
			engine.cookieManager.checkRemember();
		}
*/
	}
	
	/**
	 * Initializes Esuli
	 */
	this.init = function() {
		this.tab = new TabMain("tabMenu", "subMenu");
		this.gadgetManager = new GadgetManager();
		this.statistics = new Statistics();
		this.contentManager = new ContentManager();
		this.staticPageManager = new StaticPageManager();
		this.workbook = new Workbook();
		this.messageManager = new MessageManager();
		this.classroom = new Classroom();
		this.applet = new Applet();
		this.shopping = new Shopping();
		this.sales = new Sales();
		this.dateSelector = new DateSelector(); // Kell?
//		this.recorder = new Recorder(); // Kell?
		this.faq = new FaqManager();
	}
}
/**
 * Statistics module
 * @constructor
 * @author Morr
 */
function Statistics() {
	
	/**
	 * Browser type
	 * @type String (Explorer,Netscape,Opera)
	 */
	var browserType = -1;
	
	/**
	 * Browser version
	 * @type String
	 */
	var browserVersion = -1;
	
	/**
	 * Screen resolution width
	 * @type Number
	 */
	var screenResolutionWidth = -1;
	
	/**
	 * Screen resolution height
	 * @type Number
	 */
	var screenResolutionHeight = -1;
	
	/**
	 * Last added statistics page
	 * @type Object
	 * @param Last added Tab, Sub and page
	 */
	var lastAddedPage = { tab: '', sub: '', page: '' };
	
	/**
	 * Last page opened
	 * @type String
	 */
	var lastOpenPage = '';
	
	/**
	 * Detect browser type and version
	 * Send it to DB statistics
	 */
	function detectBrowser() {
		if( browserType != -1 ) {
			return;
		}

		if ( navigator.appName.indexOf( 'Microsoft' ) != -1 ) {
			browserType = 'Explorer';
		} else if ( navigator.appName.indexOf( 'Netscape' ) != -1 ) {
			browserType = 'Netscape';
		} else if (window.opera) {
			browserType = 'Opera';
		} else {
			browserType = 'Other';
		}
		
		browserVersion = navigator.appVersion;
		paren = browserVersion.indexOf( '(' );
		whole_ver = navigator.appVersion.substring( 0, paren - 1 );
		browserVersion = parseInt( whole_ver );
		
		var command = new CommGateRequest (
			'REQ_ACCESS', 
			[ 'ESULI_STATISTICS_BROWSER' ],  
			function(response) {}
		);
		command.addDataLevel ( [['TYPE', 'VERSION', '' ], [ browserType, browserVersion, '' ]] );

		engine.commGate.sendWithSession([ command ]);
	}
	
	/**
	 * Get browser type and version
	 * @return Array Browser type, Browser version
	 */
	this.getBrowser = function() {
		ret = new Array( browserType, browserVersion );
		return ret;
	}
	
	/**
	 * Detect screen resolution width and height
	 * Send it to DB statistics
	 */
	function detectScreenResolution() {
		if( screenResolutionWidth != -1 ) {
			return;
		}
		
		screenResolutionWidth = screen.width;
		screenResolutionHeight = screen.height;
		
		var command = new CommGateRequest (
			'REQ_ACCESS', 
			[ 'ESULI_STATISTICS_RESOLUTION' ],  
			function(response) {}
		);
		command.addDataLevel ( [['WIDTH', 'HEIGHT', '' ], [ screenResolutionWidth, screenResolutionHeight, '' ]] );

		engine.commGate.sendWithSession([ command ]);
	}
	
	/**
	 * Get screen resolution width and height
	 * @return Array width, height
	 */
	this.getScreenResolution = function() {		
		ret = new Array( screenResolutionWidth, screenResolutionHeight );
		return ret;
	}
	
	/**
	 * Send page info to DB statistics
	 */
	this.sendPageToStatistics = function() {
		var date = new Date();
		var year = date.getFullYear();
		var month = ( date.getMonth() + 1 ) < 10 ? '0' + ( date.getMonth() + 1 ) : date.getMonth() + 1;
		var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
		var fullDate = year + ' ' + month + ' ' + day;
		
		var tabName = esuli.tab.getTabName( esuli.tab.activeTabId );
		var subName = esuli.tab.getSubMenuName( esuli.tab.activeTabId, esuli.tab.activeSubMenuId );
		
		var actualPage = esuli.contentManager.getLastPage().get("page");
		
		if( lastOpenPage == actualPage && lastAddedPage.page == actualPage ) {
			return;
		}
		
		lastAddedPage.tab = tabName;
		lastAddedPage.sub = subName;
		lastAddedPage.page = actualPage;
		
		var command = new CommGateRequest (
			'REQ_ACCESS', 
			[ 'ESULI_STATISTICS_PAGE' ],  
			function(response) {}
		);
		command.addDataLevel ( [['DATE', 'TAB', 'SUB', 'PAGE' ], [ fullDate, tabName, subName, actualPage ]] );

		engine.commGate.sendWithSession([ command ]);
	}
	
	/**
     * On LayoutReload event set last opened page
     */
    this.listenLayoutReload = function() {
		var actualPage = esuli.contentManager.getLastPage().get("page");
    	lastOpenPage = actualPage;
    }

	engine.eventManager.addListener(EventManager.EVENT_LAYOUT_RELOAD, this);
	
	// detectBrowser();
	// detectScreenResolution();
}
/**
 * ToolTip
 * @constructor
 * @author Morr
 */
function ToolTipND() {
	
	/**
	 * Clien width
	 * @type Number
	 */
	var myWidth = 0;
	
	/**
	 * Clien height
	 * @type Number
	 */
	var myHeight = 0;
	
	/**
	 * Mouse X position
	 * @type Number
	 */
	var mouseX = 0;
	
	/**
	 * Mouse Y position
	 * @type Number
	 */
	var mouseY = 0;
	
	/**
	 * Screen margin for mouse position
	 * @type Number
	 */
	var mouseMargin = 10;
	
	/**
	 * Get element by id
	 * @param DOM element id
	 * @return Object
	 */
	function getElt(pId) {
		return (document.getElementById ? document.getElementById(pId)
			: document.all ? document.all[pId]
			: null);
	}
	
	/**
	 * Get client width and height
	 */
	function getClientWH() {
		if(typeof( window.innerWidth ) == 'number' ) {
			myWidth = window.innerWidth;
			myHeight = window.innerHeight;
		} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
			myWidth = document.documentElement.clientWidth;
			myHeight = document.documentElement.clientHeight;
		} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
			myWidth = document.body.clientWidth;
			myHeight = document.body.clientHeight;
		}
	}
	
	/**
	 * Move toolTip
	 * @param Event
	 */
	function moveToolTip(e) {
		if (!e) var e = window.event;
		if (e.pageX || e.pageY) {
			mouseX = e.pageX;
			mouseY = e.pageY;
		} else if (e.clientX || e.clientY) {
			mouseX = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
			mouseY = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
		}

		if (mouseX < 0) {
			mouseX = 0;
		}
		if (mouseY < 0) {
			mouseY = 0;
		}
		
		var tooltip = getElt('ToolTipBox');
		
		tooltip.style.width = tooltip.offsetWidth + 'px';
		tooltip.style.height = tooltip.offsetHeight + 'px';
		
		if(e.clientX > (myWidth - tooltip.offsetWidth - mouseMargin - 20)) {
			tooltip.style.left = (mouseX - tooltip.offsetWidth - mouseMargin) + 'px';
		} else {
			tooltip.style.left = mouseX + mouseMargin + 'px';
		}
		
		if(e.clientY > (myHeight - tooltip.offsetHeight - mouseMargin - 5)) {
			tooltip.style.top = (mouseY - tooltip.offsetHeight - mouseMargin) + 'px';
		} else {
			tooltip.style.top = mouseY + mouseMargin + 'px';
		}
		
		return true;
	}
	
	/**
	 * Show toolTip
	 * @param Object Caller element
	 * @param String Title of the toolTip
	 * @param String Content of the toolTip
	 */
	this.show = function(pObj, pTitle, pContent) {		
		if (navigator.appName.indexOf('Microsoft') == -1) {
			document.captureEvents(Event.MOUSEMOVE);
		}
		document.onmousemove = moveToolTip;
		
		if(!document.attachEvent) {
			pObj.addEventListener('mouseout', hide, false);
		} else {
			pObj.attachEvent('onmouseout', hide); 
		}
		
		if(pObj.title) {
			pObj.title = "";
		}
		if(pObj.alt = "") {
			pObj.alt = "";
		}
		pObj.style.cursor = "hand";
		
		getClientWH();
		
		var tooltip = getElt('ToolTipBox');
		var tooltipHeader = getElt('ToolTipHeader');
		var tooltipContent = getElt('ToolTipContent');
		tooltipHeader.innerHTML = pTitle ? pTitle : "";
		tooltipContent.innerHTML = pContent ? pContent : "";
		tooltip.style.visibility = 'visible';
	}
	
	/**
	 * Hide toolTip
	 */
	function hide() {
		if (navigator.appName.indexOf('Microsoft') == -1) {
			document.captureEvents(Event.MOUSEMOVE);
		}
		document.onmousemove = null;
		
		var tooltip = getElt('ToolTipBox');
		tooltip.style.width = '220px';
		tooltip.style.height = '';
		tooltip.style.visibility = 'hidden';
	}
	
	/**
	 * For IE change toolTip background
	 */
	if (navigator.appName.indexOf('Microsoft') != -1) {
		opacity = 85;
		var tooltip = getElt('ToolTipBox');
		var tooltipHeader = getElt('ToolTipHeader');
		var tooltipContentBg = getElt('tooltipContentBg');
		tooltipHeader.style.background = 'transparent url("images/1_5/tooltip/tooltipHeader.gif") repeat left top';
		tooltipContentBg.style.background = 'transparent url("images/1_5/tooltip/tooltipContent.gif") repeat left bottom';
		tooltip.style.opacity = (opacity / 100); 
		tooltip.style.MozOpacity = (opacity / 100); 
		tooltip.style.KhtmlOpacity = (opacity / 100); 
		tooltip.style.filter = "alpha(opacity=" + opacity + ")";
	}
}
/**
 * Applet module
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function Applet() {
	
	/**
	 * Certificate acception requested or not
	 * @type Boolean
	 */
	var trusted = false;
	
	/**
	 * Voip controller object
	 * @type Voip
	 */
	this.voip = new Voip();
	
	/**
	 * Returns trusted state
	 * @return Trusted state
	 * @type Boolean
	 */
	this.getTrusted = function() {
		return trusted;
	}
	
	/**
	 * Sets trusted state
	 * @param Boolean New trusted state
	 */
	this.setTrusted = function(appletTrusted) {
		trusted = Boolean(appletTrusted);
	}
	
}/**
 * Manages VoIP applet
 *
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function Voip() {
    
    /**
     * Contacts of user
     * @type Array
     */
    var contacts;
    
    /**
     * Visibility of applet
     */
    var visible;
    
    /**
     * Pointer to this
     * @type Voip
     */
    var self = this;
    
    /**
     * Shows applet box and initializes it when necessary
     */
    this.show = function() {
    	if (visible) {
    		return;
    	}
    	
	    try {
    		engine.templateManager.processTemplate("applet_voip", { user: esuli.user, contacts: contacts }, "VoIPBox");
    		esuli.applet.setTrusted(true);
    	} catch(e) {
    		//TODO: Log error
    	}
   		$("VoIPBox").style.display = "block";
		
		new DragAndDrop($("VoIPMover"), $("VoIPBox"));
	//	new DragAndDrop($("VoIPMoverBottom"), $("VoIPBox"));
		
		visible = true;


    }
    
    /**
     * Hides applet box
     */
    this.hide = function() {
    	if (! visible) {
    		return;
    	}
    	
    	$("VoIPBox").innerHTML = "";
		$("VoIPBox").style.display = "none";
		visible = false;
    }
    
    this.listenUserLogin = function(event) {
		/*
    	var req = new CommGateRequest(
    		"REQ_ACCESS",
    		[ "ESULI_ACCESS_CONTACTLIST" ],
    		function(response) {
				contacts = response[0].getDataAsObjectArray();
    		}
    	);
    	
    	req.addDataLevel([ [], [] ]);
    	engine.commGate.sendWithSession([ req ]);
		*/
    }
    
    //Initialization start
    contacts = new Array();
    
    engine.eventManager.addListener(EventManager.EVENT_USER_LOGIN, this);

}
/**
*  @constructor
*/
function Classes(pID, pName, pUId, pLevel, pBegin, pMaxNo, pDates, pType) {
	
	/**
	* Class id
	* @type Number
	*/
	var id = new Number(pID);
	
	/**
	 * Class name
	 * @type String
	 */
	var name = new String(pName);
	
	/**
	 * User id-s in this class
	 * @type String
	 */
	var uid = new String(pUId);

	/**
	 * Class level
	 * @type String
	 */
	var level = new String(pLevel);
	
	/**
	 * Class begining date
	 * @type String
	 */
	var begin = new String(pBegin);
	
	/**
	 * Class max user number
	 * @type String
	 */
	var maxno = new Number(pMaxNo);
	
	/**
	 * Class lesson dates
	 * @type Array
	 */
	var dates = pDates;
	
	/**
	 * Class type
	 * @type String
	 */
	var type = new String(pType);
	
	/**
	 * Return Class id
	 * @return Class id
	 * @type Number
	 */
	this.getId = function() {
		return id;
	}
	
	/**
	 * Return Class uid
	 * @return Class uid
	 * @type Number
	 */
	this.getUid = function() {
		return uid;
	}
	
	/**
	 * Return Class name
	 * @return Class name
	 * @type String
	 */
	this.getName = function() {
		return name;
	}
	
	/**
	 * Return Class level
	 * @return Class level
	 * @type String
	 */
	this.getLevel = function() {
		return level;
	}
	
	/**
	 * Return Class begining date
	 * @return Class begin
	 * @type String
	 */
	this.getBegin = function() {
		return begin;
	}
	
	/**
	 * Return Class max user number
	 * @return Class max user number
	 * @type String
	 */
	this.getMaxno = function() {
		return maxno;
	}
	
	/**
	 * Return Class lesson dates
	 * @return Class lesson dates
	 * @type Array
	 */
	this.getDates = function() {
		return dates;
	}
	
	/**
	 * Return Class lesson next date
	 * @return Class lesson next date
	 * @type String
	 */
	this.getNextDate = function() {
		var nextDate = dates[0];
		re = /-/gi;
		nextDate = nextDate.replace(re,'.');
		nextDate = nextDate.substring(0,19);
		nextDate = nextDate != "" ? nextDate : "-";
		return nextDate;
	}


	/**
	 * Return Class type
	 * @return Class type
	 * @type String
	 */
	this.getType = function() {
		return type;
	}
}
/**
 * 
 */
function Classroom() {
	
	/**
	 * Pointer to this
	 * @type Home
	 */
	var self = this;
	
	/**
	 * Student's classes array
	 * @type Array
	 */
	this.classesArray = new Array();
	
	/**
	 * Is classes downloaded
	 * @type Boolean
	 */
	var classesDownloaded = false;
	
	/**
	 * Technic room status
	 * - hide: Hide technic room
	 * - show: Show technic room
	 */
	var technicRoom = "hide";
	
	/**
	 * Technic room number
	 * @type Number
	 */
	var technicRoomNum = -1;
	
	/**
	 * Get technic room status
	 * @return Technic room status
	 * @type String
	 */
	this.getTechnicRoomStatus = function() {
		return technicRoom;
	}
	
	/**
	 * Set technic room status
	 * @param Technic room status
	 * @type String
	 */
	this.setTechnicRoomStatus = function( pStatus ) {
		technicRoom = pStatus;
	}
	
	/**
	 * Get technic room number
	 * @return Technic room number
	 * @type String
	 */
	this.getTechnicRoomNumber = function() {
		if(technicRoomNum != -1) {
			return technicRoomNum;
		} else {
			var command = new CommGateRequest (
				'REQ_ACCESS', 
				[ 'ESULI_STUDENT_GET_TECHNICS_ROOM' ],  
				function(response) {
					var data = response[0].getDataAsObjectArray();
					room_number = data[0].room_number;
					technicRoomNum = room_number;
					engine.cookieManager.set('uRoom','technika' + room_number);
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
				}
			);
			command.addDataLevel([ [ "" ],[ "" ] ]);
			engine.commGate.sendWithSession([ command ]);
		}
		return false;
	}
	
	/**
	 * Show technic room
	 */
	this.showTechnicRoom = function() {
		self.setTechnicRoomStatus("show");
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
	}
	
	/**
	 * Hide technic room
	 */
	this.hideTechnicRoom = function() {
		self.setTechnicRoomStatus("hide");
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
	}

	/**
	 * Loads student's classes from database
	 */
	function getClasses() {
		var command = new CommGateRequest ( 
			'REQ_ACCESS', 
			[ 'ESULI_STUDENT_GET_CLASSES' ], 
			function(pResponse) {
			    var cmd;
			    var data;
			    for (var i = 0; i < pResponse.length; i++) {
					cmd = pResponse[i].getCommandLine();
					if ((cmd[1] == 'RES_DATA')) {
				    	data = pResponse[i].getDataAsArray();
					    var classes;
					    for (var i = 0; i < data.length; i++) {
							if( data[i][0] != "ID" ) {
		
							    var datesArray = data[i][6];
							    re = /;/gi;
							    datesArray = datesArray.replace(re,'","');
							    re = /\(/gi;
							    datesArray = datesArray.replace(re,'["');
							    re = /\)/gi;
							    datesArray = datesArray.replace(re,'"]');
							    datesArray = eval(datesArray);
							
				    			    classes = new Classes( data[i][0], data[i][1], data[i][2], data[i][3], data[i][4], data[i][5], datesArray, "normal" );
							    esuli.classroom.classesArray.push(classes);
							}
					    }
					}
			    }
				if ( data ) {
					classesDownloaded = true;
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
				}
			}
		);
		command.addDataLevel ( [ [ '', '', '' ], 
		[ '', '', '' ]] );
		engine.commGate.sendWithSession([ command ]);
	}
	

    /**
     * Send email to customer service
     */
    this.sendHeadsettShoppingRequest = function() {
		var box = $('living_pbox');
		var city = $('living_city');
		var street = $('living_street');
		var phone = $('phone');
		
		if(esuli.staticContent.trimTextInput(box.value) == '') {
			box.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Nem adtad meg az irányítószámot!', 'alert'));
			return;
		}
		
		if(!esuli.staticContent.trimTextInput(city.value)) {
			city.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Nem adtál meg települést!', 'alert'));			
			return;
		}
		
		if(!esuli.staticContent.trimTextInput(street.value)) {
			street.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Nem adtad meg az utcát, házszámot!', 'alert'));			
			return;
		}
		
		if(!esuli.staticContent.trimTextInput(phone.value)) {
			phone.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Nem adtál meg telefonszámot!', 'alert'));			
			return;
		} else if(!esuli.staticContent.checkTelefon(esuli.staticContent.trimTextInput(phone.value))) {
			phone.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Az telefonszám formátuma nem megfelelő!', 'alert'));
			return;
		}
		
		esuli.user.updateProfile();

        var email = esuli.user.getEmail();
        var surname = esuli.user.getLivingAddress().getSurname() ? esuli.user.getLivingAddress().getSurname() : "";
        var forename = esuli.user.getLivingAddress().getForename() ? esuli.user.getLivingAddress().getForename() : "";
        var name = surname + " " + forename;
        var tel = esuli.user.getPhone() ? esuli.user.getPhone() : "";
		var address = esuli.user.getLivingAddress().getZip() + " " + esuli.user.getLivingAddress().getCity() + " " + esuli.user.getLivingAddress().getAddress();

        var message = "";
            message += "Vásárló adatai:" + "\n\n"
             + "Név: " + name + "\n"
             + "E-mail cím: " + email + "\n"
             + "Telefon: " + tel + "\n"
             + "Cím: " + address + "\n";

		engine.commGate.send([ new CommGateRequest("SEND_EMAIL", [ "info@enyelviskola.hu", message, "Mikrofon és kamera vétel" ], null ), new CommGateRequest("HAVE_SESSION", [ esuli.user.getSessionId() ], null ) ] );
		engine.dialogManager.add(new Dialog("Köszönjük! Rendelésedet továbbítottuk partnerünknek, aki néhány napon belül kiszállítja neked a mikrofonos fejhallgatót és webkamerát, de előtte emailben és telefonon is értesíteni fog.<br /><br /><span class='grayNormal'>A rendelést partnerünk, a PC Land Kft. fogja postázni. További információ: 06-21-381-3980, Cím: 1135 Budapest, Jász u. 71.</span>", "alert", null));
	}
	
	/**
	 * Returns requested page
	 * @param Object Page request
	 * @return Requested page
	 * @type Object
	 */
	this.getPage = function(pageRequest) {
		
		var page = { leftWidth: '0px', centerWidth: '743px', rightWidth: '225px', left: '', center: '', right: '' };
		
		switch (pageRequest.get("page")) {
			
			case "roomlist":
				page.leftWidth = '372px';
				page.centerWidth = '371px';
				page.rightWidth = '225px'
				page.left = engine.templateManager.getTemplate("contentspin").process({});
				page.center = engine.templateManager.getTemplate("classroom_etikett").process({});
				
				if ( ! classesDownloaded ) {
					getClasses();
					return page;
				}

				page.left = engine.templateManager.getTemplate("classroom_roomlist").process({ myClasses: this.classesArray });
				
				break;
			
			case "technika":
				page.leftWidth = '372px';
				page.centerWidth = '371px';
				page.rightWidth = '225px'
				page.center = engine.templateManager.getTemplate("classroom_headsett").process({});
				
				if(!self.getTechnicRoomNumber()) {
					page.left = engine.templateManager.getTemplate("contentspin").process({});
				} else {
					page.left = engine.templateManager.getTemplate("classroom_technika").process({});
				}
				
				if(self.getTechnicRoomStatus() == "show") {
					page.bottom = engine.templateManager.getTemplate("classroom_technicroom").process({});
				}
				
				break;
				
			case "try":
				page.center = engine.templateManager.getTemplate("classroom_try").process({});

				break;
			
			default:
				//TODO: Log error
				return;
		}
		
		lastPage = pageRequest;
		
		return page;
	}
	
	/**
	 * Returns last visited page
	 * @return Last visited page
	 * @type Object
	 */
	this.getLastPage = function() {
		self.getPage(lastPage);
	}
}
/**
 * Engine object
 * @type Engine
 */
var engine = new Object();

/**
 * Esuli object
 * @type Esuli
 */
var esuli = new Object();

/**
 * Log object
 * @type Esuli
 */
 glLog = new Log("glLog");

/**
 * Initializes everything
 */
function init() {
	
	/**
	 * Interface
	 */
	this.interface = 'Normal';

	esuli.init();

	esuli.tab.addTab( 
					'Main',   //Tab type - Main or Info //Tab type - Main or Info 
					'Asztal',  //Tab Title
					'active', //Tab Status - aktive or inactive or lessons
					[
						['Mi az eNyelviskola.hu?', { module: "staticPageManager", page: "static_home" }, 'active'], 
//						['Gyakori kérdések', { module: "faq", page: "faq" }, 'inactive'], 
//						['Munkatársaink', { module: "staticPageManager", page: "static_munkatarsak" }, 'inactive'], 
						['Elérhetőségeink', { module: "staticPageManager", page: "static_ugyfelszolgalat" }, 'inactive'],
						['Személyes', { module: "user", page: "profile" }, 'inactive'],
						['Üzenetek', { module: "messageManager", page: "allMessages" }, 'inactive']
					] 
				);
	esuli.tab.addTab( 
					'Main', 
					'Tanfolyamok', 
					'', 
					[
						['Tanfolyamok', { module: "shopping", page: "info" }, 'active'],
//						['Árak', { module: "shopping", page: "pricelist" }, 'inactive'], 
//						['Akciók', { module: "staticPageManager", page: "static_akciok"}, 'inactive'],
//						['Beiratkozás', { module: "shopping", page: "registration" }, 'inactive'],
						['Szintfelmérő', { module: "user", page: "levelSurvey" }, 'inactive'] 
					] 
				);
	esuli.tab.addTab( 
					'Main',
					'Tanterem',
					'',
					[
						['Tantermek', { module: "classroom", page: "roomlist" }, 'active'],
						['Technikai próba', { module: "classroom", page: "technika"}, 'inactive'], 
						['Tudnivalók', { module: "staticPageManager", page: "static_tantereminfo"}, 'inactive'],
						['Kipróbálom!', { module: "classroom", page: "try"}, 'inactive']		
					] 
				);
	esuli.tab.addTab( 
					'Main', 
					'Tananyag', 
					'', 
					[
						['Tankönyvek', { module: "workbook", page: "lessonList" }, 'active'],
						['Tudnivalók', { module: "staticPageManager", page: "static_tankonyvinfo"}, 'inactive'],
						['Tippek', { module: "staticPageManager", page: "static_tanulasitippek" }, 'inactive'], 
						['Segédanyagok', { module: "staticPageManager", page: "static_segedanyagok"}, 'inactive']
					] 
				);

	// DO NOT ADD OR REMOVE MAIN TABS, THIS MUST BE THE 5TH ONE OR IT WON'T WORK (counting starts from 0)
	esuli.tab.addTab(
					'Sales',
					'Sales',
					'active',
					[
						['Cégek', { module: "sales", page: "companyList" }, 'active']
					] 
				);	
}

/**
 * Initialize Engine
 * Initialize Esuli (not logged in)
 */
function pre_init() {
	engine = new Engine();
	engine.init();
	
	esuli = new Esuli();
	esuli.pre_init();
}
BASE_URL =  "http://www.enyelviskola.hu/";
Recorder_URL = "http://www.enyelviskola.hu/engine/upload.php"; //Upload PHP location
Player_URL = "http://shield.steery.com:8000/voice/"; //Icecast server root
CommGate.URL = BASE_URL + "engine/php/main1_5.php"; //main1_5.php location
TemplateManager.URL = BASE_URL + "ajax/1_5/templates/"; //Templates dir location
VIDEOPLAYER_URL = "http://www.enyleviskola.hu/video/enyelvplayer.swf";
VIDEO_URL_PREFIX = "http://www.enyleviskola.hu/video";


/**
*   Workbook feladat HTML állományok könyvtára.
*   @type   String
*   @see    WorkbookExercise
*/
_WORKBOOK_LESSONPATH    = BASE_URL + 'lessons';

/**
 * Is FireBug log is allowed
 */
allowFireBugLog = true;
/**
 * @author Johnny
 */

function CurrentDate( pCurrDate, pIsStudent, pTeacherId, pComment ) {
	
	var currdate = new String(pCurrDate);
	var isStudent = new Boolean();
	
	if (pIsStudent == 'N') {
		isStudent = false;
	} else {
		isStudent = true;
	}
	
	var teacherId = new String(pTeacherId);
	var comment = new String(pComment);
	
	this.getCurrDate = function() {
		return currdate;
	}
	
	this.getIsStudent = function() {
		return isStudent;
	}
	
	this.setIsStudent = function(pValue) {
		isStudent = pValue;
	}
	
	this.getTeacherId = function() {
		return teacherId;
	}
	
	this.getComment = function() {
		return comment;
	}

}
/**
 * @author Johnny
 */

function DateSelector() {
	
	var maxSum = new Number();
	
	var dayNames = new Array("Vasárnap","Hétfő","Kedd","Szerda","Csütörtök","Péntek","Szombat");
	var monthNames = new Array("Jan.","Febr.","Márc.","Ápr.","Máj.","Jún.","Júl.","Aug.","Szept.","Okt.","Nov.","Dec.");
	
	var DateSelectorData = new Array();
	
	var overColor = '#f2f2f2';
	var clickedColor = '#ff0000';
	var clickedOverColor = '#fff001';
	
	var firstDate = new Date();
	var lastDate = new Date(); 
	var firstDateNumber = 10;
	var lastDateNumber = 20;
	
	var freeTime = 15; //sec
	var lessonTime = 45; //sec
	var startTime = 9; //hour
	var endTime = 18; //hour
	var totalTime;
	
	var rowsCount;
	var columnCount = 7;
	
	var dataObj = new Array();
	
	var firstDayOfWeek = new Date();
	var dayOfMonth;
	var dayOfWeek;
	var monthOfYear;
	var year;
	var hoursOfDay;
	var minutesOfHours;
	var weekOfYears;
	
	var self = this;
	
	this.init = function(actualDate) {
		firstDayOfWeek = actualDate;
		dayOfMonth = actualDate.getDate();
		dayOfWeek = actualDate.getDay();
		monthOfYear = actualDate.getMonth();
		year = actualDate.getFullYear();
		hoursOfDay = actualDate.getHours();
		minutesOfHours = actualDate.getMinutes();
		weekOfYears = getWeek( actualDate );
		
		totalTime = endTime-startTime;
		rowsCount = (totalTime*60)/(freeTime+lessonTime);
		
		var expdate = firstDate.getDate() - firstDateNumber;
		firstDate.setDate(expdate);

		expdate = lastDate.getDate() + lastDateNumber;
		lastDate.setDate(expdate);

		createDateSelectorTable();
	}
	
	this.getFirstDayOfWeek = function() {
		return firstDayOfWeek;
	}
	
	this.getWeekOfYears = function(){
		return weekOfYears;
	}
	
	function createDateSelectorTable() {
		var pStatus;
		var pCssClassName;
		
		var dataContent = new String();
		
		for (var i = 0; i < rowsCount+1; i++ ) {
			dataObj[i] = new Array();
			for (var j = 0; j < columnCount+1; j++) {
				if ( i == 0 && j == 0) {
					dataObj[i][j] = new TableItem(i, j, dataContent, 'emptyCorner', '#e4e8ee', '', null);
				} else {
					var tmpDate = new Date(firstDayOfWeek);
					var expdate = tmpDate.getDate() + (j-1);
					tmpDate.setDate(expdate);
					
					if ( i == 0 && j != 0 ) {
						dataContent = new String(monthNames[tmpDate.getMonth()]+' '+getTwoDigitsFormat(tmpDate.getDate())+'.<br />'+dayNames[tmpDate.getDay()]);
						if ( j == columnCount ) {
							dataObj[i][j] = new TableItem(i, j, dataContent, 'dateItemLast', '#e4e8ee', '', null);
						} else {
							dataObj[i][j] = new TableItem(i, j, dataContent, 'dateItem', '#e4e8ee', '', null);
						}
					} else if ( i != 0 && j == 0 ) {
						if ( i == rowsCount ) {
							dataObj[i][j] = new TableItem(i, j, getTwoDigitsFormat(startTime + i-1)+':00', 'timeItemLast', '#e4e8ee', '', null);
						} else {
							dataObj[i][j] = new TableItem(i, j, getTwoDigitsFormat(startTime + i-1)+':00', 'timeItem', '#e4e8ee', '', null);
						}
					} else {
						dataContent = new String('');
						if (i == rowsCount && j != columnCount && j != 0){
							dataObj[i][j] = new TableItem(i, j, dataContent, 'ItemNoBottom', '#eef3f9', 'inactive', tmpDate.getFullYear()+'-'+(tmpDate.getMonth()+1)+'-'+getTwoDigitsFormat(tmpDate.getDate())+' '+getTwoDigitsFormat(startTime + i-1)+':00');
						} else if (i == rowsCount && j == columnCount) {
							dataObj[i][j] = new TableItem(i, j, dataContent, 'ItemNoRightNoBottom', '#eef3f9', 'inactive', tmpDate.getFullYear()+'-'+(tmpDate.getMonth()+1)+'-'+getTwoDigitsFormat(tmpDate.getDate())+' '+getTwoDigitsFormat(startTime + i-1)+':00');
						} else if (j == columnCount && i != 0 && i != rowsCount) {
							dataObj[i][j] = new TableItem(i, j, dataContent, 'ItemNoRight', '#eef3f9', 'inactive', tmpDate.getFullYear()+'-'+(tmpDate.getMonth()+1)+'-'+getTwoDigitsFormat(tmpDate.getDate())+' '+getTwoDigitsFormat(startTime + i-1)+':00');
						} else {
							dataObj[i][j] = new TableItem(i, j, dataContent, 'Item', '#eef3f9', 'inactive', tmpDate.getFullYear()+'-'+(tmpDate.getMonth()+1)+'-'+getTwoDigitsFormat(tmpDate.getDate())+' '+getTwoDigitsFormat(startTime + i-1)+':00');
						}
					}
				}
			}
		}
	}
	
	function getTwoDigitsFormat(value) {
		if (value < 10) {
			return '0'+value;
		} else {
			return value;
		}
		
	}
	
	function fillTable() {
		for(var i = 0; i < dataObj.length; i++) {
			for(var j = 0; j < dataObj[i].length; j++) {
				if ( dataObj[i][j].getDateData().toString() != 'null' ) {
					var tmp = getDateSelectorDataItem(dataObj[i][j].getDateData());
					try {
						if (tmp) {
							if (!tmp.getIsStudent() && (new Date() < strToDate(dataObj[i][j].getDateData().toString()))) {
								dataObj[i][j].setStatus('free');
								dataObj[i][j].setBgColor('#ffffff');
								
								dataObj[i][j].setCurrDate(tmp);
							} else if(tmp.getIsStudent()) {
								if (new Date() < strToDate(dataObj[i][j].getDateData().toString())) {
									dataObj[i][j].setStatus('active');
									dataObj[i][j].setBgColor(clickedColor);
								
									dataObj[i][j].setCurrDate(tmp);
								} else{
									dataObj[i][j].setStatus('activeOld');
									dataObj[i][j].setBgColor(clickedColor);
								
									dataObj[i][j].setCurrDate(tmp);
								}
							} 
						}
					} 
					catch (e) {
					//TODO alert(e.message);
					}
				}
			}
		}
	}
	
	function strToDate( str ) {
		var temp = new Array();
		temp = str.split(' ');
		var date = temp[0];
		var time = temp[1];
		
		return new Date(new Number(date.split('-')[0]), new Number(date.split('-')[1])-1, new Number (date.split('-')[2]), new Number(time.split(':')[0]-16), new Number(time.split(':')[1]), 0);
	}
	
	function getDateSelectorDataItem( item ) {
		for (var i = 0; i < DateSelectorData.length; i++) {
			if (item.toString() == DateSelectorData[i].getCurrDate().toString()) {
				return DateSelectorData[i];
			}
		}
		return false;
	}
	
	this.changeClass = function( xPosition, yPosition, status ) {
		var row = $(xPosition+'_0');
		var column = $('0_'+yPosition);
		var item = $(xPosition+'_'+yPosition);
		var Obj = getTableItem(xPosition, yPosition);
		
		if (status == 'over') {
			if (Obj.getStatus() == 'inactive' || Obj.getStatus() == 'free') {
				row.style.backgroundColor = overColor;
				column.style.backgroundColor = overColor;
				item.style.backgroundColor = overColor;
			} else {
				row.style.backgroundColor = overColor;
				column.style.backgroundColor = overColor;
				item.style.backgroundColor = clickedOverColor;
			}
		} else {
			if ( Obj.getStatus() == 'inactive' || Obj.getStatus() == 'free') {
				row.style.backgroundColor = getTableItem(xPosition, 0).getBgColor();
				column.style.backgroundColor = getTableItem(0, yPosition).getBgColor();
				item.style.backgroundColor = getTableItem(xPosition, yPosition).getBgColor();
			} else {
				row.style.backgroundColor = getTableItem(xPosition, 0).getBgColor();
				column.style.backgroundColor = getTableItem(0, yPosition).getBgColor();
				item.style.backgroundColor = clickedColor;
			}
		}
	}
	
	this.selectItem = function( xPosition, yPosition ) {
		var Obj = getTableItem(xPosition, yPosition);
		var item = $(xPosition+'_'+yPosition);
		
		if (maxSum > 0) {
			if (Obj.getStatus() == 'free') {
				Obj.setStatus('active');
				item.style.backgroundColor = clickedColor;
				
				this.sendDataToDB(Obj.getDateData(), '+', Obj.getCurrDate().getTeacherId());
				Obj.getCurrDate().setIsStudent(true);
			}
			else {
				Obj.setStatus('free');
				Obj.setBgColor('#ffffff');
				item.style.backgroundColor = Obj.getBgColor();
				
				this.sendDataToDB(Obj.getDateData(), '-', Obj.getCurrDate().getTeacherId());
				Obj.getCurrDate().setIsStudent(false);
			}
		} else {
			engine.dialogManager.add( new Dialog("Nincs már több választási lehetőséged!", "alert") );
		}
	}
	
	this.sendDataToDB = function(pDate, pEvent, pTeacherId) {
		var comm = new CommGateRequest("REQ_ACCESS", [ "ESULI_STUDENT_SET_CHAT" ], function (response){
			var data = response[0].getCommandLine();
			
			if(data[0] == 'ERROR') {
				engine.dialogManager.add( new Dialog(data[1], "alert") );
			}
		});
		comm.addDataLevel([ [ "DATE" ], [ pDate+';'+pEvent+';'+pTeacherId ] ] );
		engine.commGate.sendWithSession([ comm ]);
	}
	
	function getTableItem(xPosition, yPosition) {
		return dataObj[xPosition][yPosition];
	}
	
	this.getDataObj = function() {
		return dataObj;
	}
	
	function getWeek( actualDate ) {
		var actualYearJan = new Date(actualDate.getFullYear(),0,1);
		return Math.ceil((( (actualDate - actualYearJan) / 86400000) + actualYearJan.getDay() )/7);
	}
	
	this.getDataFromDB = function(pageRequest){
		var oldSeq = esuli.contentManager.getSeq();
		
		if (DateSelectorData.length != 0) {
			return true;	
		}
		
		var comm = new CommGateRequest("REQ_ACCESS", [ "ESULI_STUDENT_GET_CHAT" ], function (response){
		    try{
			var data = response[0].getDataAsArray();
			if( data[0] != 'ERROR' ) {
			    data = response[0].getDataAsObjectArray();
			
			    for(var i = 0; i < data.length; i++) {
				maxSum = new Number(data[i].maxsum);

				var tmpArray = dbStrToArray(data[i].datelist);
				
				for(var j = 0; j < tmpArray.length; j++) {
					DateSelectorData.push(new CurrentDate(tmpArray[j][0], tmpArray[j][1], tmpArray[j][2], tmpArray[j][3]));
				}

			    }
			
			    fillTable();
			} else {
			    DateSelectorData.push(new CurrentDate('','','',''));
			}
			
			if (pageRequest != undefined && oldSeq == esuli.contentManager.getSeq()) {
				engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, pageRequest));
			}
		    } catch (e){alert(e.message);}
		});
		//alert('first: ' + firstDate + ' last: '  + lastDate);
		comm.addDataLevel([ [ "FIRST_DATE", "LAST_DATE" ], [ firstDate.getFullYear()+'-'+Number(firstDate.getMonth()+1)+'-'+firstDate.getDate(), lastDate.getFullYear()+'-'+Number(lastDate.getMonth()+1)+'-'+lastDate.getDate() ] ] );
		engine.commGate.sendWithSession([ comm ]);
		
		return false;
	}
	

	function dbStrToArray (pStr) {
	    var wpos = 0;
	    var wArray = new Array();
	

	    if ( !pStr  || !( pStr.replace ) ) return null;
	
	    var str = pStr.replace( '"', '' );
	    str = str.replace ( /'/g, "+#27+" );
	    str = str.replace ( /,/g, "+#2c+" );
	    str = str.replace ( /\n/g, "+#0d+" );
	    str = str.replace ( /\t/g, "+#09+" );
	    str = str.replace ( /\r/g, "+#0a+" );	
	
	    re = /;$/gi;
	    str = str.replace(re,'');
	    re = /\);\(/gi;
	    str = str.replace(re,'"],["');
	    re = /;/gi;
	    str = str.replace(re,'","');
	    re = /\(\(/gi;
	    str = str.replace(re,'[["');
	    re = /\)\)\)\)/gi;
	    str = str.replace(re,'"]]]]');
	    re = /\)\)/gi;
	    str = str.replace(re,'"]]');
	    re = /\(/gi;
	    str = str.replace(re,'["');
	    re = /\)/gi;
	    str = str.replace(re,'"]');
	    re = /\"\[/gi;
	    str = str.replace(re,'[');
	    re = /\]"/gi;
	    str = str.replace(re,']');
	
	    if ( str.substr(0,1) != "[" ) {
	    	wArray = eval ( '["' + str + '"]' );
	    } else {
	    	wArray = eval ( str );
	    }
	
	    for ( var i=0; i < wArray.length; i++ ) {
	        if ( typeof wArray[i] == 'object' && wArray[i].constructor == Array ) {
		    	for (var j = 0; j < wArray[i].length; j++) {
					wArray[i][j] = decodeSpecialCharsFieldValue(wArray[i][j]);
				}
			} else {
		    	wArray[i] = decodeSpecialCharsFieldValue ( wArray[i] );
			}
	    }
	
	    return wArray;
	}
	
	function getFirstDayOfWeek( today ) {
		switch (today.getDay()) {
			case 0:  
					var expdate = today.getDate() - 6;
					today.setDate(expdate);
				break;
			case 2: 
					var expdate = today.getDate() - 1;
					today.setDate(expdate);
				break;
			case 3: 
					var expdate = today.getDate() - 2;
					today.setDate(expdate);
				break;
			case 4: 
					var expdate = today.getDate() - 3;
					today.setDate(expdate);
				break;
			case 5: 
					var expdate = today.getDate() - 4;
					today.setDate(expdate);
				break;
			case 6: 
					var expdate = today.getDate() - 5;
					today.setDate(expdate);
				break;
		}
		return today;
	}
	
	this.navPrevOrNext = function(nav, value) {
		var myDate =  firstDayOfWeek;
		
		if(nav == 'prev') {
			myDate.setDate(myDate.getDate()-value);
		} else {
			myDate.setDate(myDate.getDate()+value);
		}
		
		this.init(myDate);
		fillTable();
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, {module: 'workbook', page: 'exerciseList', levelId: esuli.workbook.levelPage.getCurrentLevelId(), lessonId: esuli.workbook.lessonPage.getCurrentLessonId(), exerciseId: esuli.workbook.exercisePage.getCurrentExerciseId() }));
	}
	
	this.init( getFirstDayOfWeek(new Date()) );

}
/**
 * @author Johnny
 */

function TableItem( pXposition, pYposition, pDataContent, pClassName, pBgColor, pStatus, pDateData ) {
	
	var xPosition = new Number(pXposition);
	var yPosition = new Number(pYposition);
	
	var dataContent = new String(pDataContent);
	var className = new String(pClassName);
	var bgColor = new String(pBgColor);
	var status = new String(pStatus);
	var dateData = new String(pDateData);
	var currDate = new Object();
	
	this.setCurrDate = function( pCurrDate ) {
		currDate = pCurrDate;
	}
	
	this.getCurrDate = function() {
		return currDate;
	}
	
	this.getDateData = function() {
		return dateData;
	}
	
	this.getStatus = function() {
		return status;
	}
	
	this.setStatus = function( pStatus ) {
		status = new String(pStatus);
	}
	
	this.getBgColor = function() {
		return bgColor;
	}
	
	this.setBgColor = function( pColor ) {
		bgColor = new String(pColor);
	}
	
	this.getClassName = function() {
		return className;
	}
	
	this.setClassName = function( pClassName ) {
		className = new String( pClassName );
	}
	
	this.getDataContent = function() {
		return dataContent;
	}
	
	this.getXposition = function() {
		return xPosition;
	}
	
	this.getYposition = function() {
		return yPosition;
	}
	
}
/**
*  @constructor
*/
function Faq(pID, pTitle, pText, pStatus) {
	
	/**
	* Faq id
	* @type Number
	*/
	var id = new Number(pID);
	
	/**
	 * Faq title
	 * @type String
	 */
	var title = new String(pTitle);
	
	/**
	 * Faq text
	 * @type String
	 */
	var text = new String(pText);
	
	/**
	 * Faq status
	 * @type String
	 */
	var status = new String(pStatus);
	
	/**
	 * Return Faq id
	 * @return Faq id
	 * @type Number
	 */
	this.getId = function() {
		return id;
	}
	
	/**
	 * Return Faq title
	 * @return Faq title
	 * @type String
	 */
	this.getTitle = function() {
		return title;
	}
	
	/**
	 * Return Faq text
	 * @return Faq text
	 * @type String
	 */
	this.getText = function() {
		return text;
	}
	
	/**
	 * Return Faq status
	 * @return Faq status
	 * @type String
	 */
	this.getStatus = function() {
		return status;
	}
	
	/**
	 * Set Faq status
	 * @param Faq status
	 * @type String
	 */
	this.setStatus = function(pStatus) {
		status = pStatus;
	}
}
/**
* Faq manager module in esuli
* @constructor
* @author Sperg Adam
 */
function FaqManager() {
	
	/**
	 * Last visited page
	 * @type Object
	 */
	var lastPage = new Object();
	
	/**
	 * Is faq downloaded
	 * @type Boolean
	 */
	var faqDownloaded = false;
	
	/**
	 * Faq array
	 * @type Array
	 */
	var faq = new Array();
	
	/**
	 * Opened Faq id
	 * @type Number
	 */
	var activeFaqId = -1;
	
	/**
	 * Pointer to this
	 * @type FaqManager
	 */
	var self = this;
	
	/**
	 * Loads faq from database
	 */
	function loadFaq() {		
		var comm = new CommGateRequest("REQ_SELECT", [ "ESULI_GET_FAQ" ], 
			function(pResponse) {
				var data = pResponse[0].getDataAsObjectArray();
				var faqObj;
				for (var i = 0; i < data.length; i++) {
					faqObj = new Faq(data[i].id, data[i].title, data[i].text, 'inactive');
					if(activeFaqId == -1) {
						activeFaqId = faqObj.getId();
						faqObj.setStatus('active');
					}
					faq.push(faqObj);
				}
				faqDownloaded = true;

				if (esuli.tab.activeTab == "Asztal" && esuli.tab.activeSubMenuId == 1) {
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
			}
		});
		
		comm.addDataLevel([ [ "" ],[ "" ] ]);
		engine.commGate.sendWithSession([ comm ]);
	 }
	
	/**
	 * Get Faq by id
	 * @param Faq id
	 * @type String
	 * @return Faq object
	 */
	this.getFaq = function(pId) {
		for(var i = 0; i < faq.length; i++) {
			if(faq[i].getId() == pId) {
				return faq[i];
				break;
			}
		}
		return false;
	}
	
	/**
	 * Show / Hide faq
	 * @param Faq id to show
	 * @type String
	 */
	this.showHideFaq = function( pId ) {
		if(!pId || !self.getFaq(pId)) {
			return;
		}
		self.getFaq(activeFaqId).setStatus('inactive');
		var hideFaqHead = $("faqHead_" + activeFaqId);
		hideFaqHead.className = "faqHead";
		var hideFaqContent = $("faqContent_" + activeFaqId);
		hideFaqContent.style.display = "none";
		
		self.getFaq(pId).setStatus('active');
		var showFaqHead = $("faqHead_" + pId);
		showFaqHead.className = "faqHeadOpened";
		var ahowFaqContent = $("faqContent_" + pId);
		ahowFaqContent.style.display = "block";
		activeFaqId = pId;
	}
	
	/**
	 * Returns requested page
	 * @param Object Page request
	 * @return Requested page
	 * @type Object
	 */
	this.getPage = function(pageRequest) {
		if (! check(pageRequest)) {
			//TODO: Log error
			return;
		}

		var page = { leftWidth: "64%", rightWidth: "35%", left: "", right: "" };

		switch (pageRequest.get("page").toString()) {

			case "faq":
				if(!faqDownloaded) {
					page.left = engine.templateManager.getTemplate("spin").process({});
					loadFaq();
				} else {
					page.left = engine.templateManager.getTemplate("static_kerdesekesvalaszok").process({ faq: faq });
				}
				break;

			default:
				//TODO: Log error
				return;
		}

		lastPage = pageRequest;

		return page;
	}

	/**
	 * Returns last visited page
	 * @return Last visited page
	 * @type Object
	 */
	this.getLastPage = function() {
		self.getPage(lastPage);
	}
}
/**
* @constructor
* @author Morr
*/
function Gadget(pID, pName, pDiv, pTab, pSeq, pType, pContent) {
	
	/**
	* Gadget id
	* @type Number
	*/
	var id = new Number(pID);
	
	/**
	 * Gadget name (title)
	 * @type String
	 */
	var name = new String(pName);
	
	/**
	 * Gadget div
	 * @type String
	 */
	var div = new String(pDiv);
	
	/**
	 * Gadget tab
	 * @type String
	 */
	var tab = new String(pTab);
	
	/**
	 * Gadget sequence
	 * @type String
	 */
	var seq = new Number(pSeq);
	
	/**
	 * Gadget type
	 * @type String
	 */
	var type = new String(pType);
	
	/**
	 * Gadget content
	 * @type Array
	 */
	var content = new Array(pContent);
	
	/**
	 * Return gadget id
	 * @return Return id
	 * @type Number
	 */
	this.getId = function() {
		return id;
	}
	
	/**
	 * Return gadget name (title)
	 * @return Return name
	 * @type String
	 */
	this.getName = function() {
		return name;
	} 
	
	/**
	 * Return gadget div
	 * @return Return Div
	 * @type String
	 */
	this.getDiv = function() {
		return div;
	}
	
	/**
	 * Return gadget tab
	 * @return Return Tab
	 * @type String
	 */
	this.getTab = function() {
		return tab;
	}
	
	/**
	 * Return gadget sequence
	 * @return Return Sequence
	 * @type Number
	 */
	this.getSeq = function() {
		return seq;
	}
	
	/**
	 * Return gadget type
	 * @return Return Type
	 * @type String
	 */
	this.getType = function() {
		return type;
	}
	
	/**
	 * Return gadget content
	 * @return Return Content
	 * @type Array
	 */
	this.getContent = function(pAll) {
		if(typeof(content) == 'object' && !pAll) {
			var random = Math.floor(Math.random() * content.length);
			return content[random];
		} else {
			return content;
		}
	}
	
	/**
	 * Set gadget content
	 * @param Content
	 * @type Array
	 */
	this.setContent = function(pContent) {
		content = pContent;
	}
}
/**
 * Gadgetek kezelése
 *
 * @constructor
 * @author Morr
 */
function GadgetManager() {
	
	/**
	 * Pointer to this
	 * @type MessageManager
	 */
	var self = this;
	
	/**
	 * Gadgets array
	 * @type Array
	 * name, div, tab, seq, type, html
	 */
	var gadgets = new Array();
	
	/**
	 * Gadget types db called
	 * @type Array
	 */
	var calledDbType = new Array();
	
	/**
	 * Gadget types downloaded form db
	 * @type Array
	 */
	var downloadedDbType = new Array();
	
	/**
	 * All basic gadget information is downloaded form db
	 * @type Boolean
	 */
	var gadgetsDownloaded = false;
	
	/**
	 * Get all gadget
	 * @return Gadgets Array
	 */
	this.getGadgets = function() {
		if(gadgetsDownloaded && (calledDbType.length == downloadedDbType.length)) {
			return gadgets;
		} else {
			return false;
		}
	}
	
	/**
	 * Get template name for given type
	 * @param String Gadget type
	 * @return String Gadget template name
	 */
	this.getTemplateName = function(pType) {
		var templateName;
		switch( pType.toString() ) {
		    case 'tanár':
				templateName = 'teacher';
				break;
			case 'rólunkírták':
				templateName = 'forus';
				break;
		    case 'iskolák':
		    case 'ügynök':
				templateName = 'agent';
				break;
			case 'statikus html':
				templateName = 'html';
				break;
		}
		return templateName;
	}
	
    /**
     * Get gadgets information from DB
     */
	function getGadgetFromDB() {
	    if (engine.cookieManager.get("agent")) {
			var	comm = new CommGateRequest("REQ_SELECT", [ "ESULI_GET_GADGETS" ], getGadgetFromDBCallback);
			comm.addDataLevel([ [ "AGENT", "", "" ], [ engine.cookieManager.get("agent"), "", "" ] ]);
			engine.commGate.sendWithSession([ comm ]);
	    } else if (engine.cookieManager.get("interface")) {
            var comm = new CommGateRequest("REQ_SELECT", [ "ESULI_GET_GADGETS" ], getGadgetFromDBCallback);
            comm.addDataLevel([ [ "INTERFACE", "", "" ], [ engine.cookieManager.get("interface"), "", "" ] ]);
            engine.commGate.sendWithSession([ comm ]);
        }
		else {
			var	comm = new CommGateRequest("REQ_SELECT", [ "ESULI_GET_GADGETS" ], getGadgetFromDBCallback);
			comm.addDataLevel([ [ "", "", "" ], [ "", "", "" ] ]);
			engine.commGate.sendWithSession([ comm ]);
	    }
	}
	
	/**
	 * Get gadgets information from DB
	 * response
	 * "NAME","DIV","TAB","SEQ","TYPE","HTML"
	 */
	function getGadgetFromDBCallback( pResponse ) {
		var cmd;
		var data;
		
		for(var i = 0; i < pResponse.length; i++) {
			cmd = pResponse[i].getCommandLine();
			if((cmd) && (cmd[i]) && (cmd[1] == 'RES_DATA')) {
				data = pResponse[i].getDataAsObjectArray();
				if(data) break;
			}
		}
		
		if(data) {
			for( var i = 0; i < data.length; i++ ) {
				if(data[i].type == 'statikus html') {
					var gadget = new Gadget(i, data[i].name, data[i].div, data[i].tab, data[i].seq, data[i].type, data[i].html);
				} else if(!isTypeDownloaded(data[i].type) && !isTypeDownloading(data[i].type)) {
					calledDbType.push(data[i].type);
					var gadget = new Gadget(i, data[i].name, data[i].div, data[i].tab, data[i].seq, data[i].type, new Array());
					getTypeGadgetFromDb(data[i].type);
				} else if(!isTypeDownloaded(data[i].type) && isTypeDownloading(data[i].type)) {
					var gadget = new Gadget(i, data[i].name, data[i].div, data[i].tab, data[i].seq, data[i].type, new Array());
				} else {
					var gadget = new Gadget(i, data[i].name, data[i].div, data[i].tab, data[i].seq, data[i].type, self.getTypeGadgetContent(data[i].type));
				}
				gadgets.push(gadget);
			}
			gadgetsDownloaded = true;
		}
	}
	
	/**
	 * Is given type gadget download in progress
	 * @param String Type
	 * @return Boolean true if gadget type download in progress
	 */
	function isTypeDownloading(pType) {
		for(var i = 0; i < calledDbType.length; i++) {
			if(calledDbType[i] == pType) {
				return true;
				break;
			}
		}
		return false;
	}
	
	/**
	 * Is given type gadget downloaded
	 * @param String Type
	 * @return Boolean true if gadget type is downloaded
	 */
	function isTypeDownloaded(pType) {
		for(var i = 0; i < downloadedDbType.length; i++) {
			if(downloadedDbType[i] == pType) {
				return true;
				break;
			}
		}
		return false;
	}
	
	/**
	 * Get gadget type content form db
	 * @param String Gadget type
	 */
	function getTypeGadgetFromDb(pType) {
		var dbProc = '';
		var dataLevel;
		var content = new Array();
		switch( pType ) {
		    case 'tanár':
				dbProc = 'ESULI_GET_TEACHER_GADGET_INFO';
				dataLevel = [ [ '', '','' ], [ '', '', '' ] ];
				break;
			case 'rólunkírták':
				dbProc = 'ESULI_GET_FORUS_GADGET_INFO';
				dataLevel = [ [ '', '','' ], [ '', '', '' ] ];
				break;
		    case 'iskolák':
				dbProc = 'ESULI_GET_PARTNER_AGENTS';
				dataLevel = [ [ 'NAME', 'TYPE','' ], [ engine.cookieManager.get('agent'), 'iskola', '' ] ];
				break;
		    case 'ügynök':
				dbProc = 'ESULI_GET_AGENT_GADGET_INFO';
				dataLevel = [ [ 'AGENT', '', '' ], [ engine.cookieManager.get('agent'), '', '' ] ];
				break;
		}
		
		comm = new CommGateRequest(
			"REQ_SELECT",
			[ dbProc ],
			function( pResponse ) {
				var cmd;
				var data;
				for( var i = 0; i < pResponse.length; i++ ) {
					cmd = pResponse[i].getCommandLine();
					if ( ( cmd ) && ( cmd[i] ) && ( cmd[1] == 'RES_DATA' ) ) {
						data = pResponse[i].getDataAsObjectArray();
						if ( data ) break;
					}
				}
				if ( data ) {
					content = data;
				}
				
				for(var i = 0; i < gadgets.length; i++) {
					if(gadgets[i].getType() == pType) {
						gadgets[i].setContent(content);
					}
				}
				
				downloadedDbType.push(pType);
			}
		);
		comm.addDataLevel ( dataLevel );
		engine.commGate.sendWithSession ( [ comm ] );
	}
	
	/**
	 * Get given type gadget content
	 * @param String Gadget type
	 * @return Array Gadget content
	 */
	this.getTypeGadgetContent = function(pType) {
		for(var i = 0; i < gadgets.length; i++) {
			if(gadgets[i].getType() == pType) {
				return gadgets[i].getContent(true);
				break;
			}
		}
	}

	/**
	 * Send error report
	 */
	this.errorReport = function() {
		var tabName = esuli.tab.getTabName( esuli.tab.activeTabId );
		var subName = esuli.tab.getSubMenuName( esuli.tab.activeTabId, esuli.tab.activeSubMenuId );
		var actualPage = esuli.contentManager.getLastPage().get("page");

		var message = "";
			message += "Felhasználói hiba bejelentés." + "\n\n"
			 + "Bejelentő e-mail címe: " + esuli.user.getEmail() + "\n\n"
			 + "A hibát a következő oldalon találta:" + "\n"
			 + "Tab menu: " + tabName + "\n"
			 + "Sub menu: " + subName + "\n"
			 + "Page: " + actualPage;

		var error = $('errorReport');
		if(error && error.value != '') {
			message += "\n\n" + "A hiba leírása: " + error.value;
			error.value = "";
		}

		engine.commGate.send([ new CommGateRequest("SEND_EMAIL", [ "info@enyelviskola.hu", message, "Felhasználói hiba bejelentés" ], null ), new CommGateRequest("HAVE_SESSION", [ esuli.user.getSessionId() ], null ) ] );
		engine.dialogManager.add(new Dialog("Köszönjük, munkatársunk hamarosan ellenőrzi az oldalt!", "alert", null));
	}

	this.sendAkcioMessage = function() {
		var senderName = $('senderName') ? $('senderName').value : esuli.user.getNickname();
		var friendName = $('friendName').value;
		var friendEmail = $('friendEmail').value;
		var friendMessage = $('friendMessage').value;

		var message = "Kedves " + friendName + "!\n\n" +
						senderName + " üzenetet küldött neked az eNyelviskola.hu akciójáról.\n" +
						"Az akcióról további információt itt találsz: http://www.enyelviskola.hu/lakossagi_akciok\n\n" +
						friendMessage + "\n\n" +
						"eNyelviskola.hu - Élvezd az angolt, bárhol, bármikor!\n" +
						"   http://www.eNyelviskola.hu";

		engine.commGate.send([new CommGateRequest("SEND_EMAIL", [friendName + "<" + friendEmail + ">", message, senderName + ": eNyelviskola.hu akció", "info@enyelviskola.hu"], null)]);
		engine.dialogManager.add(new Dialog("Az üzenetet elküldtük barátodnak!", "alert", null));

		$('friendName').value = '';
		$('friendEmail').value = '';
		$('friendMessage').value = '';
	}

	// init, get gadgets form db
	getGadgetFromDB();
}
/**
*  @constructor
* @author Johnny
*/
function Message(pID, pDate, pSender, pRecipient, pSubject, pMessage, pState, pFolder) {
	
	/**
	 * Üzenet meg van-e jelenítve, default false
	 * @type Boolean
	 */
	var opened = false;
	
	/**
	* Üzenet id
	* @type Number
	*/
	var id = new Number(pID);
	
	/**
	 * Üzenet dátuma
	 * @type String
	 */
	var messageDate = new String(pDate);
	
	/**
	 * Üzenet Küldője
	 * @type String
	 */
	var sender = new String(pSender);
	
	/**
	 * Üzenet fogadója
	 * @type String
	 */
	var recipient = new String(pRecipient);
	
	/**
	 * Üzenet tárgy
	 * @type String
	 */
	var subject = new String(pSubject);
	
	/**
	 * Üzenet
	 * @type String
	 */
	var message = new String(pMessage);
	
	/**
	 * Üzenet állápota
	 * @type String
	 */
	var state = new String(pState);
	
	/**
	 * Üzenet mappa
	 * @type String
	 */
	var folder = new String(pFolder);
	
	/**
	 * Visszaadja az Üzenet id-jét
	 * @return Üzenet id
	 * @type Number
	 */
	this.getId = function() {
		return id;
	}
	
	/**
	 * Visszaadja az Üzenet dátumát
	 * @return Üzenet dátum
	 * @type Date
	 */
	this.getDate = function() {
		return messageDate;
	} 
	
	/**
	 * Visszaadja az Üzenet dátumát megformázva
	 * @return Üzenet dátum megformázva
	 * @type Date
	 */
	this.getFormedDate = function() {
		var formedDate = messageDate;
		re = /-/gi;
		formedDate = formedDate.replace(re,'.');
		formedDate = formedDate.substring(0,19);
		return formedDate;
	}
	
	/**
	 * Visszaadja az Üzenet küldőjét
	 * @return Üzenet küldője
	 * @type String
	 */
	this.getSender = function() {
		return sender;
	}
	
	/**
	 * Visszaadja az Üzenet címzettje
	 * @return Üzenet címzettje
	 * @type String
	 */
	this.getRecipient = function() {
		return recipient;
	}
	
	
	/**
	 * Visszaadja az Üzenet témája
	 * @return Üzenet témája
	 * @type String
	 */
	this.getSubject = function() {
		return subject;
	}
	
	/**
	 * Visszaadja az Üzenetet
	 * @return Üzenet
	 * @type String
	 */
	this.getMessage = function() {
		return message;
	}
	
	/**
	 * Visszaadja az Üzenet státusza
	 * @return Üzenet státusz
	 * @type String
	 */
	this.getState = function() {
		return state;
	}
	
	/**
	 * Beállítja az Üzenet státusza
	 * @param String
	 */
	this.setState = function(pValue) {
		state = new String(pValue);
	}
	
	/**
	 * Visszaadja az Üzenet mappája
	 * @return Üzenet mappája
	 * @type String
	 */
	this.getFolder = function() {
		return folder;
	}
	
	/**
	 * Visszaadja hogy az Üzenet nyitott-e
	 * @return Üzenet nyitott-e
	 * @type Boolean
	 */
	this.isOpened = function() {
		return opened;
	}
	
	/**
	 * Beállítja hogy az Üzenet nyitott-e
	 * @param Boolean
	 */
	this.setOpened = function( value ) {
		opened = value;
	}
	
}
/**
 * Message manager module in esuli
 * @constructor
 * @author Robi
 */
function MessageManager() {
	
	/**
	 * Last visited page
	 * @type Object
	 */
	var lastPage = new Object();
	
	/**
	 * Is messages downloaded
	 * @type Boolean
	 */
	var messagesDownloaded = false;
	
	/**
	 * Incoming messages array
	 * @type Array
	 */
	var incoming = new Array();
	
	/**
	 * Outgoing messages array
	 * @type Array
	 */
	var outgoing = new Array();
	
	/**
	 * Pointer to this
	 * @type MessageManager
	 */
	var self = this;
	
	/**
	 * Loads messages from database
	 */
	function loadMessages() {		
		var comm = new CommGateRequest("REQ_ACCESS", [ "ESULI_GET_MESSAGES" ], function(response) {
		    incoming = new Array();
		    outgoing = new Array();
		    
			var data = response[0].getDataAsObjectArray();
		    var message;
		    
		    for (var i = 0; i < data.length; i++) {
	    		message = new Message(data[i].id, data[i].date, data[i].sender, data[i].recipient, data[i].subject, data[i].message, data[i].state, data[i].folder);
				
		    	if (message.getFolder() == "SENT") {
		    		outgoing.push(message);
					message.setState("Olvasott");
		    	} else if (message.getFolder() == "INBOX") {
		    		incoming.push(message);
		    	}
		    }
		    
		    messagesDownloaded = true;
		    
			if (esuli.tab.activeTab == "Asztal" && esuli.tab.activeSubMenuId == 4) {
			    engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
			}
		});
		
		comm.addDataLevel([ [ "" ],[ "" ] ]);
		engine.commGate.sendWithSession([ comm ]);
	 }

	/**
	 * Returns requested page
	 * @param Object Page request
	 * @return Requested page
	 * @type Object
	 */
	this.getPage = function(pageRequest) {
		if (! check(pageRequest)) {
			//TODO: Log error
			return;
		}
		
		var page = { leftWidth: '372px', centerWidth: '371px', rightWidth: '225px', left: '', center: '', right: '' };
		
		switch (pageRequest.get("page").toString()) {
			
			case "allMessages":
					var lastoutid = outgoing.length > 0 ? outgoing[outgoing.length - 1].getId() : 0;
					var lastincid = incoming.length > 0 ? incoming[incoming.length - 1].getId() : 0;
					page.leftTop = engine.templateManager.getTemplate("messages_sendmessage").process({});
					page.left = engine.templateManager.getTemplate("messages_outgoing").process({outgoing: outgoing, messagesDownloaded: messagesDownloaded, lastid: lastoutid});
					page.center = engine.templateManager.getTemplate("messages_incoming").process({incoming: incoming, messagesDownloaded: messagesDownloaded, lastid: lastincid});
				break;
			
			default:
				//TODO: Log error
				return;
		}
		
		lastPage = pageRequest;
		
		return page;
	}
	
	/**
	 * Returns last visited page
	 * @return Last visited page
	 * @type Object
	 */
	this.getLastPage = function() {
		self.getPage(lastPage);
	}
	
	/**
	 * Send a new message
	 */
	this.sendMessage = function(pRecipient, pSubject, pMessage) {
		var recipient = $('message_recipient');
		var subject = $('message_subject');
		var message = $('message_message');

		subject.className = 'normalTextInput';
		message.className = 'normalTextarea';

		if(esuli.staticContent.trimTextInput(subject.value) == '') {
			subject.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Nem adtad meg az üzenet tárgyát!', 'alert'));
			return;
		}
		
		if(esuli.staticContent.trimTextInput(message.value) == '') {
			message.className = 'normalTextareaError';
			engine.dialogManager.add(new Dialog('Nem írtál üzenetet!', 'alert'));
			return;
		}
		
		var comm = new CommGateRequest("REQ_ACCESS", 
			[ "ESULI_SEND_MESSAGE" ], 
			function(response) {
				var data = response[0].getDataAsObjectArray();
				
				if ( data[0].id ) {
					engine.dialogManager.add(new Dialog("Az üzenetet elküldtük.", "alert"));
					outgoing.push(new Message(data[0].id, data[0].date, data[0].sender, data[0].recipient, data[0].subject, data[0].message, "Olvasott", data[0].folder));
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
				} else {
					engine.dialogManager.add(new Dialog("Az üzeneted sajnos nem kézbesítődött, kérjük próbáld meg később.", "alert"));
				}
			});
			
		comm.addDataLevel([ [ "RECIPIENT", "SUBJECT", "MESSAGE" ], [ recipient.value, subject.value, message.value ] ]);
		engine.commGate.sendWithSession([ comm ]);
	}
	
	/**
	 * Send user question
	 */
	this.sendUserQuestion = function() {
		var question = $('userQuestion');
		
		if(esuli.staticContent.trimTextInput(question.value) == '') {
			question.className = 'normalTextareaError';
			engine.dialogManager.add(new Dialog('Nem írtál kérdést!', 'alert'));
			return;
		}
		
		var comm = new CommGateRequest("REQ_ACCESS", 
			[ "ESULI_SEND_MESSAGE" ], 
			function(response) {
				var data = response[0].getDataAsObjectArray();
				
				if ( data[0].id ) {
					engine.dialogManager.add(new Dialog("A üzenetet megkaptuk, hamarosan válaszolunk rá!", "alert"));
					outgoing.push(new Message(data[0].id, data[0].date, data[0].sender, data[0].recipient, data[0].subject, data[0].message, "Olvasott", data[0].folder));
					question.value = "";
				} else {
					engine.dialogManager.add(new Dialog("Az kérdésed sajnos nem kézbesítődött, kérjük próbáld meg később.", "alert"));
				}
			});
			
		comm.addDataLevel([ [ "RECIPIENT", "SUBJECT", "MESSAGE" ], [ 'info@enyelviskola.hu', 'Kérdés', question.value ] ]);
		engine.commGate.sendWithSession([ comm ]);
	}

	/**
	 * Reply Message
	 * @param Number Message id
	 */
	this.replyMessage = function(mId) {
		var messageSubject = $("message_subject");
		var messageTexarea = $("message_message");
		var messageRecipient = $("message_recipient");
		for (var i = 0; i < incoming.length; i++) {
			if (incoming[i].getId() == mId) {
				messageSubject.value = "Re: " + incoming[i].getSubject();
				messageTexarea.innerHTML = "\n" + "\n"
										+ "----- ----- -----"
										+ "\n" 
										+ "On " 
										+ incoming[i].getFormedDate() 
										+ ", " 
										+ incoming[i].getSender() 
										+ " wrote:" 
										+ "\n" 
										+ "----- ----- -----"
										+ "\n" 
										+ incoming[i].getMessage();
				messageRecipient.focus();
				break;
			}
		}
	}

	/**
	 * Gets messages after user login
	 * @param Object event
	 */
	this.listenUserLogin = function(event) {
		if (esuli.user.getRole() == "student") {
		    loadMessages();
		} else {
		    incoming = new Array();
		    outgoing = new Array();
		    messagesDownloaded = true;
		}
	}
	
	/**
	 * Show / Hide messages content
	 * @param Number Message id
	 * @param String Message folder
	 * @param String Message status
	 */
	this.showHideMessage = function(messageId, folder, state) {
		var messageDiv = $("message_" + folder + "_" + messageId);

		if (folder == "incoming") {
			for (var i = 0; i < incoming.length; i++) {
				if (incoming[i].getId() == messageId){
					if (state == "Olvasatlan") {
						incoming[i].setState("Olvasott");
						setMessageState(incoming[i].getId(), "Olvasott");
					}
					
					incoming[i].setOpened(!incoming[i].isOpened());
					break;
				}
			}
		} else {
			for (var i = 0; i < outgoing.length; i++) {
				if (outgoing[i].getId() == messageId){
					outgoing[i].setOpened(!outgoing[i].isOpened());
					break;
				}
			}
		}

		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
	}
    
	/**
	 * Set message state
	 * @param Number Message 
	 * @param String Message state
	 */
	function setMessageState( messageId, state ) {
		var command = new CommGateRequest("REQ_ACCESS", [ "ESULI_SET_MESSAGE_STATE" ]);
		command.addDataLevel([ [ "AUTOB_Üzenet_ID", "STATE" ], [ messageId, state ] ]);
		
		engine.commGate.sendWithSession([ command ]);
	}
	
	/**
	 * Remove message
	 * @param Number Message Id
	 * @param String Message folder
	 * @param Boolean Force removing
	 */
	this.removeMessage = function(messageId, folder, force) {
		if(!force) {
			engine.dialogManager.add(new Dialog(
				"Biztosan törölni akarod?",
				"confirm",
				[ null, function () { self.removeMessage(messageId, folder, true); }, null ],
				[ "", "Igen", "Nem" ])
				);
			return;
		}
		var command = new CommGateRequest("REQ_ACCESS", [ "ESULI_DELETE_MESSAGE" ],function(response) {
			var data = response[0].getDataAsArray();
			
			if (data[0][1] == "SUCCESS") {
				if ( folder == "incoming") {
					for(var i = 0; i < incoming.length; i++) {
						if (incoming[i].getId() == messageId ){
							incoming.splice(i,1);
							engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
						}
					}
				} else {
					for(var i = 0; i < outgoing.length; i++) {
						if (outgoing[i].getId() == messageId) {
							outgoing.splice(i,1);
							engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
						}
					}
				}
			} else {
				//TODO: log
			}		
		});
		
		command.addDataLevel([ [ "AUTOB_Üzenet_ID", "FOLDER" ], [ messageId, folder ] ]);
		engine.commGate.sendWithSession([ command ]);
	}
	
	//Initialize
	engine.eventManager.addListener(EventManager.EVENT_USER_LOGIN, this);
    
}
var notReadyLessons = new Object();

notReadyLessons["A1-1"] = new Array();
notReadyLessons["A1-1"][11] = "Different People With Different Occupations";
notReadyLessons["A1-1"][12] = "Weather";
notReadyLessons["A1-1"][13] = "Disasters";
notReadyLessons["A1-1"][14] = "Holidays";
notReadyLessons["A1-1"][15] = "Life Is Great";
notReadyLessons["A1-1"][16] = "Advert Mania";
notReadyLessons["A1-1"][17] = "Neck and Neck";
notReadyLessons["A1-1"][18] = "Home, Sweet Home!";
notReadyLessons["A1-1"][19] = "Life On A Submarine";
notReadyLessons["A1-1"][20] = "Weekend! At Last!";
notReadyLessons["A1-1"][21] = "Animal Parade";
notReadyLessons["A1-1"][22] = "Sports Around the Globe";
notReadyLessons["A1-1"][23] = "Inventors and Inventions";
notReadyLessons["A1-1"][24] = "Space Adventure";
notReadyLessons["A1-1"][25] = "Let's Travel";
notReadyLessons["A1-1"][26] = "Story Time";
notReadyLessons["A1-1"][27] = "Once Upon a Time";
notReadyLessons["A1-1"][28] = "Row, row, row your boat";
notReadyLessons["A1-1"][29] = "Fascinating Fashion";
notReadyLessons["A1-1"][30] = "The Globe-trotter";

notReadyLessons["A1-2"] = new Array();
notReadyLessons["A1-2"][11] = "Christina Ricci";
notReadyLessons["A1-2"][12] = "A Disappointed Letter";
notReadyLessons["A1-2"][13] = "Customs and Habits";
notReadyLessons["A1-2"][14] = "Holiday Precaution";
notReadyLessons["A1-2"][15] = "Always Fashion";
notReadyLessons["A1-2"][16] = "Insights into British Family life";
notReadyLessons["A1-2"][17] = "Student Work";
notReadyLessons["A1-2"][18] = "Driving in Britain";
notReadyLessons["A1-2"][19] = "Green Environment";
notReadyLessons["A1-2"][20] = "Different Lifestyles";
notReadyLessons["A1-2"][21] = "Terrorism";
notReadyLessons["A1-2"][22] = "Ernest Hemingway";
notReadyLessons["A1-2"][23] = "Sea-life";
notReadyLessons["A1-2"][24] = "China";
notReadyLessons["A1-2"][25] = "Our Body";
notReadyLessons["A1-2"][26] = "Writing... what?";
notReadyLessons["A1-2"][27] = "Without Home";
notReadyLessons["A1-2"][28] = "I Don't Feel Good";
notReadyLessons["A1-2"][29] = "Against the Law";
notReadyLessons["A1-2"][30] = "Have You Been To England?";

notReadyLessons["A2-1"] = new Array();
notReadyLessons["A2-1"][11] = "Surviving A Disaster";
notReadyLessons["A2-1"][12] = "A Famous Computer Guru";
notReadyLessons["A2-1"][13] = "A Yummy Recipe";
notReadyLessons["A2-1"][14] = "What Do You Need For A Picnic?";
notReadyLessons["A2-1"][15] = "Pizza á la Complicated";
notReadyLessons["A2-1"][16] = "Ninety Days for Your Health";
notReadyLessons["A2-1"][17] = "Life in the Countryside";
notReadyLessons["A2-1"][18] = "What IQ Tests Measure";
notReadyLessons["A2-1"][19] = "Chocolate Comes First";
notReadyLessons["A2-1"][20] = "The Wedding";
notReadyLessons["A2-1"][21] = "Fashion Craze";
notReadyLessons["A2-1"][22] = "Movie Stars";
notReadyLessons["A2-1"][23] = "Life is Extreme";
notReadyLessons["A2-1"][24] = "The World of Art";
notReadyLessons["A2-1"][25] = "The World of Records";
notReadyLessons["A2-1"][26] = "Hotel Holiday";
notReadyLessons["A2-1"][27] = "And Action!";
notReadyLessons["A2-1"][28] = "Sounds of Music";
notReadyLessons["A2-1"][29] = "Who Is The Murderer?";
notReadyLessons["A2-1"][30] = "New Life in New Orleans";

notReadyLessons["A2-2"] = new Array();
notReadyLessons["A2-2"][11] = "Our Environment";
notReadyLessons["A2-2"][12] = "Finding a Job";
notReadyLessons["A2-2"][13] = "Enercon E66";
notReadyLessons["A2-2"][14] = "William Shakespeare";
notReadyLessons["A2-2"][15] = "Useful Things";
notReadyLessons["A2-2"][16] = "Cheese";
notReadyLessons["A2-2"][17] = "Waking Up In The Morning";
notReadyLessons["A2-2"][18] = "Pets Around";
notReadyLessons["A2-2"][19] = "Different Cultures";
notReadyLessons["A2-2"][20] = "Social Events";
notReadyLessons["A2-2"][21] = "UFOs";
notReadyLessons["A2-2"][22] = "Following The Clues";
notReadyLessons["A2-2"][23] = "Flora, Fauna and Landscape";
notReadyLessons["A2-2"][24] = "The King's Court";
notReadyLessons["A2-2"][25] = "Do You Remember Well?";
notReadyLessons["A2-2"][26] = "On Board!";
notReadyLessons["A2-2"][27] = "The Merchant of Baghdad";
notReadyLessons["A2-2"][28] = "The Merchant of Baghdad II.";
notReadyLessons["A2-2"][29] = "The Merchant of Baghdad";
notReadyLessons["A2-2"][30] = "Hair Today";

notReadyLessons["B1-1"] = new Array();
notReadyLessons["B1-1"][11] = "Music";
notReadyLessons["B1-1"][12] = "Books and Reading";
notReadyLessons["B1-1"][13] = "Environment for Children";
notReadyLessons["B1-1"][14] = "Being Disabled";
notReadyLessons["B1-1"][15] = "Traffic In Towns";
notReadyLessons["B1-1"][16] = "Cities and Slums";
notReadyLessons["B1-1"][17] = "My Love: Ireland";
notReadyLessons["B1-1"][18] = "Weather";
notReadyLessons["B1-1"][19] = "Hotels";
notReadyLessons["B1-1"][20] = "On the Phone";
notReadyLessons["B1-1"][21] = "Being Professional";
notReadyLessons["B1-1"][22] = "Addictions";
notReadyLessons["B1-1"][23] = "Coffee";
notReadyLessons["B1-1"][24] = "Sticky Problems";
notReadyLessons["B1-1"][25] = "Shopping Addictions";
notReadyLessons["B1-1"][26] = "Finding a Job";
notReadyLessons["B1-1"][27] = "A Letter of Complaint";
notReadyLessons["B1-1"][28] = "Problems with Comprehension?";
notReadyLessons["B1-1"][29] = "Fear of Age and Lies";
notReadyLessons["B1-1"][30] = "A Famous Film Director";

notReadyLessons["B1-2"] = new Array();
notReadyLessons["B1-2"][11] = "Tools";
notReadyLessons["B1-2"][12] = "Boys in Hollywood";
notReadyLessons["B1-2"][13] = "Five Days on Coral Island";
notReadyLessons["B1-2"][14] = "Bad Luck";
notReadyLessons["B1-2"][15] = "Surprise, surprise";
notReadyLessons["B1-2"][16] = "Half Truths";
notReadyLessons["B1-2"][17] = "Your Home Budget";
notReadyLessons["B1-2"][18] = "Hoax";
notReadyLessons["B1-2"][19] = "Education or Learning?";
notReadyLessons["B1-2"][20] = "Applying for a Job";
notReadyLessons["B1-2"][21] = "Domestic Males";
notReadyLessons["B1-2"][22] = "Sea Life";
notReadyLessons["B1-2"][23] = "On the Go";
notReadyLessons["B1-2"][24] = "There's No Accounting For Taste";
notReadyLessons["B1-2"][25] = "Aviation";
notReadyLessons["B1-2"][26] = "Business Lifestyles";
notReadyLessons["B1-2"][27] = "Celebs";
notReadyLessons["B1-2"][28] = "Love!";
notReadyLessons["B1-2"][29] = "Rafting?";
notReadyLessons["B1-2"][30] = "Letter Writing";

notReadyLessons["B2-1"] = new Array();
notReadyLessons["B2-1"][11] = "Heavy and Light Industry";
notReadyLessons["B2-1"][12] = "Robotics";
notReadyLessons["B2-1"][13] = "Swan of Avon";
notReadyLessons["B2-1"][14] = "Are You House-proud?";
notReadyLessons["B2-1"][16] = "Eagle-eyed";
notReadyLessons["B2-1"][17] = "For Goodness";
notReadyLessons["B2-1"][18] = "On TV";
notReadyLessons["B2-1"][19] = "Britain, Britain";
notReadyLessons["B2-1"][20] = "Home, Sweet Home";
notReadyLessons["B2-1"][21] = "Wild West";
notReadyLessons["B2-1"][22] = "It's a Dog-eat-dog World";
notReadyLessons["B2-1"][23] = "Extraterrestial";
notReadyLessons["B2-1"][24] = "Be Airborne";
notReadyLessons["B2-1"][25] = "The Human Genome";
notReadyLessons["B2-1"][26] = "Are You an Environmentalist?";
notReadyLessons["B2-1"][27] = "The European Union";
notReadyLessons["B2-1"][28] = "Are You Sporty?";
notReadyLessons["B2-1"][29] = "It's Disastrous";
notReadyLessons["B2-1"][30] = "Enter Into Politics";
notReadyLessons["B2-1"][15] = "Sick as a Dog";
/**
 * Not logged in functions
 * @constructor
 */
function PreFunction() {
	
	/**
	 * Pointer to this
	 * @type PreFunction
	 */
	var self = this;
	
	/**
	 * Selected three box
	 * @type Number
	 */
	var selectedThreeBox = 1;
	
	/**
	 * News box count
	 * @type Number
	 */
	var newsBoxCount = null;
	
	/**
	 * Selected news box
	 * @type Number
	 */
	var selectedNewsBox = 1;
	
	/**
	 * Show selected news box content
	 * @type Boolean
	 */
	var showNewsContent = false;
	
	/**
	 * News box image count
	 * @type Number
	 */
	var newsBoxImageCount = null;
	
	/**
	 * Selected image in selected news box
	 * @type Number
	 */
	var selectedNewsBoxImage = 1;
	
	/**
	 * For us box count
	 * @type Number
	 */
	var forUsBoxCount = null;
	
	/**
	 * Selected for us box
	 * @type Number
	 */
	var selectedForUsBox = 1;
	
	/**
	 * Initialize pre functions
	 */
	function preFuncInit() {
		getNewsBoxCount();
		getForUsBoxCount();
		manageContent();
		
		var infobar = $('preInfobar');
		var tabmenu = $('tabMenuFrame');
		var submenufirst = $('subMenuFirst');
		var submenulast = $('subMenuLast');
		var body = $('bodyBorder');
		var footerbar = $('footerBar');
		if(!document.attachEvent) {
			infobar.addEventListener('mouseout', hideInfobar, false);
			tabmenu.addEventListener('mouseover', hideInfobar, false);
			if(submenufirst) {
				submenufirst.addEventListener('mouseover', hideInfobar, false);
			}
			if(submenulast) {
				submenulast.addEventListener('mouseover', hideInfobar, false);
			}
			body.addEventListener('mouseover', hideInfobar, false);
			footerbar.addEventListener('mouseout', hideFooterBar, false);
		} else {
			infobar.attachEvent('onmouseout', hideInfobar);
			tabmenu.attachEvent('onmouseover', hideInfobar);
			if(submenufirst) {
				submenufirst.attachEvent('onmouseover', hideInfobar);
			}
			if(submenulast) {
				submenulast.attachEvent('onmouseover', hideInfobar);
			}
			body.attachEvent('onmouseover', hideInfobar);
			footerbar.attachEvent('onmouseout', hideFooterBar); 
		}
	}
	
	/**
	 * Manage pre content display
	 */
	function manageContent() {
		var centerBottom = $('bodyCenterBottomContent');
		
		if(centerBottom && centerBottom.innerHTML != '' && centerBottom.innerHTML != '&nbsp;') {
			centerBottom.style.display = 'block';
		}
		
		esuli.staticContent.setContentEnd();
	}
	
	/**
	 * Show info bar
	 * @param Infobar id
	 * @type Number
	 */
	this.showInfobar = function(pId) {
		if(!$('preInfobar')) {
			return;
		} else {
			$('preInfobar').style.display = 'block';
		}
		
		var k = -1;
		for(var i = 0; i < 10; i++) {
			if($('preInfobar' + i) && $('subMenu' + i)) {
				k++;
				if(pId == i) {
					$('preInfobar' + i).style.display = 'block';
					$('subMenu' + i).className = 'subMenuNormalSelected';
				} else {
					$('preInfobar' + i).style.display = 'none';
					if(pId == i + 1) {
						$('subMenu' + i).className = 'subMenuRightSelected';
					} else if (pId == i - 1) {
						$('subMenu' + i).className = 'subMenuLeftSelected';
					} else {
						$('subMenu' + i).className = 'subMenuNormal';
					}
				}
			} else {
				break;
			}
		}
		if(pId == 0) {
			$('subMenuFirst').className = 'subMenuFirstSelected';
		} else {
			$('subMenuFirst').className = 'subMenuFirst';
		}
		if(pId == k) {
			$('subMenuLast').className = 'subMenuLast subMenuLeftSelected';
		} else {
			$('subMenuLast').className = 'subMenuLast';
		}
	}
	
	/**
	 * Hide info bar
	 */
	function hideInfobar(evt) {		
		if(!$('preInfobar')) {
			return;
		}
		var infobar = $('preInfobar');
		var children = infobar.all || infobar.getElementsByTagName('*');
		
		if (!evt) { 
            evt = window.event; 
        }
		
		var to = evt.relatedTarget || evt.toElement;
		
		if(to && ((to.id && to.id.indexOf('subMenu') > -1) || to == infobar)) {
			return;
		}
		
		for(var i = 0; i < children.length; i++) {
			if(to == children[i]) {
				return;
			}
		}

		infobar.style.display = 'none';
		
		for(var i = 0; i < 10; i++) {
			if($('preInfobar' + i) && $('subMenu' + i)) {
				$('preInfobar' + i).style.display = 'none';
				$('subMenu' + i).className = 'subMenuNormal';
			} else {
				break;
			}
		}
		if($('subMenuFirst')) {
			$('subMenuFirst').className = 'subMenuFirst';
		}
		if($('subMenuLast')) {
			$('subMenuLast').className = 'subMenuLast';
		}
	}
	
	/**
	 * Show footer bar
	 * @param Footer id
	 * @type Number
	 */
	this.showFooterbar = function(pId) {
		if(!$('footerBar')) {
			return;
		} else {
			$('footerBar').style.display = 'block';
		}
		
		for(var i = 0; i < 10; i++) {
			if($('footerBar' + i)) {
				if(pId == i) {
					$('footerBar' + i).style.display = 'block';
				} else {
					$('footerBar' + i).style.display = 'none';
				}
			} else {
				break;
			}
		}
	}
	
	/**
	 * Hide footer bar
	 */
	function hideFooterBar(evt) {		
		if(!$('footerBar')) {
			return;
		}
		var footerbar = $('footerBar');
		var children = footerbar.all || footerbar.getElementsByTagName('*');
		
		if (!evt) { 
            evt = window.event; 
        }
		
		var to = evt.relatedTarget || evt.toElement;
		
		if(to && to == footerbar) {
			return;
		}
		
		for(var i = 0; i < children.length; i++) {
			if(to == children[i]) {
				return;
			}
		}

		footerbar.style.display = 'none';
		
		for(var i = 0; i < 10; i++) {
			if($('footerBar' + i)) {
				$('footerBar' + i).style.display = 'none';
			} else {
				break;
			}
		}
	}
	
	/**
	 * Change three box class
	 * @param Three box id number
	 * @type Number
	 */
	this.threeBoxOver = function(pOver) {
		if(pOver == selectedThreeBox) {
			return;
		}
		$('preThreeBox' + pOver).className = 'preThreeBox' + pOver + 'Hover';
	}
	
	/**
	 * Change three box class
	 * @param Three box id number
	 * @type Number
	 */
	this.threeBoxOut = function(pOut) {
		if(pOut == selectedThreeBox) {
			return;
		}
		$('preThreeBox' + pOut).className = 'preThreeBox' + pOut;
	}
	
	/**
	 * Change three box actual content
	 * @param Selected three box
	 * @type Number
	 */
	this.threeBoxFocus = function(pSelected) {
		if(pSelected == selectedThreeBox) {
			return;
		}
		selectedThreeBox = pSelected;
		for(var i = 1; i < 4; i++) {
			if(i == pSelected) {
				$('preThreeBox' + i).className = 'preThreeBox' + i + 'Selected';
				$('preThreeBoxActual' + i).style.display = 'block';
			} else {
				$('preThreeBox' + i).className = 'preThreeBox' + i;
				$('preThreeBoxActual' + i).style.display = 'none';
			}
		}
		$('preThreeBoxJoiner').className = 'preThreeBoxJoiner' + pSelected;
	}
	
	/**
	 * Send plus information for normal online education
	 */
	this.sendPlusInfoNormal = function() {
		var normalName = $('plusInfoNormalName');
		var normalEmail = $('plusInfoNormalEmail');
		
		var defNormalName = 'Neved:';
		var defNormalEmail = 'E-mail címed:';
		
		normalName.className = 'normalTextInput';
		normalEmail.className = 'normalTextInput';
		
		if(esuli.staticContent.trimTextInput(normalName.value) == '' || normalName.value == defNormalName) {
			normalName.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Nem adtad meg a neved!', 'alert'));
			return;
		}
		if(esuli.staticContent.trimTextInput(normalEmail.value) == '' || normalEmail.value == defNormalEmail) {
			normalEmail.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Nem adtad meg az e-mail címed!', 'alert'));
			return;
		}
		if(!esuli.staticContent.checkEmail(esuli.staticContent.trimTextInput(normalEmail.value))) {
			normalEmail.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Az e-mail cím formátuma nem megfelelő!', 'alert'));
			return;
		}
		
		engine.dialogManager.add(new Dialog('Kedves ' + normalName.value + '!<br /><br class="halfLine" />Köszönjük, hogy érdeklődsz online nyelvoktató szolgáltatásunk iránt!<br /><br class="halfLine" />Hamarosan részletes tájékoztatást küldük az általad megadott e-mail címre.', 'alert'));

		var message = normalName.value + ' további információt kért tőlünk a lakossági nyelvoktatással kapcsolatban.' + "\n\n" + '- automata értesítés -';
		
		engine.commGate.sendWithSession([ new CommGateRequest("SEND_EMAIL", [ 'pragai.robert@steery.com; info@enyelviskola.hu', message, 'Lakossági nyelvoktatás érdeklődés', normalEmail.value ], null) ] );
		
		normalName.value = defNormalName;
		normalEmail.value = defNormalEmail;
	}
	
	/**
	 * Send plus information to company
	 */
	this.sendPlusInfoCompany = function() {
		var companyCompanyName = $('plusInfoCompanyCompanyName');
		var companyName = $('plusInfoCompanyName');
		var companyEmail = $('plusInfoCompanyEmail');
		var companyTelefon = $('plusInfoCompanyTelefon');
		var defCompanyName = 'Az Ön neve:';
		var defCompanyCompanyName = 'Az Ön cégének neve:';
		var defCompanyEmail = 'Az Ön email címe:';
		var defCompanyTelefon = 'Az Ön telefonszáma:';
		
		companyCompanyName.className = 'normalTextInput';
		companyName.className = 'normalTextInput';
		companyEmail.className = 'normalTextInput';
		companyTelefon.className = 'normalTextInput';
		
		if(esuli.staticContent.trimTextInput(companyCompanyName.value) == '' || companyCompanyName.value == defCompanyCompanyName) {
			companyCompanyName.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Kérjük, adja meg cégének teljes nevét!', 'alert'));
			return;
		}
		if(esuli.staticContent.trimTextInput(companyName.value) == '' || companyName.value == defCompanyName) {
			companyName.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Kérjük, adja meg a teljes nevét!', 'alert'));
			return;
		}
		if(esuli.staticContent.trimTextInput(companyEmail.value) != '' && companyEmail.value != defCompanyEmail) {
			if(!esuli.staticContent.checkEmail(esuli.staticContent.trimTextInput(companyEmail.value))) {
				companyEmail.className = 'normalTextInputError';
				engine.dialogManager.add(new Dialog('Az e-mail cím formátuma nem megfelelő!<br /><br class="halfLine" /><span class="grayNormal">Az e-mail cím megadása nem kötelező. Amennyiben mégis megadja, kérjük saját, létező e-mail címét adja meg!</span>', 'alert'));
				return;
			}
		}
		if(esuli.staticContent.trimTextInput(companyTelefon.value) != '' && companyTelefon.value != defCompanyTelefon) {
			if(!esuli.staticContent.checkTelefon(esuli.staticContent.trimTextInput(companyTelefon.value))) {
				companyTelefon.className = 'normalTextInputError';
				engine.dialogManager.add(new Dialog('Az telefonszám formátuma nem megfelelő!<br /><br class="halfLine" /><span class="grayNormal">A telefonszám megadása nem kötelező. Amennyiben mégis megadja, kérjük saját, létező telefonszámát adja meg!</span>', 'alert'));
				return;
			}
		}
		if((esuli.staticContent.trimTextInput(companyEmail.value) == '' || companyEmail.value == defCompanyEmail) && (esuli.staticContent.trimTextInput(companyTelefon.value) == '' || companyTelefon.value == defCompanyTelefon)) {
			companyEmail.className = 'normalTextInputError';
			companyTelefon.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Nem adta meg elérhetőségeit!<br /><br class="halfLine" /><span class="grayNormal">Ahhoz, hogy fel tudjuk venni Önnel a kapcsolatot fontos, hogy megadja e-mail címét, vagy telefonszámát!</span>', 'alert'));
			return;
		}

		engine.dialogManager.add(new Dialog('Kedves ' + companyName.value + '!<br /><br class="halfLine" />Köszönjük, hogy érdeklődik online nyelvoktató szolgáltatásunk iránt!<br /><br class="halfLine" />Az Ön által megadott elérhetőségek valamelyikén hamarosan meg fogjuk keresni, hogy részletes tájékoztatást nyújthassunk.', 'alert'));
		
		var from = companyEmail.value != defCompanyEmail ? companyEmail.value : 'info@enyelviskola.hu';
		var message = 'A ' + companyCompanyName.value + ' vállalattól ' + companyName.value + ' további információt kért tőlünk.' + "\n\n" + 'Az alábbi elérhetőségeket adta meg:' + "\n";
		if(companyEmail.value != defCompanyEmail) {
			message += "\n" + 'E-mail cím: ' + companyEmail.value;
		}
		if(companyTelefon.value != defCompanyTelefon) {
			message += "\n" + 'Telefon: ' + companyTelefon.value;
		}
		message += "\n\n" + '- automata értesítés -';
		
		engine.commGate.sendWithSession([ new CommGateRequest("SEND_EMAIL", [ 'pragai.robert@steery.com; bognar.eszter@enyelviskola.hu', message, 'Vállalati nyelvoktatás érdeklődés', from ], null) ] );
		
		companyCompanyName.value = defCompanyCompanyName;
		companyName.value = defCompanyName;
		companyEmail.value = defCompanyEmail;
		companyTelefon.value = defCompanyTelefon;
	}
	
	/**
	 * Send plus information for exam online education
	 */
	this.sendPlusInfoExam = function() {
		var examName = $('plusInfoExamName');
		var examEmail = $('plusInfoExamEmail');
		
		var defExamName = 'Neved:';
		var defExamEmail = 'E-mail címed:';
		
		examName.className = 'normalTextInput';
		examEmail.className = 'normalTextInput';
		
		if(esuli.staticContent.trimTextInput(examName.value) == '' || examName.value == defExamName) {
			examName.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Nem adtad meg a neved!', 'alert'));
			return;
		}
		if(esuli.staticContent.trimTextInput(examEmail.value) == '' || examEmail.value == defExamEmail) {
			examEmail.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Nem adtad meg az e-mail címed!', 'alert'));
			return;
		}
		if(!esuli.staticContent.checkEmail(esuli.staticContent.trimTextInput(examEmail.value))) {
			examEmail.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Az e-mail cím formátuma nem megfelelő!', 'alert'));
			return;
		}
		
		engine.dialogManager.add(new Dialog('Kedves ' + examName.value + '!<br /><br class="halfLine" />Köszönjük, hogy érdeklődsz online nyelvoktató szolgáltatásunk iránt!<br /><br class="halfLine" />Hamarosan részletes tájékoztatást küldük az általad megadott e-mail címre.', 'alert'));

		var message = examName.value + ' további információt kért tőlünk a nyelvvizsgákkal kapcsolatban.' + "\n\n" + '- automata értesítés -';
		
		engine.commGate.sendWithSession([ new CommGateRequest("SEND_EMAIL", [ 'pragai.robert@steery.com; bognar.eszter@enyelviskola.hu', message, 'Nyelvvizsga érdeklődés', examEmail.value ], null) ] );
		
		examName.value = defExamName;
		examEmail.value = defExamEmail;
	}

	this.sendAkcioUzenet = function() {
		var senderName = $('senderName').value;
		var friendName = $('friendName').value;
		var friendEmail = $('friendEmail').value;
		var friendMessage = $('friendMessage').value;

		var message = "Kedves " + friendName + "!\n\n" +
						senderName + " üzenetet küldött neked az eNyelviskola.hu akciójáról.\n" +
						"Az akcióról további információt itt találsz: http://www.enyelviskola.hu/lakossagi_akciok\n\n" +
						friendMessage + "\n\n" +
						"eNyelviskola.hu - Élvezd az angolt, bárhol, bármikor!\n" +
						"   http://www.eNyelviskola.hu";

		engine.commGate.send([new CommGateRequest("SEND_EMAIL", [friendName + "<" + friendEmail + ">", message, senderName + ": eNyelviskola.hu akció", "info@enyelviskola.hu"], null)]);
		engine.dialogManager.add(new Dialog("Az üzenetet elküldtük barátodnak!", "alert", null));

		$('senderName').value = '';
		$('friendName').value = '';
		$('friendEmail').value = '';
		$('friendMessage').value = '';
	}
	
	/**
	 * Get news box count
	 * @type Number
	 */
	function getNewsBoxCount() {
		newsBoxCount = 0;
		while($('newsBox' + ( newsBoxCount + 1)) != undefined) {
			newsBoxCount++;
		}
		if(newsBoxCount > 0) {
			showNewsBox();
		}
		return newsBoxCount;
	}
	
	/**
	 * Get next news box
	 */
	this.getNextNewsBox = function() {
		if(selectedNewsBox + 1 > newsBoxCount) {
			selectedNewsBox = 1;
		} else {
			selectedNewsBox++;
		}
		showNewsBox();
	}
	
	/**
	 * Get previous news box
	 */
	this.getPreviousNewsBox = function() {
		if(selectedNewsBox - 1 == 0) {
			selectedNewsBox = newsBoxCount;
		} else {
			selectedNewsBox--;
		}
		showNewsBox();
	}
	
	/**
	 * Show selected news box
	 */
	function showNewsBox() {
		for(var i = 1; i < (newsBoxCount + 1); i++) {
			if(i == selectedNewsBox) {
				$('newsBox' + selectedNewsBox).style.display = 'block';
			} else {
				$('newsBox' + i).style.display = 'none';
			}
		}
		
		showNewsContent = false;
		self.showHideNews();
		
		getNewsBoxImageCount();
		
		esuli.staticContent.setContentEnd();
	}
	
	/**
	 * Show or hide news content
	 */
	this.showHideNews = function() {
		for(var i = 1; i < (newsBoxCount + 1); i++) {
			if($('newsBoxContent' + i + 'ShowHide')) {
				if(!showNewsContent) {
					$('newsBoxContent' + i + 'ShowHide').innerHTML = 'bővebben';
					$('newsBoxContent' + i).style.display = 'none';
				} else {
					$('newsBoxContent' + i + 'ShowHide').innerHTML = 'bezárás';
					$('newsBoxContent' + i).style.display = 'block';
				}
			}
		}
		
		showNewsContent = showNewsContent ? false : true;
		
		esuli.staticContent.setContentEnd();
	}
	
	/**
	 * Get news box image count
	 * @type Number
	 */
	function getNewsBoxImageCount() {
		newsBoxImageCount = 0;
		selectedNewsBoxImage = 1;
		while($('newsBox' + selectedNewsBox + 'Img' + ( newsBoxImageCount + 1)) != undefined) {
			newsBoxImageCount++;
		}
		if(newsBoxImageCount > 0) {
			showNewsBoxImage();
		}
	}
	
	/**
	 * Get next image in selected news box
	 */
	this.getNextNewsBoxImage = function() {
		if(selectedNewsBoxImage + 1 > newsBoxImageCount) {
			selectedNewsBoxImage = 1;
		} else {
			selectedNewsBoxImage++;
		}
		showNewsBoxImage();
	}
	
	/**
	 * Get previous image in selected news box
	 */
	this.getPreviousNewsBoxImage = function() {
		if(selectedNewsBoxImage - 1 == 0) {
			selectedNewsBoxImage = newsBoxImageCount;
		} else {
			selectedNewsBoxImage--;
		}
		showNewsBoxImage();
	}
	
	/**
	 * Show selected image in selected news box
	 */
	function showNewsBoxImage() {
		for(var i = 1; i < (newsBoxImageCount + 1); i++) {
			if(i == selectedNewsBoxImage) {
				$('newsBox' + selectedNewsBox + 'Img' + selectedNewsBoxImage).style.display = 'block';
				setNewsBoxImagePacer();
			} else {
				$('newsBox' + selectedNewsBox + 'Img' + i).style.display = 'none';
			}
		}
	}
	
	/**
	 * Set selected image pacers position in selected news box
	 */
	function setNewsBoxImagePacer() {
		if($('preNewsBox' + selectedNewsBox + 'Img' + selectedNewsBoxImage + 'Previous')) {
			$('preNewsBox' + selectedNewsBox + 'Img' + selectedNewsBoxImage + 'Previous').style.marginTop = ($('preNewsBox' + selectedNewsBox + 'Img' + selectedNewsBoxImage + 'In').offsetHeight / 2) + 'px';
		}
		if($('preNewsBox' + selectedNewsBox + 'Img' + selectedNewsBoxImage + 'Next')) {
			$('preNewsBox' + selectedNewsBox + 'Img' + selectedNewsBoxImage + 'Next').style.marginTop = ($('preNewsBox' + selectedNewsBox + 'Img' + selectedNewsBoxImage + 'In').offsetHeight / 2) + 'px';
		}
	}
	
	/**
	 * Get for us box count
	 * @type Number
	 */
	function getForUsBoxCount() {
		if(forUsBoxCount != null) {
			return forUsBoxCount;
		}
		forUsBoxCount = 0;
		while($('forUsBox' + ( forUsBoxCount + 1)) != undefined) {
			forUsBoxCount++;
		}
		if(forUsBoxCount > 0) {
			$('preForUs').style.display = 'block';
			showForUsBox();
		}
		return forUsBoxCount;
	}
	
	/**
	 * Get next for us box
	 */
	this.getNextForUsBox = function() {
		if(selectedForUsBox + 1 > forUsBoxCount) {
			selectedForUsBox = 1;
		} else {
			selectedForUsBox++;
		}
		showForUsBox();
	}
	
	/**
	 * Get prefious for us box
	 */
	this.getPreviousForUsBox = function() {
		if(selectedForUsBox - 1 == 0) {
			selectedForUsBox = forUsBoxCount;
		} else {
			selectedForUsBox--;
		}
		showForUsBox();
	}
	
	/**
	 * Show selected for us box
	 */
	function showForUsBox() {
		for(var i = 1; i < (forUsBoxCount + 1); i++) {
			if(i == selectedForUsBox) {
				$('forUsBox' + selectedForUsBox).style.display = 'block';
			} else {
				$('forUsBox' + i).style.display = 'none';
			}
		}
		
		esuli.staticContent.setContentEnd();
	}
	
	/**
	 * Kiszámolja az ügyfél cégének mekkora felhasználható kerete van az adójából nyelvoktatásra
	 * @param Fogalalkoztatottak száma, bruttó bér, árbevétel 2,5 milliárd fölött, állam részesedése, e-mail cím, kér e még infót
	 */
	this.calculateLimit = function() {
		var employees = $('leadEmployees'); // Alkalmazottak száma
		var wageAvarage = $('leadWageAvarage'); // Átlag bér
		var turnOver = $('leadSizeCategory') ? $('leadSizeCategory').value == 'yes' ? true : false : false; // 2,5 milliárd fölött van e
		var govInvolvement = $('leadGovInvolvement') ? $('leadSizeCategory').value == 'yes' ? true : false : false; // Állami vagy önkormányzati részesedés van e
		var email = $('leadEmail'); // E-mail cím
		var name =  $('leadName'); // Név
		
		employees.className = 'normalTextInput';
		wageAvarage.className = 'normalSelect';
		email.className = 'normalTextInput';
		name.className = 'normalTextInput';
		
		if(esuli.staticContent.trimTextInput(employees.value) == '') {
			employees.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Kérjük, adja meg alkalmazottainak számát.', 'alert'));
			return;
		}
		if(!esuli.staticContent.checkNumber(esuli.staticContent.trimTextInput(employees.value))) {
			employees.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Hibásan adta meg alkalmazottainak számát!', 'alert'));
			return;
		}
		
		if(esuli.staticContent.trimTextInput(wageAvarage.value) == '') {
			wageAvarage.className = 'normalSelectError';
			engine.dialogManager.add(new Dialog('Kérjük, adja meg alkalmazottainak átlag bruttó bérét.', 'alert'));
			return;
		}
		
		if(esuli.staticContent.trimTextInput(email.value) == '') {
			email.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Nem adta meg az e-mail címét!', 'alert'));
			return;
		}
		if(!esuli.staticContent.checkEmail(esuli.staticContent.trimTextInput(email.value))) {
			email.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Az e-mail cím formátuma nem megfelelő!', 'alert'));
			return;
		}
		
		if(esuli.staticContent.trimTextInput(name.value) == '') {
			name.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Nem adta meg a nevét!', 'alert'));
			return;
		}
		
		// A megadott alkalmazotti létszám * átlagos bér = bérkeret ...
		var hire = employees.value * wageAvarage.value;
		
		// ... melynek 1,5%-a a szakképzési hozzájárulás.
		var contri = (hire / 100) * 1.5;
		
		// KKV-knél 60, nagyvállalatoknál 33%-a használható fel a szakképzési hozzájárulásnak akkreditált képzésre.
		var percent = 60;
		
		// ha a megadott alkalmazotti létszám 249 fölött van, a cég a szakképzési hozzájárulás 33%-át használhatja fel, egyébként 60%-ot.
		if(employees.value > 249) {
			percent = 33;
		}
		
		// ha az éves árbevétel vagy mérlegfőösszeg meghaladja a 2,5 milliárd forintot,
		// a cég a szakképzési hozzájárulás 33%-át használhatja fel, egyébként 60%-ot.
		if(turnOver) {
			percent = 33;
		}
		
		// Felhasználható keret
		var result = (contri / 100) * percent;
		
		var hours = Math.round(result * 12 / 3700);
		
		engine.dialogManager.add(new Dialog('Köszönjük, a választ e-mailben megküldtük!<br /><br class="halfLine" /><span class="grayNormal">Az Ön által megadott adatok alapján már kis is számítottuk a cége rendelkezésére álló keretet, melyet felhasználva úgy fejlesztheti cégét, hogy az közben nem eredményez semmilyen extra kiadást!</span>', 'alert'));

		var message = "Tisztelt " + name.value + "!" + "\n\n"
					+ "Kérésére kiszámoltuk azt az összeget, amelyet az Ön cége az alkalmazottai angol nyelvoktatására fordíthat ahelyett, hogy ezt az összeget befizetné szakképzési hozzájárulásként." + "\n\n"
					+ "Ez az összeg hozzávetőlegesen " + result + " Ft havonta!" + "\n"
					+ "Évente ez " + (result * 12) + " Ft!!!" + "\n\n"
					+ "Ebből a keretből legalább " + hours + " nyelvórán vehetnek részt a vállalat dolgozói az eNyelviskola.hu online akkreditált nyelviskolában." + "\n\n"
					+ "Önnek semmi más dolga nincs, csak ki kell töltenie az alábbi linken található adatlapot és el kell juttatnia hozzánk, a további adminisztrációs feladatokat mi elvégezzük!" + "\n\n"
					+ "Kérjük, kattintson az alábbi linkre vagy másolja azt be a böngészőjébe:" + "\n"
					+ BASE_URL + 'szakkepzesi_hozzajarulas.doc' + "\n\n"
					+ "Üdvözlettel," + "\n"
					+ "eNyelviskola.hu" + "\n"
					+ "info@enyelviskola.hu"
		
		engine.commGate.sendWithSession([ new CommGateRequest("SEND_EMAIL", [ email.value, message, 'Szakképzési hozzájárulás kalkulátor', 'info@enyelviskola.hu' ], null) ] );

		employees.value = '';
		wageAvarage.value = '';
		email.value = '';
		name.value = '';
	}
	
	/**
	 * Newsletter unsubscribe
	 * @param User newsletter id
	 * @type Number
	 */
	this.signOff = function(pMid) {
		var comm = new CommGateRequest("REQ_SELECT", 
			[ "ESULI_SET_NEWS_RESPONSE" ], 
			function(pResponse) {
				var cmd;
				var data;
				
				for(var i = 0; i < pResponse.length; i++) {
					cmd = pResponse[i].getCommandLine();
					if(cmd && cmd[1] && cmd[1] == 'RES_DATA') {
						data = pResponse[i].getDataAsArray();
						if(data[0][1] == 'SUCCESS') {
							engine.dialogManager.add( new Dialog("Sikeresen leiratkoztál a hírlevélről.", "alert" ) );
						} else {
							engine.dialogManager.add( new Dialog("Leiratkozásod sajnos nem sikerült, kérjük próbáld meg később, vagy érdeklődj az ügyfélszolgálaton!", "alert" ) );
						}
						break;
					}
				}
			});
			
		comm.addDataLevel([ [ "MID", "QUESTIONS", "ANSWERS" ], [ pMid, 'SIGN_OFF;WHY', 'TRUE;' + $('newsletterWhy').value ]]);
		engine.commGate.sendWithSession([ comm ]);
	}
	
	// Initialize
	preFuncInit();
}
/**
 * Sales agent
 */
var SalesAgent = function(agentId, agentName) {
	
	/**
	 * Agent id
	 * @type Number
	 */
	var id = (agentId != undefined ? agentId : null);
	
	/**
	 * Agent name
	 * @type String
	 */
	var name = (agentName != undefined ? agentName : "");
	
	/**
	 * Set agent id
	 * @param Number
	 */
	this.setId = function(agentId) {
		id = agentId;
	}
	
	/**
	 * Get agent id
	 * @return Agnet id
	 * @type Number
	 */
	this.getId = function() {
		return id;
	}
	
	/**
	 * Set agent name
	 * @param Agent name
	 * @type String
	 */
	this.setName = function(agentName) {
		name = agentName;
	}
	
	/**
	 * Get agent name
	 * @return Agent name
	 * @type String
	 */
	this.getName = function() {
		return name;
	}
}

/**
 *
 */
var SalesCompany = function(companyId, companyName, companyAddress, companyPhone, companyFax, companyAgent, companyStatus, companyComment, companyLastUpdate, companyTaxNumber, companyPublicNumber, companySeat) {
	
	var id = (companyId != undefined ? companyId : null);
	
	var name = (companyName != undefined ? companyName : "");
	
	var address = (companyAddress != undefined ? companyAddress : "");
	
	var phone = (companyPhone != undefined ? companyPhone : "");
	
	var fax = (companyFax != undefined ? companyFax : "");
	
	var agent = (companyAgent instanceof SalesAgent ? companyAgent : new SalesAgent());
	
	var status = (companyStatus != undefined ? companyStatus : "");
	
	var comment = (companyComment != undefined ? companyComment : "");
	
	var lastUpdate = (companyLastUpdate != undefined ? companyLastUpdate : "");
	
	var taxNumber = (companyTaxNumber != undefined ? companyTaxNumber : "");
	
	var publicNumber = (companyPublicNumber != undefined ? companyPublicNumber : "");
	
	var seat = (companySeat != undefined ? companySeat : "");
	
	this.setId = function(companyId) {
		id = companyId;
	}
	
	this.getId = function() {
		return id;
	}
	
	this.setName = function(companyName) {
		name = companyName;
	}
	
	this.getName = function() {
		return name;
	}
	
	this.setAddress = function(companyAddress) {
		address = companyAddress;
	}
	
	this.getAddress = function() {
		return address;
	}
	
	this.setPhone = function(companyPhone) {
		phone = companyPhone;
	}
	
	this.getPhone = function() {
		return phone;
	}
	
	this.setFax = function(companyFax) {
		fax = companyFax;
	}
	
	this.getFax = function() {
		return fax;
	}
	
	this.setAgent = function(companyAgent) {
		agent = companyAgent;
	}
	
	this.getAgent = function() {
		return agent;
	}
	
	this.setStatus = function(companyStatus) {
		status = companyStatus
	}
	
	this.getStatus = function() {
		return status;
	}
	
	this.setComment = function(companyComment) {
		comment = companyComment;
	}
	
	this.getComment = function() {
		return comment;
	}
	
	this.setLastUpdate = function(companyLastUpdate) {
		lastUpdate = companyLastUpdate;
	}
	
	this.getLastUpdate = function() {
		return lastUpdate;
	}
	
	this.setPublicNumber = function(companyPublicNumber) {
		publicNumber = companyPublicNumber;
	}
	
	this.getPublicNumber = function() {
		return publicNumber;
	}
	
	this.setTaxNumber = function(companyTaxNumber) {
		taxNumber = companyTaxNumber;
	}
	
	this.getTaxNumber = function() {
		return taxNumber;
	}
	
	this.setSeat = function(companySeat) {
		seat = companySeat;
	}
	
	this.getSeat = function() {
		return seat;
	}
}
/**
 *
 */
var CompanyManager = function() {
	
	/**
	 *
	 */
	var companies = new Array();
	
	/**
	 * 
	 */
	var companiesLoaded = false;
	
	/**
	 *
	 */
	var statuses = [ "E00 - kapcsolat ", "E01 - első telefon", "E02 - tájékoztató anyag", "E03 - első találkozó időpont", "E04 - első találkozó", "E05 - ajánlatkérés", "E06 - ajánlat", "E07 - elfogadott ajánlat", "E08 - szerződésterv", "E09 - szerződés", "E10 - újraszerződés kezdeményezése", "E11 - újraszerződés", "E12 - újraszerződést elutasították", "Aktív", "Passzív", "Letiltva" ];
	
	/**
	 *
	 */
	this.getStatuses = function() {
		return statuses;
	}
	
	/**
	 * 
	 */
	this.isLoaded = function() {
		return companiesLoaded;
	}
	
	/**
	 *
	 */
	this.clearCompanies = function() {
		companiesLoaded = false;
	}
	
	/**
	 *
	 */
	this.getCompany = function(id, callbackPage) {
		if (companiesLoaded) {
			for (var i = 0; i < companies.length; i++) {
				if (companies[i].getId() == id) {
					return companies[i];
				}
			}
		}
	
		loadCompanies(callbackPage);
	
		return null;
	}
	
	/**
	 * 
	 */
	this.getCompanies = function(callbackPage) {
		if (companiesLoaded) {
			return companies;
		}
	
		loadCompanies(callbackPage);
	
		return null;
	}
	
	/**
	 * Load companies from db
	 */
	function loadCompanies(callbackPage) {
		var oldSeq = esuli.contentManager.getSeq();
	
		var c = new CommGateRequest(
			"REQ_ACCESS", 
			[ "SALES_GET_ALL_COMPANIES" ], 
			function(response) {
				companies = new Array();
			
				var data = response[0].getDataAsObjectArray();
			
				for (var i = 0; i < data.length; i++) {
					companies.push(new SalesCompany(
						data[i].id,
						data[i].name,
						data[i].address,
						data[i].phone,
						data[i].fax,
						new SalesAgent(data[i].agent_id, data[i].agent_name),
						data[i].status,
						data[i].comment,
						data[i].last_update,
						data[i].taxnumber,
						data[i].publicnumber,
						data[i].seat
					));
				}
			
				companiesLoaded = true;
			
				if (callbackPage != undefined && oldSeq == esuli.contentManager.getSeq()) {
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, callbackPage));
				}
			});
	
		c.addDataLevel([
			[ "name", "state", "agent_name", "sort", "order" ],
			[ esuli.sales.companyPage.getSearchName(), esuli.sales.companyPage.getSearchStatus(), esuli.sales.companyPage.getSearchAgentName(), esuli.sales.companyPage.getSortBy(), esuli.sales.companyPage.getSortByDirection() ]
		]);
	
		engine.commGate.sendWithSession([ c ]);
	}
	
	/**
	 * 
	 */
	this.saveCompany = function(company) {
		var c = new CommGateRequest(
			"REQ_ACCESS",
			[ "SALES_SET_COMPANY" ],
			function(response) {
				companiesLoaded = false;
				window.location.hash = engine.historyManager.getCurrentLocation() - 1;
			}
		);
		
		c.addDataLevel([
			[ "id", "name", "address", "phone", "fax", "agent_id", "status", "comment", "taxnumber", "publicnumber", "seat" ],
			[ company.getId(), company.getName(), company.getAddress(), company.getPhone(), company.getFax(), company.getAgent().getId(), company.getStatus(), company.getComment(), company.getTaxNumber(), company.getPublicNumber(), company.getSeat() ]
		]);
	
		engine.commGate.sendWithSession([ c ]);
	}
	
	/**
	 *
	 */
	this.deleteCompany = function(id, callbackPage) {
		var oldSeq = esuli.contentManager.getSeq();
	
		var c = new CommGateRequest(
			"REQ_ACCESS",
			[ "SALES_DELETE_COMPANY" ],
			function(response) {
				if (callbackPage != undefined && oldSeq == esuli.contentManager.getSeq()) {
					companiesLoaded = false;
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, callbackPage));
				}
			}
		);
	
		c.addDataLevel([
			[ "id" ],
			[ id ]
		]);
	
		engine.commGate.sendWithSession([ c ]);
	}
}

/**
 *
 */
var CompanyPage = function() {
	
	var lastPage = null;
	
	var name = "";
	var status = "";
	var agentName = "";
	var sortBy = "name";
	var sortByDirection = "asc";
	
	var self = this;

	/**
	 *
	 */
	this.getSearchName = function() {
		return name;
	}
	
	/**
	 *
	 */
	this.getSearchStatus = function() {
		return status;
	}
	
	/**
	 *
	 */
	this.getSearchAgentName = function() {
		return agentName;
	}
	
	/**
	 *
	 */
	this.getSortBy = function() {
		return sortBy;
	}
	
	/**
	 *
	 */
	this.getSortByDirection = function() {
		return sortByDirection;
	}
	
	/**
	 *
	 */
	this.getPage = function(pageRequest) {
		if (! check(pageRequest)) {
			//TODO: Log error
			return;
		}
	
		switch (pageRequest.get("page")) {
		
			case "companyList":
				var companies = esuli.sales.companyManager.getCompanies({ module: "sales", page: "companyList", tabId: 5, subId: 0 });
		
				if (companies == null) {
					return engine.templateManager.getTemplate("contentspin").process({});
				} else {
					return engine.templateManager.getTemplate("sales_companylist").process({ companyList: companies });
				}
			
				break;

			case "editCompany":
				var id = pageRequest.get("id");
				var company = null;
		
				if (id > 0) {
					company = esuli.sales.companyManager.getCompany(pageRequest.get("id"), { module: "sales", page: "editCompany", id: id, tabId: 5, subId: 0 });
			
					if (company == null) {
						return engine.templateManager.getTemplate("contentspin").process({});
					} else {
						return engine.templateManager.getTemplate("sales_companyform").process({ company: company });
					}
				} else {
					return engine.templateManager.getTemplate("sales_companyform").process({ company: new SalesCompany() });
				}
			
				break;
		
			case "viewCompany":
				var id = pageRequest.get("id");
				var page = { module: "sales", page: "viewCompany", id: id, tabId: 5, subId: 0 };
				var company = esuli.sales.companyManager.getCompany(id, page);
		
				if (company == null) {
					return engine.templateManager.getTemplate("contentspin").process({});
				} else {
					var events = esuli.sales.evtManager.getEvents(id, page);
				
					if (events == null) {
						return engine.templateManager.getTemplate("contentspin").process({});
					} else {
						var contacts = esuli.sales.contactManager.getContacts(id, page);
			
						if (contacts == null) {
							return engine.templateManager.getTemplate("contentspin").process({});
						} else {
							var contracts = esuli.sales.contractManager.getContracts(id, page);
				
							if (contracts == null) {
								return engine.templateManager.getTemplate("spin").process({});
							} else {
								return engine.templateManager.getTemplate("sales_companyview").process({ company: company, eventList: events, contactList: contacts, contractList: contracts });
							}
						}
					}
				}
		
				break;
		}
	
		return page;
	}
	
	/**
	 * Returns last visited page
	 * @return Last visited page
	 * @type Object
	 */
	this.getLastPage = function() {
		self.getPage(lastPage);
	}
	
	/**
	 *
	 */
	this.editCompany = function(id) {
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { module: "sales", page: "editCompany", id: id, tabId: 5, subId: 0 }));
	}
	
	/**
	 *
	 */
	this.viewCompany = function(id) {
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { module: "sales", page: "viewCompany", id: id, tabId: 5, subId: 0 }));
	}
	
	/**
	 *
	 */
	this.saveCompany = function() {
		var company = null;
	
		if ($("companyId").value.length > 0) {
			company = esuli.sales.companyManager.getCompany($("companyId").value);
		} else {
			company = new SalesCompany();
			company.setAgent(new SalesAgent(esuli.user.getAgentId()));
		}
	
		company.setName($("companyName").value.trim());
		company.setAddress($("companyAddress").value.trim());
		company.setPhone($("companyPhone").value.trim());
		company.setFax($("companyFax").value.trim());
		company.setStatus($("companyStatus").options[$("companyStatus").selectedIndex].value);
		company.setComment($("companyComment").value.trim());
		company.setTaxNumber($("companyTaxNumber").value.trim());
		company.setPublicNumber($("companyPublicNumber").value.trim());
		company.setSeat($("companySeat").value.trim());
	
		esuli.sales.companyManager.saveCompany(company);
	}
	
	/**
	 *
	 */
	this.showCompanyList = function() {
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { module: "sales", page: "companyList", tabId: 5, subId: 0 }));
	}
	
	/**
	 *
	 */
	this.clearAndSearch = function() {
		$("searchName").value = "";
		$("searchStatus").selectedIndex = 0;
		$("searchAgentName").value = "";
	
		self.search();
	}
	
	/**
	 *
	 */
	this.search = function() {
		name = $("searchName").value;
		status = $("searchStatus").options[$("searchStatus").selectedIndex].value;
		agentName = $("searchAgentName").value;
	
		esuli.sales.companyManager.clearCompanies();
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { module: "sales", page: "companyList", tabId: 5, subId: 0 }));
	}
	
	/**
	 *
	 */
	this.sort = function(companySortBy) {
		if (sortBy == companySortBy) {
			sortByDirection = (sortByDirection == "asc" ? "desc" : "asc");
		} else {
			sortBy = companySortBy;
			sortByDirection = "asc";
		}
	
		esuli.sales.companyManager.clearCompanies();
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { module: "sales", page: "companyList", tabId: 5, subId: 0 }));
	}
	
	/**
	 *
	 */
	this.deleteCompany = function(id) {
		engine.dialogManager.add(new Dialog("Biztosan törlöd?", "confirm", [null,function() {esuli.sales.companyManager.deleteCompany(id, { module: "sales", page: "companyList", tabId: 5, subId: 0 });},null], ["", "Törlés", "Mégse"]));
	}
}

/**
 *
 */
var SalesContact = function(contactId, contactSurname, contactForename, contactPhone, contactTitle, contactCompanyId, contactComment) {
	
	/**
	 *
	 */
	var id = (contactId != undefined ? contactId : null);
	
	/**
	 *
	 */
	var surname = (contactSurname != undefined ? contactSurname : "");
	
	/**
	 *
	 */
	var forename = (contactForename != undefined ? contactForename : "");
	
	/**
	 *
	 */
	var phone = (contactPhone != undefined ? contactPhone : "");
	
	/**
	 *
	 */
	var title = (contactTitle != undefined ? contactTitle : "");
	
	/**
	 *
	 */
	var companyId = (contactCompanyId != undefined ? contactCompanyId : null);
	
	/**
	 *
	 */
	var comment = (contactComment != undefined ? contactComment : "");
	
	/**
	 *
	 */
	this.setId = function(contactId) {
		id = contactId;
	}
	
	/**
	 *
	 */
	this.getId = function() {
		return id;
	}
	
	/**
	 *
	 */
	this.setSurname = function(contactSurname) {
		surname = contactSurname;
	}
	
	/**
	 *
	 */
	this.getSurname = function() {
		return surname;
	}
	
	/**
	 *
	 */
	this.setForename = function(contactForename) {
		forename = contactForename;
	}
	
	/**
	 *
	 */
	this.getForename = function() {
		return forename;
	}
	
	/**
	 *
	 */
	this.setPhone = function(contactPhone) {
		phone = contactPhone;
	}
	
	/**
	 *
	 */
	this.getPhone = function() {
		return phone;
	}
	
	/**
	 *
	 */
	this.setTitle = function(contactTitle) {
		title = contactTitle;
	}
	
	/**
	 *
	 */
	this.getTitle = function() {
		return title;
	}
	
	/**
	 *
	 */
	this.setCompanyId = function(contactCompanyId) {
		companyId = contactCompanyId;
	}
	
	/**
	 *
	 */
	this.getCompanyId = function() {
		return companyId;
	}
	
	/**
	 *
	 */
	this.setComment = function(contactComment) {
		comment = contactComment;
	}
	
	/**
	 *
	 */
	this.getComment = function() {
		return comment;
	}
}
/**
 *
 */
var ContactManager = function() {
	
	/**
	 *
	 */
	var contacts = new Map();
	
	/**
	 *
	 */
	this.getContact = function(companyId, id, callbackPage) {
		if (contacts.containsKey(companyId)) {
			var companyContacts = contacts.get(companyId);
		
			for (var i = 0; i < companyContacts.length; i++) {
				if (companyContacts[i].getId() == id) {
					return companyContacts[i];
				}
			}
		}
	
		loadContacts(companyId, callbackPage);
	
		return null;
	}
	
	/**
	 *
	 */
	this.getContacts = function(companyId, callbackPage) {
		if (contacts.containsKey(companyId)) {
			return contacts.get(companyId);
		}
	
		loadContacts(companyId, callbackPage);
	
		return null;
	}
	
	/**
	 *
	 */
	function loadContacts(companyId, callbackPage) {
		var oldSeq = esuli.contentManager.getSeq();
	
		var c = new CommGateRequest(
			"REQ_ACCESS", 
			[ "SALES_GET_CONTACTS" ], 
			function(response) {
				contacts.put(companyId, new Array());
		
				var data = response[0].getDataAsObjectArray();
		
				for (var i = 0; i < data.length; i++) {
					contacts.get(companyId).push(new SalesContact(
						data[i].id,
						data[i].surname,
						data[i].forename,
						data[i].phone,
						data[i].title,
						data[i].company_id,
						data[i].comment
					));
				}
		
				if (callbackPage != undefined && oldSeq == esuli.contentManager.getSeq()) {
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, callbackPage));
				}
			});
	
		c.addDataLevel([ [ "id" ], [ companyId ] ]);
	
		engine.commGate.sendWithSession([ c ]);
	}
	
	/**
	 *
	 */
	this.saveContact = function(contact) {
		var c = new CommGateRequest(
			"REQ_ACCESS",
			[ "SALES_SET_CONTACT" ],
			function(response) {
				contacts.remove(contact.getCompanyId());
				esuli.sales.companyManager.clearCompanies();
				window.location.hash = engine.historyManager.getCurrentLocation() - 1;
			}
		);
	
		c.addDataLevel([
			[ "id", "surname", "forename", "phone", "title", "company_id", "comment" ],
			[ contact.getId(), contact.getSurname(), contact.getForename(), contact.getPhone(), contact.getTitle(), contact.getCompanyId(), contact.getComment() ]
		]);
	
		engine.commGate.sendWithSession([ c ]);
	}
	
	/**
	 *
	 */
	this.deleteContact = function(companyId, id, callbackPage) {
		var oldSeq = esuli.contentManager.getSeq();
	
		var c = new CommGateRequest(
			"REQ_ACCESS",
			[ "SALES_DELETE_CONTACT" ],
			function(response) {
				if (callbackPage != undefined && oldSeq == esuli.contentManager.getSeq()) {
					contacts.remove(companyId);
					esuli.sales.companyManager.clearCompanies();
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, callbackPage));
				}
			}
		);
	
		c.addDataLevel([
			[ "id" ],
			[ id ]
		]);
	
		engine.commGate.sendWithSession([ c ]);
	}
}

/**
 *
 */
var ContactPage = function() {
	
	var lastPage = null;
	
	/**
	 *
	 */
	this.getPage = function(pageRequest) {
		if (! check(pageRequest)) {
			//TODO: Log error
			return;
		}
	
		var companyId = pageRequest.get("companyId");
		var company = esuli.sales.companyManager.getCompany(companyId, { module: pageRequest.get("module"), page: pageRequest.get("page"), companyId: companyId, tabId: 5, subId: 0 });
		if (company == null) {
			return engine.templateManager.getTemplate("contentspin").process({});
		}
	
		switch (pageRequest.get("page")) {
			
			case "contactList":
				var contacts = esuli.sales.contactManager.getContacts(companyId, { module: "sales", page: "contactList", companyId: companyId, tabId: 5, subId: 0 });
		
				if (contacts == null) {
					return engine.templateManager.getTemplate("contentspin").process({});
				} else {
					return engine.templateManager.getTemplate("sales_contactlist").process({ contactList: contacts, companyId: companyId });
				}
		
			break;
		
			case "editContact":
				var id = pageRequest.get("id");
		
				if (id > 0) {
					var contact = esuli.sales.contactManager.getContact(companyId, id, { module: "sales", page: "editContact", companyId: companyId, id: id, tabId: 5, subId: 0 });
			
					if (contact == null) {
						return engine.templateManager.getTemplate("contentspin").process({});
					} else {
						return engine.templateManager.getTemplate("sales_contactform").process({ contact: contact });
					}
				} else {
					var contact = new SalesContact();
					contact.setCompanyId(companyId);
			
					return engine.templateManager.getTemplate("sales_contactform").process({ contact: contact });
				}
		
			break;
		
			case "viewContact":
				var id = pageRequest.get("id");
		
				var contact = esuli.sales.contactManager.getContact(companyId, id, { module: "sales", page: "viewContact", companyId: companyId, id: id, tabId: 5, subId: 0 });
		
				if (contact == null) {
					return engine.templateManager.getTemplate("contentspin").process({});
				} else {
					return engine.templateManager.getTemplate("sales_contactview").process({ contact: contact });
				}
		
			break;
		}
	
		return page;
	}
	
	/**
	 * Returns last visited page
	 * @return Last visited page
	 * @type Object
	 */
	this.getLastPage = function() {
		self.getPage(lastPage);
	}
	
	/**
	 *
	 */
	this.showContactList = function(companyId) {
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { module: "sales", page: "contactList", companyId: companyId, tabId: 5, subId: 0 }));
	}
	
	/**
	 *
	 */
	this.editContact = function(companyId, id) {
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { module: "sales", page: "editContact", companyId: companyId, id: id, tabId: 5, subId: 0 }));
	}
	
	/**
	 *
	 */
	this.viewContact = function(companyId, id) {
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { module: "sales", page: "viewContact", companyId: companyId, id: id, tabId: 5, subId: 0 }));
	}
	
	/**
	 *
	 */
	this.saveContact = function() {
		var contact = null;
	
		if ($("contactId").value.length > 0) {
			contact = esuli.sales.contactManager.getContact($("companyId").value, $("contactId").value);
		} else {
			contact = new SalesContact();
			contact.setCompanyId($("companyId").value);
		}
	
		contact.setSurname($("contactSurname").value.trim());
		contact.setForename($("contactForename").value.trim());
		contact.setPhone($("contactPhone").value.trim());
		contact.setTitle($("contactTitle").value.trim());
		contact.setComment($("contactComment").value.trim());
	
		esuli.sales.contactManager.saveContact(contact);
	}
	
	/**
	 *
	 */
	this.deleteContact = function(companyId, id) {
		engine.dialogManager.add(new Dialog("Biztosan törlöd?", "confirm", [null, function() {esuli.sales.contactManager.deleteContact(companyId, id, { module: "sales", page: "contactList", companyId: companyId, tabId: 5, subId: 0 }); }, null], ["", "Törlés", "Mégse"]));
	}
}
/**
 *
 */
var SalesContract = function(contractId, contractDate, contractAmount, contractRetail, contractHeadcount, contractDetails, contractStatus, contractCompanyId, contractManualId) {
	
	/**
	 *
	 */
	var id = (contractId != undefined ? contractId : null);
	
	/**
	 *
	 */
	var date = (contractDate != undefined ? (contractDate.indexOf(" ") != -1 ? contractDate.substring(0, contractDate.indexOf(" ")) : contractDate) : "");
	
	/**
	 *
	 */
	var amount = (contractAmount != undefined ? contractAmount : "");
	
	/**
	 *
	 */
	var retail = (contractRetail != undefined ? contractRetail : "");
	
	/**
	 *
	 */
	var headcount = (contractHeadcount != undefined ? contractHeadcount : "");
	
	/**
	 *
	 */
	var details = (contractDetails != undefined ? contractDetails : "");
	
	/**
	 *
	 */
	var status = (contractStatus != undefined ? contractStatus : "");
	
	/**
	 *
	 */
	var companyId = (contractCompanyId != undefined ? contractCompanyId : null);
	
	/**
	 *
	 */
	var manualId = (contractManualId != undefined ? contractManualId : "");
	
	/**
	 *
	 */
	this.setId = function(contractId) {
		id = contractId;
	} 
	
	/**
	 *
	 */
	this.getId = function() {
		return id;
	}
	
	/**
	 *
	 */
	this.setDate = function(contractDate) {
		date = (contractDate.indexOf(" ") != -1 ? contractDate.substring(0, contractDate.indexOf(" ")) : contractDate);
	}
	
	/**
	 *
	 */
	this.getDate = function() {
		return date;
	}
	
	/**
	 *
	 */
	this.setAmount = function(contractAmount) {
		amount = contractAmount;
	}
	
	/**
	 *
	 */
	this.getAmount = function() {
		return amount;
	}
	
	/**
	 *
	 */
	this.setRetail = function(contractRetail) {
		retail = contractRetail;
	}
	
	/**
	 *
	 */
	this.getRetail = function() {
		return retail;
	}
	
	/**
	 *
	 */
	this.setHeadcount = function(contractHeadcount) {
		headcount = contractHeadcount;
	}
	
	/**
	 *
	 */
	this.getHeadcount = function() {
		return headcount;
	}
	
	/**
	 *
	 */
	this.setDetails = function(contractDetails) {
		details = contractDetails;
	}
	
	/**
	 *
	 */
	this.getDetails = function() {
		return details;
	}
	
	/**
	 *
	 */
	this.setStatus = function(contractStatus) {
		status = contractStatus;
	}
	
	/**
	 *
	 */
	this.getStatus = function() {
		return status;
	}
	
	/**
	 *
	 */
	this.setCompanyId = function(contractCompanyId) {
		companyId = contractCompanyId;
	}
	
	/**
	 *
	 */
	this.getCompanyId = function() {
		return companyId;
	}
	
	/**
	 *
	 */
	this.setManualId = function(contractManualId) {
		manualId = contractManualId;
	}
	
	/**
	 *
	 */
	this.getManualId = function() {
		return manualId;
	}	
}

/**
 *
 */
var ContractManager = function() {
	
	/**
	 *
	 */
	var contracts = new Map();
	
	/**
	 *
	 */
	this.getContract = function(companyId, id, callbackPage) {
		if (contracts.containsKey(companyId)) {
			var companyContracts = contracts.get(companyId);
		
			for (var i = 0; i < companyContracts.length; i++) {
				if (companyContracts[i].getId() == id) {
					return companyContracts[i];
				}
			}
		}
	
		loadContracts(companyId, callbackPage);
	
		return null;
	}
	
	/**
	 *
	 */
	this.getContracts = function(companyId, callbackPage) {
		if (contracts.containsKey(companyId)) {
			return contracts.get(companyId);
		}
	
		loadContracts(companyId, callbackPage);
	
		return null;
	}
	
	/**
	 *
	 */
	function loadContracts(companyId, callbackPage) {
		var oldSeq = esuli.contentManager.getSeq();
	
		var c = new CommGateRequest(
			"REQ_ACCESS", 
			[ "SALES_GET_COMPANY_CONTRACTS" ], 
			function(response) {
				contracts.put(companyId, new Array());
		
				var data = response[0].getDataAsObjectArray();
		
				for (var i = 0; i < data.length; i++) {
					contracts.get(companyId).push(new SalesContract(
						data[i].id,
						data[i].date,
						data[i].amount,
						data[i].retail,
						data[i].headcount,
						data[i].details,
						data[i].status,
						data[i].company_id,
						data[i].contractid
					));
				}
		
				if (callbackPage != undefined && oldSeq == esuli.contentManager.getSeq()) {
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, callbackPage));
				}
			});
	
		c.addDataLevel([ [ "company_id" ], [ companyId ] ]);
	
		engine.commGate.sendWithSession([ c ]);
	}
	
	/**
	 *
	 */
	this.saveContract = function(contract) {
		var c = new CommGateRequest(
			"REQ_ACCESS",
			[ "SALES_SET_COMPANY_CONTRACT" ],
			function(response) {
				contracts.remove(contract.getCompanyId());
				esuli.sales.companyManager.clearCompanies();
				window.location.hash = engine.historyManager.getCurrentLocation() - 1;
			}
		);
	
		c.addDataLevel([
			[ "id", "company_id", "date", "amount", "retail", "headcount", "details", "status", "contractid" ],
			[ contract.getId(), contract.getCompanyId(), contract.getDate(), contract.getAmount(), contract.getRetail(), contract.getHeadcount(), contract.getDetails(), contract.getStatus(), contract.getManualId() ]
		]);
	
		engine.commGate.sendWithSession([ c ]);
	}
	
	/**
	 *
	 */
	this.deleteContract = function(companyId, id, callbackPage) {
		var oldSeq = esuli.contentManager.getSeq();
	
		var c = new CommGateRequest(
			"REQ_ACCESS",
			[ "SALES_DELETE_COMPANY_CONTRACT" ],
			function(response) {
				if (callbackPage != undefined && oldSeq == esuli.contentManager.getSeq()) {
					contracts.remove(companyId);
					esuli.sales.companyManager.clearCompanies();
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, callbackPage));
				}
			}
		);
	
		c.addDataLevel([
			[ "id" ],
			[ id ]
		]);
	
		engine.commGate.sendWithSession([ c ]);
	}
}
/**
 *
 */
var ContractPage = function() {
	
	var lastPage = null;
	
	/**
	 *
	 */
	this.getPage = function(pageRequest) {
		if (! check(pageRequest)) {
			//TODO: Log error
			return;
		}
	
		var companyId = pageRequest.get("companyId");
		var company = esuli.sales.companyManager.getCompany(companyId, { module: pageRequest.get("module"), page: pageRequest.get("page"), companyId: companyId, tabId: 5, subId: 0 });
		if (company == null) {
			return engine.templateManager.getTemplate("contentspin").process({});
		}
	
		switch (pageRequest.get("page")) {
			
			case "contractList":
				var contracts = esuli.sales.contractManager.getContracts(companyId, { module: "sales", page: "contractList", companyId: companyId, tabId: 5, subId: 0 });
		
				if (contracts == null) {
					return engine.templateManager.getTemplate("contentspin").process({});
				} else {
					return engine.templateManager.getTemplate("sales_contractlist").process({ contractList: contracts, companyId: companyId });
				}
		
				break;
		
			case "editContract":
				var id = pageRequest.get("id");
		
				if (id > 0) {
					var contract = esuli.sales.contractManager.getContract(companyId, id, { module: "sales", page: "editContract", companyId: companyId, id: id, tabId: 5, subId: 0 });
			
					if (contract == null) {
						return engine.templateManager.getTemplate("contentspin").process({});
					} else {
						return engine.templateManager.getTemplate("sales_contractform").process({ contract: contract });
					}
				} else {
					var contract = new SalesContract();
					contract.setCompanyId(companyId);
			
					return engine.templateManager.getTemplate("sales_contractform").process({ contract: contract });
				}
		
				break;
		
			case "viewContract":
				var id = pageRequest.get("id");
		
				var contract = esuli.sales.contractManager.getContract(companyId, id, { module: "sales", page: "viewContract", companyId: companyId, id: id, tabId: 5, subId: 0 });
		
				if (contract == null) {
					return engine.templateManager.getTemplate("contentspin").process({});
				} else {
					return engine.templateManager.getTemplate("sales_contractview").process({ contract: contract });
				}
		
				break;
		}
	
		return page;
	}
	
	/**
	 * Returns last visited page
	 * @return Last visited page
	 * @type Object
	 */
	this.getLastPage = function() {
		self.getPage(lastPage);
	}
	
	/**
	 *
	 */
	this.showContractList = function(companyId) {
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { module: "sales", page: "contractList", companyId: companyId, tabId: 5, subId: 0 }));
	}
	
	/**
	 *
	 */
	this.editContract = function(companyId, id) {
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { module: "sales", page: "editContract", companyId: companyId, id: id, tabId: 5, subId: 0 }));
	}
	
	/**
	 *
	 */
	this.viewContract = function(companyId, id) {
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { module: "sales", page: "viewContract", companyId: companyId, id: id, tabId: 5, subId: 0 }));
	}
	
	/**
	 *
	 */
	this.saveContract = function() {
		var contact = null;
	
		if ($("contractId").value.length > 0) {
			contract = esuli.sales.contractManager.getContract($("companyId").value, $("contractId").value);
		} else {
			contract = new SalesContract();
			contract.setCompanyId($("companyId").value);
		}
	
		if (! $("contractDate").value.match(/^[\d]{4}-[\d]{2}-[\d]{2}$/)) {
			engine.dialogManager.add(new Dialog("Hibás dátumformátum, a következő formában kell megadni: éééé-hh-nn!", "alert"));
			return;
		}
	
		contract.setDate($("contractDate").value.trim());
		contract.setAmount($("contractAmount").value.trim());
		contract.setRetail($("contractRetail").value.trim());
		contract.setHeadcount($("contractHeadcount").value.trim());
		contract.setDetails($("contractDetails").value.trim());
		contract.setStatus($("contractStatus").value.trim());
		contract.setManualId($("contractManualId").value.trim());
	
		esuli.sales.contractManager.saveContract(contract);
	}
	
	/**
	 *
	 */
	this.deleteContract = function(companyId, id) {
		engine.dialogManager.add(new Dialog("Biztosan törlöd?", "confirm", [null, function() {esuli.sales.contractManager.deleteContract(companyId, id, { module: "sales", page: "contractList", companyId: companyId, tabId: 5, subId: 0 });}, null], ["", "Törlés", "Mégse"]));
	}
}
/**
 *
 */
var SalesEvent = function(eventId, eventDate, eventDescription, eventCompanyId) {
	
	/**
	 *
	 */
	var id = (eventId != undefined ? eventId : null);
	
	/**
	 *
	 */
	var date = (eventDate != undefined ? (eventDate.indexOf(" ") != -1 ? eventDate.substring(0, eventDate.indexOf(" ")) : eventDate) : "");
	
	/**
	 *
	 */
	var description = (eventDescription != undefined ? eventDescription : "");
	
	/**
	 *
	 */
	var companyId = (eventCompanyId != undefined ? eventCompanyId : null);
	
	/**
	 *
	 */
	this.setId = function(eventId) {
		id = eventId;
	}
	
	/**
	 *
	 */
	this.getId = function() {
		return id;
	}
	
	/**
	 *
	 */
	this.setDate = function(eventDate) {
		date = (eventDate.indexOf(" ") != -1 ? eventDate.substring(0, eventDate.indexOf(" ")) : eventDate);
	}
	
	/**
	 *
	 */
	this.getDate = function() {
		return date;
	}
	
	/**
	 *
	 */
	this.setDescription = function(eventDescription) {
		description = eventDescription;
	}
	
	/**
	 *
	 */
	this.getDescription = function() {
		return description;
	}
	
	/**
	 *
	 */
	this.setCompanyId = function(eventCompanyId) {
		companyId = eventCompanyId;
	}
	
	/**
	 *
	 */
	this.getCompanyId = function() {
		return companyId;
	}
}

/**
 *
 */
var EvtManager = function() {
	
	/**
	 *
	 */
	var events = new Map();
	
	/**
	 *
	 */
	this.getEvent = function(companyId, id, callbackPage) {
		if (events.containsKey(companyId)) {
			var companyEvents = events.get(companyId);
		
			for (var i = 0; i < companyEvents.length; i++) {
				if (companyEvents[i].getId() == id) {
					return companyEvents[i];
				}
			}
		}
	
		loadEvents(companyId, callbackPage);
	
		return null;
	}
	
	/**
	 *
	 */
	this.getEvents = function(companyId, callbackPage) {
		if (events.containsKey(companyId)) {
			return events.get(companyId);
		}
	
		loadEvents(companyId, callbackPage);
	
		return null;
	}
	
	/**
	 *
	 */
	function loadEvents(companyId, callbackPage) {
		var oldSeq = esuli.contentManager.getSeq();
	
		var c = new CommGateRequest(
			"REQ_ACCESS", 
			[ "SALES_GET_COMPANY_EVENTS" ], 
			function(response) {
				events.put(companyId, new Array());
		
				var data = response[0].getDataAsObjectArray();
		
				for (var i = 0; i < data.length; i++) {
					events.get(companyId).push(new SalesEvent(
						data[i].id,
						data[i].date,
						data[i].description,
						data[i].company_id
					));
				}
		
				if (callbackPage != undefined && oldSeq == esuli.contentManager.getSeq()) {
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, callbackPage));
				}
			});
	
		c.addDataLevel([ [ "company_id" ], [ companyId ] ]);
	
		engine.commGate.sendWithSession([ c ]);
	}
	
	/**
	 *
	 */
	this.saveEvent = function(event) {
		var c = new CommGateRequest(
			"REQ_ACCESS",
			[ "SALES_SET_COMPANY_EVENT" ],
			function(response) {
				events.remove(event.getCompanyId());
				esuli.sales.companyManager.clearCompanies();
				window.location.hash = engine.historyManager.getCurrentLocation() - 1;
			}
		);
	
		c.addDataLevel([
			[ "id", "company_id", "date", "description" ],
			[ event.getId(), event.getCompanyId(), event.getDate(), event.getDescription() ]
		]);
	
		engine.commGate.sendWithSession([ c ]);
	}
	
	/**
	 *
	 */
	this.deleteEvent = function(companyId, id, callbackPage) {
		var oldSeq = esuli.contentManager.getSeq();
	
		var c = new CommGateRequest(
			"REQ_ACCESS",
			[ "SALES_DELETE_COMPANY_EVENT" ],
			function(response) {
				if (callbackPage != undefined && oldSeq == esuli.contentManager.getSeq()) {
					events.remove(companyId);
					esuli.sales.companyManager.clearCompanies();
					window.location.hash = engine.historyManager.getCurrentLocation() - 1;
					//engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, callbackPage));
				}
			}
		);
	
		c.addDataLevel([
			[ "id" ],
			[ id ]
		]);
	
		engine.commGate.sendWithSession([ c ]);
	}
}
/**
 *
 */
var EvtPage = function() {
	
	var lastPage = null;
	
	/**
	 *
	 */
	this.getPage = function(pageRequest) {
		if (! check(pageRequest)) {
			//TODO: Log error
			return;
		}
	
		var companyId = pageRequest.get("companyId");
		var company = esuli.sales.companyManager.getCompany(companyId, { module: pageRequest.get("module"), page: pageRequest.get("page"), companyId: companyId, tabId: 5, subId: 0 });
		if (company == null) {
			return engine.templateManager.getTemplate("contentspin").process({});
		}
	
		switch (pageRequest.get("page")) {
			
			case "eventList":
				var events = esuli.sales.evtManager.getEvents(companyId, { module: "sales", page: "eventList", companyId: companyId, tabId: 5, subId: 0 });
		
				if (events == null) {
					return engine.templateManager.getTemplate("contentspin").process({});
				} else {
					return engine.templateManager.getTemplate("sales_eventlist").process({ eventList: events, companyId: companyId });
				}
		
				break;
		
			case "editEvent":
				var id = pageRequest.get("id");
		
				if (id > 0) {
					var event = esuli.sales.evtManager.getEvent(companyId, id, { module: "sales", page: "editEvent", companyId: companyId, id: id, tabId: 5, subId: 0 });
			
					if (event == null) {
						return engine.templateManager.getTemplate("contentspin").process({});
					} else {
						return engine.templateManager.getTemplate("sales_eventform").process({ event: event });
					}
				} else {
					var event = new SalesEvent();
					event.setCompanyId(companyId);
			
					return engine.templateManager.getTemplate("sales_eventform").process({ event: event });
				}
	
				break;
		
			case "viewEvent":
				var id = pageRequest.get("id");
		
				var event = esuli.sales.evtManager.getEvent(companyId, id, { module: "sales", page: "viewEvent", companyId: companyId, id: id, tabId: 5, subId: 0 });
		
				if (event == null) {
					return engine.templateManager.getTemplate("contentspin").process({});
				} else {
					return engine.templateManager.getTemplate("sales_eventview").process({ event: event });
				}
		
				break;
		}
	
		return page;
	}
	
	/**
	 * Returns last visited page
	 * @return Last visited page
	 * @type Object
	 */
	this.getLastPage = function() {
		self.getPage(lastPage);
	}
	
	/**
	 *
	 */
	this.showEventList = function(companyId) {
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { module: "sales", page: "eventList", companyId: companyId, tabId: 5, subId: 0 }));
	}
	
	/**
	 *
	 */
	this.editEvent = function(companyId, id) {
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { module: "sales", page: "editEvent", companyId: companyId, id: id, tabId: 5, subId: 0 }));
	}
	
	/**
	 *
	 */
	this.viewEvent = function(companyId, id) {
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { module: "sales", page: "viewEvent", companyId: companyId, id: id, tabId: 5, subId: 0 }));
	}
	
	/**
	 *
	 */
	this.saveEvent = function() {
		var event = null;
	
		if ($("eventId").value.length > 0) {
			event = esuli.sales.evtManager.getEvent($("companyId").value, $("eventId").value);
		} else {
			event = new SalesEvent();
			event.setCompanyId($("companyId").value);
		}
	
		if (! $("eventDate").value.match(/^[\d]{4}-[\d]{2}-[\d]{2}$/)) {
			engine.dialogManager.add(new Dialog("Hibás dátumformátum, a következő formában kell megadni: éééé-hh-nn!", "alert"));
			return;
		}
	
		event.setDate($("eventDate").value.trim());
		event.setDescription($("eventDescription").value.trim());
	
		esuli.sales.evtManager.saveEvent(event);
	}
	
	/**
	 *
	 */
	this.deleteEvent = function(companyId, id) {
		engine.dialogManager.add(new Dialog("Biztosan törlöd?", "confirm", [null, function() {esuli.sales.evtManager.deleteEvent(companyId, id, { module: "sales", page: "eventList", companyId: companyId, tabId: 5, subId: 0 });}, null], ["", "Törlés", "Mégse"]));
	}
}
/**
 *
 */
var Sales = function() {
	
	var lastPage = null;
	
	/**
	 * Company
	 */
	this.companyManager = new CompanyManager();
	this.companyPage = new CompanyPage();
	
	/**
	 * Contact
	 */
	this.contactManager = new ContactManager();
	this.contactPage = new ContactPage();
	
	/**
	 * Contract
	 */
	this.contractManager = new ContractManager();
	this.contractPage = new ContractPage();
	
	/**
	 * Event
	 */
	this.evtManager = new EvtManager();
	this.evtPage = new EvtPage();
	
	/**
	 * Pointer to this
	 * @type Shopping
	 */
	var self = this;
	
	/**
	 * Returns requested page
	 * @param Object Page request
	 * @return Requested page
	 * @type Object
	 */
	this.getPage = function(pageRequest) {
		if (! check(pageRequest)) {
			//TODO: Log error
			return;
		}
	
		var page = { leftWidth: '0px', centerWidth: '968px', rightWidth: '0px', left: '', center: '', right: '' };
		
		if(esuli.user.getRole() != 'agent') {
			page.center = engine.templateManager.getTemplate("sales_notagent").process({});
		} else {
			switch (pageRequest.get("page")) {
		
				case "companyList":
				case "editCompany":
				case "viewCompany":
					page.center = self.companyPage.getPage(pageRequest);
					break;
		
				case "contactList":
				case "editContact":
				case "viewContact":
					page.center = self.contactPage.getPage(pageRequest);
					break;
		
				case "contractList":
				case "editContract":
				case "viewContract":
					page.center = self.contractPage.getPage(pageRequest);
					break;
		
				case "eventList":
				case "editEvent":
				case "viewEvent":
					page.center = self.evtPage.getPage(pageRequest);
					break;
		
				default:
				//TODO: Log error
				return;
			}
		}
	
		lastPage = pageRequest;
	
		return page;
	}
	
	/**
	 * Returns last visited page
	 * @return Last visited page
	 * @type Object
	 */
	this.getLastPage = function() {
		self.getPage(lastPage);
	}
	
	//Initialize
	this.init = function() {
		esuli.tab.showTabMenu("Sales", true);
		esuli.tab.setActiveTab("Sales", "Sales");
		esuli.tab.setActiveSubMenu(0);
	}
}
/**
 * 
 */
function PayingIn(pID, pPID, pName, pDate, pState, pPrice, pPaymentType, pComment) {
		
	/**
	* Befizetés id
	* @type Number
	*/
	var id = new Number(pID);
	
	/**
	 * Termék id
	 * @type Number
	 */
	var pid = new Number(pPID);
	
	/**
	 * Termék elnevezése
	 * @type String
	 */
	var name = new String(pName);
	
	/**
	 * Befizetés dátuma
	 * @type String
	 */
	var payingInDate = new String(pDate);
	
	/**
	 * Befizetés státusza
	 * @type String
	 */
	var state = new String(pState);
	
	/**
	* Befizetés ára
	* @type Number
	*/
	var price = new Number(pPrice);
	
	/**
	 * Berizetési mód
	 * @type String
	 */
	var paymentType = new String(pPaymentType);
	
	/**
	 * Megjegyzés a befizetéshez
	 * @type String
	 */
	var comment = new String(pComment);
	
	/**
	 * Visszaadja a Befizetés id-ját
	 * @return Befizetés id
	 * @type Number
	 */
	this.getId = function() {
		return id;
	}
	
	/**
	 * Visszaadja a Termék id-ját
	 * @return Termék id
	 * @type Number
	 */
	this.getPId = function() {
		return pid;
	}
	
	/**
	 * Visszaadja a Termék elnevezését
	 * @return Termék elnevezése
	 * @type String
	 */
	this.getName = function() {
		return name;
	}
	
	/**
	 * Visszaadja a Befizetés dátumát
	 * @return Befizetés dátuma
	 * @type Date
	 */
	this.getDate = function() {
		return payingInDate;
	}
	
	/**
	 * Visszaadja a Befizetés státuszát
	 * @return Befizetés státusza
	 * @type String
	 */
	this.getState = function() {
		return state;
	}
	
	/**
	 * Beállítja a Befizetés státuszát
	 * @param String Státusz
	 */
	this.setState = function( pState ) {
		state = pState;
	}
	
	/**
	 * Visszaadja a Befizetés árát
	 * @return Befizetés ára
	 * @type Number
	 */
	this.getPrice = function() {
		return price;
	}
	
	/**
	 * Visszaadja a Befizetés árát megformázva
	 * @return Befizetés ára megformázva
	 * @type String
	 */
	this.getStyledPrice = function() {
		var styledPrice = price.toString();
		if( styledPrice.length > 3 ) {
			var ret;
			ret = styledPrice.substring( 0, ( styledPrice.length - 3 ) );
			ret += ".";
			ret += styledPrice.substring( styledPrice.length - 3 );
			return ret;
		} else {
			return styledPrice;
		}
	}
	
	/**
	 * Visszadja a Befizetés típusát
	 * @return Befizetés típusa
	 * @type String
	 */
	this.getPaymentType = function() {
		return paymentType;
	}
	
	/**
	 * Visszaadja a Befizetéshez írt megjegyzést
	 * @return Megjegyzés
	 * @type String
	 */
	this.getComment = function() {
		return comment;
	}
}
/**
 * 
 * 
 */
function PayingInListPage() {
	
	/**
	 * Last visited page
	 * @type Object
	 */
	var lastPage;
	
	/**
	 * Orders downloaded
	 * @type Boolean
	 */
	var ordersLoaded = false;
	
	/**
	 * Paid-up orders array
	 * @type Array
	 */
	this.paidUp = new Array();
	
	/**
	 * Not paid-up orders array
	 * @type Array
	 */
	this.notPaidUp = new Array();
	
	/**
	 * New paying in orders array
	 * @type Array
	 */
	this.newPayingIn = new Array();
	
	/**
	 * Pointer to this
	 * @type Shopping
	 */
	var self = this;
	
	/**
	 * Set orders loaded or not
	 * @param Boolean Loaded or not
	 */
	this.setOrdersLoaded = function( pLoaded ) {
		ordersLoaded = pLoaded;
	}
	
	/**
	 * Add product to paying in array
	 * @param Number Product id, String User comment
	 */
	this.toPayingIn = function( pId, pComment ) {
		var find = false;
		var product = esuli.shopping.products.getProduct( pId );
		
		if( product ) {
			var comment = pComment ? pComment : "";
			var randomId = Math.floor( Math.random() * 100000 + 1 );
			payingIn = new PayingIn( randomId, product.getId(), product.getName(), "", "Új", product.getPrice(), "", comment);

			self.newPayingIn.push(payingIn);
			
			self.sendSeasonTicketMail(product.getName(), product.getPrice());

			esuli.shopping.payingInPage.showPayingInPage(randomId);
		} else {
			engine.dialogManager.add(new Dialog("Olyan terméket választottál, ami jelenleg nem elérhető!", "alert", null));
		}
	}
	
	/**
	 * Get new paying in array, or by id
	 * @return New paying in Objects array
	 * @type Array, Object
	 */
	this.getNewPayingIn = function( pId ) {
		if( pId ) {
			var ret;
			for (var i = 0; i < self.newPayingIn.length; i++) {	
				if( self.newPayingIn[i].getId() == pId ) {
					ret = self.newPayingIn[i];
					break;
				}
			}
		} else {
			var ret = new Array();
			for (var i = 0; i < self.newPayingIn.length; i++) {	
				if( self.newPayingIn[i].getState() == "Új" ) {
					ret.push( self.newPayingIn[i] );
				}
			}	
		}
		return ret;
	}
	
	/**
	 * Get not paid up in array, or by id
	 * @return Not paid up in Objects array
	 * @type Array, Object
	 */
	this.getNotPaidUpPayingIn = function( pId ) {
		if( pId ) {
			var ret;
			for (var i = 0; i < self.notPaidUp.length; i++) {	
				if( self.notPaidUp[i].getId() == pId ) {
					ret = self.notPaidUp[i];
					break;
				}
			}
		} else {
			var ret = new Array();
			for (var i = 0; i < self.notPaidUp.length; i++) {	
				if( self.notPaidUp[i].getState() == "Új" ) {
					ret.push( self.notPaidUp[i] );
				}
			}	
		}
		return ret;
	}
	
	/**
	 * Change paying in status
	 * @param Product Id
	 */
	this.removeNewPayingIn = function( pId ) {
		for (var i = 0; i < self.newPayingIn.length; i++) {	
			if( ( pId.toString() == self.newPayingIn[i].getId().toString() ) && ( self.newPayingIn[i].getState() == "Új" ) ) {
				self.newPayingIn[i].setState("Fizetésre vár");
				break;
			}
		}
	}
	
	/**
	 * Send curse registration
	 */
	this.sendCourseRegistration = function() {
		var headcount = $("courseHeadcount");
		var coursecount = $("courseCoursecount");
		var dateTime = $("courseDateTime");
		var comments = $("courseComments");
		
		if(!headcount || !dateTime || !comments) {
			return;
		}
		
		headcount.className = 'normalSelect';
		dateTime.className = 'normalTextarea';
		comments.className = 'normalTextarea';
		
		if(esuli.staticContent.trimTextInput(dateTime.value) == '') {
			dateTime.className = 'normalTextareaError';
			engine.dialogManager.add(new Dialog('Kérjük add meg, milyen napokon és időpontban szeretnél járni!', 'alert'));
			return;
		}
		
		var products = esuli.shopping.products.getProducts( "Tanfolyam" );
		
		if( ! products ) {
			engine.dialogManager.add(new Dialog('Olyan terméket választottál, ami jelenleg nem elérhető!', "alert", null));
			return;
		}
		
		switch (coursecount.value) {
			case "1": coursecount = "32"; break;
			case "2": coursecount = "64"; break;
			case "4": coursecount = "128"; break;
		}
		
		var find = false;
		var product;
		
		for (var i = 0; i < products.length; i++) {
			if( headcount.value == products[i].getMaxHeadCount() && coursecount == products[i].getHours() ) {
				if( esuli.user.getPhase() == "ingyenes" && coursecount == "32" ) {
					if( products[i].getComment() == "kedvezménnyel" ) {
						product = products[i];
						find = true;
						break;
					} else {
						continue;
					}
				} else {
					if( products[i].getComment() == "kedvezménnyel" ) {
						continue;
					} else {
						product = products[i];
						find = true;
						break;
					}
				}
			}
		}
		
		if( find ) {
			var comment = '<div class="staticFormList">'
						+ '<span class="payingin">Választott időpontok:</span>'
						+ '<div class="payingin">' + dateTime.value + '</div>'
						+ '<br class="clear" clear="all"/>'
						+ '</div>'
						+ '<div class="staticFormList">'
						+ '<span class="payingin">Megjegyzések:</span>'
						+ '<div class="payingin">' + comments.value + '</div>'
						+ '<br class="clear" clear="all"/>'
						+ '</div>';

			var randomId = Math.floor( Math.random() * 100000 + 1 );
			
			payingIn = new PayingIn(randomId, product.getId(), product.getName(), "", "Új", product.getPrice(), "", comment);
			self.newPayingIn.push(payingIn);
		} else {
			engine.dialogManager.add(new Dialog("Olyan terméket választottál, ami jelenleg nem elérhető!", "alert", null));
			return;
		}
		
		switch (headcount.value) {
			case "1": headcount = "Magánóra"; break;
			case "2": headcount = "2 fős csoport"; break;
			case "3": headcount = "3 fős csoport"; break;
			case "4": headcount = "4 fős csoport"; break;
			case "6": headcount = "Kiscsoport (5-6 fő)"; break;
		}
		
		switch (coursecount) {
			case "32": coursecount = "1 tanfolyamra (0% kedvezmény)"; break;
			case "64": coursecount = "2 tanfolyamra (10% kedvezmény)"; break;
			case "128": coursecount = "4 tanfolyamra (15% kedvezmény)"; break;
		}
		
		self.sendCourseRegistrationMail( headcount, coursecount, dateTime.value, comments.value );
		
		esuli.shopping.payingInPage.showPayingInPage(randomId);
	}
	
	/**
	 * Send mail in curse registration
	 * @param 
	 */
	this.sendCourseRegistrationMail = function( pHeadcount, pCoursecount, pDateTime, pComments ) {
		var email = esuli.user.getEmail();
		var surname = esuli.user.getLivingAddress().getSurname() ? esuli.user.getLivingAddress().getSurname() : "";
		var forename = esuli.user.getLivingAddress().getForename() ? esuli.user.getLivingAddress().getForename() : "";
		var name = surname + " " + forename;
		var tel = esuli.user.getPhone() ? esuli.user.getPhone() : "";
		
		var message = "";
			message += "Beiratkozás új tanfolyamra" + "\n\n"
					+ "Az alábbi felhasználó beiratkozást kezdeményezett!" + "\n\n"
					+ "E-mail cím: " + email + "\n"
					+ "Név: " + name + "\n"
					+ "Telefon: " + tel + "\n"
					+ "Létszám: " + pHeadcount + "\n"
					+ "Darabszám: " + pCoursecount + "\n\n"
					+ "Időpontok: " + pDateTime + "\n\n"
					+ "Megjegyzések: " + pComments + "\n\n";
					+ "- automata értesítés -";
		
		engine.commGate.send([ new CommGateRequest("SEND_EMAIL", [ "info@enyelviskola.hu", message, "Beiratkozás új tanfolyamra" ], null ), new CommGateRequest("HAVE_SESSION", [ esuli.user.getSessionId() ], null ) ] );
	}
	
	/**
	 * Send mail in season ticket purchase
	 * @param String Product name, Product price
	 */
	this.sendSeasonTicketMail = function(pProductName, pProductPrice) {
		var email = esuli.user.getEmail();
		var surname = esuli.user.getLivingAddress().getSurname() ? esuli.user.getLivingAddress().getSurname() : "";
		var forename = esuli.user.getLivingAddress().getForename() ? esuli.user.getLivingAddress().getForename() : "";
		var name = surname + " " + forename;
		var tel = esuli.user.getPhone() ? esuli.user.getPhone() : "";
		
		var message = "";
			message += "Havibérlet vásárlás" + "\n\n"
					+ "Az alábbi felhasználó havibérlet vásárlást kezdeményezett!" + "\n\n"
					+ "E-mail cím: " + email + "\n"
					+ "Név: " + name + "\n"
					+ "Telefon: " + tel + "\n"
					+ "Termék név: " + pProductName + "\n"
					+ "Termék ár: " + pProductPrice+ "\n\n";
					+ "- automata értesítés -";
		engine.commGate.send([ new CommGateRequest("SEND_EMAIL", [ "info@enyelviskola.hu", message, "Havibérlet vásárlás" ], null ), new CommGateRequest("HAVE_SESSION", [ esuli.user.getSessionId() ], null ) ] );
	}
	
	/**
	 * Loads orders from database
	 * @return Orders
	 */
	function loadOrders(pPayment) {		
		var comm = new CommGateRequest("REQ_ACCESS", [ "ESULI_GET_ORDERS" ], function(response) {
		    self.paidUp = new Array();
		    self.notPaidUp = new Array();
			
			var data = response[0].getDataAsObjectArray();
			var date;
			
		    for (var i = 0; i < data.length; i++) {
				date = data[i].date;
				
				if (date.indexOf(".") > -1) {
					date = date.split(".");
					date = date[0];
				}

				date = date.substr(0, date.length - 3);
				
	    		payingIn = new PayingIn(data[i].id, data[i].productid, data[i].productname, date, data[i].state, data[i].price, data[i].paymenttype, ( data[i].comment ? data[i].comment : "" ) );
				
		    	if (data[i].state == "Teljesített") {
		    		self.paidUp.push(payingIn);
		    	} else {
		    		self.notPaidUp.push(payingIn);
		    	}
		    }
		    
		    ordersLoaded = true;
			
			if (esuli.tab.activeTab == "Asztal" || esuli.tab.activeTab == "Tanfolyamok") {
				esuli.tab.changeTabAndSubMenu( 'Asztal', 3);
				engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { module: "user", page: "profile", payment: pPayment }));
			}
		});
		
		comm.addDataLevel([ [ "" ],[ "" ] ]);
		engine.commGate.sendWithSession([ comm ]);
	 }
	
	/**
	 * Returns requested page
	 * @param Object Page request
	 * @return Requested page
	 * @type Object
	 */
	this.getPage = function(pageRequest) {
		if (! check(pageRequest)) {
			//TODO: Log error
			return;
		}
		
		var page = { leftWidth: '372px', centerWidth: '371px', rightWidth: '225px', center: ""};
		if( ordersLoaded ) {
			if( ! esuli.shopping.products.isLoaded()  ) {
				page.center = engine.templateManager.getTemplate("contentspin").process({});
				esuli.shopping.products.loadProducts();
			} else {
				var payment = pageRequest.get("payment") ? engine.templateManager.getTemplate("shopping_cart_" + pageRequest.get("payment")).process({}) : "";
				page.center = engine.templateManager.getTemplate("shopping_payinginlist").process({ paidup:self.paidUp, notpaidup:self.notPaidUp, newpayingin:self.getNewPayingIn(), payment:payment });
			}
		} else {
			page.center = engine.templateManager.getTemplate("contentspin").process({});
			var payment = pageRequest.get("payment") ? pageRequest.get("payment") : null;
			loadOrders(payment);
		}
		
		lastPage = pageRequest;
		
		return page;
	}
	
	/**
	 * Returns last visited page
	 * @return Last visited page
	 * @type Object
	 */
	this.getLastPage = function() {
		self.getPage(lastPage);
	}
	
}
/**
 * 
 * 
 */
function PayingInPage() {
	
	/**
	 * Last visited page
	 * @type Object
	 */
	var lastPage;
	
	/**
	 * Paying in Id
	 * @type Number
	 */
	var payingInId;
	
	/**
	 * Paying in Object
	 * @type Object
	 */
	var payingIn;
	
	/**
	 * Product id
	 * @type Number
	 */
	var productId;
	
	/**
	 * Product Object
	 * @type Object
	 */
	var product;
	
	/**
	 * Is contract accepted
	 * @type Boolean
	 */
	var contractAccepted = false;
	
	/**
	 * Type of payment
	 * @type String
	 */
	var paymentType = "-1";
	
	/**
	 * Plus esuli banalnce to type of payment
	 * @type Boolean
	 */
	var plusEsuliBalance = false;
	
	/**
	 * Update profile
	 * @type Boolean
	 */
	var updateProfile = true;
	
	/**
	 * Invoice delivery
	 * @type Boolean
	 */
	var invoiceDelivery = false;
	
	/**
	 * Last product pice
	 * @type Number
	 */
	var lastPrice;
	
	/**
	 * Pointer to this
	 * @type Shopping
	 */
	var self = this;
	
	/**
	 * Sets contract accept
	 * @param Boolean Is contract accepted
	 */
	this.setContractAccepted = function(accept) {
		contractAccepted = accept;
	}
	
	/**
	 * Returns contract accept
	 * @return Is contract accepted
	 * @type Boolean
	 */
	this.isContractAccepted = function() {
		return contractAccepted;
	}
	
	/**
	 * Sets payment type
	 * @param String Type of payment
	 */
	this.setPaymentType = function(payment) {
		paymentType = payment;
	}
	
	/**
	 * Returns payment type
	 * @return Type of payment
	 * @type String
	 */
	this.getPaymentType = function() {
		return paymentType;
	}
	
	/**
	 * Sets esuli balance
	 * @param Boolean Is plus esuli balance
	 */
	this.setPlusEsuliBalance = function(need) {
		plusEsuliBalance = need;
	}
	
	/**
	 * Returns plus esuli balance
	 * @return Is plus esuli balance
	 * @type Boolean
	 */
	this.isPlusEsuliBalance = function() {
		return plusEsuliBalance;
	}
	
	/**
	 * Sets profile update
	 * @param Boolean Update profile or not
	 */
	this.setUpdateProfile = function(profile) {
		updateProfil = profile;
	}
	
	/**
	 * Return profile update
	 * @return Update profile or not
	 * @type Boolean
	 */
	this.isUpdateProfile = function() {
		return updateProfile;
	}
	
	/**
	 * Sets invoice delivery
	 * @param Boolean Deliver invoice or not
	 */
	this.setInvoiceDelivery = function(invoice) {
		invoiceDelivery = invoice;
	}
	
	/**
	 * Return invoice delivery
	 * @return Deliver invoice or not
	 * @type Boolean
	 */
	this.isInvoiceDelivery = function() {
		return invoiceDelivery;
	}
	
	/**
	 * Return last product price
	 * @return Last price
	 * @type Number
	 */
	this.getLastPrice = function() {
		return lastPrice;
	}
	
	/**
	 * Checks everything and posts order
	 */
	this.pay = function() {
		if(!contractAccepted) {
			engine.dialogManager.add(new Dialog("Vásárlás csak a Tanulmányi szerződés elfogadása után véglegesíthető!", "alert"));
			return;
		}
		
		if(paymentType == "-1") {
			engine.dialogManager.add(new Dialog("Válassz fizetési módot.", "alert"));
			return;
		}
		
		if(paymentType == "esulibalance" && product.getPrice() > esuli.user.getCredit()) {
			engine.dialogManager.add(new Dialog("Ehhez a vásárláshoz nem rendelkezel elegendő belső egyenleggel!", "alert"));			
			return;
		}
		
		if ( $("surname").value == "" ||
			$("forename").value == "" ||
			$("living_city").value == "" ||
			$("living_pbox").value == "" ||
			$("living_street").value == ""
			) {
			engine.dialogManager.add(new Dialog("Kérünk, add meg a lakcímedet!", "alert"));
			return;
		}
		
		if ( $("billing_name").value == "" ||
			$("billing_city").value == "" ||
			$("billing_pbox").value == "" ||
			$("billing_street").value == "" 
			) {
			engine.dialogManager.add(new Dialog("Kérünk, add meg a számlázási címedet!", "alert"));
			return;
		}
		
		if ( ( $("delivery_name").value == "" ||
				$("delivery_city").value == "" ||
				$("delivery_pbox").value == "" ||
				$("delivery_street").value == ""
			) && ( paymentType == "yellowcheque" || invoiceDelivery
			) ) {
			engine.dialogManager.add(new Dialog("Kérünk, add meg a postázási címedet!", "alert"));
			return;	
		}
			
		var paymentHun;
		switch (paymentType) {
			case "yellowcheque": paymentHun = "Sárga csekk"; break;
			case "banktransfer": paymentHun = "Banki átutalás"; break;
			case "bankcard":     paymentHun = "Bankkártyás fizetés"; break;
			case "paypal":       paymentHun = "PayPal"; break;
			case "esulibalance": paymentHun = "Belső egyenleg"; break;
		}
		
		if(plusEsuliBalance) {
			paymentHun += " + Belső egyenleg";
		}
		
		var comm = new CommGateRequest("REQ_ACCESS", [ "ESULI_PAYINGIN" ], function(response) {
			//update user profile
			esuli.user.updateProfile();
			
			if (paymentType == "esulibalance") {
				esuli.user.setCredit(esuli.user.getCredit() - payingIn.getPrice());
			}
			
			lastPrice = payingIn.getPrice();
			
			esuli.shopping.payingInListPage.removeNewPayingIn(payingIn.getId());
			
			esuli.shopping.payingInListPage.setOrdersLoaded(false);
			
			engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { module: "user", page: "profile", payment: paymentType }));
		});
		
		comm.addDataLevel([
			[
				"PRODUCT_ID",
				"PAYMENT",
				"SURNAME",
				"FORENAME",
				"CITY",
				"PBOX",
				"ADDRESS",
				"DELIVERY_NAME",
				"DELIVERY_CITY",
				"DELIVERY_PBOX",
				"DELIVERY_ADDRESS",
				"BILLING_NAME",
				"BILLING_CITY",
				"BILLING_PBOX",
				"BILLING_ADDRESS",
				"INVOICE",
				"PRODUCT_TYPE",
				"COMMENT"
			],
			[
				productId,
				paymentHun,
				$("surname").value,
				$("forename").value,
				$("living_city").value,
				$("living_pbox").value,
				$("living_street").value,
				$("delivery_name").value,
				$("delivery_city").value,
				$("delivery_pbox").value,
				$("delivery_street").value,
				$("billing_name").value,
				$("billing_city").value,
				$("billing_pbox").value,
				$("billing_street").value,
				(invoiceDelivery ? "true" : "false"),
				product.getType(),
				payingIn.getComment()
			]
		]);

		engine.commGate.sendWithSession([ comm ]);
	}
	
	/**
	 * Show paying in page
	 * @param Selected paying in id
	 * @type Number 
	 */
	this.showPayingInPage = function( pId ) {
		payingInId = pId;
		payingIn = esuli.shopping.payingInListPage.getNewPayingIn( payingInId );
		if( !payingIn ) {
			payingIn = esuli.shopping.payingInListPage.getNotPaidUpPayingIn( payingInId );
		}
		
		if( payingIn ) {
			if( productId != payingIn.getPId() ) {
				if( ( paymentType == "esulibalance" ) && ( esuli.user.getCredit() < product.getPrice() ) ) {
					self.setPaymentType("-1");
				}
				if( esuli.user.getCredit() >= payingIn.getPrice() ) {
					self.setPlusEsuliBalance(false);
				}
			}
			productId = payingIn.getPId();
			product = esuli.shopping.products.getProduct( productId );
			
			engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { module: "shopping", page: "payingin" }));
		} else {
			engine.dialogManager.add(new Dialog("Olyan terméket választottál, ami jelenleg nem elérhető!", "alert", null));
		}
	}
	
	/**
	 * Returns requested page
	 * @param Object Page request
	 * @return Requested page
	 * @type Object
	 */
	this.getPage = function(pageRequest) {
		if (! check(pageRequest)) {
			//TODO: Log error
			return;
		}
		
		var page = { leftWidth: '372px', centerWidth: '371px', rightWidth: '225px', left: "", center:"", right: "" };
		
		var payment = payingIn.getPaymentType() != "" ? engine.templateManager.getTemplate("shopping_cart_payments").process({payingin:payingIn}) : "";
		
		page.left = engine.templateManager.getTemplate("shopping_payinginuser").process({product:product, payingin:payingIn});
		page.center = engine.templateManager.getTemplate("shopping_payingin").process({product:product, payingin:payingIn, payment:payment});
		
		lastPage = pageRequest;
		
		return page;
	}
	
	/**
	 * Returns last visited page
	 * @return Last visited page
	 * @type Object
	 */
	this.getLastPage = function() {
		self.getPage(lastPage);
	}
	
}
/**
 * 
 */
function Product(pId, pDescription, pName, pLanguage, pComment, pPrice, pPartner, pType, pMaxHeadCount, pHours) {
		
	/**
	* Termék id
	* @type Number
	*/
	var id = new Number(pId);
	
	/**
	 * Termék leírás
	 * @type String
	 */
	var description = new String(pDescription);
	
	/**
	 * Termék elnevezése
	 * @type String
	 */
	var name = new String(pName);
	
	/**
	 * Termék nyelve
	 * @type String
	 */
	var language = new String(pLanguage);
	
	/**
	 * Megjegyzés a termékhez
	 * @type String
	 */
	var comment = new String(pComment);
	
	/**
	* Termék ára
	* @type Number
	*/
	var price = new Number(pPrice);
	
	/**
	 * Termékhez kapcsolt partner
	 * @type String
	 */
	var partner = new String(pPartner);
	
	/**
	 * Termék típusa
	 * @type String
	 */
	var type = new String(pType);
	
	/**
	 * Tanfolyamnál maximális létszám
	 * @type Number
	 */
	var headCount = new Number(pMaxHeadCount);
	
	/**
	 * Tanfolyamnál óraszám
	 * @type Number
	 */
	var hours = new Number(pHours);
	
	/**
	 * Visszaadja a Befizetés id-ját
	 * @return Befizetés id
	 * @type Number
	 */
	this.getId = function() {
		return id;
	}
	
	/**
	 * Visszaadja a Termék leírását
	 * @return Termék leírása
	 * @type String
	 */
	this.getDescription = function() {
		return description;
	}
	
	/**
	 * Visszaadja a Termék elnevezését
	 * @return Termék elnevezése
	 * @type String
	 */
	this.getName = function() {
		return name;
	}
	
	/**
	 * Visszaadja a Termék nyelvét
	 * @return Termék nyelve
	 * @type String
	 */
	this.getLanguage = function() {
		return language;
	}
	
	/**
	 * Visszaadja a Termékhez írt megjegyzést
	 * @return Termék megjegyzést
	 * @type String
	 */
	this.getComment = function() {
		return comment;
	}
	
	/**
	 * Visszaadja a Termék árát
	 * @return Termék ára
	 * @type Number
	 */
	this.getPrice = function() {
		return price;
	}
	
	/**
	 * Visszaadja a Termék árát megformázva
	 * @return Termék ára megformázva
	 * @type String
	 */
	this.getStyledPrice = function() {
		var styledPrice = price.toString();
		if( styledPrice.length > 3 ) {
			var ret;
			ret = styledPrice.substring( 0, ( styledPrice.length - 3 ) );
			ret += ".";
			ret += styledPrice.substring( styledPrice.length - 3 );
			return ret;
		} else {
			return styledPrice;
		}
	}
	
	/**
	 * Visszaadja a Termékhez kapcsolt partnert
	 * @return Termék partner
	 * @type String
	 */
	this.getPartner = function() {
		return partner;
	}
	
	/**
	 * Visszaadja a Termék típusát
	 * @return Termék típus
	 * @type String
	 */
	this.getType = function() {
		return type;
	}
	
	/**
	 * Visszadja a tanfolyam maximális létszámát
	 * @return Max létszám
	 * @type Number
	 */
	this.getMaxHeadCount = function() {
		return headCount;
	}
	
	/**
	 * Visszaadja a tanfolyam óraszámát
	 * @return Óraszám
	 * @type Number
	 */
	this.getHours = function() {
		return hours;
	}
}
/**
 * 
 * 
 */
function ProductManager() {
	
	/**
	 * Products downloaded
	 * @type Boolean
	 */
	var productsLoaded = false;
	
	/**
	 * Products array
	 * @type Array
	 */
	this.products = new Array();
	
	/**
	 * Are products loaded
	 * @type Boolean
	 * @return true if loaded
	 */
	this.isLoaded = function() {
		return productsLoaded;
	}
	
	/**
	 * Loads products from database
	 * @return Orders
	 */
	this.loadProducts = function() {		
		var comm = new CommGateRequest("REQ_ACCESS", [ "ESULI_GET_PRODUCTS" ], function(response) {
		    self.products = new Array();
		    self.notPaidUp = new Array();
			
			var data = response[0].getDataAsObjectArray();
			
		    for (var i = 0; i < data.length; i++) {
	    		product = new Product(data[i].id, data[i].description, data[i].name, data[i].language, data[i].comment, data[i].price, data[i].partner, data[i].type, data[i].maxheadcount, data[i].hours);
				self.products.push(product);
		    }
		    
		    productsLoaded = true;
		
			engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
		});
		
		comm.addDataLevel([ [ "" ],[ "" ] ]);
		engine.commGate.sendWithSession([ comm ]);
	 }
	
	/**
	 * Get products by type, or all product
	 * @param String Type
	 * @return Array All product (in selected type)
	 */
	this.getProducts = function( pType ) {
		var ret = new Array();
		
		if( ! pType || pType == "undefined" ) {
			ret =  self.products;
		} else {
			for (var i = 0; i < self.products.length; i++) {			
				if( self.products[i].getType() == pType ) {
					ret.push(self.products[i]);
				}
			}
		}
			
		return ret;
	}
	
	/**
	 * Get product by id
	 * @param Number Product id
	 * @return Object Product
	 */
	this.getProduct = function( pId ) {
		var ret;
		
		for (var i = 0; i < self.products.length; i++) {			
			if( self.products[i].getId().toString() == pId.toString() ) {
				ret = self.products[i];
				break;
			}
		}
		
		return ret;
	}
}
/**
 * Shopping module
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function Shopping() {
	
	/**
	 * Last visited page
	 * @type Object
	 */
	var lastPage;
	
	/**
	 * Paying-in list controller object
	 * @type PayingInListPage
	 */
	this.payingInListPage = new PayingInListPage();
	
	/**
	 * Paying-in controller object
	 * @type PayingInPage
	 */
	this.payingInPage = new PayingInPage();
	
	/**
	 * Products manager object
	 * @type ProductManager
	 */
	this.products = new ProductManager();
	
	/**
	 * Pointer to this
	 * @type Shopping
	 */
	var self = this;
	
	/**
	 * Returns requested page
	 * @param Object Page request
	 * @return Requested page
	 * @type Object
	 */
	this.getPage = function(pageRequest) {
		if (! check(pageRequest)) {
			//TODO: Log error
			return;
		}
		
		var page = { leftWidth: '372px', centerWidth: '371px', rightWidth: '225px', right: "" };
		
		switch (pageRequest.get("page")) {
			
			case "info":
				if( ! self.products.isLoaded() ) {
					page.left = engine.templateManager.getTemplate("contentspin").process({});
					page.center = engine.templateManager.getTemplate("contentspin").process({});
					self.products.loadProducts();
				} else {
					page.left = engine.templateManager.getTemplate("shopping_infocourse").process({});
					page.center = engine.templateManager.getTemplate("shopping_infoseasonticket").process({seasontickets: self.products.getProducts("Havibérlet")});
				}
				break;
				
			case "pricelist":
				if( ! self.products.isLoaded() ) {
					page.left = engine.templateManager.getTemplate("contentspin").process({});
					page.center = engine.templateManager.getTemplate("contentspin").process({});
					self.products.loadProducts();
				} else {
					page.left = engine.templateManager.getTemplate("shopping_pricelistcourse").process({});
					page.center = engine.templateManager.getTemplate("shopping_pricelistseasonticket").process({seasontickets: self.products.getProducts("Havibérlet")});
				}
				break;
				
			case "profile":
				page.extend(self.payingInListPage.getPage(pageRequest));
				break;
				
			case "registration":
				if( !esuli.user.getLevelSurvey("normal").isLoaded(pageRequest) ) {
					page.left = engine.templateManager.getTemplate("contentspin").process({});
					page.center = engine.templateManager.getTemplate("contentspin").process({});
				} else {
					page.left = engine.templateManager.getTemplate("shopping_registrationcourse").process({});		
					if( ! self.products.isLoaded() ) {
						page.center = engine.templateManager.getTemplate("contentspin").process({});
						self.products.loadProducts();
					} else {
						page.center = engine.templateManager.getTemplate("shopping_registrationseasonticket").process({seasontickets: self.products.getProducts("Havibérlet")});
					}
				}
				break;
			
			case "payingin":
				page.extend(self.payingInPage.getPage(pageRequest));
				break;
			
			/*
			case "yellowcheque":
			case "banktransfer":
			case "bankcard":
			case "paypal":
			case "esulibalance":
				page.left = engine.templateManager.getTemplate("shopping_cart_" + pageRequest.get("page")).process({});
				esuli.shopping.cart.clear();
				esuli.shopping.orderList.clear();
				break;
				
			case "seasontickets":
				if( ! self.products.isLoaded() ) {
					page.left = engine.templateManager.getTemplate("spin").process({});
					self.products.loadProducts();
				} else {
					page.leftWidth = "98%";
					page.rightWidth = "1%";
					page.left = engine.templateManager.getTemplate("shopping_seasontickets").process({seasontickets:self.products.getProducts("Havibérlet"), k:1});
				}
				break;
			
			default:
				//TODO: Log error
				return;
			*/
		}
		
		lastPage = pageRequest;
		
		return page;
	}
	
	/**
	 * Returns last visited page
	 * @return Last visited page
	 * @type Object
	 */
	this.getLastPage = function() {
		self.getPage(lastPage);
	}
	
}
/**
 * Azoknak a smarty oldalaknak a listája, amiknél nem jelentkeztetjük be autómatikisan a felhasználót.
 * Vizsgálja: ajax/1_5/Esuli.js -> pre_init()
 *
 * Lehetőségek a listán szereplő pl. "/teszt" oldallal:
 * I. Felhasználó nincs bejelentkezve -> megjelenik a "teszt" oldal
 * II. Felhasználó már be van/volt jelentkezve -> megjelenik "teszt" oldal, a felhasználót nem jelentkeztetjük be (cookie-k nem vesznek el, csak nem vesszük őket figyelembe)
 * III. a, Felhasználó bejelentkezik a "/teszt" oldalról -> bejelentezik a felhasználó, megjelenik a "teszt" oldal
 * III. b, Felhasználó bejelentkezik a "/teszt" oldalról, de a "teszt" szerepel a "disallowAfterLogin" listában is -> bejelentkezik a felhasználó, nyitóoldalra kerül
 */
dontLoginRemember = new Array( 
							"teszt"
							 );

/**
 * Azoknak a smarty oldalaknak a listája, amiket bejelentkezés után nem jelenítünk meg.
 * Vizsgálja: ajax/1_5/user/User.js -> listenProfileLoaded()
 *
 * Lehetőségek a listán szereplő pl. "/teszt" oldallal:
 * I. Felhasználó nincs bejelentkezve -> megjelenik a "teszt" oldal
 * II. Felhasználó már be van/volt jelentkezve -> nem jelenik meg a "teszt" oldal, nyitóoldalra kerül
 * III. Felhasználó bejelentkezik a "/teszt" oldalról -> nem jelenik meg a "teszt" oldal, nyitóoldalra kerül
 */
disallowAfterLogin = new Array( 
							"lakossagi_nyelvoktatas", 
							"lakossagi_tanfolyamok", 
							"lakossagi_bovebben", 
							"lakossagi_elerhetosegek", 
							"lakossagi_akciok", 
							"vallalati_nyelvoktatas", 
							"vallalati_tanfolyamok", 
							"vallalati_bovebben", 
							"vallalati_szakkepzesi", 
							"vallalati_hagyomanyos", 
							"nyelvvizsga_felkeszites", 
							"nyelvvizsga_arak", 
							"nyelvvizsga_euro", 
							"nyelvvizsga_origo", 
							"nyelvvizsga_tanacsok", 
							"teszt"
							 );/**
 * Global, common functions
 * @constructor
 */
function StaticContent() {
	
	/**
	 * Pointer to this
	 * @type StaticContent
	 */
	var self = this;
	
	/**
	 * Step over password blur if displays changed now
	 * @type Boolean
	 */
	var stepOverPasswordBlur = false;
	
	/**
	 * Set content end height
	 */
	this.setContentEnd = function() {
		var minDiff = 10;
		var correction = 7;
		
		var bodyLeft = $('bodyLeft');
		var bodyCenter = $('bodyCenter');
		var bodyRight = $('bodyRight');
		
		var bodyLeftEnd = $('bodyLeftEnd');
		var bodyCenterEnd = $('bodyCenterEnd');
		var bodyRightEnd = $('bodyRightEnd');
		
		bodyLeftEnd.style.display = 'none';
		bodyCenterEnd.style.display = 'none';
		bodyRightEnd.style.display = 'none';
		
		var bodyLeftHeight = bodyLeft.offsetHeight;
		var bodyCenterHeight = bodyCenter.offsetHeight;
		var bodyRightHeight = bodyRight.offsetHeight;
		
		var maxHeight = bodyLeftHeight >= bodyCenterHeight ? bodyLeftHeight >= bodyRightHeight ? bodyLeftHeight : bodyRightHeight : bodyCenterHeight > bodyRightHeight ? bodyCenterHeight : bodyRightHeight;
		
		if((bodyLeftHeight + minDiff) <= maxHeight) {
			bodyLeftEnd.style.display = 'block';
			bodyLeftEnd.style.height = maxHeight - bodyLeftHeight - correction + 'px';
		}
		if((bodyCenterHeight + minDiff) <= maxHeight) {
			bodyCenterEnd.style.display = 'block';
			bodyCenterEnd.style.height = maxHeight - bodyCenterHeight - correction + 'px';
		}
		if((bodyRightHeight + minDiff) <= maxHeight) {
			bodyRightEnd.style.display = 'block';
			bodyRightEnd.style.height = maxHeight - bodyRightHeight - correction + 'px';
		}
	}
	
	/**
	 * Chech email
	 * @param String Email
	 * @return Boolean true if email is valid, false if not
	 */
	this.checkEmail = function(pEmail) {
		filter = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
		if(filter.test(pEmail)) {
			return true;
		}
		return false;
	}
	
	/**
	 * Chech username
	 * @param String Username
	 * @return Boolean true if username is valid, false if not
	 */
	this.chechUsername = function(pUsername) {
		var filter =  "!@#$%^&*()+=-[]\\\';,./{}|\":<>?ˇ˘~°˛`˙´˝¨¸÷×ß¤€đĐłŁ ";
		for(var i = 0; i < pUsername.length; i++) {
			if(filter.indexOf(pUsername.charAt(i)) != -1) {
				return false;
				break;
			}
		}
		if(pUsername.length < 5) {
			return false;
		}
		return true;
	}
	
	/**
	 * Chech password
	 * @param String Password
	 * @return Boolean true if password is valid, false if not
	 */
	this.chechPassword = function(pPassword) {
		return self.chechUsername(pPassword);
	}
	
	/**
	 * Chech telefon
	 * @param String Telefon
	 * @return Boolean true if telefon is valid, false if not
	 */
	this.checkTelefon = function(pTelefon) {
		var filter = '0123456789()/-+ ';
		for(var i = 0; i < pTelefon.length; i++) {
			if(filter.indexOf(pTelefon.charAt(i)) == -1) {
				return false;
				break;
			}
		}
		if(pTelefon.length < 6) {
			return false;
		}
		return true;
	}
	
	/**
	 * Check number
	 * @param Number 
	 * @return Boolean true if number, false if not
	 */
	this.checkNumber = function(pNumber) {
		var filter = '0123456789';
		for(var i = 0; i < pNumber.length; i++) {
			if(filter.indexOf(pNumber.charAt(i)) == -1) {
				return false;
				break;
			}
		}
		return true;
	}
	
	/**
	 * Change input class and value on focus
	 * @param Object Input, String input default value
	 * @param String Type
	 */
	this.inputFocus = function(pInput, pDefaultValue, pType) {
		if(pDefaultValue && pInput.value == pDefaultValue) {
			pInput.value = '';
		}
		var type = !pType ? 'normal' : pType;
		pInput.className = type + 'TextInputSelected';
	}
	
	/**
	 * Change input class and value on blur
	 * @param Object Input, String input default value
	 * @param String Type
	 */
	this.inputBlur = function(pInput, pDefaultValue, pType) {
		if(pDefaultValue && self.trimTextInput(pInput.value) == '') {
			pInput.value = pDefaultValue;
		}
		var type = !pType ? 'normal' : pType;
		pInput.className = type + 'TextInput';
	}
	
	/**
	 * Change select class on on focus
	 * @param Object Select
	 */
	this.selectFocus = function(pSelect) {
		pSelect.className = 'normalSelectSelected';
	}
	
	/**
	 * Change select class on blur
	 * @param Object Select
	 */
	this.selectBlur = function(pSelect) {
		pSelect.className = 'normalSelect';
	}
	
	/**
	 * Change textarea class on on focus
	 * @param Object Textarea
	 * @param String Type
	 */
	this.textareaFocus = function(pTextarea, pType) {
		var type = !pType ? 'normal' : pType;
		pTextarea.className = type + 'TextareaSelected';
	}
	
	/**
	 * Change textarea class on blur
	 * @param Object Textarea
	 * @param String Type
	 */
	this.textareaBlur = function(pTextarea, pType) {
		var type = !pType ? 'normal' : pType;
		pTextarea.className = type + 'Textarea';
	}
	
	/**
	 * Change input display and class on password focus
	 * @param Input id
	 */
	this.passwordFocus = function(pId) {
		var password = $(pId);
		var passwordText = $(pId + 'Text');
		password.className = 'normalTextInputSelected';
		passwordText.className = 'normalTextInputSelected';
		if(password.style.display == 'inline') {
			return;
		}
		stepOverPasswordBlur = true;
		passwordText.style.display = 'none';
		password.style.display = 'inline';
		password.focus();
	}
	
	/**
	 * Change input display and class on password blur
	 * @param Input id
	 */
	this.passwordBlur = function(pId) {
		if(stepOverPasswordBlur) {
			stepOverPasswordBlur = false;
			return;
		}
		var password = $(pId);
		var passwordText = $(pId + 'Text');
		if(self.trimTextInput(password.value) == '') {
			password.value = '';
			passwordText.style.display = 'inline';
			password.style.display = 'none';
		}
		password.className = 'normalTextInput';
		passwordText.className = 'normalTextInput';
		stepOverPasswordBlur = false;
	}
	
	/**
	 * Strip the beginning and end of the string
	 * @param String to strip
	 * @return Stripped string
	 * @type String
	 */
	this.trimTextInput = function(pString, pChars) {
		var chars = pChars || "\\s";
		var clear = pString.replace(new RegExp("^[" + chars + "]+", "g"), "");
		return clear.replace(new RegExp("[" + chars + "]+$", "g"), "");
	}
	
/******************************************************************/
/******************************************************************/
/******************************************************************/
/******************************************************************/
/******************************************************************/
	
	this.checkSenderEmail = function() {
		if ($("sourceMail").value.length > 0) {
			$("offerForm").submit();
		} else {
			engine.dialogManager.add(new Dialog("Kérjük, mindenképpen adja meg saját nevét, csak így tudunk Önre hivatkozni ismerőseinél!", "alert"));
		}
	}

    /**
     * Hírek oldalon "bővebben" gombra nyitja/zárja a diveket
     * @param String A megjelnítendő div ID -ja
     */
	this.showHide = function(pId) {
		if (! pId) {
			pId = 0;
		}
		
		var divs = document.getElementsByTagName('div');
		
		for (var i = 0; i < divs.length; i++) {
			if (divs[i].className == 'newsContentLong') {
				if (divs[i].id == 'newsContent_' + pId) {
					divs[i].style.display = 'block';
				} else {
					divs[i].style.display = 'none';
				}
			} else if (divs[i].className == 'newsContentShow') {
				if (divs[i].id == 'newsShow_' + pId) {
					divs[i].style.display = 'none';
				} else {
					divs[i].style.display = 'block';
				}
			} else if (divs[i].className == 'newsContentShort') {
				if(divs[i].id == 'newsShort_' + pId) {
					divs[i].style.display = 'none';
				} else {
					divs[i].style.display = 'block';
				}
			}
		}
	}
	
	/**
	 * Szövegben kikeresi az első mondatot
	 * @param String
	 * @return Az első mondat
	 * @type String
	 */
	this.findFirstSentence = function( pString ) {
	/*
		var sentEnds = new Array('.','!','?');
		var sentFirst = 1000;
		for( var i = 0; i < sentEnds.length; i++ ) {
			var firstFind = pString.indexOf( sentEnds[i] )
			if( firstFind != -1 && firstFind < sentFirst )
				sentFirst = firstFind;
		}
	*/
		var end = pString.indexOf( '<br' );
		return pString.substring( 0, end );
	}

    /**
     * Szövegben kikeresi az első mondat után részt
     * @param String
     * @return Az első mondat utáni rész
     * @type String
     */
    this.findAllButFirstSentence = function( pString ) {
	/*
        var sentEnds = new Array('.', '!', '?');
        var sentFirst = 1000;
        for( var i = 0; i < sentEnds.length; i++ ) {
            var firstFind = pString.indexOf( sentEnds[i] )
            if( firstFind != -1 && firstFind < sentFirst )
                sentFirst = firstFind;
        }
	*/
		var begin = pString.indexOf( '<br' );
        return pString.substring( begin );
    }

    /**
     * Cikkek tanácsok oldalon "bővebben" gombra nyitja/zárja a diveket
     * @param String A megjelnítendő téma div ID -ja
     */
	this.showHideAdvice = function( pId ) {
		if( !pId )
			pId = 0;
		var divs = document.getElementsByTagName('div');
		for( var i = 0; i < divs.length; i++ ) {
			if( divs[i].className == 'adviceFull' ) {
				if( divs[i].id == 'adviceFull_' + pId )
					divs[i].style.display = 'block';
				else
					divs[i].style.display = 'none';
			} else if( divs[i].className == 'adviceIntro' ) {
				if( divs[i].id == 'adviceIntro_' + pId )
					divs[i].style.display = 'none';
				else
					divs[i].style.display = 'block';
			}
		}
	}

	/**
	 * faq oldalon az értékelés ( Mennyire volt hasznos ez az információ? ) kezelése
	 * ha kiválaszt egyet, akkor azt egyből tároljuk, és megjelenítjük neki a textboxot
	 * ahol kifejtheti, véleménye szerint mivel lehetne még bővíteni az infót
	 * @param String , melyik faq-t értékelte, milyenre értékelte
	 */
	this.selectHelpFul = function( pId, pHelpFul ) {
		if( pHelpFul == -1 )
			return;
		
		var select = $( 'faqHelpfulSelect_' + pId );
		var textareaDiv = $( 'faqExtend_' + pId );
		if( select && textareaDiv ) {
			select.disabled = true;
			textareaDiv.style.display = 'block';
			// TODO: Eltárolni valahol az értékelést
		} else return;
	}
	
	/**
	 * faq oldalon az user bővítési javaslatának a kezelése
	 * @param String , melyik faq-hoz írt , mit írt
	 */
	this.sendHelpExtend = function( pId, pValue ) {
		if( pValue == '' )
			return;
		
		// TOTO Eküldeni az üzenetet
	}

	this.sendCegesAdo = function( pPage ) {
		var nev = $( 'cegesado_name' ).value;
		var cegnev = $( 'cegesado_firm' ).value;
		var email = $( 'cegesado_email' ).value;
		var telefon = $( 'cegesado_tel' ).value;

		if ( nev == "" && cegnev == "" ) {
			engine.dialogManager.add( new Dialog("A <span class='staticRise'>Név</span> vagy a <span class='staticRise'>Cégnév</span> mezők valamelyikének kitöltése kötelező!", "alert" ) );
			return false;
		}

		if ( email == "" && telefon == "") {
			engine.dialogManager.add( new Dialog("Az <span class='staticRise'>E-mail cím</span> vagy a <span class='staticRise'>Telefonszám</span> mezők valamelyikének kitöltése kötelező!", "alert" ) );
			return false;
		}
		
		if ( email != "" && !( email.indexOf('@') > 0 && email.indexOf('@') < email.length - 2 && email.indexOf('.') > 0 ) ) {
			engine.dialogManager.add( new Dialog("Hibás e-mail címet adott meg!", "alert" ) );
	        return false;
	    }

		if ( telefon != "" ) {
			var karakterek = '0123456789()/-+ ';
			for ( var i = 0; i < telefon.length; i++ ) {
				if ( karakterek.indexOf( telefon.charAt(i) ) == -1 ) {
					engine.dialogManager.add( new Dialog("Hibás telefonszámot adott meg!", "alert" ) );
					return false;
				}
			}
		}
		
		var time = $( 'cegesado_time' ).value;
		var message = $( 'cegesado_message' ).value;
		var recipient = 'info@enyelviskola.hu';
		var subject = '';
		var finalAlert = '';
		var showAgent = '';
		
		if( pPage == 'ado' ) {
			subject = 'Adó - kapcsolatfelvételi űrlap';
			finalAlert = 'Köszönjük érdeklődését!<br /><br />Az időpont egyeztetés végett hamarosan jelentkezni fogunk Önnél.';
		} else if( pPage == 'cegesangol' ) {
			subject = 'Céges angol oktatás - kapcsolatfelvételi űrlap';
			finalAlert = 'Köszönjük, Ön jó döntést hozott és egy nagy lépéssel közelebb került ahhoz, hogy munkatársai számára ingyenes angol nyelvoktatást tegyen lehetővé.<br /><br />Az időpont egyeztetés végett hamarosan jelentkezni fogunk Önnél.';
		} else if( pPage == 'otdolog' ) {
			var agent = $( 'message_agent' ).value;
			var agentEmail = $( 'message_recipient' ).value;
			if( agent != 'nincs ügynök' )
				showAgent = 'Ügynök: ' + agent + "\n";
			if( agentEmail != 'info@enyelviskola.hu')
				recipient = recipient + ',' + agentEmail;
			subject = 'Ötdolog - kapcsolatfelvételi űrlap';
			finalAlert = 'Köszönjük érdeklődését!<br /><br />Az időpont egyeztetés végett hamarosan jelentkezni fogunk Önnél.';
		}
		
		email == '' ? email = 'info@enyelviskola.hu' : email;
		
		var message_all = 'Tisztelt eNyelviskola!'
			+ "\n\n"
			+ 'Az alábbi érdeklődő az eNyelviskolával kapcsolatban személyes tájékoztatást kért:'
			+ "\n\n"
			+ showAgent
			+ 'Név: ' + nev
			+ "\n"
			+ 'Cégnév: ' + cegnev
			+ "\n"
			+ 'E-mail cím: ' + email
			+ "\n"
			+ 'Telefonszám: ' + telefon
			+ "\n"
			+ 'Javasolt időpontok: ' + time
			+ "\n"
			+ 'Megjegyzések: ' + message
			+ "\n\n"
			+ 'Üdvözlettel:'
			+ "\n\n"
			+ 'eNyelviskola.hu';
		
		engine.commGate.sendWithSession([ new CommGateRequest("SEND_EMAIL", [ recipient, message_all, subject, email ], null) ] );
		engine.dialogManager.add( new Dialog( finalAlert, "alert" ) );
	}
	
	/**
	 * Szakképzési ürlap kitöltésének ellenőrzése
	 */
	this.checkTrainingForm = function() {
		var firm = $('firm').value; // Cégnév
		var address = $('address').value; // Cím
		var name = $('fromName').value; // Kapcsolattartó neve
		var tel = $('tel').value; // Kapcsolattartó telefonszáma
		var email = $('fromAddress'); // Kapcsolattartó e-mail címe
		
		if ( email.value != "" && !( email.value.indexOf('@') > 0 && email.value.indexOf('@') < email.value.length - 2 && email.value.indexOf('.') > 0 ) ) {
			email.value = '';
			engine.dialogManager.add( new Dialog("Kérjük, e-mailcímét helyesen adja meg!", "alert" ) );
	        return false;
	    }
		
		if( firm == '' || address == '' || name == '' || tel == '' || email.value == '' ) {
			engine.dialogManager.add( new Dialog("Kérjük, adjon meg minden szükséges adatot!", "alert" ) );
	        return false;
		}

 		document.szakkepzesi_urlap.submit();
	}
	
	/**
	 *
	 */
	this.getReload = function() {
		var url = window.location.href;
		var reload = url.substring( BASE_URL.length, url.length );
		var clearReload = reload.split("#");
		return clearReload[0].split(".", 1);
	}
}
/**
 * StaticPageManager module in esuli
 * @author Johnny, Horvath 'Koko' Kornel, MOrr
 * @constructor
 */
function StaticPageManager() {
	
	/**
	 * Last visited page
	 * @type Object
	 */
	var lastPage;

    /**
	 * Returns requested page
	 * @param Object Page request
	 * @return Requested page
	 * @type Object
	 */
	this.getPage = function(pageRequest) {
		if (! check(pageRequest)) {
			//TODO: Log error
			return;
		}
		
		var page = { centerWidth: '743px', rightWidth: '225px', center: '', right: '' };
    	
		switch (pageRequest.get("page")) {
			case "static_rolunkirtak":
				//page.center = engine.templateManager.getTemplate(pageRequest.get("page")).process({ Comments: esuli.gadget.forus.getComments() });
				page.center = engine.templateManager.getTemplate("contentspin").process({});
				break;
			
			case "static_segedanyagok":
				page.leftWidth = '372px';
				page.centerWidth = '371px';
				page.rightWidth = '225px';
				page.left = engine.templateManager.getTemplate(pageRequest.get("page") + 'left').process({});
				page.center = engine.templateManager.getTemplate(pageRequest.get("page") + 'center').process({});
				break;
				
			default:
				page.center = engine.templateManager.getTemplate(pageRequest.get("page")).process({});
		}
		
		lastPage = pageRequest;
		
		return page;
    }
    
	/**
 	 * Returns last visited page
	 * @return Last visited page
	 * @type Object
	 */
	this.getLastPage = function() {
		self.getPage(lastPage);
	}
}
/**
 * @constructor
 * @author Johnny
 * @param String tabMenü divjének idje
 * @param String subMenü divjének idje 
 */
function TabMain( tabDivId, subDivId ) {
	
	/**
	 * @type Object
	 */
	var self = this;
	
	/**
	 * @type Array
	 */
	this.tabArray = new Array();
	
	/**
	 * @type Object
	 */
	this.tabDiv = document.getElementById( tabDivId );
	
	/**
	 * @type Object
	 */
	this.subDiv = document.getElementById( subDivId );
	
	/**
	 * @type String
	 */
	this.tabsType = new String();
	
	/**
	 * @type String
	 */
	this.activeTab = new String();
	
	/**
	 * @type Number
	 */
	this.activeTabId = new Number();
	
	/**
	 * @type number
	 */
	this.activeSubMenuId = new Number();
	
	/**
	* figyeli a NavChange típusú eseményeket
	* @param Object 
	*/
	this.listenNavChange = function( event ) {
	    var tabId = event.get("tabId") == undefined ? event.get("tabMenuId") : event.get("tabId");
	    var subId = event.get("subId") == undefined ? event.get("subMenuId") : event.get("subId");
	    var type = esuli.tab.getTabType( tabId );
		
	    self.showTabAndSubMenu( tabId, subId, type );
	}
	
	/**
	 * Tab és subMenu váltása
	 * @param String Tabmenü neve
	 * @param Number subMenü id-je
	 */
	this.changeTabAndSubMenu = function( tabMenuName, subMenuId ) {
		var tabType = '';
		
		for (var i = 0; i < self.tabArray.length; i++) {
			if ( self.tabArray[i].getName() == tabMenuName ){
				tabType = self.tabArray[i].getType();
				for (var j = 0; j < self.tabArray[i].getSubMenu().length; j++) {
					if (self.tabArray[i].getSubMenu()[j].getId() == subMenuId){
						self.tabArray[i].getSubMenu()[j].setStatus("active");
					} else {
						self.tabArray[i].getSubMenu()[j].setStatus("inactive");
					}
				}
			}
		}
		this.setActiveTab( tabMenuName, tabType.toString() );
	}
	
	/**
	* NavChange esemény hatására megjeleníti a Tab-, SubMenüt
	* @param Number TabMenü id
	* @param Number SubMenü id 
	* @param String TabMenü státusza
	*/
	this.showTabAndSubMenu = function( tabId, subId, type ) {
	    var subContent = null;
	    var tabName = self.getTabName( tabId );
	    var subMenu = null;
	    
		this.activeTab = tabName;
		this.activeTabId = tabId;
		this.activeSubMenuId = subId;
	    
	    setTabMenuStatus( type.toString(), tabName );
	    
	    var content = '<ul id="menu">';
		for( var i = 0; i < this.tabArray.length; i++ ) {
		    if ( this.tabArray[i].getType().toString() == type ) {	
				if ( this.tabArray[i].getStatus().toString() == "lessonsNext" || this.tabArray[i].getStatus().toString() == "lessons" ) {
					content += engine.templateManager.getTemplate("nav_tabmenu").process({ status: this.tabArray[i].getStatus(), event: "esuli.tab.showTabMenu('Main',false)", tabName: this.tabArray[i].getName() });
				} else {
					content += engine.templateManager.getTemplate("nav_tabmenu").process({ status: this.tabArray[i].getStatus(), event: "esuli.tab.setActiveTab('"+this.tabArray[i].getName()+"','"+this.tabArray[i].getType()+"')", tabName: this.tabArray[i].getName() });
				}
				
				if ( this.tabArray[i].getStatus() == "active" || this.tabArray[i].getStatus() == "firstActive" || this.tabArray[i].getStatus() == "lastActive" ) {
				    subMenu = this.tabArray[i].getSubMenu();
				}
		    }
		}
		content += '</ul>';
		
		subContent = '<ul>';
		for ( var j = 0; j < subMenu.length; j++ ) {
		    if( subMenu[j].getId() == subId ) {
				subContent += engine.templateManager.getTemplate("nav_submenu").process({ className: "active", event: "esuli.tab.setActiveSubMenu('" + subMenu[j].getId() + "')", subName: subMenu[j].getName() });
		    } else {
				subContent += engine.templateManager.getTemplate("nav_submenu").process({ className: "inactive", event: "esuli.tab.setActiveSubMenu('" + subMenu[j].getId() + "')", subName: subMenu[j].getName() });
		    }
		}
		subContent += '</ul>';
		
		this.subDiv.innerHTML = subContent;
		this.tabDiv.innerHTML = content;
	}
	
	/**
	* visszaadja a submenu nevét tabid és subid alapján
	* @param Int tabId
	* @param Int subId
	* @return a tab neve
	* @type String
	*/
	this.getSubMenuName = function( tabId, subId ) {
	    var tabName = self.getTabName( tabId );
	    var tmpArray = null;
		
	    for ( var i = 0; i < getTabArrayLength(); i++ ) {
			if ( this.tabArray[i].getId() == tabId  ) {
			    tmpArray = getActualSubMenu( tabName );
			    for ( var j = 0; j < tmpArray.length; j++ ) {
					if ( tmpArray[j].getId() == subId )
					    return tmpArray[j].getName();
			    }
			}
	    }
	    return;
	}
	
	/**
	* visszaadja a levelt tab és subMenu id alapján
	* @param tabid
	* @param subId
	* @return level
	* @type String 
	*/
	this.getLevel = function(tabId, subMenuId) {	
	    for ( var i = 0; i < getTabArrayLength(); i++ ) {
			if ( this.tabArray[i].getId() == tabId ) {
			    var subMenu = this.tabArray[i].getSubMenu();
			    for ( var j = 0; j < subMenu.length; j++ ) {
					if ( subMenu[j].getId() == subMenuId )
					    return subMenu[j].getLevel();
			    }
			}
	    }	    
	    return;
	}
	
	/**
	 * visszaadja a tab nevét az id alapján
	 * @return tab neve
	 * @type string
	 */
	this.getTabName = function( tabId ) {
	    for (  var i = 0; i < getTabArrayLength(); i++ ) {
			if ( self.tabArray[i].getId() == tabId )
			    return self.tabArray[i].getName();
	    }	    
	    return;
	}
	
	/**
	* visszaadja a tab típusát id alapján
	* @param Int
	* @return a tab típusa
	* @type String;
	*/
	this.getTabType = function( tabId ) {
	    for ( var i = 0; i < getTabArrayLength(); i++ ) {
			if ( this.tabArray[i].getId() == tabId  )
			    return this.tabArray[i].getType();
	    }
	    return;
	}
	
	/**
	 * Egy elem hozzáadása az Objektumhoz
	 * @param String Tab típusa
	 * @param String Tab neve
	 * @param String Tab státusza
	 * @param Array Tab submenüje
	 */
	this.addTab = function( tabType, tabName, tabStatus, subArray ) {
	    var tabId = getTabArrayLength();		
	    var tab = new Tabs( tabType, tabId, tabName, tabStatus, subArray );
		
	    if ( tab )
			this.tabArray.push( tab );
	}
	
	/**
	 * Egy elem törlése az Objetumból
	 * @param String Tab típusa
	 * @param String Tab neve
	 */
	this.removeTab = function( tabType, tabName ) {
		for ( var i = 0; i < this.tabArray.length; i++ ) {
			if( this.tabArray[i].getType() == tabType && this.tabArray[i].getName() == tabName ) {
				this.tabArray.splice( i, 1 );
				break;
			}
		}
	}
	
	/**
	 * Egy sub menü törlése 
	 * @param Sting Tab típusa
	 * @param String Tab neve
	 * @param String Sub Menu neve
	 */
	this.removeSubMenu = function(  tabType, tabName, subMenuName ) {
		for ( var i = 0; i < getTabArrayLength(); i++ ) {
			if( this.tabArray[i].getType() == tabType && this.tabArray[i].getName() == tabName ) {
				var tmpArray = getActualSubMenu( tabName );
				for ( var j = 0; j < tmpArray.length; j++ ) {
					if( tmpArray[j].getName() == subMenuName ) {
						self.tabArray[i].getSubMenu().splice( j, 1 );
						break;
					}
			    }
			}
		}
	}
	
	/**
	 * Tab menüsor megjelenítése 
	 * @param String Tabok típusa
	 * @param Boolen meghívodjon-e a setMenuStatus függvény
	 */
	this.showTabMenu = function( type, flag ) {
	    this.tabsType = type;
	    var content = null;
	    var subMenu = null;

	    if ( flag ) {
			setTabMenuStatus( type );
			return;
		}
		
		content = '<ul>';
		content += engine.templateManager.getTemplate("nav_tabmenufirst").process({ firsClass: this.tabArray[0].getStatus()});
		for( var i = 0; i < this.tabArray.length; i++ ) {
			if ( this.tabArray[i].getType() == type && ( this.tabArray[i].getStatus() == 'active' || this.tabArray[i].getStatus() == "firstActive" || this.tabArray[i].getStatus() == "lastActive" ) ) {
				this.activeTab = this.tabArray[i].getName();
				this.activeTabId = this.tabArray[i].getId();
			}
			
			var className = this.tabArray[i].getClassName();
			if ( this.tabArray[i].getType() == type ) {
				if ( this.tabArray[i].getStatus().toString() == "lessonsNext" || this.tabArray[i].getStatus().toString() == "lessons" ) {
					content += engine.templateManager.getTemplate("nav_tabmenu").process({ status: className, event: "esuli.tab.showTabMenu('Main',false)", tabName: this.tabArray[i].getName() });
				} else {
					content += engine.templateManager.getTemplate("nav_tabmenu").process({ status: className, event: "esuli.tab.setActiveTab('"+this.tabArray[i].getName()+"','"+this.tabArray[i].getType()+"')", tabName: this.tabArray[i].getName() });
				}
			}
			
			if ( this.tabArray[i].getName() == this.activeTab )
				subMenu = this.tabArray[i].getSubMenu();
		}
		
		var lastClass = '';
		for(var i = 0; i < this.tabArray.length; i++) {
			if(this.tabArray[i].getType() == this.tabsType) {
				lastClass = this.tabArray[i].getStatus();
			}
		}
		content += engine.templateManager.getTemplate("nav_tabmenulast").process({ lastClass: lastClass});
		content += '</ul>';
	    this.tabDiv.innerHTML = content;
	    this.showSubMenu( subMenu );
	}
	
	/**
	 * sub menü megjelenítése
	 * @param Array a kiválasztott Tab sub meüje
	 */
	this.showSubMenu = function( subMenu ) {
	    var content = null;
	    var onClickEvent = null;
	    var flag = false;
	    
	    if ( engine.cookieManager.get("contentReload") ) {
			allSubMenuSetInactive( subMenu );
	    } else {
			for ( var j = 0; j < subMenu.length; j++ ) {
			    if ( subMenu[j].getStatus() == "active" )
					flag = true;
			}
			if ( !flag ) {
			    subMenu[0].setStatus("active");
			}
	    }
	    
		content = '<ul>';
		content += engine.templateManager.getTemplate("nav_submenufirst").process({ firsClass: subMenu[0].getStatus()});
		for ( var j = 0; j < subMenu.length; j++ ) {
			if ( subMenu[j].getStatus() == "active" || subMenu[j].getStatus() == "firstActive" || subMenu[j].getStatus() == "lastActive")
				this.activeSubMenuId = subMenu[j].getId(); 
			
			var className = '';
			if(subMenu[j].getStatus() == "active" || subMenu[j].getStatus() == "firstActive" || subMenu[j].getStatus() == "lastActive") {	
				className = 'subMenuNormalSelected';
			} else if(subMenu[j - 1] && subMenu[j - 1].getStatus() == "active") {	
			    className = 'subMenuLeftSelected';
			} else if(subMenu[j + 1] && subMenu[j + 1].getStatus() == "active") {
			    className = 'subMenuRightSelected';
			} else {
			    className = 'subMenuNormal';
			}
			content += engine.templateManager.getTemplate("nav_submenu").process({ status: className, event: "esuli.tab.setActiveSubMenu('"+subMenu[j].getId()+"')", subName: subMenu[j].getName() });
			
			if ( subMenu[j].getStatus() == 'active' || subMenu[j].getStatus() == "firstActive" || subMenu[j].getStatus() == "lastActive")
			    onClickEvent = subMenu[j].getOnClick();
	    }
		content += engine.templateManager.getTemplate("nav_submenulast").process({ lastClass: subMenu[subMenu.length-1].getStatus()});
		content += '</ul>';
		
	    this.subDiv.innerHTML = content;
	    
	    if (! engine.cookieManager.get("contentReload")) {
	    	engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, onClickEvent.extend({ tabId: this.activeTabId, subId: this.activeSubMenuId })));
	    } else {
			engine.cookieManager.remove("contentReload");
	    }
	}
	
	/**
	 * Az aktuális subMenü minden elemét inaktívra állítja
	 * @param Array éppen aktuális subMenü
	 */
	function allSubMenuSetInactive( subMenu ) {
	    for( var i = 0; i < subMenu.length; i++ ) {
		    subMenu[i].setStatus("inactive");
	    }
	}
	
	/**
	 * beállítja hogy melyik legyen az aktív tab
	 * @param String a tab neve
	 * @param TabMenü típusa 
	 */
	this.setActiveTab = function( which, type ) {
	    this.activeTab = which;
	    setTabMenuStatus( type, which );
	    this.showTabMenu( type, false );
	}
	
	/**
	 * beállítja hogy melyik legyen az aktív sub menü
	 * @param String a sub menü neve
	 */
	this.setActiveSubMenu = function( which ) {
	    var subMenu = new Array(); 
	    subMenu = getActualSubMenu( this.activeTab );
		
	    for( var i = 0; i < subMenu.length; i++ ) {
			if ( subMenu[i].getId() == which )
		    	subMenu[i].setStatus( 'active' );
			else
		    	subMenu[i].setStatus( 'inactive' );
	    }
	    this.showSubMenu( subMenu );
	}
	
	/**
	* szint alapján visszaadja a tab és subMenu Id-t
	* @param String szint
	* @return tabId, subId
	* @type Object
	*/
	this.getIds = function( level ) {
	    for ( var i = 0; i < getTabArrayLength(); i++ ) {
			var subMenu = this.tabArray[i].getSubMenu();
			for ( var j = 0; j < subMenu.length; j++ ) {
		   		if ( subMenu[j].getLevel() == level )
					return { tabMenuId: this.tabArray[i].getId(), subMenuId: subMenu[j].getId() };
			}
	    }
	    return;
	}
	
	/**
	* Beállítja a tabMenü elemeinek css osztályát
	* @param String Tabok típusa
	* @param TabMenü neve
	*/
	function setTabMenuStatus( type, which ) {
	    var typeSum = sumOfType( type );
	    var activeIndex;
	    var typeArray = getArray( type );

		if ( type == "Info" )
			var lessonsTabId = getLessonsTabId( type );
	    
	    for( var i = 0; i < typeArray.length; i++ ) {
			if (  which == undefined ) {
			    if ( typeArray[i].getStatus() == "active" )
					activeIndex = typeArray[i].getId();
			}
			else {
			    if ( typeArray[i].getName() == which )
					activeIndex = typeArray[i].getId();
			}
	    }
	    for( var i = 0; i < typeArray.length; i++ ) {
			if ( which == undefined ) {	    
			    if ( typeArray[i].getStatus() == "lessons" || typeArray[i].getStatus() == "lessonsNext" ) {
					if ( activeIndex-1 != typeArray[i].getId() )
					    typeArray[i].setStatus( "lessons" );
					else
					    typeArray[i].setStatus( "lessonsNext" );
			    }
			    
			    if ( typeArray[i].getStatus() == "active" ) {
					if ( i != 0 && i != typeSum-1  )
					    typeArray[i].setStatus( "active" );
					else if ( i == 0 )
					    	typeArray[i].setStatus( "firstActive" );
					else if ( i == typeSum-1 )
					    typeArray[i].setStatus( "lastActive" );
			    }
			    
			    if ( typeArray[i].getStatus() == "" ) {
					if ( activeIndex-1 == typeArray[i].getId() &&  lessonsTabId+1 == typeArray[i].getId() )
					    typeArray[i].setStatus( "activeNextLessonPrev" );
				
					else if ( activeIndex-1 != typeArray[i].getId() &&  lessonsTabId+1 == typeArray[i].getId() )
					    typeArray[i].setStatus( "inactiveNextLessonPrev" );
					
					else if ( i == 0 && activeIndex-1 == typeArray[i].getId() )
					    typeArray[i].setStatus( "firstInactiveNext" );
					
					else if ( i == 0 && activeIndex-1 != typeArray[i].getId() )
					    typeArray[i].setStatus( "firstInactive" );
					
					else if ( i == typeSum-1 && typeArray[i-1] && typeArray[i-1].getId() == activeIndex )
					    typeArray[i].setStatus( "lastInactivePrev" );
					
					else if ( i == typeSum-1 && typeArray[i-1] && typeArray[i-1].getId() != activeIndex )
					    typeArray[i].setStatus( "lastInactive" );
					
					else if ( activeIndex+1 == typeArray[i].getId() )
					    typeArray[i].setStatus( "activePrev" );
					
					else if ( activeIndex-1 == typeArray[i].getId() )
					    typeArray[i].setStatus( "activeNext" );
				    
					else 
					    typeArray[i].setStatus( "inactive" );
			    }
			} else {
			    if ( typeArray[i].getStatus() == "lessons" || typeArray[i].getStatus() == "lessonsNext" ) {
					if ( activeIndex-1 == typeArray[i].getId() )
					    typeArray[i].setStatus( "lessonsNext" );
					else
				    	typeArray[i].setStatus( "lessons" );
			    }
			    
			    if ( typeArray[i].getName() == which ) {
					if ( i != 0 && i != typeSum-1  )
					    typeArray[i].setStatus( "active" );
					
					else if ( i == 0 )
					    typeArray[i].setStatus( "firstActive" );
					
					else if ( i == typeSum-1 )
					    typeArray[i].setStatus( "lastActive" );
			    }
			    
			    if ( typeArray[i].getName() != which && typeArray[i].getStatus() != "lessons" && typeArray[i].getStatus() != "lessonsNext" ) {
					if ( activeIndex-1 == typeArray[i].getId() &&  lessonsTabId+1 == typeArray[i].getId() )
					    typeArray[i].setStatus( "activeNextLessonPrev" );
					
					else if ( activeIndex-1 != typeArray[i].getId() && lessonsTabId+1 == typeArray[i].getId() )
					    typeArray[i].setStatus( "inactiveNextLessonPrev" );
					
					else if ( i == 0 && activeIndex-1 == typeArray[i].getId() )
					    typeArray[i].setStatus( "firstInactiveNext" );
					
					else if ( i == 0 && activeIndex-1 != typeArray[i].getId() )
					    typeArray[i].setStatus( "firstInactive" );
					
					else if ( i == typeSum-1 && typeArray[i-1] && typeArray[i-1].getId() == activeIndex )
					    typeArray[i].setStatus( "lastInactivePrev" );
					
					else if ( i == typeSum-1 && typeArray[i-1] && typeArray[i-1].getId() != activeIndex )
					    typeArray[i].setStatus( "lastInactive" );
					
					else if ( activeIndex+1 == typeArray[i].getId() )
					    typeArray[i].setStatus( "activePrev" );
					
					else if ( activeIndex-1 == typeArray[i].getId() )
					    typeArray[i].setStatus( "activeNext" );
				    
					else 
					    typeArray[i].setStatus( "inactive" );
			    }
			}
	    }
	}
	
	/**
	* visszaadja a lessons státuszú tab id-jét
	* @param String Tabok típusa
	* @return adott típusú és lessons státuszú tab id-je 
	* @type integer
	*/
	function getLessonsTabId( type ) {
	    for ( var i = 0; i < getTabArrayLength(); i++ ) {
			if ( self.tabArray[i].getType() == type && (self.tabArray[i].getStatus() == "lessons" || self.tabArray[i].getStatus() == "lessonsNext") )
			   return self.tabArray[i].getId();
	    }
	    return;
	}
	
	/**
	* visszaad egy tömböt melyben csak azok a tab objectumok lesznek, amelyeknek a típusa megegyezik a megadottal
	* @param String Tabok típusa
	* @return adott típusú tab objectumok
	* @type Array
	*/
	function getArray( type ) {
	    var tmpArray = new Array();
	    
	    for ( var i = 0; i < getTabArrayLength(); i++ ) {
			if ( self.tabArray[i].getType() == type )
			    tmpArray.push( self.tabArray[i] );
	    }
	    return tmpArray;
	}
	
	/**
	* Visszaadja az azonos típusú tabok számát
	* @param String Tabok típusa
	* @return adott típusú tabok száma
	* @type integer
	*/
	function sumOfType( type ) {
	    var sum = new Number(0);
	    
	    for ( var i = 0; i < getTabArrayLength(); i++ ) {
			if ( self.tabArray[i].getType() == type )
			    sum++;
	    }
	    return sum;
	}
	
	/**
	 * visszaadja a az aktíve tab submenüjét
	 * @param String az aktív tab neve
	 * @return aktuális submenü tömb
	 * @type Array
	 */	
	function getActualSubMenu( actualTab ) {
	    var tmpArray = new Array();
		var subMenu = null;
		
	    for( var i = 0; i < getTabArrayLength(); i++ ) {
			if ( self.tabArray[i].getName() == actualTab ) {
				subMenu = self.tabArray[i].getSubMenu();
			    for ( var j = 0; j < subMenu.length; j++ ) {
					tmpArray.push( subMenu[j] );
			    }
			}
	    }
	    return tmpArray;
	}
	
	/**
	 * visszaadja a tabok számát
	 * @return tabok száma
	 * @type int
	 */
	function getTabArrayLength() {
	    return self.tabArray.length;
	}
	
	function clearTabs() {
	    this.tabArray = new Array();
	}
	
	engine.eventManager.addListener( EventManager.EVENT_NAV_CHANGE, this );
}
/**
 * @constructor
 * @author Johnny
 * @param Number SubMenu id
 * @param String SubMenu név
 * @param Object SubMenu onClick esemény
 * @param String SubMenu státusz
 * @param String SubMenu szint
 */
function SubMenu( subMenuId, subMenuName, subMenuOnClick, subMenuStatus ) {
	/**
	 *  SubMenu id
	 *  @type Number 
	 */
	var subId = new Number( subMenuId );
	
	/**
	 * SubMenu neve
	 * @type String
	 */
	var subName = new String( subMenuName );
	
	/**
	 * SubMenu onClick eseménye
	 * @type Object
	 */
	var subOnClick = subMenuOnClick;
	
	/**
	 * SubMenu
	 * @type String
	 */
	var subStatus = new String( subMenuStatus );
	
	/**
	 * SubMenu szint
	 * @type String
	 */
	var subLevel = subMenuOnClick.module + "_" + (subMenuOnClick.levelId != undefined ? subMenuOnClick.levelId : subMenuOnClick.page);
	
	/**
	 * Visszaadja a SubMenu idjét
	 * @return SubMenu idje
	 * @type Integer
	 */
	this.getId = function() {
		return subId;
	}
	
	/**
	 * Visszaadja a SubMenu nevét
	 * @return Submenu neve
	 * @type String
	 */
	this.getName = function() {
		return subName;
	}
	
	/**
	 * Visszaadja a SubMenu onClick eseményét
	 * @return SubMenu onClickje
	 * @type Object
	 */
	this.getOnClick = function() {
		return subOnClick;
	}
	
	/**
	 * Visszaadja a SubMenu statuszát
	 * @return SubMenu státusza
	 * @type String
	 */
	this.getStatus = function() {
		return subStatus;
	}
	
	/**
	 * Visszaadja a SubMenu szintjét
	 * @return SubMenu szintje
	 * @type String
	 */
	this.getLevel = function() {
		return subLevel;
	}
	
	/**
	 * Beállítja a SubMenu státuszát
	 * @param String SubMenu státusza
	 */
	this.setStatus = function( status ) {
		subStatus = new String ( status );
	}
	
}
/**
 * @constructor
 * @author Johnny
 * @param String TabMenu típusa
 * @param Number TabMenu idje
 * @param String TabMenu neve
 * @param Array TabMenu submenüje 
 */
function Tabs( tabType, tabId, tabName, tabStatus, subArray ) {	
	/**
	 * TabMenu típus
	 * @type String
	 */
	var tabType = new String( tabType );
	
	/**
	 * TabMenu id
	 * @type Number
	 */
	var tabId = new Number( tabId );
	
	/**
	 * TabMenu Név
	 * @type String
	 */
	var tabName = new String( tabName );
	
	/**
	 * TabMenu státusz
	 * @type String
	 */
	var tabStatus = new String( tabStatus );
	
	/**
	 * TabMenu subMenüje
	 * @type Array
	 */
	var subMenu = new Array;
	
	/**
	 * subMenü adatok
	 * @type Array
	 */
	var tmpArray = eval( subArray );
	
	/**
	 * subMenu objektum
	 * @type Object
	 */
	var sub = null;
	
	for ( var i = 0; i < tmpArray.length; i++ ) {
		sub = new SubMenu( i, tmpArray[i][0], tmpArray[i][1], tmpArray[i][2] );
		if ( sub )
			subMenu.push( sub );
	} 
	
	/**
	 * Visszaadja a subMenu objektumok tömbjét
	 * @return subMenu objektumok tömbjét
	 * @type Array
	 */
	this.getSubMenu = function() {
		return subMenu;
	}
	
	/**
	 * Visszaadja a TabMenu idjét
	 * @return TabMenu id
	 * @type Number
	 */
	this.getId = function() {
 		return tabId;
 	}
 	
	/**
	 * Visszaadja a Tabmenu nevét
	 * @return TabMenu neve
	 * @type String
	 */
 	this.getName = function() {
 		return tabName;
 	}
 	
	/**
	 * Visszaadja a TabMenu státuszát
	 * @return TabMenu státusz
	 * @type String
	 */
 	this.getStatus = function() {
 		return tabStatus;
 	}
 	
	/**
	 * Beállítja a TabMenu státuszát
	 * @param String TabMenu státusza
	 */
 	this.setStatus = function( status ) {
 		tabStatus = new String( status );
 	}

	/**
	 * Visszaadja a TamMenu css class-át
	 * @return  String  TabMenu class
	 */
	this.getClassName = function() {
		var status = tabStatus;
		var className = '';
		switch(status.toString()) {
			case 'inactive':
			case 'lastInactive':
			case 'firstInactive':
				className = 'tabMenuNormal';
				break;
			case 'firstActive':
			case 'active':
			case 'lastActive':
				className = 'tabMenuNormalSelected';
				break;
			case 'firstInactiveNext':
			case 'activeNext':
				className = 'tabMenuRightSelected';
				break;
			case 'activePrev':
			case 'lastInactivePrev':
				className = 'tabMenuLeftSelected';
				break;
			default:
				className = 'tabMenuNormal';
		}
		return className;
	}
 	
	/**
	 * Visszaadja a TabMenu típusát
	 * @return TabMenu típusa
	 * @type String
	 */
 	this.getType = function() {
 		return tabType;
 	}
}
/**
 * User address class
 * @param String Name
 * @param String Surname
 * @param String Forename
 * @param String City
 * @param Number ZIP code (aka PBox)
 * @param String Street address and number
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function Address(addressName, addressSurname, addressForename, addressCity, addressZip, addressAddress) {
	
	/**
	 * Name
	 * @type String
	 */
	var name = (check(addressName) ? addressName : "");
	
    /**
     * Surname
     * @type String
     */
    var surname = (check(addressSurname) ? addressSurname : "");

    /**
     * Forename
     * @type String
     */
    var forename = (check(addressForename) ? addressForename : "");

	/**
	 * City
	 * @type String
	 */
	var city = (check(addressCity) ? addressCity : "");
	
	/**
	 * ZIP code (aka PBox)
	 * @type Number
	 */
	var zip = (check(addressZip) ? addressZip : "");
	
	/**
	 * Street address and number
	 * @type String
	 */
	var address = (check(addressAddress) ? addressAddress : "");
	
	/**
	 * Sets name
	 * @param String Name
	 */
	this.setName = function(addressName) {
		name = String(addressName);
	}
	
	/**
	 * Returns name
	 * @return Name
	 * @type String
	 */
	this.getName = function() {
		return name;
	}
	
	/**
	 * Sets city
	 * @param String City
	 */
	this.setCity = function(addressCity) {
		city = String(addressCity);
	}
	
	/**
	 * Returns city
	 * @return City
	 * @type String
	 */
	this.getCity = function() {
		return city;
	}
	
	/**
	 * Sets ZIP code (aka PBox)
	 * @param Number ZIP code (aka PBox)
	 */
	this.setZip = function(addressZip) {
		zip = Number(addressZip);
	}
	
	/**
	 * Returns ZIP code (aka PBox)
	 * @return ZIP code (aka PBox)
	 * @type Number
	 */
	this.getZip = function() {
		return zip;
	}
	
	/**
	 * Sets street address and number
	 * @param Street address and number
	 */
	this.setAddress = function(addressAddress) {
		address = String(addressAddress);
	}
	
	/**
	 * Returns street address and number
	 * @return Street address and number
	 * @type String
	 */
	this.getAddress = function() {
		return address;
	}
	
	/**
	 * Sets surname
	 * @param String Surname
	 */
	this.setSurname = function(addressSurname) {
		if (check(addressSurname)) {
			surname = String(addressSurname);
		}
	}
	
	/**
	 * Returns surname
	 * @return Surname
	 * @type String
	 */
	this.getSurname = function() {
		return surname;
	}
	
	/**
	 * Sets forename
	 * @param String Forename
	 */
	this.setForename = function(addressForename) {
		if (check(addressForename)) {
			forename = String(addressForename);
		}
	}
	
	/**
	 * Returns forename
	 * @return Forename
	 * @type String
	 */
	this.getForename = function() {
		return forename;
	}
	
	/**
	 * Clones this object
	 * @return Cloned object
	 * @type Address
	 */
	this.clone = function() {
		return new Address(name, surname, forename, city, zip, address);
	}
	
}
/**
 * Class to handler user's level surveying
 * @constructor
 */
function LevelSurvey(pType) {
	
	/**
	 * Level survey type
	 * @type String
	 */
	var type = new String(pType);
	
	/**
	 * Is level survey loaded from db
	 * @type Boolean
	 */
	var isLevelSurveyLoaded = false;
	
	/**
	 * Is level survey checked
	 * @type Boolean
	 */
	var isLevelSurveyChecked = false;
	
	/**
	 * Count of correct answers
	 * @type Number
	 */
	var resultScore = 0;
	
	/**
	 * Percent of correct answers
	 * @type Number
	 */
	var resultPercent = 0;
	
	/**
	 * Level and level name by score
	 * @type Array
	 */
	var resultLevel = {level: "", name: ""};
	
	/**
	 * Pointer to this
	 * @type LevelSurveying
	 */
	var self = this;
	
	/**
	 * Get level survey type
	 * @return Level survey type
	 * @type String
	 */
	this.getType = function() {
		return type;
	}
	
	/**
	 * Is level survey loaded from db
	 * @return true if loaded, false if not (call load from db)
	 * @type Boolean
	 */
	this.isLoaded = function(callbackPage) {
		if(isLevelSurveyLoaded) {
			return true;
		}
		loadLevelSurvey(callbackPage);
		return false;
	}
	
	/**
	 * Is level survey checked
	 * @return true if it is, false if ont
	 * @type Boolean
	 */
	this.isChecked = function() {
		return isLevelSurveyChecked;
	}
	
	/**
	 * Get result score
	 * @return Result score
	 * @type Number
	 */
	this.getScore = function() {
		return resultScore;
	}
	
	/**
	 * Get result percent
	 * @return Result percent
	 * @type Number
	 */
	this.getPercent = function() {
		return resultPercent;
	}
	
	/**
	 * Get result level and name
	 * @return Result level and name
	 * @type Array
	 */
	this.getLevel = function() {
		return resultLevel;
	}
	
	/**
	 * Set result level and name
	 * @param String Level and level name
	 */
	this.setLevel = function(pLevel, pName) {
		resultLevel = {level: pLevel, name: pName};
	}
	
	/**
	 * Map containing question - right answer pairs
	 * @type Map
	 */
	var rightAnswers = new Map();
	
	/**
	 * Map containing question - user answer pairs
	 * @type Map
	 */
	var userAnswers = new Map();
	
	/**
	 * Level survey scores
	 * @type Array
	 */
	var levelSurveyScores = [{type: 'home', scores: new Array(3, 5, 7, 9, 11, 13)},
								{type: 'normal', scores: new Array(6, 18, 26, 37, 48, 54)}];
							
	/**
	 * Level survey Levels
	 * @type Array
	 */
	var levelSurveyLevels = new Array("A1-1", "A1-2", "A2-1", "A2-2", "B1-1", "B1-2", "B2-1");
								
	/**
	 * Level survey Level names
	 * @type Array
	 */
	var levelSurveyNames = new Array("Kezdő I", "Kezdő II", "Alapfok I", "Alapfok II", "Középfok I", "Középfok II", "Középfok III");
	
	/**
	 * Calculate level by score
	 * @param Score
	 * @type Number
	 */
	function levelCalculate(pScore) {
		var scores = "";
		for(var i = 0; i < levelSurveyScores.length; i++) {
			if(levelSurveyScores[i]["type"] == type) {
				scores = levelSurveyScores[i]["scores"];
			}
		}
		if(scores == "") {
			return {level: "", name: ""};
		}
		for(var i = 0; i < scores.length; i++) {
			if(pScore > scores[i]) {
				continue;
			} else {
				return {level: levelSurveyLevels[i], name: levelSurveyNames[i]};
				break;
			}
		}

		return {level: levelSurveyLevels[levelSurveyLevels.length - 1], name: levelSurveyNames[levelSurveyNames.length - 1]};
	}
	
    /**
     * Gets survey from db
     * @param Object event
     */
	function loadLevelSurvey(callbackPage) {
		var oldSeq = esuli.contentManager.getSeq();

		var comm = new CommGateRequest(
			"REQ_ACCESS",
			[ "ESULI_GET_LEVEL_SURVEY" ],
			function(pResponse) {
				var data = pResponse[0].getDataAsObjectArray();
				
				resultScore = data[0].result;
				resultPercent = data[0].percent;
				resultLevel = levelCalculate(resultScore);
				
				var questions = new Array();
				questions = data[0].questions.split(";");
				var answers = new Array();
				answers = data[0].answers.split(";");
				
				if (data[0].answers != "") {
					isLevelSurveyChecked = true;
					for ( var i = 0; i < questions.length; i++ ) {
						userAnswers.put( questions[i], answers[i] );
					}
				}
				
				isLevelSurveyLoaded = true;
				
				if (callbackPage != undefined && oldSeq == esuli.contentManager.getSeq()) {
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, callbackPage));
				}
			}
		);

		comm.addDataLevel([ [ "TYPE" ], [ type ] ]);
		engine.commGate.sendWithSession([ comm ]);
	}
	
	/**
	 * Parses input HTML for the questions and the right answers
	 * @param String Input HTML
	 * @return Parsed HTML
	 * @type String
	 */
	function parse(exerciseHTML) {
		var html = "";
		
		var tagStart = 0;
		var tagEnd = 0;
		var inputName = "";
		var inputValue = "";
		var inputType = "";
		var remainder = exerciseHTML;
		var htmlTag = remainder.match(/<[^>]*>/);
		
		while (htmlTag) {
			//actual HTML tag
			htmlTag = String(htmlTag);
			
			//start & and of HTML tag
			tagStart = remainder.indexOf(htmlTag);
			tagEnd = tagStart + htmlTag.length;
			
			//name of HTML tag
			inputName = htmlTag.match(/name=[^ >]*/i);
			if (inputName) {
				inputName = String(inputName).replace(/name=/i, "");
				inputName = String(inputName).replace(/"/g, "");
			}
			
			//value of HTML tag
			inputValue = htmlTag.match(/value="[^">]*"/i);
			if (inputValue) {
				inputValue = String(inputValue).replace(/value=/i, "");
				inputValue = String(inputValue).replace(/"/g, "");
			}
			
			//input tags
			if (htmlTag.indexOf("<input") == 0 && inputName && inputValue) {
				//add keylogging
				htmlTag = htmlTag.replace(/<input/i, "<input onkeyup=\"esuli.user.getLevelSurvey('" + type + "').setAnswer('" + inputName + "')\" onclick=\"esuli.user.getLevelSurvey('" + type + "').setAnswer('" + inputName + "')\"");
				
				//type of input tag
				inputType = htmlTag.match(/type="?[^">]*"?/i);
				if (inputType) {
					inputType = String(inputType).replace(/type=/i, "");
					inputType = String(inputType).replace(/"/g, "");
				} else {
					inputType = "text";
				}
				
				switch (inputType) {
					
					//input radio
					case "radio":
						//this is the right radio button
						if (htmlTag.match(/checked/i)) {
							rightAnswers.put(inputName, inputValue);
							
							htmlTag = htmlTag.replace(/checked="checked"/gi, "");
							htmlTag = htmlTag.replace(/checked/gi, "");
						}
						
						//add user answer
						htmlTag = htmlTag.replace(/<input/i, "<input {if userAnswers.get('" + inputName + "') == '" + inputValue + "'} checked=\"checked\"{/if}");
						break;
					
					//input checkbox
					case "checkbox":
						//this is the right checkbox
						if (htmlTag.match(/checked/i)) {
							rightAnswers.put(inputName, inputValue);
							
							htmlTag = htmlTag.replace(/checked="checked"/gi, "");
							htmlTag = htmlTag.replace(/checked/gi, "");
						//this is a bad checkbox
						} else {
							rightAnswers.put(inputName, "");
						}
						
						//add user answer
						htmlTag = htmlTag.replace(/<input/i, "<input {if userAnswers.get('" + inputName + "') == '" + inputValue + "'} checked=\"checked\"{/if}");
						break;
					
					//input text
					case "text":
						rightAnswers.put(inputName, inputValue);
						
						//add user answer
						htmlTag = htmlTag.replace(/value="[^">]*"/gi, "value=\"{if userAnswers.get('" + inputName + "')}${decodeSpecialCharsFieldValue(userAnswers.get('" + inputName + "'))}{/if}\" onFocus=\"this.className='LessonTextboxSelected'\" onBlur=\"this.className='LessonTextbox'\"");
						break;
				}
			}
			
			//add to parsed HTML
			html += remainder.substring(0, tagStart) + htmlTag;
			
			//set remainder HTML to parse
			remainder = remainder.substring(tagEnd);
			
			//set next HTML tag
			htmlTag = remainder.match(/<[^>]*>/);
		}
		
		//convert it to template
		return html + remainder;
	}
	
	/**
	 * Sets answer to a key
	 * @param String Key of answer
	 */
	this.setAnswer = function(key) {
		var inputs = document.getElementsByName(key);
		var input;
		
		for (var i = 0; i < inputs.length; i++) {
			//HTML element
			input = inputs[i];
			
			//textarea or input text
			if (input.rows != undefined || input.type == "text") {
				answer = encodeSpecialCharsFieldValue(input.value).trim();
				
				//remove double spaces
				while (answer.match(/  /)) {
					answer = answer.replace(/  /g, " ");
				}
				
				//remove leading spaces
				if (answer.charAt(0) == " ") {
					answer = answer.substr(1);
				}
				
				//remove trailing spaces
				if (answer.charAt(answer.length) == " ") {
					answer = answer.substr(0, answer.length - 1);
				}
				
				userAnswers.put(key, answer);
			
			//input radio
			} else if (input.type == "radio" && input.checked) {
				userAnswers.put(key, encodeSpecialCharsFieldValue(input.value));
			
			//input checkbox
			} else if (input.type == "checkbox") {
				if (input.checked) {
					userAnswers.put(key, encodeSpecialCharsFieldValue(input.value));
				} else {
					userAnswers.put(key, "");
				}
			}
		}
	}
	
	/**
	 * Return true if the exercise is fully completed
	 * @return True if the exercise is fully completed
	 * @type Boolean
	 */
	function isCompleted() {
		var it = rightAnswers.keys().iterator()
		var names = new Array();
		var completeds = new Array();
		var inputs;
		var element;
		
		while (it.hasNext()) {
			inputs = document.getElementsByName(it.next());
			
			for (var j = 0; j < inputs.length; j++) {
				names.push(inputs[j].name);
				
				element = inputs[j];
				
				if (
					(element.tagName == "INPUT" && (element.type == "text" || element.type == "password") && element.value != "") ||
					(element.tagName == "INPUT" && (element.type == "checkbox" || element.type == "radio") && element.checked) ||
					(element.tagName == "TEXTAREA" && element.value != "")
				) {
					completeds.push(inputs[j].name);
				}
			}
		}
		
		for (var i = 0; i < names.length; i++) {
			if (completeds.indexOf(names[i]) < 0) {
				return false;
			}
		}
		return true;
	}
	
	/**
	 * Parses and processes first part
	 * @param String Input HTML
	 * @return Parsed and processed HTML
	 * @type String
	 */
	function process(exerciseHTML) {
		var html = "";
		
		var tagStart = 0;
		var tagEnd = 0;
		var inputName = "";
		var inputValue = "";
		var inputType = "";
		var remainder = exerciseHTML;
		var htmlTag = remainder.match(/<[^>]*>/);
		
		while (htmlTag) {
			//actual HTML tag
			htmlTag = String(htmlTag);
			
			//start & and of HTML tag
			tagStart = remainder.indexOf(htmlTag);
			tagEnd = tagStart + htmlTag.length;
			
			//name of HTML tag
			inputName = htmlTag.match(/name=[^ >]*/i);
			if (inputName) {
				inputName = String(inputName).replace(/name=/i, "");
				inputName = String(inputName).replace(/"/g, "");
			}
			
			//value of HTML tag
			inputValue = htmlTag.match(/value="[^">]*"/i);
			if (inputValue) {
				inputValue = String(inputValue).replace(/value=/i, "");
				inputValue = String(inputValue).replace(/"/g, "");
			}
			
			//input tags
			if (htmlTag.indexOf("<input") == 0 && inputName && inputValue) {

				//type of input tag
				inputType = htmlTag.match(/type="?[^">]*"?/i);
				if (inputType) {
					inputType = String(inputType).replace(/type=/i, "");
					inputType = String(inputType).replace(/"/g, "");
				} else {
					inputType = "text";
				}
				
				switch (inputType) {
					
					//input radio
					case "radio":
						//this is the right radio button
						if (htmlTag.match(/checked/i)) {
							htmlTag = htmlTag.replace(/checked="checked"/gi, "");
							htmlTag = htmlTag.replace(/checked/gi, "");
						}
						
						var thisIsRightAnswer = rightAnswers.get(inputName) == inputValue ? true : false;
						var thisIsUserAnswer = userAnswers.get(inputName) == inputValue ? true : false;
						
						//add solution
						var arVersion = navigator.appVersion.split("MSIE");
						var version = parseFloat(arVersion[1]);
						
						var iePNGBugSpan = "";
						var iePNGBugSpanOkSelected = "";
						var iePNGBugSpanBad = "";
						var iePNGBugSpanBadSelected = "";
						var iePNGBugImg = "";
						if ((version >= 5.5) && (document.body.filters)) {
							var begin = " style=\"vertical-align:middle; display:inline-block; width:18px; height:18px; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader (src='images/1_5/workbook/";
							var end = "', sizingMethod='scale');\"";
							iePNGBugSpan = begin + "radio.png" + end;
							iePNGBugSpanOkSelected = begin + "radio_ok_selected.png" + end;
							iePNGBugSpanBad = begin + "radio_bad.png" + end;
							iePNGBugSpanBadSelected = begin + "radio_bad_selected.png" + end;
							iePNGBugImg = " style=\"display: none;\"";
						}
												
						htmlTag = "<span class=\"LessonRadioImg\"";
						if( thisIsRightAnswer ) {
							if( thisIsUserAnswer ) {
								htmlTag += iePNGBugSpanOkSelected + "><img width=\"18\" height=\"18\"" + iePNGBugImg + " src=\"images/1_5/workbook/radio_ok_selected.png";
							} else {
								htmlTag += iePNGBugSpanBad + "><img width=\"18\" height=\"18\"" + iePNGBugImg + " src=\"images/1_5/workbook/radio_bad.png";
							}
						} else {
							if( thisIsUserAnswer ) {
								htmlTag += iePNGBugSpanBadSelected + "><img width=\"18\" height=\"18\"" + iePNGBugImg + " src=\"images/1_5/workbook/radio_bad_selected.png";
							} else {
								htmlTag += iePNGBugSpan + "><img width=\"18\" height=\"18\"" + iePNGBugImg + " src=\"images/1_5/workbook/radio.png";
							}
						}
						htmlTag += "\" /></span>";
											
						break;
					
					//input checkbox
					case "checkbox":
						//this is the right checkbox
						if (htmlTag.match(/checked/i)) {
							htmlTag = htmlTag.replace(/checked="checked"/gi, "");
							htmlTag = htmlTag.replace(/checked/gi, "");
						}
						
						//add user answer
						htmlTag = htmlTag.replace(/<input/i, "<input " + (userAnswers.get(inputName) == inputValue ? " checked=\"checked\"" : ""));
						
						//add solution
						htmlTag = htmlTag.replace(/><\/span>/i, ">" + (rightAnswers.get(inputName) == inputValue ? "&nbsp;OK&nbsp;" : "") + "</span>");
						
						break;
					
					//input text
					case "text":
						var isUserAnswerRight = userAnswers.get(inputName) == rightAnswers.get(inputName) ? true : false;
						
						//add user answer
						htmlTag = htmlTag.replace(/<input/i, "<input value=\"" + (userAnswers.get(inputName) ? decodeSpecialCharsFieldValue(userAnswers.get(inputName)) : "") + "\"");
						
						//add solution						
						htmlTag = "<span class=\"LessonTextbox";
						if( isUserAnswerRight ) {
							htmlTag += "Ok\">" + userAnswers.get(inputName) + "</span>";
						} else {
							htmlTag += "BadPre\">" + whereIsBad(userAnswers.get(inputName), rightAnswers.get(inputName)) + "</span><span class=\"ExerciseAnswerIsBad\">&nbsp;" + rightAnswers.get(inputName) + "&nbsp;</span>";
						}
						
						break;
				}
			}
			
			//add to parsed HTML
			html += remainder.substring(0, tagStart) + htmlTag;
			
			//set remainder HTML to parse
			remainder = remainder.substring(tagEnd);
			
			//set next HTML tag
			htmlTag = remainder.match(/<[^>]*>/);
		}
		
		//convert it to template
		return html + remainder;
	}
	
	/**
	 * Check where is user answer bad
	 */
	function whereIsBad( pUserAnswer, pInputValue ) {
		var ret = '';
		var find = false;
		
		if( !pUserAnswer || pUserAnswer == "" || pUserAnswer == null ) {
			return '</span><span class="LessonTextboxBad">';
		}
		
		for ( var i = 0; i < pUserAnswer.length; i++ ) {
			if ( ( pUserAnswer.charAt(i) != pInputValue.charAt(i) ) && !find ) {
				ret += '</span><span class="LessonTextboxBad">' + pUserAnswer.charAt(i);
				find = true;
			} else {
				ret += pUserAnswer.charAt(i);
			}
		}
		return ret;
	}
	
	/**
	 * Processes user answers
	 * @param Boolean Force process
	 */
	this.solve = function(force) {
		if (! isCompleted() && ! force) {
			engine.dialogManager.add(new Dialog(
				"A Szintfelmérő nincs teljesen kitöltve.<br />Biztosan javítsam?",
				"confirm",
				[null, function() { esuli.user.getLevelSurvey(type).solve(true); }, null],
				["", "Javítsd", "Ne javítsd"]
			));
			return;
		}
		
		resultCalculate();
		
		if(type == "home") {
			esuli.user.setPhase("technika");
//			esuli.home.showNextFiveStepPage();
		} else {
			engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
		}
	}
	
	/**
	 * Calculates level survey result
	 * Send it to DB
	 * Set user level survey level
	 */
	function resultCalculate() {
		var it = rightAnswers.keys().iterator();
		var count = 0;
		var key;
		
		while (it.hasNext()) {
			key = it.next();
			
			if (decodeSpecialCharsFieldValue(rightAnswers.get(key)).toUpperCase() == decodeSpecialCharsFieldValue(userAnswers.get(key)).toUpperCase()) {
				count++;
			}
		}
		
		resultScore = count;
		resultPercent = Math.round(count * 100 / rightAnswers.size());
		resultLevel = levelCalculate(resultScore);
		
		isLevelSurveyChecked = true;
		
		var comm = new CommGateRequest ( 
			'REQ_ACCESS', 
			[ 'ESULI_STUDENT_SET_LEVEL' ], 
			function(pResponse) {}
		);
		comm.addDataLevel ( [ [ 'LEVEL', '', '' ], 
		[ resultLevel.level, '', '' ]] );
		engine.commGate.sendWithSession([ comm ]);
		
		var command = new CommGateRequest ( 
			'REQ_ACCESS', 
			[ 'ESULI_SET_LEVEL_SURVEY' ], 
			function(pResponse) {} 
		);
		command.addDataLevel ( [ [ "TYPE", "RESULT", "PERCENT", "QUESTION", "ANSWER" ], 
		[ type, resultScore, resultPercent, userAnswers.keysArray().toString().replace(/,/g, ';'), userAnswers.valuesArray().toString().replace(/,/g, ';') ]] );

		engine.commGate.sendWithSession([ command ]);
	}
	
	/**
	 * Clears level survey result
	 */
	this.clearResult = function() {
		resultScore = 0;
		resultPercent = 0;
		isLevelSurveyChecked = false;
		userAnswers.clear();

		var comm = new CommGateRequest ( 
			'REQ_ACCESS', 
			[ 'ESULI_SET_LEVEL_SURVEY' ], 
			function(pResponse) {} 
		);
		comm.addDataLevel ( [ [ "TYPE", "RESULT", "PERCENT", "QUESTION", "ANSWER" ], 
		[ type, 0, 0, "", "" ] ] );
		engine.commGate.sendWithSession([ comm ]);
		
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
	}
	
	/**
	 * Returns requested page
	 * @return Requested page
	 * @type Object
	 */
	this.getPage = function() {
		var page = { leftWidth: '0px', centerWidth: '743px', rightWidth: '225px', left: "", center: "", right: "" };
		var survey = "";
		var surveyHtml = engine.commGate.getStringByUrl(BASE_URL + "/ajax/1_5/templates/levelsurvey/" + type + "ls.tmpl");
		if(isLevelSurveyChecked) {
			survey = new Template(type + "LevelSurvey", process(parse(surveyHtml)));
		} else {
			survey = new Template(type + "LevelSurvey", parse(surveyHtml));
		}
		page.center = survey.process({rightAnswers: rightAnswers, userAnswers: userAnswers});
		return page;
	}
}
/**
 * Represents the user.
 * @constructor
 */
function User() {
	
	/**
	 * Pointer to this
	 * @type User
	 */
	var self = this;
	
	/**
	 * Last visited page
	 * @type Object
	 */
	var lastPage;
	
	/**
	 * Agent id of user
	 * @type Number
	 */
	var agentId = 0;
	
	/**
	 * Agent is supervisor
	 * @type Boolean
	 */
	var supervisor = false;
	
	/**
	 * Is agent page
	 * @type Boolean
	 */
	var isAgentPage = false;
	
	/**
	 * Is user logged in
	 * @type Boolean 
	 */
	var loggedIn = false;

	/**
	 * Session id
	 * @type Number
	 */
	var sessionId = -1;
	
	/**
	 * Is user registered now
	 */
	var newReg = false;
	
	/**
	 * Role
	 * @type String
	 */
	var role = "guest";
	
	/**
	 * Email address
	 * @type String
	 */
	var email = "";
	
	/**
	 * Nick name
	 * @type String
	 */
	var nickname = "";
	
	/**
	 * Credit
	 * @type Number
	 */
	var credit = 0;
	
	/**
	 * Phone number
	 * @type String
	 */
	var phone = "";	
	
	/**
	 * User want newsletter
	 * @type Boolean
	 */
	var newsLetter = false;
	
	/**
	 * Living address
	 * @type Address
	 */
	var livingAddress = new Address();
	
	/**
	 * Delivery address
	 * @type Address
	 */
	var deliveryAddress = new Address();
	
	/**
	 * Billing address
	 * @type Address
	 */
	var billingAddress = new Address();
	
	/**
	 * Temporary address for copy
	 * @type Address
	 */
	var tempAddress = new Address();
	
	/**
	 * Level surveying pages
	 * @type LevelSurvey
	 */
	var levelSurvey = new Array();
	
	/**
	 * Is profile loaded
	 * @type Boolean
	 */
	var profilLoaded = false;
	
	/**
	 * User Phase
	 * @type String
	 */
	var phase = "";

    /**
     * Ticket start date
     * @type Boolean
     */
    var monthlyTicketStart;

    /**
     * Ticket type
     * @type Boolean
     */
    var monthlyTicketType;

    /**
     * Ticket over
     * @type Boolean
     */
    this.monthlyTicketOver = false;
    
    this.setAgentId = function(userAgentId) {
	agentId = userAgentId;
    }
    
    this.getAgentId = function() {
	return agentId;
    }
    
    this.setSupervisor = function(userSupervisor) {
	supervisor = userSupervisor;
    }
    
    this.isSupervisor = function() {
	return supervisor;
    }

	/**
	 * Get level survey 
	 * @return Level survey
	 * @type Object
	 */
	this.getLevelSurvey = function(pType) {
		var type = !pType ? "normal" : pType;
		if(levelSurvey.length > 0) {
			for(var i = 0; i < levelSurvey.length; i++) {
				if(levelSurvey[i].getType() == type) {
					return levelSurvey[i];
					break;
				}
			}
		}
		var ls = new LevelSurvey(type);
		levelSurvey.push(ls);
		return ls;
	}
	
	/**
	 * Returns user loged in
	 * @return Session loged in
	 * @type Boolean
	 */
	this.isLoggedIn = function() {
	    return loggedIn;
	}
	
	/**
	 * Returns session id
	 * @return Session id
	 * @type Number
	 */
	this.getSessionId = function() {
		return sessionId;
	}
	
	/**
	 * Sets session id
	 * @param Number Session id
	 */
	this.setSessionId = function(userSessionId) {
		sessionId = userSessionId;
	}
	
	/**
	 * Is new reg
	 * @return New reg
	 */
	this.isNewReg = function() {
		return newReg;
	}
	
	/**
	 * Returns role
	 * @return Role
	 * @type String
	 */
	this.getRole = function() {
		return role;
	}
	
	/**
	 * Sets role
	 * @param String Role
	 */
	this.setRole = function(userRole) {
		role = userRole;
	}
	
	/**
	 * Sets phone number
	 * @param String Phone number
	 */
	this.setPhone = function(userPhone) {
		phone = userPhone;
	}
	
	/**
	 * Returns phone number
	 * @return Phone
	 * @type String
	 */
	this.getPhone = function() {
		return phone;
	}
	
	/**
	 * Returns newsletter
	 * @return true if user want newsletter
	 * @type Boolean
	 */
	this.getNewsLetter = function() {
		return newsLetter;
	}
	
	/**
	 * Returns email address
	 * @return Email address
	 * @type String
	 */
	this.getEmail = function() {
		return email;
	}
	
	/**
	 * Sets email address
	 * @param String Email address
	 */
	this.setEmail = function(userEmail) {
		email = userEmail;

	}
	
	/**
	 * Returns Nick name
	 * @return Nick name
	 * @type String
	 */
	this.getNickname = function() {
		return nickname;
	}
	
	/**
	 * Returns credit
	 * @return credit
	 * @type Number
	 */
	this.getCredit = function() {
		return credit;
	}
	
	/**
	 * Sets credit
	 * @param Number Credit
	 */
	this.setCredit = function(userCredit) {
		credit = userCredit;
	}

	/**
	 * Sets living address
	 * @param Address Living addres
	 */
	this.setLivingAddress = function(userLivingAddress) {
		if (checkType(userLivingAddress, Address)) {
			livingAddress = userLivingAddress;
		}
	}
	
	/**
	 * Returns living address
	 * @return Living address
	 * @type Address
	 */
	this.getLivingAddress = function() {
		return livingAddress;
	}
	
	/**
	 * Sets delivery address
	 * @param Address Delivery addres
	 */
	this.setDeliveryAddress = function(userDeliveryAddress) {
		if (checkType(userDeliveryAddress, Address)) {
			deliveryAddress = userDeliveryAddress;
		}
	}
	
	/**
	 * Returns delivery address
	 * @return Delivery address
	 * @type Address
	 */
	this.getDeliveryAddress = function() {
		return deliveryAddress;
	}
	
	/**
	 * Sets billing address
	 * @param Address Billing addres
	 */
	this.setBillingAddress = function(userBillingAddress) {
		if (checkType(userBillingAddress, Address)) {
			billingAddress = userBillingAddress;
		}
	}
	
	/**
	 * Returns billing address
	 * @return Billing address
	 * @type Address
	 */
	this.getBillingAddress = function() {
		return billingAddress;
	}
	
	/**
	 * Return profile is loaded
	 * @retunr profile is loaded
	 * @type Boolean
	 */
	this.getProfilLoaded = function() {
		return profilLoaded;
	}
	
	/**
	 * Set user phase
	 * @param Phase
	 * @type String
	 */
	this.setPhase = function(pPhase) {
		phase = pPhase;
		var command = new CommGateRequest (
			'REQ_ACCESS', 
			[ 'ESULI_STUDENT_SET_PHASE' ],  
			function(response) {}
		);
       command.addDataLevel ( [['PHASE', '', '' ], [ pPhase, '', '' ]] );

       engine.commGate.sendWithSession([ command ]);
	}
	
	/**
	 * Get user phase
	 * @return Pahes 
	 * @type String
	 */
	this.getPhase = function() {
		return phase;
	}
	
	/**
	 * Send USER_PRELOGIN event
	 */
	this.preLogin = function() {
		var event = new Event(self, EventManager.EVENT_USER_PRELOGIN);
		event.put("uEmail", $("loginUsername").value);
		event.put("uPassword", $("loginPassword").value);
		event.put("uRemember", "yes")
		
		engine.eventManager.invoke(event);
		self.listenUserPrelogin(event);
	}
	
	/**
	 * Login user
	 * @param Object event
	 */
	this.listenUserPrelogin = function(event) {

            glLog.fireBugLog("group", "", "", "Call listenUserPrelogin()");
            glLog.fireBugLog("log", "User.js", "listenUserPrelogin()", "1");

		engine.log.addLog( 'User.js', 'listenUserPrelogin', 'INFO', event.get("uEmail") + ' sid: ' + event.get("sId") + ' is logging in.' );

		var sId = event.get('sId');
		var uUserName = event.get("uEmail");
		var uPassword = event.get('uPassword');
		
		var now = new Date();
		var hour = now.getHours();
		var day = now.getDay();
		
		//Munkaidőben, munkanapon nem engedjük be a richtereseket
		if ( uUserName && uUserName.indexOf('richter.hu') != -1 && hour > 7 &&  hour < 17 && day < 6 && day > 0 ) {
			engine.dialogManager.add(new Dialog("A Richter Gedeon dolgozói a vállalattal való megállapodásunk értelmében reggel 8 és délután 17 óra között nem vehetik igénybe a szolgáltatást. Egy másik időpontban szívesen látjuk! Megértését köszönjük!", "alert", [ null, null, null ]));
			return;
		}
		
		if (sId) {
			// Automata belépés történt
			engine.commGate.send([ new CommGateRequest("ESULI_RENEW_SESSION", [ sId ], commGateLogin) ]);
		} else {
			// Sima bejelentkezés, ellenőrizzük
			var uUserNameInput = $('loginUsername');
			var uPasswordInput = $('loginPassword');
			var uPasswordTextInput = $('loginPasswordText');
			
			uUserNameInput.className = 'normalTextInput';
			uPasswordInput.className = 'normalTextInput';
			uPasswordTextInput.className = 'normalTextInput';
			
			var defUserName = 'Felhasználónév:';
			var defEmail = 'E-mail cím:';
			
			// Username check
			if(esuli.staticContent.trimTextInput(uUserName) == '' || uUserName == defUserName) {
				uUserNameInput.className = 'normalTextInputError';
				engine.dialogManager.add(new Dialog('Nem adtad meg a felhasználónevet!', 'alert'));
				return;
			}
			
			// Password check
			if(esuli.staticContent.trimTextInput(uPassword) == '') {
				uPasswordInput.className = 'normalTextInputError';
				uPasswordTextInput.className = 'normalTextInputError';
				engine.dialogManager.add(new Dialog('Nem adtad meg a jelszót!', 'alert'));
				return;
			}

            glLog.fireBugLog("log", "User.js", "listenUserPrelogin()", "2");			
			engine.commGate.send([ new CommGateRequest("ESULI_LOGIN", [ uUserName, uPassword, 'Normal' ], commGateLogin) ]);
		}

		glLog.fireBugLog("groupEnd", "", "", "Call listenUserPrelogin()");
	}
	
	/**
	 * Login user
	 * Response
	 */
	function commGateLogin( pResponse ) {
		var comm0 = pResponse[0].getCommandLine();
		
		if( comm0[2] == 1 ) {
			var comm1 = pResponse[1].getCommandLine();
			var aTmp = getStringAsObjectArray(comm1[5]);
			var status = aTmp["status"];

			if ( status == "Inaktív" ) {
				engine.dialogManager.add(new Dialog("Fizetési hátralék miatt ezzel az e-mail címmel jelenleg nem tudsz belépni. Kérjük, rendezd tartozásod!<br /><br />Ha kérdésed van, keresd ügyfélszolgálatunkat az <a href='mailto:info@enyelviskola.hu'>info@enyelviskola.hu</a> email címen, a (1) 555-7190-es telefonszámon vagy az <a href='skype:enyelviskola'>enyelviskola</a> Skype címen.", "alert", null));
				return;
			}
			
			engine.cookieManager.set( "remember", "yes" );	
			engine.cookieManager.set( "sId", aTmp["sessionid"]);
			
			init();

			if( engine.cookieManager.get("agent") ) {
				engine.cookieManager.remove("agent");
			}

			sessionId = aTmp["sessionid"];
			role =  aTmp["rolename"];
			email = aTmp["email"];
			nickname = aTmp["nickname"];
			credit = aTmp["credit"];
			loggedIn = true;
			
			if(role == "student") {
				loadProfile();
			} else if (role == "agent") {
				var c = new CommGateRequest(
					'REQ_ACCESS',
					[ 'SALES_GET_AGENT_ID' ], [], 
					function(response) {
						var data = response[0].getDataAsObjectArray();
						esuli.user.setAgentId(data.agentid);
						esuli.user.setSupervisor(data.type == "supervisor" > 0 ? false : true);
					});
				c.addDataLevel([ [ "" ], [ "" ] ]);
				engine.commGate.sendWithSession([ c ]);
				
				profilLoaded = true;
				//engine.eventManager.invoke(new Event(self, EventManager.EVENT_PROFILE_LOADED));
				esuli.user.listenProfileLoaded();
			} else {
			    profilLoaded = true;
			    //engine.eventManager.invoke(new Event(self, EventManager.EVENT_PROFILE_LOADED));
				esuli.user.listenProfileLoaded();
			}
			
			var name = email;
			if (livingAddress.getForename()) {
				name = livingAddress.getSurname() + " " + livingAddress.getForename();
			}
			engine.cookieManager.set( "uEmail", name );
			engine.eventManager.invoke(new Event(self, EventManager.EVENT_USER_LOGIN));
		} else {
			if( engine.cookieManager.get("remember") == "yes" && engine.cookieManager.get("sId") != null) {
				engine.cookieManager.set( "remember", "no" );
				engine.cookieManager.remove("sId");
			}
			if ( comm0[3] == "INVALID PASSWORD" ) {
				var uPassword = $('loginPassword');
				var uPasswordText = $('loginPasswordText');
				uPassword.className = 'normalTextInputError';
				uPasswordText.className = 'normalTextInputError';
				engine.dialogManager.add(new Dialog('Hibás jelszó!', 'alert'));
			}
			if ( comm0[3] == "UNKNOWN STUDENT." || comm0[3] == "INVALID INTERFACE" ) {
				var uUserName = $('loginUsername');
				uUserName.className = 'normalTextInputError';
				engine.dialogManager.add(new Dialog('Nem megfelelő felhasználónevet vagy e-mail címet adtál meg!', 'alert'));
			}
			if( comm0[2] == "-25" && comm0[3] == "" ) {
				engine.log.addLog( 'User.js', 'commGateLogin', 'INFO', ' sid: ' + sessionId + ' is on -25 (logged in from two place)' );
				engine.dialogManager.add(new Dialog('Időközben egy másik böngészőprogramból is bejelentkeztél az eNyelviskolába, ezért itt kiléptettünk. Ha szeretnéd újra ebben a böngészőben használni a weblapot, akkor csak jelentkezz be ismét!', 'alert', esuli.user.logout()));
			}
		}
		
        engine.log.addLog( 'User.js', 'commGateLogin', 'INFO', email + ' sid: ' + sessionId + ' ' + role + ' is logging in.' );
	}
	
	/**
	 * Logout user
	 */
	this.logout = function() {
		engine.log.addLog( 'User.js', 'logout', 'INFO',  this.getEmail + ' is logging out.' );
		engine.cookieManager.set( "remember", "no" );
		engine.cookieManager.remove("sId");
		engine.cookieManager.remove("interface");
		engine.cookieManager.remove("uEmail");
		engine.cookieManager.remove("uRoom");

		window.document.location.href = BASE_URL;
	}
	
	/**
	 * Registering new user 
	 */
	this.userReg = function(pReg) {
		var loginHeader = $('loginHeader');
		var loginButton = $('userLoginButton');
		var regBox = $('registerPasswordBox');
		var notRegButton = $('userNotRegButton');
		var forgottenPassword = $('forgottenPasswordBox');
		if(!loginButton || !regBox || !notRegButton) {
			return;
		}
		
		var uUserName = $('loginUsername');
		var uPassword = $('loginPassword');
		var uPasswordText = $('loginPasswordText');
		var uPasswordAgain = $('registerPasswordAgain');
		var uPasswordAgainText = $('registerPasswordAgainText');
		var uEmail = $('registerEmail');
		var uNewsLetter = $('registerNewsLetter').checked ? true : false;
		if(!uUserName || !uPassword || !uPasswordAgain || !uEmail) {
			return;
		}
		
		uUserName.className = 'normalTextInput';
		uPassword.className = 'normalTextInput';
		uPasswordText.className = 'normalTextInput';
		uPasswordAgain.className = 'normalTextInput';
		uPasswordAgainText.className = 'normalTextInput';
		uEmail.className = 'normalTextInput';

		if(!pReg) {
			loginHeader.innerHTML = 'Bejelentkezés';
			loginButton.style.display = 'block';
			regBox.style.display = 'none';
			notRegButton.style.display = 'none';
			forgottenPassword.style.display = 'block';
			return
		} else if(regBox.style.display != 'block') {
			loginHeader.innerHTML = 'Regisztráció';
			loginButton.style.display = 'none';
			regBox.style.display = 'block';
			notRegButton.style.display = 'block';
			forgottenPassword.style.display = 'none';
			return;
		}
		
		var defUserName = 'Felhasználónév:';
		var defEmail = 'E-mail cím:';
		
		// Username check
		if(esuli.staticContent.trimTextInput(uUserName.value) == '' || uUserName.value == defUserName) {
			uUserName.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Nem adtad meg a felhasználónevet!', 'alert'));
			return;
		} else if(!esuli.staticContent.chechUsername(uUserName.value)) {
			uUserName.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('A megadott felhasználónév formátuma nem megfelelő!<br /><br class="halfLine" /><span class="grayNormal">A felhasználónév kizárólag a magyar abc betűiből és számokból állhat, szóközt és speciális karaktereket nem tartalmazhat. Minimális hossza 5 karakter!</span>', 'alert'));			
			return;
		}
		
		// Password check
		if(esuli.staticContent.trimTextInput(uPassword.value) == '') {
			uPassword.className = 'normalTextInputError';
			uPasswordText.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Nem adtad meg a jelszót!', 'alert'));
			return;
		} else if(!esuli.staticContent.chechPassword(uPassword.value)) {
			uPassword.className = 'normalTextInputError';
			uPasswordText.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('A megadott jelszó formátuma nem megfelelő!<br /><br class="halfLine" /><span class="grayNormal">A jelszó kizárólag a magyar abc betűiből és számokból állhat, szóközt és speciális karaktereket nem tartalmazhat. Minimális hossza 5 karakter!</span>', 'alert'));
			return;
		} else if(esuli.staticContent.trimTextInput(uPasswordAgain.value) == '' || esuli.staticContent.trimTextInput(uPassword.value) != esuli.staticContent.trimTextInput(uPasswordAgain.value)) {
			uPassword.className = 'normalTextInputError';
			uPasswordText.className = 'normalTextInputError';
			uPasswordAgain.className = 'normalTextInputError';
			uPasswordAgainText.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('A két jelszó nem egyezik!', 'alert'));
			return;
		}
		
		// Email check
		if(esuli.staticContent.trimTextInput(uEmail.value) == '' || uEmail.value == defEmail) {
			uEmail.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Nem adtad meg az e-mail címed!', 'alert'));
			return;
		} else if(!esuli.staticContent.checkEmail(esuli.staticContent.trimTextInput(uEmail.value))) {
			uEmail.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Az e-mail cím formátuma nem megfelelő!<br /><br class="halfLine" /><span class="grayNormal">A regisztráció során saját, létező e-mail címedet add meg, mert a későbbi kapcsolattartásban fontos szerepe lesz, illetve sikeres regisztrációt követőne ezt is használhatod a bejelentkezéshez.</span>', 'alert'));
			return;
		}
		
		newsLetter = $('registerNewsLetter').checked ? true : false;
		nickname = uUserName.value;
		
		engine.log.addLog( 'User.js', 'userReg', 'INFO', uEmail + ' registration.' );
	    
		if (engine.cookieManager.get('agent')) {
		    engine.commGate.send([ new CommGateRequest("REQ_REGISTER", [ uEmail.value, uUserName.value, uPassword.value, engine.cookieManager.get('agent'), 'Normal' ], commGateReg) ]);
		} else {
		    engine.commGate.send([ new CommGateRequest("REQ_REGISTER", [ uEmail.value, uUserName.value, uPassword.value, "", 'Normal'], commGateReg) ]);
		}
	}
	
	/**
	 * Registering new user
	 * Response
	 */
	function commGateReg(pResponse) {
		var comm0 = pResponse[0].getCommandLine();
		var comm1 = pResponse[1].getCommandLine();
		
		if( comm0[2] == 1 && comm1[2] != "FAILURE" ) {
			var aTmp = getStringAsObjectArray(comm1[5]);
			
			engine.cookieManager.set( "remember", "yes" );	
			engine.cookieManager.set( "sId", aTmp["sessionid"]);
			
			init();
			
			engine.dialogManager.add(new Dialog("Örömmel köszöntünk az eNyelviskola.hu hallgatói között!", "alert"));
			
			sessionId = aTmp["sessionid"];
			role =  aTmp["rolename"];
			email = aTmp["email"];
			
			loggedIn = true;
			
			isNewReg = true;
			
			self.setPhase("levelSurvey");
			
			//Profile mentése (Csak nickname és newslater miatt érdekes, lehet később kikerül)
			saveRegisterProfile();
			
			engine.eventManager.invoke(new Event(self, EventManager.EVENT_USER_LOGIN));
			
		} else if( comm1[2] == "FAILURE" && comm1[3] == "EXISTING EMAIL" ) {
			var uEmail = $('registerEmail');
			uEmail.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog("A megadott e-mail cím korábban már regisztrálva lett!<br />Ha új regisztrációt szeretnél létrehozni, adj meg más e-mail címet!", "alert"));
		} else if( comm1[2] == "FAILURE" && comm1[3] == "EXISTING NICKNAME" ) {
			var uUserName = $('loginUsername');
			uUserName.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog("A megadott felhasználónév korábban már regisztrálva lett, adj meg másik felhasználónevet!!", "alert"));
		} else {
			engine.dialogManager.add(new Dialog("Sikertelen regisztráció, próbáld újra!", "alert"));
	    }
	}
	
	/**
	 * Converts DB string to array
	 * @param String Input DB string
	 * @return Converted array
	 * @type Array
	 */
	function getStringAsObjectArray(pString) {
		var res = new Array();
		
		pString = pString.substring(2,pString.length-2);
		pos = pString.indexOf(");(");
		tmp1 = pString.substring(0,pos);
		tmp2 = pString.substring(pos+3);
		
		while(tmp1.length != 0) {
			pos = tmp1.indexOf(";");
			
			if (pos > -1) {
				sKey = tmp1.substring(0, pos);
				tmp1 = tmp1.substring(pos + 1);
			} else {
				sKey = tmp1;
				tmp1 = "";
			}
			
			pos = tmp2.indexOf(";");
			
			if (pos > -1) {
				sValue = tmp2.substring(0, pos);
				tmp2 = tmp2.substring(pos + 1);
			} else {
				sValue = tmp2;
				tmp2 = "";
			}
			
			res[sKey.toLowerCase()] = sValue;
		}
		
		return res;
	}
	
	/**
	 * Request new password for the user
	 */
	this.sendNewPasswd = function() {
		var userName = $('loginUsername');
		var defUserName = 'Felhasználónév:';
		
		// Username check
		if(esuli.staticContent.trimTextInput(userName.value) == '' || userName.value == defUserName) {
			userName.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Add meg a felhasználóneved, vagy az e-mail címed!', 'alert'));
			return;
		}
		
		engine.commGate.send([ new CommGateRequest(
			"ESULI_RENEW_PASSWORD", 
			[userName.value], 
			function(pResponse) {
				var comm0 = pResponse[0].getCommandLine();
				var comm1 = pResponse[1].getCommandLine();

				if( comm0[2] == 1 && comm1[2] != "FAILURE" ) {
					engine.dialogManager.add(new Dialog("Létrehoztunk Neked egy új jelszót, amit elküldtünk e-mailben. Ezzel az új jelszóval be tudsz jelentkezni, utána pedig ha szeretnéd, a Személyes menüpontban megadhatsz egy másik, számodra jobban megjegyezhető jelszót.", "alert"));
				} else if( comm1[2] == "FAILURE" && comm1[3] == "NON_EXISTENT_USER" ) {
					if(userName.value.indexOf('@') != -1) {
						engine.dialogManager.add(new Dialog('Nincs regisztrált felhasználó a megadott e-mail címmel!', 'alert'));
					} else {
						engine.dialogManager.add(new Dialog('Nincs regisztrált felhasználó a megadott felhasználónévvel!', 'alert'));
					}
				}
			}
		) ]);
	}
	
	/**
 	 * Személyes adatok és beállítások mentése
 	 * @param Boolean Called from profile page
 	 */
	this.saveProfile = function(formProfilePage) {
		if (formProfilePage) {
			livingAddress.setSurname($('surname').value);
			livingAddress.setForename($('forename').value);
			livingAddress.setCity($('living_city').value);
			livingAddress.setZip($('living_pbox').value);
			livingAddress.setAddress($('living_street').value);
			deliveryAddress.setName($('delivery_name').value);
			deliveryAddress.setCity($('delivery_city').value);
			deliveryAddress.setZip($('delivery_pbox').value);
			deliveryAddress.setAddress($('delivery_street').value);
			billingAddress.setName($('billing_name').value);
			billingAddress.setCity($('billing_city').value);
			billingAddress.setZip($('billing_pbox').value);
			billingAddress.setAddress($('billing_street').value);
			phone = $('phone').value;
			newsLetter = $('newsLetter').checked ? true : false;
			var saveNickname = null;
			if($('nickname')) {
				var userName = $('nickname');
				userName.className = 'normalTextInput';
				if(esuli.staticContent.trimTextInput(userName.value) == '') {
					userName.className = 'normalTextInputError';
					engine.dialogManager.add(new Dialog('Nem adtad meg a felhasználónevet!', 'alert'));
					return;
				} else if(!esuli.staticContent.chechUsername(userName.value)) {
					userName.className = 'normalTextInputError';
					engine.dialogManager.add(new Dialog('A megadott felhasználónév formátuma nem megfelelő!<br /><br class="halfLine" /><span class="grayNormal">A felhasználónév kizárólag a magyar abc betűiből és számokból állhat, szóközt és speciális karaktereket nem tartalmazhat. Minimális hossza 5 karakter!</span>', 'alert'));			
					return;
				}
				saveNickname = userName.value;
			}
    	}
		
		var command = new CommGateRequest(
			'REQ_ACCESS',
			[ 'ESULI_SET_PROFILE' ],
			function(pResponse) {
				var comm0 = pResponse[0].getCommandLine();
				if( comm0[2] == 1 ) {
					var comm1 = pResponse[0].getDataAsArray();
					if ( comm1[0][1] == "FAILURE" && comm1[0][2] == "EXISTING NICKNAME" ) {
						var userName = $('nickname');
						userName.className = 'normalTextInputError';
						engine.dialogManager.add(new Dialog("A megadott felhasználónév korábban már regisztrálva lett, adj meg másik felhasználónevet!!", "alert"));
					} else {
						if(saveNickname != null ) {
							nickname = saveNickname;
							engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
						}
						if (formProfilePage) {
							engine.dialogManager.add(new Dialog("Adataidat elmentettük. Köszönjük!", "alert", [ null, null ,null ]));
						}
					}
				} else {
					engine.dialogManager.add(new Dialog("Probléma a feldolgozás során, kérlek próbáld újra!", "alert"));
				}			
			});
        
		command.addDataLevel([ [
			'SURNAME',
			'FORENAME',
			'LIVING_CITY',
			'LIVING_PBOX',
			'LIVING_STREET',
			'DELIVERY_NAME',
			'DELIVERY_CITY',
			'DELIVERY_PBOX',
			'DELIVERY_STREET',
			'BILLING_NAME',
			'BILLING_CITY',
			'BILLING_PBOX',
			'BILLING_STREET',
			'PHONE',
			'NEWS',
			'NICKNAME'
		], [
			livingAddress.getSurname(),
			livingAddress.getForename(),
			livingAddress.getCity(),
			livingAddress.getZip(),
			livingAddress.getAddress(),
			deliveryAddress.getName(),
			deliveryAddress.getCity(),
			deliveryAddress.getZip(),
			deliveryAddress.getAddress(),
			billingAddress.getName(),
			billingAddress.getCity(),
			billingAddress.getZip(),
			billingAddress.getAddress(),
			phone,
			newsLetter,
			saveNickname
		] ] );
		
		engine.commGate.sendWithSession([ command ]);
	}
	
	/**
	 * Update user profile
	 */
	this.updateProfile = function() {
		livingAddress.setSurname( $('surname') ? $('surname').value : livingAddress.getSurname() );
		livingAddress.setForename( $('forename') ? $('forename').value : livingAddress.getForename() );
		livingAddress.setCity( $('living_city') ? $('living_city').value : livingAddress.getCity() );
		livingAddress.setZip( $('living_pbox') ? $('living_pbox').value : livingAddress.getZip() );
		livingAddress.setAddress( $('living_street') ? $('living_street').value : livingAddress.getAddress() );
		
		deliveryAddress.setName( $('delivery_name') ? $('delivery_name').value : deliveryAddress.getName() );
		deliveryAddress.setCity( $('delivery_city') ? $('delivery_city').value : deliveryAddress.getCity() );
		deliveryAddress.setZip( $('delivery_pbox') ? $('delivery_pbox').value : deliveryAddress.getZip() );
		deliveryAddress.setAddress( $('delivery_street') ? $('delivery_street').value : deliveryAddress.getAddress() );
		
		billingAddress.setName( $('billing_name') ? $('billing_name').value : billingAddress.getName() );
		billingAddress.setCity( $('billing_city') ? $('billing_city').value : billingAddress.getCity() );
		billingAddress.setZip( $('billing_pbox') ? $('billing_pbox').value : billingAddress.getZip() );
		billingAddress.setAddress( $('billing_street') ? $('billing_street').value : billingAddress.getAddress() );
		
		phone = $('phone') ? $('phone').value : this.getPhone() ;
		
		newsLetter = this.getNewsLetter();
		
		var command = new CommGateRequest(
			'REQ_ACCESS',
			[ 'ESULI_SET_PROFILE' ],
			null);

		command.addDataLevel([ [
			'SURNAME',
			'FORENAME',
			'LIVING_CITY',
			'LIVING_PBOX',
			'LIVING_STREET',
			'DELIVERY_NAME',
			'DELIVERY_CITY',
			'DELIVERY_PBOX',
			'DELIVERY_STREET',
			'BILLING_NAME',
			'BILLING_CITY',
			'BILLING_PBOX',
			'BILLING_STREET',
			'PHONE',
			'NEWS',
			'NICKNAME'
		], [
			livingAddress.getSurname(),
			livingAddress.getForename(),
			livingAddress.getCity(),
			livingAddress.getZip(),
			livingAddress.getAddress(),
			deliveryAddress.getName(),
			deliveryAddress.getCity(),
			deliveryAddress.getZip(),
			deliveryAddress.getAddress(),
			billingAddress.getName(),
			billingAddress.getCity(),
			billingAddress.getZip(),
			billingAddress.getAddress(),
			phone,
			newsLetter,
			null
		] ] );
		
		engine.commGate.sendWithSession([ command ]);
	}
    
    /**
	 * morr1337
     * Személyes adatok és beállítások mentése regisztrációkor
     */
    function saveRegisterProfile() {
	var command = new CommGateRequest(
	    'REQ_ACCESS',
	    [ 'ESULI_SET_PROFILE' ],
	    function(response) {
			loadProfile();
	    });
	    
	command.addDataLevel([ [
	    'SURNAME',
	    'FORENAME',
	    'LIVING_CITY',
	    'LIVING_PBOX',
	    'LIVING_STREET',
	    'DELIVERY_NAME',
	    'DELIVERY_CITY',
	    'DELIVERY_PBOX',
	    'DELIVERY_STREET',
	    'BILLING_NAME',
	    'BILLING_CITY',
	    'BILLING_PBOX',
	    'BILLING_STREET',
	    'PHONE',
	    'NEWS',
		'NICKNAME'
	], [
	    livingAddress.getSurname(),
	    livingAddress.getForename(),
	    "",
	    "",
	    "",
	    "", "", "", "", "", "", "", "",
		esuli.user.getPhone(),
		esuli.user.getNewsLetter(),
		esuli.user.getNickname()
	] ] );
	
	engine.commGate.sendWithSession([ command ]);
    }
        
    /**
	 * morr1337
     * Személyes adatok és beállítások lekérdezése
     */
    function loadProfile() {
        glLog.fireBugLog("group", "", "", "Call loadProfile()");
		var command = new CommGateRequest ( 'REQ_ACCESS', [ 'ESULI_GET_PROFILE' ], commGateLoadProfile );
		command.addDataLevel ( [['INTERFACE', '', '' ], [ engine.cookieManager.get("interface"), '', '']] );

		engine.commGate.sendWithSession([ command ]);
		glLog.fireBugLog("log", "User.js", "commgateLogin()", "loading profile from DB");
		glLog.fireBugLog("groupEnd", "", "", "End loadProfile()");
    }
	
    function commGateLoadProfile(pResponse) {
	    var cmd;
	    var data;

	    for (var i = 0; i < pResponse.length; i++) {
			cmd = pResponse[i].getCommandLine();
			if ((cmd[1] == 'RES_DATA')) {
		    	data = pResponse[i].getDataAsObjectArray();
		    	data = data[0];
		    	break;
			}
	    }
	    
	    if (! check(data)) {
			return;
	    }
	    
		livingAddress.setSurname(data.surname);
		livingAddress.setForename(data.forename);
		livingAddress.setCity(data.living_city);
		livingAddress.setZip(data.living_pbox);
		livingAddress.setAddress(data.living_street);
        deliveryAddress.setName(data.delivery_name);		
		deliveryAddress.setCity(data.delivery_city);
		deliveryAddress.setZip(data.delivery_pbox);
		deliveryAddress.setAddress(data.delivery_street);
        billingAddress.setName(data.billing_name);
        billingAddress.setCity(data.billing_city);
        billingAddress.setZip(data.billing_pbox);
        billingAddress.setAddress(data.billing_street);
		tempAddress.setSurname(data.surname);
		tempAddress.setForename(data.forename);
		tempAddress.setCity(data.living_city);
		tempAddress.setZip(data.living_pbox);
		tempAddress.setAddress(data.living_street);
		phone = data.phone;
		credit = data.credit;
		
		if( data.phase && ( data.phase != "" && data.phase != "undefined" ) ) {
			self.setPhase(data.phase);
		}
		
		if( data.level && ( data.level != "" && data.level != "undefined" ) ) {
			self.getLevelSurvey("home").setLevel("", data.level);
		}
		
		if( data.news && ( data.news != "" && data.news != "0" && data.news != "undefined" ) ) {
			newsLetter = true;
		}
/*		
		if (  data.ticket_start  && data.ticket_start != "" ) {
			monthlyTicketStart =  new Date (data.ticket_start.substr(0,4), data.ticket_start.substr(5,2) - 1,  data.ticket_start.substr(8,2));
            monthlyTicketType =  data.ticket_type;
			//lejárt már a bérlete?
			var now = new Date();
			var delta =  ( now - monthlyTicketStart )  / 86400000;
			if ( delta > 30 ) {
				esuli.user.monthlyTicketOver = true;
			 	engine.dialogManager.add(new Dialog("A bérleted sajnos már lejárt, ezért újabb feladatokat megoldani már nem fogsz tudni. A megoldottakat természetesen továbbra is megnézheted.", "alert" ));
			}
		}
	*/	
		if (  data.ticket_end  && data.ticket_end != "" ) {
			monthlyTicketEnd =  new Date (data.ticket_end.substr(0,4), data.ticket_end.substr(5,2) - 1,  data.ticket_end.substr(8,2));
            monthlyTicketType =  data.ticket_type;
			//lejárt már a bérlete?
			var now = new Date();
			if ( now > monthlyTicketEnd ) {
				esuli.user.monthlyTicketOver = true;
			 	engine.dialogManager.add(new Dialog("A bérleted sajnos már lejárt, ezért újabb feladatokat megoldani már nem fogsz tudni. A megoldottakat természetesen továbbra is megnézheted.", "alert" ));
			}
		}

		profilLoaded = true;	
		//engine.eventManager.invoke(new Event(self, EventManager.EVENT_PROFILE_LOADED));
		esuli.user.listenProfileLoaded();
	}
	
	/**
	 * Jelszó mentése
	 */
	this.setPassword = function() {
		var oldPassword = $('old_password');
		var newPassword = $('password');
		var newPasswordAgain = $('password_2');
		
		if(!oldPassword || !newPassword || !newPasswordAgain) {
			return;
		}
		
		oldPassword.className = 'normalTextInput';
		newPassword.className = 'normalTextInput';
		newPasswordAgain.className = 'normalTextInput';
		
		// Password check
		if(esuli.staticContent.trimTextInput(oldPassword.value) == '') {
			oldPassword.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Nem adtad meg a régi jelszót!', 'alert'));
			return;
		} else if(esuli.staticContent.trimTextInput(newPassword.value) == '') {
			newPassword.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('Nem adtad meg az új jelszót!', 'alert'));
			return;
		} else if(!esuli.staticContent.chechPassword(newPassword.value)) {
			newPassword.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('A megadott jelszó formátuma nem megfelelő!<br /><br class="halfLine" /><span class="grayNormal">A jelszó kizárólag a magyar abc betűiből és számokból állhat, szóközt és speciális karaktereket nem tartalmazhat. Minimális hossza 5 karakter!</span>', 'alert'));
			return;
		} else if(esuli.staticContent.trimTextInput(newPasswordAgain.value) == '' || esuli.staticContent.trimTextInput(newPassword.value) != esuli.staticContent.trimTextInput(newPasswordAgain.value)) {
			newPassword.className = 'normalTextInputError';
			newPasswordAgain.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog('A két jelszó nem egyezik!', 'alert'));
			return;
		}
		
		var command = new CommGateRequest(
			'REQ_ACCESS',
			[ 'ESULI_SET_PASSWORD' ],
			function(pResponse) {
				var comm0 = pResponse[0].getCommandLine();
		        if( comm0[2] == 1 ) {
					var comm1 = pResponse[0].getDataAsArray();
					oldPassword.value = '';
					newPassword.value = '';
					newPasswordAgain.value = '';
					engine.dialogManager.add(new Dialog(comm1[0][2], "alert"));
				}
				else {
					engine.dialogManager.add(new Dialog("Probléma a feldolgozás során, kérlek próbáld újra!", "alert"));
				}
			});
		
		command.addDataLevel ( [['OLD', 'NEW', 'NEW2' ], [ oldPassword.value, newPassword.value, newPasswordAgain.value ]] );
		
		engine.commGate.sendWithSession([ command ]);
		//engine.dialogManager.add(new Dialog("Jelszavadat elmentettük. Köszönjük!", "alert"));
    }
		
	/**
	 * Store the address for copy
	 */
	this.saveTempAddress = function() {
		tempAddress.setSurname($('surname').value);
		tempAddress.setForename($('forename').value);
		tempAddress.setCity($('living_city').value);
		tempAddress.setZip($('living_pbox').value);
		tempAddress.setAddress($('living_street').value);
		
		this.setCopyAddress( true );
	}
	
	/**
 	 * Copy address if needed
	 */
	this.setCopyAddress = function( pKeyUp ) {
		var copy = $("profilCopyAdresses").checked ? true : false;
		
		if( !copy && pKeyUp ) {
			return;
		}
		
		$('delivery_name').value = copy ? tempAddress.getSurname() + ' ' + tempAddress.getForename() : deliveryAddress.getName();
		$('delivery_city').value = copy ? tempAddress.getCity() : deliveryAddress.getCity();
		$('delivery_pbox').value = copy ? tempAddress.getZip() : deliveryAddress.getZip();
		$('delivery_street').value = copy ? tempAddress.getAddress() : deliveryAddress.getAddress();
		
		$('billing_name').value = copy ? tempAddress.getSurname() + ' ' + tempAddress.getForename() : billingAddress.getName();
		$('billing_city').value = copy ? tempAddress.getCity() : billingAddress.getCity();
		$('billing_pbox').value = copy ? tempAddress.getZip() : billingAddress.getZip();
		$('billing_street').value = copy ? tempAddress.getAddress() : billingAddress.getAddress();
	}
	
	/**
	 * After user profil loaded, user can use the site
	 * Manage smarty pages
	 */
	this.listenProfileLoaded = function(event) {
		engine.log.fireBugLog('log', 'User.js', 'listenProfileLoaded', 'loaded');
		
		var avEmail = "";
		var allowedInEmail = /^[a-zA-Z0-9\.\@]$/;
		
		for ( var i = 0; i < esuli.user.getEmail().length; i++ ) {
			if ( esuli.user.getEmail().charAt(i).match( allowedInEmail ) ) {
				avEmail += esuli.user.getEmail().charAt(i);
			} else {
				continue;
			}
		}
		
		if(esuli.user.getLivingAddress().getForename()) {
			engine.cookieManager.set("avName", esuli.user.getLivingAddress().getSurname() + " " + esuli.user.getLivingAddress().getForename() + " " + avEmail);
		} else {
			engine.cookieManager.set("avName", avEmail);
		}
		
		if(esuli.user.isNewReg()) {
			esuli.tab.showTabMenu( 'Main', true );
			esuli.tab.changeTabAndSubMenu( "Asztal", 0 );
			esuli.tab.setActiveSubMenu(0);
		} else {
			// smartyException.js
			var reload = esuli.staticContent.getReload();
			if( reload.length > 0 && reload != "" ) {
				var allowed = true;
				for( var i = 0; i < disallowAfterLogin.length; i++ ) {
					if( reload.indexOf( disallowAfterLogin[i] ) != -1 ) {
						allowed = false;
						break;
					}
				}
				
				if( !allowed || isAgentPage ) {
					esuli.tab.showTabMenu( 'Main', true );
					esuli.tab.changeTabAndSubMenu( "Asztal", 0 );
					esuli.tab.setActiveSubMenu(0);
				} else if (reload == "sales") {
					esuli.sales.init();
				}
			} else {
				esuli.tab.showTabMenu( 'Main', true );
				esuli.tab.changeTabAndSubMenu( "Asztal", 0 );
				esuli.tab.setActiveSubMenu(0);
			}
		}
		
		$('logout').style.display = 'block';
	}

	/**
	 * Returns requested page
	 * @param Object Page request
	 * @return Requested page
	 * @type Object
	 */
	this.getPage = function(pageRequest) {
		if (! check(pageRequest)) {
			//TODO: Log error
			return;
		}
		
		var page = { leftWidth: '0px', centerWidth: '743px', rightWidth: '225px', left: "", center: "", right: "" };
		
		switch (pageRequest.get("page")) {
			
			case "profile":
				page.leftWidth = '372px';
				page.centerWidth = '371px';
				page.rightWidth = '225px';
				page.left = engine.templateManager.getTemplate("profil_szemelyesadatok").process({});
				page.leftBottom = engine.templateManager.getTemplate("profil_jelszo").process({});
				page.extend(esuli.shopping.getPage(pageRequest));
				break;

			case "levelSurvey":
				if( !esuli.user.getLevelSurvey("normal").isLoaded(pageRequest) ) {
					page.center = engine.templateManager.getTemplate("contentspin").process({});
				} else {
					page.extend(esuli.user.getLevelSurvey("normal").getPage(pageRequest));
				}
				break;
			
			default:
				//TODO: Log error
				return;
		}
		
		lastPage = pageRequest;
		
		return page;
	}
	
	/**
	 * Returns last visited page
	 * @return Last visited page
	 * @type Object
	 */
	this.getLastPage = function() {
		self.getPage(lastPage);
	}
	
	//automatikus loginról értesülnünk kell, hogy lekérjünk beállítsunk bizonyos dolgokat
	engine.eventManager.addListener(EventManager.EVENT_USER_PRELOGIN, self);
	
	//engine.eventManager.addListener(EventManager.EVENT_PROFILE_LOADED, self);
}
/**
 * Course object in Workbook module
 * @param String Level
 * @param String Type
 * @author Horvath 'Koko' Kornel
 */
function WorkbookCourse(courseLevel, courseType) {
	
	/**
	 * Type constants
	 * @type Array
	 */
	var TYPES = [
		{ name: "A típusú", title: "Nyelvvizsgára felkészítő kurzus", price: 87000 },
		{ name: "B típusú", title: "Nyelvvizsgára felkészítő kurzus", price: 45000 },
		{ name: "C típusú", title: "Nyelvvizsgára felkészítő kurzus", price: 117000 },
		{ name: "Írásbeli típusú", title: "15 leckés kurzus", price: 22500 },
		{ name: "Szóbeli típusú", title: "15 leckés kurzus", price: 43500 },
		{ name: "Kombinált típusú", title: "15 leckés kurzus", price: 58500 },
		{ name: "Társalgás típusú", title: "15 leckés kurzus", price: 36000 }
	];
	
	/**
	 * Level
	 * @type String
	 */
	var level = courseLevel;
	
	/**
	 * Type
	 * @type String
	 */
	var type = courseType;
	
	/**
	 * Title
	 * @type String
	 */
	var title = "";
	
	/**
	 * Price
	 * @type Number
	 */
	var price = 0;
	
	/**
	 * Sets level
	 * @param String Level
	 */
	this.setLevel = function(courseLevel) {
		level = courseLevel;
	}
	
	/**
	 * Returns level
	 * @return Level
	 * @type String
	 */
	this.getLevel = function() {
		return level;
	}
	
	/**
	 * Sets type
	 * @param String Type
	 */
	this.setType = function(courseType) {
		type = courseType;
	}
	
	/**
	 * Returns type
	 * @return Type
	 * @type String
	 */
	this.getType = function() {
		return type;
	}
	
	/**
	 * Sets title
	 * @param String Title
	 */
	this.setTitle = function(courseTitle) {
		title = courseTitle;
	}
	
	/**
	 * Returns title
	 * @return Title
	 * @type String
	 */
	this.getTitle = function() {
		return title;
	}
	
	/**
	 * Sets price
	 * @param Number Price
	 */
	this.setPrice = function(coursePrice) {
		price = coursePrice;
	}
	
	/**
	 * Returns price
	 * @return Price
	 * @type Number
	 */
	this.getPrice = function() {
		return price;
	}
	
	//Initialize
	for (var i = 0; i < TYPES.length; i++) {
		if (type == TYPES[i].name) {
			title = TYPES[i].title;
			price = TYPES[i].price;
			break;
		}
	}
	
}
/**
 * Exercise object in workbook.
 * @param WorkbookLesson Parent lesson
 * @param Number Id
 * @param Number Type
 * @param Number Type order
 * @param String Color
 * @param String Status
 * @param String File name
 * @param String Title
 * @param Number Result percent
 * @constructor
 * @author Gábor, Horvath 'Koko' Kornel
 */
function WorkbookExercise(exerciseLesson, exerciseId, exerciseType, exerciseTypeOrder, exerciseColor, exerciseStatus, exerciseFileName, exerciseTitle, exerciseResultPercent, exerciseComment) {

	/**
	 * Parent lesson
	 * @type WorkbookLesson
	 */
	var parent = exerciseLesson;

	/**
	 * Id
	 * @type Number
	 */
	var id = exerciseId;
	
	/**
	 * Type
	 * @type Number
	 */
	var type = exerciseType;
	
	/**
	 * Type order
	 * @type Number
	 */
	var typeOrder = exerciseTypeOrder;
	
	/**
	 * Color
	 * @type String
	 */
	var color = exerciseColor;
	
	/**
	 * File name
	 * @type String
	 */
	var fileName = exerciseFileName;
	
	/**
	 * Title
	 * @type String
	 */
	var title = exerciseTitle;
	
	/**
	 * Has extra
	 * @type String
	 */
	var extra;
	
	/**
	 * Status
	 * @type String
	 */
	var status = exerciseStatus;
	
	/**
	 * Result score
	 * @type Number
	 */
	var resultScore = null;
	
	/**
	 * Result percent
	 * @type Number
	 */
	var resultPercent = exerciseResultPercent;
	
	/**
	 * Page HTML
	 * @type String
	 */
	var html;
	
	/**
	 * Is loaded
	 * @type Boolean
	 */
	var loaded = false;
	
	/**
	 * Solved times
	 * @type Number
	 */
	var solvedCount = 0;
	
	/**
	 * Map containing records
	 * @type Map
	 */
	var records = new Map();
	
	/**
	 * Map containing question objects
	 * @type Map
	 */
	var questions = new Map();
	
    /**
     * String containing teacher comments on homework
     * @type String
     */
    var comment = exerciseComment;

	/**
	 * Are stories loadet to reading
	 * @type Boolean
	 */
	var storiesLoaded = false;

	/**
	 * Is User observations loaded
	 * @type Boolean
	 */
	var observationsLoaded = false;
	
	/**
	 * Stories for reading
	 * @type Array
	 */
	var stories = new Array();
	
	/**
	 * Story contents for reading
	 * @type Array
	 */
	var story = new Array();
	
	/**
	 * Current opened story
	 * @type Number
	 */
	var currentStory = null;
	
	/**
	 * Are words loaded to words
	 * @type Boolean
	 */
	var wordsLoaded = false;
	
	/**
	 * User added words
	 * @type Array
	 */
	var words = new Array();
	
	/**
	 * Is community page opened
	 * @type Boolean
	 */
	var communityPageOpened = false;
	
	/**
	 * User Observations
	 * @type Array
	 */
	var observations = new Array();
	
	/**
	 * Pointer to this
	 * @type WorkbookExercise
	 */
	var self = this;
	
	/**
	 * Returns sequence inside the type
	 * @return Sequence in type
	 * @type Number
	 */
	this.getTypeOrder = function() {
		return typeOrder;
	}
	
	/**
	 * Sets sequence inside the type
	 * @param Number Sequence in type
	 */
	this.setTypeOrder = function(exerciseTypeOrder) {
		typeOrder = exerciseTypeOrder;
	}
	
	/**
	 * Returns the file name of the given record
	 * @param String Name of record
	 * @return File name of record
	 * @type String
	 */
	this.getRecordFile = function(recordName) {
		return records.get(recordName);
	}
	
	/**
	 * Sets file name of the given record
	 * @param String Name of record
	 * @param String File name of record
	 */
	this.setRecordFile = function(recordName, recordFile) {
		records.put(recordName, recordFile);
	}
	
	/**
	 * Returns id
	 * @return Id
	 * @type Number
	 */
	this.getId = function() {
		return id;
	}
	
	/**
	 * Sets id
	 * @param Number Id
	 */
	this.setId = function(exerciseId) {
		id = exerciseId;
	}
	
	/**
	 * Returns file path
	 * @return File path
	 * @type String
	 */
	function getPath() {
		return BASE_URL + "lessons/" + parent.getParent().getId() + "/" + parent.getName() + "/" + fileName;
	}
	
	/**
	 * Returns parent lesson
	 * @return Parent lesson
	 * @type WorkbookLesson
	 */
	this.getParent = function() {
		return parent;
	}
	
	/**
	 * Sets parent lesson
	 * @param WorkbookLesson Parent lesson
	 */
	this.setParent = function(exerciseParent) {
		parent = exerciseParent;
	}
	
	/**
	 * Returns result score
	 * @return Result score
	 * @type Number
	 */
	this.getResultScore = function() {
		return resultScore;
	}
	
	/**
	 * Sets result score
	 * @param Number Result score
	 */
	this.setResultScore = function(exerciseResultScore) {
		resultScore = exerciseResultScore;
	}
	
	/**
	 * Returns result percent
	 * @return Result percent
	 * @type Number
	 */
	this.getResultPercent = function() {
		return resultPercent;
	}
	
	/**
	 * Sets result percent
	 * @param Number Result percent
	 */
	this.setResultPercent = function(exerciseResultPercent) {
		resultPercent = exerciseResultPercent;
	}
	
	/**
	 * Returns map contains question objects
	 * @return Map contains question objects
	 * @type Map
	 */
	this.getQuestions = function() {
		return questions;
	}
	
	/**
	 * Returns solved count
	 * @return Solved count
	 * @type Number
	 */
	this.getSolvedCount = function() {
		return solvedCount;
	}
	
	/**
	 * Returns HTML part
	 * @return HTML part
	 * @type String
	 */
	this.getHtml = function() {
		return html;
	}
	
	/**
	 * Returns extra HTML part
	 * @return extra HTML part
	 * @type String
	 */
	this.getExtra = function() {
		return extra;
	}
	
	/**
	 * Returns status
	 * @return Status
	 * @type String
	 */
	this.getStatus = function() {
		return status;
	}
	
	/**
	 * Sets status
	 * @param String Status
	 */
	this.setStatus = function(exerciseStatus) {
		status = exerciseStatus;
	}

    /**
     * Returns exercise comment
     * @return Comment
     * @type String
     */
    this.getComment = function() {
        return comment;
    }

    /**
     * Sets comment
     * @param String Comment
     */
    this.setComment = function(exerciseComment) {
        comment = exerciseComment;
    }

	/**
	 * Set stories not loaded
	 */
	this.setStoriesNotLoaded = function() {
		storiesLoaded = false;
	}
	
	/**
	 * Set words not loaded
	 */
	this.setWordsNotLoaded = function() {
		wordsLoaded = false;
	}
	
	/**
	 * Returns type
	 * @return Type
	 * @type Number
	 */
	this.getType = function() {
		return type;
	}
	
	/**
	 * Sets type
	 * @param Number Type
	 */
	this.setType = function(exerciseType) {
		type = exerciseType;
	}
	
	/**
	 * Return title
	 * @return Title
	 * @type String
	 */
	this.getTitle = function() {
		return title;
	}
	
	/**
	 * Sets title
	 * @param String Title
	 */
	this.setTitle = function(exerciseTitle) {
		title = exerciseTitle;
	}
	
	/**
	 * Return filename
	 * @return filename
	 * @type String
	 */
	this.getFileName = function() {
		return fileName;
	}

	
	/**
	 * Returns true if exercise is green
	 * @return True if green
	 * @type Boolean
	 */
	this.isBlue = function() {
		return (color == "blue" ? true : false);
	}
	
	/**
	 * Returns true if exercise is yellow
	 * @return True if yellow
	 * @type Boolean
	 */
	this.isYellow = function() {
		return (color == "yellow" ? true : false);
	}
	
	/**
	 * Returns true if exercise is orange
	 * @return True if orange
	 * @type Boolean
	 */
	this.isBrown = function() {
		return (color == "brown" ? true : false);
	}
	
	/**
	 * Returns color
	 * @return Color
	 * @type String
	 */
	this.getColor = function() {
		return color;
	}
	
	/**
	 * Sets color
	 * @param String color
	 */
	this.setColor = function(exerciseColor) {
		color = exerciseColor;
	}
	
	/**
	 * Is community page opened
	 * @return Is community page opened
	 * @type Boolean
	 */
	this.isCommunityPageOpened = function() {
		return communityPageOpened;
	}
	
	/**
	 * Set community page status
	 * @param Opened or not
	 * @type Boolean
	 */
	this.setCommunityPageStatus = function(pOpened) {
		communityPageOpened = !pOpened ? false : true;
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
	}
	
	/**
	 * Find where is user answer bad
	 */
	this.whereIsBad = function( userAnswer, inputValue ) {
		var ret = '';
		var find = false;
		
		if( userAnswer == "" ) {
			return '</span><span class="LessonTextboxBad">' + userAnswer;
		}
		
		for ( var i = 0; i < userAnswer.length; i++ ) {
			if ( ( userAnswer.charAt(i) != inputValue.charAt(i) ) && !find ) {
				ret += '</span><span class="LessonTextboxBad">' + userAnswer.charAt(i);
				find = true;
			} else {
				ret += userAnswer.charAt(i);
			}
		}
		
		return ret;
	}
	
	/**
	 * Listens for user login event
	 * @param Event Event of login
	 */
	this.listenUserLogin = function(event) {
		if (status == "Megoldott") {
			sendSolve();
		}
	}
	
	/**
	 * Clears answers
	 */
    this.clear = function() {
    	if (type == WorkbookExerciseType.TYPE_HOMEWORK) {
    		return;
    	}
    	
    	solvedCount++;
    	
    	if (type == WorkbookExerciseType.TYPE_TEST) {
    		return;
    	}
    	
   	    status = "Megoldandó";
	    resultScore = null;
	    resultPercent = null;
   	    
		questions.map(function(question) {
			question.clear();
		});
		
		if (esuli.user.isLoggedIn()) {
			var comm = new CommGateRequest("REQ_ACCESS", [ "ESULI_CLEAR_PACKAGE_SOLUTIONS" ]);
			comm.addDataLevel([ [ "PACKAGEID" ], [ parent.getId() ] ]);
			engine.commGate.sendWithSession([ comm ]);
		}
    }
	
	/**
	 * Returns true is exercise is solved
	 * @return True is exercise is solved
	 * @type Boolean
	 */
	this.isSolved = function() {
		return (status == "Megoldott" ? true : false);
	}
	
	/**
	 * Returns true is exercise is corrected
	 * @return True is exercise is corrected
	 * @type Boolean
	 */
	this.isCorrected = function() {
		return (status == "Javított" ? true : false);
	}
	
	/**
	 * Returns true if exercise is buyable
	 * @return True if exercise is buyable
	 * @type Boolean
	 */
	this.isBuyable = function() {
		return (status == "Megvásárolható" ? true : false);
	}
	
	/**
	 * Return true if the exercise is fully completed
	 * @return True if the exercise is fully completed
	 * @type Boolean
	 */
	this.isCompleted = function() {
		var it = questions.keys().iterator()
		var names = new Array();
		var completeds = new Array();
		var inputs;
		var element;
		
		while (it.hasNext()) {
			inputs = document.getElementsByName(it.next());
			
			for (var j = 0; j < inputs.length; j++) {
				names.push(inputs[j].name);
				
				element = inputs[j];
				
				if (
					(element.tagName == "INPUT" && (element.type == "text" || element.type == "password") && element.value != "") ||
					(element.tagName == "INPUT" && element.type == "radio" && element.checked) ||
					(element.tagName == "TEXTAREA" && element.value != "") ||
    				(element.tagName == "INPUT" && element.type == "checkbox" )
				) {
					completeds.push(inputs[j].name);
				}
			}
		}
		
		for (var i = 0; i < names.length; i++) {
			if (completeds.indexOf(names[i]) < 0) {
				return false;
			}
		}
		
		return true;
	}
	
	/**
	 * Parses input HTML for the questions and the right answers
	 * @param String Input HTML
	 */
	function parse(exerciseHTML) {
		questions.map(function(question) {
			question.clear();
		});
		
		html = "";
		
		var tagStart = 0;
		var tagEnd = 0;
		var inputName = "";
		var inputValue = "";
		var inputType = "";
		var remainder = exerciseHTML;
		var htmlTag = remainder.match(/<[^>]*>/);
		
		while (htmlTag) {
			//actual HTML tag
			htmlTag = String(htmlTag);
			
			//start & and of HTML tag
			tagStart = remainder.indexOf(htmlTag);
			tagEnd = tagStart + htmlTag.length;
			
			//name of HTML tag
			inputName = htmlTag.match(/name=[^ >]*/i);
			if (inputName) {
				inputName = String(inputName).replace(/name=/i, "");
				inputName = String(inputName).replace(/"/g, "");
			}
			
			//value of HTML tag
			inputValue = htmlTag.match(/value="[^">]*"/i);
			if (inputValue) {
				inputValue = String(inputValue).replace(/value=/i, "");
				inputValue = String(inputValue).replace(/"/g, "");
			}
			
			//input tags
			if (htmlTag.indexOf("<input") == 0 && inputName && inputValue) {
				//add keylogging
				htmlTag = htmlTag.replace(/<input/i, "<input onkeyup=\"esuli.workbook.getLevel('" + parent.getParent().getId() + "').getLesson(" + parent.getId() + ").getExercise(" + id + ").getQuestions().get('" + inputName + "').setUserAnswer();\" onclick=\"esuli.workbook.getLevel('" + parent.getParent().getId() + "').getLesson(" + parent.getId() + ").getExercise(" + id + ").getQuestions().get('" + inputName + "').setUserAnswer();\"");
				
				//type of input tag
				inputType = htmlTag.match(/type="?[^">]*"?/i);
				if (inputType) {
					inputType = String(inputType).replace(/type=/i, "");
					inputType = String(inputType).replace(/"/g, "");
				} else {
					inputType = "text";
				}
				
				switch (inputType) {
					
					//input radio
					case "radio":
						//this is the right radio button
						if (htmlTag.match(/checked/i)) {
							questions.put(inputName, new WorkbookExerciseQuestion(inputName, WorkbookExerciseQuestion.TYPE_RADIO, inputValue));
							
							htmlTag = htmlTag.replace(/checked="checked"/gi, "");
							htmlTag = htmlTag.replace(/checked/gi, "");
						}
						
						//add user answer
						htmlTag = htmlTag.replace(/<input/i, "<input {if exercise.getQuestions().get('" + inputName + "').getUserAnswer() == '" + inputValue + "'} checked=\"checked\"{/if}");
						
						//add solution
						var arVersion = navigator.appVersion.split("MSIE");
						var version = parseFloat(arVersion[1]);
						
						var iePNGBugSpan = "";
						var iePNGBugSpanOkSelected = "";
						var iePNGBugSpanBad = "";
						var iePNGBugSpanBadSelected = "";
						var iePNGBugImg = "";
						if ((version >= 5.5) && (document.body.filters)) {
							var begin = " style=\"vertical-align:middle; display:inline-block; width:18px; height:18px; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader (src='images/1_5/workbook/";
							var end = "', sizingMethod='scale');\"";
							iePNGBugSpan = begin + "radio.png" + end;
							iePNGBugSpanOkSelected = begin + "radio_ok_selected.png" + end;
							iePNGBugSpanBad = begin + "radio_bad.png" + end;
							iePNGBugSpanBadSelected = begin + "radio_bad_selected.png" + end;
							iePNGBugImg = " style=\"display: none;\"";
						}
						
						htmlTag = "{if (exercise.isSolved() || exercise.isCorrected())}<span class=\"LessonRadioImg\"{if exercise.getQuestions().get('" + inputName + "').getRightAnswer() == '" + inputValue + "'}{if exercise.getQuestions().get('" + inputName + "').getUserAnswer() == '" + inputValue + "'}" + iePNGBugSpanOkSelected + "><img width=\"18\" height=\"18\"" + iePNGBugImg + " src=\"images/1_5/workbook/radio_ok_selected.png{else}" + iePNGBugSpanBad + "><img width=\"18\" height=\"18\"" + iePNGBugImg + " src=\"images/1_5/workbook/radio_bad.png{/if}{else}{if exercise.getQuestions().get('" + inputName + "').getUserAnswer() == '" + inputValue + "'}" + iePNGBugSpanBadSelected + "><img width=\"18\" height=\"18\"" + iePNGBugImg + " src=\"images/1_5/workbook/radio_bad_selected.png{else}" + iePNGBugSpan + "><img width=\"18\" height=\"18\"" + iePNGBugImg + " src=\"images/1_5/workbook/radio.png{/if}{/if}\" /></span>{else}" + htmlTag + "{/if}";
						
						break;
					
					//input checkbox
					case "checkbox":
						//this is the right checkbox
						if (htmlTag.match(/checked/i)) {
							questions.put(inputName, new WorkbookExerciseQuestion(inputName, WorkbookExerciseQuestion.TYPE_CHECKBOX, inputValue));
							
							htmlTag = htmlTag.replace(/checked="checked"/gi, "");
							htmlTag = htmlTag.replace(/checked/gi, "");
						//this is a bad checkbox
						} else {
							questions.put(inputName, new WorkbookExerciseQuestion(inputName, WorkbookExerciseQuestion.TYPE_CHECKBOX, ""));
							questions.get(inputName).setUserAnswer("");
						}
						
						//add user answer
						htmlTag = htmlTag.replace(/<input/i, "<input {if exercise.getQuestions().get('" + inputName + "').getUserAnswer() == '" + inputValue + "'} checked=\"checked\"{/if}");
						
						//add solution
						var arVersion = navigator.appVersion.split("MSIE");
						var version = parseFloat(arVersion[1]);
						
						var iePNGBugSpanOk = "";
						var iePNGBugSpanOkSelected = "";
						var iePNGBugSpanBad = "";
						var iePNGBugSpanBadSelected = "";
						var iePNGBugImg = "";
						if ((version >= 5.5) && (document.body.filters)) {
							var begin = " style=\"vertical-align:middle; display:inline-block; width:18px; height:21px; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader (src='images/1_5/workbook/";
							var end = "', sizingMethod='scale');\"";
							iePNGBugSpanOk = begin + "checkbox_ok.png" + end;
							iePNGBugSpanOkSelected = begin + "checkbox_ok_selected.png" + end;
							iePNGBugSpanBad = begin + "checkbox_bad.png" + end;
							iePNGBugSpanBadSelected = begin + "checkbox_bad_selected.png" + end;
							iePNGBugImg = " style=\"display: none;\"";
						}
						
						var htmlTag = "{if (exercise.isSolved() || exercise.isCorrected())}<span class=\"LessonCheckboxImg\"{if exercise.getQuestions().get('" + inputName + "').isCorrect()}{if exercise.getQuestions().get('" + inputName + "').getUserAnswer() == '" + inputValue + "'}" + iePNGBugSpanOkSelected + "><img width=\"18\" height=\"21\"" + iePNGBugImg + " src=\"images/1_5/workbook/checkbox_ok_selected.png{else}" + iePNGBugSpanOk + "><img width=\"18\" height=\"21\"" + iePNGBugImg + " src=\"images/1_5/workbook/checkbox_ok.png{/if}{else}{if exercise.getQuestions().get('" + inputName + "').getUserAnswer() == '" + inputValue + "'}" + iePNGBugSpanBadSelected + "><img width=\"18\" height=\"21\"" + iePNGBugImg + " src=\"images/1_5/workbook/checkbox_bad_selected.png{else}" + iePNGBugSpanBad + "><img width=\"18\" height=\"21\"" + iePNGBugImg + " src=\"images/1_5/workbook/checkbox_bad.png{/if}{/if}\" /></span>{else}" + htmlTag + "{/if}";

						break;
					
					//input text
					case "text":
						htmlTag = htmlTag.replace(/<input/i, "<input onFocus=\"this.className='LessonTextboxSelected'\" onBlur=\"this.className='LessonTextbox'\"");
						questions.put(inputName, new WorkbookExerciseQuestion(inputName, WorkbookExerciseQuestion.TYPE_TEXT, inputValue.trim()));
						
						//add user answer
						htmlTag = htmlTag.replace(/value="[^">]*"/gi, "value=\"${decodeSpecialCharsFieldValue(exercise.getQuestions().get('" + inputName + "').getUserAnswer())}\"");
						
						//add solution
						//htmlTag = "{if (exercise.isSolved() || exercise.isCorrected())}<span class=\"LessonTextbox{if exercise.getQuestions().get('" + inputName + "').isCorrect()}Ok{else}Bad{/if}\">${decodeSpecialCharsFieldValue(exercise.getQuestions().get('" + inputName + "').getUserAnswer())}</span>{if !exercise.getQuestions().get('" + inputName + "').isCorrect()}<span class=\"ExerciseAnswerIsBad\">&nbsp;" + inputValue + "&nbsp;</span>{/if}{else}" + htmlTag + "{/if}";
						htmlTag = "{if (exercise.isSolved() || exercise.isCorrected())}<span class=\"LessonTextbox{if exercise.getQuestions().get('" + inputName + "').isCorrect()}Ok\">${decodeSpecialCharsFieldValue(exercise.getQuestions().get('" + inputName + "').getUserAnswer())}{else}BadPre\">${exercise.whereIsBad(decodeSpecialCharsFieldValue(exercise.getQuestions().get('" + inputName + "').getUserAnswer()),\"" + inputValue + "\")}{/if}</span>{if !exercise.getQuestions().get('" + inputName + "').isCorrect()}<span class=\"ExerciseAnswerIsBad\">&nbsp;" + inputValue + "&nbsp;</span>{/if}{else}" + htmlTag + "{/if}";
						
						break;
				}
			
			//textarea tags
			} else if (htmlTag.indexOf("<textarea") == 0 && inputName) {
				//add keylogging
				htmlTag = htmlTag.replace(/<textarea/i, "<textarea onkeyup=\"esuli.workbook.getLevel('" + parent.getParent().getId() + "').getLesson(" + parent.getId() + ").getExercise(" + id + ").getQuestions().get('" + inputName + "').setUserAnswer();\" onclick=\"esuli.workbook.getLevel('" + parent.getParent().getId() + "').getLesson(" + parent.getId() + ").getExercise(" + id + ").getQuestions().get('" + inputName + "').setUserAnswer();\" onFocus=\"esuli.staticContent.textareaFocus(this,'Lesson');\" onBlur=\"esuli.staticContent.textareaBlur(this,'Lesson');\"");
				
				//add user answer
				htmlTag += "${decodeSpecialCharsFieldValue(exercise.getQuestions().get('" + inputName + "').getUserAnswer())}";
				
				questions.put(inputName, new WorkbookExerciseQuestion(inputName, WorkbookExerciseQuestion.TYPE_TEXTAREA, ""));
			}
			
			//add to parsed HTML
			html += remainder.substring(0, tagStart) + htmlTag;
			
			//set remainder HTML to parse
			remainder = remainder.substring(tagEnd);
			
			//set next HTML tag
			htmlTag = remainder.match(/<[^>]*>/);
		}
		
		//convert it to template
		html = new Template(parent.getParent().getId() + "_" + parent.getId() + "_" + id, html + remainder);
	}
	
	/**
	 * Solves exercise
	 */
	this.solve = function() {
		//update user answers
		var it = questions.values().iterator();
		
		while (it.hasNext()) {
			it.next().setUserAnswer();
		}
		
	    //calculate result
	    var it = questions.values().iterator();
	    var count = 0;
	    
	    while (it.hasNext()) {
	    	if (it.next().isCorrect()) {
    			count++;
    	    }
	    }
	    
	    if (! self.isHomework()) {
	    	resultScore = count;
	    	resultPercent = Math.round(count * 100 / questions.size());
	    }
    	
	    status = "Megoldott";
	    solvedCount++;
	    
	    engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, {
			tabId: esuli.tab.activeTabId, 
			subId: esuli.tab.activeSubMenuId, 
	    	module: "workbook",
	    	page: "exerciseList",
	    	levelId: esuli.workbook.levelPage.getCurrentLevelId(),
	    	lessonId: esuli.workbook.lessonPage.getCurrentLessonId(),
	    	exerciseId: id
	    }));
		
	    if (esuli.user.isLoggedIn()) {
			sendSolve();
	    }
	}
	
	/**
	 * Sends solve
	 */
	function sendSolve() {
		var it = questions.values().iterator();
		var answers = new Array()
		
		while (it.hasNext()) {
			answers.push(it.next().getUserAnswer());
		}
		
		var comm = new CommGateRequest("REQ_ACCESS", [ "ESULI_SOLVE_LESSON" ], null);
		comm.addDataLevel([
			[ "LESSONID", "USERQUEST", "USERANS", "RESULT", "PERCENT" ],
			[
				id,
				questions.keysArray().toString().replace(/,/g, ';'),
				answers.toString().replace(/,/g, ';'),
				resultScore,
				resultPercent
			]
		]);
		
		engine.commGate.sendWithSession([ comm ]);
	}
	
	/**
	 * Returns true if homework
	 * @return True if homework
	 * @type Boolean
	 */
	this.isHomework = function() {
		var it = questions.values().iterator();
		
		while (it.hasNext()) {
			var item = it.next();
			if (item.getType() == WorkbookExerciseQuestion.TYPE_TEXTAREA) {
				return true;
			}
		}
		
		return false;
	}
	
    /**
     * Returns true if has note textarea (e.g. speaking lesson)
     * @return True if has notes
     * @type Boolean
     */
    this.hasNotes = function() {
        var it = questions.values().iterator();

        while (it.hasNext()) {
            var item = it.next();
            if (item.getId() == 'NOTES') {
                return true;
            }
        }

        return false;
    }


	/**
	 * Loads data from database
	 * @param Object Callback page request
	 * @return True if data has already been loaded
	 * @type Boolean
	 */
	this.loadData = function(callbackPage) {
		var oldSeq = esuli.contentManager.getSeq();
		
		if (loaded || type == WorkbookExerciseType.TYPE_CHAT45 || type == WorkbookExerciseType.TYPE_TEACHER45 || status == "Megvásárolható") {
			loaded = true;
			return true;
		}
		
		parse(engine.commGate.getStringByUrl(getPath() + '.html'));
		
		if (type == WorkbookExerciseType.TYPE_VIDEO) {
			loaded = true;
			return true;
		}
		
		var whtml = html.getSource();
		var commands = new Array();
		var comm;
		
		var recI = 1;
		while (whtml.indexOf("$$RECORDER$$") > -1) {
			var path = "E-" + parent.getParent().getId() + "-" + (parent.getOrder() < 10 ? "0" : "") + parent.getOrder() + "-" + (type < 10 ? "0" : "") + type + "-" + typeOrder + "-" + recI++;
			comm = new CommGateRequest("REQ_ACCESS", [ "ESULI_RECORD_FILENAME" ]);
			comm.addDataLevel([
				[ "EXERCISEID", "RECORD" ],
				[ exerciseId, path ]
			]);
			
			commands.push(comm);
			
    		whtml = whtml.replace(/\$\$RECORDER\$\$/, "$$RECORDER_PROCESSED$$");
        }
		
		comm = new CommGateRequest(
			(! esuli.user.isLoggedIn() ? "REQ_SELECT" : "REQ_ACCESS"),
			[ "ESULI_GET_LESSON" ],
			function(response) {
				var data = response[0].getDataAsObjectArray();
				
				if (data[0].extra == "TRUE") {
					extra = engine.commGate.getStringByUrl(getPath() + ".extra");
				}
				
				if (esuli.user.isLoggedIn()) {
					questions.map(function(question) {
						question.clear();
					});
					
					if (data[0].state == "Megoldott" || data[0].state == "Javított") {
						var answerQuestions = getArrayFromDBString(data[0].userquest);
						var answerSolutions = getArrayFromDBString(data[0].userans);
						
						for (var i = 0; i < answerQuestions.length; i++) {
							questions.get(answerQuestions[i]).setDirectUserAnswer(answerSolutions[i]);
						}
					}
					
					resultScore = data[0].result;
					resultPercent = data[0].percent;
					status = data[0].state;
					solvedCount = data[0].solvednum;
					comment = data[0].comment;
		
					//records
					var record = getArrayFromDBString(data[0].record);
					var recordFile = getArrayFromDBString(data[0].recordfile);
					
					if (record.length == recordFile.length) {
						for (var i = 0; i < record.length; i++) {
							records.put(record[i], recordFile[i] + ".spx");
						}
					}
				}
				
				loaded = true;
				
				if (callbackPage != undefined && oldSeq == esuli.contentManager.getSeq()) {
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, callbackPage));
				}
			}
		);
		
		comm.addDataLevel([ [ "LESSONID" ], [ id ] ]);
		
		commands.push(comm);
		
		engine.commGate.sendWithSession(commands);
		
		return false;
	}
	
	/**
	 * Olvasmányhoz tartozó történetek lekérdezése db-ből
	 * @param Object Callback page request
	 * @return True if data has already been loaded
	 * @type Boolean
	 */
	this.loadStories = function(callbackPage) {
		var oldSeq = esuli.contentManager.getSeq();
		
		if(storiesLoaded) {
			return true;
		}
		comm = new CommGateRequest(
			"REQ_SELECT",
			[ "ESULI_STUDENT_GET_EXERCISE_STORIES" ],
			function(response) {
				var data = response[0].getDataAsObjectArray();

				if(data) {
					stories = data;
				}
				
				if(stories.length > 0) {
					loadStory(callbackPage);
				} else {
					storiesLoaded = true;
					if (callbackPage != undefined && oldSeq == esuli.contentManager.getSeq()) {
						engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, callbackPage));
					}
				}
			}
		);
		
		comm.addDataLevel([ [ "EXERCISEID" ], [ id ] ]);
		engine.commGate.sendWithSession([ comm ]);
		return false;
	}
	
	/**
	 * Olvasmányhoz tartozó történetek tartalmának lekérdezése db-ből
	 * Ha lejöttek, akkor megjeleníthető az olvasmány
	 * @param Object Callback page request
	 */
	function loadStory(callbackPage) {
		var oldSeq = esuli.contentManager.getSeq();
		comm = new CommGateRequest(
			"REQ_SELECT",
			[ "ESULI_STUDENT_GET_EXERCISE_STORY" ],
			function(response) {
				var data = response[0].getDataAsObjectArray();
				
				if(data) {
					story.length = 0;
				    var tempStory;
				    for (var i = 0; i < data.length; i++) {
			    		tempStory = new WorkbookExerciseStory(data[i].storyid, data[i].studentid, data[i].studentname, decodeSpecialCharsFieldValue(data[i].text), data[i].date, data[i].state);
				    	story.push(tempStory);
				    }
				}
				
				storiesLoaded = true;
				if (callbackPage != undefined && oldSeq == esuli.contentManager.getSeq()) {
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, callbackPage));
				}
			}
		);
		
		comm.addDataLevel([ [ "EXERCISEID" ], [ id ] ]);
		engine.commGate.sendWithSession([ comm ]);
	}
	
	/**
	 * Olvasmányhoz tartozó történetek
	 * @return Array Történetek, megnyitott történet tartalma
	 */
	this.getStories = function() {
		var storyContent = new Array();
		if(currentStory != null) {
			for(var i = 0; i < story.length; i++) {
				if(story[i].getStoryId() == currentStory.storyid) {
					storyContent.push(story[i]);
				}
			}
		}
		return ret = new Array(stories, currentStory, storyContent);
	}
	
	/**
	 * Open stpry
	 * @param Story id
	 * @type Number
	 */
	this.openStory = function(pStoryId) {
		if(pStoryId == 'add') {
			currentStory = {type: 'add', storyid: null};
		} else if(pStoryId == null) {
			currentStory = null;
		} else {
			for(var i = 0; i < stories.length; i++) {
				if(stories[i].storyid == pStoryId) {
					currentStory = stories[i];
					break;
				}
			}
		}
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
	}
	
	/**
	 * Get current story id
	 * @return Number Story id
	 */
	this.getCurrentStoryId = function() {
		return currentStory != null ? currentStory.storyid : false;
	}
	
	/**
	 * Szavakhoz tartozó szavak (felhasználók álltal hozzáadott) lekérdezése db-ből
	 * @param Object Callback page request
	 * @return True if data has already been loaded
	 * @type Boolean
	 */
	this.loadWords = function(callbackPage) {
		var oldSeq = esuli.contentManager.getSeq();
		
		if(wordsLoaded) {
			return true;
		}
		
		comm = new CommGateRequest(
			"REQ_SELECT",
			[ "ESULI_STUDENT_GET_EXERCISE_WORDS" ],
			function(response) {
				var data = response[0].getDataAsObjectArray();

				if(data) {
					words.length = 0;
				    var tempWord;
				    for (var i = 0; i < data.length; i++) {
						tempWord = new WorkbookExerciseWords(data[i].studentid, data[i].studentname, decodeSpecialCharsFieldValue(data[i].eng), decodeSpecialCharsFieldValue(data[i].hun), data[i].date, data[i].state, decodeSpecialCharsFieldValue(data[i].example), decodeSpecialCharsFieldValue(data[i].comment));
						words.push(tempWord);
				    }
				}

				wordsLoaded = true;
				if (callbackPage != undefined && oldSeq == esuli.contentManager.getSeq()) {
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, callbackPage));
				}
			}
		);

		comm.addDataLevel([ [ "EXERCISEID" ], [ id ] ]);
		engine.commGate.sendWithSession([ comm ]);
		return false;
	}
	
	/**
	 * Get words array
	 * @return Words
	 * @type Objects in Array
	 */
	this.getWords = function() {
		return words;
	}
	
	/**
	 *
	 */
	this.loadObservations = function(callbackPage) {
		var oldSeq = esuli.contentManager.getSeq();
		
		if(observationsLoaded) {
			return true;
		}
		comm = new CommGateRequest(
			"REQ_SELECT",
			[ "ESULI_GET_FELADATLAP_HOZZÁSZÓLÁS" ],
			function(response) {
				var data = response[0].getDataAsObjectArray();

				if(data) {
					observations = data;
				}
				
				observationsLoaded = true;
				
				if (observations.length > 0 && callbackPage != undefined && oldSeq == esuli.contentManager.getSeq()) {
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, callbackPage));
				}
			}
		);
		
		comm.addDataLevel([ [ "FELADATLAP_ID" ], [ id ] ]);
		engine.commGate.sendWithSession([ comm ]);
		return false;
	}
	
	/**
	 *
	 */
	this.getObservations = function() {
		return observations;
	}
	
	/**
     * Adatbázis mezőben (; karakterekkel leírt tömb stringből csinál javascript tömböt.
     * Pl ((A;B);(X;Y)) -> [['A','B'],['X','Y']]
     * @param String Input DB string
     * @return Converted and eval'd array
     * @type Array
     */
	function getArrayFromDBString(inputString) {
		if (! inputString || ! inputString.replace) {
			return new Array();
		}
		
		var outputArray = new Array();
		var str = inputString;
		
		str = str.replace('"', '');
		str = str.replace(/;$/gi, '');
		str = str.replace(/\);\(/gi, '"],["');
		str = str.replace(/;/gi, '","');
		str = str.replace(/\(\(/gi, '[["');
		str = str.replace(/\)\)\)\)/gi, '"]]]]');
		str = str.replace(/\)\)/gi, '"]]');
		str = str.replace(/\(/gi, '["');
		str = str.replace(/\)/gi, '"]');
		str = str.replace(/\"\[/gi, '[');
		str = str.replace(/\]"/gi, ']');
		
		if (str.substr(0, 1) != "[") {
			outputArray = eval('["' + str + '"]');
		} else {
			outputArray = eval(str);
		}
		
		for (var i = 0; i < outputArray.length; i++) {
			if (outputArray[i] instanceof Array) {
				for (var j = 0; j < outputArray[i].length; j++) {
					outputArray[i][j] = decodeSpecialCharsFieldValue(outputArray[i][j]);
				}
			} else {
				outputArray[i] = decodeSpecialCharsFieldValue(outputArray[i]);
			}
		}
		
		return outputArray;
	}
	
}
/**
 * Exercise page in workbook module
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function WorkbookExercisePage() {
	
	/**
	 * Id of current exercise
	 * @type Number
	 */
	var currentExerciseId = 0;
	
	/**
	 * Returns execise page
	 * @param Object Callback page name
	 * @return Requested page
	 * @type Object
	 */
	this.getPage = function(pageRequest) {
		currentExerciseId = pageRequest.get("exerciseId");

		var levelId = pageRequest.get("levelId");
		var lessonId = pageRequest.get("lessonId");
		
		var level = esuli.workbook.getLevel(levelId);
		var lesson = level.getLesson(lessonId);
		var exercise = lesson.getExercise(currentExerciseId);
		
		if (!exercise.loadData(pageRequest)) {
			return engine.templateManager.getTemplate("contentspin").process({});
		}
		
		// Plus functions for defined lesson types
		if(exercise.getType() == 3 && exercise.isCommunityPageOpened() && !exercise.loadStories(pageRequest)) {
			return engine.templateManager.getTemplate("contentspin").process({});
		} else if(exercise.getType() == 9 && exercise.isCommunityPageOpened() && !exercise.loadWords(pageRequest)) {
			return engine.templateManager.getTemplate("contentspin").process({});
		}
		
		var type = lesson.getExerciseType(exercise.getType());
		var whtml = "";
		var templateName;
		var resultLineType;
		
	    if (exercise.isHomework()) {
			if ( !exercise.hasNotes())	resultLineType = "workbook_resultline_homework";
			else resultLineType = "workbook_resultline_notes";
	    } else if ((type.getId() == WorkbookExerciseType.TYPE_TEST) && (exercise.getSolvedCount() < 2)) {
			resultLineType = "workbook_resultline_test";
	    } else if (! exercise.getQuestions().isEmpty()) {
			resultLineType = "workbook_resultline_normal";
	    }
		
		if (exercise.getStatus() == "Megvásárolható") {
			templateName = "workbook_notbought";
		} else if (type.isBrown()) {
			if (! esuli.user.isLoggedIn()) {
				templateName = "profil_mustlogin";
			} else {
				if (esuli.dateSelector.getDataFromDB(pageRequest)) {
					if (esuli.applet.getTrusted() == false) {
						templateName = "applet_trust";
					} else {
						templateName = "applet_trusted";
						esuli.applet.voip.show();
					}
				} else {
					templateName = "spin";
				}
			}
		} else {
			templateName = "workbook_exercise";
			try {
				whtml = engine.templateManager.getTemplate("workbook_lesson").process({lessoncontent: exercise.getHtml().process({ exercise: exercise, page: self })});
			} catch(e) {
				alert("process: " + e.message);
			}
			
        	if ((exercise.getStatus() == "Megoldott" || exercise.getStatus() == "Javított") && exercise.getExtra()) {
				whtml += engine.templateManager.getTemplate("workbook_lessonextra").process({lessonextra: exercise.getExtra()});
        	}
			
    		while (whtml.indexOf("$$AVREC$$") > -1) {
				var recorderHTML = '';
				if (exercise.getStatus() == 'Megoldott') {
					recorderHTML = '<div id="videoplayer"></div>';

					var comm = new CommGateRequest(
						"REQ_ACCESS",
						[ "ESULI_GET_VIDEOS" ],
						function(pResponse, ketto) {
							var res = pResponse[0].getDataAsArray()[0];
							var s = "";
							for (var x = 1; x < res.length; x++) {
								var videoFile = res[x];
								if (videoFile.slice(-4) == '.flv') {
									videoFile = videoFile.slice(0, -4);
								}
								var movie = VIDEOPLAYER_URL + '?video=' + VIDEO_URL_PREFIX + '/' + videoFile + '&amp;type=1';
								s += '<div><object type="application/x-shockwave-flash" data="' + movie + '" width="320" height="240">';
								s += '<param name="movie" value="' + movie + '" />';
								s += '<param name="quality" value="high" />';
								s += '<param name="wmode" value="transparent" />';
								s += '</object></div>';
							}
							document.getElementById("videoplayer").innerHTML = s;
						}
					);

					comm.addDataLevel([["EXERCISEID"], [currentExerciseId]]);
					engine.commGate.sendWithSession([comm]);
				} else {
					recorderHTML = '<object type="application/x-shockwave-flash" data="videorecorder/videorecorder.swf" width="340" height="360"><param name="flashvars" value="sscode=asp&specialID=valami" /><param value="high" name="quality"/><param value="transparent" name="wmode"/><param value="videorecorder/videorecorder.swf" name="movie"/></object>';
				}

				whtml = whtml.replace(/\$\$AVREC\$\$/, recorderHTML);
            }
			
			// Plus functions for defined lesson types
			if(exercise.getType() == 3 && exercise.isCommunityPageOpened()) {
				var stories = exercise.getStories();
				whtml = engine.templateManager.getTemplate("workbook_stories").process({stories: stories[0], current: stories[1], content: stories[2]});
			} else if(exercise.getType() == 9 && exercise.isCommunityPageOpened()) {
				var words = exercise.getWords();
				whtml = engine.templateManager.getTemplate("workbook_words").process({words: words});
			}
		}
		return engine.templateManager.getTemplate(templateName).process({
			content: whtml,
			resultLineType: resultLineType,
			exercises: lesson.getExercises(),
			exercise: exercise,
			type: type,
			page: self
		});}
	
	/**
	 * Open Story
	 * @param Number Story id
	 */
	this.openStory = function(pStoryId) {
		var level = esuli.workbook.getLevel(esuli.workbook.levelPage.getCurrentLevelId());
		var lesson = level.getLesson(esuli.workbook.lessonPage.getCurrentLessonId());
		var exercise = lesson.getExercise(currentExerciseId);
		exercise.openStory(pStoryId);
	}
	
	/**
	 * Create a new story
	 */
	this.addNewStory = function() {
		var level = esuli.workbook.getLevel(esuli.workbook.levelPage.getCurrentLevelId());
		var lesson = level.getLesson(esuli.workbook.lessonPage.getCurrentLessonId());
		var exercise = lesson.getExercise(currentExerciseId);
		
		var addStoryTitle = $("addStoryTitle");
		if(!addStoryTitle.value || addStoryTitle.value == "") {
			addStoryTitle.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog("Add meg a történet címét!", "alert", [ null, null ,null ]));
			return;
		}
		var addToStory = $("addToStory");
		if(!addToStory.value || addToStory.value == "") {
			addToStory.className = 'normalTextareaError';
			engine.dialogManager.add(new Dialog("Add meg a történet szövegét!", "alert", [ null, null ,null ]));
			return;
		}
		addToStory = addToStory.value.replace(/\n/g, "<br />");
		addToStory = addToStory.replace(/\r/g, "<br />");
		
		comm = new CommGateRequest(
			"REQ_ACCESS",
			[ "ESULI_STUDENT_ADD_EXERCISE_STORIES" ],
			function(pResponse) {
				var comm0 = pResponse[0].getCommandLine();
				if( comm0[2] == 1 ) {
					var comm1 = pResponse[0].getDataAsArray();
					exercise.setStoriesNotLoaded();
					engine.dialogManager.add(new Dialog("Köszönjük!", "alert", [ null, null ,null ]));
					// parseInt(comm1[0][2])
					exercise.openStory(null);
				} else {
					engine.dialogManager.add(new Dialog("Probléma a feldolgozás során, próbáld újra!", "alert"));
				}
			}
		);

		comm.addDataLevel([ [ "EXERCISEID", "TITLE", "CONTENT" ], [ currentExerciseId, encodeSpecialCharsFieldValue(addStoryTitle.value), encodeSpecialCharsFieldValue(addToStory) ] ]);
		engine.commGate.sendWithSession([ comm ]);
	}
		
	/**
	 * Add text to reading story
	 */
	this.addToStory = function() {
		var level = esuli.workbook.getLevel(esuli.workbook.levelPage.getCurrentLevelId());
		var lesson = level.getLesson(esuli.workbook.lessonPage.getCurrentLessonId());
		var exercise = lesson.getExercise(currentExerciseId);
		var currentStoryId = exercise.getCurrentStoryId();
		
		var addToStory = $("addToStory");
		if(!addToStory.value || addToStory.value == "") {
			addToStory.className = 'normalTextareaError';
			engine.dialogManager.add(new Dialog("Add meg a történet szövegét!", "alert", [ null, null ,null ]));
			return;
		}
		addToStory = addToStory.value.replace(/\n/g, "<br />");
		addToStory = addToStory.replace(/\r/g, "<br />");
		
		comm = new CommGateRequest(
			"REQ_ACCESS",
			[ "ESULI_STUDENT_ADD_EXERCISE_STORY" ],
			function(pResponse) {
				var comm0 = pResponse[0].getCommandLine();
				if( comm0[2] == 1 ) {
					var comm1 = pResponse[0].getDataAsArray();
					if ( comm1[0][1] == "FAILURE" && comm1[0][2] == "STORY ADDED PREVIOUSLY" ) {
						engine.dialogManager.add(new Dialog("Te már előzőleg hozzáadtad a magadét a történethez!", "alert", [ null, null ,null ]));
					} else {
						exercise.setStoriesNotLoaded();
						engine.dialogManager.add(new Dialog("Köszönjük!", "alert", [ null, null ,null ]));
						exercise.openStory(currentStoryId);
					}
				} else {
					engine.dialogManager.add(new Dialog("Probléma a feldolgozás során, kérlek próbáld újra!", "alert"));
				}
			}
		);

		comm.addDataLevel([ [ "STORYID", "STORY" ], [ currentStoryId, encodeSpecialCharsFieldValue(addToStory) ] ]);
		engine.commGate.sendWithSession([ comm ]);
	}

	/**
	 * Felapadtlaphoz tartozó kérsések / észrevételek lekérdezése
	 */
	this.getObservations = function(pageRequest) {
		currentExerciseId = pageRequest.get("exerciseId");
		
		var levelId = pageRequest.get("levelId");
		var lessonId = pageRequest.get("lessonId");
		
		var level = esuli.workbook.getLevel(levelId);
		var lesson = level.getLesson(lessonId);
		var exercise = lesson.getExercise(currentExerciseId);
		
		if(!exercise.loadObservations(pageRequest)) {
			return '';
		}
		
		var observations = exercise.getObservations();
		if(observations.length > 0) {
			return engine.templateManager.getTemplate("workbook_observations").process({observations: observations});
		} else {
			return '';
		}
	}

	
	/**

	 * Add word 
	 */
	this.addWord = function() {
		var level = esuli.workbook.getLevel(esuli.workbook.levelPage.getCurrentLevelId());
		var lesson = level.getLesson(esuli.workbook.lessonPage.getCurrentLessonId());
		var exercise = lesson.getExercise(currentExerciseId);
		var addEng = $("addEng");
		var addHun = $("addHun");
		var example = $("addExample").value;
		var comment = $("addComment").value;
		
		if(!addEng.value || addEng.value == "") {
			addEng.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog("Nem adtad meg a szót, vagy kifejezést angolul!", "alert", [ null, null ,null ]));
			return;
		}
		if(!addHun.value || addHun.value == "") {
			addHun.className = 'normalTextInputError';
			engine.dialogManager.add(new Dialog("Nem adtad meg a szót, vagy kifejezést magyarul!", "alert", [ null, null ,null ]));
			return;
		}
		
		example = example.replace(/\n/g, "<br />");
		example = example.replace(/\r/g, "<br />");
		comment = comment.replace(/\n/g, "<br />");
		comment = comment.replace(/\r/g, "<br />");
		
		comm = new CommGateRequest(
			"REQ_ACCESS",
			[ "ESULI_STUDENT_ADD_EXERCISE_WORD" ],
			function(pResponse) {
				var comm0 = pResponse[0].getCommandLine();
				if( comm0[2] == 1 ) {
					exercise.setWordsNotLoaded();
					engine.dialogManager.add(new Dialog("Köszönjük!", "alert", [ null, null ,null ]));
					exercise.loadWords(esuli.contentManager.getLastPage());
				} else {
					engine.dialogManager.add(new Dialog("Probléma a feldolgozás során, kérlek próbáld újra!", "alert"));
				}
			}
		);

		comm.addDataLevel([ [ "EXERCISEID", "ENG", "HUN", "EXAMPLE","COMMENT" ], [ currentExerciseId, encodeSpecialCharsFieldValue(addEng.value), encodeSpecialCharsFieldValue(addHun.value), encodeSpecialCharsFieldValue(example), encodeSpecialCharsFieldValue(comment) ] ]);
		engine.commGate.sendWithSession([ comm ]);
	}
	
	/**
	 * Send report if user find obscenity in lesson
	 */
	this.sendReport = function() {
		var level = esuli.workbook.getLevel(esuli.workbook.levelPage.getCurrentLevelId());
		var lesson = level.getLesson(esuli.workbook.lessonPage.getCurrentLessonId());
		var exercise = lesson.getExercise(currentExerciseId);
		
		var fileName = exercise.getFileName();
		
		var message = "";
			message += "Felhasználói bejelentés leckében talált oda nem illő tartalomról. (Írjuk együtt oldalon)" + "\n\n"
			 + "Bejelentő e-mail címe: " + esuli.user.getEmail() + "\n\n"
			 + "Kifogásolt tartalmú lecke: " + fileName;
		
		engine.commGate.send([ new CommGateRequest("SEND_EMAIL", [ "info@enyelviskola.hu", message, "Felhasználói bejelentés obszcén tartalomról" ], null ), new CommGateRequest("HAVE_SESSION", [ esuli.user.getSessionId() ], null ) ] );
		engine.dialogManager.add(new Dialog("Köszönjük, munkatársunk hamarosan ellenőrzi az oldal tartalmát!", "alert", null));
	}
	
	/**
	 * Send error report for exercise
	 */
	this.sendErrorReport = function() {
		var level = esuli.workbook.getLevel(esuli.workbook.levelPage.getCurrentLevelId());
		var lesson = level.getLesson(esuli.workbook.lessonPage.getCurrentLessonId());
		var exercise = lesson.getExercise(currentExerciseId);
		
		var fileName = exercise.getFileName();
		
		var message = "";
			message += "Felhasználói bejelentés leckében talált hibáról." + "\n\n"
			 + "Bejelentő e-mail címe: " + esuli.user.getEmail() + "\n\n"
			 + "Hibás lecke: " + fileName;
		
		var error = $('workbookError');
		if(error && error.value != '') {
			message += "\n\n" + "A hiba: " + error.value;
			error.value = "";
		}
		
		engine.commGate.send([ new CommGateRequest("SEND_EMAIL", [ "info@enyelviskola.hu", message, "Felhasználói hiba bejelentés" ], null ), new CommGateRequest("HAVE_SESSION", [ esuli.user.getSessionId() ], null ) ] );
		engine.dialogManager.add(new Dialog("Köszönjük, munkatársunk hamarosan ellenőrzi a feladatlapot!", "alert", null));
	}
	
	/**
	 * Kérdés / Észrevétel feltevés a feladathoz
	 */
	this.sendObservation = function() {
		var question = $('workbookQuestion');

		if(!question.value) {
			question.className = 'normalTextareaError';
			engine.dialogManager.add( new Dialog("Kérjük add meg kérdésedet!", "alert" ) );
			return false;
		}

		comm = new CommGateRequest(
			"REQ_ACCESS",
			[ "ESULI_SET_FELADATLAP_HOZZÁSZÓLÁS" ],
			function(pResponse) {
				var cmd;
				var data;
				for( var i = 0; i < pResponse.length; i++ ) {
					cmd = pResponse[i].getCommandLine();
					if ( ( cmd ) && ( cmd[1] ) && ( cmd[1] == 'RES_DATA' ) ) {
						data = pResponse[i].getDataAsArray();
						if ( data[0][1] == 'SUCCESS' ) {
							engine.dialogManager.add( new Dialog("Kérdésedet megkaptuk, hamarosan válaszolunk rá.", "alert" ) );
							question.className = 'normalTextarea';
							question.value = '';
						} else
							engine.dialogManager.add( new Dialog("A kérdés elküldése nem sikerül, kérjük próbáld meg később, vagy érdeklődj az ügyfélszolgálaton!", "alert" ) );
					} else
						engine.dialogManager.add( new Dialog("A kérdés elküldése nem sikerül, kérjük próbáld meg később, vagy érdeklődj az ügyfélszolgálaton!", "alert" ) );
				}
			}
		);
		
		comm.addDataLevel([ [ 'FELADATLAP_ID', 'QUESTION' ], [ currentExerciseId, question.value ] ]);
		engine.commGate.sendWithSession([ comm ]);
	}
	
	/**
	 * Clears solution of the specified exercise
	 */
	this.clearExercise = function() {
		var level = esuli.workbook.getLevel(esuli.workbook.levelPage.getCurrentLevelId());
		var lesson = level.getLesson(esuli.workbook.lessonPage.getCurrentLessonId());
		var exercise = lesson.getExercise(currentExerciseId);
		
		engine.dialogManager.add(new Dialog(
			"Biztosan törlöd a feladat javításokat?",
			"CONFIRM",
			[
				null,
				function () {
					esuli.workbook.lessonPage.clearExercises();
				},
				null
			])
		);
	}
	
	/**
	 * Solves the specified exercise
	 */
	this.solveExercise = function() {
		if ( esuli.user.monthlyTicketOver ) {
			engine.dialogManager.add(new Dialog("A bérleted sajnos már lejárt, ezért újabb feladatokat megoldani már nem fogsz tudni. A megoldottakat természetesen továbbra is megnézheted. Ha tetszett, rendeld meg újra!", "alert" ));
			return;
		}
		var level = esuli.workbook.getLevel(esuli.workbook.levelPage.getCurrentLevelId());
		var lesson = level.getLesson(esuli.workbook.lessonPage.getCurrentLessonId());
		var exercise = lesson.getExercise(currentExerciseId);
		
		if (exercise.getType() == WorkbookExerciseType.TYPE_HOMEWORK) {
			engine.dialogManager.add(new Dialog(
				"Biztosan javítsam a házi feladatot?",
				"confirm",
				[ null, function () { exercise.solve(); }, null ],
				[ "", "Javítsd", "Ne javítsd" ])
			);
		} else if (! exercise.isCompleted()) {
			engine.dialogManager.add(new Dialog(
				"A feladat nincs teljesen kitöltve.<br/>Biztosan javítsam?",
				"confirm",
				[ null, function () { exercise.solve(); }, null ],
				[ "", "Javítsd", "Ne javítsd" ])
			);
		} else {
			exercise.solve();
		}
	}
	
	/**
	 * Returns current exercise id
	 * @return Id of current exercise
	 * @type Number
	 */
	this.getCurrentExerciseId = function() {
		return currentExerciseId;
	}
	
	/**
	 * Sets current exercise id
	 * @param Number Id of exercise
	 */
	this.setCurrentExerciseId = function(exerciseId) {
		currentExerciseId = exerciseId
	}
}
/**
 * Question class for Exercise in Workbook module
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function WorkbookExerciseQuestion(questionId, questionType, questionRightAnswer) {
	
	/**
	 * Id of question
	 * @type String
	 */
	var id = questionId;
	
	/**
	 * Type of question
	 * @type String
	 */
	var type = questionType;
	
	/**
	 * Right answer
	 * @type String
	 */
	var rightAnswer = questionRightAnswer;
	
	/**
	 * User answer
	 * @type String
	 */
	var userAnswer = "";
	
	/**
	 * Pointer to this
	 * @type WorkbookExerciseQuestion
	 */
	var self = this;
	
	/**
	 * Sets id
	 * @param String Id
	 */
	this.setId = function(questionId) {
		id = questionId;
	}
	
	/**
	 * Returns id
	 * @return Id
	 * @type String
	 */
	this.getId = function() {
		return id;
	}
	
	/**
	 * Sets type
	 * @param String Type
	 */
	this.setType = function(questionType) {
		type = questionType;
	}
	
	/**
	 * Returns type
	 * @return Type
	 * @type String
	 */
	this.getType = function() {
		return type;
	}
	
	/**
	 * Sets right answer
	 * @param String Right Answer
	 */
	this.setRightAnswer = function(questionRightAnswer) {
		rightAnswer = questionRightAnswer;
	}
	
	/**
	 * Returns right answer
	 * @return Right Answer
	 * @type String
	 */
	this.getRightAnswer = function() {
		return rightAnswer;
	}
	
	/**
	 * Sets user answer
	 */
	this.setUserAnswer = function() {
		var inputs = document.getElementsByName(id);
		var input;
		
		for (var i = 0; i < inputs.length; i++) {
			//HTML element
			input = inputs[i];
			
			//textarea or input text
			if (input.rows != undefined || input.type == "text") {
				userAnswer = encodeSpecialCharsFieldValue(input.value).trim();
			
			//input radio
			} else if (input.type == "radio" && input.checked) {
				userAnswer = encodeSpecialCharsFieldValue(input.value);
			
			//input checkbox
			} else if (input.type == "checkbox") {
				if (input.checked) {
					userAnswer = encodeSpecialCharsFieldValue(input.value);
				} else {
					userAnswer = "";
				}
			}
		}
	}
	
	/**
	 * Directly sets user answer
	 * @param String User answer
	 */
	this.setDirectUserAnswer = function(questionUserAnswer) {
		if (check(questionUserAnswer)) {
			userAnswer = questionUserAnswer;
		} else {
			userAnswer = "";
		}
	}
	
	/**
	 * Returns user answer
	 * @return User answer
	 * @type String
	 */
	this.getUserAnswer = function() {
		return userAnswer;
	}
	
	/**
	 * Clears user answer
	 */
	this.clear = function() {
		userAnswer = "";
	}
	
	/**
	 * Returns true if user answer is correct
	 * @return True if user answer is correct
	 * @type Boolean
	 */
	this.isCorrect = function() {
		return (
			processField(decodeSpecialCharsFieldValue(rightAnswer).toUpperCase()) ==
			processField(decodeSpecialCharsFieldValue(userAnswer).toUpperCase())
		);
	}
	
}

/**
 * Text type constant
 * @type Number
 */
WorkbookExerciseQuestion.TYPE_TEXT = 0;

/**
 * Checkbox type constant
 * @type Number
 */
WorkbookExerciseQuestion.TYPE_CHECKBOX = 1;

/**
 * Radio type constant
 * @type Number
 */
WorkbookExerciseQuestion.TYPE_RADIO = 2;

/**
 * TextArea type constant
 * @type Number
 */
WorkbookExerciseQuestion.TYPE_TEXTAREA = 3;
/**
*  @constructor
*/
function WorkbookExerciseStory(pStoryId, pStudentId, pStudentName, pText, pDate, pState) {
	
	/**
	* Story id
	* @type Number
	*/
	var storyId = new Number(pStoryId);
	
	/**
	* Student id
	* @type Number
	*/
	var studentId = new Number(pStudentId);
	
	/**
	 * Student name
	 * @type String
	 */
	var studentName = new String(pStudentName);
	
	/**
	 * Story text
	 * @type String
	 */
	var text = new String(pText);
	
	/**
	 * Story adding date
	 * @type String
	 */
	var date = new String(pDate);
	
	/**
	 * Story state
	 * @type String
	 */
	var state = new String(pState);
	
	/**
	 * Return Story id
	 * @return Story id
	 * @type Number
	 */
	this.getStoryId = function() {
		return storyId;
	}
	
	/**
	 * Return Student id
	 * @return Student id
	 * @type Number
	 */
	this.getStudentId = function() {
		return storyId;
	}
	
	/**
	 * Return Student name
	 * @return Student name
	 * @type String
	 */
	this.getStudentName = function() {
		return studentName;
	}
	
	/**
	 * Return Story text
	 * @return Story text
	 * @type String
	 */
	this.getText = function() {
		return text;
	}
	
	/**
	 * Return Story adding date
	 * @return Story adding date
	 * @type String
	 */
	this.getDate = function() {
		return date;
	}
	
	/**
	 * Return Story adding formed date
	 * @return Story adding formed date
	 * @type String
	 */
	this.getFormedDate = function() {
		var formedDate = date;
		re = /-/gi;
		formedDate = formedDate.replace(re,'.');
		formedDate = formedDate.substring(0,19);
		return formedDate;
	}
	
	/**
	 * Return Story state
	 * @return Story state
	 * @type String
	 */
	this.getState = function() {
		return state;
	}
}
/**
 * ExerciseType object in workbook.
 * @param WorkbookLesson Parent lesson
 * @param Number Id
 * @param String Caption
 * @param String Color
 * @param Number Price
 * @param String Status
 * @constructor
 * @author Gabor, Horvath 'Koko' Kornel
 */
function WorkbookExerciseType(exerciseTypeParent, exerciseTypeId, exerciseTypeCaption, exerciseTypeColor, exerciseTypePrice, exerciseTypeStatus, exerciseTypeSelected) {
	
	/**
	 * Parent lesson
	 * @type WorkbookLesson
	 */
	var parent = exerciseTypeParent;
	
	/**
	 * Id
	 * @type Number
	 */
	var id = exerciseTypeId;
	
	/**
	 * Caption
	 * @type String
	 */
	var caption = exerciseTypeCaption;
	
	/**
	 * Price
	 * @type Number
	 */
	var price = Number(exerciseTypePrice);
	
	/**
	 * Selected state
	 * @type Boolean
	 */
	var selected = ( exerciseTypeSelected == true ? true : false );
	
	/**
	 * Status
	 * @type String
	 */
	var status = exerciseTypeStatus;
	
	/**
	 * Color
	 * @type String
	 */
	var color = exerciseTypeColor;
	
	/**
	 * Returns parent lesson
	 * @return Parent lesson
	 * @type WorkbookLesson
	 */
	this.getParent = function() {
		return parent;
	}
	
	/**
	 * Sets parent lesson
	 * @param WorkbookLesson Parent lesson
	 */
	this.setParent = function(exerciseTypeParent) {
		parent = exerciseTypeParent;
	}
	
	/**
	 * Returns id
	 * @return Id
	 * @type Number
	 */
	this.getId = function() {
		return id;
	}
	
	/**
	 * Sets id
	 * @param Number Id
	 */
	this.setId = function(exerciseTypeId) {
		id = exerciseTypeId;
	}
	
	/**
	 * Returns caption
	 * @return Caption
	 * @type String
	 */
	this.getCaption = function() {
		return caption;
	}
	
	/**
	 * Sets caption
	 * @param String Caption
	 */
	this.setCaption = function(exerciseTypeCaption) {
		caption = exerciseTypeCaption;
	}
	
	/**
	 * Returns price
	 * @return Price
	 * @type Number
	 */
	this.getPrice = function() {
		return price;
	}
	
	/**
	 * Sets price
	 * @param Number Price
	 */
	this.setPrice = function(exerciseTypePrice) {
		price = Number(exerciseTypePrice);
	}
	
	/**
	 * Returns status
	 * @return Status
	 * @type String
	 */
	this.getStatus = function() {
		return status;
	}
	
	/**
	 * Sets status
	 * @param String Status
	 */
	this.setStatus = function(exerciseTypeStatus) {
		status = exerciseTypeStatus;
	}
	
	/**
	 * Returns true if buyable
	 * @return True if buyable
	 * @type Boolean
	 */
	this.isBuyable = function() {
		return (status == "Megvásárolható" ? true : false);
	}
	
	/**
	 * Returns selected state
	 * @return Selected state
	 * @type Boolean
	 */
	this.isSelected = function() {
		return selected;
	}
	
	/**
	 * Sets selected flag
	 * @param Boolean Selected
	 */
	this.setSelected = function(exerciseTypeSelected) {
		selected = exerciseTypeSelected;
	}
	
	/**
	 * Returns color
	 * @return Color
	 * @type String
	 */
	this.getColor = function() {
		return color;
	}
	
	/**
	 * Sets color
	 * @param String Color
	 */
	this.setColor = function(exerciseTypeColor) {
		color = exerciseTypeColor;
	}
	
	/**
	 * Returns true if exercise is green
	 * @return True if green
	 * @type Boolean
	 */
	this.isBlue = function() {
		return (color == "blue" ? true : false);
	}
	
	/**
	 * Returns true if exercise is yellow
	 * @return True if yellow
	 * @type Boolean
	 */
	this.isYellow = function() {
		return (color == "yellow" ? true : false);
	}
	
	/**
	 * Returns true if exercise is orange
	 * @return True if orange
	 * @type Boolean
	 */
	this.isBrown = function() {
		return (color == "brown" ? true : false);
	}
	
}

/**
 * Video type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_VIDEO = 1;

/**
 * Warmup type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_WARMUP = 2;

/**
 * Reading type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_READING = 3;

/**
 * Understanding type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_UNDERSTANDING = 4;

/**
 * Grammar type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_GRAMMAR = 5;

/**
 * Grammaticex type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_GRAMMATICEX = 6;

/**
 * EverydayEnglish type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_EVERYDAYENGLISH = 7;

/**
 * Test type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_TEST = 8;

/**
 * Words type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_WORDS = 9;

/**
 * Homework type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_HOMEWORK = 10;

/**
 * Chat45 type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_CHAT45 = 11;

/**
 * ReadingExam type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_READINGEXAM = 12;

/**
 * Listening type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_LISTENING = 13;

/**
 * Writing type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_WRITING = 14;

/**
 * GrammarExam type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_GRAMMAREXAM = 15;

/**
 * Mediation type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_MEDIATION = 16;

/**
 * Speaking type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_SPEAKING = 17;

/**
 * TeacherEval type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_TEACHEREVAL = 18;

/**
 * Teacher45 type constant
 * @type Number
 */
WorkbookExerciseType.TYPE_TEACHER45 = 19;
/**
*  @constructor
*/
function WorkbookExerciseWords(pStudentId, pStudentName, pEng, pHun, pDate, pState, pExample, pComment) {
	
	/**
	* Student id
	* @type Number
	*/
	var studentId = new Number(pStudentId);
	
	/**
	 * Student name
	 * @type String
	 */
	var studentName = new String(pStudentName);
	
	/**
	 * Word in english
	 * @type String
	 */
	var eng = new String(pEng);
	
	/**
	 * Word in hungaryan
	 * @type String
	 */
	var hun = new String(pHun);
	
	/**
	 * Word adding date
	 * @type String
	 */
	var date = new String(pDate);
	
	/**
	 * Word state
	 * @type String
	 */
	var state = new String(pState);
	
	/**
	 * Word comment
	 * @type String
	 */
	var comment = new String(pComment);
	
	/**
	 * Words example
	 * @type String
	 */
	var example = new String(pExample);
	
	/**
	 * Return Student id
	 * @return Student id
	 * @type Number
	 */
	this.getStudentId = function() {
		return storyId;
	}
	
	/**
	 * Return Student name
	 * @return Student name
	 * @type String
	 */
	this.getStudentName = function() {
		return studentName;
	}
	
	/**
	 * Return Word in english
	 * @return Word in english
	 * @type String
	 */
	this.getEng = function() {
		return eng;
	}
	
	/**
	 * Return Word in hungaryan
	 * @return Word in hungaryan
	 * @type String
	 */
	this.getHun = function() {
		return hun;
	}
	
	/**
	 * Return Word adding date
	 * @return Word adding date
	 * @type String
	 */
	this.getDate = function() {
		return date;
	}
	
	/**
	 * Return Word adding formed date
	 * @return Word adding formed date
	 * @type String
	 */
	this.getFormedDate = function() {
		var formedDate = date;
		re = /-/gi;
		formedDate = formedDate.replace(re,'.');
		formedDate = formedDate.substring(0,19);
		return formedDate;
	}
	
	/**
	 * Return Word state
	 * @return Word state
	 * @type String
	 */
	this.getState = function() {
		return state;
	}
	
	/**
	 * Return Word example
	 * @return Word example
	 * @type String
	 */
	this.getExample = function() {
		return example;
	}
	
	/**
	 * Return Word comment
	 * @return Word comment
	 * @type String
	 */
	this.getComment = function() {
		return comment;
	}
}
/**
 * Lesson object in workbook
 * @param WorkbookLevel Parent level
 * @param Number Id
 * @param String Accessibility
 * @param Number Order
 * @param String Name
 * @param String Title
 * @param Number Bought percent of exercises
 * @constructor
 * @author Gábor, Horvath 'Koko' Kornel
 */
function WorkbookLesson(lessonParent, lessonId, lessonAccess, lessonOrder, lessonName, lessonTitle, lessonBoughtPercent) {
	/**
	 * Parent level
	 * @type WorkbookLevel
	 */
	var parent = lessonParent;
	
	/**
	 * Id
	 * @type String
	 */
	var id = lessonId;
	
	/**
	 * Accessibility
	 * @type String
	 */
	var access = lessonAccess;
	
	/**
	 * Order
	 * @type Number
	 */
	var order = lessonOrder;
	
	/**
	 * Name
	 * @type String
	 */
	var name = lessonName;
	
	/**
	 * Title
	 * @type String
	 */
	var title = lessonTitle;
	
	/**
	 * Data is loaded
	 * @type Boolean
	 */
	var loaded = false;
	
	/**
	 * Selected exercise id
	 * @type Number
	 */
	var selectedExerciseId;
	
	/**
	 * Bought percent of exercises
	 * @type Number
	 */
	var boughtPercent = lessonBoughtPercent;
	
	/**
	 * Is all exercise bought
	 * @type Boolean 
	 */
	var exercisesHasBought = false;
	
	/**
	 * Exercises map
	 * @type Map
	 */
	var exercises = new Map();
	
	/**
	 * ExerciseTypes map
	 * @type Map
	 */
	var types = new Map();
	
	/**
	 * Id of selected exercise
	 * @type Number
	 */
	var selectedExerciseId = 0;
	
	/**
	 * User notes for lesson
	 * @type String
	 */
	var notes = "";
	
	/**
	 * Are notes loaded
	 * @type Boolean
	 */
	var notesLoaded = false;
	
	/**
	 * Are notes opened
	 * @type Boolean
	 */
	var notesOpened = false;
	
	/**
	 * Pointer to this
	 * @type WorkbookLesson
	 */
	var self = this;
	
	/**
	 * Returns selected exercise id
	 * @return Id of selected exercise 
	 * @type Number
	 */
	this.getSelectedExerciseId = function() {
		return selectedExerciseId;
	}
	
	/**
	 * Sets selected exercise id
	 * @param Number Id of selected exercise
	 */
	this.setSelectedExerciseId = function(exerciseId) {
		selectedExerciseId = exerciseId;
		document.cookie = "exercise=" + exerciseId;
	}
	
	/**
	 * Returns parent level
	 * @return Parent level
	 * @type WorkbookLevel
	 */
	this.getParent = function() {
		return parent;
	}
	
	/**
	 * Sets parent level
	 * @param WorkbookLevel Parent level
	 */
	this.setParent = function(lessonParent) {
		parent = lessonParent;
	}
	
	/**
	 * Returns id
	 * @return Id
	 * @type Number
	 */
	this.getId = function() {
		return id;
	}
	
	/**
	 * Sets id
	 * @param Number Id
	 */
	this.setId = function(levelId) {
		id = levelId;
	}
	
	/**
	 * Returns accessibility
	 * @return Accessibility
	 * @type String
	 */
	this.getAccess = function() {
		return access;
	}
	
	/**
	 * Sets accessibility
	 * @param String Accessibility
	 */
	this.setAccess = function(lessonAccess) {
		access = lessonAccess;
	}
	
	/**
	 * Returns order
	 * @type Number
	 */
	this.getOrder = function() {
		return order;
	}
	
	/**
	 * Sets order
	 * @param Number order
	 */
	this.setOrder = function(lessonOrder) {
		order = lessonOrder;
	}
	
	/**
	 * Returns name
	 * @return Name
	 * @type String
	 */
	this.getName = function() {
		return name;
	}
	
	/**
	 * Sets name
	 * @param String Name
	 */
	this.setName = function(lessonName) {
		name = lessonName;
	}
	
	/**
	 * Returns title
	 * @return Title
	 * @type String
	 */
	this.getTitle = function() {
		return title;
	}
	
	/**
	 * Sets title
	 * @param String Title
	 */
	this.setTitle = function(lessonTitle) {
		title = lessonTitle;
	}
	
	/**
	 * Is data loaded
	 * @return Is data loaded
	 * @type Boolean
	 */
	this.isLoaded = function() {
		return loaded;
	}
	
	/**
	 * Notes are opened
	 * @return Notes are opened
	 * @type Boolean 
	 */
	this.notesOpened = function() {
		return notesOpened;
	}
	
	/**
	 * Open notes
	 */
	this.openNotes = function() {
		if(notesOpened) {
			return;
		}
		notesOpened = true;
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
	}
	
	/**
	 * Close notes
	 */
	this.closeNotes = function() {
		if(!notesOpened) {
			return;
		}
		notesOpened = false;
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
	}
	
	/**
	 * Get user notes
	 * @return user notes
	 * @type String
	 */
	this.getNotes = function() {
		return notes;
	}
	
	/**
	 * Set user notes
	 */
	this.setNotes = function() {
		var notesTA = $('lessonNotesTA').value;
		notes = notesTA;
		return;
	}
	
	/**
	 * Clear notes content
	 * Update in db
	 */
	this.clearNotes = function(pForce) {
		if(!pForce) {
			engine.dialogManager.add(new Dialog(
				"Biztosan törölni akarod?",
				"confirm",
				[ null, function () { self.clearNotes(true); }, null ],
				[ "", "Igen", "Nem" ])
				);
		} else {
			var notesTA = $('lessonNotesTA');
			notesTA.value = "";
			notes = "";
			self.saveNotes(false);
		}
	}
	
	/**
	 * Load notes from db
	 */
	this.loadNotes = function(pCurrentLesson) {
		var oldLesson = pCurrentLesson;
		
		if(notesLoaded) {
			return true;
		}
		
		comm = new CommGateRequest(
			"REQ_ACCESS",
			[ "ESULI_STUDENT_GET_LESSON_NOTES" ],
			function(response) {
				var data = response[0].getDataAsObjectArray();

				if(data) {
					notes = decodeSpecialCharsFieldValue(data[0].notes);
				}

				notesLoaded = true;
				if (self.getId() == oldLesson && self.notesOpened()) {
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, esuli.contentManager.getLastPage()));
				}
			}
		);

		comm.addDataLevel([ [ "LESSONID" ], [ self.getId() ] ]);
		engine.commGate.sendWithSession([ comm ]);
		return false;
	}
	
	/**
	 * Save notes to db
	 */
	this.saveNotes = function(pDialog) {
		var notesTA = $('lessonNotesTA').value;
		
		comm = new CommGateRequest(
			"REQ_ACCESS",
			[ "ESULI_STUDENT_ADD_LESSON_NOTES" ],
			function(pResponse) {
				var comm0 = pResponse[0].getCommandLine();
				if( comm0[2] == 1 ) {
					if(pDialog) {
						engine.dialogManager.add(new Dialog("Jegyzetek elmentve!", "alert", [ null, null ,null ]));
					}
				} else {
					engine.dialogManager.add(new Dialog("Probléma a feldolgozás során, kérlek próbáld újra!", "alert"));
				}
			}
		);

		comm.addDataLevel([ [ "LESSONID", "NOTES" ], [ self.getId(), encodeSpecialCharsFieldValue(notesTA) ] ]);
		engine.commGate.sendWithSession([ comm ]);
	}
	
	/**
	 * Open lesson ntes print window
	 */
	this.openNotesPrintPage =function() {
		var printNotesTitle = parent.getCaption() + " - " + title;
		var printNotes = notes;
	    	printNotes = printNotes.replace(/\n/g, "<br />");
	    	printNotes = printNotes.replace(/\r/g, "<br />");
		
		var notesPrintPageContent =  engine.templateManager.getTemplate("workbook_lessonnotesprint").process({ title: printNotesTitle, notes: printNotes });
		var notesPrintPage = window.open('','mywin','left=40,top=40,width=600,height=400,toolbar=0,resizable=0,scrollbars=yes');
			notesPrintPage.document.write(notesPrintPageContent);
			notesPrintPage.document.close();
	}
	
	/**
	 * Listens for user login event
	 * @param Event Event of login
	 */
	this.listenUserLogin = function(event) {
		exercises.map(function(exercise) {
			exercise.listenUserLogin(event);
		});
	}
	
	/**
	 * Buys the specified exerciseType
	 * @param Number Id of exerciseType
	 */
	this.buyExerciseType = function(exerciseTypeId) {
		types.get(exerciseTypeId).setStatus("Megoldandó");
		
		var exercise;
		var it = exercises.values().iterator();
		
		while (it.hasNext()) {
			exercise = it.next();
			
			if (exercise.getType() == exerciseTypeId) {
				exercise.setStatus("Megoldandó");
			}
		}
	}
	
	/**
	 * Returns the total price of the selected exercises
	 * @return Total price of the selected exercises
	 * @type Number
	 */
	this.getTotalPrice = function() {
		var allBlueSelected = true;
		var type;
		var it = types.values().iterator();
		while (it.hasNext()) {
			type = it.next();
			
			if (type.isBlue() && ! type.isSelected()) {
				allBlueSelected = false;
				break;
			}
		}
		
		var totalPrice = (allBlueSelected ? (parent.isExam() ? 1200 : 500) : 0);
		var it = types.values().iterator();
		while (it.hasNext()) {
			type = it.next();
			if ((! type.isBlue() || ! allBlueSelected) && (type.isSelected())) {
				totalPrice += type.getPrice();
			}
		}
		
		return totalPrice;
	}
	
	/**
	 * Returns first acceptable exercise id
	 * @return First acceptable exercise id
	 * @return Number
	 */
	this.getFirstExerciseId = function() {
		if (exercises.isEmpty()) {
			return 0;
		}
		
		var it = exercises.values().iterator();
		var exercise;
		
		while (it.hasNext()) {
			exercise = it.next();
			
			if (! exercise.isBuyable()) {
				return exercise.getId();
			}
		}
		
		return exercises.values().iterator().next().getId();
	}
	
	/**
	 * Calculates exercise states
	 */
	this.calculateExerciseStates = function() {
		if (exercises.isEmpty()) {
			return;
		}
		
		var totalTypes = types.size();
		var boughtTypes = 0;
		
		var it = exercises.values().iterator();
		var exercise;
		
		while (it.hasNext()) {
			exercise = it.next();
			
			if (! exercise.isBuyable()) {
				if (selectedExerciseId == 0) {
					selectedExerciseId = exercise.getId();
				}
				
				boughtTypes++;
			}
		}
		
		if (selectedExerciseId == 0) {
			selectedExerciseId = exercises.values().iterator().next().getId();
		}
		
		boughtPercent = (boughtTypes * 100) / totalTypes;
	}
	
	/**
	 * Returns bought percent of exercises
	 * @return Bought percent of exercises
	 * @type Number
	 */
	this.getBoughtPercent = function() {
		return boughtPercent;
	}
	
	/**
	 * Sets bought percent of exercise
	 * @param Number Bought percent of exercise
	 */
	this.setBoughtPercent = function(lessonBoughtPercent) {
		boughtPercent = lessonBoughtPercent
	}
	
	/**
	 * Returns the specified exercise
	 * @param Number Id of exercise
	 * @return Found exercise
	 * @type WorkbookExercise
	 */
	this.getExercise = function(exerciseId) {
		return exercises.get(exerciseId);
	}
	
	/**
	 * Returns the specified exerciseType
	 * @param Id Id of exerciseType
	 * @return Found exerciseType
	 * @type WorkbookExerciseType
	 */
	this.getExerciseType = function(exerciseTypeId) {
		return types.get(exerciseTypeId);
	}
	
	/**
	 * Returns all exercises
	 * @param String Callback page name
     * @param Boolean backFire whether fire EVENT_LESSON_LOADED event on load
	 * @return All exercises
	 * @type Map
	 */
	this.getExercises = function(callbackPage,backFire) {
		if (! loaded) {
			loadExercises(callbackPage,backFire);
		} 
		else if ( backFire )
        {
        	engine.eventManager.invoke(new Event(self, EventManager.EVENT_LESSON_LOADED, { id : id }));
        }

		return exercises;
	}
	
	/**
	 * Returns all exerciseTypes
	 * @param String Callback page name
	 * @return All exerciseTypes
	 * @type Map
	 */
	this.getExerciseTypes = function(callbackPage) {
		if (! loaded) {
			loadExercises(callbackPage);
		}
		
		return types;
	}
	
	/**
	 * Loads data from database
	 * @param Object Callback page request
     * @param Boolean backFire whether fire EVENT_LESSON_LOADED event on load
	 */
	function loadExercises(callbackPage,backFire) {
		var oldSeq = esuli.contentManager.getSeq();
		
		var comm = new CommGateRequest(
			(! esuli.user.isLoggedIn() ? "REQ_SELECT" : "REQ_ACCESS"),
			[ "ESULI_GET_LESSONLIST" ],
			function(response) {
				exercises.clear();
				types.clear();
				
				var data = response[0].getDataAsObjectArray();
				
				var typesCounter = new Array();
				for (var i = 0; i < data.length; i++) {
					data[i].typename = data[i].title;
					if(!typesCounter[data[i].typename]) {
						typesCounter[data[i].typename] = 1;
					} else {
						typesCounter[data[i].typename]++;
					}
					data[i].typeorder = typesCounter[data[i].typename];
					
					if(data[i].typeorder > 1) {
						data[i].title += " " + data[i].typeorder;
					}				
				}
				
				var color;
				for (var i = 0; i < data.length; i++) {
					if((data[i].typeorder == 1) && (typesCounter[data[i].typename] > 1)) {
						data[i].title += " 1";
					}
					switch (data[i].code) {
						case "Zöld": color = "blue"; break;
						case "Sárga": color = "yellow"; break;
						case "Narancs": color = "brown"; break;
					}
					
					exercises.put(data[i].id, new WorkbookExercise(self, data[i].id, data[i].type, data[i].typeorder, color, data[i].state, data[i].filename, data[i].title, data[i].resultpercent, data[i].comment));
					
					if (! types.containsKey(data[i].type)) {
						var selected = data[i].state != "Megvásárolható" ? true : false ;
						types.put(data[i].type, new WorkbookExerciseType(self, data[i].type, data[i].typename, color, data[i].prize, data[i].state, selected ));
					}
					
				}
				
				self.calculateExerciseStates();
				loaded = true;
				if (callbackPage != undefined && oldSeq == esuli.contentManager.getSeq()) {
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, callbackPage));
				}
				if ( backFire )
				{
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LESSON_LOADED, { id: id }));
				}
			}
		);
		
		comm.addDataLevel([ [ "LESSONID" ], [ id ] ]);
		engine.commGate.sendWithSession([ comm ]);
	}
	
}
/**
 * Lesson page in workbook module
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function WorkbookLessonPage() {
	
	/**
	 * Id of current lesson
	 * @type Number
	 */
	var currentLessonId = 0;
	
	/**
	 * Returns lesson list page
	 * @param Object Page request object
	 * @return Requested page
	 * @type Object
	 */
	this.getPage = function(pageRequest) {
		currentLessonId = pageRequest.get("lessonId");
		
		var levelId = pageRequest.get("levelId");
		var level = esuli.workbook.getLevel(levelId);
		var lesson = level.getLesson(currentLessonId);
		
		esuli.workbook.levelPage.setCurrentLevelId(levelId);
		level.setSelectedLessonId(currentLessonId);
		
		if (check(pageRequest.get("exerciseId"))) {
			lesson.setSelectedExerciseId(pageRequest.get("exerciseId"));
		} else {
			lesson.setSelectedExerciseId(lesson.getFirstExerciseId());
		}
		esuli.workbook.exercisePage.setCurrentExerciseId(lesson.getSelectedExerciseId());
		
		var page = {
			leftWidth: "225px",
			centerWidth: "518px",
			rightWidth: "225px",
			left: engine.templateManager.getTemplate("contentspin").process({}),
			center: engine.templateManager.getTemplate("contentspin").process({}),
			right: engine.templateManager.getTemplate("contentspin").process({})
		}
		
		if (lesson.getBoughtPercent() == 0 && lesson.getAccess() != "Ingyenes") {
			engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { tabId: esuli.tab.activeTabId, subId: esuli.tab.activeSubMenuId, module: "workbook", page: "lessonList", levelId: pageRequest.get("levelId") }));
			return page;
		}
		
		page.extend({
			leftWidth: "195px",
			centerWidth: "548px",
			rightWidth: "225px"
		});
		
		var exercises = lesson.getExercises(pageRequest);
		
		if (exercises.isEmpty()) {
			return page;
		}
		
		var title = engine.templateManager.getTemplate("workbook_lessontitle").process({ level: level, lesson: lesson, page: self });
		page.extend({centerTop: title });
		
		var notes = engine.templateManager.getTemplate("workbook_lessonnotes").process({ level: level, lesson: lesson, page: self });
		page.extend({rightTop: notes });
		
		pageRequest.put("exerciseId", lesson.getSelectedExerciseId());
		
		page.left = engine.templateManager.getTemplate("workbook_exerciselist").process({ level: level, lesson: lesson, page: self });	
		page.center = esuli.workbook.exercisePage.getPage(pageRequest);
		
		var dictionary = engine.templateManager.getTemplate("workbook_dictionary").process({});
		var question = engine.templateManager.getTemplate("workbook_question").process({});
		var observations = esuli.workbook.exercisePage.getObservations(pageRequest);
		
		page.right = dictionary + question + observations;

		return page;
	}
	
	/**
	 * Returns current lesson id
	 * @return Id of current lesson
	 * @type Number
	 */
	this.getCurrentLessonId = function() {
		return currentLessonId;
	}
	
	/**
	 * Sets current lesson id
	 * @param Number Id of current lesson
	 */
	this.setCurrentLessonId = function(lessonId) {
		currentLessonId = lessonId;
	}
	
	/**
	 * Show the specified exercise
	 * @param Number Id of exercise
	 */
	this.showExercise = function(exerciseId) {
		var level = esuli.workbook.getLevel(esuli.workbook.levelPage.getCurrentLevelId());
		var lesson = level.getLesson(currentLessonId);
		lesson.setSelectedExerciseId(exerciseId);
		
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { tabId: esuli.tab.activeTabId, subId: esuli.tab.activeSubMenuId, module: "workbook", page: "exerciseList", levelId: level.getId(), lessonId: currentLessonId, exerciseId: exerciseId }));
	}
	
	/**
	 * Clears user solutions of exercises
	 */
	this.clearExercises = function() {
		var level = esuli.workbook.getLevel(esuli.workbook.levelPage.getCurrentLevelId());
		var lesson = level.getLesson(currentLessonId);
		var it = lesson.getExercises().values().iterator();
		
		while (it.hasNext()) {
			it.next().clear();
		}
		
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { tabId: esuli.tab.activeTabId, subId: esuli.tab.activeSubMenuId, module: "workbook", page: "exerciseList", levelId: level.getId(), lessonId: lesson.getId() }));
	}
	
	/**
	 * Sets type selection
	 * @param Number Id of type
	 * @param Boolean Is selected
	 */
	this.setExerciseSelected = function(typeId, selected) {
		var level = esuli.workbook.getLevel(esuli.workbook.levelPage.getCurrentLevelId());
		var lesson = level.getLesson(currentLessonId);
		
		lesson.getExerciseType(typeId).setSelected(selected);
		
		if (selected && lesson.getExerciseType(WorkbookExerciseType.TYPE_WORDS) != null) {
			lesson.getExerciseType(WorkbookExerciseType.TYPE_WORDS).setSelected(selected);
		}
		
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { tabId: esuli.tab.activeTabId, subId: esuli.tab.activeSubMenuId, module: "workbook", page: "lessonList", levelId: level.getId() }));
	}
	
}
/**
 * Level object in workbook.
 * @param String Id
 * @param String Caption
 * @constructor
 * @author Gábor, Horvath 'Koko' Kornel
 */
function WorkbookLevel(levelId, levelCaption, levelType) {
	
	/**
	 * Id
	 * @type String
	 */
	var id = levelId;
	
	/**
	 * Caption
	 * @type String
	 */
	var caption = levelCaption;
	
	/**
	 * Type
	 * @type String
	 */
	var type = levelType;

	/**
	 * Data loaded
	 * @type Boolean
	 */
	var loaded = false;

	/**
	 * Lessons array
	 * @type Array
	 */
	var lessons = new Map();
	
	/**
	 * Id of selected lesson
	 * @type Number
	 */
	var selectedLessonId = 0;
	
	/**
	 * Pointer to this
	 * @type WorkbookLevel
	 */
	var self = this;
	
	/**
	 * Returns id
	 * @return Id
	 * @type String
	 */
	this.getId = function() {
		return id;
	}
	
	/**
	 * Sets id
	 * @param String Id
	 */
	this.setId = function(levelId) {
		id = levelId;
	}
	
	/**
	 * Returns caption
	 * @return Caption
	 * @type String
	 */
	this.getCaption = function() {
		return caption;
	}
	
	/**
	 * Sets caption
	 * @param String Caption
	 */
	this.setCaption = function(levelCaption) {
		caption = levelCaption;
	}
	
	/**
	 * Get type
	 * @return Type
	 * @type String
	 */
	this.getType = function() {
		return type;
	}
	
	/**
	 * Returns selected lesson id
	 * @return Id of selected lesson 
	 * @type Number
	 */
	this.getSelectedLessonId = function() {
		return selectedLessonId;
	}
	
	/**
	 * Sets selected lesson id
	 * @param Number Id of selected lesson
	 */
	this.setSelectedLessonId = function(lessonId) {
		selectedLessonId = lessonId;
	}
	
	/**
	 * Returns true if level is exam
	 * @return True if exam
	 * @type Boolean
	 */
	this.isExam = function() {
		return (id.indexOf("EU-") > -1 ? true : false);
	}
	
	/**
	 * Retunr true if level is lodaded
	 * @retunr true if loaded, false if not
	 * @type Boolean
	 */
	this.isLoaded = function() {
		return loaded;
	}
	
	/**
	 * Listens for user login event
	 * @param Event Event of login
	 */
	this.listenUserLogin = function(event) {
		if (lessons.size() == 0) {
			return;
		}
		
		lessons.map(function(lesson) {
			lesson.listenUserLogin();
		});
		
		loaded = false;
		
		loadLessons();
	}

	/**
	 * Returns lesson
	 * @param Number Level id
	 * @return Lesson
	 * @type WorkbookLesson
	 */
	this.getLesson = function(lessonId) {
		return lessons.get(lessonId);
	}
	
	/**
	 * Returns lessons
	 * @param Object Callback page request
	 * @return Lessons
	 * @type Map
	 */
	this.getLessons = function(callbackPage,backFire) {
		if (! loaded) {
			loadLessons(callbackPage,backFire);
		}
		else if ( backFire )
		{
            engine.eventManager.invoke(new Event(self, EventManager.EVENT_LEVEL_LOADED, { id: id } ));
		}

		return lessons;
	}

	/**
	 * Loads data from database
	 */
	function loadLessons(callbackPage,backFire) {
		var oldSeq = esuli.contentManager.getSeq();

		var comm = new CommGateRequest(
			(! esuli.user.isLoggedIn() ? "REQ_SELECT" : "REQ_ACCESS"),
			[ "ESULI_GET_PACKAGELIST" ],
			function(response) {
				lessons.clear();
				
				var data = response[0].getDataAsObjectArray();

				if( data && data.length != 0 ) {
					for (var i = 0, seq = (data[0].access == "Ingyenes" ? 0 : 1); i < data.length; i++, seq++) {
						lessons.put(data[i].id, new WorkbookLesson(self, data[i].id, data[i].access, seq, data[i].name, data[i].title, Number(data[i].boughtpercent)));
					}
				}
				
				loaded = true;
				
				if (callbackPage != undefined && oldSeq == esuli.contentManager.getSeq()) {
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, callbackPage));
				} else if (
					callbackPage == undefined &&
					esuli.workbook.levelPage.getCurrentLevelId() == id &&
					esuli.contentManager.getLastPage().get("module") == "workbook"
				) {
					engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { tabId: esuli.tab.activeTabId, subId: esuli.tab.activeSubMenuId, module: "workbook", page: "lessonList", levelId: id }));
				}

				if ( backFire )
        		{
            		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LEVEL_LOADED, {id : id }));
        		}
			}
		);

		comm.addDataLevel([ [ "LEVELID" ], [ id ] ]);
		engine.commGate.sendWithSession([ comm ]);
	}

}
/**
 * Level page in workbook module
 * @constructor
 * @author Horvath 'Koko' Kornel
 */
function WorkbookLevelPage() {
	
	/**
	 * Id of current level
	 * @type String
	 */
	var currentLevel = "A1-1";
	
	/**
	 * Returns lesson list page
	 * @param Object Page request object
	 * @return Requested page
	 * @type Object
	 */
	this.getPage = function(pageRequest) {
		currentLevel = pageRequest.get("levelId") ? pageRequest.get("levelId") : currentLevel;
		
		var page = {
			leftWidth: "225px",
			centerWidth: "518px",
			rightWidth: "225px",
			center: engine.templateManager.getTemplate("contentspin").process({}),
			left: engine.templateManager.getTemplate("workbook_typeselect").process({})
		}
		
		var level = esuli.workbook.getLevel(currentLevel);
		var lessons = level.getLessons(pageRequest);
		
		if (lessons.isEmpty()) {
			if( level.isLoaded() ) {
				page.extend({ center: engine.templateManager.getTemplate("workbook_emptylist").process({selected: level.getCaption()}) });
			}
			return page;
		}
		
		page.center = engine.templateManager.getTemplate("workbook_lessonlist").process({ level: level, lessons: lessons, page: self, selected: level.getCaption()});
		
		if (level.getSelectedLessonId() != 0) {
			esuli.workbook.lessonPage.setCurrentLessonId(level.getSelectedLessonId());
			var lesson = lessons.get(level.getSelectedLessonId());
			var exercises = lesson.getExercises(pageRequest);
			
			if (exercises.isEmpty()) {
				return page.extend({ left: engine.templateManager.getTemplate("contentspin").process({}) });
			}

			page.extend({ left: engine.templateManager.getTemplate("workbook_typeselect").process({}) });
		}
		
		return page;
	}
	
	/**
	 * Returns current level id
	 * @return Id of current level
	 * @type String
	 */
	this.getCurrentLevelId = function() {
		return currentLevel;
	}
	
	/**
	 * Sets current level id
	 * @param String Id of current level
	 */
	this.setCurrentLevelId = function(levelId) {
		currentLevel = levelId;
	}
	
	/**
	 * Click on lesson button
	 * @param Number Lesson id
	 */
	this.showLesson = function(lessonId) {
		esuli.workbook.getLevel(currentLevel).setSelectedLessonId(lessonId);
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { tabId: esuli.tab.activeTabId, subId: esuli.tab.activeSubMenuId, module: "workbook", page: "exerciseList", levelId: currentLevel, lessonId: lessonId }));
	}
}
/**
 * 
 */
function Recorder() {
	
	/**
	 * Pointer to this
	 * @type Recorder
	 */
	var self = this;
	
	/**
	 * is IE
	 */
	var isIE  = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false;
	
	/**
	 * is Win
	 */
	var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false;
	
	/**
	 * is Opera
	 */
	var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false;
	
	/**
	 * Major version of Flash required
	 */
	var requiredMajorVersion = 9;
	
	/**
	 * Minor version of Flash required
	 */
	var requiredMinorVersion = 0;
	
	/**
	 * Revision of Flash required
	 */
	var requiredRevision = 45;
	
	/**
	 *
	 */
	function controlVersion() {
		var version;
		var axo;
		var e;

		try {
			// version will be set for 7.X or greater players
			axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
			version = axo.GetVariable("$version");
		} catch (e) {
		}

		if (!version) {
			try {
				// version will be set for 6.X players only
				axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");

				// installed player is some revision of 6.0
				// GetVariable("$version") crashes for versions 6.0.22 through 6.0.29,
				// so we have to be careful. 

				// default to the first public version
				version = "WIN 6,0,21,0";

				// throws if AllowScripAccess does not exist (introduced in 6.0r47)		
				axo.AllowScriptAccess = "always";

				// safe to call for 6.0r47 or greater
				version = axo.GetVariable("$version");

			} catch (e) {
			}
		}

		if (!version) {
			try {
				// version will be set for 4.X or 5.X player
				axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");
				version = axo.GetVariable("$version");
			} catch (e) {
			}
		}

		if (!version) {
			try {
				// version will be set for 3.X player
				axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");
				version = "WIN 3,0,18,0";
			} catch (e) {
			}
		}

		if (!version) {
			try {
				// version will be set for 2.X player
				axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
				version = "WIN 2,0,0,11";
			} catch (e) {
				version = -1;
			}
		}

		return version;
	}
	
	/**
	 * JavaScript helper required to detect Flash Player PlugIn version information
	 */
	function getSwfVer() {
		// NS/Opera version >= 3 check for Flash plugin in plugin array
		var flashVer = -1;

		if (navigator.plugins != null && navigator.plugins.length > 0) {
			if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) {
				var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : "";
				var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description;
				var descArray = flashDescription.split(" ");
				var tempArrayMajor = descArray[2].split(".");			
				var versionMajor = tempArrayMajor[0];
				var versionMinor = tempArrayMajor[1];
				var versionRevision = descArray[3];
				if (versionRevision == "") {
					versionRevision = descArray[4];
				}
				if (versionRevision[0] == "d") {
					versionRevision = versionRevision.substring(1);
				} else if (versionRevision[0] == "r") {
					versionRevision = versionRevision.substring(1);
					if (versionRevision.indexOf("d") > 0) {
						versionRevision = versionRevision.substring(0, versionRevision.indexOf("d"));
					}
				}
				var flashVer = versionMajor + "." + versionMinor + "." + versionRevision;
			}
		}
		// MSN/WebTV 2.6 supports Flash 4
		else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4;
		// WebTV 2.5 supports Flash 3
		else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3;
		// older WebTV supports Flash 2
		else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2;
		else if ( isIE && isWin && !isOpera ) {
			flashVer = controlVersion();
		}	
		return flashVer;
	}
	
	/**
	 * When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available
	 */
	this.detectFlashVer = function() {
		versionStr = getSwfVer();
		if (versionStr == -1 ) {
			return false;
		} else if (versionStr != 0) {
			if(isIE && isWin && !isOpera) {
				// Given "WIN 2,0,0,11"
				tempArray         = versionStr.split(" "); 	// ["WIN", "2,0,0,11"]
				tempString        = tempArray[1];			// "2,0,0,11"
				versionArray      = tempString.split(",");	// ['2', '0', '0', '11']
			} else {
				versionArray      = versionStr.split(".");
			}
			var versionMajor      = versionArray[0];
			var versionMinor      = versionArray[1];
			var versionRevision   = versionArray[2];

	        	// is the major.revision >= requested major.revision AND the minor version >= requested minor
			if (versionMajor > parseFloat(requiredMajorVersion)) {
				return true;
			} else if (versionMajor == parseFloat(requiredMajorVersion)) {
				if (versionMinor > parseFloat(requiredMinorVersion))
					return true;
				else if (versionMinor == parseFloat(requiredMinorVersion)) {
					if (versionRevision >= parseFloat(requiredRevision))
						return true;
				}
			}
			return false;
		}
	}
	
	/**
	 * AC_AddExtension
	 */
	function acAddExtension(src, ext) {
		if (src.indexOf('?') != -1)
			return src.replace(/\?/, ext+'?'); 
		else
			return src + ext;
	}
	
	/**
	 * AC_Generateobj
	 */
	function acGenerateObj(objAttrs, params, embedAttrs)  { 
		var str = '';
		if (isIE && isWin && !isOpera) {
			str += '<object ';
			for (var i in objAttrs) {
				str += i + '="' + objAttrs[i] + '" ';
			}
			str += '>';
			for (var i in params) {
				str += '<param name="' + i + '" value="' + params[i] + '" /> ';
			}
			str += '</object>';
		} else {
			str += '<embed ';
			for (var i in embedAttrs) {
				if(i != "toMap" && i != "serialize" && i != "extend")
					str += i + '="' + embedAttrs[i] + '" ';
			}
			str += '> </embed>';
		}
		return str;
	}
	
	/**
	 * AC_FL_RunContent
	 */
	this.acFlRunContent = function() {
		var getArg = acGetArgs(arguments, ".swf", "movie", "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000", "application/x-shockwave-flash");
		var ret = acGenerateObj(getArg.objAttrs, getArg.params, getArg.embedAttrs);
		return ret;
	}
	
	/**
	 * AC_SW_RunContent
	 */
	this.acSwRunContent = function() {
		var get = acGetArgs(arguments, ".dcr", "src", "clsid:166B1BCA-3F9C-11CF-8075-444553540000", null);
		var ret = acGenerateObj(get.objAttrs, get.params, get.embedAttrs);
		return ret;
	}
	
	/**
	 * AC_GetArgs
	 */
	function acGetArgs(args, ext, srcParamName, classid, mimeType){
		var ret = new Object();
		ret.embedAttrs = new Object();
		ret.params = new Object();
		ret.objAttrs = new Object();
		for (var i=0; i < args.length; i=i+2) {
			var currArg = args[i].toLowerCase();
			
			switch (currArg) {	
				case "classid":
	        		break;
				case "pluginspage":
					ret.embedAttrs[args[i]] = args[i+1];
					break;
				case "src":
				case "movie":	
					args[i+1] = acAddExtension(args[i+1], ext);
					ret.embedAttrs["src"] = args[i+1];
					ret.params[srcParamName] = args[i+1];
					break;
				case "onafterupdate":
				case "onbeforeupdate":
				case "onblur":
				case "oncellchange":
				case "onclick":
				case "ondblclick":
				case "ondrag":
				case "ondragend":
				case "ondragenter":
				case "ondragleave":
				case "ondragover":
				case "ondrop":
				case "onfinish":
				case "onfocus":
				case "onhelp":
				case "onmousedown":
				case "onmouseup":
				case "onmouseover":
				case "onmousemove":
				case "onmouseout":
				case "onkeypress":
				case "onkeydown":
				case "onkeyup":
				case "onload":
				case "onlosecapture":
				case "onpropertychange":
				case "onreadystatechange":
				case "onrowsdelete":
				case "onrowenter":
				case "onrowexit":
				case "onrowsinserted":
				case "onstart":
				case "onscroll":
				case "onbeforeeditfocus":
				case "onactivate":
				case "onbeforedeactivate":
				case "ondeactivate":
				case "type":
				case "codebase":
				case "id":
					ret.objAttrs[args[i]] = args[i+1];
					break;
				case "width":
				case "height":
				case "align":
				case "vspace": 
				case "hspace":
				case "class":
				case "title":
				case "accesskey":
				case "name":
				case "tabindex":
					ret.embedAttrs[args[i]] = ret.objAttrs[args[i]] = args[i+1];
					break;
				default:
					ret.embedAttrs[args[i]] = ret.params[args[i]] = args[i+1];
			}
		}

		ret.objAttrs["classid"] = classid;
		if (mimeType)
			ret.embedAttrs["type"] = mimeType;
		
		return ret;
	}
}
/**
 * 
 */
function Workbook() {
	
	/**
	 * Last visited page
	 * @type Object
	 */
	var lastPage;
	
	/**
	 * Levels array
	 * @type Array
	 */
	var levels = new Map();
	
	/**
	 * Level page controller
	 * @type WorkbookLevelPage
	 */
	this.levelPage = new WorkbookLevelPage();
	
	/**
	 * Lesson page controller
	 * @type WorkbookLessonPage
	 */
	this.lessonPage = new WorkbookLessonPage();
	
	/**
	 * Exercise page controller
	 * @type WorkbookExercisePage
	 */
	this.exercisePage = new WorkbookExercisePage();
	
    /**
     * Color of the basic exercises
     * @type Object
     */
    var colorBasic;

    /**
     * Color of the exercises corrected by teacher
     * @type Object
     */
    var colorTeacher;

    /**
     * Color of the audio chat exercise
     * @type Object
     */
    var colorChat;

	/**
	 * Pointer to this
	 * @type Workbook
	 */
	var self = this;

	/**
	 * Listens for user login event
	 * @param Event Event of login
	 */
	this.listenUserLogin = function(event) {
		levels.map(function(level) {
			level.listenUserLogin();
		});
	}

	/**
	 * Returns the specified level
	 * @param Number Id
	 * @return Specified level
	 * @type WorkbookLevel
	 */
	this.getLevel = function(levelId) {
		return levels.get(levelId);
	}
	
	/**
	 * Returns levels array
	 * @return Levels array
	 * @type Map
	 */
	this.getLevels = function() {
		return levels;
	}
	
	/**
	 * Show selected lessons list 
	 * @param Level id
	 * @type String
	 */
	this.showLessonList = function(pLevleId) {
		engine.eventManager.invoke(new Event(self, EventManager.EVENT_LAYOUT_RELOAD, { tabId: esuli.tab.activeTabId, subId: esuli.tab.activeSubMenuId, module: "workbook", page: "lessonList", levelId: pLevleId }));
	}
	
	/**
	 * Returns requested page
	 * @param Object Page request
	 * @return Requested page
	 * @type Object
	 */
	this.getPage = function(pageRequest) {
		if (! check(pageRequest)) {
			//TODO: Log error
			return;
		}

		var page = {};
		
		switch (pageRequest.get("page")) {
			
			case "lessonList":
				page.extend(self.levelPage.getPage(pageRequest));
				break;
			
			case "exerciseList":
				page.extend(self.lessonPage.getPage(pageRequest));
				break;
			
			default:
				//TODO: Log error
		}
		
		lastPage = pageRequest;
		
		return page;
	}
	
	/**
	 * Returns last visited page
	 * @return Last visited page
	 * @type Object
	 */
	this.getLastPage = function() {
		self.getPage(lastPage);
	}
	
	//Initialize
	engine.eventManager.addListener(EventManager.EVENT_USER_LOGIN, self);
	
	levels.put("A0-0", new WorkbookLevel("A0-0", "Szintfelmérő", "normal"));
	levels.put("A1-1", new WorkbookLevel("A1-1", "Kezdő I.", "normal"));
	levels.put("A1-2", new WorkbookLevel("A1-2", "Kezdő II.", "normal"));
	levels.put("A2-1", new WorkbookLevel("A2-1", "Alapfok I.", "normal"));
	levels.put("A2-2", new WorkbookLevel("A2-2", "Alapfok II.", "normal"));
	levels.put("B1-1", new WorkbookLevel("B1-1", "Alapfok III.", "normal"));
	levels.put("B1-2", new WorkbookLevel("B1-2", "Alapfok IV.", "normal"));
	levels.put("B1-3", new WorkbookLevel("B1-3", "Középfok I.", "normal"));
	levels.put("B1-4", new WorkbookLevel("B1-4", "Középfok II.", "normal"));
	levels.put("B2-1", new WorkbookLevel("B2-1", "Középfok III.", "normal"));
	levels.put("B2-2", new WorkbookLevel("B2-2", "Középfok IV.", "normal"));
	levels.put("B2-3", new WorkbookLevel("B2-3", "Felső-közép I.", "normal"));
	levels.put("B2-4", new WorkbookLevel("B2-4", "Felső-közép II.", "normal"));
	levels.put("C1-1", new WorkbookLevel("C1-1", "Felsőfok I.", "normal"));
	levels.put("C1-2", new WorkbookLevel("C1-2", "Felsőfok II.", "normal"));
	levels.put("EU-1", new WorkbookLevel("EU-1", "Euro nyelvvizsga alapszint", "exam"));
	levels.put("EU-2", new WorkbookLevel("EU-2", "Euro nyelvvizsga középszint", "exam"));
	levels.put("OR-1", new WorkbookLevel("OR-1", "Origo nyelvvizsga alapszint", "exam"));
	levels.put("OR-2", new WorkbookLevel("OR-2", "Origo nyelvvizsga középszint", "exam"));
	levels.put("PE-1", new WorkbookLevel("PE-1", "Presentation English", "pre"));

	self.colorBasic = 'kék';
	self.colorTeacher = 'sárga';
	self.colorChat = 'narancs';
}
function encodeSpecialCharsFieldValue(pStr) {
    var wstr = new String(pStr);
    
    if (wstr == null) {
        return "";
    }
    
    wstr = wstr.replace(/"/g, "+#22+");
    wstr = wstr.replace(/'/g, "+#27+");
    wstr = wstr.replace(/,/g, "+#2c+");
    wstr = wstr.replace(/;/g, "+#3b+");
    wstr = wstr.replace(/\(/g, "+#28+");
    wstr = wstr.replace(/\)/g, "+#29+");
    wstr = wstr.replace(/\[/g, "+#5b+");
    wstr = wstr.replace(/\]/g, "+#5d+");
    wstr = wstr.replace(/\{/g, "+#7b+");
    wstr = wstr.replace(/\}/g, "+#7d+");
    wstr = wstr.replace(/\n/g, "+#0d+");
    wstr = wstr.replace(/\t/g, "+#09+");
    wstr = wstr.replace(/\r/g, "+#0a+");
    
    return wstr;
}

function decodeSpecialCharsFieldValue(pStr) {
    var wstr = new String(pStr);
    
    if (wstr == null) {
        return "";
    }
    
    wstr = wstr.replace(/\+#22\+/gi, "\"");
    wstr = wstr.replace(/\+#27\+/gi, "'");
    wstr = wstr.replace(/\+#2c\+/gi, ",");
    wstr = wstr.replace(/\+#3b\+/gi, ";");
    wstr = wstr.replace(/\+#28\+/gi, "(");
    wstr = wstr.replace(/\+#29\+/gi, ")");
    wstr = wstr.replace(/\+#5b\+/gi, "[");
    wstr = wstr.replace(/\+#5d\+/gi, "]");
    wstr = wstr.replace(/\+#7b\+/gi, "{");
    wstr = wstr.replace(/\+#7d\+/gi, "}");
    wstr = wstr.replace(/\+#0d\+/gi, "\n");
    wstr = wstr.replace(/\+#09\+/gi, "\t");
    wstr = wstr.replace(/\+#0a\+/gi, "\r");
    
    return wstr;
}

function processField(pString) {
    if (pString.length == 1) {
    	return pString;
    }
	
	var wstr = pString;
	
	//Írásjeleket levesszük elejéről végéről
    wstr = wstr.replace(/(!|\?|\.|\,|\s)$/, "");
    wstr = wstr.replace(/^(!|\?|\.|\,|\s)/, "");
    
	//Dupla space-ekete is levesszük
    wstr = wstr.replace(/\s\s/, "");
    
	//Szimpla idézőjeleket egyeségesítjük
    wstr = wstr.replace(/`|´/, "'");
    
    return wstr;
}
