/*
*
* Copyright (c) 2006-2008 Sam Collett (http://www.texotela.co.uk)
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*
* Version 2.2.3
* Demo: http://www.texotela.co.uk/code/jquery/select/
*
* $LastChangedDate$
* $Rev$
*
*/

; (function($) {

    /**
    * Adds (single/multiple) options to a select box (or series of select boxes)
    *
    * @name     addOption
    * @author   Sam Collett (http://www.texotela.co.uk)
    * @type     jQuery
    * @example  $("#myselect").addOption("Value", "Text"); // add single value (will be selected)
    * @example  $("#myselect").addOption("Value 2", "Text 2", false); // add single value (won't be selected)
    * @example  $("#myselect").addOption({"foo":"bar","bar":"baz"}, false); // add multiple values, but don't select
    *
    */
    $.fn.addOption = function() {
        var add = function(el, v, t, sO) {
            var option = document.createElement("option");
            option.value = v, option.text = t;
            // get options
            var o = el.options;
            // get number of options
            var oL = o.length;
            if (!el.cache) {
                el.cache = {};
                // loop through existing options, adding to cache
                for (var i = 0; i < oL; i++) {
                    el.cache[o[i].value] = i;
                }
            }
            // add to cache if it isn't already
            if (typeof el.cache[v] == "undefined") el.cache[v] = oL;
            el.options[el.cache[v]] = option;
            if (sO) {
                option.selected = true;
            }
        };

        var a = arguments;
        if (a.length == 0) return this;
        // select option when added? default is true
        var sO = true;
        // multiple items
        var m = false;
        // other variables
        var items, v, t;
        if (typeof (a[0]) == "object") {
            m = true;
            items = a[0];
        }
        if (a.length >= 2) {
            if (typeof (a[1]) == "boolean") sO = a[1];
            else if (typeof (a[2]) == "boolean") sO = a[2];
            if (!m) {
                v = a[0];
                t = a[1];
            }
        }
        this.each(
		function() {
		    if (this.nodeName.toLowerCase() != "select") return;
		    if (m) {
		        for (var item in items) {
		            add(this, item, items[item], sO);
		        }
		    }
		    else {
		        add(this, v, t, sO);
		    }
		}
	);
        return this;
    };

    /**
    * Add options via ajax
    *
    * @name     ajaxAddOption
    * @author   Sam Collett (http://www.texotela.co.uk)
    * @type     jQuery
    * @param    String url      Page to get options from (must be valid JSON)
    * @param    Object params   (optional) Any parameters to send with the request
    * @param    Boolean select  (optional) Select the added options, default true
    * @param    Function fn     (optional) Call this function with the select object as param after completion
    * @param    Array args      (optional) Array with params to pass to the function afterwards
    * @example  $("#myselect").ajaxAddOption("myoptions.php");
    * @example  $("#myselect").ajaxAddOption("myoptions.php", {"code" : "007"});
    * @example  $("#myselect").ajaxAddOption("myoptions.php", {"code" : "007"}, false, sortoptions, [{"dir": "desc"}]);
    *
    */
    $.fn.ajaxAddOption = function(url, params, select, fn, args) {
        if (typeof (url) != "string") return this;
        if (typeof (params) != "object") params = {};
        if (typeof (select) != "boolean") select = true;
        this.each(
		function() {
		    var el = this;
		    $.getJSON(url,
				params,
				function(r) {
				    $(el).addOption(r, select);
				    if (typeof fn == "function") {
				        if (typeof args == "object") {
				            fn.apply(el, args);
				        }
				        else {
				            fn.call(el);
				        }
				    }
				}
			);
		}
	);
        return this;
    };

    /**
    * Removes an option (by value or index) from a select box (or series of select boxes)
    *
    * @name     removeOption
    * @author   Sam Collett (http://www.texotela.co.uk)
    * @type     jQuery
    * @param    String|RegExp|Number what  Option to remove
    * @param    Boolean selectedOnly       (optional) Remove only if it has been selected (default false)   
    * @example  $("#myselect").removeOption("Value"); // remove by value
    * @example  $("#myselect").removeOption(/^val/i); // remove options with a value starting with 'val'
    * @example  $("#myselect").removeOption(/./); // remove all options
    * @example  $("#myselect").removeOption(/./, true); // remove all options that have been selected
    * @example  $("#myselect").removeOption(0); // remove by index
    * @example  $("#myselect").removeOption(["myselect_1","myselect_2"]); // values contained in passed array
    *
    */
    $.fn.removeOption = function() {
        var a = arguments;
        if (a.length == 0) return this;
        var ta = typeof (a[0]);
        var v, index;
        // has to be a string or regular expression (object in IE, function in Firefox)
        if (ta == "string" || ta == "object" || ta == "function") {
            v = a[0];
            // if an array, remove items
            if (v.constructor == Array) {
                var l = v.length;
                for (var i = 0; i < l; i++) {
                    this.removeOption(v[i], a[1]);
                }
                return this;
            }
        }
        else if (ta == "number") index = a[0];
        else return this;
        this.each(
		function() {
		    if (this.nodeName.toLowerCase() != "select") return;
		    // clear cache
		    if (this.cache) this.cache = null;
		    // does the option need to be removed?
		    var remove = false;
		    // get options
		    var o = this.options;
		    if (!!v) {
		        // get number of options
		        var oL = o.length;
		        for (var i = oL - 1; i >= 0; i--) {
		            if (v.constructor == RegExp) {
		                if (o[i].value.match(v)) {
		                    remove = true;
		                }
		            }
		            else if (o[i].value == v) {
		                remove = true;
		            }
		            // if the option is only to be removed if selected
		            if (remove && a[1] === true) remove = o[i].selected;
		            if (remove) {
		                o[i] = null;
		            }
		            remove = false;
		        }
		    }
		    else {
		        // only remove if selected?
		        if (a[1] === true) {
		            remove = o[index].selected;
		        }
		        else {
		            remove = true;
		        }
		        if (remove) {
		            this.remove(index);
		        }
		    }
		}
	);
        return this;
    };

    /**
    * Sort options (ascending or descending) in a select box (or series of select boxes)
    *
    * @name     sortOptions
    * @author   Sam Collett (http://www.texotela.co.uk)
    * @type     jQuery
    * @param    Boolean ascending   (optional) Sort ascending (true/undefined), or descending (false)
    * @example  // ascending
    * $("#myselect").sortOptions(); // or $("#myselect").sortOptions(true);
    * @example  // descending
    * $("#myselect").sortOptions(false);
    *
    */
    $.fn.sortOptions = function(ascending) {
        var a = typeof (ascending) == "undefined" ? true : !!ascending;
        this.each(
		function() {
		    if (this.nodeName.toLowerCase() != "select") return;
		    // get options
		    var o = this.options;
		    // get number of options
		    var oL = o.length;
		    // create an array for sorting
		    var sA = [];
		    // loop through options, adding to sort array
		    for (var i = 0; i < oL; i++) {
		        sA[i] = {
		            v: o[i].value,
		            t: o[i].text
		        }
		    }
		    // sort items in array
		    sA.sort(
				function(o1, o2) {
				    // option text is made lowercase for case insensitive sorting
				    o1t = o1.t.toLowerCase(), o2t = o2.t.toLowerCase();
				    // if options are the same, no sorting is needed
				    if (o1t == o2t) return 0;
				    if (a) {
				        return o1t < o2t ? -1 : 1;
				    }
				    else {
				        return o1t > o2t ? -1 : 1;
				    }
				}
			);
		    // change the options to match the sort array
		    for (var i = 0; i < oL; i++) {
		        o[i].text = sA[i].t;
		        o[i].value = sA[i].v;
		    }
		}
	);
        return this;
    };
    /**
    * Selects an option by value
    *
    * @name     selectOptions
    * @author   Mathias Bank (http://www.mathias-bank.de), original function
    * @author   Sam Collett (http://www.texotela.co.uk), addition of regular expression matching
    * @type     jQuery
    * @param    String|RegExp value  Which options should be selected
    * can be a string or regular expression
    * @param    Boolean clear  Clear existing selected options, default false
    * @example  $("#myselect").selectOptions("val1"); // with the value 'val1'
    * @example  $("#myselect").selectOptions(/^val/i); // with the value starting with 'val', case insensitive
    *
    */
    $.fn.selectOptions = function(value, clear) {
        var v = value;
        var vT = typeof (value);
        var c = clear || false;
        // has to be a string or regular expression (object in IE, function in Firefox)
        if (vT != "string" && vT != "function" && vT != "object") return this;
        this.each(
		function() {
		    if (this.nodeName.toLowerCase() != "select") return this;
		    // get options
		    var o = this.options;
		    // get number of options
		    var oL = o.length;
		    for (var i = 0; i < oL; i++) {
		        if (v.constructor == RegExp) {
		            if (o[i].value.match(v)) {
		                o[i].selected = true;
		            }
		            else if (c) {
		                o[i].selected = false;
		            }
		        }
		        else {
		            if (o[i].value == v) {
		                o[i].selected = true;
		            }
		            else if (c) {
		                o[i].selected = false;
		            }
		        }
		    }
		}
	);
        return this;
    };

    /**
    * Copy options to another select
    *
    * @name     copyOptions
    * @author   Sam Collett (http://www.texotela.co.uk)
    * @type     jQuery
    * @param    String to  Element to copy to
    * @param    String which  (optional) Specifies which options should be copied - 'all' or 'selected'. Default is 'selected'
    * @example  $("#myselect").copyOptions("#myselect2"); // copy selected options from 'myselect' to 'myselect2'
    * @example  $("#myselect").copyOptions("#myselect2","selected"); // same as above
    * @example  $("#myselect").copyOptions("#myselect2","all"); // copy all options from 'myselect' to 'myselect2'
    *
    */
    $.fn.copyOptions = function(to, which) {
        var w = which || "selected";
        if ($(to).size() == 0) return this;
        this.each(
		function() {
		    if (this.nodeName.toLowerCase() != "select") return this;
		    // get options
		    var o = this.options;
		    // get number of options
		    var oL = o.length;
		    for (var i = 0; i < oL; i++) {
		        if (w == "all" || (w == "selected" && o[i].selected)) {
		            $(to).addOption(o[i].value, o[i].text);
		        }
		    }
		}
	);
        return this;
    };

    /**
    * Checks if a select box has an option with the supplied value
    *
    * @name     containsOption
    * @author   Sam Collett (http://www.texotela.co.uk)
    * @type     Boolean|jQuery
    * @param    String|RegExp value  Which value to check for. Can be a string or regular expression
    * @param    Function fn          (optional) Function to apply if an option with the given value is found.
    * Use this if you don't want to break the chaining
    * @example  if($("#myselect").containsOption("val1")) alert("Has an option with the value 'val1'");
    * @example  if($("#myselect").containsOption(/^val/i)) alert("Has an option with the value starting with 'val'");
    * @example  $("#myselect").containsOption("val1", copyoption).doSomethingElseWithSelect(); // calls copyoption (user defined function) for any options found, chain is continued
    *
    */
    $.fn.containsOption = function(value, fn) {
        var found = false;
        var v = value;
        var vT = typeof (v);
        var fT = typeof (fn);
        // has to be a string or regular expression (object in IE, function in Firefox)
        if (vT != "string" && vT != "function" && vT != "object") return fT == "function" ? this : found;
        this.each(
		function() {
		    if (this.nodeName.toLowerCase() != "select") return this;
		    // option already found
		    if (found && fT != "function") return false;
		    // get options
		    var o = this.options;
		    // get number of options
		    var oL = o.length;
		    for (var i = 0; i < oL; i++) {
		        if (v.constructor == RegExp) {
		            if (o[i].value.match(v)) {
		                found = true;
		                if (fT == "function") fn.call(o[i], i);
		            }
		        }
		        else {
		            if (o[i].value == v) {
		                found = true;
		                if (fT == "function") fn.call(o[i], i);
		            }
		        }
		    }
		}
	);
        return fT == "function" ? this : found;
    };

    /**
    * Returns values which have been selected
    *
    * @name     selectedValues
    * @author   Sam Collett (http://www.texotela.co.uk)
    * @type     Array
    * @example  $("#myselect").selectedValues();
    *
    */
    $.fn.selectedValues = function() {
        var v = [];
        this.find("option:selected").each(
		function() {
		    v[v.length] = this.value;
		}
	);
        return v;
    };

    /**
    * Returns options which have been selected
    *
    * @name     selectedOptions
    * @author   Sam Collett (http://www.texotela.co.uk)
    * @type     jQuery
    * @example  $("#myselect").selectedOptions();
    *
    */
    $.fn.selectedOptions = function() {
        return this.find("option:selected");
    };

})(jQuery);;/*
* jQuery Media Plugin for converting elements into rich media content.
*
* Examples and documentation at: http://malsup.com/jquery/media/
* Copyright (c) 2007-2008 M. Alsup
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* @author: M. Alsup
* @version: 0.90 (10-MAY-2009)
* @requires jQuery v1.1.2 or later
* $Id: jquery.media.js 2460 2007-07-23 02:53:15Z malsup $
*
* Supported Media Players:
*    - Flash
*    - Quicktime
*    - Real Player
*    - Silverlight
*    - Windows Media Player
*    - iframe
*
* Supported Media Formats:
*   Any types supported by the above players, such as:
*     Video: asf, avi, flv, mov, mpg, mpeg, mp4, qt, smil, swf, wmv, 3g2, 3gp
*     Audio: aif, aac, au, gsm, mid, midi, mov, mp3, m4a, snd, rm, wav, wma
*     Other: bmp, html, pdf, psd, qif, qtif, qti, tif, tiff, xaml
*
* Thanks to Mark Hicken and Brent Pedersen for helping me debug this on the Mac!
* Thanks to Dan Rossi for numerous bug reports and code bits!
* Thanks to Skye Giordano for several great suggestions!
*/
; (function($) {

	/**
	* Chainable method for converting elements into rich media.
	*
	* @param options
	* @param callback fn invoked for each matched element before conversion
	* @param callback fn invoked for each matched element after conversion
	*/
	$.fn.media = function(options, f1, f2) {
		return this.each(function() {
			if (typeof options == 'function') {
				f2 = f1;
				f1 = options;
				options = {};
			}
			var o = getSettings(this, options);
			// pre-conversion callback, passes original element and fully populated options
			if (typeof f1 == 'function') f1(this, o);

			var r = getTypesRegExp();
			var m = r.exec(o.src.toLowerCase()) || [''];

			o.type ? m[0] = o.type : m.shift();
			for (var i = 0; i < m.length; i++) {
				fn = m[i].toLowerCase();
				if (isDigit(fn[0])) fn = 'fn' + fn; // fns can't begin with numbers
				if (!$.fn.media[fn])
					continue;  // unrecognized media type
				// normalize autoplay settings
				var player = $.fn.media[fn + '_player'];
				if (!o.params) o.params = {};
				if (player) {
					var num = player.autoplayAttr == 'autostart';
					o.params[player.autoplayAttr || 'autoplay'] = num ? (o.autoplay ? 1 : 0) : o.autoplay ? true : false;
				}
				var $div = $.fn.media[fn](this, o);

				$div.css('backgroundColor', o.bgColor).width(o.width);
				// post-conversion callback, passes original element, new div element and fully populated options
				if (typeof f2 == 'function') f2(this, $div[0], o, player.name);
				break;
			}
		});
	};

	/**
	* Non-chainable method for adding or changing file format / player mapping
	* @name mapFormat
	* @param String format File format extension (ie: mov, wav, mp3)
	* @param String player Player name to use for the format (one of: flash, quicktime, realplayer, winmedia, silverlight or iframe
	*/
	$.fn.media.mapFormat = function(format, player) {
		if (!format || !player || !$.fn.media.defaults.players[player]) return; // invalid
		format = format.toLowerCase();
		if (isDigit(format[0])) format = 'fn' + format;
		$.fn.media[format] = $.fn.media[player];
		$.fn.media[format + '_player'] = $.fn.media.defaults.players[player];
	};

	// global defautls; override as needed
	$.fn.media.defaults = {
		width: 400,
		height: 400,
		autoplay: 0,         // normalized cross-player setting
		bgColor: '#ffffff', // background color
		params: { wmode: 'transparent' },  // added to object element as param elements; added to embed element as attrs
		attrs: {},        // added to object and embed elements as attrs
		flvKeyName: 'file',    // key used for object src param (thanks to Andrea Ercolino)
		flashvars: {},        // added to flash content as flashvars param/attr
		flashVersion: '7',       // required flash version
		expressInstaller: null,   // src for express installer

		// default flash video and mp3 player (@see: http://jeroenwijering.com/?item=Flash_Media_Player)
		flvPlayer: 'mediaplayer.swf',
		mp3Player: 'mediaplayer.swf',

		// @see http://msdn2.microsoft.com/en-us/library/bb412401.aspx
		silverlight: {
			inplaceInstallPrompt: 'true', // display in-place install prompt?
			isWindowless: 'true', // windowless mode (false for wrapping markup)
			framerate: '24',   // maximum framerate
			version: '0.9',  // Silverlight version
			onError: null,   // onError callback
			onLoad: null,   // onLoad callback
			initParams: null,   // object init params
			userContext: null    // callback arg passed to the load callback
		}
	};

	// Media Players; think twice before overriding
	$.fn.media.defaults.players = {
		flash: {
			name: 'flash',
			types: 'flv,mp3,swf',
			oAttrs: {
				classid: 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000',
				type: 'application/x-oleobject',
				codebase: 'http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=' + $.fn.media.defaults.flashVersion
			},
			eAttrs: {
				type: 'application/x-shockwave-flash',
				pluginspage: 'http://www.adobe.com/go/getflashplayer'
			}
		},
		quicktime: {
			name: 'quicktime',
			types: 'aif,aiff,aac,au,bmp,gsm,mov,mid,midi,mpg,mpeg,mp4,m4a,psd,qt,qtif,qif,qti,snd,tif,tiff,wav,3g2,3gp',
			oAttrs: {
				classid: 'clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B',
				codebase: 'http://www.apple.com/qtactivex/qtplugin.cab'
			},
			eAttrs: {
				pluginspage: 'http://www.apple.com/quicktime/download/'
			}
		},
		realplayer: {
			name: 'real',
			types: 'ra,ram,rm,rpm,rv,smi,smil',
			autoplayAttr: 'autostart',
			oAttrs: {
				classid: 'clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA'
			},
			eAttrs: {
				type: 'audio/x-pn-realaudio-plugin',
				pluginspage: 'http://www.real.com/player/'
			}
		},
		winmedia: {
			name: 'winmedia',
			types: 'asx,asf,avi,wma,wmv',
			autoplayAttr: 'autostart',
			oUrl: 'url',
			oAttrs: {
				classid: 'clsid:6BF52A52-394A-11d3-B153-00C04F79FAA6',
				type: 'application/x-oleobject'
			},
			eAttrs: {
				type: $.browser.mozilla && isFirefoxWMPPluginInstalled() ? 'application/x-ms-wmp' : 'application/x-mplayer2',
				pluginspage: 'http://www.microsoft.com/Windows/MediaPlayer/'
			}
		},
		// special cases
		iframe: {
			name: 'iframe',
			types: 'html,pdf'
		},
		silverlight: {
			name: 'silverlight',
			types: 'xaml'
		}
	};

	//
	//  everything below here is private
	//


	// detection script for FF WMP plugin (http://www.therossman.org/experiments/wmp_play.html)
	// (hat tip to Mark Ross for this script)
	function isFirefoxWMPPluginInstalled() {
		var plugs = navigator.plugins;
		for (i = 0; i < plugs.length; i++) {
			var plugin = plugs[i];
			if (plugin['filename'] == 'np-mswmp.dll')
				return true;
		}
		return false;
	}

	var counter = 1;

	for (var player in $.fn.media.defaults.players) {
		var types = $.fn.media.defaults.players[player].types;
		$.each(types.split(','), function(i, o) {
			if (isDigit(o[0])) o = 'fn' + o;
			$.fn.media[o] = $.fn.media[player] = getGenerator(player);
			$.fn.media[o + '_player'] = $.fn.media.defaults.players[player];
		});
	};

	function getTypesRegExp() {
		var types = '';
		for (var player in $.fn.media.defaults.players) {
			if (types.length) types += ',';
			types += $.fn.media.defaults.players[player].types;
		};
		return new RegExp('\\.(' + types.replace(/,/ig, '|') + ')\\b');
	};

	function getGenerator(player) {
		return function(el, options) {
			return generate(el, options, player);
		};
	};

	function isDigit(c) {
		return '0123456789'.indexOf(c) > -1;
	};

	// flatten all possible options: global defaults, meta, option obj
	function getSettings(el, options) {
		options = options || {};
		var $el = $(el);
		var cls = el.className || '';
		// support metadata plugin (v1.0 and v2.0)
		var meta = $.metadata ? $el.metadata() : $.meta ? $el.data() : {};
		meta = meta || {};
		var w = meta.width || parseInt(((cls.match(/w:(\d+)/) || [])[1] || 0));
		var h = meta.height || parseInt(((cls.match(/h:(\d+)/) || [])[1] || 0));

		if (w) meta.width = w;
		if (h) meta.height = h;
		if (cls) meta.cls = cls;

		var a = $.fn.media.defaults;
		var b = options;
		var c = meta;

		var p = { params: { bgColor: options.bgColor || $.fn.media.defaults.bgColor} };
		var opts = $.extend({}, a, b, c);
		$.each(['attrs', 'params', 'flashvars', 'silverlight'], function(i, o) {
			opts[o] = $.extend({}, p[o] || {}, a[o] || {}, b[o] || {}, c[o] || {});
		});

		if (typeof opts.caption == 'undefined') opts.caption = $el.text();

		// make sure we have a source!
		opts.src = opts.src || $el.attr('href') || $el.attr('src') || 'unknown';
		return opts;
	};

	//
	//  Flash Player
	//

	// generate flash using SWFObject library if possible
	$.fn.media.swf = function(el, opts) {
		if (!window.SWFObject && !window.swfobject) {
			// roll our own
			if (opts.flashvars) {
				var a = [];
				for (var f in opts.flashvars)
					a.push(f + '=' + opts.flashvars[f]);
				if (!opts.params) opts.params = {};
				opts.params.flashvars = a.join('&');
			}
			return generate(el, opts, 'flash');
		}

		var id = el.id ? (' id="' + el.id + '"') : '';
		var cls = opts.cls ? (' class="' + opts.cls + '"') : '';
		var $div = $('<div' + id + cls + '>');

		// swfobject v2+
		if (window.swfobject) {
			$(el).after($div).appendTo($div);
			if (!el.id) el.id = 'movie_player_' + counter++;

			// replace el with swfobject content
			swfobject.embedSWF(opts.src, el.id, opts.width, opts.height, opts.flashVersion,
            opts.expressInstaller, opts.flashvars, opts.params, opts.attrs);
		}
		// swfobject < v2
		else {
			$(el).after($div).remove();
			var so = new SWFObject(opts.src, 'movie_player_' + counter++, opts.width, opts.height, opts.flashVersion, opts.bgColor);
			if (opts.expressInstaller) so.useExpressInstall(opts.expressInstaller);

			for (var p in opts.params)
				if (p != 'bgColor') so.addParam(p, opts.params[p]);
			for (var f in opts.flashvars)
				so.addVariable(f, opts.flashvars[f]);
			so.write($div[0]);
		}

		if (opts.caption) $('<div>').appendTo($div).html(opts.caption);
		return $div;
	};

	// map flv and mp3 files to the swf player by default
	$.fn.media.flv = $.fn.media.mp3 = function(el, opts) {
		var src = opts.src;
		var player = /\.mp3\b/i.test(src) ? $.fn.media.defaults.mp3Player : $.fn.media.defaults.flvPlayer;
		var key = opts.flvKeyName;
		src = encodeURIComponent(src);
		opts.src = player;
		opts.src = opts.src + '?' + key + '=' + (src);
		var srcObj = {};
		srcObj[key] = src;
		opts.flashvars = $.extend({}, srcObj, opts.flashvars);
		return $.fn.media.swf(el, opts);
	};

	//
	//  Silverlight
	//
	$.fn.media.xaml = function(el, opts) {
		if (!window.Sys || !window.Sys.Silverlight) {
			if ($.fn.media.xaml.warning) return;
			$.fn.media.xaml.warning = 1;
			alert('You must include the Silverlight.js script.');
			return;
		}

		var props = {
			width: opts.width,
			height: opts.height,
			background: opts.bgColor,
			inplaceInstallPrompt: opts.silverlight.inplaceInstallPrompt,
			isWindowless: opts.silverlight.isWindowless,
			framerate: opts.silverlight.framerate,
			version: opts.silverlight.version
		};
		var events = {
			onError: opts.silverlight.onError,
			onLoad: opts.silverlight.onLoad
		};

		var id1 = el.id ? (' id="' + el.id + '"') : '';
		var id2 = opts.id || 'AG' + counter++;
		// convert element to div
		var cls = opts.cls ? (' class="' + opts.cls + '"') : '';
		var $div = $('<div' + id1 + cls + '>');
		$(el).after($div).remove();

		Sys.Silverlight.createObjectEx({
			source: opts.src,
			initParams: opts.silverlight.initParams,
			userContext: opts.silverlight.userContext,
			id: id2,
			parentElement: $div[0],
			properties: props,
			events: events
		});

		if (opts.caption) $('<div>').appendTo($div).html(opts.caption);
		return $div;
	};

	//
	// generate object/embed markup
	//
	function generate(el, opts, player) {
		var $el = $(el);
		var o = $.fn.media.defaults.players[player];

		if (player == 'iframe') {
			var o = $('<iframe' + ' width="' + opts.width + '" height="' + opts.height + '" >');
			o.attr('src', opts.src);
			o.css('backgroundColor', o.bgColor);
		}
		else if ($.browser.msie) {
			var a = ['<object width="' + opts.width + '" height="' + opts.height + '" '];
			for (var key in opts.attrs)
				a.push(key + '="' + opts.attrs[key] + '" ');
			for (var key in o.oAttrs || {}) {
				var v = o.oAttrs[key];
				if (key == 'codebase' && window.location.protocol == 'https:')
					v = v.replace('http', 'https');
				a.push(key + '="' + v + '" ');
			}
			a.push('></ob' + 'ject' + '>');
			var p = ['<param name="' + (o.oUrl || 'src') + '" value="' + opts.src + '">'];
			for (var key in opts.params)
				p.push('<param name="' + key + '" value="' + opts.params[key] + '">');
			var o = document.createElement(a.join(''));
			for (var i = 0; i < p.length; i++)
				o.appendChild(document.createElement(p[i]));
		}
		else {
			var a = ['<embed width="' + opts.width + '" height="' + opts.height + '" style="display:block"'];
			if (opts.src) a.push(' src="' + opts.src + '" ');
			for (var key in opts.attrs)
				a.push(key + '="' + opts.attrs[key] + '" ');
			for (var key in o.eAttrs || {})
				a.push(key + '="' + o.eAttrs[key] + '" ');
			for (var key in opts.params) {
				if (key == 'wmode' && player != 'flash') // FF3/Quicktime borks on wmode
					continue;
				a.push(key + '="' + opts.params[key] + '" ');
			}
			a.push('></em' + 'bed' + '>');
		}
		// convert element to div
		var id = el.id ? (' id="' + el.id + '"') : '';
		var cls = opts.cls ? (' class="' + opts.cls + '"') : '';
		var $div = $('<div' + id + cls + '>');
		$el.after($div).remove();
		($.browser.msie || player == 'iframe') ? $div.append(o) : $div.html(a.join(''));
		if (opts.caption) $('<div>').appendTo($div).html(opts.caption);
		return $div;
	};
})(jQuery);
;/**
 * @classDescription The Mapifies variable is the main class object for jMaps
 */
