/**
 * jQuery.ScrollTo - Easy element scrolling using jQuery.
 * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 * Date: 2/19/2008
 * @author Ariel Flesler
 * @version 1.3.3
 */
;(function($){var o=jQuery.scrollTo=function(a,b,c){o.window().scrollTo(a,b,c)};o.defaults={axis:'xy',duration:1};o.window=function(){return jQuery(jQuery.browser.safari?'body':'html')};jQuery.fn.scrollTo=function(l,m,n){if(typeof m=='object'){n=m;m=0}n=jQuery.extend({},o.defaults,n);m=m||n.speed||n.duration;n.queue=n.queue&&n.axis.length>1;if(n.queue)m/=2;n.offset=j(n.offset);n.over=j(n.over);return this.each(function(){var a=this,b=jQuery(a),t=l,c,d={},w=b.is('html,body');switch(typeof t){case'number':case'string':if(/^([+-]=)?\d+(px)?$/.test(t)){t=j(t);break}t=jQuery(t,this);case'object':if(t.is||t.style)c=(t=jQuery(t)).offset()}jQuery.each(n.axis.split(''),function(i,f){var P=f=='x'?'Left':'Top',p=P.toLowerCase(),k='scroll'+P,e=a[k],D=f=='x'?'Width':'Height';if(c){d[k]=c[p]+(w?0:e-b.offset()[p]);if(n.margin){d[k]-=parseInt(t.css('margin'+P))||0;d[k]-=parseInt(t.css('border'+P+'Width'))||0}d[k]+=n.offset[p]||0;if(n.over[p])d[k]+=t[D.toLowerCase()]()*n.over[p]}else d[k]=t[p];if(/^\d+$/.test(d[k]))d[k]=d[k]<=0?0:Math.min(d[k],h(D));if(!i&&n.queue){if(e!=d[k])g(n.onAfterFirst);delete d[k]}});g(n.onAfter);function g(a){b.animate(d,m,n.easing,a&&function(){a.call(this,l)})};function h(D){var b=w?jQuery.browser.opera?document.body:document.documentElement:a;return b['scroll'+D]-b['client'+D]}})};function j(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);/**
 * jQuery.LocalScroll
 * Copyright (c) 2007-2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
 * Dual licensed under MIT and GPL.
 * Date: 6/3/2008
 *
 * @projectDescription Animated scrolling navigation, using anchors.
 * http://flesler.blogspot.com/2007/10/jquerylocalscroll-10.html
 * @author Ariel Flesler
 * @version 1.2.6
 *
 * @id jQuery.fn.localScroll
 * @param {Object} settings Hash of settings, it is passed in to jQuery.ScrollTo, none is required.
 * @return {jQuery} Returns the same jQuery object, for chaining.
 *
 * @example $('ul.links').localScroll();
 *
 * @example $('ul.links').localScroll({ filter:'.animated', duration:400, axis:'x' });
 *
 * @example $.localScroll({ target:'#pane', axis:'xy', queue:true, event:'mouseover' });
 *
 * Notes:
 *	- The plugin requires jQuery.ScrollTo.
 *	- The hash of settings, is passed to jQuery.ScrollTo, so the settings are valid for that plugin as well.
 *	- jQuery.localScroll can be used if the desired links, are all over the document, it accepts the same settings.
 *  - If the setting 'lazy' is set to true, then the binding will still work for later added anchors.
 *  - The setting 'speed' is deprecated, use 'duration' instead.
 *	- If onBefore returns false, the event is ignored.
 **/
;(function( $ ){
	var URI = location.href.replace(/#.*/,'');//local url without hash

	var $localScroll = $.localScroll = function( settings ){
		$('body').localScroll( settings );
	};

	//Many of these defaults, belong to jQuery.ScrollTo, check it's demo for an example of each option.
	//@see http://www.freewebs.com/flesler/jQuery.ScrollTo/
	$localScroll.defaults = {//the defaults are public and can be overriden.
		duration:1000, //how long to animate.
		axis:'y',//which of top and left should be modified.
		event:'click',//on which event to react.
		stop:true//avoid queuing animations 
		/*
		lock:false,//ignore events if already animating
		lazy:false,//if true, links can be added later, and will still work.
		target:null, //what to scroll (selector or element). Keep it null if want to scroll the whole window.
		filter:null, //filter some anchors out of the matched elements.
		hash: false//if true, the hash of the selected link, will appear on the address bar.
		*/
	};

	//if the URL contains a hash, it will scroll to the pointed element
	$localScroll.hash = function( settings ){
		settings = $.extend( {}, $localScroll.defaults, settings );
		settings.hash = false;//can't be true
		if( location.hash )
			setTimeout(function(){ scroll( 0, location, settings ); }, 0 );//better wrapped with a setTimeout
	};

	$.fn.localScroll = function( settings ){
		settings = $.extend( {}, $localScroll.defaults, settings );

		return ( settings.persistent || settings.lazy ) 
				? this.bind( settings.event, function( e ){//use event delegation, more links can be added later.
					var a = $([e.target, e.target.parentNode]).filter(filter)[0];//if a valid link was clicked.
					a && scroll( e, a, settings );//do scroll.
				})
				: this.find('a,area')//bind concretely, to each matching link
						.filter( filter ).bind( settings.event, function(e){
							scroll( e, this, settings );
						}).end()
					.end();

		function filter(){//is this a link that points to an anchor and passes a possible filter ? href is checked to avoid a bug in FF.
			return !!this.href && !!this.hash && this.href.replace(this.hash,'') == URI && (!settings.filter || $(this).is( settings.filter ));
		};
	};

	function scroll( e, link, settings ){
		var id = link.hash.slice(1),
			elem = document.getElementById(id) || document.getElementsByName(id)[0];
		if ( elem ){
			e && e.preventDefault();
			var $target = $( settings.target || $.scrollTo.window() );//if none specified, then the window.

			if( settings.lock && $target.is(':animated') ||
			settings.onBefore && settings.onBefore.call(link, e, elem, $target) === false ) return;

			if( settings.stop )
				$target.queue('fx',[]).stop();//remove all its animations
			$target
				.scrollTo( elem, settings )//do scroll
				.trigger('notify.serialScroll',[elem]);//notify serialScroll about this change
			if( settings.hash )
				$target.queue(function(){
					location = link.hash;
					// make sure this function is released
					$(this).dequeue();
				});
		}
	};

})( jQuery );/**
 * jQuery.serialScroll
 * Copyright (c) 2007-2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
 * Dual licensed under MIT and GPL.
 * Date: 3/20/2008
 *
 * @projectDescription Animated scrolling of series.
 * @author Ariel Flesler
 * @version 1.2.1
 *
 * @id jQuery.serialScroll
 * @id jQuery.fn.serialScroll
 * @param {Object} settings Hash of settings, it is passed in to jQuery.ScrollTo, none is required.
 * @return {jQuery} Returns the same jQuery object, for chaining.
 *
 * http://flesler.blogspot.com/2008/02/jqueryserialscroll.html
 *
 * Notes:
 *	- The plugin requires jQuery.ScrollTo.
 *	- The hash of settings, is passed to jQuery.ScrollTo, so its settings can be used as well.
 */
;(function( $ ){

	var $serialScroll = $.serialScroll = function( settings ){
		$.scrollTo.window().serialScroll( settings );
	};

	//Many of these defaults, belong to jQuery.ScrollTo, check it's demo for an example of each option.
	//@see http://flesler.webs/jQuery.ScrollTo/
	$serialScroll.defaults = {//the defaults are public and can be overriden.
		duration:1000, //how long to animate.
		axis:'x', //which of top and left should be scrolled
		event:'click', //on which event to react.
		start:0, //first element (zero-based index)
		step:1, //how many elements to scroll on each action
		lock:true,//ignore events if already animating
		cycle:true, //cycle endlessly ( constant velocity )
		constant:true //use contant speed ?
		/*
		navigation:null,//if specified, it's a selector a collection of items to navigate the container
		target:null, //if specified, it's a selector to the element to be scrolled.
		interval:0, //it's the number of milliseconds to automatically go to the next
		lazy:false,//go find the elements each time (allows AJAX or JS content, or reordering)
		stop:false, //stop any previous animations to avoid queueing
		force:false,//force the scroll to the first element on start ?
		jump: false,//if true, when the event is triggered on an element, the pane scrolls to it
		items:null, //selector to the items (relative to the matched elements)
		prev:null, //selector to the 'prev' button
		next:null, //selector to the 'next' button
		onBefore: function(){}, //function called before scrolling, if it returns false, the event is ignored
		exclude:0 //exclude the last x elements, so we cannot scroll past the end
		*/
	};

	$.fn.serialScroll = function( settings ){
		settings = $.extend( {}, $serialScroll.defaults, settings );
		var event = settings.event, //this one is just to get shorter code when compressed
			step = settings.step, // idem
			lazy = settings.lazy;//idem

		return this.each(function(){
			var 
				context = settings.target ? this : document, //if a target is specified, then everything's relative to 'this'.
				$pane = $(settings.target || this, context),//the element to be scrolled (will carry all the events)
				pane = $pane[0], //will be reused, save it into a variable
				items = settings.items, //will hold a lazy list of elements
				active = settings.start, //active index
				auto = settings.interval, //boolean, do auto or not
				nav = settings.navigation, //save it now to make the code shorter
				timer; //holds the interval id

			if( !lazy )//if not lazy, go get the items now
				items = getItems();

			if( settings.force )
				jump( {}, active );//generate an initial call

			// Button binding, optionall
			$(settings.prev||[], context).bind( event, -step, move );
			$(settings.next||[], context).bind( event, step, move );

			// Custom events bound to the container
			if( !pane.ssbound )//don't bind more than once
				$pane
					.bind('prev.serialScroll', -step, move ) //you can trigger with just 'prev'
					.bind('next.serialScroll', step, move ) //for example: $(container).trigger('next');
					.bind('goto.serialScroll', jump ); //for example: $(container).trigger('goto', [4] );
			if( auto )
				$pane
					.bind('start.serialScroll', function(e){
						if( !auto ){
							clear();
							auto = true;
							next();
						}
					 })
					.bind('stop.serialScroll', function(){//stop a current animation
						clear();
						auto = false;
					});
			$pane.bind('notify.serialScroll', function(e, elem){//let serialScroll know that the index changed externally
				var i = index(elem);
				if( i > -1 )
					active = i;
			});
			pane.ssbound = true;//avoid many bindings

			if( settings.jump )//can't use jump if using lazy items and a non-bubbling event
				(lazy ? $pane : getItems()).bind( event, function( e ){
					jump( e, index(e.target) );
				});

			if( nav )
				nav = $(nav, context).bind(event, function( e ){
					e.data = Math.round(getItems().length / nav.length) * nav.index(this);
					jump( e, this );
				});

			function move( e ){
				e.data += active;
				jump( e, this );
			};
			function jump( e, button ){
				if( !isNaN(button) ){//initial or special call from the outside $(container).trigger('goto',[index]);
					e.data = button;
					button = pane;
				}

				var
					pos = e.data, n,
					real = e.type, //is a real event triggering ?
					$items = settings.exclude ? getItems().slice(0,-settings.exclude) : getItems(),//handle a possible exclude
					limit = $items.length,
					elem = $items[pos],
					duration = settings.duration;

				if( real )//real event object
					e.preventDefault();

				if( auto ){
					clear();//clear any possible automatic scrolling.
					timer = setTimeout( next, settings.interval ); 
				}

				if( !elem ){ //exceeded the limits
					n = pos < 0 ? 0 : limit - 1;
					if( active != n )//we exceeded for the first time
						pos = n;
					else if( !settings.cycle )//this is a bad case
						return;
					else
						pos = limit - n - 1;//invert, go to the other side
					elem = $items[pos];
				}

				if( !elem || real && active == pos || //could happen, save some CPU cycles in vain
					settings.lock && $pane.is(':animated') || //no animations while busy
					real && settings.onBefore && //callback returns false ?
					settings.onBefore.call(button, e, elem, $pane, getItems(), pos) === false ) return;

				if( settings.stop )
					$pane.queue('fx',[]).stop();//remove all its animations

				if( settings.constant )
					duration = Math.abs(duration/step * (active - pos ));//keep constant velocity

				$pane
					.scrollTo( elem, duration, settings )//do scroll
					.trigger('notify.serialScroll',[pos]);//in case serialScroll was called on this elem more than once.
			};
			function next(){//I'll use the namespace to avoid conflicts
				$pane.trigger('next.serialScroll');
			};
			function clear(){
				clearTimeout(timer);
			};
			function getItems(){
				return $( items, pane );
			};
			function index( elem ){
				if( !isNaN(elem) ) return elem;//number
				var $items = getItems(), i;
				while(( i = $items.index(elem)) == -1 && elem != pane )//see if it matches or one of its ancestors
					elem = elem.parentNode;
				return i;
			};
		});
	};

})( jQuery );/*
 * jQuery Autocomplete plugin 1.1
 *
 * Copyright (c) 2009 Jörn Zaefferer
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
 * 
 * OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!
 * OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!
 * OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!
 * 
 * 		------------> JAG HAR SKRIVIT OM HUR formatItem ANV�NDS!  <---------------
 * 
 * OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!
 * OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!OBS!
 */

;(function($) {
	
$.fn.extend({
	autocomplete: function(urlOrData, options) {
		var isUrl = typeof urlOrData == "string";
		options = $.extend({}, $.Autocompleter.defaults, {
			url: isUrl ? urlOrData : null,
			data: isUrl ? null : urlOrData,
			delay: isUrl ? $.Autocompleter.defaults.delay : 10,
			max: options && !options.scroll ? 10 : 150
		}, options);
		
		// if highlight is set to false, replace it with a do-nothing function
		options.highlight = options.highlight || function(value) { return value; };
		
		// if the formatMatch option is not specified, then use formatItem for backwards compatibility
		options.formatMatch = options.formatMatch || options.formatItem;
		
		return this.each(function() {
			new $.Autocompleter(this, options);
		});
	},
	result: function(handler) {
		return this.bind("result", handler);
	},
	search: function(handler) {
		return this.trigger("search", [handler]);
	},
	flushCache: function() {
		return this.trigger("flushCache");
	},
	setOptions: function(options){
		return this.trigger("setOptions", [options]);
	},
	unautocomplete: function() {
		return this.trigger("unautocomplete");
	}
});

$.Autocompleter = function(input, options) {

	var KEY = {
		UP: 38,
		DOWN: 40,
		DEL: 46,
		TAB: 9,
		RETURN: 13,
		ESC: 27,
		COMMA: 188,
		PAGEUP: 33,
		PAGEDOWN: 34,
		BACKSPACE: 8
	};

	// Create $ object for input element
	var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);

	var timeout;
	var previousValue = "";
	var cache = $.Autocompleter.Cache(options);
	var hasFocus = 0;
	var lastKeyPressCode;
	var config = {
		mouseDownOnSelect: false
	};
	var select = $.Autocompleter.Select(options, input, selectCurrent, config);
	
	var blockSubmit;
	
	// prevent form submit in opera when selecting with return key
	$.browser.opera && $(input.form).bind("submit.autocomplete", function() {
		if (blockSubmit) {
			blockSubmit = false;
			return false;
		}
	});
	
	// only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
	$input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
		// a keypress means the input has focus
		// avoids issue where input had focus before the autocomplete was applied
		hasFocus = 1;
		// track last key pressed
		lastKeyPressCode = event.keyCode;
		switch(event.keyCode) {
		
			case KEY.UP:
				event.preventDefault();
				if ( select.visible() ) {
					select.prev();
				} else {
					onChange(0, true);
				}
				break;
				
			case KEY.DOWN:
				event.preventDefault();
				if ( select.visible() ) {
					select.next();
				} else {
					onChange(0, true);
				}
				break;
				
			case KEY.PAGEUP:
				event.preventDefault();
				if ( select.visible() ) {
					select.pageUp();
				} else {
					onChange(0, true);
				}
				break;
				
			case KEY.PAGEDOWN:
				event.preventDefault();
				if ( select.visible() ) {
					select.pageDown();
				} else {
					onChange(0, true);
				}
				break;
			
			// matches also semicolon
			case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
			case KEY.TAB:
			case KEY.RETURN:
				if( selectCurrent() ) {
					// stop default to prevent a form submit, Opera needs special handling
					event.preventDefault();
					blockSubmit = true;
					return false;
				}
				break;
				
			case KEY.ESC:
				select.hide();
				break;
				
			default:
				clearTimeout(timeout);
				timeout = setTimeout(onChange, options.delay);
				break;
		}
	}).focus(function(){
		// track whether the field has focus, we shouldn't process any
		// results if the field no longer has focus
		hasFocus++;
	}).blur(function() {
		hasFocus = 0;
		if (!config.mouseDownOnSelect) {
			hideResults();
		}
	}).click(function() {
		// show select when clicking in a focused field
		if ( hasFocus++ > 1 && !select.visible() ) {
			onChange(0, true);
		}
	}).bind("search", function() {
		// TODO why not just specifying both arguments?
		var fn = (arguments.length > 1) ? arguments[1] : null;
		function findValueCallback(q, data) {
			var result;
			if( data && data.length ) {
				for (var i=0; i < data.length; i++) {
					if( data[i].result.toLowerCase() == q.toLowerCase() ) {
						result = data[i];
						break;
					}
				}
			}
			if( typeof fn == "function" ) fn(result);
			else $input.trigger("result", result && [result.data, result.value]);
		}
		$.each(trimWords($input.val()), function(i, value) {
			request(value, findValueCallback, findValueCallback);
		});
	}).bind("flushCache", function() {
		cache.flush();
	}).bind("setOptions", function() {
		$.extend(options, arguments[1]);
		// if we've updated the data, repopulate
		if ( "data" in arguments[1] )
			cache.populate();
	}).bind("unautocomplete", function() {
		select.unbind();
		$input.unbind();
		$(input.form).unbind(".autocomplete");
	});
	
	
	function selectCurrent() {
		
		var selected = select.selected();
		
		if( !selected )
			return false;
		
		if (typeof options.vetoSelection == "function") {
			if (options.vetoSelection(selected)) {
				return false;
			}
		}
		
		var v = selected.result;
		previousValue = v;
		
		if ( options.multiple ) {
			var words = trimWords($input.val());
			if ( words.length > 1 ) {
				var seperator = options.multipleSeparator.length;
				var cursorAt = $(input).selection().start;
				var wordAt, progress = 0;
				$.each(words, function(i, word) {
					progress += word.length;
					if (cursorAt <= progress) {
						wordAt = i;
						return false;
					}
					progress += seperator;
				});
				words[wordAt] = v;
				// TODO this should set the cursor to the right position, but it gets overriden somewhere
				//$.Autocompleter.Selection(input, progress + seperator, progress + seperator);
				v = words.join( options.multipleSeparator );
			}
			v += options.multipleSeparator;
		}
		
		$input.val(v);
		hideResultsNow();
		$input.trigger("result", [selected.data, selected.value]);
		return true;
	}
	
	function onChange(crap, skipPrevCheck) {
		if( lastKeyPressCode == KEY.DEL ) {
			select.hide();
			return;
		}
		
		var currentValue = $input.val();
		
		if ( !skipPrevCheck && currentValue == previousValue )
			return;
		
		previousValue = currentValue;
		
		currentValue = lastWord(currentValue);
		if ( currentValue.length >= options.minChars) {
			$input.addClass(options.loadingClass);
			if (!options.matchCase)
				currentValue = currentValue.toLowerCase();
			request(currentValue, receiveData, hideResultsNow);
		} else {
			stopLoading();
			select.hide();
		}
	};
	
	function trimWords(value) {
		if (!value)
			return [""];
		if (!options.multiple)
			return [$.trim(value)];
		return $.map(value.split(options.multipleSeparator), function(word) {
			return $.trim(value).length ? $.trim(word) : null;
		});
	}
	
	function lastWord(value) {
		if ( !options.multiple )
			return value;
		var words = trimWords(value);
		if (words.length == 1) 
			return words[0];
		var cursorAt = $(input).selection().start;
		if (cursorAt == value.length) {
			words = trimWords(value)
		} else {
			words = trimWords(value.replace(value.substring(cursorAt), ""));
		}
		return words[words.length - 1];
	}
	
	// fills in the input box w/the first match (assumed to be the best match)
	// q: the term entered
	// sValue: the first matching result
	function autoFill(q, sValue){
		// autofill in the complete box w/the first match as long as the user hasn't entered in more data
		// if the last user key pressed was backspace, don't autofill
		if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
			// fill in the value (keep the case the user has typed)
			$input.val($input.val() + sValue.substring(lastWord(previousValue).length));
			// select the portion of the value not typed by the user (so the next character will erase)
			$(input).selection(previousValue.length, previousValue.length + sValue.length);
		}
	};

	function hideResults() {
		clearTimeout(timeout);
		timeout = setTimeout(hideResultsNow, 200);
	};

	function hideResultsNow() {
		var wasVisible = select.visible();
		select.hide();
		clearTimeout(timeout);
		stopLoading();
		if (options.mustMatch) {
			// call search and run callback
			$input.search(
				function (result){
					// if no value found, clear the input box
					if( !result ) {
						if (options.multiple) {
							var words = trimWords($input.val()).slice(0, -1);
							$input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
						}
						else {
							$input.val( "" );
							$input.trigger("result", null);
						}
					}
				}
			);
		}
	};

	function receiveData(q, data) {
		if ( data && data.length && hasFocus ) {
			stopLoading();
			select.display(data, q);
			autoFill(q, data[0].value);
			select.show();
			if (typeof options['onShow'] == "function") {
				options['onShow']();
			}
		} else {
			hideResultsNow();
		}
	};

	function request(term, success, failure) {
		if (!options.matchCase)
			term = term.toLowerCase();
		var data = cache.load(term);
		// recieve the cached data
		if (data && data.length) {
			success(term, data);
		// if an AJAX url has been supplied, try loading the data now
		} else if( (typeof options.url == "string") && (options.url.length > 0) ){
			
			jQuery(input).trigger("start", [term]);
			
			var extraParams = {
				timestamp: +new Date()
			};
			$.each(options.extraParams, function(key, param) {
				extraParams[key] = typeof param == "function" ? param() : param;
			});
			
			$.ajax({
				// try to leverage ajaxQueue plugin to abort previous requests
				mode: "abort",
				// limit abortion to this input
				port: "autocomplete" + input.name,
				dataType: options.dataType,
				url: options.url,
				data: $.extend({
					q: lastWord(term),
					limit: options.max
				}, extraParams),
				success: function(data) {
					var parsed = options.parse && options.parse(data) || parse(data);
					cache.add(term, parsed);
					success(term, parsed);
					jQuery(input).trigger("done");
				}
			});
		} else {
			// if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
			select.emptyList();
			failure(term);
		}
	};
	
	function parse(data) {
		var parsed = [];
		var rows = data.split("\n");
		for (var i=0; i < rows.length; i++) {
			var row = $.trim(rows[i]);
			if (row) {
				row = row.split("|");
				parsed[parsed.length] = {
					data: row,
					value: row[0],
					result: options.formatResult && options.formatResult(row, row[0]) || row[0]
				};
			}
		}
		return parsed;
	};

	function stopLoading() {
		$input.removeClass(options.loadingClass);
	};

};

$.Autocompleter.defaults = {
	inputClass: "ac_input",
	resultsClass: "ac_results",
	loadingClass: "ac_loading",
	minChars: 1,
	delay: 400,
	matchCase: false,
	matchSubset: true,
	matchContains: false,
	cacheLength: 10,
	max: 100,
	mustMatch: false,
	extraParams: {},
	selectFirst: true,
	formatItem: function(row, liInner) { liInner.html(row[0]) },
	formatMatch: null,
	autoFill: false,
	width: 0,
	multiple: false,
	multipleSeparator: ", ",
	highlight: function(value, term) {
		return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
	},
    scroll: true,
    scrollHeight: 180
};

$.Autocompleter.Cache = function(options) {

	var data = {};
	var length = 0;
	
	function matchSubset(s, sub) {
		if (!options.matchCase) 
			s = s.toLowerCase();
		var i = s.indexOf(sub);
		if (options.matchContains == "word"){
			i = s.toLowerCase().search("\\b" + sub.toLowerCase());
		}
		if (i == -1) return false;
		return i == 0 || options.matchContains;
	};
	
	function add(q, value) {
		if (length > options.cacheLength){
			flush();
		}
		if (!data[q]){ 
			length++;
		}
		data[q] = value;
	}
	
	function populate(){
		if( !options.data ) return false;
		// track the matches
		var stMatchSets = {},
			nullData = 0;

		// no url was specified, we need to adjust the cache length to make sure it fits the local data store
		if( !options.url ) options.cacheLength = 1;
		
		// track all options for minChars = 0
		stMatchSets[""] = [];
		
		// loop through the array and create a lookup structure
		for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
			var rawValue = options.data[i];
			// if rawValue is a string, make an array otherwise just reference the array
			rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
			
			var value = options.formatMatch(rawValue, i+1, options.data.length);
			if ( value === false )
				continue;
				
			var firstChar = value.charAt(0).toLowerCase();
			// if no lookup array for this character exists, look it up now
			if( !stMatchSets[firstChar] ) 
				stMatchSets[firstChar] = [];

			// if the match is a string
			var row = {
				value: value,
				data: rawValue,
				result: options.formatResult && options.formatResult(rawValue) || value
			};
			
			// push the current match into the set list
			stMatchSets[firstChar].push(row);

			// keep track of minChars zero items
			if ( nullData++ < options.max ) {
				stMatchSets[""].push(row);
			}
		};

		// add the data items to the cache
		$.each(stMatchSets, function(i, value) {
			// increase the cache size
			options.cacheLength++;
			// add to the cache
			add(i, value);
		});
	}
	
	// populate any existing data
	setTimeout(populate, 25);
	
	function flush(){
		data = {};
		length = 0;
	}
	
	return {
		flush: flush,
		add: add,
		populate: populate,
		load: function(q) {
			if (!options.cacheLength || !length)
				return null;
			/* 
			 * if dealing w/local data and matchContains than we must make sure
			 * to loop through all the data collections looking for matches
			 */
			if( !options.url && options.matchContains ){
				// track all matches
				var csub = [];
				// loop through all the data grids for matches
				for( var k in data ){
					// don't search through the stMatchSets[""] (minChars: 0) cache
					// this prevents duplicates
					if( k.length > 0 ){
						var c = data[k];
						$.each(c, function(i, x) {
							// if we've got a match, add it to the array
							if (matchSubset(x.value, q)) {
								csub.push(x);
							}
						});
					}
				}				
				return csub;
			} else 
			// if the exact item exists, use it
			if (data[q]){
				return data[q];
			} else
			if (options.matchSubset) {
				for (var i = q.length - 1; i >= options.minChars; i--) {
					var c = data[q.substr(0, i)];
					if (c) {
						var csub = [];
						$.each(c, function(i, x) {
							if (matchSubset(x.value, q)) {
								csub[csub.length] = x;
							}
						});
						return csub;
					}
				}
			}
			return null;
		}
	};
};

