( function ($) {

    function extractPage(link) {
        return link.protocol + "//" + link.host + link.pathname;
    }

    function reorder(data, panel) {
        var $panel = $(panel), sort = [], $old, h, i;
        data.panels.each( function () {
            var z = parseInt($(this).css('z-index'));
            sort.push( { z: isNaN(z) ? 0 : z, panel: this } );
        } );
        sort.sort( function (e1, e2) { return e2.z - e1.z; } );
        // reset old current tab attributes
        $old = $(sort[0].panel);
        $old.removeClass('current');
        $old.height(data.height);
        // shift z-index values for tabs above new current tab
        for (i = sort.length - 1; i > 0; i -= 1)
            if (sort[i].panel === panel) break;
        for (i -= 1; i >= 0; i -= 1)
            $(sort[i].panel).css('z-index', sort[i + 1].z);
        $panel.css('z-index', sort[0].z);
        $panel.css('height', '');
        $panel.addClass('current');
        $panel.parent().height($panel.outerHeight());
    }

    function inElement(elmt, x, y) {
        var pos = $(elmt).offset(), width = elmt.offsetWidth, height = elmt.offsetHeight;
        return (x >= pos.left) && (x < (pos.left + width)) && (y >= pos.top) && (y < (pos.top + height));
    }

    function tabClickHandler(event) {
        var data = $(this).data('QATabPanels'), i;
        if (data) {
            for (i = 0; i < data.tabs.length; i += 1)
                if (inElement(data.tabs[i], event.pageX, event.pageY)) {
                    reorder(data, data.panels[i]);
                    return false;
                }
        }
        return true;
    }

    function linkClickHandler(event) {
        var hash = this.hash;
        if (hash != undefined) {
            hash = hash.substring(1);
            $('a[name="' + hash + '"]').QATabPanels('makeVisible');
        }
        return true;
    }

    var methods = {

        init: function (options) {
            return this.each( function () {
                var $this = $(this), data = $this.data('QATabPanels'),
                    panels, tabs, ht, z;
                if (!data) {
                    panels = $this.children();
                    tabs = [];
                    ht = 30;  // FIX ME - should use a computed minimum
                    z = panels.length;
                    panels.each( function (idx) {
                        var $this = $(this);
                        tabs.push($this.find('*.tab-panel-tab')[0]);
                        $this.css('z-index', z);
                        if (idx > 0) {
                            $this.height(ht);
                        }
                        z -= 1;
                    } );
                    data = { panels: panels, tabs: tabs, height: ht };
                    $this.data('QATabPanels', data);
                    $this.bind('click.QATabPanels', tabClickHandler);
                    reorder(data, panels[0]);
                }
            } );
        },

        destroy: function () {
            return this.each( function () {
                var $this = $(this), data = $this.data('QATabPanels'),
                    panels;
                if (data) {
                    panels.each( function () {
                        $(this).unbind('click.QATabPanels', tabClickHandler);
                    } );
                    $this.removeData('QATabPanels');
                }
            } );
        },

        makeVisible: function () {
            $(this).parents('*.tab-panel').each( function () {
                var data = $(this).parent().data('QATabPanels');
                if (data) reorder(data, this);
            } );
        }

    };

    $.fn.QATabPanels = function (method) {
        if (methods[method])
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        else if ((typeof method === 'object') || !method)
            return methods.init.apply(this, arguments);
        else
            $.error('Method ' +  method + ' does not exist on jQuery.QATabPanels');
    };

    $(document).ready( function () {
        var docPage = extractPage(document.location);
        $('a[href]').each( function () {
            var page = extractPage(this), $this;
            if (docPage == page) {
                $this = $(this);
                if (this.hash.length > 1)
                    $this.bind('click.QATabPanels', linkClickHandler);
                else
                    $this.addClass('current');
                        // FIX ME: this shouldn't really be here
            }
        } );
    } );

} )(jQuery);

$(document).ready( function () {
    $('*.tab-panel-group').QATabPanels('init');
    var hash = window.location.hash;
    if (hash.length > 1) {
        hash = hash.substring(1);
        $('a[name="' + hash + '"]').QATabPanels('makeVisible');
    }
} );