var Mapifies;

if (!Mapifies) Mapifies = {};

/**
 * The main object that holds the maps
 */
Mapifies.MapObjects = {};

/**
 * Creates a new map on the passed element with the defined options.  Creates a global object that contains the map.
 * @method
 * @namespace Mapifies.MapObjects
 * @id Mapifies.MapObjects.Set
 * @alias Mapifies.MapObjects.Set
 * @param {jQuery} element The element that contains the map.
 * @param {Object} options An object that contains the options.
 * @return {Object} The object that contains the map.
 */
Mapifies.MapObjects.Set = function ( element, options ) {
	var mapName = jQuery(element).attr('id');
	var thisMap = new GMap2(element);
	Mapifies.MapObjects[mapName] = thisMap;
	Mapifies.MapObjects[mapName].Options = options;
	return Mapifies.MapObjects[mapName];
};

/**
 * Adds additional objects and functions to an existing MapObject
 * @method
 * @namespace Mapifies.MapObjects
 * @id Mapifies.MapObjects.Append
 * @alias Mapifies.MapObjects.Append
 * @param {jQuery} element The element that contains the map
 * @param {Object} description The name of the object to create
 * @param {Object} appending The object or function to append
 */
Mapifies.MapObjects.Append = function ( element, description, appending ) {
	var mapName = jQuery(element).attr('id');
	Mapifies.MapObjects[mapName][description] = appending;
};