$.Autocompleter.Select = function (options, input, select, config) {
	var CLASSES = {
		ACTIVE: "ac_over"
	};
	
	var listItems,
		active = -1,
		data,
		term = "",
		needsInit = true,
		element,
		list;
	
	// Create results
	function init() {
		if (!needsInit)
			return;
		element = $("<div/>")
		.hide()
		.addClass(options.resultsClass)
		.css("position", "absolute")
		.appendTo(jQuery(input).parent());
		//.appendTo(document.body);
	
		list = $("<ul/>").appendTo(element).mouseover( function(event) {
			if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
	            active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
			    
			    var newLi = $(target(event));
			    newLi.addClass(CLASSES.ACTIVE);
			    if (typeof options.selectionChanged == "function") {
			    	options.selectionChanged(newLi);
			    }
	        }
		}).click(function(event) {
			$(target(event)).addClass(CLASSES.ACTIVE);
			select();
			// TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
			$(input).focus();
			return false;
		}).mousedown(function() {
			config.mouseDownOnSelect = true;
		}).mouseup(function() {
			config.mouseDownOnSelect = false;
		});
		
		if( options.width > 0 )
			element.css("width", options.width);
			
		needsInit = false;
	} 
	
	function target(event) {
		var element = event.target;
		while(element && element.tagName != "LI")
			element = element.parentNode;
		// more fun with IE, sometimes event.target is empty, just ignore it then
		if(!element)
			return [];
		return element;
	}

	function moveSelect(step) {
		listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
		movePosition(step);
        var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
        if(options.scroll) {
            var offset = 0;
            listItems.slice(0, active).each(function() {
				offset += this.offsetHeight;
			});
            if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
                list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
            } else if(offset < list.scrollTop()) {
                list.scrollTop(offset);
            }
        }
	};
	
	function movePosition(step) {
		active += step;
		if (active < 0) {
			active = listItems.size() - 1;
		} else if (active >= listItems.size()) {
			active = 0;
		}
	}
	
	function limitNumberOfItems(available) {
		return options.max && options.max < available
			? options.max
			: available;
	}
	
	function fillList() {
		list.empty();
		var max = limitNumberOfItems(data.length);
		for (var i=0; i < max; i++) {
			if (!data[i])
				continue;
			var li = $("<li/>");
			li.append('<div class="liInner"></div>');
			var formatted = options.formatItem(data[i].data, li.children(), i+1, max, data[i].value, term);
			if ( formatted === false )
				continue;
			li = li.addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
			$.data(li, "ac_data", data[i]);
		}
		listItems = list.find("li");
		if ( options.selectFirst ) {
			listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
			active = 0;
		}
		// apply bgiframe if available
		if ( $.fn.bgiframe )
			list.bgiframe();
	}
	
	return {
		display: function(d, q) {
			init();
			data = d;
			term = q;
			fillList();
		},
		next: function() {
			moveSelect(1);
		},
		prev: function() {
			moveSelect(-1);
		},
		pageUp: function() {
			if (active != 0 && active - 8 < 0) {
				moveSelect( -active );
			} else {
				moveSelect(-8);
			}
		},
		pageDown: function() {
			if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
				moveSelect( listItems.size() - 1 - active );
			} else {
				moveSelect(8);
			}
		},
		hide: function() {
			element && element.hide();
			listItems && listItems.removeClass(CLASSES.ACTIVE);
			active = -1;
			if (typeof options['onHide'] == "function") {
				options['onHide']();
			}
			
		},
		visible : function() {
			return element && element.is(":visible");
		},
		current: function() {
			return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
		},
		show: function() {
			var offset = $(input).position();
			element.css({
				width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
				top: offset.top + input.offsetHeight -1,
				left: offset.left
			}).show();
            if(options.scroll) {
                list.scrollTop(0);
                list.css({
					maxHeight: options.scrollHeight,
					overflow: 'auto'
				});
				
                if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
					var listHeight = 0;
					listItems.each(function() {
						listHeight += this.offsetHeight;
					});
					var scrollbarsVisible = listHeight > options.scrollHeight;
                    list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
					if (!scrollbarsVisible) {
						// IE doesn't recalculate width when scrollbar disappears
						listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
					}
                }
                
            }
		},
		selected: function() {
			var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
			return selected && selected.length && $.data(selected[0], "ac_data");
		},
		emptyList: function (){
			list && list.empty();
		},
		unbind: function() {
			element && element.remove();
		}
	};
};

