jQuery.handleError =  function (s, xhr, status, e) {
    var data;
    
    try {
        data = $.httpData(xhr, s.dataType, s);
    } catch (e) {
        data = null;
    }

    // If a local callback was specified, fire it
    if (s.error) s.error(xhr, status, e, data);

    // Fire the global callback
    if (s.global)
        $.event.trigger("ajaxError", [xhr, s, e, data]);
};

jQuery.ajaxes = function (calls, all_success, any_error) {
    var completed = 0;
    var requests = [];
    var had_error = false;
    
    $.each(calls, function (i, options) {
        if (all_success) {
            var success = options.success;
            options.success = function (data) {
                if (success) success(data);
                if (++completed == calls.length) all_success(data);
            };
        }

        if (any_error) {
            var error = options.error;
            options.error = function (data) {
                if (error) error(data);
                if (!had_error) any_error(data);
                had_error = true;
            };
        }
        
        requests.push($.ajax(options));
    });
    
    return requests;
};

jQuery.iload = function (url, data, target, method, enctype) {
    if (!data) data = {};
    if (!method) method = "post";
    if (!enctype) enctype = "multipart/form-data";

    var form_el = $('<form />');
    form_el.attr('action', url);
    form_el.attr('method', method);
    form_el.attr('enctype', enctype);
    form_el.attr('target',  target);
    
    $.each(data, function (name, value) {
        var input_el = $('<input type="hidden" />');
        input_el.attr('name', name);
        input_el.val(value);
        form_el.append(input_el);
    });
    
    if (!target) {
        target = "target-" + Math.random().toString().slice(2);

        var iframe_el = $('<iframe src="/static/blank.html" style="width: 0; height: 0; display: none;" />');
        iframe_el.attr('id', target);
        iframe_el.attr('name', target);
        iframe_el.bind('load', function () {
            var doc = iframe_el.contents();
            form_el = form_el.clone(true, doc[0]);
            doc.find('body').append(form_el);
            form_el.submit();
        });

        $('body').append(iframe_el);
    } else {

        $('body').append(form_el);
        form_el.submit();
        form_el.remove();
    }
};

jQuery.fn._attr = jQuery.fn.attr;
jQuery.fn.attr = function (name, value, type) {
    if (jQuery.isArray(name)) {
        var el = this;
        var results = {};
        jQuery.each(name, function (i, name) {
            results[name] = el._attr(name, value, type);
        });
        return results;
    } else {
        return this._attr(name, value, type);
    }
};

jQuery.fn._css = jQuery.fn.css;
jQuery.fn.css = function (name, value) {
    if (jQuery.isArray(name)) {
        var el = this;
        var results = {};
        jQuery.each(name, function (i, name) {
            results[name] = el._css(name, value);
        });
        return results;
    } else {
        return this._css(name, value);
    }
};

jQuery.fn._remove = jQuery.fn.remove;
jQuery.fn.remove = function (remove_data) {
    if (remove_data === false) {
        return this.each(function () { this.parentNode.removeChild(this); });
    } else {
        return this._remove();
    }
};

jQuery.fn._data = jQuery.fn.data;
jQuery.fn.data = function(name, value) {
    if (name === undefined && value === undefined) {
        return jQuery.cache[jQuery.data(this.get(0))];
    } else {
        return this._data(name, value);
    }
};

jQuery.fn.ifind = function (selector) {
    return this[0].contentWindow.$(selector);
};

jQuery.fn.scrollTo = function (target, speed) {
    return this.each(function () {
        $(this).animate({scrollTop: this.scrollTop + (target.offset().top - $(this).offset().top)
                                                   - (parseInt(target.css('marginTop')) +
                                                      parseInt(target.css('borderTopWidth'))),
                                               
                         scrollLeft: this.scrollLeft + (target.offset().left - $(this).offset().left)
                                                     - (parseInt(target.css('marginLeft')) +
                                                        parseInt(target.css('borderLeftWidth')))},
                        'fast');
    });
};

jQuery.fn.outerHTML = function(s) {
    return (s ? this.before(s).remove() : jQuery("<div>").append(this.clone()).html());
};

jQuery.fn.shorten = function (n) {
    return this.each(function () {        
        var text = $(this).text();
        if (text.length > (n - 3))
            $(this).attr('title', text).text(text.substring(0, n - 3) + "...");
    });
};

jQuery.fn.filterFind = function (expr) {
    return this.find(expr).add(this.filter(expr))
};