/**
 * Returns the current map object for the passed element
 * @method
 * @namespace Mapifies.MapObjects
 * @id Mapifies.MapObjects.Get
 * @alias Mapifies.MapObjects.Get
 * @param {jQuery} element The element that contains the map.
 * @return {Object} Mapifies The Mapifies object that contains the map.
 */
Mapifies.MapObjects.Get = function ( element ) {
	return Mapifies.MapObjects[jQuery(element).attr('id')];
};

/**
 * The main function to initialise the map
 * @method
 * @namespace Mapifies
 * @id Mapifies.Initialise
 * @alias Mapifies.Initialise
 * @param {jQuery} element The element to initialise the map on.
 * @param {Object} options The object that contains the options.
 * @param {Object} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the map object and options.
 */
Mapifies.Initialise = function ( element, options, callback ) {
	/**
	 * Default options for Initialise
	 * @method
	 * @namespace Mapifies.Initialise
	 * @id Mapifies.Initialise.defaults
	 * @alias Mapifies.Initialise.defaults
	 * @param {String} language The locale language for the map
	 * @param {String} mapType The type of map to create.  Options are 'map' (default), 'sat' and 'hybrid'.
	 * @param {Object} mapCenter An array that contains the Lat/Lng coordinates of the map center.
	 * @param {Number} mapZoom The initial zoom level of the map.
	 * @param {String} mapControl The option for the map control.  The options are 'small' (default), 'large' or 'none'
	 * @param {Boolean} mapEnableType Defines if the buttons for map type are shown.  Default false.
	 * @param {Boolean} mapEnableOverview Defines if the map overview is shown.  Default false.
	 * @param {Boolean} mapEnableDragging Defines if the map is draggable or not.  Default true.
	 * @param {Boolean} mapEnableInfoWindows Defines if info windows are shown on the map or not.  Default true.
	 * @param {Boolean} mapEnableDoubleClickZoom Defines if double clicking zooms the map.  Default false.
	 * @param {Boolean} mapEnableSmoothZoom Defines if smooth scrolling is enabled.  Default false.
	 * @param {Boolean} mapEnableGoogleBar Defines if the google map search tool is enabled.  Default false.
	 * @param {Boolean} mapEnableScaleControl Defines if the scale bar is shown.  Default false.
	 * @param {Boolean} mapShowjMapsIcon Defines if the jMaps icon is shown.  Default true.
	 * @param {Boolean} debugMode Defines if the map object created is returned to the Firebug console.  Default false.
	 * @return {Object} The options for SearchAddress
	 */
	function defaults() {
		return {
			// Initial type of map to display
			'language': 'en',
			// Options: "map", "sat", "hybrid"
			'mapType': 'map',
			// Initial map center
			'mapCenter': [55.958858,-3.162302],
			// Initial zoom level
			'mapZoom': 12,
			// Initial map control size
			// Options: "large", "small", "none"
			'mapControl': 'small',
			// Initialise type of map control
			'mapEnableType': false,
			// Initialise small map overview
			'mapEnableOverview': false,
			// Enable map dragging when left button held down
			'mapEnableDragging': true,
			// Enable map info windows
			'mapEnableInfoWindows': true,
			// Enable double click zooming
			'mapEnableDoubleClickZoom': false,
			// Enable zooming with scroll wheel
			'mapEnableScrollZoom': false,
			// Enable smooth zoom
			'mapEnableSmoothZoom': false,
			// Enable Google Bar
			'mapEnableGoogleBar': false,
			// Enables scale bar
			'mapEnableScaleControl': false,
			// Enable the Mapifies icon
			'mapShowjMapsIcon': false,
			//Debug Mode
			'debugMode': false
		};
	};
	options = jQuery.extend(defaults(), options);
	
	if (GBrowserIsCompatible()) {
			
		var thisMap = Mapifies.MapObjects.Set(element, options);
		var mapType = Mapifies.GetMapType(options.mapType);
		thisMap.setCenter(new GLatLng(options.mapCenter[0], options.mapCenter[1]), options.mapZoom, mapType);
		
		if (options.mapShowjMapsIcon) {
			Mapifies.AddScreenOverlay(element,
				{
					'imageUrl':'http://hg.digitalspaghetti.me.uk/jmaps/raw-file/3228fade0b3c/docs/images/jmaps-mapicon.png',
					'screenXY':[70,10],
					'overlayXY':[0,0],
					'size':[42,25]
				}
			);
		}
		
		// Attach a controller to the map view
		// Will attach a large or small.  If any other value passed (i.e. "none") it is ignored
		switch (options.mapControl) {
			case "small":
				thisMap.addControl(new GSmallMapControl());
				break;
			case "large":
				thisMap.addControl(new GLargeMapControl());
				break;
		};
		// Type of map Control (Map,Sat,Hyb)
		if (options.mapEnableType) 
			thisMap.addControl(new GMapTypeControl()); // Off by default
		// Show the small overview map
		if (options.mapEnableOverview) 
			thisMap.addControl(new GOverviewMapControl());// Off by default
		// GMap2 Functions (in order of the docs for clarity)
		// Enable a mouse-dragable map
		if (!options.mapEnableDragging) 
			thisMap.disableDragging(); // On by default
		// Enable Info Windows
		if (!options.mapEnableInfoWindows) 
			thisMap.disableInfoWindow(); // On by default
		// Enable double click zoom on the map
		if (options.mapEnableDoubleClickZoom) 
			thisMap.enableDoubleClickZoom(); // On by default
		// Enable scrollwheel on the map
		if (options.mapEnableScrollZoom) 
			thisMap.enableScrollWheelZoom(); //Off by default
		// Enable smooth zooming
		if (options.mapEnableSmoothZoom) 
			thisMap.enableContinuousZoom(); // Off by default
		// Enable Google Bar
		if (options.mapEnableGoogleBar) 
			thisMap.enableGoogleBar(); //Off by default
		// Enables Scale bar
		if (options.mapEnableScaleControl) 
			thisMap.addControl(new GScaleControl());
		
		if (options.debugMode) 
			console.log(Mapifies);
		
		if (typeof callback == 'function') 
			return callback(thisMap, element, options);
	} else {
		jQuery(element).text('Your browser does not support Google Maps.');
		return false;
	}
	return;
};

/**
 * A function to move a map to a passed position
 * @method
 * @namespace Mapifies
 * @id Mapifies.MoveTo
 * @alias Mapifies.MoveTo
 * @param {jQuery} element The element to initialise the map on.
 * @param {Object} options The object that contains the options.
 * @param {Object} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the map object and options or true.
 */
Mapifies.MoveTo = function ( element, options, callback ) {
	/**
 	 * Default options for MoveTo
   * @method
   * @namespace Mapifies
   * @id Mapifies.MoveTo
   * @alias Mapifies.MoveTo
   * @param {String} centerMethod The element to initialise the map on.
   * @param {String} mapType The type of map to create.  Options are 'map' (default), 'sat' and 'hybrid'.
   * @param {Object} mapCenter An array that contains the Lat/Lng coordinates of the map center.
   * @param {Number} mapZoom The initial zoom level of the map.
   * @return {Function} callback The callback option with the point object and options or true.
   */	
	function defaults() {
		return {
			'centerMethod': 'normal',
			'mapType': null,
			'mapCenter': [],
			'mapZoom': null
		};
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);	
	if (options.mapType)
		var mapType = Mapifies.GetMapType(options.mapType);
	var point = new GLatLng(options.mapCenter[0], options.mapCenter[1]);
	switch (options.centerMethod) {
		case 'normal':
			thisMap.setCenter(point, options.mapZoom, mapType);
		break;
		case 'pan':
			thisMap.panTo(point);
		break;
	}
	if (typeof callback == 'function') return callback(point, options);
};

/**
 * Save your current position on the map
 * @method
 * @namespace Mapifies
 * @id Mapifies.SavePosition
 * @alias Mapifies.SavePosition
 * @param {jQuery} element The element to initialise the map on.
 * @param {Object} options The object that contains the options.
 * @param {Object} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the map object and options or true.
 */
Mapifies.SavePosition = function( element, options, callback ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.savePosition();
	if (typeof callback == 'function') return callback(thisMap);
};

/**
 * Goto a previously saved position
 * @method
 * @namespace Mapifies
 * @id Mapifies.GotoSavedPosition
 * @alias Mapifies.GotoSavedPosition
 * @param {jQuery} element The element to initialise the map on.
 * @param {Object} options The object that contains the options.
 * @param {Function} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the map object and options or true.
 */
Mapifies.GotoSavedPosition = function ( element, options, callback) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.returnToSavedPosition();
	if (typeof callback == 'function') return callback(thisMap);
};

/**
 * Create a keyboard handler to handle keyboard navigation
 * @method
 * @namespace Mapifies
 * @id Mapifies.CreateKeyboardHandler
 * @alias Mapifies.CreateKeyboardHandler
 * @param {jQuery} element The element to initialise the map on.
 * @param {Object} options The object that contains the options.
 * @param {Object} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the keyboard handler.
 */
Mapifies.CreateKeyboardHandler = function( element, options, callback ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	var keyboardHandler = new GKeyboardHandler(thisMap);
	if (typeof callback == 'function') return callback(keyboardHandler);
};

/**
 * Check if a map container element has been resized or toggled from show/hide (Added r68)
 * @method
 * @namespace Mapifies
 * @id Mapifies.CheckResize
 * @alias Mapifies.CheckResize
 * @param {jQuery} element The element to initialise the map on.
 * @param {Object} options The object that contains the options.
 * @param {Object} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the map object handler.
 */
Mapifies.CheckResize = function( element, options, callback ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.checkResize();
	if (typeof callback == 'function') return callback(element);
};

