/** 
@fileOverview NetRelations common extensions to jQuery
*/

(function ($) {

    /**
    Get the element matching the fragment part of an URL via Ajax
    */
    $.getFragment = function (options) {
        if (typeof options == 'string') {
            options = {
                url: options
            };
        }
        var url = new netr.URI(options.url);
        var fragment = '#' + url.fragment;
        var _success = options.success;

        options.success = function (data, textStatus, jqXHR) {
            var content = $(fragment, data);
            _success(content, textStatus, jqXHR);
        };

        // IE seems to sometimes escape the hash part and send it along to the server.
        // This might cause an error, so we have to take the hash part away before requesting
        url.fragment = '';
        options.url = url.getAbsolute();

        return $.ajax(options);
    };

    /* 
    Add selector for external links
    */
    $.expr[":"].external = function (el, i, match, array) {
        return $(el).isExternal();
    };

    $.extend($.fn, {

        /**
        Returns whether the first link is external
        @memberOf $.fn
        */
        isExternal: function () {
            var docHost, linkHost;
            // Is it a link to begin with?
            if (this.is("a")) {
                // A mailto link is not external
                if (this.attr('protocol') != "mailto:") {
                    // If the second-level domain matches the current one, it's not an external link
                    docHost = document.location.hostname.match(/\w+\.\w+$/);
                    linkHost = this.prop('hostname').match(/\w+\.\w+$/);
                    if (docHost && linkHost && docHost[0] != linkHost[0]) {
                        return true;
                    }
                }
            }
            return false;
        },

        /**
        Convert obfuscated mailto elements into real links
        */
        activateEmailLinks: function (options) {
            options = $.extend({}, {
                textSelector: '.email-text:first', // Optional element with text to be used as the visible link text
                addressSelector: '.email-address:first', // Element with obfuscated email adress (entity encoded, decimal or hexadecimal)
                salt: 'INGEN_SPAM_' // Optional prefix to further reduce the risk of spam bots picking up addresses
            }, options || {});

            return this.each(function () {
                var textElem = $(options.textSelector, this);
                var addressElem = $(options.addressSelector, this);
                if (addressElem.length) {
                    var addressText = addressElem.text().replace(options.salt, "");
                    var textText = (textElem.length ? textElem.text() : addressText).replace(options.salt, "");
                    $(this).replaceWith('<a href="mailto:' + addressText + '">' + textText + '</a>');
                }
            });
        },

        /**
        When clicked, supplied links should open i a new window
        */
        triggerNewWindow: function (options) {
            options = $.extend({}, {
                widthRegEx: /\bw([0-9]+)\b/, // Regular expression for width (matches w400)
                heightRegEx: /\bh([0-9]+)\b/, // Regular expression for height (matches h400)
                warning: '' // HTML string that is appended to the link. E.g. '(will open in a new window)'
            }, options || {});

            return this.each(function () {
                var $this = $(this);
                if (options.warning) {
                    $this.append(options.warning);
                }
                if (options.widthRegEx.test($this.attr('class')) && options.heightRegEx.test($this.attr('class'))) {
                    $this.click(function (e) {
                        e.preventDefault();
                        window.open(this.href, '_blank', 'menubar=yes,toolbar=no,location=yes,resizable=yes,scrollbars=yes,status=yes,width=' + options.widthRegEx.exec($this.attr('class'))[1] + ',height=' + options.heightRegEx.exec($this.attr('class'))[1]);
                    });
                }
                this.target = '_blank';
            });
        },

        /**
        Return or set the minimum height of an element
        @param {Number} [height] Set the minimum height to this value
        @memberOf $.fn
        */
        minHeight: function (height) {
            // Explorer versions prior to IE7 needs to have height instead of min-height
            var type = ($.browser.msie && parseInt($.browser.version, 10) < 7) ? "height" : "min-height";
            if (height == undefined) {
                // Get min-height for the first element
                return this.css(type);
            } else {
                // Set the min-height on all elements (default to pixels if value is unitless)
                this.css(type, height.toString().match(/^\d+$/) ? height + "px" : height);
                return this;
            }
        },

        /**
        Return the height of the tallets matched element
        @memberOf $.fn
        */
        getHighestHeight: function () {
            var maxHeight = 0;
            // Get the height of the highest element
            this.each(function () {
                var el = $(this), height;
                el.minHeight(0);
                height = el.outerHeight();
                if (height > maxHeight) {
                    maxHeight = height;
                }
            });
            return maxHeight;
        },

        /**
        Justifies the heights of a bunch of elements to match the highest one
        @memberOf $.fn
        */
        justify: function () {
            var maxHeight = this.getHighestHeight();
            // Set min-height for all elements
            this.each(function () {
                var el = $(this);
                el.minHeight(el.height() + maxHeight - el.outerHeight());
            });
            return this;
        },

        /**
        Justifies the heights of a bunch of elements to match the highest passed in one
        @param {jQuery} [elements] A bunch of elements to make the matched elements taller than
        @param {Number} [pixels] Make the matched elements at least this much taller
        @memberOf $.fn
        */
        makeTallerThan: function (elements, pixels) {
            pixels = isNaN(pixels) ? 0 : pixels;
            var maxHeight = elements.getHighestHeight();
            return this.each(function () {
                var el = $(this);
                var height = el.height();
                if (maxHeight + pixels > height) {
                    el.minHeight(maxHeight + pixels);
                }
            });
        },

        alignBottoms: function (pixels) {
            pixels = isNaN(pixels) ? 0 : pixels;
            var bottom = Math.ceil(Math.max.apply(Math, this.map(function () {
                var el = $(this);
                return el.offset().top + el.height();
            }).get()) + pixels);
            this.each(function () {
                var el = $(this);
                el.minHeight(Math.ceil(bottom - el.offset().top));
            });
        },

        /**
        Center an element horizontally in the viewport
        @memberOf $.fn
        */
        centerInViewport: function () {
            return this.each(function () {
                $(this).css({
                    left: ($(window).width() / 2) - ($(this).width() / 2)
                });
            });
        },

        /**
        Get an elements corresponding input
        */
        getLabel: function () {
            if (this.is('input, select, textarea') && this.attr('id')) {
                return $('label[for=' + this.attr('id') + ']');
            }
        },

        /**
        Generate a random id for the element(s)
        @param {Boolean} [overwrite] Whether to overwrite an exisiting id
        */
        generateRandomId: function (overwrite) {
            overwrite = overwrite === false ? false : true;
            return this.each(function () {
                var el = $(this);
                var id;
                if (overwrite || !el.attr('id')) {
                    // Loop just to be sure the id doesn't already exist in the DOM
                    do {
                        id = Math.random().toString().replace(/\D/, '');
                    } while ($('#' + id).length)
                    el.attr('id', id);
                }
            });
        }

    });
})(jQuery);