$.fn.selection = function(start, end) {
	if (start !== undefined) {
		return this.each(function() {
			if( this.createTextRange ){
				var selRange = this.createTextRange();
				if (end === undefined || start == end) {
					selRange.move("character", start);
					selRange.select();
				} else {
					selRange.collapse(true);
					selRange.moveStart("character", start);
					selRange.moveEnd("character", end);
					selRange.select();
				}
			} else if( this.setSelectionRange ){
				this.setSelectionRange(start, end);
			} else if( this.selectionStart ){
				this.selectionStart = start;
				this.selectionEnd = end;
			}
		});
	}
	var field = this[0];
	if ( field.createTextRange ) {
		var range = document.selection.createRange(),
			orig = field.value,
			teststring = "<->",
			textLength = range.text.length;
		range.text = teststring;
		var caretAt = field.value.indexOf(teststring);
		field.value = orig;
		this.selection(caretAt, caretAt + textLength);
		return {
			start: caretAt,
			end: caretAt + textLength
		}
	} else if( field.selectionStart !== undefined ){
		return {
			start: field.selectionStart,
			end: field.selectionEnd
		}
	}
};

})(jQuery);
SliderPage = function(slider, index, pageElement, tabElement) {
	this.slider = slider;
	this.pageElement = pageElement;
	this.tabElement = tabElement;
	this.index = index;
	
	this.listenersFrom = new List();
	this.listenersTo = new List();
}

SliderPage.prototype.maySlideFrom = function(toPage) {
	var maySlide = true;
	
	for (var i=0; i<this.listenersFrom.size(); i++) {
		var listener = this.listenersFrom.get(i);
		var result = listener(toPage);
		if (result === false)
		{
			maySlide = false;
		} 
	}
	
	return maySlide;
}

SliderPage.prototype.maySlideTo = function(fromPage) {
	var maySlide = true;
	
	for (var i=0; i<this.listenersTo.size(); i++) {
		var listener = this.listenersTo.get(i);
		var result = listener(fromPage);
		if (result === false)
		{
			maySlide = false;
		} 
	}
	
	return maySlide;
}

SliderPage.prototype.subscribeFrom = function(func) {
	this.listenersFrom.add(func);
}
SliderPage.prototype.subscribeTo = function(func) {
	this.listenersTo.add(func);
	
	if( this.slider.currentPageIndex == this.index ) {
		func();
	}
}


//=============================================================
//=============================================================
//=============================================================


Slider = function() {
	this.pages = new List();
	this.currentPageIndex = 0;
	this.panelWidth = 0;
}

Slider.prototype.init = function() {
	this.element = jQuery("#slider");
	this.scroller = this.element.find(".scroll");
	
	var thisSlider = this;
	this.scroller.scroll(function() {
		if (!thisSlider.isScrolling) {
			thisSlider._slideTo(thisSlider.getCurrentPage(), true);
		}
	});
	
	this.container = this.element.find(".scrollContainer");
	
	
	// Set tab width
	var tabs = this.element.find("ul.navigation li a");
	
	var tabPaddingRight = parseInt(tabs.css("padding-right").replace("px",""));
	var maxWidth = 118 + tabPaddingRight;
	
	tabs.closest("table").width( maxWidth * tabs.size() + 20 );
	
	var navWidth = this.element.find("ul.navigation").width() - 20;
	console.log(navWidth);
	var tabWidth = navWidth / tabs.size();
	tabWidth = tabWidth - tabPaddingRight;
	
	tabWidth = Math.min(tabWidth, maxWidth);
	
	tabs.width(tabWidth);
	
	// Set panels width
	var panels = this.container.children("div.panel");
	this.panelWidth = panels[0].offsetWidth;
	this.container.css('width', panels[0].offsetWidth * panels.length);
	
	this.tabs = jQuery("#slider ul.navigation");
	this.tabs.children("li:last").addClass("last");
	
	var index = -1;
	panels.each(function() {
		index++;
		var pageEl = jQuery(this);
		
		var tabEl = thisSlider.tabs.find('a[href$="' + pageEl.attr("id") + '"]');
		
		var page = new SliderPage( thisSlider, index, pageEl, tabEl );
		thisSlider.pages.add( page );
		
		tabEl.click(function() {
			thisSlider.slideTo(page);
			return false;
		});
		
		
		page.subscribeFrom(function() {
			// Validate all fields on page.
			var invalids = pageEl.find(".section input, .section select");
			var valid = true;
			invalids.each(function(){
				valid = valid && ( validateField( jQuery(this) ) || jQuery(this).parents(".popup").length > 0 );
			});
			return valid;
		});
		
	});
	
	thisSlider.setCurrentPage( this.pages.get(0) );
	
	// Set up next/prev-buttons
	jQuery("button.next").click(function() {
		thisSlider.next();
	});
	jQuery("button.prev").click(function() {
		thisSlider.prev();
	});
	
	this.updateButtons();
}