jQuery.fn.caret = function(begin, end) {    
    if (this.length == 0) return;
    if (typeof begin == 'number') {
        end = (typeof end == 'number') ? end : begin;  
        return this.each(function(){
            if (this.setSelectionRange) {
                this.focus();
                this.setSelectionRange(begin, end);
            } else if (this.createTextRange) {
                var range = this.createTextRange();
                range.collapse(true);
                range.moveEnd('character', end);
                range.moveStart('character', begin);
                range.select();
            }
        });
    } else {
        if (this[0].setSelectionRange){
            begin = this[0].selectionStart;
            end = this[0].selectionEnd;
        } else if (document.selection && document.selection.createRange){
            var range = document.selection.createRange();            
            begin = 0 - range.duplicate().moveStart('character', -100000);
            end = begin + range.text.length;
        }
        return {begin:begin, end:end};
    }
};

jQuery.fn.tip = function (text, direction) {
    var el = $(this);
    el.unbind('mouseenter').bind('mouseenter', function () {
        // should use direction for north, west, etc. tooltips
        var tip = $('<div class="tip"><div class="tip-peak"></div><div class="tip-bubble"><span class="tip-content"></span></div></div>');
        var bubble = tip.find('.tip-bubble');
        var content = tip.find('.tip-content');

        el.data('tip', tip);

        // Check which element to append the tooltip to
        if (el.parents('#content').length) {
            el.parent().append(tip);
            tip.css({ top: el.position().top + el.outerHeight(true) + 3,
                          left: el.position().left + parseInt(el.css('margin-left')) + 2 });
        } else {
            $('body').append(tip);
            tip.css({ top: el.offset().top + el.outerHeight(true) + 3,
                      left: el.offset().left + 2 });
        }

        // Set content and measure width and height
        content.html(text);
        bubble.css({width: Math.min(bubble.width(), content.outerWidth(true) + 2),
                    height: content.outerHeight(true)});
    
        $('.tip').show();
    }).unbind('mouseleave').bind('mouseleave', function () {
        el.removeData('tip');
        $('.tip').remove();
    });
};

jQuery.fn.tooltip = function (text, showDuration, waitDuration, hideDuration) {
    return this.each(function () {
        var el = $(this);

        // Hide currently shown tooltips
        var start_opacity = 0.0;
        if (el.data('tooltip')) {
            start_opacity = el.data('tooltip').css('opacity');
            el.data('tooltip').hide().trigger('click');
        }
    
        var tooltip = $('<div class="tooltip"><div class="tooltip-peak"></div><div class="tooltip-bubble"><span class="tooltip-content"></span></div></div>');
        var bubble = tooltip.find('.tooltip-bubble');
        var content = tooltip.find('.tooltip-content');

        el.data('tooltip', tooltip);

        // Check which element to append the tooltip to
        if (el.parents('#content').length) {
            el.parent().append(tooltip);
            tooltip.css({ top: el.position().top + el.outerHeight(true) + 3,
                          left: el.position().left + parseInt(el.css('margin-left')) + 2 });
        } else {
            $('body').append(tooltip);
            tooltip.css({ top: el.offset().top + el.outerHeight(true) + 3,
                          left: el.offset().left + 2 });
        }

        // Set content and measure width and height
        content.html(text);
        bubble.css({width: Math.min(bubble.width(), content.outerWidth(true) + 2),
                    height: content.outerHeight(true)});
        
        // fade in / fade out
        ($.browser.msie ? tooltip.children() : tooltip).css({ opacity: start_opacity })
               .animate({ opacity: 1.0 }, (showDuration ? showDuration : 1000) * (1.0 - start_opacity))
               .animate({ opacity: 1.0 }, (waitDuration ? waitDuration : 1000))
               .animate({ opacity: 0.0 }, (hideDuration ? hideDuration : 1000), function () {
                   tooltip.remove();
                   el.removeData('tooltip');
               });

        // Click to trigger fade out
        tooltip.bind('click', function () {
            tooltip.stop().fadeOut();
            el.removeData('tooltip');
        });
    });
};

jQuery.fn.addHover = function () {
    this.hover(function () { $(this).addClass('hover'); },
               function () { $(this).removeClass('hover'); });
};

jQuery.fn.disable = function (opacity) {
    opacity = (opacity ? opacity : 0.5);

    result = $([]);    
    this.not('.disabled').each(function () {
        var item = $(this).tag('span');
        item.addClass('disabled');     
        item.css('opacity', opacity);
        item.data('disabled-events', $.extend(true, {}, item.data('events')));

        $.each(item.data('events') || [], function (type, handlers) {
            $.each(handlers, function (i, handler) {
                $.event.remove(item[0], type, handler);
            });
        });

        result = result.add(item);
    });
    
    return result;
};

