/**
 * Module containing FlashApi functions
 * @author Priit Kervi (priit.kervi@regio.ee)
*/
FlashApi = {

	stack: new Array(),	
	loaded: false,
	
	/**
	* Use this function if you need to call some FlashApi function but not sure, if the flash component is already loaded.
	* The function will be put into stack. When MapCat component is loaded, all the functions in stack will be called in the order
	* they were put there. Example: 
	* FlashApi.run(function(){
	*	FlashApi.addComponent('navi','components/NavigationWindow/navi.swf')
	*});
	* @params {Function} fn the function to be called.
	*/
	run: function(fn) {
		if (this.loaded) {
			fn();
		} else {
			this.stack.push(fn);
		}
	},

	/** 
	 * Initializises FlashApi. Should be called after page is loaded and flash component is created (!). NB! Used if component is just written into html page.
	 */	
	init: function(flashId) {
		if (window[flashId]) {
			FlashApi.flash = window[flashId];
		} else if (document[flashId]) {
			FlashApi.flash = document[flashId];
		} else {
			alert("Error! JavaScript <-> Flash communication is not possible. Both window." + flashId + 
				" and document." + flashId + " are not defined");
		}
	},
	
	/** 
	   * Initializises FlashApi. Should be called after page is loaded and flash component is created (!). NB! Used if component is embed onto html page using AC_FL_RunContent function.
	   */
	 init2: function(flashId) {
		if (navigator.appName.indexOf("Microsoft") != -1) {
			FlashApi.flash = window[flashId];
		} else if (document[flashId]) {
			// if integrating flash by calling AC_FL_RunContent, there will be 2 objects with id == flashId, the first one will be object, and the second - embed
			FlashApi.flash = document[flashId].item(1); 
		} else {
			alert("Error! JavaScript <-> Flash communication is not possible. Both window." 
				+ flashId + " and document." + flashId + " are not defined");
		}
	},
	
	/**
	* Returns  MapCat component version information
	* @param {Object} specifiers additional parameters specifying function output (optional)
	* @param {Boolean} specifiers.full if true output will contain the whole information (optional)
	* @param return version info in JSON format. Info object can contain properties:
	* 	version 	- MapCat version
	* 	svn		- url of the branch in repository
	* 	revision	- closest svn revision number
	* 	date		- version date
	* @type Object
	*/
	getVersion: function(specifiers) {
		return FlashApi.flash.getVersion(specifiers);
	},
	
	// manipulations of objects at any type of layers
	////////////////////////////////////////////////////////////////////////
	
	/**
	* Calls the object onRollOver handler
	* @param {String} layerId id of the layer the object belongs to.
	* @param {String} objectId id of the object the onRollOver handler to be called
	*/
	callObjectOnRollOver: function(layerId, objectId) {
		FlashApi.flash.callObjectOnRollOver(layerId, objectId);
	},
	
	/**
	* Calls the object onRollOut handler
	* @param {String} layerId id of the layer the object belongs to.
	* @param {String} objectId id of the object the onRollOut handler to be called
	*/
	callObjectOnRollOut: function(layerId, objectId) {
		FlashApi.flash.callObjectOnRollOut(layerId, objectId);
	},	
	
	/**
	* The function is called by flash component when the object onRollOver is called
	* @param {String} object.objectId id of the object
	* @param {String} object.layerId id of the layer the object belongs to
	* @param {String} object.typeName name of the geometry type, e.g. MULTIPOLYGON
	* @param {Number} object.typeCode corresponding  code of the geometry type used inside flash component
	* @param {Object} object.onRollOver definition of action to be performed when mouse is over the object
	* @param {Object} object.onRollOver.action can be "tooltip", "displayinfo" or "javascript"
	* @param {Object} object.onRollOver.content onRollOver action input, e.g. text of the tooltip
	* @param {Object} object.onRelease definition of action to be performed when the object is clicked
	* @param {Object} object.onRelease.action can be "tooltip", "displayinfo", "javascript", "openurl"
	* @param {Object} object.onRelease.content onRelease action input, e.g. text to be shown in ino window
	*/
	objectOnMouseOver: function(object) {
		if (FlashApi.onObjectOnMouseOver) 
			FlashApi.onObjectOnMouseOver(object);
	},
	
	/**
	* The function is called by flash component when the object onRollOut is called
	* @param {String} object.objectId id of the object
	* @param {String} object.layerId id of the layer the object belongs to
	* @param {String} object.typeName name of the geometry type, e.g. MULTIPOLYGON
	* @param {Number} object.typeCode corresponding  code of the geometry type used inside flash component
	* @param {Object} object.onRollOver definition of action to be performed when mouse is over the object
	* @param {Object} object.onRollOver.action can be "tooltip", "displayinfo" or "javascript"
	* @param {Object} object.onRollOver.content onRollOver action input, e.g. text of the tooltip
	* @param {Object} object.onRelease definition of action to be performed when the object is clicked
	* @param {Object} object.onRelease.action can be "tooltip", "displayinfo", "javascript", "openurl"
	* @param {Object} object.onRelease.content onRelease action input, e.g. text to be shown in ino window
	*/
	objectOnMouseOut: function(object) {
		if (FlashApi.onObjectOnMouseOut) 
			FlashApi.onObjectOnMouseOut(object);
	},

	/**
	* The function is called by flash component when the object onRelease is called
	* @param {String} object.objectId id of the object
	* @param {String} object.layerId id of the layer the object belongs to
	* @param {String} object.typeName name of the geometry type, e.g. MULTIPOLYGON
	* @param {Number} object.typeCode corresponding  code of the geometry type used inside flash component
	* @param {Object} object.onRollOver definition of action to be performed when mouse is over the object
	* @param {Object} object.onRollOver.action can be "tooltip", "displayinfo" or "javascript"
	* @param {Object} object.onRollOver.content onRollOver action input, e.g. text of the tooltip
	* @param {Object} object.onRelease definition of action to be performed when the object is clicked
	* @param {Object} object.onRelease.action can be "tooltip", "displayinfo", "javascript", "openurl"
	* @param {Object} object.onRelease.content onRelease action input, e.g. text to be shown in ino window
	*/	
	objectOnMouseClicked: function(object) {
		if (FlashApi.onObjectOnMouseClicked) 
			FlashApi.onObjectOnMouseClicked(object);
	},
	
	/**
	* Sets object style to the specified one (object may belong to any layer)
	* @param {String} layerId id of the layer the object belongs to
	* @param {String} objectId id of the object
	* @param {Object} style id of the style (String) or style JSON representation
	* @param {String} symbol symbol of point object (optional, ignored by not point object)
	*/
	setObjectStyle: function(layerId, objectId, style, symbol) {
		FlashApi.flash.setObjectStyle(layerId, objectId, style, symbol);
	},	
	
	/**
	* The function is called by flash component when map is clicked (if object is clicked, onMapClicked event is thrown before onObjectOnMouseClicked event).
	* @param {Object} coords coordinates of mouse click (object with properties: e (east coordinate/longitude) and n (north coordinate/latitude))
	*/
	mapClicked: function(coords) {
		if (FlashApi.onMapClicked) 
			FlashApi.onMapClicked(coords);		
	},
	
	// end of manipulations of objects at any type of layers
	////////////////////////////////////////////////////////////////////////
	
	// system layers manipulation
	////////////////////////////////////////////////////////////////////////
	
	/** 
	 * Creates or replaces a system layer with given id
	 * @param id {String} system layer id
	 */	
	addSystemLayer: function(id) {
		FlashApi.flash.addSystemLayer(id);
	},
	
	/** 
	 * Removes the system layer with given id
	 * @param id {String} system layer id
	 */		
	removeSystemLayer: function(id) {
		FlashApi.flash.removeSystemLayer(id);
	},

	/** 
	 * Removes all objects from the system layer with given id
	 * @param id {String} unique layer id
	 */		
	clearSystemLayer: function(id) {
		FlashApi.flash.clearSystemLayer(id);
	},
	
	/** 
	 * Adds new object to system layer and applies given style.
	 * @param {String} layerId id of the system layer object should be added to
	 * @param {Object} attr has next parameters:
	 * @param {String} objectId id of the object to be added. Must be unique or the object with the id will be replaced.
	 * @param {String} typeName name of the object type (WKT types + RECTANGLE, CIRCLE and ELLIPSE, not needed if wkt is passed in). 
	 * @param {String} wkt wkt representation of object geometry (optional, if not specified, type and geo must be given).
	 * @param {Array} geo array of coordinates (not needed, if wkt is passed in). Its details depends on the object type. 
	 * @param {String} styleId id of the style to be applied to the object (optional, if not defined JSON style object should be given)
	 * @param {String} style JSON representaion of style (optional, if not defined style id must be specified)
	 * @param {String} tooltip tooltip to be shown on mouse over event
	 * @param {String} info info to be shown in info popup window (can be encoded HTML)
	 * @param {String} label label to be shown near point object if labels are on for the layer
	 * @param {String} symbolId id of the object symbol
	 * @param {Boolean} noRolloverEffect if object should not have visual roll over effect (false by default)
	 * @return {Boolean} true if object was successfully added
	 */
	addObjectToSystemLayer: function(layerId, attr) {
		FlashApi.flash.addObjectToSystemLayer(layerId, attr);
	},
	
	/** 
	 * Adds new point/multipoint object to the system layer and applies given style.
	 * @param layerId {String} system layer id
	 * @param attr {Object} has next parameters:
	 * @param {String} objectId id of the object to be added, Must be unique or the object with the id will be replaced.
	* @param {Array} geo array containing one point (for single point) or many points (for multipoint)
	 * @param {String} styleId id of the style to be applied to the object (optional, if not defined color and alpha must be specified)
	 * @param {String} color color of the point symbol(optional, if style not defined)
	 * @param {Number} alpha opacity of the point symbol (optional, if style not defined)
	 * @param {String} symbolId id of the object symbol
	 * @param {String} tooltip tooltip to be shown on mouse over event
	 * @param {String} info info to be shown in info popup window (can be encoded HTML)
	 * @param {String} label label to be shown near point object if labels are on for the layer
	 */	
	addPointToSystemLayer: function(layerId, attr) {
		FlashApi.flash.addPointToSystemLayer(layerId, attr);
	},
	
	/** 
	 * Adds new line object to the system layer and applies given style.
	 * @param layerId {String} system layer id
	 * @param attr {Object} has next parameters:
	 * @param {String} objectId id of the object to be added, Must be unique or the object with the id will be replaced.
	 * @param {Array} geo array of line points
	 * @param {String} styleId id of the style to be applied to the object (optional, if not defined colors, widths and alpha must be specified)
	 * @param {Array} colors colors of lines 
	 * @param {Array} widths  widths of lines
	 * @param {Number} alpha opacity of the line (optional, if style not defined)
	 * @param {String} tooltip tooltip to be shown on mouse over event
	 * @param {String} info info to be shown in info popup window (can be encoded HTML)
	 */	
	addLineToSystemLayer: function(layerId, attr) {
		FlashApi.flash.addLineToSystemLayer(layerId, attr);
	},
	
	/** 
	 * Adds new polygon object to the system layer and applies given style.
	 * @param layerId {String} system layer id
	 * @param attr {Object} has next parameters:
	 * @param {String} objectId id of the object to be added, Must be unique or the object with the id will be replaced.
	 * @param {Array} geo array of polygon points (it is not required the last point to be equal to the first one)
	 * @param {String} styleId id of the style to be applied to the object (optional, if not defined colors, alphas and border width must be specified)
	 * @param {String} lineColor color of the polygon border (optional, if style not defined)
	 * @param {Number} lineAlpha opacity of the polygon border (optional, if style not defined)
	 * @param {Number} lineWidth width of the polygon border (optional, if style not defined)
	 * @param {String} fillColor color of the polygon fill (optional, if style not defined)
	 * @param {Number} fillAlpha opacity of the polygon fill (optional, if style not defined)
	 * @param {String} tooltip tooltip to be shown on mouse over event
	 * @param {String} info info to be shown in info popup window (can be encoded HTML)
	 */		
	addPolygonToSystemLayer: function(layerId, attr) {
		FlashApi.flash.addPolygonToSystemLayer(layerId, attr);
	},

	/** 
	 * Shows heading defining arrow near point object.
	 * @param {String} layerId system layer id
	 * @param {String} objectId id of the object
	 * @param  {Number} azimuth azimuth (heading) the arrow should point to (0 - north, 90 - east etc)
	 */		
	showObjectAzimuthAtSystemLayer: function(layerId, objectId, azimuth) {
		FlashApi.flash.showObjectAzimuthAtSystemLayer(layerId, objectId, azimuth);
	},

	/** 
	 * Removes heading defining arrow near point object.
	 * @param {String} layerId system layer id
	 * @param {String} objectId id of the object
	 */			
	removeObjectAzimuthAtSystemLayer: function(layerId, objectId) {
		FlashApi.flash.removeObjectAzimuthAtSystemLayer(layerId, objectId);
	},	
	
	/** 
	 * Changes object coordinates
	 * @param {String} layerId system layer id
	 * @param {String} objectId id of the object to be relocated
	 * @param  {Array} coords coords array of the object coordinates
	 */	
	changeObjectCoordinatesAtSystemLayer: function(layerId, objectId, coords) {
		FlashApi.flash.changeObjectCoordinatesAtSystemLayer(layerId, objectId, coords);
	},
	
	/**
	* Changes the appearance of object at system layer.
	* @param {String} layerId id of the layer the object belongs to.
	* @param {String} objectId id of the object to be restyled. 
	* @param {Object} style JSON representation of style. 
	* e.g. {id:'temp', line:{alpha:80, lines:[{color:'000000', width:5}, {color:'ff0000', width:3}]}}
	* @param {String} symbol symbol id for point object (optional, ignored by not point objects)
	*/
	restyleObjectAtSystemLayer: function(layerId, objectId, style, symbol) {
		FlashApi.flash.restyleObjectAtSystemLayer(layerId, objectId, style, symbol);
	},
		
	/** 
	 * Removes object from the system layer
	 * @param {String} layerId system layer id
	 * @param {String} objectId  id of the object to be removed
	 */
	removeObjectFromSystemLayer: function(layerId, objectId) {
		FlashApi.flash.removeObjectFromSystemLayer(layerId, objectId);
	},

	/** 
	 * Centers to system layer so that all objects on it are shown on map
	 * @param {String} layerId system layer id
	 */	
	centerToSystemLayer: function(layerId) {
		FlashApi.flash.centerToSystemLayer(layerId);
	},
	
	
   /**
	* Creates tween object and starts tweening object properties.
	* @param {String} params.layerId id of the layer the object belongs to
	* @param {String} params.objectId id of object which property should be tweened
	* @param {Array} params.properties names of the properties to be tweened (current version supports only "location")
	* @param {Array} params.startValues start values of coresponding properties values 
	* (for “location” property it should be a point coordinates containing object with properties “e” for east coordinate and “n” for north coordinate. Example: {e: 659968, n: 6473785})
	* @param {Array} params.endValues end values of coresponding properties values
	* @param {Number} params.duration tween duration given in milliseconds
	* @param {Object} params.listener object representing tween events listener. 
	* It maps events names and appropriate js function names handling the events.
	* Supported events are:
	*	onMotionFinished — called when the tween reaches the end point;
	*	onMotionStopped — called when the tween is stopped;
	*	onMotionResumed - called when the tween is resumed.
	* @return	true if tweening has started. Otherwise (e.g. object with given id cannot be found) false.
	*/
	tweenObject: function(params) {
		return FlashApi.flash.tweenObject(params);
	},
	
	/**
	* Stops object's tween.
	* @param 	{String} layerId id of the layer the object belongs to
	* @param	{String} objectId id of the object
	* @return  true if there was a tween and it was stopped, false otherwise 
	*/
	stopObjectTween: function(layerId, objectId) {
		return FlashApi.flash.stopObjectTween(layerId, objectId);
	},
	
	/**
	* Resumes object's tween.
	* @param {String} layerId id of the layer the object belongs to
	* @param {String} objectId id of the object
	* @return true if there was a tween and it was resumed, false otherwise 
	*/
	resumeObjectTween: function(layerId, objectId) {
		return FlashApi.flash.resumeObjectTween(layerId, objectId);
	},
	
	/**
	* Stops and destroys object's tween.
	* @param 	{String} layerId id of the layer the object belongs to
	* @param	{String} objectId id of the object
	* @return  true if there was a tween and it was destroyed, false otherwise 
	*/
	destroyObjectTween: function(layerId, objectId) {
		return FlashApi.flash.destroyObjectTween(layerId, objectId);
	},
	
	// end of system layers manipulation
	////////////////////////////////////////////////////////////////////////

	/**
	* Shows/hides/reloads a layer.
	* @param {String} Lid id of the layer
	* @param {Number} checked 1 for true (show layer), 0 for false
	* @param {String} addUrl parameters to be added to the layer’s request URL (optional)
	* @param {Number} forceReload 1 for true (force layer reloading from server), 0 for false (default behaviour – reloads only if necessary)
	* @param {Object} addPost specified object properties will be send to the server as POST request parameters (optional)
	*/
	checkLayer: function(Lid, checked, addUrl, forceReload, addPost) {
		args = {Lid:Lid, checked:Number(checked), addUrl:addUrl, forceReload:forceReload, addPost:addPost};
		FlashApi.flash.checkLayerJS(args);
	},
	
	/**
	* Loads layer data.
	* @param {String} layerId id of the layer
	* @param {Object} parameters optional parameters specifying the way layer data is loaded
	* @param {String} parameters.addUrl parameters to be added to the layers request URL (optional)
	* @param {Object} parameters.addPost specified object properties will be send to the server as POST request parameters (optional)
	* @param {Boolean} parameters.forceReload true to force layer reloading from server, false to reload only if necessary (default)
	* @param {Boolean} parameters.clear true to remove all objects on layer, false to preserve all objects (default)
	* @param {Boolean} parameters.optimize true to enable optimization, false to switch off optimization (optional, if not specified optimization is applied if it is on)
	*/
	loadLayer: function(layerId, parameters) {
		FlashApi.flash.loadLayer(layerId, parameters);
	},

	/**
	* Shows/hides/reloads many layers at one time. 
	* @param {Array} layers an array of layers attributes (attributes are the same, as input parameters of FlashApi.checkLayer function. NB! Attribute names are case sensetive.)
	*/
	checkLayerArr: function(layers) {
		FlashApi.flash.checkLayerArrJS(layers);
	},

	/** 
	 * Removes objects from layer
	 * @param {String} layerId layer id
	 * @param {Array} objectsIds ids of the objects to be removed. Optional, if not specified all objects will be deleted. If an empty array is passed in no object will be deleted.
	 */
	removeObjects: function(layerId, objectsIds) {
		FlashApi.flash.removeObjects(layerId, objectsIds);
	},	
	
	/**
	* Centers map to object with obID.
	* @param {String} layerId id of the layer the object belongs to
	* @param {String} objectId id of the object to be centered to
	* @param {String} addUrl parameters to be added to the layer’s request URL (optional)
	* @param(String) zoom zoom to specified zoom level (optional)
	*/
	centerToObject: function(layerId, objectId, addUrl, zoom) {
		args = {Lid:layerId, obId:objectId, addUrl:addUrl, zoom:zoom};
		FlashApi.flash.centerToObjectJS(args);
	},

	/**
	* Centers and zooms map so that all objects on layer are visible.
	* @param {String} layerId id of the layer
	* @param {String} addUrl parameters to be added to the layer’s request URL (optional)
	*/
	centerToLayer: function(layerId, addUrl) {
		args = {Lid:layerId, addUrl:addUrl};
		FlashApi.flash.centerToLayerJS(args);
	},
	
	/**
	* Centers and zooms map so that all objects on layers are visible.
	* @param {Array} layers array of layers to be centered on. Each array element is an object with parameters:
	* 	Lid id of the layer
	*	addUrl parameters to be added to the layer’s request URL (optional)
	* 	forceReload 1 for true (force layer reloading from server), 0 for false (default behaviour – reloads only if necessary)
	*/
	centerToMultyLayers: function(layers) {
		FlashApi.flash.centerToMultyLayersJS(layers);
	},

	/**
	* Centers and zooms map to given east and north coordinates. The zoom parameter is optional – uses current zoom if omitted.
	* @param {Number} e east coordinate of new map view center
	* @param {Number} n north coordinate of new map view center
	* @param {Number} zoom new map zoom level (optional, if omitted, the zoom level will stay the same)
	*/
	centerMap: function(e, n, zoom) {
		FlashApi.flash.centerMapJS({e:e, n:n, zoom:zoom});
	},
	
	/**
	* Centers map to show area defined by specified bounding box.
	* @param args bounding box object (coordinates may be geographical or cartesian, 
	* must be in the same srs, as map is defined in map configuration.) with extra optional arguments
	* @param args.min_e east coordinate of bounding box lower-left corner
	* @param args.min_n north coordinate of bounding box lower-left corner
	* @param args.max_e east coordinate of bounding box upper-right corner
	* @param args.max_n north coordinate of bounding box upper-right corner
	* @param args.min_zoom minimum final zoom level (optional). NB! If specified value is outside map zoom range, it is ignored.
	* @param args.max_zoom maximum final zoom level (optional). NB! If specified value is outside map zoom range, it is ignored.
	* @param args.zoom defines final zoom level. If specified, min_zoom and max_zoom are ignored (optional). NB! If specified value is outside map zoom range, it is ignored.
	*/	
	centerMapToBbox: function(args) {
		FlashApi.flash.centerMapToBbox(args);
	},
		
	/**
	* Shows search result symbol at specified location with specified text inside symbol
	* @param {Object} searchResult search result data
	* @param {Number} searchResult.e east coordinate of result
	* @param {Number} searchResult.n north coordinate of result
	* @param {Number} searchResult.z zoom level the result should be shown at
	* @param {String} searchResult.name name of the object to be shown as label or tooltip (depends on search result symbol implementation)
	* @param {String} searchResult.shortName short name of the object to be shown as label (optional, if omitted 'name' will be used)
	* @param {String} searchResult.Lid id of the layer to be made visible when showing the search result (the object may belong to the layer or may be useful for some other reason)
	* @param {Boolean} searchResult.doNotCenter optional (default is false). If true, map is not recentered.
	* @param {Object} searchResult.btnConf optional button configuration, overrides default. Its properties:
	* 		{Boolean} info show/hide info button
	* 		{Boolean} routeA show/hide "add to route as start point" button
	* 		{Boolean} routeB show/hide "add to route as end point" button
	* 		{Boolean} trash show/hide close button
	*/
	searchResultOnMap: function(searchResult) {
		FlashApi.flash.makeSearchResult(searchResult);
	},

	/**
	* Removes search result from map.
	*/
	removeSearchResult: function() {
		FlashApi.flash.removeSearchResult();
	},
		
	// labels manipulation
	/**
	* Shows labels of all objects on the layer.
	* @param {String} layerId id of the layer
	*/
	showLayerLabels: function(layerId) {
		FlashApi.flash.showLayerLabels(layerId);
	},
	
	/**
	* Hides labels of all objects on the layer.
	* @param {String} layerId id of the layer
	*/
	hideLayerLabels: function(layerId) {
		FlashApi.flash.hideLayerLabels(layerId);
	},
	
	/**
	* Temporarily shows label of the object (if it is defined for the object). 
	* Next time the object will be redrawn its label will be shown or hidden according to the layer's labels state.
	* @param {String} layerId id of the layer the object belongs to
	* @param {String} objectId id of the object
	*/
	showObjectLabel: function(layerId, objectId) {
		FlashApi.flash.showObjectLabel(layerId, objectId);
	},
	
	/**
	* Temporarily hides label of the object.
	* Next time the object will be redrawn its label will be shown or hidden according to the layer's labels state.
	* @param {String} layerId id of the layer the object belongs to
	* @param {String} objectId id of the object
	*/
	hideObjectLabel: function(layerId, objectId) {
		FlashApi.flash.hideObjectLabel(layerId, objectId);
	},		
	// END: labels manipulation

	/**
	  * Starts editing object.
	  * @param {Object} args 
	  * @param {String} args.lid id of layer, which stile to use or where the object belongs to (it may be system layer or server layer)
	  * @param {String}  args.objectId id of the object to be edited
	  * @param {Number} args.type  type of the object (optional, if objectId is specified)
	  * @param {String} args.symbol symbol of point object (optional)
	  * @param {String} args.styleId id of the style to be applied to the object (optional, if not defined args.style will be looked next)
	  * @param {Object} args.style  json style representation (style will not be saved for future use, thus id may be any string). (Optional)
	  * Examples of styles in json format: 
	  *	{point:{color:'00ff00', alpha:80}}
	  *	{line:{alpha:80, lines:[{color:'000000', width:5}, {color:'ff0000', width:3}]}}
	  *	{area:{fillColor:'0000ff', fillAlpha:30, lineColor:'0000ff', lineWidth:2, lineAlpha:80}}
	  * If style is defined, it will be applied to the geometry, otherwise the style of object or (if object id is not specified) layer will be used
	  * @param {Array} args.geo  predifined coordinates of object (optional)
	  * @param {String}  args.action a code specifying the action to be performed when starting edit mode when object id is passed in (case insensetive):
	  * 	"COPY" - to copy the geometry of an object the id of which is passed in (the object on its layer is not hidden);
	  * 	"COPY_AND_HIDE" - to copy the geometry of an object the id of which is passed in and hide the object on its layer;
	  * 	"HIDE_ON_CLICK" - to hide the object the id of which is passed in at the first click and start digitizing a new from scratch (default for backwards compatibility).
	  * @param {Number} args.sendResponse 1 - flash notifies JS about changes in object by calling FlashApi.editModeResponse, 0 - the function will not be called
	  * @param {Boolean} centerToObject if to center to object or not
	  */	
	startEditMode: function(args, centerToObject){
		FlashApi.flash.startEditMode(args, centerToObject);
	},
	
	/**
	* Changes the style of object being edited.
	* @param {String} args.styleId id of the style to be applied to the object (optional, if not defined args.style will be looked next)
	* @param	{Object} args.style JSON representation of style to be applied to the object, e.g.  {id:'temp', area:{fillColor:'0000ff', fillAlpha:30, lineColor:'0000ff', lineWidth:2, lineAlpha:80}}
	* @param	{String} args.symbol symbol of point object to be used (optional)
	*/ 
	restyleEditedObject: function(args){
		FlashApi.flash.restyleEditedObject(args);
	},

	/**
	* Exits edit mode.
	*/
	stopEditMode: function(success){
		FlashApi.flash.stopEditMode(success);
	},

	/**
	* Enters animation mode.
	* @param {String} layerId id of the layer the object belongs to
	* @param {String} objectId id of the object to be animated
	* @param {Object} parameters optional parameters
	*	parameters.play - if true, animation is started automatically, false by default
	*/
	startAnimatingObject: function(layerId, objectId, parameters){
		FlashApi.flash.startAnimatingObject(layerId, objectId, parameters);
	},

	/**
	* Exits animation mode.
	*/
	stopAnimation: function(){
		FlashApi.flash.stopAnimation();
	},

	setFollowedObject: function(Lid, obId, addUrl){
		var args = {Lid:Lid, obId:obId, addUrl:addUrl};
		FlashApi.flash.setFollowedObject(args);
	},

	clearFollowedObject: function(){
		FlashApi.flash.clearFollowedObject();
	},
	
	/**
	* Selects object on map if object is currently on map (that means layer must be visible too)
	* @param args function arguments
	* @param args.layerId the id of the layer the object belongs to
	* @param args.objectId the id of the object to be selected
	* @return true if object is selected, false otherwise (layer is hidden or object is not currently on map)
	*/
	selectObject: function(args) {
		return FlashApi.flash.selectObject(args);
	},
	
	/**
	* Removes object selection: releases object style to the initial one and/or removes special effects.
	* Deprecated, use clearSelection instead.
	* @deprecated
	*/
	clearHighlight: function(){
		FlashApi.flash.clearSelection();
	},	
	
	/**
	* Removes object selection: releases object style to the initial one and/or removes special effects.
	*/
	clearSelection: function(){
		FlashApi.flash.clearSelection();
	},
	
	/**
	* Search given address or location and show the results in searh results list of MapCat component.
	* @param {String} query the address or location name to be searched
	*/
	geoCode: function(query){		
		var address = 'q=' + query;
		FlashApi.flash.geoCode(address);
	},

	/** 
	* Swaps two layers, the layer that was on top goes down and the lower layer goes up. The order of layers in parameters list is not important. 
	* @param {String} layerId1 the first layer id
	* @param {String} layerId2 the second layer id
	*/
	swapLayers: function(layerId1, layerId2){
		var args = {layerId1:layerId1, layerId2:layerId2};
		FlashApi.flash.swapLayersJS(args);
	},

	/** Reorder layers.
	 * @param {Array} layers array of layers ids ordered in new way
	 */
	reorderLayers: function(layers) {
		FlashApi.flash.reorderLayersJS(layers);
	},		
	
	/** 
	* Swaps two groups, the group that was on top goes down and the lower group goes up. The order of groups in parameters list is not important. 
	* @param {String} groupId1 the first group id
	* @param {String} groupId2 the second group id
	*/
	swapGroups: function(groupId1, groupId2){
		var args = {groupId1:groupId1, groupId2:groupId2};
		FlashApi.flash.swapGroupsJS(args);
	},

	/** 
	* Reorder groups.
	* @param  {Array} groups array of groups ids ordered in new way
	*/
	reorderGroups: function(groups) {
		FlashApi.flash.reorderGroupsJS(groups);
	},	
	
	/**
	* Get information about flash component current state to start printing. Flash component will throw event onPrintInfoReceived 
	* to provide JavaScript with information about current MapCat component state.
	*/
	print: function(){
		FlashApi.flash.getInfoForPrinting();
	},
		
	/**
	* Called by flash component after calling FlashApi.print function. Gives JavaScript required information to
	* restore MapCat component state when opening it in new window.
	* @param {Number} args.e east coodinate of current map view center 
	* @param {Number} args.n north coodinate of current map view center 
	* @param {Number} args.zoom current map view zoom level
	* @param {Number} args.min_e - current map view left lower corner east coordinate
	* @param {Number} args.min_n - current map view left lower corner north coordinate
	* @param {Number} args.max_e - current map view right upper corner east coordinate
	* @param {Number} args.max_n - current map view right upper corner north coordinate
	* @param {Number} args.cur_map - index of currently selected map
	* @param {Boolean} args.navi - true if navigation window is shown, false if it is hidden or disabled
	* @param {String} args.lids - the list of visible layers ids separated by ';'
	* @param {String} args.addUrls - the list of additional parameters of corresponding layers separated by ';'
	*/
	receiveInfoForPrinting: function(args) {
		if (FlashApi.onPrintInfoReceived)
			FlashApi.onPrintInfoReceived(args);
	},
		
	/**
	* Called by flash component when it is ready to operate (all configuration lodaded etc).
	* The function executes all functions that were put into stack by calling FlashApi.run before flash was ready.
	*/
	flashLoaded: function() {
		FlashApi.loaded = true;
		FlashApi.executeFunctionsInStack();	
		if (FlashApi.onFlashLoaded) 
			FlashApi.onFlashLoaded();
	},
	
	/**
	* Private, for inner use only. Executes functions put into functions stack by calling FlashApi.run before flash component is loaded.
	*/
	executeFunctionsInStack: function() {
		for (var i = 0; i < this.stack.length; i++)
			this.stack[i]();	
	},
	
	/**
	 * This event is called when layers are loaded from server and flash has build its menu model. The order of groups/layers is reversed comparing to layers configuration.
	 * It is fired before flashLoaded (!)
	 * @param {Array} menu menu representation.
	 * @see #getGroups for details about the menu model representation properties.
	 * @deprecated
	 */
	menuLoaded: function(menu) {	
		if (this.onMenuLoaded)
			this.onMenuLoaded(menu);
	},

	/**
	 * This event is called when layers are loaded from server and flash has built its menu model.
	 * It is fired before flashLoaded (!)
	 * @param {Array} layers groups and layers information.
	 * @see #getLayersData for details about the layersData properties.
	 */	
	layersDataLoaded: function(layersData) {	
		if (this.onLayersDataLoaded)
			this.onLayersDataLoaded(layersData);
	},

	/**
	 * The getter for groups.
	 * @return  menu model representation. NB! The order of groups and layers is reversed comparing to layers configuration.
	 * @see #getLayersData for details about the returned value.
	 * @type Array
	 * @deprecated
	 */	
	getGroups: function() {
		return FlashApi.flash.getGroups();
	},

	/**
	 * The getter for groups and layers information.
	 * @return  groups and layers information in the order they are defined in configuration.
	 * Array consists of group objects, each group object has properties:
	 * id - unique id of the group used in flash component,
	 * name - name of the group to be shown in menu,
	 * layers -  array of layers that belongs to the group, each is an object with properties:
	 * 	id - unique id of the layer used in flash component,
	 * 	name - name of the layer to be shown in menu,
	 * 	checked - if the layer is visible or not,
	 * 	enabled - if the layer is enabled or not,
	 * 	type - code of the default type of geometries to be shown on the layer (currently not supported, undefined is returned),
	 * 	style - default style name to be applied to the object on the layer (optional),
	 *	symbol - default symbol used to display point object that belongs to the layer (optional),
	 *	color - default color used to display symbol of point object that belongs to the layer (optional),
	 *	alpha - default alpha used to display symbol of point object or line that belongs to the layer (optional),
	 *	colors - array of colors to be used to display nested lines of line object that belongs to the layer (optional),
	 *	widths - array of line widths to be used to display nested lines of line object that belongs to the layer (optional),
	 *	fillColor - fill color of the area type of geometries, like polygons, circles, rectangles (optional),
	 *	fillAlpha - fill alpha of the area type of geometries (optional),
	 *	lineColor - line color of the area type of geometries (optional),
	 *	lineWidth - line width of the area type of geometries (optional),
	 *	lineAlpha - line alpha of the area type of geometries (optional)
	 * @type Array
	 */		
	getLayersData: function() {
		return FlashApi.flash.getLayersData();
	},
	
	flashErrorMessage: function(args){
		//alert(args.level + " " + args.msg);
	},

	/**
	* Is called by flash component when object is clicked/under mouse cursor and the layer the object belongs to is configured this way:
	* onClick is set to "openurl" / "onRollOver" is set to "openurl". In this case the URL specified in object xml is send with the event.
	* @param {String} url the URL specified in object xml
	*/
	openUrl: function(url){
		if (FlashApi.onOpenUrl)
			FlashApi.onOpenUrl(url);
	},

	/**
	 * The function is called when the layers' objects xml contains <js_data> tag.
	 * @param {String} message the content of  <js_data> tag.
	 * @param {String} layerId id of the layer which xml contained the tag.
	 */
	jsDataReceived: function(message, layerId){
		if (FlashApi.onJsDataReceived)
			FlashApi.onJsDataReceived(message, layerId);
	},
	
	/**
	* The function is called by MapCat client when editing object is finished by double click and every time the node of object is added/moved/deleted.
	* For points the function is called every time the point is put on map. Objects of type CIRCLE and RECTANGLE can not be exported as WKT.
	* If you don't want to get notifications about that event, the startEditMode function argument sendResponse should be set to 0, or just skipped.
	* @param {Object} args
	* @param {Number} args.type MapCat geometry type code (deprecated)
	* @param {String} args.typeName name of the geometry type (WKT types + CIRCLE and RECTANGLE)
	* @param {String} args.lid id of the layer the object belongs to
	* @param {String} args.id id of the object
	* @param {Object} args.geo coordinates of the object
	* @param {String} args.wkt WKT representation  of the object (undefined, if object type is not supported by WKT).
	*/
	editModeResponse: function(args){
		if (FlashApi.onEditModeResponse)
			FlashApi.onEditModeResponse(args);
	},

	/**
	* Deprecated, use objectOnMouseClicked instead.
	* The function can be used to listen object clicks. For that the object xml definition should contain the tag
	* <onClickAction action='javascript'>getDataInfo</onClickAction>
	* @param {String} args.id id of the object clicked
	* @params {String}  args.Lid id of the layer the object belongs to
	* @params {Number} args.type the code of the geometry type, e.g. 1 - point, 2 - line, 3 - polygon.
	*/
	getDataInfo: function(args){
		//alert(args.id + " " + args.Lid + " " + args.type);
	},

	/**
	* Is called every time map is panned, zoomed in/out or recentered programmatically.
	* @param {Number} args.zoom - current zoom level (a number between min_zoom and max_zoom specified in map configuration)
	* @param {Number} args.metersPerPixel - number of meters in one pixel at current zoom level
	* @param {Number} args.min_e - current map view left lower corner east coordinate
	* @param {Number} args.min_n - current map view left lower corner north coordinate
	* @param {Number} args.max_e - current map view right upper corner east coordinate
	* @param {Number} args.max_n - current map view right upper corner north coordinate
	* @param {Number} args.center_e - current map view center east coordinate
	* @param {Number} args.center_n - current map view center north coordinate
	* @param {Boolean} args.isDynamicZoomEnded - false if dynamic (animated) zoom is in progress, true if it has ended
	*/
	getMapParams: function(args) {
		if (FlashApi.onMapParamsChanged)
			FlashApi.onMapParamsChanged(args);
	},

	/**
	* Called, when flash component raports errors to JavaScript
	* @param {Number} code error code (see language configuration file for possible error codes and their meanings)
	* @param {String} message error message
	*/
	getErrors: function(code, message){
		if (FlashApi.onError)
			FlashApi.onError({code:code, message:message});		
	},
		
	/** 
	 * Adds external component to MapCat component at runtime
	 * @param  {String}  name name of the external component (can be used to remove the component, see FlashApi.removeComponent)
	 * @param  {String}  url URL the external component can be loaded from
	 */
	addComponent: function(name, url) {
		if (url) {
			FlashApi.flash.addComponent(name, url);
		} else {
			url = name;
			name = name.substr(name.lastIndexOf("/") + 1);
			name = name.substr(0, name.lastIndexOf("."));
			FlashApi.flash.addComponent(name, url);
		}
	},
	
	/** 
	 * Removes external component from MapCat component at runtime.
	 * @param  {String}  name name of the external component
	 */
	removeComponent: function(name) {
		if (name.lastIndexOf("/")) {
			name=name.substr(name.lastIndexOf("/")+1);
			name=name.substr(0,name.lastIndexOf("."));
		}
		FlashApi.flash.removeComponent(name);
	},		
		
	/** 
	 * Displays email window of MapCat component (if emailWindow component is loaded)
	 * @param  {String}  url used in Delfi project. Used to pass url to email sender script.
	 */		
	openEmail: function(url) {
		if (FlashApi.flash.openEmail)
			FlashApi.flash.openEmail(url);
	},
	
	/** 
	 * Displays message box of MapCat component (if messageBox component is loaded)
	 * @param  {String}  title header text of the message box
	 * @param {String}  text content of the message box
	 * @param {String}  type icon to be shown in message box. Supported values are "info", "warning" and "error"
	 */		
	msgBox: function(title, text, type) {
		if (FlashApi.flash.msgBox)
			FlashApi.flash.msgBox(title, text, type);
	},
	
	/** 
	 * Shows info window of MapCat component (if infoBox component is loaded)
	 * @param {Object} args arguments passed to the function
	 * @param {String} args.header the header of info window. If not defined, the default header will be used, see language configuration file.
		* @param {String} args.content the content of info window. 
		* - OR -
		* @param {String} args.url plain url(not encoded) where to get the content of info window. 
		* @param {Number} args.width width of the window.
		* @param {Number} args.height height of the window.
		* @param {Boolean} args.hideHeader true if you need to hide header.
	 */
	showInfoBox: function(args) {
		if (FlashApi.flash.showInfo)
			FlashApi.flash.showInfo(args);
	},
	
	/**
	* Sets flash component resize button state. This will change the button appearance and the event send to 
	* JavaScript the button is clicked next time (@see FlashApi.showSidebar and FlashApi.hideSidebar)
	* @param {Boolean} maximized if flash component is maximized or not
	*/
	setResizeButtonState: function(maximized) {
		FlashApi.flash.setResizeButtonState(maximized);
	},
	
	/**
	* Called when resize button in flash component is clicked when being in  maximized state
	*/
	showSidebar: function() {
		if (FlashApi.onShowSidebar)
			FlashApi.onShowSidebar();
	},
	
	/**
	* Called when resize button in flash component is clicked when not being in  maximized state
	*/	
	hideSidebar: function() {
		if (FlashApi.onHideSidebar)
			FlashApi.onHideSidebar();
	},
		
	/** 
	 * Switches map to specified one.
	 * @param {Number} index map index in map configuration (main configuration file). Numbering starts from 0
	 */
	selectMap: function(index){
		FlashApi.flash.selectMap(index);
	},

	/**
	* Reloads and applyes language configuration file where are specified texts of GUI elements and localized error messages.
	* @param url the URL of language configuration file to be loaded
	*/
	reloadLanguageFile: function(url) {
		FlashApi.flash.reloadLanguageFile(url);
	},
	
	/* BEGIN CITY24 CUSTOM FUNCTIONS */
	
	/**
	 * Shows custom info
	 * @param {Object} args arguments passed to the function.
	 * @param {String} args.content the content of info window.
	 * @param {String} args.target target div id.
	 * @param {String} args.mapwrapper
	 */
	showCustomInfoBox: function(args) {
		var targetObj = $("#" + args.target);
		var wrapper = $("#"+ args.mapwrapper);
		
		var left = ((wrapper.outerWidth() / 2) - 150) + "px";
		var top = ((wrapper.outerHeight() / 2) - 100) + "px";
		
		targetObj.html(args.content);
		
		targetObj.css({
			position: "absolute",
			"margin-left": left,
			"margin-top": top
		});
		
		targetObj.show();
	},
	
	/**
	 * Close custom info
	 * @param {String} target target div id.
	 */
	closeCustomInfoBox: function(target) {
		var targetObj = $("#" + target);
		targetObj.hide();
		targetObj.empty();
	},
	
	/**
	 * Show custom info window tab.
	 * @param {String} prefix target tab name prefix.
	 * @param {Number} currentItem tab to show.
	 * @param {Number} totalItems total tabs.
	 * @param {Object} args arguments passed to the function.
	 * @param {String} args.counterServiceUrl counter service URL.
	 */
	showCustomInfoWindowTab: function(prefix, currentItem, totalItems, args) {
		for (var i=1; i<=totalItems; i++) {
			var targetObj = $("#" + prefix + i);
			if (i == currentItem) {
				targetObj.show();
			} else {
				targetObj.hide();
			}
		}
		
		// Request counter service URL by AJAX
		if (args.counterServiceUrl) {
			var rnd = Math.floor(1 + (Math.random() * 60000));
			$.get(args.counterServiceUrl + "&rnd=" + rnd);
		}
	}
	
}
