(function($) {
    $.extend({
        disableTextSelection: function() {
            $(document.documentElement).bind("drag selectstart", function() { return false; });
            $(document.body).addClass("no-select");
        },
        enableTextSelection: function() {
            $(document.documentElement).unbind("drag selectstart");
            $(document.body).removeClass("no-select");
        },
        esc: function(s) { return s.replace(/&/g,"&amp;").replace(/>/g,"&gt;").replace(/</g,"&lt;").replace(/"/g,"&quot;"); }
    });
    $.fn.extend({
        any: function(p) {
            for (var i = 0; i < this.length; ++i)
                if (p.call(this[i])) return true;
            return false;
        },
        contains: function(node) {
            return this.any(function() { return this == node; });
        },
        calendar: function() {
            return this.each(function() {
                var dateField = $(this);

                // Create calendar object and bind to a "trigger" icon
                var cal = new Calendar(1, null, function(cal, date) { dateField.val(date); if (cal.dateClicked) cal.hide(); }, function(cal) { cal.hide(); });
                cal.create()
                $(cal.element).bind("click mousedown", function(e) { e.stopPropagation(); }); // Prevent calendar events from escaping
                cal.setDateFormat("%e/%m/%Y");
                cal.yearStep = 1;
                var trigger = $("<a href='#'><img src='/images/calendar-icon.png' /></a>");
                trigger.click(function() {
                    cal.parseDate(dateField.val());
                    cal.showAtElement(trigger[0], "CR");
                    return false;
                });
                dateField.after(trigger).after($("<span>&nbsp;</span>"));
            });
            return this;
        },
        backgroundSubmit: function(callback) {
            // Submit the selected form or forms to a hidden iframe
            return this.each(function() {
                if (this.nodeName != "FORM") throw "Can't backgroundSubmit() something that isn't a form";
                var form = $(this);

                var submitValues = {};

                function doneLoading() {
                    if (this.contentWindow.location.href != "about:blank") {
                        var successful = true;
                        if (this.contentWindow.formErrors)
                        {
                            // Form submission has validation errors
                            form.showErrors(this.contentWindow.formErrors);
                            successful = false;

                            // Let the page redraw before showing the dialog
                            setTimeout(function() { alert("There were some problems with your submission. Please see above for details."); }, 0);
                        }

                        if (callback) callback.call(form[0], successful, this.contentWindow, submitValues);

                        // If the iframe is removed now, Firefox gets stuck showing a loading icon in the tab bar; use a timeout to prevent that
                        var iframe = $(this);
                        setTimeout(function() { iframe.remove(); }, 0);
                    }
                }

                // Make a second form in order to submit without triggering events in Chrome
                var frameName = "bgsubmit_" + (""+Math.random()).substr(2);
                var hiddenFrame = $("<iframe style='display:none' src='about:blank' name='" + $.esc(frameName) + "'></iframe>").load(doneLoading).appendTo($(document.body));
                var surrogateForm = $("<form />").attr({
                    action: form.attr("action"),
                    method: "post",
                    target: frameName,
                    enctype: form.attr("enctype")
                }).hide().appendTo(document.body);

                // Copy form values
                $(form.serializeArray()).each(function () {
                    surrogateForm.append('<input type=hidden name="'+$.esc(this.name)+'" value="'+$.esc(this.value)+'" />');
                    submitValues[this.name] = this.value;
                });

                // Can't copy file fields in IE. *Move* the file fields, submit and move them back.
                var files = [];
                form.find("input[type=file]").each(function() {
                    files.push({el: this, parent: this.parentNode, before: this.nextSibling});
                    surrogateForm.append(this);
                });

                surrogateForm.submit();
                surrogateForm.remove();

                surrogateForm.find("input[type=file]").remove();
                for (var i = files.length - 1; i >= 0; i--) files[i].parent.insertBefore(files[i].el, files[i].before);
            });
        },
        registerBackgroundSubmit: function(options) {
            return this.submit(function(e) {
                var form = $(this);
                e.preventDefault();
                if (options.flag) var flagField = $("<input type='hidden' value='1' name=\""+$.esc(options.flag)+"\" />").appendTo(form);
                if (options.loader) var loader = $("<span>&nbsp;</span><img src='" + $.esc(options.loader) + "' />").insertAfter(form.find("input[type=submit]").eq(0));
                form.backgroundSubmit(function(successful, contentWindow, vals) {
                    if (options.loader) loader.remove();
                    if (options.callback) options.callback.call(this, successful, contentWindow, vals);
                });
                if (options.flag) flagField.remove();
            });
        },
        showErrors: function(errors) {
            this.find(".error").hide();
            for (var k in errors) {
                var v = errors[k];
                var node = this.find(".error.error-"+k).show().find(".error-text").text(v);
            }
            return this;
        },
        dragdrop: function() {
            return this.each(function() {
                var list = $(this);
                list.mousedown(function(e) {
                    if (e.target.nodeName != "IMG") return;
                    var li = $(e.target).closest("li");

                    // dragItem is the "floating" image that appears to be dragged around. It's actually a
                    // copy of the real image, which is still in place, but hidden. I apply 15% transparency
                    // to dragItem by calling fadeTo() rather than using the "opacity" CSS property.
                    var dragItem = li.find("img").clone().css({position: "absolute"}).fadeTo(0, 0.85).appendTo("body");

                    // Once the drag item is created, Opera triggers an additional mousedown event on it. This causes
                    // Opera's built-in image-dragging logic to kick in, unless I call preventDefault() on that event too.
                    dragItem.mousedown(function(e) { e.preventDefault(); });

                    function reposition(e) {
                        // Determine where the top-left corner of dragItem should go.
                        var w = dragItem.width(), h = dragItem.height();
                        var x = e.pageX - Math.floor(dragItem.width()) / 2, y = e.pageY - Math.floor(dragItem.height()) / 2;

                        // Clamp to the list's rectangle
                        var listPos = list.offset(), listW = list.width(), listH = list.height();
                        x = Math.max(Math.min(x, listPos.left + listW - w), listPos.left);
                        y = Math.max(Math.min(y, listPos.top  + listH - h), listPos.top );

                        // Reposition the drag item while working around an IE 8 bug
                        /*@cc_on if (@_jscript_version == 5.8) { dragItem.hide(); } @*/
                        dragItem.css({left: x + "px", top: y + "px"});
                        /*@cc_on if (@_jscript_version == 5.8) { dragItem.show(); } @*/

                        // Move the hidden LI to a new position.
                        // Because of borders, padding and margins, the mouse not be within an LI element.
                        // Instead, locate the LI whose center is closest under the 2-norm.
                        var closest = null, bestDist = 9999999;
                        list.children().each(function() {
                            var cur = $(this);
                            var curPos = cur.offset();
                            var thisDist = Math.pow(curPos.left + cur.width() / 2 - e.pageX, 2) + Math.pow(curPos.top + cur.height() / 2 - e.pageY, 2);
                            if (thisDist < bestDist) { bestDist = thisDist; closest = cur; }
                        });
                        if (closest[0] != li[0]) {
                            if (li.nextAll().contains(closest[0]))
                                li.insertAfter(closest);  // If moving forwards, insert *after*
                            else
                                li.insertBefore(closest); // If moving backwards, insert *before*
                        }
                    }
                    reposition(e);
                    li.fadeTo(0, 0);
                    $.disableTextSelection();
                    $(document.documentElement).mousemove(function(e) {
                        reposition(e);
                        e.preventDefault();
                    });
                    $(document.documentElement).mouseup(function(e) {
                        var targetPos = li.find("img").offset();
                        dragItem.animate({left: targetPos.left + "px", top: targetPos.top + "px"}, {duration: 150, complete: function() { li.fadeTo(150, 1, function() { dragItem.remove(); }); }});
                        $(document.documentElement).unbind("mousemove mouseup");
                        $.enableTextSelection();
                    });

                    e.preventDefault(); // Prevent default image-dragging behaviour in some browsers
                });
            });
        },
        selectOther: function() {
            function adjustVisibility() {
                if (this.value == "")
                    $(this).next().addClass("js_visible").removeClass("js_hidden");
                else
                    $(this).next().addClass("js_hidden").removeClass("js_visible");
            }
            return this.each(adjustVisibility).bind("click change keydown", adjustVisibility);
        },
        // Enqueue a jquery method call in the animation queue.
        // Example: $(elem).animate({backgroundColor: "blue"}, 500).then("css", {backgroundColor: "transparent"});
        // Example: $(elem).animate({backgroundColor: "blue"}, 500).then(function() { /* do something else */ });
        then: function(name) {
            if (name.constructor == Function) {
                var fn = name;
                this.queue(function() {
                    var that = $(this);
                    fn.call(that);
                    that.dequeue();
                });
            }
            else {
                var args = Array.prototype.slice.call(arguments, 1);
                this.queue(function() {
                    var that = $(this);
                    that[name].apply(that, args);
                    that.dequeue();
                });
            }
            return this;
        }
    });
    $(function() {
        $("input.date").calendar();
        $("select.other").selectOther();
        var sn = $("#subnav");
        // Apply position: fixed to the subnav when the header is scrolled off the page.
        // In IE 6, skip this because it doesn't support position: fixed.
        if (sn.length > 0 /*@cc_on @if (@_jscript_version == 5.6) && false @end @*/) {
            var minScrollPos = sn.offset().top - (parseInt(sn.css("margin-top")) || 0);
            var snHeight = sn.height();
            $(window).scroll(function() {
                var maxScrollPos = $("#footer").offset().top - sn.attr("offsetHeight") - (parseInt(sn.css("margin-bottom")) || 0);
                if ($(window).scrollTop() <= minScrollPos || snHeight > $(window).height())
                    sn.css({position: "static", top: ""}); // Header is visible; use static positioning
                else if ($(window).scrollTop() <= maxScrollPos)
                    sn.css({position: "fixed", top: 5}); // Header not visible; use fixed positioning
                else
                    sn.css({position: "relative", top: maxScrollPos - minScrollPos}); // Don't overlap the footer
            });
        }
    });
})(jQuery);

if (window.opera) { document.write('<style type="text/css">.am-image, .am-image-spacer, .article .odd { padding-top: 0 !important; } .spacer-r, .spacer-l { height: 11.9em !important; }</style>'); }