jQuery.fn.enable = function (opacity) {
    opacity = (opacity ? opacity : 1.0);

    result = $([]);    
    this.filter('.disabled').each(function () {
        var item = $(this).tag('a');
        item.removeClass('disabled');        
        item.css('opacity', opacity);        

        item.children().removeClass('disabled').css('opacity', opacity);        

        $.each(item.data('disabled-events') || [], function (type, handlers) {
            $.each(handlers, function (i, handler) {
                $.event.add(item[0], type, handler, handler.data);
            });
        });
    
        item.removeData('disabled-events');
        result = result.add(item);
    });
    
    return result;
};

jQuery.fn.action = function (label, fn, cls, max_length) {
    return this.each(function () {
        var item = $(this);
        var icon = item.children('.icon');
        var icon_label = item.children('.icon-label');
        var icon_badge = item.children('.icon-badge');
        
        if (!icon.length && !icon_label.length) {
            icon = $('<div class="icon" />');
            icon_label = $('<span class="icon-label" />');
            icon_badge = $('<div class="icon-badge" />');
                
            item.append(icon);
            item.append(icon_label);
            item.append(icon_badge);
            item.disableSelection();
        }

        icon_label.html(label.replace(/\_/g,' '));
        
        if (max_length) { icon_label.shorten(max_length); }
        
        cls = (cls == null ? label.toLowerCase() : cls);
        item.attr('class', cls);
        
        if (fn) { item.bind('click', fn); }
    });
};

jQuery.fn.tag = function (tag) {
    if (tag === undefined) {
        return this[0].tagName;
    } else {
        var result = $([]);
        this.each(function () {
            if (this.tagName.toLowerCase() != tag.toLowerCase()) {
                // Create a new element with the desired tag
                var new_el = $('<' + tag + ' />');
            
                // Copy attributes
                $.each(this.attributes, function (i, attr) { 
                    if (!attr.nodeName.match('^jQuery') && attr.nodeValue) {
                        new_el.attr(attr.nodeName, attr.nodeValue); 
                    }
                });
            
                // Copy data
                $.each($(this).data() || {}, function (name, value) {
                    if (name == 'events') {
                        $.each(value, function (type, handlers) {
                            $.each(handlers, function (i, handler) {
                                $.event.add(new_el[0], type, handler, handler.data);
                            });
                        });
                    } else {
                        new_el.data(name, value);
                    }
                });
            
                // Copy html
                new_el.html($(this).html());
            
                $(this).replaceWith(new_el);
                result = result.add(new_el);
            }
        });
        
        return result;
    }
};

jQuery.fn.corner = function(o, adjustSize) {
    return this.each(function () {
        var el = $(this);

        o = (o||"").toLowerCase();
        var color = ((o.match(/bg|white|dark|lightblue/) || ['bg'])[0]);
        var opts = {
            tl:  /top|tl/.test(o),       tr:  /top|tr/.test(o),
            bl:  /bottom|bl/.test(o),    br:  /bottom|br/.test(o)
        };
    
        if (!opts.tl && !opts.tr && !opts.bl && !opts.br) {
            opts = { tl: true, tr: true, bl: true, br: true };
        }
    
        // Only create shadow and inset if we haven't already
        if (!el.find('.inset').length) {
            var shadow_el = $('<div class="fill" />');
            var inset_el = $('<div class="inset" />');
            shadow_el.addClass('shadow-' + color);
    
            el.contents().appendTo(inset_el);
            el.append(shadow_el);
            el.append(inset_el);
    
            inset_el.css(el.css(['padding-top', 'padding-right', 'padding-bottom', 'padding-left',
                                 'border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width',
                                 'border-top-style', 'border-right-style', 'border-bottom-style', 'border-left-style',
                                 'border-top-color', 'border-right-color', 'border-bottom-color', 'border-left-color']));
    
            if (adjustSize) {
                el.css({width: el.outerWidth() + 2, height: el.outerHeight() + 2});
            }

            el.css({padding: 0, border: 0});
        }
    
        $.each(['tl', 'tr', 'bl', 'br'], function (i, corner) {
            if (opts[corner] && !el.find('.corner-' + corner).length) {
                var corner_el = $('<div class="corner" />');
                corner_el.addClass('corner-' + corner);
                corner_el.addClass('corner-' + color);
                el.append(corner_el);
            }
        });
    });
};

