(function($) {
	
	$.fn.extend({
		
		/* ------------------------------------------------
		 * @plugin		m3Placeholder
		 * @created		May 19, 2010
		 * ------------------------------------------------
		 * displays placeholder value when field is empty,
		 * clears the field when it is focused on or when a
		 * value is entered (other than the placeholder's value)
		 */
		
		m3Placeholder: function(options) {
			var defaults = {
				attr_placeholder: "placeholder", // attribute name
				class_placeholder: "placeholder" // class name
			};
			
			var options = $.extend(defaults, options);
			var self = this;
		
			return this.each(function() {
				
				var element = $(this);
				var placeholder_value = element.attr(options.attr_placeholder);
				
				function clear() {
					element.removeClass(options.attr_placeholder);
					
					if (element.val() == placeholder_value) {
						element.val("");
					}
				}
				
				function display() {
					if ((element.val() == "") || (element.val() == placeholder_value)) {
						element.val(placeholder_value).addClass(options.attr_placeholder).removeClass("error");
					}
				}
				
				display();
				
				element
					.change(clear)
					.focus(clear)
					.blur(display)
					.parents('form').submit(clear)
				;

			});
		},
		// end m3Placeholder
		
		/* ------------------------------------------------
		 * @plugin		m3Toggle
		 * @created		May 19, 2010
		 * -----------------------------------------------*/
		/*
			toggles the panel element corresponding with the trigger element. by default,
			the panel element is the next element after the trigger, but it can also be
			the previous element or an element to be determined by a set selector.
		 */
		
		m3Toggle: function(options) {
			
			var defaults = {
				panelSelector: null,
				opened: false,
				ajax: null,
				openedSelector: "opened",
				closedSelector: "closed",
				direction: 'next',
				labelOpen: null,
				onOpen: function(){},
				onClose: function(){},
				onAfterOpen: function() {},
				onAfterClose: function() {}
			};

			var options = $.extend(defaults, options);
			var self = this;
			
			return this.each(function() {
				
				var element = $(this);
				
				/*
				 * select the panel we're gonna work with
				 */
				if (options.panelSelector !== null) {
					var panel = element.siblings(options.panelSelector);
				}
				else {
					if (options.direction === 'next') {
						var panel = element.next(options.panelSelector);
					}
					else if (options.direction === 'prev') {
						var panel = element.prev(options.panelSelector);
					}
				}
				
				//log(element)
				//log(panel)
				//log('---------------------');
				
				/*
				 * store some original values that we might need later
				 */
				var panelLabel = element.text(),
					panelOpacity = panel.css('opacity'),
					panelWidth = panel.width(),
					panelHeight = panel.height()
				;
				
				function markOpened() {
					element.removeClass(options.closedSelector).addClass(options.openedSelector);
					
					if (null !== typeof options.labelOpen) {
						element.text(options.labelOpen);
					}
				}
				
				function markClosed(){
					element.addClass(options.closedSelector).removeClass(options.openedSelector);
					
					if (null !== typeof options.labelOpen) {
						element.text(panelLabel);
					}
				}
				
				if (null !== options.ajax) {
					$.ajax({
						type: 'GET',
						url: options.ajax,
						success: function(content) {
							panel.html(content);
							
							// panel content has been altered, store the new width and height value
							panelWidth = panel.width(),
							panelHeight = panel.height()
						}
					});
				}
				
				if (element.is(options.opened)) {
					markOpened();
					element.text(panelLabel);
				}
				else {
					panel.hide();
					markClosed();
				}
				
				//log('-----------');
				//log(element);
				//log(panel);
								
				element.click(function(e) {
					if (panel.is(":hidden")) {
						panel.show();
						options.onOpen.call(panel);
						
						/*
						 * inspect the visibility, width, height and opacity of the panel.
						 * if these properties all equal the original values,
						 * the panel is in its original state and is declared 'opened'
						 */
						var trackerOpen = setInterval(function() {
							if (panel.is(':visible') && panel.css('opacity') === panelOpacity && panel.width() == panelWidth && panel.height() && panelHeight) {
								clearInterval(trackerOpen);
								markOpened();
								options.onAfterOpen.call(panel);
							}
						}, 100);
					}
					else {
						panel.hide();
						options.onClose.call(panel);
						
						/*
						 * inspect the invisibility of the panel
						 */
						var trackerClose = setInterval(function() {
							if (panel.is(':hidden')) {
								clearInterval(trackerClose);
								markClosed();
								options.onAfterClose.call(panel);
							}
						}, 100);
					}
					return false;
				});
			});
		},
		// end m3Toggle
		
		/* ------------------------------------------------
		 * @plugin		m3LiveResults
		 * @created		June 18, 2010
		 * -----------------------------------------------*/
		/*
			...
		 */
		
		m3LiveResults: function(options) {
			
			var defaults = {
				resultsSelector: '.container_results',
				paginationSelector: '.pagination',
				pageSelector: "a[rel='page_nav']",
				resultsNode: null,
				paginationNode: null,
				onFilter: function(){},
				onPage: function(){},
				onSort: function(){},
				onReponse: function(){},
				onResponseAfterFilter: function(){}, // response
				onResponseAfterPage: function(){},
				onResponseAfterSort: function(){}
			};

			var options = $.extend(defaults, options);
			var self = this;
			
			return this.each(function() {
				
				var results = $(this);
				var form = results.find("form");
				var filters = form.find(":input"); // selects all input, textarea, select and button elements. 
				var pages = results.find(options.paginationSelector).find(options.pageSelector);
				var containerResults = results.find(options.resultsSelector);
				var containerPagination = results.find(options.paginationSelector);
				
				if (containerResults.length === 0) {
					return;
				}
				
				var isLoading = false;
				
				var loadingScreen = "<div id='loading' style='position: absolute'>";
					loadingScreen += "<div id='loading_progress'></div>";
					loadingScreen += "<div id='loading_screen' style='position: absolute'></div>";
					loadingScreen += "</div>";
				
				loadingScreen = $(loadingScreen);
				
				function setupLoading() {
					
					loadingScreen.prependTo(results);
					
					loadingScreen.css({
						width: containerResults.outerWidth(),
						height: containerResults.outerHeight(),
						left: containerResults.position().left,
						top: containerResults.position().top
					});
					
					loadingScreen.find("#loading_screen").css({
						width: containerResults.outerWidth(),
						height: containerResults.outerHeight()
					});
					
					loadingScreen.hide();
									
				}
				
				function showLoadingScreen() {
					loadingScreen.css({
						left: containerResults.position().left,
						top: containerResults.position().top
					});
					
					loadingScreen.show();
				}
				
				function getResults (event) {
					
					
					//log('--getResults');
					//log($(event.target));
					
					if ($(event.target).is(options.pageSelector)) {
						form.find(":input[name='pg']").val( $(event.target).text() );
						
						options.onPage.call( $(event.target) );
					}
					
					if (!isLoading) {
						isLoading = true;
						showLoadingScreen();
						
						$.ajax({
							url: form.attr('action'),
							data: form.serialize(),
							success: function(response) {
								
								var responseResults = (null === options.resultsNode)
									? response
									: $(response).find(options.resultsNode)
								;
								
								containerResults.html( $(responseResults).text() );
								
								if (null !== options.paginationNode) {
									
									//log( $(response).find(options.paginationNode).text());
									
									containerPagination.html(  $(response).find(options.paginationNode).text() )
								}
								
								
								
								loadingScreen.hide();
								isLoading = false;
																
								options.onResponse.call( $(response) );
							}
						});
					}
					
					return false;
				}
				
				setupLoading();
				
				filters.live("change", function(e) {
					options.onFilter.call( $(e.target) );
					getResults(e);
				});
				
				pages.live("click", function(e) {
					getResults(e);
					options.onPage.call( $(e.target) );
					e.preventDefault();
				});
			});
		},
		// end m3LiveResults

		/* ------------------------------------------------
		* @plugin			  m3MasterCheckbox
		* @created			 June 4, 2010
		* ------------------------------------------------
		*
		*/

		m3MasterCheckbox: function(options) {
			
			var defaults = {
				isDisabled: true
			};
			
			var options = $.extend(defaults, options);
			var self = this;
			
			return this.each(function() {
				
				var master = $(this);
				var slaves = $(":checkbox[name='" +  master.attr("name") + "']").not(master);
				
				function isActive() {
					return !slaves.is(":checked");
				}
					
				function setMaster() {
					
					master.attr("checked", !slaves.is(":checked"));
					
					if (options.isDisabled) {
						master.attr("disabled", !slaves.is(":checked"));
					}
				}
				
				setMaster();
				
				slaves.click(setMaster);
				
				master.click(function() {
					
					if (this.checked) {
						slaves.attr("checked", false);
					}
					
					if (!this.checked) {
						$(this).attr("checked", true);
					}
					
					if (options.isDisabled) {
						$(this).attr("disabled", true);
					}
				})
			});
		},
		/* ------------------------------------------------
		* @plugin			  m3ColumnizeList
		* @created			 June 10, 2010
		* ------------------------------------------------
		*
		*/

		m3ColumnizeList: function(numColumns, options) {
		   
			var defaults = {
				itemSelector: 'li',
				itemWrapperTag: '<ul />',
				columnClass: 'col',
				wrapperClass: 'col_wrapper'
			};
		   
			var options = $.extend(defaults, options);
			var numColumns = numColumns;
		   
			return this.each(function() {
			   
				var list = $(this);
				var columnWrapper = $("<div class='" + options.wrapperClass + "'style='overflow: hidden' />");
				//var items = $(this).find(options.itemSelector).clone();
				var items = $(this).find(options.itemSelector);
				var numItemsPerSet = Math.ceil(items.length / numColumns);
				
				list.before(columnWrapper);
			   
				for (var iCol = 0; iCol < numColumns; iCol++) {
					
					var column = [];
					var columnIndex = iCol+1;
					var columnClass = options.columnClass + columnIndex;
					var columnEl = $("<div class='" + options.columnClass + " " + columnClass + "'/>");
				   
					columnEl.appendTo(columnWrapper).addClass(options.columnClass + " " + columnClass);
				   
					for (var iItem = (iCol * numItemsPerSet); iItem < columnIndex * numItemsPerSet; iItem++) {
						if ('undefined' !== typeof  items[iItem]) {
							column.push(items[iItem]);
						}
					}
					
					$(column).appendTo(columnEl);
									   
					if (false !== options.itemWrapperTag) {
						$(column).wrapAll(options.itemWrapperTag);
					}
				}
				
				list.remove();
			});
		},
		// end m3ColumnizeList
		
		/* ------------------------------------------------
		* @plugin			  m3LangSwitch
		* @created			 June 4, 2010
		* ------------------------------------------------
		*
		*/

		m3LangSwitch: function(options) {
			var defaults = {
				currentLangSelector: ".current",
				containerId: "container_lang",
				langSelectedId: "lang_selected"
			};
			
			var options = $.extend(defaults, options);
			var self = this;
		
			return this.each(function() {
				
				var menu = $(this);
				var menu_items = menu.find("li");
				var current_lang = menu.find("li" + options.currentLangSelector + "");
				var wrapper = $("<div id='" + options.containerId + "' />");
				var selected_lang = $("<p id='" + options.langSelectedId + "' />");
				
				menu.wrap(wrapper);
				
				selected_lang
					.prependTo("#" + options.containerId +"")
					.html(current_lang.html())
				;
				
				function showMenu() {
					menu.show();
				
					$(document).click(function(e) {
						if (!$(e.target).parents(wrapper).length) {
							menu.hide();
							$(document).unbind('click');
						}
					});
				}
				
				function hideMenu() {
					menu.hide();
				}
				
				selected_lang.toggle(self.showMenu, self.hideMenu);
				
				menu_items
					.click(function() {
						hideMenu();
					})
					.find("a").attr("target", "_blank")
				;
				
				hideMenu();
				current_lang.hide();
			});
		},
		// end m3LangSwitch

		/* ------------------------------------------------
		* @plugin			  m3Scroll
		* @created			 June 7, 2010
		* ------------------------------------------------
		*
		* see http://jqueryui.com/demos/slider/#side-scroll
		*/

		m3Scroll: function(options) {
			var defaults = {
				contentSelector: ".scroll_content"
			};
			
			var options = $.extend(defaults, options);
			var self = this;
		
			return this.each(function() {
				
				var pane = $(this);
				var content = pane.find(options.contentSelector);
				
				content.after('<div class="scroll-bar-wrap ui-widget-content ui-corner-bottom"><div class="scroll-bar"></div></div>');
				
				//build slider
				var scrollbar = $(".scroll-bar").slider({
					slide:function(e, ui){
						if( content.width() > pane.width() ){ content.css('margin-left', Math.round( ui.value / 100 * ( pane.width() - content.width() )) + 'px'); }
						else { content.css('margin-left', 0); }
					}
				});
				
				//append icon to handle
				var handleHelper = pane
					.find('.ui-slider-handle')
					.mousedown(function(){
						scrollbar.width( handleHelper.width() );
					})
					.mouseup(function(){
						scrollbar.width( '100%' );
					})
					.append('<span class="ui-icon ui-icon-grip-dotted-vertical"></span>')
					.wrap('<div class="ui-handle-helper-parent"></div>').parent()
				;
				
				//change overflow to hidden now that slider handles the scrolling
				pane.css('overflow','hidden').addClass("ui-widget ui-widget-header ui-corner-all");
				pane.find(".scroll-bar-wrap").css({ 'padding': "0 4px 0 2px", 'margin': "0 -1px -1px -1px"});
				pane.find(".scroll-bar-wrap .ui-slider").css({ 'background': 'none', 'border': '0', 'height': '2em', 'margin': '0 auto' });
				pane.find(".ui-handle-helper-parent").css({ 'position': 'relative', 'width': '100%', 'height': '100%', 'margin': '0 auto' });
				pane.find(".ui-slider-handle").css({ 'top':'.2em', 'height': '1.5em' });
				pane.find(".ui-slider-handle .ui-icon").css({ 'margin': '8px auto 0', 'position': 'relative', 'top': '50%' });
				
				//size scrollbar and handle proportionally to scroll distance
				function sizeScrollbar(){
					var remainder = content.width() - pane.width();
					var proportion = remainder / content.width();
					var handleSize = pane.width() - (proportion * pane.width());
					scrollbar.find('.ui-slider-handle').css({
						width: handleSize,
						'margin-left': -handleSize/2
					});
					handleHelper.width('').width( scrollbar.width() - handleSize );
				}

				//reset slider value based on scroll content position
				function resetValue(){
					var remainder = pane.width() - content.width();
					var leftVal = content.css('margin-left') == 'auto' ? 0 : parseInt(content.css('margin-left'));
					var percentage = Math.round(leftVal / remainder * 100);
					scrollbar.slider("value", percentage);
				}
				//if the slider is 100% and window gets larger, reveal content
				function reflowContent(){
					var showing = content.width() + parseInt( content.css('margin-left') );
					var gap = pane.width() - showing;
					if (gap > 0){
						content.css('margin-left', parseInt( content.css('margin-left') ) + gap);
					}
				}
				
				//change handle position on window resize
				$(window).resize(function(){
					resetValue();
					sizeScrollbar();
					reflowContent();
				});

				//init scrollbar size
				setTimeout(sizeScrollbar,10);//safari wants a timeout
			});
		}
		// end m3Scroll
	});
})(jQuery);

$(function() {
	
	// log() shortcut for console log function 
	window.log = (typeof console == "object") ? console.log : function() {};
	
	/* ------------------------------------------------
	 * selectors
	 * ------------------------------------------------
	 * hasPlaceholder: returns all elements with placeholder attribute
	 */
	
	$.expr[':'].hasPlaceholder = function(el) {
		return (typeof $(el).attr('placeholder') !== 'undefined');
	};
	
	// for styling purposes
	$("body").addClass("js_enabled");
	
	// add target attribute to all anchors which href value starts with 'http://' (and therefore most likely an external link)
	$('a[href^="http://"]').attr("target", "_blank");
	
	// dutch date input for validator plugin
	$.validator.addMethod(
	    "dutchDate",
	    function(value, element) {
	        // put your own logic here, this is just a (crappy) example
	        return value.match(/^\d\d-\d\d-\d\d\d\d$/);
	    },
	    "Vul een geldige datum in volgens formaat dd-mm-jjjj"
	);

	
});