Slider.prototype.updateButtons = function() {
	jQuery("button.prev").disable(this.currentPageIndex == 0);
	jQuery("button.next").disable(this.currentPageIndex == this.pages.size()-1);
}

Slider.prototype.updateTabs = function() {
	this.tabs.children("li").removeClass("prev").removeClass("done").removeClass("selected").removeClass("selectedLast");
	
	var page = this.getCurrentPage();
	if (page.index < this.pages.size()-1) {
		page.tabElement.parent().addClass("selected");
	} else {
		page.tabElement.parent().addClass("selectedLast");
	}
	var prevPage = this.getPage(this.currentPageIndex-1);
	if (prevPage) {
		prevPage.tabElement.parent().addClass("prev");
		prevPage = this.getPage( prevPage.index-1 );
	}
	while (prevPage) {
		prevPage.tabElement.parent().addClass("done");
		prevPage = this.getPage( prevPage.index-1 );
	}
}

Slider.prototype.setCurrentPage = function(page) {
	this.currentPageIndex = page.index;
	this.updateTabs();
	this.updateButtons();
}
Slider.prototype.getCurrentPage = function() {
	return this.getPage(this.currentPageIndex);
}
Slider.prototype.getPage = function(index) {
	return this.pages.get(index);
}
Slider.prototype.getPageByName = function(name) {
	for (var i=0; i<this.pages.size(); i++) {
		var page = this.pages.get(i);
		if ( page.tabElement.is("a[href$='"+name+"']") ) {
			return page;
		}
	}
	return null;
}




Slider.prototype.next = function() {
	if (this.currentPageIndex+1 >= this.pages.size())
		return false;
	this.slideTo( this.getPage(this.currentPageIndex + 1) );
	return true;
}

Slider.prototype.prev = function() {
	if (this.currentPageIndex-1 < 0)
		return false;
	this.slideTo( this.getPage(this.currentPageIndex - 1) );
	return true;
}

Slider.prototype._furthestAllowedSlide = function(page) {
	if (page.index < this.currentPageIndex) {   // Going backwards, then it's ok.
		return page;
	}
	
	var furthestPage = this.getCurrentPage();
	
	for (var index=this.currentPageIndex; index<page.index; index++) {
		var fromPage = this.getPage(index);
		var toPage = this.getPage(index+1);
		
		var maySlideFrom = fromPage.maySlideFrom(toPage);
		var maySlideTo = toPage.maySlideTo(fromPage);
		
		if (!maySlideFrom || !maySlideTo) {
			break;
		}
		
		furthestPage = toPage;
	}
	
	return furthestPage;
}

Slider.prototype.slideTo = function(page) {
	var slideToPage = this._furthestAllowedSlide(page);
	
	if (slideToPage != this.getCurrentPage()) {
		// clearAllFieldErrors( this.getCurrentPage().pageElement );
		
		this._slideTo(slideToPage);
		this.setCurrentPage(slideToPage);
		return true;
	}
	return false;
}

Slider.prototype._slideTo = function(page, dontAnimate) {
	if (dontAnimate) {
		this.scroller.scrollLeft(page.index*this.panelWidth);
	} else {
		this.isScrolling = true;
		
		var thisSlider = this;
		this.scroller.stop(true, false).animate({
			scrollLeft: page.index*this.panelWidth
		}, 400, "swing", function() {
			thisSlider.isScrolling = false;
		});
	}
}

var slider = new Slider();

CupMan.ClubChooserPopup = Class.extend({
	init: function(el) {
		this.element = el;
		var clubNameInput = this.clubNameInput = el.find("input.clubName");
		
		el.find(".addNewClubLink").click(function() {
			el.find(".addNewClub").show();
			el.find(".earlierPersonClubs").hide();
			jQuery(this).hide();
			
			
			jQuery.modal.impl.setPosition();
			
			el.find(".addNewClub").hide().show();
			el.find(".addNewClub input").focus();
			
			return false;
		});
		
		el.find(".earlierPersonClub").hover(function() {
			jQuery(this).addClass("earlierPersonClubHover");
		}, function() {
			jQuery(this).removeClass("earlierPersonClubHover");
		});
		
		var thiz = this;
		
		jQuery(".earlierPersonClub[clubid], *[clubid] button", el).live("click", function() {
			var clubElement = jQuery(this).closest("*[clubId]");
			
			if (clubElement.is(".earlierPersonClub") && clubElement.find("span.regged").size()>0 && careAboutDuplicats) {
				return false;
			}
			
			var clubId = clubElement.attr("clubId");
			console.log(clubElement, clubElement.attr("clubId"));
			thiz.chooseClub(clubId);
		});
		
		this.clubNameInput.bind("result", function(event, data, text) {
			
			console.log(data);
			var clubId = data[1];
			thiz.chooseClub(clubId);
		});
		
		this.clubNameInput.bind("start", function() {
			jQuery(this).addClass("clubNameWorking");
		});
		this.clubNameInput.bind("done", function() {
			jQuery(this).removeClass("clubNameWorking");
		});
		
		this.clubNameInput.autocomplete( CupMan.getServiceUrl("FindGlobalClubsService") + "?formId="+formId, {
			width: 350,
			vetoSelection: function(sel) {
				return sel.data[4] && careAboutDuplicates;
			},
			onShow: function() {
				clubNameInput.addClass("clubNameHover");
				el.find(".addNewClubButton").hide();
			},
			onHide: function() {
				el.find(".addNewClubButton").show();
				clubNameInput.removeClass("clubNameHover");
			},
			selectionChanged: function(li) {
				clubNameInput.removeClass("clubNameHover");
				if (li.find(".special").size() > 0 || clubNameInput.val().toLowerCase() == li.find("span.earlierTitle").text().toLowerCase()) {
					clubNameInput.addClass("clubNameHover");
				}
			},
			formatItem:  function(row, liInner, i, max, value, term) {
				if (row[0] == "new") {
					liInner.addClass("special");
					liInner.attr("clubId", "0");
					var name = clubNameInput.val();
					
					var btnOrInfo = '<button type="button">'+CupMan.T("Web.Registration."+clubPopup_textPrefix+"Popup.RegisterBtn")+'</button>';
					if (row[4] && careAboutDuplicates) {
						btnOrInfo = '<span class="regged">'+CupMan.T("Web.Registration."+clubPopup_textPrefix+"Popup.AlreadyReggedInfo")+'</span>';
					}
					
					liInner.html(
						btnOrInfo +
						'<span class="earlierTitle">'+CupMan.T("Web.Registration."+clubPopup_textPrefix+"Popup.NewAssociation")+
						'</span><span>'+ CupMan.T("Web.Registration."+clubPopup_textPrefix+"Popup.NewAssociationInfo").replace("XXX", name) +'</span>');
				} else {
					liInner.attr("clubId", row[1]);
					
					var address = "";
					if (row[2]["city"]) {
						address = CupMan.T("Web.Registration."+clubPopup_textPrefix+"Popup.From")+" " + row[2]["city"] + ", " + row[2]["nation"]; 
					}
					
					var btnOrInfo = '<button type="button">'+CupMan.T("Web.Registration."+clubPopup_textPrefix+"Popup.UseBtn")+'</button>';
					if (row[4] && careAboutDuplicates) {
						btnOrInfo = '<span class="regged">'+CupMan.T("Web.Registration."+clubPopup_textPrefix+"Popup.AlreadyReggedInfo")+'</span>';
						liInner.addClass("regged");
					}
					
					liInner.html(btnOrInfo + '<span class="earlierTitle">'+row[0]+'</span><span>'+ address +'</span>');
				}
				if (row[3]) {
					liInner.parent().addClass("ac_over");
				}
			},
			selectFirst: false,
			parse: function(data) {
				var root = jQuery(data).children();
				var clubNodes = root.children();
				
				if (clubNodes.size() > 0) {
					var selectedIndex = -1;
					var name = clubNameInput.val();
					clubNodes.each(function(i) {
						if (name.toLowerCase() == jQuery(this).text().toLowerCase())
						{
							selectedIndex = i;
						}
					});
					
					var parsed = [];
					
					if (selectedIndex == -1) {
						parsed.push({
							data: ["new", "0", {}, true],
							value: name,
							result: name
						});
					}
					
					
					clubNodes.each(function(i) {
						var clubNode = jQuery(this);
						var addressNode = clubNode.children();
						var clubCount = parseInt(clubNode.attr("formClubs"));
						
						var isRegged = clubCount > 0;
						
						var row = [clubNode.text(), // 0 
						clubNode.attr("id"),  // 1
						{
							street: addressNode.attr("street"),
							postal: addressNode.attr("postal"),    // 2
							city: addressNode.attr("city"),
							nation: addressNode.attr("nation")
						}, 
						selectedIndex==i, // 3 
						isRegged // 4
						];
						
						parsed[parsed.length] = {
							data: row,
							value: row[0],
							result: row[0]
						};
						
					});
				} else {
					return [];
				}
				return parsed;
			}
		});
		
	},
	chooseClub: function(clubId) {
		console.log("chooseclub", clubId);
		var name = this.clubNameInput.val();
		this.element.html("<h2>"+CupMan.T("Web.Registration."+clubPopup_textPrefix+"Popup.Working")+"</h2>");
		
		CupMan.callService("SelectClubService", {
    		data: {"clubId": clubId, "name": name, ownerId: personId, formId: formId}, 
    		success: function(root){
    			var status = parseInt( root.attr("status") );
	            if ( status == 0 )
	            {
	            	clubId = root.attr("clubId");
	        		window.location.href = selfUrl+formId+"/"+clubId + params;
	            } else {
	            	alert(status + " :: " + root.text());
	            }
    		}
    	});
		
	}
});/* SpinButton control
 *
 * Adds bells and whistles to any ordinary textbox to
 * make it look and feel like a SpinButton Control.
 *
 * Originally written by George Adamson, Software Unity (george.jquery@softwareunity.com) August 2006.
 * - Added min/max options
 * - Added step size option
 * - Added bigStep (page up/down) option
 *
 * Modifications made by Mark Gibson, (mgibson@designlinks.net) September 2006:
 * - Converted to jQuery plugin
 * - Allow limited or unlimited min/max values
 * - Allow custom class names, and add class to input element
 * - Removed global vars
 * - Reset (to original or through config) when invalid value entered
 * - Repeat whilst holding mouse button down (with initial pause, like keyboard repeat)
 * - Support mouse wheel in Firefox
 * - Fix double click in IE
 * - Refactored some code and renamed some vars
 *
 * Tested in IE6, Opera9, Firefox 1.5
 * v1.0  11 Aug 2006 - George Adamson	- First release
 * v1.1     Aug 2006 - George Adamson	- Minor enhancements
 * v1.2  27 Sep 2006 - Mark Gibson		- Major enhancements
 * v1.3a 28 Sep 2006 - George Adamson	- Minor enhancements
 
 Sample usage:
 
	// Create group of settings to initialise spinbutton(s). (Optional)
	var myOptions = {
					min: 0,						// Set lower limit.
					max: 100,					// Set upper limit.
					step: 1,					// Set increment size.
					spinClass: mySpinBtnClass,	// CSS class to style the spinbutton. (Class also specifies url of the up/down button image.)
					upClass: mySpinUpClass,		// CSS class for style when mouse over up button.
					downClass: mySpinDnClass	// CSS class for style when mouse over down button.
					}
 
	jQuery(document).ready(function(){

		// Initialise INPUT element(s) as SpinButtons: (passing options if desired)
		jQuery("#myInputElement").SpinButton(myOptions);

	});
 
 */
