/*
 * jQuery UI Accordion 1.7.2
 *
 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Accordion
 *
 * Depends:
 *	ui.core.js
 */
(function($) {

$.widget("ui.accordion", {

    _init: function() {

        var o = this.options, self = this;
        this.running = 0;

        // if the user set the alwaysOpen option on init
        // then we need to set the collapsible option
        // if they set both on init, collapsible will take priority
        if (o.collapsible == $.ui.accordion.defaults.collapsible &&
            o.alwaysOpen != $.ui.accordion.defaults.alwaysOpen) {
            o.collapsible = !o.alwaysOpen;
        }

        if ( o.navigation ) {
            var current = this.element.find("a").filter(o.navigationFilter);
            if ( current.length ) {
                if ( current.filter(o.header).length ) {
                    this.active = current;
                } else {
                    this.active = current.parent().parent().prev();
                    current.addClass("ui-accordion-content-active");
                }
            }
        }

        this.element.addClass("ui-accordion ui-widget ui-helper-reset");

        // in lack of child-selectors in CSS we need to mark top-LIs in a UL-accordion for some IE-fix
        if (this.element[0].nodeName == "UL") {
            this.element.children("li").addClass("ui-accordion-li-fix");
        }

        this.headers = this.element.find(o.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all")
            .bind("mouseenter.accordion", function(){ $(this).addClass('ui-state-hover'); })
            .bind("mouseleave.accordion", function(){ $(this).removeClass('ui-state-hover'); })
            .bind("focus.accordion", function(){ $(this).addClass('ui-state-focus'); })
            .bind("blur.accordion", function(){ $(this).removeClass('ui-state-focus'); });

        this.headers
            .next()
                .addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");

        this.active = this._findActive(this.active || o.active).toggleClass("ui-state-default").toggleClass("ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");
        this.active.next().addClass('ui-accordion-content-active');

        //Append icon elements
        $("<span/>").addClass("ui-icon " + o.icons.header).prependTo(this.headers);
        this.active.find(".ui-icon").toggleClass(o.icons.header).toggleClass(o.icons.headerSelected);

        // IE7-/Win - Extra vertical space in lists fixed
        if ($.browser.msie) {
            this.element.find('a').css('zoom', '1');
        }

        this.resize();

        //ARIA
        this.element.attr('role','tablist');

        this.headers
            .attr('role','tab')
            .bind('keydown', function(event) { return self._keydown(event); })
            .next()
            .attr('role','tabpanel');

        this.headers
            .not(this.active || "")
            .attr('aria-expanded','false')
            .attr("tabIndex", "-1")
            .next()
            .hide();

        // make sure at least one header is in the tab order
        if (!this.active.length) {
            this.headers.eq(0).attr('tabIndex','0');
        } else {
            this.active
                .attr('aria-expanded','true')
                .attr('tabIndex', '0');
        }

        // only need links in taborder for Safari
        if (!$.browser.safari)
            this.headers.find('a').attr('tabIndex','-1');

        if (o.event) {
            this.headers.bind((o.event) + ".accordion", function(event) { return self._clickHandler.call(self, event, this); });
        }

    },

    destroy: function() {
        var o = this.options;

        this.element
            .removeClass("ui-accordion ui-widget ui-helper-reset")
            .removeAttr("role")
            .unbind('.accordion')
            .removeData('accordion');

        this.headers
            .unbind(".accordion")
            .removeClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-corner-top")
            .removeAttr("role").removeAttr("aria-expanded").removeAttr("tabindex");

        this.headers.find("a").removeAttr("tabindex");
        this.headers.children(".ui-icon").remove();
        var contents = this.headers.next().css("display", "").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active");
        if (o.autoHeight || o.fillHeight) {
            contents.css("height", "");
        }
    },

    _setData: function(key, value) {
        if(key == 'alwaysOpen') { key = 'collapsible'; value = !value; }
        $.widget.prototype._setData.apply(this, arguments);
    },

    _keydown: function(event) {

        var o = this.options, keyCode = $.ui.keyCode;

        if (o.disabled || event.altKey || event.ctrlKey)
            return;

        var length = this.headers.length;
        var currentIndex = this.headers.index(event.target);
        var toFocus = false;

        switch(event.keyCode) {
            case keyCode.RIGHT:
            case keyCode.DOWN:
                toFocus = this.headers[(currentIndex + 1) % length];
                break;
            case keyCode.LEFT:
            case keyCode.UP:
                toFocus = this.headers[(currentIndex - 1 + length) % length];
                break;
            case keyCode.SPACE:
            case keyCode.ENTER:
                return this._clickHandler({ target: event.target }, event.target);
        }

        if (toFocus) {
            $(event.target).attr('tabIndex','-1');
            $(toFocus).attr('tabIndex','0');
            toFocus.focus();
            return false;
        }

        return true;

    },

    resize: function() {

        var o = this.options, maxHeight;

        if (o.fillSpace) {

            if($.browser.msie) { var defOverflow = this.element.parent().css('overflow'); this.element.parent().css('overflow', 'hidden'); }
            maxHeight = this.element.parent().height();
            if($.browser.msie) { this.element.parent().css('overflow', defOverflow); }

            this.headers.each(function() {
                maxHeight -= $(this).outerHeight();
            });

            var maxPadding = 0;
            this.headers.next().each(function() {
                maxPadding = Math.max(maxPadding, $(this).innerHeight() - $(this).height());
            }).height(Math.max(0, maxHeight - maxPadding))
            .css('overflow', 'auto');

        } else if ( o.autoHeight ) {
            maxHeight = 0;
            this.headers.next().each(function() {
                maxHeight = Math.max(maxHeight, $(this).outerHeight());
            }).height(maxHeight);
        }

    },

    activate: function(index) {
        // call clickHandler with custom event
        var active = this._findActive(index)[0];
        this._clickHandler({ target: active }, active);
    },

    _findActive: function(selector) {
        return selector
            ? typeof selector == "number"
                ? this.headers.filter(":eq(" + selector + ")")
                : this.headers.not(this.headers.not(selector))
            : selector === false
                ? $([])
                : this.headers.filter(":eq(0)");
    },

    _clickHandler: function(event, target) {

        var o = this.options;
        if (o.disabled) return false;

        // called only when using activate(false) to close all parts programmatically
        if (!event.target && o.collapsible) {
            this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all")
                .find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header);
            this.active.next().addClass('ui-accordion-content-active');
            var toHide = this.active.next(),
                data = {
                    options: o,
                    newHeader: $([]),
                    oldHeader: o.active,
                    newContent: $([]),
                    oldContent: toHide
                },
                toShow = (this.active = $([]));
            this._toggle(toShow, toHide, data);
            return false;
        }

        // get the click target
        var clicked = $(event.currentTarget || target);
        var clickedIsActive = clicked[0] == this.active[0];

        // if animations are still active, or the active header is the target, ignore click
        if (this.running || (!o.collapsible && clickedIsActive)) {
            return false;
        }

        // switch classes
        this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all")
            .find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header);
        this.active.next().addClass('ui-accordion-content-active');
        if (!clickedIsActive) {
            clicked.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top")
                .find(".ui-icon").removeClass(o.icons.header).addClass(o.icons.headerSelected);
            clicked.next().addClass('ui-accordion-content-active');
        }

        // find elements to show and hide
        var toShow = clicked.next(),
            toHide = this.active.next(),
            data = {
                options: o,
                newHeader: clickedIsActive && o.collapsible ? $([]) : clicked,
                oldHeader: this.active,
                newContent: clickedIsActive && o.collapsible ? $([]) : toShow.find('> *'),
                oldContent: toHide.find('> *')
            },
            down = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] );

        this.active = clickedIsActive ? $([]) : clicked;
        this._toggle(toShow, toHide, data, clickedIsActive, down);

        return false;

    },

    _toggle: function(toShow, toHide, data, clickedIsActive, down) {

        var o = this.options, self = this;

        this.toShow = toShow;
        this.toHide = toHide;
        this.data = data;

        var complete = function() { if(!self) return; return self._completed.apply(self, arguments); };

        // trigger changestart event
        this._trigger("changestart", null, this.data);

        // count elements to animate
        this.running = toHide.size() === 0 ? toShow.size() : toHide.size();

        if (o.animated) {

            var animOptions = {};

            if ( o.collapsible && clickedIsActive ) {
                animOptions = {
                    toShow: $([]),
                    toHide: toHide,
                    complete: complete,
                    down: down,
                    autoHeight: o.autoHeight || o.fillSpace
                };
            } else {
                animOptions = {
                    toShow: toShow,
                    toHide: toHide,
                    complete: complete,
                    down: down,
                    autoHeight: o.autoHeight || o.fillSpace
                };
            }

            if (!o.proxied) {
                o.proxied = o.animated;
            }

            if (!o.proxiedDuration) {
                o.proxiedDuration = o.duration;
            }

            o.animated = $.isFunction(o.proxied) ?
                o.proxied(animOptions) : o.proxied;

            o.duration = $.isFunction(o.proxiedDuration) ?
                o.proxiedDuration(animOptions) : o.proxiedDuration;

            var animations = $.ui.accordion.animations,
                duration = o.duration,
                easing = o.animated;

            if (!animations[easing]) {
                animations[easing] = function(options) {
                    this.slide(options, {
                        easing: easing,
                        duration: duration || 700
                    });
                };
            }

            animations[easing](animOptions);

        } else {

            if (o.collapsible && clickedIsActive) {
                toShow.toggle();
            } else {
                toHide.hide();
                toShow.show();
            }

            complete(true);

        }

        toHide.prev().attr('aria-expanded','false').attr("tabIndex", "-1").blur();
        toShow.prev().attr('aria-expanded','true').attr("tabIndex", "0").focus();

    },

    _completed: function(cancel) {

        var o = this.options;

        this.running = cancel ? 0 : --this.running;
        if (this.running) return;

        if (o.clearStyle) {
            this.toShow.add(this.toHide).css({
                height: "",
                overflow: ""
            });
        }

        this._trigger('change', null, this.data);
    }

});