jQuery.fn.clearFloats = function() {
    return $(this).append('<div style="clear: both;" />');
};

jQuery.fn.disableSelection = function () {
    return this.each(function() {
        if ($.browser.mozilla) {
            $(this).css('MozUserSelect', 'none');
                
        } else if ($.browser.msie) {
            $(this).bind('selectstart', function() { return false; });

        } else {
            $(this).bind('mousedown', function() { return false; });
            
        }
    });
};

jQuery.fn.valid = function(range) {
    $(this).parent().find(".error").remove();
    var message = "";

    if(this.val().match(/\w{1,}/) == null) {
        message = "(This field is required)"; }

    var regexp = new RegExp("\\w{" + range[0] + "," + range[1] + "}");
    if(this.val().search(regexp) == -1 && message == "" && range[1] != null) {
        message = "(Please enter at least " + range[0] + " characters)"; }
    
    if(message != "") {
        $(this).after('<label class="error">'+ message +'</label>');
        return false;
    } else {
        return true;
    }
};

// Preview Customize Tool 07/14/2010
jQuery.fn.edittool = function () {
    return this.each(function () {
        var el = $(this);
        var iframe = $('#preview-iframe');
    
        // Remove currently shown edittool
        iframe.ifind('.edittool').remove();
        iframe.ifind('.edittool-el').removeClass('edittool-el');
        
        if (State.customizing_css) {
            var edittool = $('<div class="edittool"><div class="edittool-peak"></div>' +
                                '<div class="edittool-content">' + 
                                    '<div class="edittool-bold edittool-tool" title="Bold"></div>' + 
                                    '<div class="edittool-italic edittool-tool" title="Italic"></div>' + 
                                    '<div class="edittool-underline edittool-tool" title="Underline"></div>' + 
                                    '<div class="edittool-sizeup edittool-tool" title="Increase Font Size"></div>' +
                                    '<div class="edittool-sizedown edittool-tool" title="Decrease Font Size"></div>' + 
                                    '<div class="edittool-line-sizeup edittool-tool" title="Increase Line Spacing"></div>' + 
                                    '<div class="edittool-line-sizedown edittool-tool" title="Decrease Line Spacing"></div>' + 
                                    '<div class="edittool-disc edittool-tool" title="Bullet points"></div>' + 
                                    '<div class="edittool-close edittool-tool" title="Close"></div>' + 
                                '</div></div>');
        
            el.data('edittool', edittool);
            el.addClass('edittool-el');

            // appends edittool below clicked element
            iframe.ifind('body').append(edittool);

            // fixes overflow of tool outside of preview content area
            if(el.offset().left > 500) { iframe.ifind('.edittool-content').css({ left: '-190px' }); }
            
            edittool.css({ top: el.offset().top + el.outerHeight(true) + 3,
                          left: el.offset().left,
                          position: 'absolute'
            });

            // Initialize State.custom_css for this element
            if (!State.custom_css['#'+el.attr('id')])
                State.custom_css['#'+el.attr('id')] = {};

            // Click to trigger close
            edittool.find('.edittool-close').bind('click', function () {
                edittool.stop().fadeOut();
                el.removeData('edittool');
                edittool.remove();
                el.removeClass('edittool-el');
            });
        

            var edittool_properties = {
                'font-weight': ['normal', 'bold'],
                'font-style': ['normal', 'italic'],
                'text-decoration': ['none', 'underline'],
                'list-style-type': ['none', 'disc']
            };

            $.each(edittool_properties, function (property, values) {
                // Initialize
                var button = edittool.find('.edittool-' + values[1]);

                if (State.custom_css['#'+el.attr('id')][property] == values[1] || iframe.ifind('#'+ el.attr('id')).css(property) == values[1]) {
                    button.addClass('selected');
                }
        
                // Click to trigger
                button.bind('click', function () {
                    //State.custom_css['#'+el.attr('id')][property] == values[0] || iframe.ifind('#'+ el.attr('id')).css(property) == values[0]
                    if (!$(this).hasClass('selected')) {
                        State.edit_custom_css(el, property, values[1]);
                        $(this).addClass('selected');
                    } else {
                        State.edit_custom_css(el, property, values[0]);
                        $(this).removeClass('selected');
                    }
                });
            });

            // Click to trigger increase font-size
            edittool.find('.edittool-sizeup').bind('click', function () {            
                if (State.custom_css['#' + el.attr('id')]['font-size']) {
                    var size = parseInt(State.custom_css['#' + el.attr('id')]['font-size']);
                } else {
                    var size = parseInt(el.css('font-size'));
                }
            
                State.edit_custom_css(el, 'font-size', size + 2 + 'px');
            });

            // Click to trigger decrease font-size
            edittool.find('.edittool-sizedown').bind('click', function () {            
                if (State.custom_css['#' + el.attr('id')]['font-size']) {
                    var size = parseInt(State.custom_css['#' + el.attr('id')]['font-size']);
                } else {
                    var size = parseInt(el.css('font-size'));
                }

                State.edit_custom_css(el, 'font-size', size - 2 + 'px');
            });

            // Click to trigger increase line-height
            edittool.find('.edittool-line-sizeup').bind('click', function () {
                if (!parseInt(el.css('line-height'))) {
                    var h = 0;
                } else {
                    var h = parseInt(el.css('line-height'));
                }
                
                var line_height = Math.max(h, parseInt(el.css('font-size')));
                State.edit_custom_css(el, 'line-height', line_height + 2 + 'px');
            });

            // Click to trigger decrease line-height
            edittool.find('.edittool-line-sizedown').bind('click', function () {            
                if (!parseInt(el.css('line-height'))) {
                    var h = 0;
                } else {
                    var h = parseInt(el.css('line-height'));
                }

                var line_height = Math.max(h - 2, parseInt(el.css('font-size')));
                State.edit_custom_css(el, 'line-height', line_height + 'px');
            });
        }

    });
};