jQuery.fn.SpinButton = function(cfg){
	return this.each(function(){

		// Apply specified options or defaults:
		// (Ought to refactor this some day to use jQuery.extend() instead)
		this.spinCfg = {
			//min: cfg && cfg.min ? Number(cfg.min) : null,
			//max: cfg && cfg.max ? Number(cfg.max) : null,
			min: cfg && !isNaN(parseFloat(cfg.min)) ? Number(cfg.min) : null,	// Fixes bug with min:0
			max: cfg && !isNaN(parseFloat(cfg.max)) ? Number(cfg.max) : null,
			step: cfg && cfg.step ? Number(cfg.step) : 1,
			page: cfg && cfg.page ? Number(cfg.page) : 10,
			upClass: cfg && cfg.upClass ? cfg.upClass : 'up',
			downClass: cfg && cfg.downClass ? cfg.downClass : 'down',
			reset: cfg && cfg.reset ? cfg.reset : this.value,
			delay: cfg && cfg.delay ? Number(cfg.delay) : 500,
			interval: cfg && cfg.interval ? Number(cfg.interval) : 100,
			_btn_width: 20,
			_btn_height: 12,
			_direction: null,
			_delay: null,
			_repeat: null
		};
		
		this.adjustValue = function(i){
			var v = (isNaN(this.value) ? this.spinCfg.reset : Number(this.value)) + Number(i);
			if (this.spinCfg.min !== null) v = Math.max(v, this.spinCfg.min);
			if (this.spinCfg.max !== null) v = Math.min(v, this.spinCfg.max);
			this.value = v;
			jQuery(this).change();
		};
		
		jQuery(this)
		.addClass(cfg && cfg.spinClass ? cfg.spinClass : 'spin-button')
		
		.mousemove(function(e){
			// Determine which button mouse is over, or not (spin direction):
			var x = e.pageX || e.x;
			var y = e.pageY || e.y;
			var el = e.target || e.srcElement;
			var direction = 
				(x > jQuery(el).offset().left + el.offsetWidth - this.spinCfg._btn_width)
				? ((y < jQuery(el).offset().top + this.spinCfg._btn_height) ? 1 : -1) : 0;
			
			if (direction !== this.spinCfg._direction) {
				// Style up/down buttons:
				switch(direction){
					case 1: // Up arrow:
						jQuery(this).removeClass(this.spinCfg.downClass).addClass(this.spinCfg.upClass);
						break;
					case -1: // Down arrow:
						jQuery(this).removeClass(this.spinCfg.upClass).addClass(this.spinCfg.downClass);
						break;
					default: // Mouse is elsewhere in the textbox
						jQuery(this).removeClass(this.spinCfg.upClass).removeClass(this.spinCfg.downClass);
				}
				
				// Set spin direction:
				this.spinCfg._direction = direction;
			}
		})
		
		.mouseout(function(){
			// Reset up/down buttons to their normal appearance when mouse moves away:
			jQuery(this).removeClass(this.spinCfg.upClass).removeClass(this.spinCfg.downClass);
			this.spinCfg._direction = null;
		})
		
		.mousedown(function(e){
			if (this.spinCfg._direction != 0) {
				// Respond to click on one of the buttons:
				var self = this;
				var adjust = function() {
					self.adjustValue(self.spinCfg._direction * self.spinCfg.step);
				};
			
				adjust();
				
				// Initial delay before repeating adjustment
				self.spinCfg._delay = window.setTimeout(function() {
					adjust();
					// Repeat adjust at regular intervals
					self.spinCfg._repeat = window.setInterval(adjust, self.spinCfg.interval);
				}, self.spinCfg.delay);
			}
		})
		
		.mouseup(function(e){
			// Cancel repeating adjustment
			window.clearInterval(this.spinCfg._repeat);
			window.clearTimeout(this.spinCfg._delay);
		})
		
		.dblclick(function(e) {
			if (jQuery.browser.msie)
				this.adjustValue(this.spinCfg._direction * this.spinCfg.step);
		})
		
		.keydown(function(e){
			// Respond to up/down arrow keys.
			switch(e.keyCode){
				case 38: this.adjustValue(this.spinCfg.step);  break; // Up
				case 40: this.adjustValue(-this.spinCfg.step); break; // Down
				case 33: this.adjustValue(this.spinCfg.page);  break; // PageUp
				case 34: this.adjustValue(-this.spinCfg.page); break; // PageDown
			}
		})

		
		.change(function(e){
			// this.adjustValue(0);
		})
		
		.keyup(function(e){
			if ( !isNaN(parseInt(jQuery(this).val())) )
				this.adjustValue(0);
		});
		
		/*
		if (this.addEventListener) {
			// Respond to mouse wheel in Firefox
			this.addEventListener('DOMMouseScroll', function(e) {
				if (e.detail > 0)
					this.adjustValue(-this.spinCfg.step);
				else if (e.detail < 0)
					this.adjustValue(this.spinCfg.step);
				
				e.preventDefault();
			}, false);
		}
		*/
	});
	
	function coord(el,prop) {
		var c = el[prop], b = document.body;
		
		while ((el = el.offsetParent) && (el != b)) {
			if (!jQuery.browser.msie || (el.currentStyle.position != 'relative'))
				c += el[prop];
		}
		
		return c;
	}
};
/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * $LastChangedDate: 2007-07-21 18:44:59 -0500 (Sat, 21 Jul 2007) $
 * $Rev: 2446 $
 *
 * Version 2.1.1
 */

(function($){

/**
 * The bgiframe is chainable and applies the iframe hack to get 
 * around zIndex issues in IE6. It will only apply itself in IE6 
 * and adds a class to the iframe called 'bgiframe'. The iframe
 * is appeneded as the first child of the matched element(s) 
 * with a tabIndex and zIndex of -1.
 * 
 * By default the plugin will take borders, sized with pixel units,
 * into account. If a different unit is used for the border's width,
 * then you will need to use the top and left settings as explained below.
 *
 * NOTICE: This plugin has been reported to cause perfromance problems
 * when used on elements that change properties (like width, height and
 * opacity) a lot in IE6. Most of these problems have been caused by 
 * the expressions used to calculate the elements width, height and 
 * borders. Some have reported it is due to the opacity filter. All 
 * these settings can be changed if needed as explained below.
 *
 * @example $('div').bgiframe();
 * @before <div><p>Paragraph</p></div>
 * @result <div><iframe class="bgiframe".../><p>Paragraph</p></div>
 *
 * @param Map settings Optional settings to configure the iframe.
 * @option String|Number top The iframe must be offset to the top
 * 		by the width of the top border. This should be a negative 
 *      number representing the border-top-width. If a number is 
 * 		is used here, pixels will be assumed. Otherwise, be sure
 *		to specify a unit. An expression could also be used. 
 * 		By default the value is "auto" which will use an expression 
 * 		to get the border-top-width if it is in pixels.
 * @option String|Number left The iframe must be offset to the left
 * 		by the width of the left border. This should be a negative 
 *      number representing the border-left-width. If a number is 
 * 		is used here, pixels will be assumed. Otherwise, be sure
 *		to specify a unit. An expression could also be used. 
 * 		By default the value is "auto" which will use an expression 
 * 		to get the border-left-width if it is in pixels.
 * @option String|Number width This is the width of the iframe. If
 *		a number is used here, pixels will be assume. Otherwise, be sure
 * 		to specify a unit. An experssion could also be used.
 *		By default the value is "auto" which will use an experssion
 * 		to get the offsetWidth.
 * @option String|Number height This is the height of the iframe. If
 *		a number is used here, pixels will be assume. Otherwise, be sure
 * 		to specify a unit. An experssion could also be used.
 *		By default the value is "auto" which will use an experssion
 * 		to get the offsetHeight.
 * @option Boolean opacity This is a boolean representing whether or not
 * 		to use opacity. If set to true, the opacity of 0 is applied. If
 *		set to false, the opacity filter is not applied. Default: true.
 * @option String src This setting is provided so that one could change 
 *		the src of the iframe to whatever they need.
 *		Default: "javascript:false;"
 *
 * @name bgiframe
 * @type jQuery
 * @cat Plugins/bgiframe
 * @author Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
 */
$.fn.bgIframe = $.fn.bgiframe = function(s) {
	// This is only for IE6
	if ( $.browser.msie && /6.0/.test(navigator.userAgent) ) {
		s = $.extend({
			top     : 'auto', // auto == .currentStyle.borderTopWidth
			left    : 'auto', // auto == .currentStyle.borderLeftWidth
			width   : 'auto', // auto == offsetWidth
			height  : 'auto', // auto == offsetHeight
			opacity : true,
			src     : 'javascript:false;'
		}, s || {});
		var prop = function(n){return n&&n.constructor==Number?n+'px':n;},
		    html = '<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+
		               'style="display:block;position:absolute;z-index:-1;'+
			               (s.opacity !== false?'filter:Alpha(Opacity=\'0\');':'')+
					       'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+
					       'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+
					       'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+
					       'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+
					'"/>';
		return this.each(function() {
			if ( $('> iframe.bgiframe', this).length == 0 )
				$(this).parent().append( document.createElement(html) );
		});
	}
	return this;
};

})(jQuery);
// BASIC FUNCTIONALITY 


var CatEditor = {};

CatEditor.Team = Class.extend({
	init: function(id, categoryId, name, suffix, promisesLodging) {
		this.id = id;
		this.categoryId = categoryId;
		this.name = name;
		this.suffix = suffix;
		this.promisesLodging = promisesLodging || false;
	}
});

CatEditor.Category = Class.extend({
	init: function(id, name, open) {
		this.id = id;
		this.name = name;
		this.open = open;
	}
});