/**
 * The SearchAddress function takes a map, options and callback function.  The options can contain either an address string, to which a point is returned - or reverse geocoding a GLatLng, where an address is returned
 * @method
 * @namespace Mapifies
 * @id Mapifies.SearchAddress
 * @param {jQuery} element The jQuery object containing the map element.
 * @param {Object} options An object of options
 * @param {Function} callback The callback function that returns the result
 * @return {Function} Returns a passed callback function or true if no callback specified
 */
Mapifies.SearchAddress = function( element, options, callback) {
	/**
	 * Default options for SearchAddress
	 * @method
	 * @namespace Mapifies.SearchAddress
	 * @id Mapifies.SearchAddress.defaults
	 * @alias Mapifies.SearchAddress.defaults
	 * @param {String} query The Address or GLatLng to query in the geocoder
	 * @param {String} returnType The type of value you want to return from Google.  This is mapped to the function names available, the options are 'getLatLng' which returns coordinates, and 'getLocations' which returns points.
	 * @param {GGeoCache} cache The GGeoCache to store the results in if required
	 * @param {String} countryCode The country code to localise results
	 * @return {Object} The options for SearchAddress
	 */
	function defaults() {
		return {
			// Address to search for
			'query': null,
			// Return Type
			'returnType': 'getLatLng',
			// Optional Cache to store Geocode Data (not implemented yet)
			'cache': undefined,
			// Country code for localisation (not implemented yet)
			'countryCode': 'uk'
		};
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
	
	// Check to see if the Geocoder already exists in the object
	// or create a temporary locally scoped one.
	if (typeof thisMap.Geocoder === 'undefined') {	
		if (typeof options.cache === 'undefined') {
		 	var geoCoder = new GClientGeocoder();
		} else {
			var geoCoder = new GClientGeocoder(cache);
		}
		Mapifies.MapObjects.Append(element, 'Geocoder', geoCoder);
		// We need to get the map object again, now we have attached the geocoder
		thisMap = Mapifies.MapObjects.Get(element);
	}
	thisMap.Geocoder[options.returnType](options.query, function(result){
		if (typeof callback === 'function') {
			return callback(result, options); 
		}
	});
	return;
};
	
/**
 * The SearchDirections function allows you to search for directions between two or more points and return it to a map and a directions panel
 * @method
 * @namespace Mapifies
 * @id Mapifies.SearchDirections
 * @param {jQuery} element The jQuery object containing the map element.
 * @param {Object} options An object of options
 * @param {Function} callback The callback function that returns the result
 * @return {Function} Returns a passed callback function or true if no callback specified
 */
Mapifies.SearchDirections = function( element, options, callback) {
	/**
	 * Default options for SearchDirections
	 * @method
	 * @namespace Mapifies.SearchDirections
	 * @id Mapifies.SearchDirections.defaults
	 * @alias Mapifies.SearchDirections.defaults
	 * @param {String} query The directions query to parse.  Must contain one 'from:' and one 'to:' query, but can contain multiple 'to:' queries.
	 * @param {String} panel The ID of the panel that the directions will be sent to.
	 * @param {String} local The local for the directions.
	 * @param {String} travelMode Allows you to specify the travel mode, either 'driving' or 'walking'.  Driving is the default.
	 * @param {Boolean} avoidHighways Allows you to avoid Highways/Motorway's on trips.  Please note this may not always be possible depending on the route.
	 * @param {Boolean} getPolyline Decides if the returned result will draw a polyline on the map on the journey.  Default is True.
	 * @param {Boolean} getSteps Decides if the textual directions are returned to the directions panel.
	 * @param {Boolean} preserveViewport Decides if the map will zoom and center in on the directions results.
	 * @param {Boolean} clearLastSearch Clears the last direction search if you do not want to have multiple points.
	 * @return {Object} The options for SearchDirections
	 */
	function defaults() {
		return {
			// From address
			'query': null,
			// Optional panel to show text directions
			'panel': null,
			//The locale to use for the directions result.
			'locale': 'en_GB',
			//The mode of travel, such as driving (default) or walking
			'travelMode': 'driving',
			// Option to avoid highways
			'avoidHighways': false,
			// Get polyline
			'getPolyline': true,
			// Get directions
			'getSteps': true,
			// Preserve Viewport
			'preserveViewport' : false,
			// clear last search
			'clearLastSearch' : false
		};
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
	
	var queryOptions = {
		'locale': options.locale,
		'travelMode': options.travelMode,
		'avoidHighways': options.avoidHighways,
		'getPolyline': options.getPolyline,
		'getSteps': options.getSteps,
		'preserveViewport' : options.preserveViewport
	};
	
	var panel = $(options.panel).get(0);
	
	if (typeof thisMap.Directions === 'undefined') {
  	Mapifies.MapObjects.Append(element, 'Directions', new GDirections(thisMap, panel));
  }	
	
	GEvent.addListener(thisMap.Directions, "load", onLoad);
  GEvent.addListener(thisMap.Directions, "error", onError);
	
	if (options.clearLastSearch) {
		thisMap.Directions.clear();
	}
	
	thisMap.Directions.load(options.query, queryOptions);
	
	function onLoad() {
		if (typeof callback == 'function') return callback(thisMap.Directions, options);	
	}
	
	function onError() {
		if (typeof callback == 'function') return callback(thisMap.Directions, options);	
	}
	
	return;
};

/**
 * Create an adsense ads manager for the map.  The Adsense manager will parse your page and show adverts on the map that relate to this.  Requires your adsense publisher id and channel
 * @method
 * @namespace Mapifies
 * @id Mapifies.CreateAdsManager
 * @param {jQuery} element The jQuery object containing the map element.
 * @param {Object} options An object of options
 * @param {Function} callback The callback function that returns the result
 * @return {Function} Returns a passed callback function or true if no callback specified
 */

Mapifies.CreateAdsManager = function( element, options, callback) {
	/**
	 * Default options for CreateAdsManager
	 * @method
	 * @namespace Mapifies.CreateAdsManager
	 * @id Mapifies.CreateAdsManager.defaults
	 * @alias Mapifies.CreateAdsManager.defaults
	 * @param {String} publisherId Your Adsense publisher ID
	 * @param {Number} maxAdsOnMap The maximum number of ads to show on the map at one time
	 * @param {Number} channel The AdSense channel this belongs to
	 * @param {Number} minZoomLevel The minimum zoom level to begin showing ads at
	 * @return {Object} The options for CreateAdsManager
	 */
	function defaults() {
		return {
			'publisherId':'',
			'maxAdsOnMap':3,
			'channel':0,
			'minZoomLevel':6
		}
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
	
	var adsOptions = {
		'maxAdsOnMap':options.maxAdsOnMap,
		'channel':options.channel,
		'minZoomLevel':options.minZoomLevel
	}
	
	if (typeof thisMap.AdsManager == 'undefined') {
  	Mapifies.MapObjects.Append(element, 'AdsManager', new GAdsManager(thisMap, options.publisherId, adsOptions));
  }	
	
	if (typeof callback == 'function') return callback(thisMap.AdsManager, options);
};
/**
 * This function allows you to pass a GeoXML or KML feed to a Google map.
 * @method
 * @namespace Mapifies
 * @id Mapifies.AddFeed
 * @alias Mapifies.AddFeed
 * @param {jQuery} element The element to initialise the map on.
 * @param {Object} options The object that contains the options.
 * @param {Fucntion} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the feed object and options.
 */
Mapifies.AddFeed = function( element, options, callback ) {
	/**
	 * Default options for AddFeed
	 * @method
	 * @namespace Mapifies.AddFeed
	 * @id Mapifies.AddFeed.defaults
	 * @alias Mapifies.AddFeed.defaults
	 * @param {String} feedUrl The URL of the GeoXML or KML feed.
	 * @param {Object} mapCenter An array with a lat/lng position to center the map on
	 * @return {Object} The options for AddFeed
	 */
	function defaults() {
		return {
			// URL of the feed to pass (required)
			'feedUrl': null,
			// Position to center the map on (optional)
			'mapCenter': []
		};
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);

	// Load feed
	var feed = new GGeoXml(options.feedUrl);
	// Add as overlay
	thisMap.addOverlay(feed);
	
	// If the user has passed the optional mapCenter,
	// then center the map on that point
	if (options.mapCenter[0] && options.mapCenter[1])
		thisMap.setCenter(new GLatLng(options.mapCenter[0], options.mapCenter[1]));
		
	if (typeof callback == 'function') return callback( feed, options );
	return;
};

/**
 * This function allows you to remove a GeoXML or KML feed from a Google map.
 * @method
 * @namespace Mapifies
 * @id Mapifies.RemoveFeed
 * @alias Mapifies.RemoveFeed
 * @param {jQuery} element The element to initialise the map on.
 * @param {GGeoXML} feed The feed to remove from the map
 * @param {Function} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the feed object and options.
 */
Mapifies.RemoveFeed = function ( element, feed, callback ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.removeOverlay(feed);
	if (typeof callback == 'function') return callback( feed );
	return;
};
/**
 * This function allows you to add a ground overlay to a map
 * @method
 * @namespace Mapifies
 * @id Mapifies.AddGroundOverlay
 * @alias Mapifies.AddGroundOverlay
 * @param {jQuery} element The element to initialise the map on.
 * @param {Object} options The object that contains the options.
 * @param {Function} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the feed object and options.
 */
Mapifies.AddGroundOverlay = function( element, options, callback) {
  /**
	 * Default options for AddGroundOverlay
	 * @method
	 * @namespace Mapifies.AddGroundOverlay
	 * @id Mapifies.AddGroundOverlay.defaults
	 * @alias Mapifies.AddGroundOverlay.defaults
	 * @param {Object} overlaySouthWestBounds The coordinates of the South West bounds of the image
	 * @param {Object} overlayNorthEastBounds The coordinates of the North East bounds of the image
	 * @param {String} overlayImage The URL of the image to be loaded
	 * @return {Object} The options for AddGroundOverlay
	 */
	function defaults() {
		return {
			// South West Boundry
			'overlaySouthWestBounds': undefined,
			// North East Boundry
			'overlayNorthEastBounds': undefined,
			// Image
			'overlayImage': undefined
		};
	};
	
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
	
	var boundries = new GLatLngBounds(new GLatLng(options.overlaySouthWestBounds[0], options.overlaySouthWestBounds[1]), new GLatLng(options.overlayNorthEastBounds[0], options.overlayNorthEastBounds[1]));
	groundOverlay = new GGroundOverlay(options.overlayImage, boundries);
	
	thisMap.addOverlay(groundOverlay);
		
	if (typeof callback == 'function') return callback( groundOverlay, options );
	return;
};

/**
 * This function removes an existing ground overlay
 * @method
 * @namespace Mapifies
 * @id Mapifies.RemoveGroundOverlay
 * @alias Mapifies.RemoveGroundOverlay
 * @param {jQuery} element The element to initialise the map on.
 * @param {GGroundOverlay} groundOverlay The ground overlay to remove.
 * @param {Function} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the feed object and options.
 */
Mapifies.RemoveGroundOverlay = function ( element, groundOverlay, callback ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.removeOverlay(groundOverlay);
	if (typeof callback === 'function') return callback(groundOverlay);
	return;
};
/**
 * This function allows you to add markers to the map with several options
 * @method
 * @namespace Mapifies
 * @id Mapifies.AddMarker
 * @alias Mapifies.AddMarker
 * @param {jQuery} element The element to initialise the map on.
 * @param {Object} options The object that contains the options.
 * @param {Function} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the marker object and options.
 */
Mapifies.AddMarker = function ( element, options, callback ) {
	/**
	 * Default options for AddGroundOverlay
	 * @method
	 * @namespace Mapifies.AddGroundOverlay
	 * @id Mapifies.AddGroundOverlay.defaults
	 * @alias Mapifies.AddGroundOverlay.defaults
	 * @param {Object} pointLatLng The Lat/Lng coordinates of the marker.
	 * @param {String} pointHTML The HTML to appear in the markers info window.
	 * @param {String} pointOpenHTMLEvent The javascript event type to open the marker info window.  Default is 'click'.
	 * @param {Boolean} pointIsDraggable Defines if the point is draggable by the end user.  Default false.
	 * @param {Boolean} pointIsRemovable Defines if the point can be removed by the user.  Default false.
	 * @param {Boolean} pointRemoveEvent The event type to remove a marker.  Default 'dblclick'.
	 * @param {Number} pointMinZoom The minimum zoom level to display the marker if using a marker manager.
	 * @param {Number} pointMaxZoom The maximum zoom level to display the marker if using a marker manager.
	 * @param {GIcon} pointIcon A GIcon to display instead of the standard marker graphic.
	 * @param {Boolean} centerMap Automatically center the map on the new marker.  Default false.
	 * @param {String} centerMoveMethod The method in which to move to the marker.  Options are 'normal' (default) and 'pan'.  Added r64
	 * @return {Object} The options for AddGroundOverlay
	 */
	function defaults() {
		var values = {
			'pointLatLng': undefined,
			'pointHTML': undefined,
			'pointOpenHTMLEvent': 'click',
			'pointIsDraggable': false,
			'pointIsRemovable': false,
			'pointRemoveEvent': 'dblclick',
			'pointMinZoom': 4,
			'pointMaxZoom': 17,
			'pointIcon': undefined,
			'centerMap': false,
			'centerMoveMethod':'normal',
			'zIndexProcess': undefined, // r73
			'importance': undefined // r73
		};
		return values;
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend({}, defaults(), options);
	
	var markerOptions = {}
	
	if (typeof options.pointIcon == 'object')
		jQuery.extend(markerOptions, {'icon': options.pointIcon});
		
	if (options.pointIsDraggable)
		jQuery.extend(markerOptions, {'draggable': options.pointIsDraggable});
			
	if (options.centerMap) {
		switch (options.centerMoveMethod) {
			case 'normal':
				thisMap.setCenter(new GLatLng(options.pointLatLng[0],options.pointLatLng[1]));
			break;
			case 'pan':
				thisMap.panTo(new GLatLng(options.pointLatLng[0],options.pointLatLng[1]));
			break;
		}
	}

	if (typeof (options.zIndexProcess) != "undefined") // r73
		jQuery.extend(markerOptions, { 'zIndexProcess': options.zIndexProcess }); // r73

	// Create marker, optional parameter to make it draggable
	var marker = new GMarker(new GLatLng(options.pointLatLng[0],options.pointLatLng[1]), markerOptions);

	if (typeof (options.importance) != "undefined") // r73
		marker.importance = options.importance; // r73

	// If it has HTML to pass in, add an event listner for a click
	if(options.pointHTML)
		GEvent.addListener(marker, options.pointOpenHTMLEvent, function(){
			marker.openInfoWindowHtml(options.pointHTML, {maxContent: options.pointMaxContent, maxTitle: options.pointMaxTitle});
		});
	// If it is removable, add dblclick event
	if(options.pointIsRemovable)
		GEvent.addListener(marker, options.pointRemoveEvent, function(){
			thisMap.removeOverlay(marker);
		});

	// If the marker manager exists, add it
	if(thisMap.MarkerManager) {
		thisMap.MarkerManager.addMarker(marker, options.pointMinZoom, options.pointMaxZoom);	
	} else {
		// Direct rendering to map
		thisMap.addOverlay(marker);
	}
		
	if (typeof callback == 'function') return callback(marker, options);
	return;
};


/**
 * This function allows you to remove markers from the map
 * @method
 * @namespace Mapifies
 * @id Mapifies.RemoveMarker
 * @alias Mapifies.RemoveMarker
 * @param {jQuery} element The element to initialise the map on.
 * @param {GMarker} options The marker to be removed
 * @param {Function} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the marker object.
 */
Mapifies.RemoveMarker = function ( element, marker, callback ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.removeOverlay(marker);
	if (typeof callback === 'function') return callback(marker);
	return;
};

/**
 * This function allows you to create a marker manager to store and manage any markers created on the map.  Google recommends not using this marker manager and instead using the open source one.
 * @method
 * @deprecated
 * @namespace Mapifies
 * @id Mapifies.CreateMarkerManager
 * @alias Mapifies.CreateMarkerManager
 * @param {jQuery} element The element to initialise the map on.
 * @param {GMarker} options The marker to be removed
 * @param {Function} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the marker object and options.
 */
Mapifies.CreateMarkerManager = function(element, options, callback) {
	/**
	 * Default options for CreateMarkerManager
	 * @method
	 * @namespace Mapifies.CreateMarkerManager
	 * @id Mapifies.CreateMarkerManager.defaults
	 * @alias Mapifies.CreateMarkerManager.defaults
	 * @param {String} markerManager The type of marker manager to use.  Options are 'GMarkerManager' (default) and 'MarkerManager'.  (Added r72)
	 * @param {Number} borderPadding Specifies, in pixels, the extra padding outside the map's current viewport monitored by a manager. Markers that fall within this padding are added to the map, even if they are not fully visible.
	 * @param {Number} maxZoom The maximum zoom level to show markers at
	 * @param {Boolean} trackMarkers Indicates whether or not a marker manager should track markers' movements.
	 * @return {Object} The options for CreateMarkerManager
	 */
	function defaults() {
		return {
			'markerManager': 'GMarkerManager',
			// Border Padding in pixels
			'borderPadding': 100,
			// Max zoom level 
			'maxZoom': 17,
			// Track markers
			'trackMarkers': false
		}
	}
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
	
	var markerManagerOptions = {
		'borderPadding': options.borderPadding,
		'maxZoom': options.maxZoom,
		'trackMarkers': options.trackMarkers
	}
	
	var markerManager = new window[options.markerManager](thisMap, options);
	Mapifies.MapObjects.Append(element, 'MarkerManager',markerManager);

	// Return the callback
	if (typeof callback == 'function') return callback( markerManager, options );
};
/**
 * This function allows you to add a polygon to a map using GLatLng points
 * @method
 * @namespace Mapifies
 * @id Mapifies.AddPolygon
 * @alias Mapifies.AddPolygon
 * @param {jQuery} element The element to initialise the map on.
 * @param {Object} options The object that contains the options.
 * @param {Function} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the polygon object, polygon options and options.
 */
Mapifies.AddPolygon = function( element, options, callback ) {
	/**
	 * Default options for AddPolygon
	 * @method
	 * @namespace Mapifies.AddPolygon
	 * @id Mapifies.AddPolygon.defaults
	 * @alias Mapifies.AddPolygon.defaults
	 * @param {Object} polygonPoints An array of Lat/Lng points that make up the vertexes of the polygon.
	 * @param {String} polygonStrokeColor The stroke colour for the polygon.
	 * @param {Number} polygonStrokeWeight The thickness of the polygon line.
	 * @param {Number} polygonStrokeOpacity A value from 0 to 1 of for the line opacity.
	 * @param {String} polygonFillColor The colour of the fill area for the polygon.
	 * @param {Number} polygonFillOpacity The value from 0 to 1 for the polygon fill opacity.
	 * @param {Object} mapCenter An array containing the LatLng point to center on.
	 * @param {Boolean} polygonClickable Defines if the polygon is clickable or not. Default true.
	 * @return {Object} The options for AddPolygon
	 */
	function defaults() {
		return {
			// An array of GLatLng objects
			'polygonPoints': [],
			// The outer stroke colour
	 		'polygonStrokeColor': "#000000",
	 		// Stroke thickness
	 		'polygonStrokeWeight': 5,
	 		// Stroke Opacity
	 		'polygonStrokeOpacity': 1,
	 		// Fill colour
	 		'polygonFillColor': "#ff0000",
	 		// Fill opacity
	 		'polygonFillOpacity': 1,
	 		// Optional center map
	 		'mapCenter': undefined,
	 		// Is polygon clickable?
	 		'polygonClickable': true
		}
	}
	
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
	var polygonOptions = {};
	
	if (!options.polygonClickable)
		polygonOptions = jQuery.extend(polygonOptions, {clickable: false});
	 		
	if(typeof options.mapCenter !== 'undefined' && options.mapCenter[0] && options.mapCenter[1])
		thisMap.setCenter(new GLatLng(options.mapCenter[0], options.mapCenter[1]));
	
	var allPoints = [];
	jQuery.each(options.polygonPoints, function(i, point) {
		allPoints.push(new GLatLng(point[0],point[1]));
	});
	
	var polygon = new GPolygon(allPoints, options.polygonStrokeColor, options.polygonStrokeWeight, options.polygonStrokeOpacity, options.polygonFillColor, options.polygonFillOpacity, polygonOptions);
	thisMap.addOverlay(polygon);
		
	if (typeof callback == 'function') return callback(polygon, polygonOptions, options);
	return;
}

/**
 * This function allows you to remove a polygon from the map
 * @method
 * @namespace Mapifies
 * @id Mapifies.RemovePolygon
 * @alias Mapifies.RemovePolygon
 * @param {jQuery} element The element to initialise the map on.
 * @param {GPolygon} polygon The polygon to be removed
 * @param {Function} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the polygon.
 */
Mapifies.RemovePolygon = function ( element, polygon, callback ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.removeOverlay(polygon);
	if (typeof callback === 'function') return callback(polygon);
	return;
};
/**
 * This function allows you to add a polyline to a map using GLatLng points
 * @method
 * @namespace Mapifies
 * @id Mapifies.AddPolyline
 * @alias Mapifies.AddPolyline
 * @param {jQuery} element The element to initialise the map on.
 * @param {Object} options The object that contains the options.
 * @param {Function} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the polygon object, polygon options and options.
 */
Mapifies.AddPolyline = function (element, options, callback) {
	/**
	 * Default options for AddPolyline
	 * @method
	 * @namespace Mapifies.AddPolyline
	 * @id Mapifies.AddPolygon.defaults
	 * @alias Mapifies.AddPolygon.defaults
	 * @param {Object} polylinePoints An array of Lat/Lng points that make up the vertexes of the polyline.
	 * @param {String} polylineStrokeColor The stroke colour for the polyline.
	 * @param {Number} polylineStrokeWidth The thickness of the polyline line.
	 * @param {Number} polylineStrokeOpacity A value from 0 to 1 of for the line opacity.
	 * @param {Object} mapCenter An array containing the LatLng point to center on.
	 * @param {Boolean} polylineGeodesic Defines if the line follows the curve of the earth.  Default false.
	 * @param {Boolean} polylineClickable Defines if the polygon is clickable or not. Default true.
	 * @return {Object} The options for AddPolyline
	 */
	function defaults() {
		return {
			// An array of GLatLng objects
			'polylinePoints': [],
			// Colour of the line
			'polylineStrokeColor': "#ff0000",
			// Width of the line
			'polylineStrokeWidth': 10,
			// Opacity of the line
			'polylineStrokeOpacity': 1,
			// Optional center map
			'mapCenter': [],
			// Is line Geodesic (i.e. bends to the curve of the earth)?
			'polylineGeodesic': false,
			// Is line clickable?
			'polylineClickable': true
		};
	};
	
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
	var polyLineOptions = {};
	if (options.polylineGeodesic)
		jQuery.extend(polyLineOptions, {geodesic: true});
			
	if(!options.polylineClickable)
		jQuery.extend(polyLineOptions, {clickable: false});

	if (options.mapCenter[0] && options.mapCenter[1])
		thisMap.setCenter(new GLatLng(options.mapCenter[0], options.mapCenter[1]));

	var allPoints = [];
	jQuery.each(options.polylinePoints, function(i, point) {
		allPoints.push(new GLatLng(point[0],point[1]));
	});

	var polyline = new GPolyline(allPoints, options.polylineStrokeColor, options.polylineStrokeWidth, options.polylineStrokeOpacity, polyLineOptions);
	thisMap.addOverlay(polyline);
		
	if (typeof callback == 'function') return callback(polyline, polyLineOptions, options);
	return;
}

/**
 * This function allows you to remove a polyline from the map
 * @method
 * @namespace Mapifies
 * @id Mapifies.RemovePolyline
 * @alias Mapifies.RemovePolyline
 * @param {jQuery} element The element to initialise the map on.
 * @param {GPolyline} polyline The polyline to be removed
 * @param {Function} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the polyline.
 */
Mapifies.RemovePolyline = function (element, polyline, callback ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.removeOverlay(polyline);
	if (typeof callback === 'function') return callback(polyline);
	return;
};

/**
 * This function allows you to add a screen overlay to a map.
 * @method
 * @namespace Mapifies
 * @id Mapifies.AddScreenOverlay
 * @alias Mapifies.AddScreenOverlay
 * @param {jQuery} element The element to initialise the map on.
 * @param {Object} options The object that contains the options.
 * @param {Function} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the screen overlay and options.
 */
Mapifies.AddScreenOverlay = function( element, options, callback ) {
	/**
	 * Default options for AddScreenOverlay
	 * @method
	 * @namespace Mapifies.AddScreenOverlay
	 * @id Mapifies.AddScreenOverlay.defaults
	 * @alias Mapifies.AddScreenOverlay.defaults
	 * @param {String} imageUrl The URL of the image to load.
	 * @param {Object} screenXY The X/Y position in the viewport to place the image.
	 * @param {Object} overlayXY The overlay X/Y position in the viewport.
	 * @param {Object} size The size of the image, which is converted to a GSize.
	 * @return {Object} The options for AddScreenOverlay
	 */
	function defaults() {
		return {
			'imageUrl':'',
			'screenXY':[],
			'overlayXY':[],
			'size':[]
		};
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);

	var overlay = new GScreenOverlay(options.imageUrl, new GScreenPoint(options.screenXY[0],options.screenXY[1]), new GScreenPoint(options.overlayXY[0],options.overlayXY[1]), new GScreenSize(options.size[0],options.size[1]));
	thisMap.addOverlay(overlay);
		
	if (typeof callback == 'function') return callback(overlay, options);
};

/**
 * This function allows you to remove a screen overlay from the map
 * @method
 * @namespace Mapifies
 * @id Mapifies.RemoveScreenOverlay
 * @alias Mapifies.RemoveScreenOverlay
 * @param {jQuery} element The element to initialise the map on.
 * @param {GScreenOverlay} overlay The overlay to be removed
 * @param {Function} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the overlay.
 */
Mapifies.RemoveScreenOverlay = function ( element, overlay, callback ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.removeOverlay(overlay);
	if (typeof callback === 'function') return callback(overlay);
	return;
};

/**
 * This function allows you to add a Google Streetview
 * @method
 * @namespace Mapifies
 * @id Mapifies.CreateStreetviewPanorama
 * @alias Mapifies.CreateStreetviewPanorama
 * @param {jQuery} element The element to initialise the map on.
 * @param {Object} options The object that contains the options.
 * @param {Function} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the street view.
 */
Mapifies.CreateStreetviewPanorama = function( element, options, callback ) {
	/**
	 * Default options for CreateStreetviewPanorama
	 * @method
	 * @namespace Mapifies.CreateStreetviewPanorama
	 * @id Mapifies.CreateStreetviewPanorama.defaults
	 * @alias Mapifies.CreateStreetviewPanorama.defaults
	 * @param {String} overideContainer A ID of a div to put the street view into, otherwise it will default to the map.
	 * @param {Object} latlng The starting Lat/Lng of the streetview - this is required.
	 * @param {Object} pov The point of view to initialse the map on.  This is 3 values, X/Y/Z
	 * @return {Object} The options for CreateStreetviewPanorama
	 */
	function defaults() {
		return {
			'overideContainer':'',
			'latlng':[40.75271883902363, -73.98262023925781],
			'pov': []
		}
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
	// Create Street View Overlay
	
	var container = null;
	if (options.overideContainer !== '') {
		container = jQuery(options.overideContainer).get(0);
	} else {
		container = jQuery(element).get(0);
	}
	
	var viewOptions = {};
	if (options.pov.length > 0) {
		jQuery.extend(viewOptions, {'pov':new GPov(options.latlng[0],options.latlng[1],options.latlng[2])});
	}
	if (options.latlng.length > 0) {
		jQuery.extend(viewOptions, {'latlng':new GLatLng(options.latlng[0],options.latlng[1])});
	}
	
	var overlay = new GStreetviewPanorama(container, viewOptions);
	if (typeof callback == 'function') return callback(overlay, options);
	return;
};

/**
 * This function allows you to remove a street view from the map
 * @method
 * @namespace Mapifies
 * @id Mapifies.RemoveStreetviewPanorama
 * @alias Mapifies.RemoveStreetviewPanorama
 * @param {jQuery} element The element to initialise the map on.
 * @param {GStreetView} view The view to be removed
 * @param {Function} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the view.
 */
Mapifies.RemoveStreetviewPanorama = function ( element, view, callback ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	view.remove();
	if (typeof callback == 'function') return callback( view );
	return;
};
/**
 * This function allows you to add a Google Traffic Layer
 * @method
 * @namespace Mapifies
 * @id Mapifies.AddTrafficInfo
 * @alias Mapifies.AddTrafficInfo
 * @param {jQuery} element The element to initialise the map on.
 * @param {Object} options The object that contains the options.
 * @param {Function} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the traffic layer.
 */
Mapifies.AddTrafficInfo = function( element, options, callback) {
	/**
	 * Default options for AddTrafficInfo
	 * @method
	 * @namespace Mapifies.AddTrafficInfo
	 * @id Mapifies.AddTrafficInfo.defaults
	 * @alias Mapifies.AddTrafficInfo.defaults
	 * @param {Object} mapCenter The Lat/Lng to center the map on
	 * @return {Object} The options for AddTrafficInfo
	 */
	function defaults() {
		return {
			// Center the map on this point (optional)
			'mapCenter': []
		};
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);

	var trafficOverlay = new GTrafficOverlay;
	// Add overlay
	thisMap.addOverlay(trafficOverlay);
	// If the user has passed the optional mapCenter,
	// then center the map on that point
	if (options.mapCenter[0] && options.mapCenter[1]) {
		thisMap.setCenter(new GLatLng(options.mapCenter[0], options.mapCenter[1]));
	}
	if (typeof callback == 'function') return callback(trafficOverlay, options);
};

/**
 * This function allows you to remove a traffic layer from the map
 * @method
 * @namespace Mapifies
 * @id Mapifies.RemoveTrafficInfo
 * @alias Mapifies.RemoveTrafficInfo
 * @param {jQuery} element The element to initialise the map on.
 * @param {GTrafficOverlay} trafficOverlay The traffic overlay to be removed
 * @param {Function} callback The callback function to pass out after initialising the map.
 * @return {Function} callback The callback option with the traffic overlay.
 */
Mapifies.RemoveTrafficInfo = function ( element, trafficOverlay, callback ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.removeOverlay(trafficOverlay);
	if (typeof callback === 'function') return callback(trafficOverlay);
	return;
};
/**
 * A helper method that allows you to pass the status code of a search and get back a friendly oject
 * @method
 * @namespace Mapifies
 * @id Mapifies.SearchCode
 * @param {Number} code The status code of the query
 * @return {Object} Returns a friendly object that contains the 'code', a 'success' boolean and a helpful 'message'.
 */
Mapifies.SearchCode = function ( code ) {
	switch (code) {
		case G_GEO_SUCCESS:
			return {'code':G_GEO_SUCCESS,'success':true,'message':'Success'};
		case G_GEO_UNKNOWN_ADDRESS:
			return {'code' : G_GEO_UNKNOWN_ADDRESS, 'success' : false, 'message' : 'No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect'};
			break;
		case G_GEO_SERVER_ERROR:
			return {'code' : G_GEO_UNKNOWN_ADDRESS, 'success' : false, 'message' : 'A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.'};
			break;
		case G_GEO_MISSING_QUERY:
			return {'code' : G_GEO_UNKNOWN_ADDRESS, 'success' : false, 'message' : 'The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.'};
			break;
		case G_GEO_BAD_KEY:
			return {'code' : G_GEO_UNKNOWN_ADDRESS, 'success' : false, 'message' : 'The given key is either invalid or does not match the domain for which it was given.'};
			break;
		case G_GEO_BAD_REQUEST:
			return {'code' : G_GEO_UNKNOWN_ADDRESS, 'success' : false, 'message' : 'A directions request could not be successfully parsed.'};
			break;
		default:
			return {
				'code': null,
				'success': false,
				'message': 'An unknown error occurred.'
			};
		break;
	};
}

/**
 * An internal function to get the google maptype constant
 * @method
 * @namespace Mapifies
 * @id Mapifies.GetMapType
 * @alias Mapifies.GetMapType
 * @param {String} mapType The string of the map type.
 * @return {String} mapType The Google constant for a maptype.
 */
Mapifies.GetMapType = function ( mapType ) {
	// Lets set our map type based on the options
	switch(mapType) {
		case 'map':	// Normal Map
			mapType = G_NORMAL_MAP;
		break;
		case 'sat':	// Satallite Imagery
			mapType = G_SATELLITE_MAP;
		break;
		case 'hybrid':	//Hybrid Map
			mapType = G_HYBRID_MAP;
		break;
	};
	return mapType;
};

/**
 * An internal function to get the google travel mode constant
 * @method
 * @namespace Mapifies
 * @id Mapifies.GetTravelMode
 * @alias Mapifies.GetTravelMode
 * @param {String} travelMode The string of the travel mode.
 * @return {String} travelMode The Google constant for a travel mode.
 */
Mapifies.GetTravelMode = function ( travelMode ) {
	switch(travelMode) {
		case 'driving':	
			travelMode = G_TRAVEL_MODE_DRIVING;
		break;
		case 'walking':	
			travelMode = G_TRAVEL_MODE_WALKING;
		break;
	};
	return travelMode;
};

/**
 * A helper function to create a google GIcon
 * @method
 * @namespace Mapifies
 * @id Mapifies.createIcon
 * @alias Mapifies.createIcon
 * @param {Object} options The options to create the icon
 * @return {GIcon} A GIcon object
 */
Mapifies.createIcon = function (options) {
	/**
	 * Default options for createIcon
	 * @method
	 * @namespace Mapifies.createIcon
	 * @id Mapifies.createIcon.defaults
	 * @alias Mapifies.createIcon.defaults
	 * @param {String} iconImage The foreground image URL of the icon.
	 * @param {String} iconShadow The shadow image URL of the icon.
	 * @param {GSize} iconSize The pixel size of the foreground image of the icon.
	 * @param {GSize} iconShadowSize The pixel size of the shadow image.
	 * @param {GPoint} iconAnchor The pixel coordinate relative to the top left corner of the icon image at which this icon is anchored to the map.
	 * @param {GPoint} iconInfoWindowAnchor The pixel coordinate relative to the top left corner of the icon image at which the info window is anchored to this icon.
	 * @param {String} iconPrintImage The URL of the foreground icon image used for printed maps. It must be the same size as the main icon image given by image.
	 * @param {String} iconMozPrintImage The URL of the foreground icon image used for printed maps in Firefox/Mozilla. It must be the same size as the main icon image given by image.
	 * @param {String} iconPrintShadow The URL of the shadow image used for printed maps. It should be a GIF image since most browsers cannot print PNG images.
	 * @param {String} iconTransparent The URL of a virtually transparent version of the foreground icon image used to capture click events in Internet Explorer. This image should be a 24-bit PNG version of the main icon image with 1% opacity, but the same shape and size as the main icon.
	 * @return {Object} The options for createIcon
	 */
	function defaults() {
		return {
			'iconImage': undefined,
			'iconShadow': undefined,
			'iconSize': undefined,
			'iconShadowSize': undefined,
			'iconAnchor': undefined,
			'iconInfoWindowAnchor': undefined,
			'iconPrintImage': undefined,
			'iconMozPrintImage': undefined,
			'iconPrintShadow': undefined,
			'iconTransparent': undefined
		};
	};
	
	options = jQuery.extend(defaults(), options);
	var icon = new GIcon(G_DEFAULT_ICON);
		
	if(options.iconImage)
		icon.image = options.iconImage;
	if(options.iconShadow)
		icon.shadow = options.iconShadow;
	if(options.iconSize)
		icon.iconSize = options.iconSize;
	if(options.iconShadowSize)
		icon.shadowSize = options.iconShadowSize;
	if(options.iconAnchor)
		icon.iconAnchor = options.iconAnchor;
	if(options.iconInfoWindowAnchor)
		icon.infoWindowAnchor = options.iconInfoWindowAnchor;
	return icon;
};

/**
 * A helper function to get the map center as a GLatLng
 * @method
 * @namespace Mapifies
 * @id Mapifies.getCenter
 * @alias Mapifies.getCenter
 * @param {jQuery} element The element that contains the map.
 * @return {GLatLng} A object containing the center of the map
 */
Mapifies.getCenter = function ( element ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	return thisMap.getCenter();
};

/**
 * A helper function to get the bounds of the map
 * @method
 * @namespace Mapifies
 * @id Mapifies.getBounds
 * @alias Mapifies.getBounds
 * @param {jQuery} element The element that contains the map.
 * @return {GSize} The bounds of the map
 */
Mapifies.getBounds = function (element){
	var thisMap = Mapifies.MapObjects.Get(element);
	return thisMap.getBounds();
};var Mapifies;

if (!Mapifies) Mapifies = {};

(function($){
	$.fn.jmap = function(method, options, callback) {
		return this.each(function(){
			if (method == 'init' && typeof options == 'undefined') {
				new Mapifies.Initialise(this, {}, null);
			} else if (method == 'init' && typeof options == 'object') {
				new Mapifies.Initialise(this, options, callback);
			} else if (method == 'init' && typeof options == 'function') {
				new Mapifies.Initialise(this, {}, options);
			} else if (typeof method == 'object' || method == null) {
				new Mapifies.Initialise(this, method, options);
			} else {
				try {
					new Mapifies[method](this, options, callback);
				} catch(err) {
					throw Error('Mapifies Function Does Not Exist');
				}
			}
		});
	}
})(jQuery);
;(function() {

// Namespacing
if (!window.mvc) window.mvc = function() { };

// This is called by the code generated script
var xforms = window.mvc.xforms = {
	init: function(form) { initChildCons(form, ''); }
};

/** Classes **/
function controlBase(el, con) { }

function group(el, con) {
	initChildCons(con, el.id);
}

function repeat(el, con) {
	this.index = el.childNodes.length - 1;
	$.each(el.childNodes, function(i) {
		this.xforms = new repeatItem(this, i);
		initChildCons(con, el.id + '-' + i);
	});
}
repeat.prototype.insertItem = insertItem;
repeat.prototype.deleteItem = deleteItem;
repeat.prototype.buildTemplate = buildTemplate;

function repeatItem(el, itemIndex) {
	this.el = el;
	this.itemIndex = itemIndex;
}

/** Common functions **/
function getControl(conID) {
	var jq = $('#' + conID);
	if (jq.length > 0) return jq[0];
	// This is commented out because we may need two or more groups with the
	// same ID (even though this is technically illegal in HTML - is there a
	// better way to identify groups or xforms controls in general?)
	//else if (jq.length > 1) throw('XForms: Multiple elements found for ID = ' + conID); 
	else throw('XForms: Element not found for ID = ' + conID);
}

/** Initialization code **/
function initChildCons(con, prefix) {
	$.each(con.cons, function(i, childCon) {
		initControl(childCon, prefix);
	});
}

function initControl(con, prefix) {
	if (prefix.length > 0 && con.id.length > 0) prefix = prefix + '_';
	var conID = prefix + con.id;
	var el = getControl(conID);
	initDom(el, con);

	// Bind actions
	if (con.acts) {
		$.each(con.acts, function(i, action) {
			if (action.type == 0) bindAction(el, action);
			else if (action.type == 2) bindInsertAction(el, action);
			else if (action.type == 3) bindDeleteAction(el, action);
		});
	}
	
	// We are rebuilding, so trigger the event
	$(el).trigger('xforms-rebuild');
}

// Append the xforms information directly to the DOM
function initDom(el, con) {
	el.xforms = createDomControl(el, con);
	el.xforms.con = con;
	el.xforms.el = el;
}

// Create a script instance of an XForm control
function createDomControl(el, con) {
	if (con.type == 0) return new group(el, con);
	else if (con.type == 3) return new repeat(el, con);
	return new controlBase(el, con);
}

// Binds XForm actions to the DOM (using HTML events via jQuery bind)
function bindAction(el, action) {
	// Condition not currently supported, dont really need
	// it as we are calling a custom script function
	eval('var func = ' + action.func);
	$(el).bind(action.ev, func);
}

// Insert specific to a trigger
function bindInsertAction(el, action) {
	eval('var cond = ' + action.cond);
	var repeat = getTriggerRepeat(el, action.ns);
	$(el).bind(action.ev, function() {
		if (cond != null ? cond() : true) {
			var index = getRepeatIndex(repeat, el, action.at);
			repeat.xforms.insertItem(index, action.pos);
		}
	});
}

// Delete specific to a trigger
function bindDeleteAction(el, action) {
	eval('var cond = ' + action.cond);
	var repeat = getTriggerRepeat(el, action.ns);
	$(el).bind(action.ev, function() {
		if (cond != null ? cond() : true) {
			var index = getRepeatIndex(repeat, el, action.at);
			repeat.xforms.deleteItem(index);
		}
	});
}

// Conditionally execute a function
function actionEvent(ev) {
	if (cond != null ? cond() : true) func(ev);
}

/** Repeat functions **/
function insertItem(index, position) {
	if (index == undefined) index = this.el.childNodes.length - 1;
	if (position == undefined) position = 0;

	var template = this.buildTemplate();
	var jq = $(this.el);
	
	if (this.el.childNodes.length == 0) {
		// If repeat is empty, just add it
		jq.html(template);
	} else if (index > -1) {
		var insertItem = $(this.el.childNodes[index]);
		if (position == 1) insertItem.before(template);
		else insertItem.after(template);
	}
	
	initChildCons(this.con, this.el.id + '-' + template.xforms.itemIndex);
	jq.trigger('xforms-insert', [template, index, position]);
	return template;
};

function deleteItem(index) {
	var jq = $(this.el);
	
	if (index > -1) {
		var deleteItem = jq.children().eq(index);
		deleteItem.remove();
		jq.trigger('xforms-delete', [deleteItem[0], index]);
	}
};

function buildTemplate() {
	this.index++;
	var temJQ = $(this.con.itemTemplate);
	var tem = temJQ[0];
	tem.xforms = new repeatItem(tem, this.index);
	var itemID = this.el.id + '-' + this.index;
	reindexAttr(this, temJQ, 'id', itemID);
	reindexAttr(this, temJQ, 'name', itemID);
	reindexAttr(this, temJQ, 'for', itemID);
	return tem;
}

function reindexAttr(repeat, tem, attr, itemID) {
	$(tem).find('[' + attr + '^=' + repeat.con.templateID + ']').each(function() {
		var jqCon = $(this);
		var newID = jqCon.attr(attr).replace(repeat.con.templateID, itemID);
		jqCon.attr(attr, newID);
	});
}

function getRepeatIndex(repeat, el, at) {
	var itemLength = repeat.childNodes.length;
	if (itemLength == 0 || at == 1)
		return 0;

	if (at == 2 && itemLength > 0) {
		return itemLength - 1;
	} else if (at == 0) {
		var tmpEl = el;
		while (tmpEl.xforms == undefined || tmpEl.xforms.itemIndex == undefined) {
			tmpEl = tmpEl.parentNode;
			if (tmpEl == undefined)
				throw("At = current not valid for insert on trigger " + el.id);
		}
		var item = $(tmpEl);
		var repeatIndex = $(repeat).children().index(item);
		return repeatIndex;
	}
}

function getTriggerRepeat(el, nodeset) {
	var conID = el.xforms.con.id;
	var repeatID = el.id.substr(0, el.id.length - conID.length);
	
	if (nodeset.length > 0) repeatID = repeatID + nodeset;
	else repeatID = repeatID.substr(0, repeatID.lastIndexOf('-'));
	
	var dom = getControl(repeatID);
	return dom;
}

})();;var local_BlockUiElementSelector = "#main";

$(document).ready(function() {
	$("form.xform").submit(function() { engine.WorkingDialog(local_BlockUiElementSelector); });
});

function hotel_ToggleDescription(e, hotelId) {
	if (window.event) e = window.event;
	var srcEl = e.srcelement ? e.srcelement : e.target;
	$("span.rest, span.more", $(srcEl).parent().parent()).toggle();
}
function hotel_ToggleModeProducts(hotelId) {
	if($('#hotel_' + hotelId + ' tr.prod-hidden').css("display") == "none")
		$('#hotel_' + hotelId + ' tr.prod-hidden').show();
	else
		$('#hotel_' + hotelId + ' tr.prod-hidden').hide();
}
var wasCurrencyChanged = false;
function currency_OnChange(o) {
	if (o == null || typeof (arHotelIDs) == "undefined" || arHotelIDs.length < 1)
		return;

	var selectedCurrency = o.value;
	for (i = 0; i < arHotelIDs.length; i++) {
		var hotelData = $("table#hotel_" + arHotelIDs[i]).metadata();

		var curFrom = hotelData.curr, curTo = (selectedCurrency == "" ? hotelData.curr : selectedCurrency);
		var exchRate = getExchangeRate(curFrom, curTo);
		if (exchRate < 0)
			return;
		//prepocteme ceny
		$("#hotel_" + arHotelIDs[i] + " span.rate, .hotel-minies li." + arHotelIDs[i] + " span.rate").each(function(i) {
			var v = $(this).metadata().o * exchRate;
			$(this).text(v.toFixed(2));
		});
		//prehodime currency
		$("#hotel_" + arHotelIDs[i] + " span.curr, .hotel-minies li." + arHotelIDs[i] + " span.curr").text(selectedCurrency == "" ? hotelData.curr : selectedCurrency);
	}
	if (false/*@cc_on || @_jscript_version < 5.7@*/)/*IE6*/ $("div.pager a.active:first").focus(); else $(o).blur();
	wasCurrencyChanged = true;
}
var arExchangeRates = new Array();
function getExchangeRate(fromCode, toCode) {
	if (fromCode == toCode) return 1;
	var d = arExchangeRates[fromCode + "_" + toCode];
	if (d == null) {
		var o = $.ajax({
			async: false,
			type: "GET",
			url: "/en/WebService.mvc/GetExchangeRate?currencyCodeFrom=" + fromCode + "&currencyCodeTo=" + toCode,
			contentType: "application/json; charset=utf-8",
			dataType: "json"
		});
		var e = eval("(" + o.responseText + ")");
		if (e.Message) {
			alert("Ajax Error:\n" + e.Message);
			return -1;
		}
		arExchangeRates[fromCode + "_" + toCode] = e;
	}
	return arExchangeRates[fromCode + "_" + toCode];
}

function pageRequest_OnBegin() {
	engine.WorkingDialog(local_BlockUiElementSelector);
}
function pageRequest_OnSuccess() {
	engine.WorkingDialog(local_BlockUiElementSelector, false);
	if (wasCurrencyChanged)
		currency_OnChange(document.getElementById("Currencies"));
	engine.ToolTipsInit();
}
function pageRequest_Failed(o) {
	$.unblockUI();
	alert("Ajax Error.\nPlease, try later, or contact site admnistrator.");
}


function loadHotelPage(url) {
	$('html, body').animate({ scrollTop: 0 }, 'fast');
	engine.WorkingDialog(local_BlockUiElementSelector);
	$.get(url, function(data) {
		$("#hotels").html(data);
		engine.WorkingDialog(local_BlockUiElementSelector, false);
		if (wasCurrencyChanged) currency_OnChange(document.getElementById("Currencies"));
		engine.ToolTipsInit("#hotels");
		mapHotelList_Destroy();
		if ($("input[id$='_IsHotelsMapVisible']").val().toLowerCase() == "true")
			mapHotelList_Show();
	});
}
;$().ready(function() {
	$("form.xf td.value.date input[type='hidden'], table.info input.date-picker[type='hidden']").datepicker({
		mandatory: true,
		gotoCurrent: true,
		changeMonth: true,
		changeYear: true,
		minDate: '+1d',
		maxDate: '+1y +1m +1d',
		showOn: 'both',
		dateFormat: datePicker_DateFormat,
		buttonImageOnly: true,
		buttonImage: datePicker_ImageButton,
		onSelect: function(dateText) {
			avhForm.SetDate(this.id.split("_")[1], $(this).datepicker('getDate'));
		}
	});
	
	$("#AvhSearchRequest_CurrencyCode").change(function() {
		currency_OnChange(this);
		$("#Currencies").selectOptions(this.value, true);
	});
	
	$("#advanced-search-button a").click(function() {
		$(this).toggleClass("hide");
		$("#hotel-search-form-body tr.advanced").toggleClass("hidden");
	});
});


function goAvh(hotelID, rateTypeID, roomID) {
	$("#HotelID").val(hotelID);
	$("#RateTypeID").val(rateTypeID);
	$("#RoomID").val(roomID);
	$("#TimeStampMs").val(new Date().getTime());
	$("#formAvh").submit();
	engine.Working();
	return false;
}

function AvhSearchForm( idPrefix, minDate, maxDate ) {
	this.IdPrefix = idPrefix;
	this.MinDate = minDate; this.MinDate.setHours(0, 0, 0, 0);
	this.MaxDate = maxDate; this.MaxDate.setHours(0, 0, 0, 0);
	this.MaxOccupancy = 5;

	var guestAgeShowIndex = 3;
	var selectMYDSeparator = " / "; //separator v hodnotach selectu

	this.GetOccupancy = function() {
		return $(getIdJQ("Occupancy")).val();
	}

	this.GetDateFromSelects = function(propName) {
		var monthYear = $(getIdJQ(propName + "_MonthYear") + " :selected").text(), s = monthYear.split(selectMYDSeparator);
		var day = $(getIdJQ(propName + "_Day") + " :selected").text(), month = s[0], year = s[1];
		var date = new Date();
		date.setFullYear(year, month - 1, day);
		date.setHours(0, 0, 0, 0);
		return date;
	}

	this.SetDate = function(propName, date) {
		var o = setDate(propName, date);
		this.Validate(o);
		this.MonthYearChanged(o);
	}

	this.Validate = function(o) {
		var propName = o.name.replace(getId(""), "").split("_")[0], fromDate = this.GetDateFromSelects("FromDate"), toDate = this.GetDateFromSelects("ToDate");
		if (fromDate < avhForm.MinDate) { fromDate = avhForm.MinDate; setDate("FromDate", fromDate); } else if (fromDate >= avhForm.MaxDate) { fromDate.setDate(avhForm.MaxDate.getDate() - 1); setDate("FromDate", fromDate); }
		if (toDate <= avhForm.MinDate) { toDate.setDate(avhForm.MinDate.getDate() + 1); setDate("ToDate", toDate); } else if (toDate > avhForm.MaxDate) { toDate = avhForm.MaxDate; setDate("ToDate", toDate); }
		//mame jistotu ze : FromDate = MinDate ... MaxDate-1, ToDate = MinDate+1 ... MaxDate;
		if (fromDate >= toDate) {
			//[30.3.09][#Com_DateFromMustStay]: DateFrom se nema menit, vzdy se podle nej upravi DateTo
/* [#Com_DateFromMustStay]
			if (propName == "FromDate")//zmenil se From -> To = From + 1
[#Com_DateFromMustStay] */
			{
				var newDate = fromDate.add("d", 1);
				if (!$("#ToDate_Day").containsOption(newDate.getDate().toString())) {
					loadDates("ToDate", newDate.getDate(), newDate.getDate(), newDate.getDate());
				}
				//alert("NewTo = " + $.datepicker.formatDate("dd.mm.yy",newDate));
				setDate("ToDate", newDate);
				this.MonthYearChanged(document.getElementById(getId("ToDate_MonthYear")));
			}
/* [#Com_DateFromMustStay]
			else {//zmenil se To -> From = To - 1
				var newDate = toDate.add("d", -1);
				if (!$("#FromDate_Day").containsOption(newDate.getDate().toString())) {
					loadDates("FromDate", newDate.getDate(), newDate.getDate(), newDate.getDate());
				}
				setDate("FromDate", newDate);
				this.MonthYearChanged(document.getElementById(getId("FromDate_MonthYear")));
			}
[#Com_DateFromMustStay] */
		}
	}

	this.MonthYearChanged = function(o/*MonthYear select*/) {
		var propName = o.name.replace(getId(""), "").split("_")[0], noOfDaysMinMax = getNoOfDaysMinMax(propName, o.options[o.selectedIndex].text), selectedDay = $(getIdJQ(propName + "_Day") + " option:selected").val();
		var minDay = noOfDaysMinMax[0], maxDay = noOfDaysMinMax[1];
		if ($(getIdJQ(propName + "_Day") + " option:first").val() != minDay || $(getIdJQ(propName + "_Day") + " option:last").val() != maxDay) {
			loadDates(propName, minDay, maxDay, selectedDay);
		}
		updateDatePicker(propName);
	}
	this.DayChanged = function(o/*Day select*/) {
		var propName = o.name.replace(getId(""), "").split("_")[0];
		updateDatePicker(propName);
	}
	this.OccupancyChanged = function(newValue) {
		if (!newValue) newValue = this.GetOccupancy();
		for (i = guestAgeShowIndex; i <= this.MaxOccupancy; i++) {
			var e = $('#trAge' + i + ', #trAge' + i + '_Mini'); if(newValue >= i) e.show(); else e.hide();
			if ($('form.xform').length == 0) if (i <= newValue) $(getIdJQ("GuestAgeList[" + (i - guestAgeShowIndex) + "]")).addClass('required'); else $(getIdJQ("GuestAgeList[" + (i - guestAgeShowIndex) + "]")).removeClass('required');
		}
		this.ValidateGuestAges();
		//$("#noOfGuests").text(newValue);
		//$("#totalGuests").text(parseInt(newValue) * parseInt($(getIdJQ("NoOfRooms")).val()));
	}
	this.GuestAgeChanged = function(i) {
		this.ValidateGuestAge(i);
	}

	this.ValidateGuestAges = function() {
		var occ = this.GetOccupancy()
		for (i = guestAgeShowIndex; i <= this.MaxOccupancy; i++)
			this.ValidateGuestAge(i);
	}
	this.ValidateGuestAge = function(i) {
		var isValid = true, occ = this.GetOccupancy();
		$('#trAge' + i + ' select:first, #trAge' + i + '_Mini select:first')
			.each(function() {
				var $this = $(this), $errMsg = $this.parent().children(".form-error-msg");
				$this.removeClass('invalid');
				$errMsg.hide();
				if (($this.val() == "" || $this.val() == "-1") && i <= occ) {
					$this.addClass('invalid');
					$errMsg.show();
					isValid = false;
				}
			});
		return isValid;
	}

	this.BeforeSubmit = function() {
		var isValid = $("form *.invalid").length == 0;
		return isValid;
	}
	

	/* private function */
	getIdJQ = function(propName) {
		return "#" + getId(propName);
	}
	getId = function(propName) {
		var prefix = (propName.indexOf("MonthYear") >= 0 || propName.indexOf("Day") >= 0) ? "" : ((avhForm ? avhForm.IdPrefix : idPrefix) + "_");
		return prefix + propName;
	}
	loadDates = function(propName, min, max, selectedDay) {
		$(getIdJQ(propName + "_Day")).removeOption(/./);
		for (i = min; i <= max; i++)
			$(getIdJQ(propName + "_Day")).addOption(i, (i < 10 ? "0" : "") + i);
		if (selectedDay)
			$(getIdJQ(propName + "_Day")).selectOptions(selectedDay, true);
	}
	getNoOfDaysMinMax = function(propName, monthYear) {
		var month = (monthYear.split(selectMYDSeparator)[0]),
			year = (monthYear.split(selectMYDSeparator)[1]),
			maxTotal = month < 8 ? (month % 2 == 0 ? (month == 2 ? (year % 4 == 0 ? 29 : 28) : 30) : 31) : (month % 2 == 0 ? 31 : 30),
			minDay = 1, maxDay = maxTotal;
		if (avhForm.MinDate.getMonth() + 1 == month && avhForm.MinDate.getFullYear() == year)
			minDay = avhForm.MinDate.getDate() + (propName == "ToDate" ? 1 : 0);
		if (avhForm.MaxDate.getMonth() + 1 == month && avhForm.MaxDate.getFullYear() == year)
			maxDay = avhForm.MinDate.getDate() + (propName == "FromDate" ? -1 : 0);
		return new Array(minDay, maxDay);
	}
	setDate = function(propName, date) {
		$(getIdJQ(propName + "_Day")).val(date.getDate());
		var month = date.getMonth() + 1, monthYearText = (month < 10 ? "0" : "") + month + selectMYDSeparator + date.getFullYear();
		var o = (document.getElementById(getId(propName + "_MonthYear")));
		for (i = 0; i < o.options.length; i++) {
			if (o.options[i].text == monthYearText) {
				o.selectedIndex = i;
				break;
			}
		}
		return o;
	}
	updateDatePicker = function(propName) {
		$(getIdJQ(propName)).val($.datepicker.formatDate(datePicker_DateFormat, avhForm.GetDateFromSelects(propName)));
	}

	/* init pri startu : */

	this.OccupancyChanged();
};/// <reference path="jquery-1.3-vsdoc.js" />
var regExp_CountryCity = /http(.?):\/\/(.+)\/(.+)\/(.*)\/?(.*)?\/?(.*)?\/?/;

$().ready(function() {

	if (typeof (mapCity) != "undefined") {
		mapCity.map.jmap('init', {
			'language': engine.LanguageCode,
			'mapCenter': mapCity.center,
			'mapZoom': 10,
			'mapControl': 'none',
			'mapEnableDragging': false,
			'mapEnableInfoWindows': false,
			'mapShowjMapsIcon': false
		});
	}

	if (typeof (cityOnChangeSelector) != "undefined") {
		$(cityOnChangeSelector).change(function() {
			var latitude, longitude, cityID, cityName, countryName;
			if (isNaN(this.value)) {
				var p = eval("(" + this.value + ")");
				cityID = p.CityID;
				cityName = p.Name;
				countryName = p.CountryName;
				latitude = p.Latitude;
				longitude = p.Longitude;
			} else {
				cityID = this.value;
				var e = geo_GetCityInfo(cityID, "en");
				if (e < 0) return;
				cityName = e.Name;
				countryName = e.CountryName;
				latitude = e.Latitude;
				longitude = e.Longitude;
			}

			$("#Weather_CityID, #BestRates_CityID").selectOptions(new RegExp('"CityID":' + cityID), true);
			$("#SelectedCity_CityID").selectOptions(cityID.toString(), true);

			$("#Weather_CityID, #BestRates_CityID, #SelectedCity_CityID, img.ajax-loading").toggle();
			engine.WeatherLoad(longitude, latitude);

			if ($("#containerBestRates").length > 0) {
				$.get("/" + engine.LanguageCode + "/WebService.mvc/bestrates", { 'cityID': cityID },
					function(data) {
						$("#containerBestRates").html(data);
						engine.ToolTipsInit($("#containerBestRates"));
						$("#BestRates_CityID").show();
						$("img.ajax-loading").hide();
						engine.VideoPlayerInit();
					});
			}
			var geoLink = "/" + countryName.toLowerCase() + "/" + cityName.toLowerCase();
			$("#weatherTitle").text(cityName);
			$("#mapCityLink").attr("href", "/" + engine.LanguageCode + "/hotels.mvc" + geoLink + "?map=on");

			if (typeof (mapCity) != "undefined" && mapCity.map.length > 0)
				Mapifies.MoveTo(mapCity.map, { 'mapCenter': [latitude, longitude] });

			$("#menu-lang a").each(function() {
				this.href = "/" + this.id.split("_")[1] + "/home.mvc" + geoLink;
			});
		}); //.change
	}
});


/*** Hotel List Map ***/
var mapHotelList = { 'map' : null, 'savedMarkerIndex' : null, 'savedHotelId' : null, 'arMarkers' : new Array(), timerID : null };
var MyMaps_CurrencyTop = null;
function mapHotelList_Show() {
	if ($("#containerHotelListMap").css("display") == "none")
		mapHotelList_Toggle();
} 
function mapHotelList_Toggle() {
	$("#containerHotelListMap, #hotels table.hotel .map-anchor").toggle();
	var isMapVisible = $("#containerHotelListMap").css("display") != "none";
	if (!isDef(mapHotelList.map))
		mapHotelList_Create();
	if (typeof(mapCity) != "undefined")
		Mapifies.MoveTo(mapHotelList.map, { 'mapCenter': mapCity.center });
	if (MyMaps_CurrencyTop == null) {
		var m = new RegExp("\\d+").exec(text = $("select.currency").css("top"));
		MyMaps_CurrencyTop = parseInt((m == null ? 0 : m[0]));
	}
	$("select.currency").css("top", (isMapVisible ? $("#containerHotelListMap").height() : 0) + MyMaps_CurrencyTop + "px");
	$("input[id$='_IsHotelsMapVisible']").val(isMapVisible);
	if (!isMapVisible && isDef(mapHotelList.savedHotelId))
		mapHotelList_SelectHotel(mapHotelList.savedHotelId, mapHotelList.savedMarkerIndex, false, false);
}

function mapHotelList_Destroy() {
	mapHotelList.map = null;
}
function mapHotelList_Create() {
	mapHotelList.map = $("#mapHotelList");
	if (mapHotelList.map.length < 1 || typeof(mapCity) == "undefined" || typeof(arHotelIDs) == "undefined")
		return;
	mapHotelList.map.jmap('init', {
		'language': engine.LanguageCode,
		'mapCenter': mapCity.center,
		'mapZoom': 11,
		'mapControl': 'large',
		'mapEnableType': true,
		'mapEnableDragging': true,
		'mapEnableInfoWindows': true,
		'mapEnableScaleControl': true,
		'mapShowjMapsIcon': false
	});

	$("table.hotel").each(function(i) {
		var hotelData = $(this).metadata();
		mapHotelList.map.jmap("AddMarker", {
				'pointIcon': MapHelper.GetHotelMarkerIcon(i, false),
				'pointLatLng': [hotelData.lat, hotelData.lng],
				'importance': 0
			}, function(marker, opt) {
			mapHotelList.arMarkers[hotelData.id] = marker;
			GEvent.addListener(marker, "click", function() { mapHotelList_SelectHotel(hotelData.id, i, true, false); });
		});
	});
}

function importanceOrder (marker,b) {
	return GOverlay.getZIndex(marker.getPoint().lat()) + marker.importance*1000000;
}

function mapHotelList_SelectHotel(hotelId, index, select, centerMap) {
	if (isDef(mapHotelList.savedHotelId)) { // -> unselect
		var tmlId = mapHotelList.savedHotelId; mapHotelList.savedHotelId = null;
		mapHotelList_SelectHotel(tmlId, mapHotelList.savedMarkerIndex, false, false);
		if (hotelId == tmlId)
			return;
		select = true;
	}
	var markerToRemove = mapHotelList.arMarkers[hotelId];
	var latLng = markerToRemove.getLatLng();
	Mapifies.RemoveMarker(mapHotelList.map, markerToRemove);
	mapHotelList.map.jmap("AddMarker", {
			'pointIcon': MapHelper.GetHotelMarkerIcon(index, select),
			'pointLatLng': [latLng.lat(), latLng.lng()],
			'importance': select ? 100 : 0,
			'zIndexProcess': function(marker, b) { return marker.importance; }
		}, function(marker, opt) {
			mapHotelList.arMarkers[hotelId] = marker;
			GEvent.addListener(marker, "click", function() { mapHotelList_SelectHotel(hotelId, index, !select, false); });
		});
	if (centerMap)
		Mapifies.MoveTo(mapHotelList.map, { 'mapCenter' : [latLng.lat(), latLng.lng()] });

	/* hotle minies */
	$("ul.hotel-minies li." + (select ? mapHotelList.savedHotelId : hotelId)).removeClass("active");
	if (select) {
		if ($("ul.hotel-minies li").length > 1)
			$("#hotel_" + hotelId).hide().insertAfter("#firstHotelContainer").addClass("active").fadeIn("slow");
		if (mapHotelList.timerID != null) clearTimeout(mapHotelList.timerID);
		mapHotelList.timerID = setTimeout("$('#hotel_" + hotelId + "').removeClass('active')", 3000);
		$("ul.hotel-minies li." + hotelId).addClass("active");
	}
	else
		$("#hotel_" + hotelId).removeClass("active");
	mapHotelList.savedHotelId = (select ? hotelId : null);
	mapHotelList.savedMarkerIndex = (select ? index : null);
}