$.extend($.ui.accordion, {
    version: "1.7.2",
    defaults: {
        active: null,
        alwaysOpen: true, //deprecated, use collapsible
        animated: 'slide',
        autoHeight: true,
        clearStyle: false,
        collapsible: false,
        event: "click",
        fillSpace: false,
        header: "> li > :first-child,> :not(li):even",
        icons: {
            header: "ui-icon-triangle-1-e",
            headerSelected: "ui-icon-triangle-1-s"
        },
        navigation: false,
        navigationFilter: function() {
            return this.href.toLowerCase() == location.href.toLowerCase();
        }
    },
    animations: {
        slide: function(options, additions) {
            options = $.extend({
                easing: "swing",
                duration: 300
            }, options, additions);
            if ( !options.toHide.size() ) {
                options.toShow.animate({height: "show"}, options);
                return;
            }
            if ( !options.toShow.size() ) {
                options.toHide.animate({height: "hide"}, options);
                return;
            }
            var overflow = options.toShow.css('overflow'),
                percentDone,
                showProps = {},
                hideProps = {},
                fxAttrs = [ "height", "paddingTop", "paddingBottom" ],
                originalWidth;
            // fix width before calculating height of hidden element
            var s = options.toShow;
            originalWidth = s[0].style.width;
            s.width( parseInt(s.parent().width(),10) - parseInt(s.css("paddingLeft"),10) - parseInt(s.css("paddingRight"),10) - (parseInt(s.css("borderLeftWidth"),10) || 0) - (parseInt(s.css("borderRightWidth"),10) || 0) );

            $.each(fxAttrs, function(i, prop) {
                hideProps[prop] = 'hide';

                var parts = ('' + $.css(options.toShow[0], prop)).match(/^([\d+-.]+)(.*)$/);
                showProps[prop] = {
                    value: parts[1],
                    unit: parts[2] || 'px'
                };
            });
            options.toShow.css({ height: 0, overflow: 'hidden' }).show();
            options.toHide.filter(":hidden").each(options.complete).end().filter(":visible").animate(hideProps,{
                step: function(now, settings) {
                    // only calculate the percent when animating height
                    // IE gets very inconsistent results when animating elements
                    // with small values, which is common for padding
                    if (settings.prop == 'height') {
                        percentDone = (settings.now - settings.start) / (settings.end - settings.start);
                    }

                    options.toShow[0].style[settings.prop] =
                        (percentDone * showProps[settings.prop].value) + showProps[settings.prop].unit;
                },
                duration: options.duration,
                easing: options.easing,
                complete: function() {
                    if ( !options.autoHeight ) {
                        options.toShow.css("height", "");
                    }
                    options.toShow.css("width", originalWidth);
                    options.toShow.css({overflow: overflow});
                    options.complete();
                }
            });
        },
        bounceslide: function(options) {
            this.slide(options, {
                easing: options.down ? "easeOutBounce" : "swing",
                duration: options.down ? 1000 : 200
            });
        },
        easeslide: function(options) {
            this.slide(options, {
                easing: "easeinout",
                duration: 700
            });
        }
    }
});

})(jQuery);