CatEditor.Editor = Class.extend({
	init: function(element, saveContin) {
		this.saveContin = saveContin;  /* boolean */ 
		this.teams = new List();       /* List<Team> */ 
		this.idTeams = new Map();      /* Map<teamId,Team> */
		this.catTeams = new Map();     /* Map<categoryId,List<Team>> */ 
		
		this.categories = new List();  /* List<Category> */
		this.idCategories = new Map(); /* Map<categoryId,Category> */
		
		this.categoryBoxes = new List();
		this.idCategoryBoxes = new Map();
		
		this.element = element;
		
		this.lodgingPromise = false;
	},
	addCategory: function(id, name, open) {
		var category = new CatEditor.Category(id, name, open);
		this.categories.add(category);
		this.idCategories.put(category.id, category);
	},
	addTeam: function(id, categoryId, name, suffix, promisesLodging) {
		if (this.idTeams.containsKey(id)) {
			return;
		}
		
		var team = new CatEditor.Team(id, categoryId, name, suffix, promisesLodging);
		
		this.registerTeam(team);
		
		this.updateTotal();
	},
	registerTeam: function(team) {
		this.teams.add(team);
		this.idTeams.put(team.id, team);
		
		if (!this.catTeams.containsKey(team.categoryId)) {
			this.catTeams.put(team.categoryId, new List());
		}
		var teams = this.catTeams.get(team.categoryId);
		if (teams.indexOf(team) < 0) {
			teams.add(team);
		}
		
		this.updateTotal();
	},
	removeTeam: function(id) {
		var team = this.idTeams.get(id);
		
		this.teams.remove( this.teams.indexOf(team) );
		
		var teams = this.catTeams.get(team.categoryId);
		teams.remove(teams.indexOf(team));
		
		
		var box = this.idCategoryBoxes.get(team.categoryId);
		box.removeTeam(team.id);
		
		this.updateTotal();
	},
	updateTotal: function() {
		jQuery("#totalTeamCount").val( this.teams.size() );
	},
	_addTeam: function(id, categoryId, name, suffix, promisesLodging) {
		var box = this.idCategoryBoxes.get(categoryId);
		if ( !box ) {
			var category = this.idCategories.get(categoryId);
			box = new CatEditor.CategoryBox(category, this);
			this.categoryBoxes.add(box);
			this.idCategoryBoxes.put(categoryId, box);
			
			var el = box.buildElement();
			this.element.append(el);
		}
		
		var suffix = suffix || box.estimateSuffix(name, 0);
		var team = new CatEditor.Team(id, categoryId, name, suffix, promisesLodging);
		
		this.registerTeam(team);
		
		box._addRow(team);
		
		this.updateTotal();
	},
	
	
	getTotalCount: function() {
		return this.teams.size();
	},
	
	getTeamCount: function(categoryId) {
		var teams = this.catTeams.get(categoryId);
		if (teams) {
			return teams.size();
		} else {
			return 0;
		}
	},
	setTeamCount: function(categoryId, count, finishedCallback) {
		var thisCatEditor = this;
		
		var _teams = this.catTeams.get(categoryId);
		var teams = new List();
		if (_teams) {
			teams.addAll(_teams);
		}
		
		if (teams.size() == count) {
			// nothing to add/remove.
			finishedCallback();
			return;
		}
		
		// add?
		if (teams.size() < count) {
			
			if (this.saveContin) {
				
				var addTeam = function(categoryId, name, callback) {
	    			CupMan.callService("teams.EditTeamService", {
						data: {
							regClubPostId: postId,
							teamPostId: -1,
							categoryId: categoryId,
							name: name
						},
						success: function(root) {
							var suffix = parseInt(root.attr("suffix"));
							var teamPostId = parseInt(root.attr("teamPostId"));
							
							thisCatEditor._addTeam(teamPostId, categoryId, name, suffix);
							
							callback();
						}
					});
	    		};
	    		
	    		var addCount = count-teams.size();
	    		var i = 0;
	    		var func = function() {
	    			if (i >= addCount) {
	    				finishedCallback();
	    				return;
	    			}
	    			i++;
	    			addTeam(categoryId, "", func);
	    		};
	    		func();
	    		
			} else { // Not saveContin
				for (var i=0; i < count-teams.size(); i++) {
					this._addTeam(teamSeq--, categoryId, "", false);
				}
				finishedCallback();
			}
		}
		
		// Remove?
		if (teams.size() > count) {
			if (this.saveContin) {
				
				CupMan.callService("teams.RemoveTeamsService", {
					data: {
						regClubPostId: postId,
						categoryId: categoryId,
						count: teams.size()-count
					},
					success: function(root) {
						root.children("Team").each(function() {
							var teamPostId = jQuery(this).attr("id");
							thisCatEditor.removeTeam(teamPostId);
						});
						
						finishedCallback();
					}
				});
				
			} else {
				for (var i=count; i < teams.size(); i++) {
					var team = teams.get(i);
					this.removeTeam(team.id);
				}
				finishedCallback();
			}
		}
	},
	
	
	/* Returns an object with several categoryId=,,Wildcats.
	 * Only used for saveContin=false (registration form)
	 */ 
	serialize: function() {
		var data = {};
		
		var categoryIds = this.catTeams.keys();
		for (var i=0; i<categoryIds.length; i++) {
			
			var categoryId = categoryIds[i];
			var teams = this.catTeams.get(categoryId);
			
			var teamString = "";
			for (var j=0; j<teams.size(); j++) {
				var team = teams.get(j);
				teamString += (j==0?"":",") + team.name + "|" + !!team.promisesLodging;
			}
			
			data[categoryId] = teamString;
		}
		
		return data;
	},
	
	buildElement: function() {
		try {
			var cats = this.catTeams.keys();
			for (var i=0; i<cats.length; i++) {
				var catId = cats[i];
				var category = this.idCategories.get(catId);
				
				// Add category box
				var categoryBox = new CatEditor.CategoryBox(category, this);
				this.categoryBoxes.add(categoryBox);
				this.idCategoryBoxes.put(catId, categoryBox);
				
				var el = categoryBox.buildElement();
				
				
				var teams = this.catTeams.get(catId);
				for (var j=0; j<teams.size(); j++) {
					var team = teams.get(j);
					categoryBox._addRow(team);
				}
				
				
				this.element.append(el);
			}
		} catch (e) {
			console.log(e);
		}
	}
});

CatEditor.CategoryBox = Class.extend({
	init: function(category, catEditor) {
		this.cat = category;
		this.rows = new List();
		this.element = null;
		this.catEditor = catEditor;
	},
	
	buildElement: function() {
		var categoryBox = jQuery(CatEditor.Builder.TEMPLATES.categoryBox);
		this.element = categoryBox;
		
		categoryBox.attr("categoryId", this.cat.id);
		categoryBox.find(".categoryNameCell h3").html( this.cat.name );
		
		categoryBox.find(".addRow a").html( CupMan.T("Web.CategoryEditor.AddTeam") + this.cat.name );
		
		var thiz = this;
		categoryBox.find(".addRow a").click(function() {
			thiz.newRow();
			return false;
		});
		
		return categoryBox;
	},
	
	saveAllRows: function() {
		for (var i=0; i<this.rows.size(); i++) {
			var row = this.rows.get(i);
			if (row.editMode) {
				row.save();
			}
		}
	},
	
	estimateSuffix: function(name, notId) {
		// h�gsta suffixet f�re notId
		var suffix = 0;
		for (var i=0; i<this.rows.size(); i++) {
			var row = this.rows.get(i);
			if (row.team.id == notId) {
				break;
			}
			if ( row.team.name.trim() == name.trim() ) {
				suffix = Math.max(suffix, row.team.suffix);
			}
		}
		return suffix + 1;
	},
	hasNameSiblings: function(name, notId) {
		var count = 0;
		for (var i=0; i<this.rows.size(); i++) {
			var row = this.rows.get(i);
			if ( row.team.name.trim() == name.trim() && row.team.id != notId ) {
				count++;
			}
		}
		return count;
	},
	updateAllRows: function() {
		for (var i=0; i<this.rows.size(); i++) {
			var row = this.rows.get(i);
			row.update();
		}
	},
	newRow: function() {
		try {
			this.saveAllRows();
			var estSuffix = this.estimateSuffix("");
			
			var team = new CatEditor.Team(teamSeq--, this.cat.id, "", estSuffix);
			var row = new CatEditor.TeamRow(team, this);
			row.editMode = true;
			this.rows.add(row);
			
			var rowEl = row.buildElement();
			this.element.find(".teamRows table tr.addRow").before(rowEl);
			
			this.updateAllRows();
			
			rowEl.find("div.edit input").focus().keyup();
			
			return row;
		} catch(e) {
			console.log(e);
		}
	},
	removeRow: function(row) {
		this.rows.remove( this.rows.indexOf(row) );
		row.element.remove();
	},
	removeTeam: function(id) {
		for (var i=0; i<this.rows.size(); i++) {
			var row = this.rows.get(i);
			if (row.team.id == id) {
				this.removeRow(row);
				break;
			}
		}
	},
	_addRow: function(team) {
		var row = new CatEditor.TeamRow(team, this);
		row.exists = true;
		this.rows.add(row);
		
		if (team.suffix == 0) {
			team.suffix = this.estimateSuffix(team.name, team.id);
		}
		
		var rowEl = row.buildElement();
		this.element.find(".teamRows table tr.addRow").before(rowEl);
		
		this.updateAllRows();
		
		return row;
	}
});

var teamSeq = -1;

CatEditor.TeamRow = Class.extend({
	init: function(team, categoryBox) {
		this.team = team;
		this.categoryBox = categoryBox;
		
		this.editMode = false;
		this.working = false;
		this.exists = false;
		
		this.oldValues = null;
	},
	
	
	buildElement: function() {
		var thiz = this;
		
		var teamRow = jQuery(CatEditor.Builder.TEMPLATES.teamRow);
		this.element = teamRow;
		
		if (catEditor.lodgingPromise) {
			teamRow.find(".lodgingCell input").attr("id", "lodgingPromise_"+this.team.id);
			teamRow.find(".lodgingCell label").attr("for", "lodgingPromise_"+this.team.id);
			
			teamRow.find(".lodgingCell label").html(CupMan.T("Web.CategoryEditor.LodgingPromise"));
			
			teamRow.find(".lodgingCell input").click(function() {
				thiz.save();
			});
			
			teamRow.find(".lodgingCell a.lodgingPromiseInfo").click(function() {
				console.log("SCROLL");
				jQuery("body").scrollTop( jQuery("body").attr("scrollHeight"));
				jQuery("#lodgingPromiseInfo").highlightFade({speed: 1000});
				return false;
			});
		} else {
			teamRow.find(".lodgingCell").html("");
		}
		teamRow.find("span.baseName").html( clubName );
		teamRow.find("span.name").html( this.team.name );
		teamRow.find("input.name").val( this.team.name ).autoGrowInput().keyup(function() {
			
			// Visa det suffix laget redan har om man inte �ndrat namnet.
			// Inte �ndrat namnet = 
			//			namnet st�mmer med textrutan och det inte beror p� att man sparat
			// 			"beror p� att man sparat" = 
			// 				den jobbar OCH _name inte �r name
			if (jQuery(this).val() == thiz.team.name && !( thiz.working && thiz.team.name!=thiz.team._name)) {
				var suffix = thiz.team.suffix;
			} else {
				
				if (thiz.categoryBox.catEditor.saveContin) {
					suffix = "?";
				} else {
					var suffix = thiz.categoryBox.estimateSuffix( jQuery(this).val(), thiz.team.id );
					
					var siblings = thiz.categoryBox.hasNameSiblings( jQuery(this).val(), thiz.team.id );
					
					if (siblings == 0) {
						suffix = "";
					}
				}
			}
			thiz.element.find("div.edit span.suffix").html(suffix);
		});
		teamRow.find("span.suffix").html( this.team.suffix );
		
		
		teamRow.find("div.edit *").click(function() {
			jQuery(this).parent().find("input").focus();
		});
		
		teamRow.find("a.edit").html(CupMan.T("Web.CategoryEditor.ChangeName")).click(function() {
			thiz.editMode = true;
			thiz.update();
			thiz.element.find("input:text").focus();
		});
		teamRow.find("a.save").html(CupMan.T("Web.CategoryEditor.Save")).click(function() {
			thiz.save();
		});
		teamRow.find("a.undo").html(CupMan.T("Web.CategoryEditor.Undo")).click(function() {
			if ( thiz.exists ) {
				thiz.editMode = false;
				thiz.update();
			} else {
				thiz.remove();
			}
		});
		teamRow.find("a.delete").html(CupMan.T("Web.CategoryEditor.Delete")).click(function() {
			thiz.remove();
		});
		
		this.update();
		
		return teamRow;
	},
	
	update: function() {
		
		if (!this.categoryBox.catEditor.saveContin) {
			// Update suffix
			this.team.suffix = this.categoryBox.estimateSuffix(this.team.name, this.team.id);
		}
		
		//debugger;
		
		var name = this.element.find("span.name").html( this.team.name );
		if (!this.editMode || !this.categoryBox.catEditor.saveContin) {
			var suffix = this.element.find("span.suffix").html( this.team.suffix );
		}
		
		var nameField = this.element.find("input.name");
		var promisesLodgingField = this.element.find(".lodgingCell input");
		
		if (!this.editMode) {
			promisesLodgingField.disable(false);
			nameField.val( this.team.name );
			if (promisesLodgingField.size() > 0) {
				promisesLodgingField.get(0).checked = this.team.promisesLodging;
			}
		} else {
			promisesLodgingField.disable();
		}
		
		var view = this.element.find("div.view");
		var edit = this.element.find("div.edit");
		
		if ( this.editMode ) {
			edit.show();
			view.hide();
			
			if (this.categoryBox.catEditor.saveContin) {
				this.element.find("div.edit span.suffix").html("?");
			}
			
			nameField.keyup();
			
		} else {
			edit.hide();
			view.show();
			
			if (this.team.suffix > 0 && this.categoryBox.hasNameSiblings(this.team.name, this.team.id)) {
				this.element.find("div.view span.suffix").show();
			} else {
				this.element.find("div.view span.suffix").hide();
			}
			
		}
		
		if ( this.working ) {
			nameField.disable(true);
			
			this.element.find("img.spinner").show();
			this.element.find("a.save, a.undo").hide();
			this.element.find("a.delete, a.edit").hide();
		} else {
			nameField.disable(false);
			if ( this.editMode ) {
				this.element.find("a.save, a.undo").show();
				this.element.find("a.delete, a.edit").hide();
			} else {
				this.element.find("a.save, a.undo").hide();
				this.element.find("a.delete, a.edit").show();
			}
			
			this.element.find("img.spinner").hide();
		}
		
		if (this.locked) {
			this.element.find("a.edit").hide();
			this.element.find("a.delete").hide();
			
			jQuery("#bookedFullInfoBar").slideDown();
		} else {
			
		}
	},
	
	save: function() {
		try { 
			var nameField = this.element.find("input.name");
			var promisesLodgingField = this.element.find(".lodgingCell input");
			
			var promisesLodging = this.team.promisesLodging;
			if (promisesLodgingField.size() > 0) {
				promisesLodging = promisesLodgingField.get(0).checked;
			}
			
			
			var name = nameField.val();
			
			name = name.replace(/\d+$/, "").trim();
			var thiz = this;
			
			if (name == this.team.name && promisesLodging == this.team.promisesLodging && this.team.exists) {
				this.categoryBox.catEditor.registerTeam(this.team);
				this.editMode = false;
				this.exists = true;
				this.working = false;
				
				this.update();
				this.categoryBox.updateAllRows();
				return;
			}
			
			this.team._name = this.team.name;
			this.team.name = name;
			this.team.promisesLodging = promisesLodging;
			var thiz = this;
			
			if (this.categoryBox.catEditor.saveContin) {
				this.working = true;
				this.update();
				
				CupMan.callService("teams.EditTeamService", {
					data: {
						regClubPostId: postId,
						teamPostId: thiz.team.id,
						categoryId: thiz.team.categoryId,
						name: name,
						promisesLodging: promisesLodging
					},
					success: function(root) {
						var suffix = parseInt(root.attr("suffix"));
						var teamPostId = parseInt(root.attr("teamPostId"));
						
						thiz.team.suffix = suffix;
						thiz.team.id = teamPostId;
						thiz.team._name = null;
						
						// Adds if not exists
						thiz.categoryBox.catEditor.registerTeam(thiz.team);
						
						thiz.editMode = false;
						thiz.exists = true;
						thiz.working = false;
						thiz.update();
						thiz.categoryBox.updateAllRows();
					}
				});
			} else {
				thiz.categoryBox.catEditor.registerTeam(thiz.team);
				thiz.editMode = false;
				thiz.exists = true;
				thiz.working = false;
				
				thiz.team.suffix = thiz.categoryBox.estimateSuffix(thiz.team.name, thiz.team.id);
				thiz.team._name = null;
				
				thiz.update();
				thiz.categoryBox.updateAllRows();
			}
		} catch (e) {
			console.log(e);
		}
	},
	
	remove: function() {
		if ( !this.exists ) {
			this.categoryBox.removeRow(this);
			this.categoryBox.updateAllRows();
		} else {
			var thisRow = this;
			
			// Changes made. Save.
			if (this.categoryBox.catEditor.saveContin) {
				
				this.working = true;
				this.update();
				
				CupMan.callService("teams.RemoveTeamService", {
					data: {
						teamPostId: thisRow.team.id
					}, 
					success: function( doc, status ){
						if ( status == 0 ) {
							thisRow.categoryBox.catEditor.removeTeam(thisRow.team.id);
							thisRow.categoryBox.updateAllRows();
						} else {
							alert("failed. status: " + status);
							// thisRow.restore();
						}
					},
					error: function( root,msg ){
						alert("failed! " + msg);
						// thisRow.restore();
					}
				});
			} else {
				thisRow.categoryBox.catEditor.removeTeam(thisRow.team.id);
				thisRow.categoryBox.updateAllRows();
			}
		}
		
	}
	
});