/*
jQuery Blink
Author: WonderGroup, Jordan Thomas
URL: http://labs.wondergroup.com/demos/mini-ui/index.html
License: MIT (http://en.wikipedia.org/wiki/MIT_License)
*/
jQuery.fn.blink = function(o) {
	var d = { speed: 200, blinks: 2, callback: null };
	var o = jQuery.extend(d, o);
	
	return this.each( function() {
		var calls = 0;
		for (i=1;i<=o.blinks;i++) {
			$(this).animate({
				opacity: 0
			}, o.speed).animate({
				opacity: 1
			}, o.speed, function() {
				calls++;
				if (calls == o.blinks && jQuery.isFunction(o.callback)) { o.callback(); }
			});
		}
	});
};

/*
jQuery Wiggle
Author: WonderGroup, Jordan Thomas
URL: http://labs.wondergroup.com/demos/mini-ui/index.html
License: MIT (http://en.wikipedia.org/wiki/MIT_License)
*/
jQuery.fn.wiggle = function(o) {
	var d = { speed: 50, wiggles: 3, travel: 5, callback: null };
	var o = jQuery.extend(d, o);
	
	return this.each( function() {
		var cache = this;
		var wrap = jQuery(this).wrap('<div class="wiggle-wrap"></div>').css("position","relative");
		var calls = 0;
		for (i=1;i<=o.wiggles;i++) {
			jQuery(this).animate({
				left: "-=" + o.travel
			}, o.speed).animate({
				left: "+=" + o.travel*2
			}, o.speed*2).animate({
				left: "-=" + o.travel
			}, o.speed, function() {
				calls++;
				if (jQuery(cache).parent().hasClass('wiggle-wrap')) {
					jQuery(cache).parent().replaceWith(cache);
				}
				if (calls == o.wiggles && jQuery.isFunction(o.callback)) { o.callback(); }
			});
		}
	});
};

/*
jQuery Bob
Author: WonderGroup, Jordan Thomas
URL: http://labs.wondergroup.com/demos/mini-ui/index.html
License: MIT (http://en.wikipedia.org/wiki/MIT_License)
*/
jQuery.fn.bob = function(o) {
	var d = { speed: 50, bobs: 3, travel: 5, callback: null };
	var o = jQuery.extend(d, o);
	
	return this.each( function() {
		var cache = this;
		var wrap = jQuery(this).wrap('<div class="bob-wrap"></div>').css("position","relative");
		var calls = 0;
		for (i=1;i<=o.bobs;i++) {
			jQuery(this).animate({
				top: "-=" + o.travel
			}, o.speed).animate({
				top: "+=" + o.travel*2
			}, o.speed*2).animate({
				top: "-=" + o.travel
			}, o.speed, function() {
				calls++;
				if (jQuery(cache).parent().hasClass('bob-wrap')) {
					jQuery(cache).parent().replaceWith(cache);
				}
				if (calls == o.bobs && jQuery.isFunction(o.callback)) { o.callback(); }
			});
		}
	});
};
