(function($) {
    
    var TRUE      = true,
        FALSE     = false,
        NULL      = null,
        window    = self,
        undefined = undefined;
    
    // custom filters:
    // a filter for external links
    $.expr[':'].external =  function(obj){
        return !obj.href.match(/^mailto\:/) && !obj.href.match(/^javascript\:/) && (obj.hostname != location.hostname);
    };
    
    // JERS jQuery plugins
    $.extend({
        noop : function(){},    
        // ajax random generator (really a date time converter)
        ajaxRan : function(interval){
            var date = new Date(); 
            if (typeof interval == 'undefined'){
                return date.getTime();
            }
            date.setSeconds(0,0); 
            date.setMinutes(Math.round((date.getMinutes()/interval)-0.5)*interval);
            return date.getTime();
        },
        // debugging things
        showInputName : function(){
            $("input").each(function(){
                $(this).qtip({
                    content: $(this).attr("name"),
                    show: {
                        ready: true
                    },
                    hide: {
                        event: false
                    },
                    style: {
                        tip: "leftMiddle",
                        classes: "ui-tooltip-cream"
                    },
                    position: {
                        my: "left center",
                        at: "right center"
                    }
                    });
            });
        }
    });

	$.fn.extend({
		// The tag name form the first element
		tag : function() {
			return $(this)[0].tagName.toLowerCase();
		},
		message : function(type, message, options) {
			return this.jqMessage(type, message, options);
		},
		jersMessage : function(type, message, options) {
			return this.jqMessage(type, message, options);
		},
		jersAjaxSubmit : function(wcId, messageContainer, options) {
			return this.jqmAjaxSubmit(wcId, messageContainer, options);
		},
		jersAjaxForm : function(wcId, messageContainer, options) {
			return this.jqmAjaxForm(wcId, messageContainer, options);
        },
        // Make any element a message element by adding type (success,error,loading) and message it will generate a nice message block
        // There is a short code for error message $().jqMessage("error",JSON.errors)
        jqMessage : function(type,message,options){
            var defaults = {
                prefix:"",
                form:"",
                scrollTo:FALSE,
                scrollToSpeed: 400
            };
            var opts = $.extend(defaults,options);
            $(".all_input_error").removeClass("all_input_error");
            return this.each(function() {
                $(this).hide();
                $(this).removeClass().html("");
                if(type.toLowerCase() != 'clear'){
                    $(this).removeClass().addClass("all_message_block all_"+type+"_message_block").html("<div class=\"all_message_header all_"+type+"_message_header\"><span class=\"all_message_text\"></span></div>").show();
                    if(typeof message == "string"){
                        $(this).find("span.all_message_text").html(message);
                    }
                    if (type.toLowerCase() == "error") {
                        if (typeof message != "string") {
                            opts.errors = message;
                            message = opts.errors.error;
                        }
                        $(this).find("span.all_message_text").html(message);
                        if (typeof opts.errors != "undefined") {
                            $(this).append($("<ul class=\"all_error_list\"></ul>"));
                            for (var key in opts.errors) {
                                if (key != "error" && key != "error_status") {
                                    if (opts.prefix == "") {
                                        if (typeof opts.form == "string" && opts.form != "") {
                                            $("#" + opts.form).find("input[name=" + key + "]").addClass("all_input_error");
                                        } else {
                                            $("input[name=" + key + "]").addClass("all_input_error");
                                            $("select[name=" + key + "]").addClass("all_input_error");
                                            $("textarea[name=" + key + "]").addClass("all_input_error");
                                            if ($("input[name=" + key + "]").attr("type") == "file") {
                                                $("input[name=" + key + "]").parent().find("div.fakefile").find("input").addClass("all_input_error");
                                            }
                                        }
                                    } else {
                                        $("#" + opts.prefix + "_" + key).addClass("all_input_error");
                                    }
                                    if (opts.errors[key] != "") {
                                        $(this).find("ul.all_error_list").append($("<li>" + opts.errors[key] + "</li>"));
                                    }
                                }
                            }
                        }
                    }
                }
                $(this).show();	
                if(type.toLowerCase() != 'loading') {
                    if ($.scrollTo && opts.scrollTo) {
                        $.scrollTo(this,opts.scrollToSpeed);
                    }
                }			
            });
        },
		jqmAjaxSubmit : function(wcId, messageContainer, options) {
			if ($().ajaxSubmit) {
				var defaults = {
					jqMessage: {},
					loadingMessage: "Uw gegevens worden opgeslagen.",
					hideForm: FALSE,
					redirect: TRUE,
					success: function(response) {
					},
					error: function(response) {
					},
					ajaxSubmitOptions: {}
				};
				if (wcId instanceof jQuery) {
					options = messageContainer;
					messageContainer = wcId;
					wcId = void(0);
				} else if (messageContainer instanceof jQuery) {
					// Do nothing
				} else {
					throw "Invalid parameters";
				}
				var postUrl;
				if (wcId == parseInt(wcId)) {
					postUrl = "/controller/WebController/?wcId=" + wcId;
				} else if (wcId instanceof Array) {
					postUrl = "/controller/WebController/?wcId=" + escape(wcId.join(" "));
				} else if (typeof(wcId) == "string") {
					postUrl = escape(wcId);
				} else if (typeof(wcId) == "undefined" || wcId == null) {
					var wcIdElement = this.find("input[name=wcId]");
					if (wcIdElement.length > 0 && wcIdElement.val() != "") {
						postUrl = "/controller/WebController/?wcId=" + escape(wcIdElement.val());
					} else {
						throw "wcId is undefined";
					}
				}
				var thisForm = this;
				var currentOptions = $.extend({}, defaults, options);
				var ajaxSubmitDefaults = {
					type: "POST",
					contentType: "application/x-www-form-urlencoded; charset=utf-8",
					url: postUrl,
					dataType: "json",
					beforeSubmit: function(data) {
						for (var n = 0; n < data.length; n++) {
							if (data[n].name == "wcId") {
								data.splice(n, 1);
								break;
							}
						}
						messageContainer.jqMessage("loading", currentOptions.loadingMessage, currentOptions.jqMessage);
					},
					success: function(JSON) {
						if (JSON.errors.error || (JSON.errors[0] && JSON.errors[0].error)) {
							messageContainer.jqMessage("error", (JSON.errors.error) ? JSON.errors : JSON.errors[0], currentOptions.jqMessage);
							currentOptions.error(JSON);
						} else {
							if (JSON.data.message) {
								messageContainer.jqMessage("success", JSON.data.message, currentOptions.jqMessage);
							}
							if (currentOptions.hideForm) {
								thisForm.hide();
							}
							if (currentOptions.redirect && JSON.data.redirectUrl) {
								document.location = JSON.data.redirectUrl;
							}
							currentOptions.success(JSON);
						}
					}
				};
				var ajaxSubmitOptions = $.extend({}, ajaxSubmitDefaults, currentOptions.ajaxSubmitOptions);
				return $(this).ajaxSubmit(ajaxSubmitOptions);
			} else {
				throw "jquery.form.js is not loaded";
			}
		},
		jqmAjaxForm : function(wcId, messageContainer, options) {
			if ($().ajaxForm) {
				var defaults = {
					jqMessage: {},
					loadingMessage: "Uw gegevens worden opgeslagen.",
					hideForm: TRUE,
					redirect: TRUE,
					success: function(response) {
					},
					error: function(response) {
					},
					ajaxFormOptions: {}
				};
				if (wcId instanceof jQuery) {
					options = messageContainer;
					messageContainer = wcId;
					wcId = void(0);
				} else if (messageContainer instanceof jQuery) {
					// Do nothing
				} else {
					throw "Invalid parameters";
				}
				var postUrl;
				if (wcId == parseInt(wcId)) {
					postUrl = "/controller/WebController/?wcId=" + wcId;
				} else if (wcId instanceof Array) {
					postUrl = "/controller/WebController/?wcId=" + escape(wcId.join(" "));
				} else if (typeof(wcId) == "string") {
					postUrl = escape(wcId);
				} else if (typeof(wcId) == "undefined" || wcId == null) {
					var wcIdElement = this.find("input[name=wcId]");
					if (wcIdElement.length > 0 && wcIdElement.val() != "") {
						postUrl = "/controller/WebController/?wcId=" + escape(wcIdElement.val());
					} else {
						throw "wcId is undefined";
					}
				}
				var thisForm = this;
				var currentOptions = $.extend({}, defaults, options);
				var ajaxFormDefaults = {
					type: "POST",
					contentType: "application/x-www-form-urlencoded; charset=utf-8",
					url: postUrl,
					dataType: "json",
					beforeSubmit: function(data) {
						for (var n = 0; n < data.length; n++) {
							if (data[n].name == "wcId") {
								data.splice(n, 1);
								break;
							}
						}
						messageContainer.jqMessage("loading", currentOptions.loadingMessage, currentOptions.jqMessage);
					},
					success: function(JSON) {
						if (JSON.errors.error || (JSON.errors[0] && JSON.errors[0].error)) {
							messageContainer.jqMessage("error", (JSON.errors.error) ? JSON.errors : JSON.errors[0], currentOptions.jqMessage);
							currentOptions.error(JSON);
						} else {
							if (JSON.data.message) {
								messageContainer.jqMessage("success", JSON.data.message, currentOptions.jqMessage);
							}
							if (currentOptions.hideForm) {
								thisForm.hide();
							}
							if (currentOptions.redirect && JSON.data.redirectUrl) {
								document.location = JSON.data.redirectUrl;
							}
							currentOptions.success(JSON);
						}
					}
				};
				var ajaxFormOptions = $.extend({}, ajaxFormDefaults, currentOptions.ajaxFormOptions);
				return $(this).ajaxForm(ajaxFormOptions);
			} else {
				throw "jquery.form.js is not loaded";
			}
		},
		monthpicker : function(options) {
			if ($().datepicker) {
				var defaults = {
					changeMonth: TRUE,
					changeYear: TRUE,
					dateFormat: "mm-yy",
					beforeShow: function(input, inst) {
						var dateString = $(this).val();
						var options = new Object();
						if (dateString.length > 0) {
							options.defaultDate = $.datepicker.parseDate("dd-" + $(this).datepicker("option", "dateFormat"), "01-" + dateString);
						}
						inst.dpDiv.addClass("ui-monthpicker");
						return options;
					},
					onClose: function(dateText, inst) {
						var month = inst.dpDiv.find(".ui-datepicker-month").val();
						var year = inst.dpDiv.find(".ui-datepicker-year").val();
						$(this).datepicker("setDate", new Date(year, month, 1));
						inst.dpDiv.find(".ui-datepicker-calendar").hide(); // Hide dates before removing class to prevent showing in IE
						inst.dpDiv.removeClass("ui-monthpicker");
					}
				};
				var datepickerOptions = $.extend({}, defaults, options);
				return $(this).datepicker(datepickerOptions);
			} else {
				throw "jquery-ui.js is not loaded";
			}
		}
	});

    /*
     * jQuery TinySort - A plugin to sort child nodes by (sub) contents or attributes.
     *
     * Version: 1.0.4
     *
     * Copyright (c) 2008 Ron Valstar
     *
     * Dual licensed under the MIT and GPL licenses:
     *   http://www.opensource.org/licenses/mit-license.php
     *   http://www.gnu.org/licenses/gpl.html
     *
     * description
     *   - A plugin to sort child nodes by (sub) contents or attributes.
     *
     * Usage:
     *   $("ul#people>li").tsort();
     *   $("ul#people>li").tsort("span.surname");
     *   $("ul#people>li").tsort("span.surname",{order:"desc"});
     *   $("ul#people>li").tsort({place:"end"});
     *
     * Change default like so:
     *   $.tinysort.defaults.order = "desc";
     *
     * in this update:
     *   - changed setArray to pushStack
     *
     * in last update:
     *   - tested with jQuery 1.4.1
     *   - correct isNum return
     *
     * Todos
     *   - fix mixed literal/numeral values
     *   - determine if I have to use pushStack or pushStack
     *
     */
    // default settings
    $.tinysort = {
         id: "TinySort"
        ,version: "1.0.4"
        ,defaults: {
             order: "asc"   // order: asc, desc or rand
            ,attr: ""       // order by attribute value
            ,place: "start" // place ordered elements at position: start, end, org (original position), first
            ,returns: false // return all elements or only the sorted ones (true/false)
        }
    };
    $.fn.extend({
        tinysort: function(_find,_settings) {
            if (_find&&typeof(_find)!="string") {
                _settings = _find;
                _find = null;
            }

            var oSettings = $.extend({}, $.tinysort.defaults, _settings);

            var oElements = {}; // contains sortable- and non-sortable list per parent
            this.each(function(i) {
                // element or sub selection
                var mElm = (!_find||_find=="")?$(this):$(this).find(_find);
                // text or attribute value
                var sSort = oSettings.order=="rand"?""+Math.random():(oSettings.attr==""?mElm.text():mElm.attr(oSettings.attr));
                // to sort or not to sort
                var mParent = $(this).parent();
                if (!oElements[mParent]) oElements[mParent] = {s:[],n:[]};  // s: sort, n: not sort
                if (mElm.length>0)  oElements[mParent].s.push({s:sSort,e:$(this),n:i}); // s:string, e:element, n:number
                else                oElements[mParent].n.push({e:$(this),n:i});
            });
            //
            // sort
            for (var sParent in oElements) {
                var oParent = oElements[sParent];
                oParent.s.sort(
                    function zeSort(a,b) {
                        var x = a.s.toLowerCase?a.s.toLowerCase():a.s;
                        var y = b.s.toLowerCase?b.s.toLowerCase():b.s;
                        if (isNum(a.s)&&isNum(b.s)) {
                            x = parseFloat(a.s);
                            y = parseFloat(b.s);
                        }
                        return (oSettings.order=="asc"?1:-1)*(x<y?-1:(x>y?1:0));
                    }
                );
            }
            //
            // order elements and fill new order
            var aNewOrder = [];
            for (var sParent in oElements) {
                var oParent = oElements[sParent];
                var aOrg = []; // list for original position
                var iLow = $(this).length;
                switch (oSettings.place) {
                    case "first": $.each(oParent.s,function(i,obj) { iLow = Math.min(iLow,obj.n) }); break;
                    case "org": $.each(oParent.s,function(i,obj) { aOrg.push(obj.n) }); break;
                    case "end": iLow = oParent.n.length; break;
                    default: iLow = 0;
                }
                var aCnt = [0,0]; // count how much we've sorted for retreival from either the sort list or the non-sort list (oParent.s/oParent.n)
                for (var i=0;i<$(this).length;i++) {
                    var bSList = i>=iLow&&i<iLow+oParent.s.length;
                    if (contains(aOrg,i)) bSList = true;
                    var mEl = (bSList?oParent.s:oParent.n)[aCnt[bSList?0:1]].e;
                    mEl.parent().append(mEl);
                    if (bSList||!oSettings.returns) aNewOrder.push(mEl.get(0));
                    aCnt[bSList?0:1]++;
                }
            }
            //
            return this.pushStack(aNewOrder); // pushStack or pushStack?
        }
    });
    // is numeric
    function isNum(n) {
        var x = /^\s*?[\+-]?(\d*\.?\d*?)\s*?$/.exec(n);
        return x&&x.length>0?x[1]:false;
    };
    // array contains
    function contains(a,n) {
        var bInside = false;
        $.each(a,function(i,m) {
            if (!bInside) bInside = m==n;
        });
        return bInside;
    };
    // set functions
    $.fn.TinySort = $.fn.Tinysort = $.fn.tsort = $.fn.tinysort;
})(jQuery);