CatEditor.Builder = {};
CatEditor.Builder.TEMPLATES = {
	categoryBox: '<div class="category" style="background: #eef"> \
 	 	<table> \
 	 		<tr> \
 	 			<td class="categoryNameCell" style="background: #eef"><h3></h3></td> \
 	 			<td class="teamsCell" style="background: #eef"> \
 	 				<div class="teamRows" style="margin-left:10px;"> \
 						<table> \
							<tr class="addRow"> \
								<td colspan="3" align="left" valign="top"> \
									<a href="#addRow" class="addLink"></a>  \
								</td> \
							</tr> \
						</table> \
 					</div> \
 	 			</td> \
 	 		</tr> \
 	 	</table> \
 	 </div>',
 	 teamRow: ' \
		<tr> \
			<td class="nameCell" align="left" valign="top"> \
				<div class="view" style="display:inline"> \
					<span class="baseName"></span> \
					<span class="name"></span> <span></span> \
					<span class="suffix"></span> \
				</div> \
				<div class="edit" style="display:inline; margin-right:10px;"> \
					<span class="baseName"></span> \
					<input type="text" class="name" /> \
					<span class="suffix"></span> \
				</div> \
				<a class="smallLinkButton edit"></a> \
				<a class="smallLinkButton save"></a> \
				<a class="smallLink undo"></a> \
				<a class="smallLinkButton delete"></a> \
				<img class="spinner" src="http://static.cupmanager.net/images/greenSpinner.gif" style="display: none;"> \
			</td> \
			<td class="lodgingCell" align="left" valign="top"> \
				<input type="checkbox" /> \
				<label for=""></label> \
				<a href="#lodgingPromiseInfo" class="lodgingPromiseInfo">*</a> \
			</td> \
			<td class="editCell" align="left" valign="top"> \
				\
			</td> \
		</tr>'
}

////////////////////////////////
// FEW TEAMS POPUP

CatEditor.FewTeamsPopup = function()
{
	// ....
}

CatEditor.FewTeamsPopup.prototype.init = function()
{
	var el = jQuery("#categoryEditorContainer .categoryTeamsPopup");
	this.el = el;
	
	var thisPopup = this;
	
	this.el.find("input#popupNrOfTeams").change( function(){
		var nr = parseInt( jQuery(this).val() );
		if ( nr == 1 ) {
			jQuery("span.singularTeamsIn").show();
			jQuery("span.pluralTeamsIn").hide();
		} else {
			jQuery("span.singularTeamsIn").hide();
			jQuery("span.pluralTeamsIn").show();
		}
	} );
	
	jQuery(".regTeamsButton").click(function(){
		try {
	    	var categoryId = el.find("select#popupCategory").val();
	    	var count = el.find("input#popupNrOfTeams").val();
	    	var name = el.find("input#popupTeamsName").val();
	    	var editing = el.find("input.editing").val();
	    	
	    	var oldName = el.find("input.oldName").val();
	    	var oldCatId = el.find("input.oldCategoryId").val();
	    	
	    	var valid = true;
	    	valid = valid && validateField(el.find("select#popupCategory"));
	    	valid = valid && validateField(el.find("input#popupNrOfTeams"));
	    	valid = valid && validateField(el.find("input#popupTeamsName"));
	    	
	    	if ( !valid )
	    		return;
	    	
	    	if ( editing == 0 )
	    	{
	    		if (catEditor.saveContin) {
		    		var addTeam = function(categoryId, name, callback) {
		    			CupMan.callService("teams.EditTeamService", {
							data: {
								regClubPostId: postId,
								teamPostId: -1,
								categoryId: categoryId,
								name: name
							},
							success: function(root) {
								var suffix = parseInt(root.attr("suffix"));
								var teamPostId = parseInt(root.attr("teamPostId"));
								
								catEditor._addTeam(teamPostId, categoryId, name, suffix);
								
								callback();
							}
						});
		    		};
		    		
		    		var spinner = el.find(".spinner");
		    		spinner.show();
		    		
		    		var i = 0;
		    		var func = function() {
		    			if (i >= count) {
		    				spinner.hide();
		    				thisPopup.close();
		    				return;
		    			}
		    			i++;
		    			addTeam(categoryId, name, func);
		    		};
		    		func();
	    		} else {
	    			for (var i=0; i<count; i++) {
	    				catEditor._addTeam(teamSeq--, categoryId, name, false);
	    			}
	    			thisPopup.close();
	    		}
	    		
	    	} else {
	        	// catEditor.editTeamReg( oldCatId, oldName, categoryId, name, count );
	    	}
	    	
	    	
	    	//catEditor.save();
	    	//catEditor.updateCategoryEditorView();
		} catch (e) {
			console.log(e);
		}
    });
	this.el.find("a.cancel").click(function(){
		thisPopup.close();
		return false;
	});
}


CatEditor.FewTeamsPopup.prototype.close = function()
{
	jQuery.modal.close();
}

CatEditor.FewTeamsPopup.prototype.open = function(catId, name, count)
{
    if ( catId > -1 ) // Editing WILL NEVER HAPPEN
    {
    	this.el.find("input.editing").val( 1 );
        
        this.el.find("select#popupCategory").val( catId );
        this.el.find("input.oldCategoryId").val( catId );
        
        this.el.find("input#popupNrOfTeams").val( catEditor.getTeamCount(catId, name) ).change();
        this.el.find("input#popupNrOfTeams").attr("validate", "notNegative");
        this.el.find("input#popupTeamsName").val( name );
        this.el.find("input.oldName").val( name );
        
        this.updateOptionalTeamName();
         
    } else {   // Adding 
        this.el.find("input.editing").val( 0 );
        
        this.el.find("select#popupCategory").val( -1 );
        this.el.find("input#popupNrOfTeams").val( 1 );
        this.el.find("input#popupNrOfTeams").attr("validate", "positive");
        
        this.el.find("input#popupTeamsName").val( "" );
        
        this.el.find(".popupTeamsName label[for='popupTeamsName']").html( clubName );
        
        this.updateOptionalTeamName();
    }
    
    var el = this.el;
    var thisPopup = this;
    this.el.find(".fewTeamsPopupScreen").show();
    this.el.find(".manyTeamsPopupScreen").hide();
    jQuery("body").scrollTop(0,0);
    this.el.modal({close:true, persist:true, position: [30]});
}

CatEditor.FewTeamsPopup.prototype.updateOptionalTeamName = function()
{
    validateField( this.el.find(".popupTeamsNameField input") );
}


////////////////////////////////
// MANY TEAMS POPUP

CatEditor.ManyTeamsPopup = function()
{
	// ....
}

CatEditor.ManyTeamsPopup.prototype.init = function()
{
	var el = jQuery("#categoryEditorContainer .categoryTeamsPopup");
	this.el = el;
	
	var thisPopup = this;
	jQuery(".saveTeamsButton").click(function(){
		
		var spinner = el.find(".spinner");
		spinner.show();
		
		var counts = new Map(); // Map<categoryId,count>
		var catIds = new List();
		
		el.find("input.numeric").each(function() {
			var catId = parseInt(jQuery(this).attr("categoryId"));
			var count = jQuery(this).val();
			catIds.add(catId);
			counts.put(catId, count);
		});
		
		var i = 0;
		var func = function() {
			if (i >= catIds.size()) {
				spinner.hide();
				thisPopup.close();
				return;
			}
			var catId = catIds.get(i);
			var count = counts.get(catId);
			i++;
			
			catEditor.setTeamCount(catId, count, func);
		};
		func();
		
	});
	this.el.find("a.cancel").click(function(){
		thisPopup.close();
	});
}

CatEditor.ManyTeamsPopup.prototype.close = function()
{
	jQuery.modal.close();
}

