﻿

/* Create support to handle namespaces and superclasses. */
/* Build the c9 namespace. */
var c9 = {
    extend: function(bc, sc, o) {
        var f = function() {};
        f.prototype = sc.prototype;
        bc.prototype = new f();
        bc.prototype.constructor = bc;
        bc.superclass = sc.prototype;
        for (var m in o)
            bc.prototype[m] = o[m];
    }
};

/* Build the namespace for the page class. */
c9.page = function() {

	/* Creates the namespace/class. */
	c9.page.superclass.init.apply(this, arguments);
	/* Calls the class initializer */
	this.initialize();
	
};

/* Extend jQuery with the page class. */
c9.extend(c9.page, jQuery, {

	/* Initialize the class. */
	initialize: function () {
		/* Initialize the page events */
		this.initEvents();
		/* Observe the links, ie with REL's. */
		this.observeLinks();
		/* Initialize observer for the search-input. */
		this.observeSearch();
		/* Initialize observer for the newsletter-input. */
		this.observeNewsletter();
		/* Initialize observer for the FAQ. */
		this.observeFAQ();
		/* Initialize the various tablesorters. */
		this.initTableSorter();
		/* Initialize the map */
		this.initMap();
		/* Initialize the page events */
		this.initAnalytics();


		/* Start the startpage posterslider-interval. */
		if ($('.imagewrapper .images').length > 0)
			window.posterSlide = setInterval(function () { c9.page.slidePoster($('.imagewrapper .images')); }, 6000);

		this.initCasePosters();
	},


	/* 
	function: c9.page.initEvents()
	Initializes the page events - no inline events on this site!
	*/
	initEvents: function () {
		/* Handles the onmouseovers for the sorttables-headings. */
		$('table th.when, table th.what, table th.where').mouseover(function (sender) { c9.util.getCursor(sender.currentTarget); });

		/* Handles the expandable link in the booking form. */
		$('.form .wrapper .group a').mouseover(function (sender) { c9.util.getCursor(sender.currentTarget); });
		$('.form .wrapper .group a').click(function () { c9.page.toggleFormExtras(); });

		/* Handles the validation of the submit button in all .forms */
		$('.form .wrapper .submit a').click(function (sender) { return c9.page.validateForm(sender.currentTarget); });

		/* Handles the images in the artists slideshows. */
		$('#slideshow .image').mouseover(function (sender) { c9.util.getCursor(sender.currentTarget); });
		$('#slideshow .image').click(function () { $('#slideShowNext').click(); });

		/* Handles the buttons in the artists slideshows. */
		$('#slideshow #pager #slideShowLast').click(function (sender) { c9.page.slideImage(sender.currentTarget, 'left'); });
		$('#slideshow #pager #slideShowNext').click(function (sender) { c9.page.slideImage(sender.currentTarget, 'right'); });

		/* Handles all inputs and selects on the site (focus/blur effects) */
		$('input, select').focus(function (sender) { $(sender.currentTarget).css("color", "black"); });
		$('input, select').blur(function (sender) { $(sender.currentTarget).css("color", "#989898"); });

		/* Handles the submission of the  */
		$('#searchbutton').click(function () { if ($('#searchinput').val() != $('#searchinput').attr('title')) { document.location.href = '/sokresultat.aspx?search=' + $('#searchinput').val(); return false; } else { return false; } });

		/* Handle the startpage posterslider. */
		$('.imagewrapper .images').mouseover(function (sender) { c9.util.getCursor(sender.currentTarget); });
		$('.imagewrapper .dots').children().each(function (i) { $(this).click(function () { clearInterval(posterSlide); this.blur(); c9.page.slidePoster($('.imagewrapper .images'), i); }); });

		/* Handles the filter functionality for the Book Artist list */
		$('.bookartistlist input:checkbox').attr('checked', 'checked');
		$('.bookartistlist input:checkbox').click(function () { c9.page.filterBookArtistList(this); });

		$('.bookingcaseslideshow .dots').children().each(function (i) { $(this).click(function () { clearInterval(caseSwitcher); this.blur(); c9.page.switchCasePosters(i + 1); }); });
	},

	filterBookArtistList: function (sender) {
		var filterList = '',
            numberOfAnchorsInTwo = 0;

		$('.selection > label > span:first-child').addClass('not');
		$(sender).closest('.selection').find('input:checkbox:checked').each(function (index) {
			filterList += ((index === 0) ? '' : ',') + $(this).val();
			$(this).next('label').find('span:first-child').removeClass('not');
		});

		if (filterList.length > 0) {
			filterList = filterList.split(',');

			$('.bookartistlist .artistlist.boxed a').each(function () {
				$(this).addClass('hidden');
				for (var i = 0; i < filterList.length; i++) {
					if ($(this).attr('rel').indexOf(filterList[i]) > -1) {
						$(this).removeClass('hidden');
						continue;
					}
				}
			});
			numberOfAnchorsInTwo = $('.bookartistlist .artistlist.boxed a:not(.hidden)').length / 2;
		} else {
			$('.bookartistlist .artistlist.boxed a').addClass('hidden');
		}

		if (numberOfAnchorsInTwo > 0) {
			$('.bookartistlist .empty').addClass('hidden');
			$('.bookartistlist .artistlist.boxed a:not(.hidden)').sortElements(function (a, b) {
				return $(a).text() > $(b).text() ? 1 : -1;
			});

			$('.bookartistlist .artistlist.boxed a:not(.hidden)').each(function (index) {
				if (index < numberOfAnchorsInTwo) {
					$(this).appendTo($('.bookartistlist .artistlist.boxed #wrapper > div:first-child'));
				} else {
					$(this).appendTo($('.bookartistlist .artistlist.boxed #wrapper > div:first-child + div'));
				}
			});
		} else {
			$('.bookartistlist .empty').removeClass('hidden');
		}
	},

	/* 
	function: c9.page.initAnalytics()
	Initializes Google Map if there is a #map-div on the page.
	*/
	initAnalytics: function () {

	},

	/* 
	function: c9.page.initMap()
	Initializes Google Map if there is a #map-div on the page.
	*/
	initMap: function () {


		/* Check if the #map-div exists. */
		if ($('#map').length > 0) {



			var latitude = $('#hfLatitude').val();
			var longitude = $('#hfLongitude').val();
			var zoom = ($('#hfZoom').val().length > 0 ? $('#hfZoom').val() : 12);

			if (latitude.length > 0) {
				if (longitude.length > 0) {

					/* Check if the browser is compatible. */
					if (typeof window.GBrowserIsCompatible != 'undefined') {
						if (window.GBrowserIsCompatible()) {

							/* Declare the map variable and initiate it. */
							var map = new window.GMap2(document.getElementById('map'));

							/* Add the large map control. */
							map.addControl(new window.GLargeMapControl());
							/* Add the Map Type Control. */
							map.addControl(new window.GMapTypeControl());

							/* Declare the arena as a LatLng. */
							var arena = new window.GLatLng(parseFloat(latitude), parseFloat(longitude));
							/* Add a marker as overlay. */
							map.addOverlay(new window.GMarker(arena));

							/* Make the mapwrapper visible. */
							$('#mapwrapper').removeClass('invisible');
							/* Make the map visible. */
							$('#map').removeClass('invisible');
							/* Center the map on the arena with the fetched zoom level. */
							map.setCenter(arena, parseFloat(zoom));

						}
					}
				}
			}
			else {
				/* Remove the #mapwrapper from the page. */
				$('#mapwrapper').remove();
				/* Remove the #map from the page. */
				$('#map').remove();
			}

		}
	},


	/* 
	function: c9.page.initTableSorter()
	Initializes the various tablesorters on the site. 
	Every table with sort functionality gets their settings here.
	*/
	initTableSorter: function () {
		/* Extend the tablesorter. */
		this.extendTableSorter();
		/* Check if any table.modulegigs exists on the page. */
		if ($("table.modulegigs"))
		/* Make the table sortable with the tablesorter-function found in /scripts/jquery.tablesorter.min.js. */
			$("table.modulegigs").tablesorter({
				/* Make the first column sortable by the extension 'dates', the third should not be sortable. */
				headers: { 0: { sorter: 'dates' }, 2: { sorter: false }, 3: { sorter: false} },
				/* Attach the zebra-widget to make the table css-classes odd/even. */
				/* This will be depricated later on. */
				widgets: ['zebra'],
				/* Hook the tableSorterTextExtraction to the contents of the table-datas. */
				textExtraction: this.tableSorterTextExtraction,
				/* Make sure the list is sorted by ascending dates by default. */
				sortList: [[0, 0]]
			});
		/* Check if any table.modulegenregigs exists on the page. */
		if ($("table.modulegenregigs"))
		/* Make the table sortable with the tablesorter-function found in /scripts/jquery.tablesorter.min.js. */
			$("table.modulegenregigs").tablesorter({
				/* Make the first column sortable by the extension 'dates', the fourth should not be sortable. */
				headers: { 0: { sorter: 'dates' }, 3: { sorter: false }, 4: { sorter: false} },
				/* Attach the zebra-widget to make the table css-classes odd/even. */
				/* This will be depricated later on. */
				widgets: ['zebra'],
				/* Hook the tableSorterTextExtraction to the contents of the table-datas. */
				textExtraction: this.tableSorterTextExtraction,
				/* Make sure the list is sorted by ascending dates by default. */
				sortList: [[0, 0]]
			});
		/* Check if any table.startgigs exists on the page. */
		if ($("table.startgigs"))
		/* Make the table sortable with the tablesorter-function found in /scripts/jquery.tablesorter.min.js. */
			$("table.startgigs").tablesorter({
				/* Make the first column sortable by the extension 'dates', the fourth should not be sortable. */
				headers: { 0: { sorter: 'dates' }, 3: { sorter: false }, 4: { sorter: false} },
				/* Attach the zebra-widget to make the table css-classes odd/even. */
				/* This will be depricated later on. */
				widgets: ['zebra'],
				/* Hook the tableSorterTextExtraction to the contents of the table-datas. */
				textExtraction: this.tableSorterTextExtraction,
				/* Make sure the list is sorted by ascending dates by default. */
				sortList: [[0, 0]]
			});
	},

	/* 
	function: c9.page.extendTableSorter()
	Extends the tablesorter(), prepares dates and handles innerHTML-data to get a wider range of sortable data.
	*/
	extendTableSorter: function () {

		/* Parser used to handle ShortDates with three-letter-months */
		/* This parser is not multilingual! See 'var m=[,,,]' below... */
		$.tablesorter.addParser({
			/* set a unique id */
			id: 'dates',
			is: function () {
				/* return false so this parser is not auto detected */
				return false;
			},
			format: function (s) {
				/* split the string */
				var a = s.split(' ');
				/* get month number */
				a[1] = this.getMonth(a[1]);
				/* glue and return as a new date */
				return new Date(a.reverse().join("/")).getTime();
			},
			getMonth: function (s) {
				/* Array of the dates, this solution is not multilingual! */
				var m = ['jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'];
				/* Set the length of the array - usually it's twelve. Duh! */
				var l = m.length;
				/* Itterate through the array */
				for (var i = 0; i < l; i++) {
					/* Check whether the month name and array item matches */
					if (m[i] == s.toLowerCase()) {
						/* Return the number of the matched month */
						return (i + 1);
					}
				}
				return 0;
			},
			/* set type, either numeric or text */
			type: 'numeric'
		});

		/* Handle data with childnodes. */
		/* Primary used with the date-columns in the gig-lists. */
		this.tableSorterTextExtraction = function (node) {
			/* Build the return string. */
			/* If there's one child node, strip the HTML from it. */
			var r = ((typeof node.childNodes[0] != 'undefined') ? node.childNodes[0].innerHTML : node.innerHTML);
			/* Repeat if there's a second child and append it to the return string. */
			r += ' ' + ((typeof node.childNodes[1] != 'undefined') ? node.childNodes[1].innerHTML : '');
			/* Repeat if there's a third child and append it to the return string. */
			r += ' ' + ((typeof node.childNodes[2] != 'undefined') ? node.childNodes[2].innerHTML : '');

			/* Send the return string back. */
			return r;
		};
	},

	/*
	function: c9.page.observeLinks()
	Hadles the a-links, 
	*/
	observeLinks: function () {
		$('a').click(function () {
			if ($(this).attr('rel') == 'external') {
				window.open($(this).attr('href'));
				return false;
			}
			return true;
		});
	},

	/* 
	function: c9.page.observeSearch()
	Handles the focus/blur events on #searchinput, also listens to ENTER-submission
	*/
	observeSearch: function () {
		/* Check if the #searchinput actually exisits in the page. */
		if ($('#searchinput')) {
			/* Populate the example-function found in /scripts/jquery.example.min.js */
			$('#searchinput').example(function () {
				/* Return the title-attribute fron the HTML. */
				return $(this).attr('title');
			});
			/* Observe the keypresses while typing. */
			$('#searchinput').keypress(function (e) {
				/* Check if the pressed key is ENTER. */
				if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
					/* Click the submit-button to post the form. */
					$('#searchbutton').click();
					/* Disallow the keypress. */
					return false;
				} else {
					/* Allow the keypress. */
					return true;
				}
			});
		}
	},

	/* 
	function: c9.page.observeFAQ()
	Handles the click/mouseover events in the '.faqlisting' lists.
	*/
	observeFAQ: function () {
		/* Check if '.faqlisting li.faqitem' exist in page. */
		if ($('.faqlisting li.faqitem')) {
			/* Observe the click-event on all links. */
			$('.faqlisting li.faqitem a').click(function () {
				/* Show/hide all siblings to the anchor. */
				$(this).siblings().toggleClass("hidden");
				/* Blur the anchor. */
				$(this).blur();
			});
			/* Observe the mouseover-event on all links. */
			$('.faqlisting li.faqitem a').mouseover(function () {
				/* Get a crossbrowser cursor. */
				c9.util.getCursor(this);
			});
		}
	},

	/* 
	function: c9.page.observeNewsletter()
	Handles the focus/blur events on #newslettersignupinput, also listens to ENTER-submission
	*/
	observeNewsletter: function () {
		/* Check if any .newslettersignupinput actually exisits in the page. */
		if ($('.newslettersignupinput')) {
			/* Populate the example-function found in /scripts/jquery.example.min.js */
			$('.newslettersignupinput').example(function () {
				/* Return the title-attribute fron the HTML. */
				return $(this).attr('title');
			});
			/* Observe the keypresses while typing. */
			$('.newslettersignupinput').keypress(function (e) {
				/* Check if the pressed key is ENTER. */
				if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
					/* Click the submit-button to post the form. */
					document.location.href = $('.newslettersignupbutton').attr('href');
					/* Disallow the keypress. */
					return false;
				} else {
					/* Allow the keypress. */
					return true;
				}
			});
		}
	},

	/* Used to keep track of which image thats visible ATM. */
	slideImageNumber: 1,

	/*
	function: c9.page.slideImage()
	param: sender = the element that executes the event
	param: direction = string to determine the direction of the slide. 
	Changes the image to the next/previous in a slideshow. 
	*/
	slideImage: function (sender, direction) {

		/* Blur the sender-element. */
		sender.blur();

		/* Make 'this' accessible from within nestled functions. */
		var that = this;
		/* Get the total count of the image (div) array */
		var imageCount = $(sender).parent('#pager').siblings().length;

		/* Itterate through the image (div) array */
		$(sender).parent('#pager').siblings().each(function () {

			/* Make sure that the current div aint hidden - to find the active one. */
			if (!$(this).hasClass('hidden')) {

				/* Handle the directions. */
				switch (direction) {
					/* If the direction is 'left'. */ 
					case 'left':
						/* Make sure the previous element exists. */
						if ($(this).prev().hasClass('imagewrapper')) {
							/* Remove the hidden-css-class. */
							$(this).prev().toggleClass('hidden');
							/* Update the c9.page.slideImageNumber by subtracting one. */
							that.slideImageNumber = that.slideImageNumber - 1;
						}
						/* If the previous element doesn't exist... */
						else {
							/* Remove the hidden-css-class of the last element in the array. */
							$(sender).parent('#pager').siblings(':last').toggleClass('hidden');
							/* Since the active element is the last one, set c9.page.slideImageNumber to the arrays length (+1) */
							that.slideImageNumber = imageCount;
						}
						/* Break the case. */
						break;

					/* If the direction is 'right'. */ 
					case 'right':
						/* Make sure the next element exists. */
						if ($(this).next().hasClass('imagewrapper')) {
							/* Remove the hidden-css-class. */
							$(this).next().toggleClass('hidden');
							/* Update the c9.page.slideImageNumber by adding one. */
							that.slideImageNumber = that.slideImageNumber + 1;
						}
						/* If the next element doesn't exist... */
						else {
							/* Remove the hidden-css-class of the first element in the array. */
							$(sender).parent('#pager').siblings(':first').toggleClass('hidden');
							/* Since the active element is the first one, set c9.page.slideImageNumber to 1 */
							that.slideImageNumber = 1;
						}
						/* Break the case. */
						break;
				}

				/* Hide the current (past) div. */
				$(this).toggleClass('hidden');

				/* Break the each-itteration. */
				return false;
			}
			return true;
		});

		/* Update the pager-element. */
		$(sender).siblings('span').html(this.slideImageNumber + '/' + imageCount);

	},

	/* Used to remember the last left-position in the startpage posterslider*/
	nLeft: 0,


	/*
	function: c9.page.slidePoster()
	param: sender = the element that executes the event
	param: number = the number of the element that should be selected.
	Changes the image to the next/previous in the startpage posterslider. 
	*/
	slidePoster: function (sender, number) {

		var imageCount = $(sender).children().length, /* Get the total count of the image (div) array */
            addon = 300, /* Extra addon to the calculation, needed to get crossbrowser functionality. */
            dDot,
            dTape;

		/* The slider should move to a set position. */
		if (typeof number != 'undefined') {

			/* Calculate the nLeft variable. */
			this.nLeft = ($(sender).scrollLeft() + $(sender).children(0).outerWidth()) * (number);

			/* Fetch the active dot. */
			dDot = $(sender).siblings().children('.active');
			/* Fetch the active tape. */
			dTape = $(sender).parent().siblings().children('.active');

			/* Inactivate the current dot. */
			dDot.removeClass('active');
			/* Inactivate the current tape. */
			dTape.removeClass('active');

			/* The set position isn't the last one. */
			if (number != imageCount) {
				/* Execute the right-to-left-animation */
				$(sender).animate({ left: -this.nLeft + 'px' }, 1000);
				$(sender).siblings().children(':eq(' + number + ')').addClass('active');
				$(sender).parent().siblings().children(':eq(' + number + ')').addClass('active');
			}
			else {
				/* Execute the left-to-right-animation */
				$(sender).animate({ left: '0px' }, 500);
				/* Activate the first dot. */
				$(sender).siblings().children(':first').addClass('active');
				/* Activate the first tape. */
				$(sender).parent().siblings().children(':first').addClass('active');
			}

		}
		else {

			/* Repopulate the nLeft variable based on the coming left position */
			this.nLeft = $(sender).scrollLeft() + $(sender).children(0).outerWidth() + this.nLeft;

			/* Fetch the active dot. */
			dDot = $(sender).siblings().children('.active');
			/* Fetch the active tape. */
			dTape = $(sender).parent().siblings().children('.active');

			/* Check that the new nLeft-value is lower then the full width of the wrapper. */
			if (this.nLeft + addon < $(sender).outerWidth()) {
				/* Execute the right-to-left-animation */
				$(sender).animate({ left: -this.nLeft + 'px' }, 1000);
				/* Inactivate the current dot. */
				dDot.removeClass('active');
				/* Inactivate the current tape. */
				dTape.removeClass('active');
				/* Activate the next dot. */
				dDot.next().addClass('active');
				/* Activate the next tape. */
				dTape.next().addClass('active');
			}
			else {
				/* Execute the left-to-right-animation */
				$(sender).animate({ left: '0px' }, 1000);
				/* Inactivate the current dot. */
				dDot.removeClass('active');
				/* Inactivate the current tape. */
				dTape.removeClass('active');
				/* Activate the first dot. */
				$(sender).siblings().children(':first').addClass('active');
				/* Activate the first tape. */
				$(sender).parent().siblings().children(':first').addClass('active');
				/* Reset the nLeft. */
				this.nLeft = 0;
			}
		}

		/* Return and halt. */
		return false;
	},

	initCasePosters: function () {
		var that = this;

		$('#framework #contents .bookingcaseslideshow .big ul li:last-child a > span:first-child + span').css('display', 'block');

		this.switchCasePosters();

		$('.bookingcaseslideshow').mouseover(function () {
			clearInterval(window.caseSwitcher);
		}).mouseout(function () {
			that.switchCasePosters();
		});

		if ($.browser.msie && $.browser.version < 8) {
			$('#framework #contents .bookingcaseslideshow ul li *').css('cursor', 'pointer');
			$('#framework #contents .bookingcaseslideshow ul li *').click(function (e) {
				e.preventDefault();
				e.stopPropagation();
				document.location.href = $(this).closest('li').find('a').attr('href');
			});
			$('#framework #contents .bookingcaselinks ul li *').css('cursor', 'pointer');
			$('#framework #contents .bookingcaselinks ul li *').click(function (e) {
				e.preventDefault();
				e.stopPropagation();
				document.location.href = $(this).closest('li').find('a').attr('href');
			});
		}
	},

	switchCasePosters: function (index) {
		if ($('.bookingcaseslideshow .big ul li').length) {
			if (typeof index === 'number') {
				// TODO: Make theese clicks animated!
				for (var i = 0; i < $('.bookingcaseslideshow ul li').length; i++) {
					if ($('.bookingcaseslideshow .big ul li.item_' + index).attr('class') !== $('.bookingcaseslideshow ul li:last').attr('class')) {
						c9.page.doSwitch(0);
						clearInterval(window.caseSwitcher);
					}
				}
			} else {
				if ($('.bookingcaseslideshow ul li').length > 1) {
					window.caseSwitcher = setInterval(function () {
						c9.page.doSwitch(500);
					}, 5000);
				}
			}
		}
	},

	doSwitch: function (speed) {
		var itemListBig = $('.bookingcaseslideshow .big ul'),
			itemLastBig = $('.bookingcaseslideshow .big ul li:last'),
			itemListSmall = $('.bookingcaseslideshow .small ul'),
			itemFirstSmall = $('.bookingcaseslideshow .small ul li:first');

		$('.bookingcaseslideshow .dots a').removeClass('active');
		$('.bookingcaseslideshow .big a > span:first-child + span').hide();

		var index = $('.bookingcaseslideshow .small ul li:first').attr('class').split(' ')[0].split('_')[1];

		setTimeout(function () {
			$('.bookingcaseslideshow .big ul li.item_' + index + ' a > span:first-child + span').css('display', 'block');
		}, 200);

		itemLastBig.animate({
			opacity: 0
		}, speed, function () {
			itemLastBig.prependTo(itemListBig).css({ opacity: 1 });
			if ($.browser.msie && $.browser.version < 8) {
				itemLastBig.css('opacity', '');
			}
			$('.bookingcaseslideshow .dots a:nth-child(' + index + ')').addClass('active');
		});

		itemListSmall.animate({
			left: '-177px'
		}, speed / 2, function () {
			itemFirstSmall.appendTo(itemListSmall);
			itemListSmall.css('left', 0);
		});
	},

	/* 
	function: c9.page.validateForm()
	param: sender = the anchor that triggers the filter
	Returns true if all validation is OK.
	A generic form validator. Triggered onclick on the submit buttons and hooked on all elements with matched css-classes.	
	
	This function could be rewritten in a more generic way!
	*/
	validateForm: function (sender) {
		/* Declare the return variable. */
		var r = true;
		/* Declare and populate a regexp used to validate e-mail addresses*/
		var reEmail = new RegExp(/^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/);
		/* Declare and populate a regexp used to validate numeric values*/
		var reNumeric = new RegExp(/^-?[0-9]+$/);
		/* Declare and populate a regexp used to validate swedish postal numbers, 'nn nnn' */
		var rePostal = new RegExp(/^\d{3} \d{2}$/);

		/* Check if any elements exists with the class 'valtext'. */
		/* Used to check that the elements value is'nt empty. */
		if ($('.valtext')) {
			/* Itterate through all matched elements. */
			$('.valtext').each(function () {
				/* Check that the value is'nt empty. */
				if ($(this).val().length == 0) {
					/* Add the 'error' class to the element. */
					$(this).addClass('error');
					/* Add the 'error' class to all siblings */
					$(this).siblings().addClass('error');
					/* Set the return variable to false. */
					r = false;
				}
				else {
					/* Remove the 'error' class to the element. */
					$(this).removeClass('error');
					/* Remove the 'error' class to all siblings */
					$(this).siblings().removeClass('error');
				}
			});
		}
		/* Check if any elements exists with the class 'valemail'. */
		/* Used to check that the elements value is'nt empty and is a valid e-mail address. */
		if ($('.valemail')) {
			/* Itterate through all matched elements. */
			$('.valemail').each(function () {
				/* Match the elements value with the reEmail regexp. */
				if (!$(this).val().match(reEmail)) {
					/* Add the 'error' class to the element. */
					$(this).addClass('error');
					/* Add the 'error' class to all siblings */
					$(this).siblings().addClass('error');
					/* Set the return variable to false. */
					r = false;
				}
				else {
					/* Remove the 'error' class to the element. */
					$(this).removeClass('error');
					/* Remove the 'error' class to all siblings */
					$(this).siblings().removeClass('error');
				}
			});
		}

		/* Check if any elements exists with the class 'valnumericoptional'. */
		/* Used to check that the elements value is a numeric value. This form element is optional */
		if ($('.valnumericoptional')) {
			/* Itterate through all matched elements. */
			$('.valnumericoptional').each(function () {
				/* Check if the element has any value*/
				if ($(this).val().length > 0) {
					/* Match the elements value with the reEmail regexp. */
					if (!$(this).val().match(reNumeric)) {
						/* Add the 'error' class to the element. */
						$(this).addClass('error');
						/* Add the 'error' class to all siblings */
						$(this).siblings().addClass('error');
						/* Set the return variable to false. */
						r = false;
					}
					else {
						/* Remove the 'error' class to the element. */
						$(this).removeClass('error');
						/* Remove the 'error' class to all siblings */
						$(this).siblings().removeClass('error');
					}
				}
				else {
					/* Remove the 'error' class to the element. */
					$(this).removeClass('error');
					/* Remove the 'error' class to all siblings */
					$(this).siblings().removeClass('error');
				}
			});
		}

		/* Check if any elements exists with the class 'valpostaloptional'. */
		/* Used to check that the elements value is a numeric value, with or without space. This form element is optional */
		if ($('.valpostaloptional')) {
			/* Itterate through all matched elements. */
			$('.valpostaloptional').each(function () {
				/* Check if the element has any value*/
				if ($(this).val().length > 0) {
					if ($(this).val().length == 5)
						$(this).val($(this).val().substring(0, 3) + ' ' + $(this).val().substring(3, 5));

					/* Match the elements value with the reEmail regexp. */
					if (!$(this).val().match(rePostal)) {
						/* Add the 'error' class to the element. */
						$(this).addClass('error');
						/* Add the 'error' class to all siblings */
						$(this).siblings().addClass('error');
						/* Set the return variable to false. */
						r = false;
					}
					else {
						/* Remove the 'error' class to the element. */
						$(this).removeClass('error');
						/* Remove the 'error' class to all siblings */
						$(this).siblings().removeClass('error');
					}
				}
				else {
					/* Remove the 'error' class to the element. */
					$(this).removeClass('error');
					/* Remove the 'error' class to all siblings */
					$(this).siblings().removeClass('error');
				}
			});
		}

		/* Check if any elements exists with the class 'valselect'. */
		/* Used to check that the selected value is'nt empty. */
		if ($('.valselect')) {
			/* Itterate through all matched elements. */
			$('.valselect').each(function () {
				/* Check that the selected value is'nt empty. */
				if ($("option:selected", this).val().length == 0) {
					/* Add the 'error' class to the element. */
					$(this).addClass('error');
					/* Add the 'error' class to all siblings */
					$(this).siblings().addClass('error');
					/* Set the return variable to false. */
					r = false;
				}
				else {
					/* Remove the 'error' class to the element. */
					$(this).removeClass('error');
					/* Remove the 'error' class to all siblings */
					$(this).siblings().removeClass('error');
				}
			});
		}

		if (r) {
			$(sender).parents('.form .wrapper').children('div.error').addClass('hidden');
		}
		else {
			$(sender).parents('.form .wrapper').children('div.error').removeClass('hidden');
		}

		/* Send back the return variable. */
		return r;
	},

	/* 
	function: c9.page.filterCalendarRows()
	param: sender = the <select> that triggers the filter
	Used to populate data used when filtering of the calendar tables.
	*/
	filterCalendarRows: function (sender) {

		/* Declare a array to hold key/value of the current columns */
		var filterArray = new Array();

		/* Select all select-objects in the same level of the HTML. */
		$(sender).siblings('select').andSelf().each(function (i, dselect) {
			/* Populate the filterArray with the current set of key/value */
			filterArray[i] = new Array($(dselect).attr('class'), dselect.options[dselect.selectedIndex].value);
		});

		/* Make it happend! */
		c9.page.filterCalendarData(sender, filterArray);
	},

	/* 
	function: c9.page.filterCalendarData()
	param: sender = the <select> that triggers the filter
	param: filterArray = a two-dimensional array with key/value of the filters.
	Used to execute filtration of calendar tables.
	*/
	filterCalendarData: function (sender, filterArray) {

		/* Declare variable to use to iterate through visible rows. */
		var iter = 0;


		/* Select all table-rows in the current table. */
		$(sender).parents('table').find("tbody tr").each(function (i, dtr) {

			/* Declare variable used to handle visible/hidden. */
			var show = true;

			/* Select all table-datas in the current table-row. */
			$(dtr).find('td').each(function (j, dtd) {
				/* itterate thourgh the filterArray. */
				for (i = 0; i < filterArray.length; i++) {
					/* Check if the current table-data has the current filter-key. */
					if ($(dtd).hasClass(filterArray[i][0])) {
						/* Check if the current filter-value is found inside the contents of the table-data. */
						/* Hack: .replace(' & ', ' &amp; ') is used to handle unescaped values in the drop to match the html that is escaped. */
						if (filterArray[i][1].length > 0 && dtd.innerHTML.indexOf(filterArray[i][1].replace(' & ', ' &amp; ')) == -1) {
							show = false;
							return;
						}
					}
				}
			});

			/* Test if the row should be visible. */
			if (show) {
				/* Remove any old class-attributes. */
				$(dtr).removeAttr('class');
				/* Test if the row is even or odd with modulus. */
				if (iter % 2) {
					/* Add the 'odd' CSS-class. */
					$(dtr).attr('class', 'odd');
				}
				else {
					/* Add the 'even' CSS-class. */
					$(dtr).attr('class', 'even');
				}
				iter++;
			}
			else {
				/* Add the 'hidden' CSS-class. */
				$(dtr).attr('class', 'hidden');
			}
		});
	},

	/* 
	function: c9.page.toggleFormExtras()
	Used to show and hide extra fields on various forms, ie on the book-an-artist form. 
	*/
	toggleFormExtras: function () {
		/* Show/hide the '.form #aSimplifyShow'. Visible by default. */
		$('.form #aSimplifyShow').toggleClass('hidden');
		/* Show/hide the '.form #aSimplifyHide'. Hidden by default. */
		$('.form #aSimplifyHide').toggleClass('hidden');
		/* Show/hide the '.form #divSimplity'. Hidden by default. */
		$('.form #divSimplity').toggleClass('hidden');
	}

});

/* Build the namespace for the util class. */
c9.util = function() {

	/* Creates the namespace/class. */
	c9.util.superclass.init.apply(this, arguments);
	/* Calls the class initializer. */
	this.initialize();
	
};

/* Extend jQuery with the util class. */
c9.extend(c9.util, jQuery, {
	
	/* Initialize the class. */
	initialize: function() {
	
	},

	/* 
	function: c9.util.getCursor()
	param: dDom = the object who trigges the event
	Used to handle crossbrowser hand/pointer cursors on onmouseovers.
	*/
	getCursor : function(sender)
	{	
		/* If the broswer is compatible with Internet Explorer. */
		if (document.all) {
			/* Set the cursor as 'hand'. */
			$(sender).css('cursor','hand');
		}
		else {
			/* Set the cursor as 'pointer'. */
			$(sender).css('cursor','pointer');
		}
	}
});

$(document).ready(function() {
	/* Set a namespace for/and load the generic util-functions. */
	c9.util = new c9.util();
	/* Set a namespace for/and load the specific page-functions. */
	c9.page = new c9.page();
});    