CatEditor.ManyTeamsPopup.prototype.open = function()
{
	this.el.find("input.numeric").val(0).each(function() {
		var catId = parseInt(jQuery(this).attr("categoryId"));
		var count = catEditor.getTeamCount(catId);
		if ( isNaN(parseInt(count)) )
			count = "";
		jQuery(this).val( count );
	});
	
	var el = this.el;
	var thisPopup = this;
	this.el.find(".fewTeamsPopupScreen").hide();
    this.el.find(".manyTeamsPopupScreen").show();
	jQuery("body").scrollTop(0,0);
	this.el.modal({close:true, persist:true, position: [30]});
}










var categoryNames = new Map(); // id -> Name
var sortedCategoryIds = new List(); 
var fewTeamsPopup = new CatEditor.FewTeamsPopup();
var manyTeamsPopup = new CatEditor.ManyTeamsPopup();


function categoryEditor_addCategoryName(id, name, isOpen)
{
	categoryNames.put(id, {"name": name, "isOpen": isOpen});
	sortedCategoryIds.add(id);
}

jQuery(function(){
	
	fewTeamsPopup.init();
	manyTeamsPopup.init();
	
	jQuery(".manyTeamsPopupScreen input.numeric").SpinButton({min:0, max:10});
	jQuery(".fewTeamsPopupScreen input.numeric").SpinButton({min:1, max:10});
	
	jQuery("#categoryEditor .firstNotice_few").click(function() {
		//jQuery("#categoryEditor .firstNotice").hide();
		//jQuery("#categoryEditor .addMoreTeams_few").show();
		
		fewTeamsPopup.open(-1, "", 0);
	});
	
	jQuery("#categoryEditor .firstNotice_many").click(function() {
		//jQuery("#categoryEditor .firstNotice").hide();
		//jQuery("#categoryEditor .addMoreTeams_many").show();
		
		manyTeamsPopup.open();
	});
	
	jQuery("#categoryEditor .addMoreTeams_few a").click(function() {
		fewTeamsPopup.open(-1, "", 0);
	});
	jQuery("#categoryEditor .addMoreTeams_many a").click(function() {
		manyTeamsPopup.open();
	});
	
}); 





function RegTask( name, func )
{
	this.name = name;
	this.func = func;
}

function RegProcess( regTasks )
{
	this.regTasks = regTasks;
	this.curTaskIndex = -1;
}
RegProcess.prototype.buildList = function()
{
	for ( var i=0; i<this.regTasks.size(); i++ )
    {
        var regTask = this.regTasks.get(i);
        
        var li = jQuery(".regTasks ul").append("<li></li>").find("li:last");
        li.html( "<span>"+regTask.name+"</span>" );
    }
}

RegProcess.prototype.next = function()
{
	if ( this.curTaskIndex == -1 )
	{
		jQuery(".regTasks ul").fadeIn(500);
		jQuery("a#confirmLink").addClass("clicked").removeAttr("href");
		jQuery("a#confirmLink img").css("opacity", 0.5);
	}
	if ( this.curTaskIndex >= 0 )
	{
        jQuery(".regTasks ul li").eq( this.curTaskIndex ).removeClass("working").addClass("complete");
	}
    
    this.curTaskIndex++;
    if ( this.curTaskIndex >= this.regTasks.size() )
       return;
    
    var li = jQuery(".regTasks ul li").eq( this.curTaskIndex );
    li.removeClass();
    li.addClass("working");
    
    this.regTasks.get( this.curTaskIndex ).func( this, li );
}

RegProcess.prototype.fail = function( msg )
{
	var li = jQuery(".regTasks ul li").eq( this.curTaskIndex );
	li.removeClass("working");
	li.addClass("fail");
	
	alert("There was an error during your registration, it has NOT been registered. Please try again.");
	window.location.reload();
}
function RegSummary( name )
{
	this.name = name;
}
// init() and refresh()


function setSummaryTileError( el, msg )
{
	el.addClass("error");
	var status = el.parent().find(".status").addClass("statusBad");
	status.show();
	status.find(".msg").html( msg );
}
function clearSummaryTileError(el)
{
	el.removeClass("error");
	var status = el.parent().find(".status").removeClass("statusBad");
	status.hide();
	status.find(".msg").html( "" );
}

function RegSummaries()
{
	this.curIndex = -1;
	this.summaries = new List();
}
RegSummaries.prototype.add = function(summary) {
	this.summaries.add( summary );
}
RegSummaries.prototype.init = function() {
	for ( var i=0; i<this.summaries.size(); i++)
	{
		var summary = this.summaries.get(i);
		summary.init( summary );
	}
}

RegSummaries.prototype.refresh = function() {
	for ( var i=0; i<this.summaries.size(); i++)
	{
		var summary = this.summaries.get(i);
		summary.refresh();
	}
}
if ( typeof CupMan == "undefined" ) {
	CupMan = {};
}

CupMan.Event = function(retroactive) {
	this.retroactive = !!retroactive;
	this.fired = false;
	this.subscribers = new List();
}

CupMan.Event.prototype.subscribe = function( func ) {
	this.subscribers.add( func );
	if ( this.fired && this.retroactive ) {
		func(null);
	}
}

CupMan.Event.prototype.fire = function(a,b,c,d,e,f,g,h) {
	this.fired = true;
	var response = true;
	
	for ( var i=0; i<this.subscribers.size(); i++ ) {
		var func = this.subscribers.get(i);
		var res = func(a,b,c,d,e,f,g,h);
		if (res === false) {
			response = false;
		}
	}
	
	return response;
}
if ( typeof CupMan == "undefined" ) {
	CupMan = {};
}

var glow_suffix = "glow";
var selected_suffix = "glow";
var disabled_suffix = "gray";


CupMan.Map = function(el)
{
	this.loadEvent = new CupMan.Event(true);
	this.clickEvent = new CupMan.Event(false);
	this.hoverEvent = new CupMan.Event(false);
	
	
	// Back-compatible
	this.clickEvent.subscribe(function(marker){
		if (typeof markerClicked != "undefined") {
			markerClicked(marker);
		}
	});
	
	
	this.typeMarkers = new Map(); // type -> markers
	this.markers = new Map();	   // id -> marker
	this.bounds = new GLatLngBounds();
	var map = this.map = new GMap2( el.get(0) );
	
	map.setCenter( new GLatLng(0,0), 6 );
	map.enableScrollWheelZoom();
	map.enableContinuousZoom();
	map.addControl(new FancyMapControl());
}

CupMan.Map.prototype.hideMarkers = function(type)
{
	this.bounds = new GLatLngBounds();
	var ids = this.markers.keys();
	for (var i=0; i<ids.length; i++)
	{
		var id = ids[i];
		var marker = this.markers.get(id);
		
		if (marker.type == type && marker.visible)
		{
			marker.visible = false;
			this.map.removeOverlay(marker);
		}
		
		if (marker.visible)
		{
			this.bounds.extend(marker.getLatLng());
		}
	}
	return this;
}
CupMan.Map.prototype.showMarkers = function(type)
{
	this.bounds = new GLatLngBounds();
	var ids = this.markers.keys();
	for (var i=0; i<ids.length; i++)
	{
		var id = ids[i];
		var marker = this.markers.get(id);
		
		if (marker.type == type && !marker.visible)
		{
			marker.visible = true;
			this.map.addOverlay(marker);
		}
		
		if (marker.visible)
		{
			this.bounds.extend(marker.getLatLng());
		}
	}
	
	return this;
}

CupMan.Map.prototype.addMarker = function(id, title, type, lat, lng)
{
	var point = new GLatLng(lat,lng);
	this.bounds.extend(point);
	
	var parentType = type;
	if (type.indexOf("/") > -1) {
		parentType = type.substr(0, type.indexOf("/"));
	}
	
	var icon = CupMan.Map.getIconForType(parentType);
	var gIcon = CupMan.Map.getIcon(icon);
	var marker = new GMarker(point, { title: title, icon: gIcon });
	
	if ( !this.typeMarkers.containsKey(type) ) {
		this.typeMarkers.put(type, new List());
	}
	this.typeMarkers.get(type).add(marker);
	this.markers.put(id, marker);
	
	marker.iconId = icon;
	marker.type = type;
	marker.parentType = parentType;
	marker.title = title;
	marker.isEnabled = true;
	marker.visible = true;
	marker.id = id;
	
	var thisMap = this;
	
	GEvent.addListener(marker,"mouseover", function() {
		if( this && this.isEnabled ) {
			this.setImage( CupMan.Map.getIconUrl(this.iconId, true) );
			
			thisMap.hoverEvent.fire(this, "in");
		}
	});
	
	GEvent.addListener(marker,"mouseout", function() {
		if( this && this.isEnabled ) {
			if( this.isSelected ) {
				this.setImage("http://maps.cupmanager.net/map_icons/"+this.iconId+"_"+selected_suffix+".png");
			} else {
				this.setImage( CupMan.Map.getIconUrl(this.iconId, false) );
			}
			
			thisMap.hoverEvent.fire(this, "out");
		}
	});
	
	GEvent.addListener(marker,"click", function() {
		if( this && this.isEnabled ){
			thisMap.clickEvent.fire(this);
		}
	});
	
	this.map.addOverlay(marker);
	
	return marker;
}

CupMan.Map.prototype.glowMarker = function(marker) {
	marker.setImage( CupMan.Map.getIconUrl(marker.iconId, true) );
}
CupMan.Map.prototype.unGlowMarker = function(marker) {
	marker.setImage( CupMan.Map.getIconUrl(marker.iconId, false) );
}

CupMan.Map.prototype.fit = function()
{
	var zoom = this.map.getBoundsZoomLevel(this.bounds);
	this.map.setCenter(this.bounds.getCenter(), Math.min(Math.max(zoom-1,1), 13));
	
	return this;
}

CupMan.Map.prototype.setZoom = function(level) {
	this.map.setZoom(level);
}

CupMan.Map.prototype.done = function()
{
	this.loadEvent.fire(this);
}

CupMan.Map.getIconForType = function(type) 
{
	var icon = "simple";
	
	if ( type == "Lodging" )
		icon = "lodging";
	
	if ( type == "Arena" )
		icon = "sport";
	
	if ( type == "Food" )
		icon = "lodgingfood";
	
	if ( type == "Restaurant" )
		icon = "food";
	
	if ( type == "Other" )
		icon = "regular";
	
	if ( type == "Miscellaneous" )
		icon = "regular";
	
	if ( type == "Cup" )
		icon = "";
		
	if ( type == "Club" )
		icon = "home";
	
	return icon;
}

CupMan.Map.getIcon = function(iconId){
	var icon = new GIcon();
	
	icon.image = CupMan.Map.getIconUrl(iconId);
	// icon.shadow = "/images/mapicons/shadow_marker.png";
	
	//icon.image = "http://maps.cupmanager.net/map_icons/"+iconId+".png";
	//icon.shadow = "http://maps.cupmanager.net/map_icons/"+iconId+"_shadow.png";
	
	//icon.iconSize = new GSize(32.0, 32.0);
	//icon.shadowSize = new GSize(49.0, 32.0);
	//icon.iconAnchor = new GPoint(15.0, 32.0);
	//icon.infoWindowAnchor = new GPoint(16.0, 16.0);
	
	//icon.iconSize = new GSize(21.0, 34.0);
	//icon.shadowSize = new GSize(40.0, 37.0);
	//icon.iconAnchor = new GPoint(10.0, 34.0);
	//icon.infoWindowAnchor = new GPoint(16.0, 16.0);
	
	icon.iconSize = new GSize(32.0, 37.0);
	icon.shadowSize = new GSize(40.0, 37.0);
	if (iconId == "lodging")
		icon.iconAnchor = new GPoint(16.0, 3.0);
	else
		icon.iconAnchor = new GPoint(16.0, 34.0);
	
	icon.infoWindowAnchor = new GPoint(16.0, 16.0);
	
	return icon;
}


CupMan.Map.getIconUrl = function(iconType, glow) {
	if (glow) {
		return imageBaseUrl+"mapicons/"+iconType+"_marker_glow.png";
	} else {
		return imageBaseUrl+"mapicons/"+iconType+"_marker.png";
	}
}