/*
 * Accordion 1.5 - jQuery menu widget
 *
 * Copyright (c) 2007 Jörn Zaefferer, Frank Marcia
 *
 * http://bassistance.de/jquery-plugins/jquery-plugin-accordion/
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Revision: $Id: jquery.accordion.js 2951 2007-08-28 07:21:13Z joern.zaefferer $
 *
 */

(function($) {

$.ui = $.ui || {}

$.ui.accordion = {};
$.extend($.ui.accordion, {
        defaults: {
                selectedClass: "selected",
                alwaysOpen: true,
                animated: 'slide',
                event: "click",
                header: "a"
        },
        animations: {
                slide: function(settings, additions) {
                        settings = $.extend({
                                easing: "swing",
                                duration: 300
                        }, settings, additions);
                        if ( !settings.toHide.size() ) {
                                settings.toShow.animate({height: "show"}, {
                                        duration: settings.duration,
                                        easing: settings.easing,
                                        complete: settings.finished
                                });
                                return;
                        }
                        var hideHeight = settings.toHide.height(),
                                showHeight = settings.toShow.height(),
                                difference = showHeight / hideHeight;
                        settings.toShow.css({ height: 0, overflow: 'hidden' }).show();
                        settings.toHide.filter(":hidden").each(settings.finished).end().filter(":visible").animate({height:"hide"},{
                                step: function(n){
                                        settings.toShow.height(Math.ceil( (hideHeight - (n)) * difference ));
                                },
                                duration: settings.duration,
                                easing: settings.easing,
                                complete: settings.finished
                        });
                },
                bounceslide: function(settings) {
                        this.slide(settings, {
                                easing: settings.down ? "bounceout" : "swing",
                                duration: settings.down ? 1000 : 200
                        });
                },
                easeslide: function(settings) {
                        this.slide(settings, {
                                easing: "easeinout",
                                duration: 700
                        })
                }
        }
});

$.fn.extend({
        nextUntil: function(expr) {
            var match = [];
        
            // We need to figure out which elements to push onto the array
            this.each(function(){
                // Traverse through the sibling nodes
                for( var i = this.nextSibling; i; i = i.nextSibling ) {
                    // Make sure that we're only dealing with elements
                    if ( i.nodeType != 1 ) continue;
        
                    // If we find a match then we need to stop
                    if ( $.filter( expr, [i] ).r.length ) break;
        
                    // Otherwise, add it on to the stack
                    match.push( i );
                }
            });
        
            return this.pushStack( match );
        },
        // the plugin method itself
        accordion: function(settings) {
                if ( !this.length )
                        return this;
        
                // setup configuration
                settings = $.extend({}, $.ui.accordion.defaults, settings);
                
                if ( settings.navigation ) {
                        var current = this.find("a").filter(function() { return this.href == location.href; });
                        if ( current.length ) {
                                if ( current.filter(settings.header).length ) {
                                        settings.active = current;
                                } else {
                                        settings.active = current.parent().parent().prev();
                                        current.addClass("current");
                                }
                        }
                }
                
                // calculate active if not specified, using the first header
                var container = this,
                        headers = container.find(settings.header),
                        active = findActive(settings.active),
                        running = 0;

                if ( settings.fillSpace ) {
                        var maxHeight = this.parent().height();
                        headers.each(function() {
                                maxHeight -= $(this).outerHeight();
                        });
                        var maxPadding = 0;
                        headers.nextUntil(settings.header).each(function() {
                                maxPadding = Math.max(maxPadding, $(this).innerHeight() - $(this).height());
                        }).height(maxHeight - maxPadding);
                } else if ( settings.autoheight ) {
                        var maxHeight = 0;
                        headers.nextUntil(settings.header).each(function() {
                                maxHeight = Math.max(maxHeight, $(this).height());
                        }).height(maxHeight);
                }

                headers
                        .not(active || "")
                        .nextUntil(settings.header)
                        .hide();
                active.parent().andSelf().addClass(settings.selectedClass);
                
                
                function findActive(selector) {
                        return selector != undefined
                                ? typeof selector == "number"
                                        ? headers.filter(":eq(" + selector + ")")
                                        : headers.not(headers.not(selector))
                                : selector === false
                                        ? $("<div>")
                                        : headers.filter(":eq(0)");
                }
                
                function toggle(toShow, toHide, data, clickedActive, down) {
                        var finished = function(cancel) {
                                running = cancel ? 0 : --running;
                                if ( running )
                                        return;
                                // trigger custom change event
                                container.trigger("change", data);
                        };
                        
                        // count elements to animate
                        running = toHide.size() == 0 ? toShow.size() : toHide.size();
                        
                        if ( settings.animated ) {
                                if ( !settings.alwaysOpen && clickedActive ) {
                                        toShow.slideToggle(settings.animated);
                                        finished(true);
                                } else {
                                        $.ui.accordion.animations[settings.animated]({
                                                toShow: toShow,
                                                toHide: toHide,
                                                finished: finished,
                                                down: down
                                        });
                                }
                        } else {
                                if ( !settings.alwaysOpen && clickedActive ) {
                                        toShow.toggle();
                                } else {
                                        toHide.hide();
                                        toShow.show();
                                }
                                finished(true);
                        }
                }
                
                function clickHandler(event) {
                        // called only when using activate(false) to close all parts programmatically
                        if ( !event.target && !settings.alwaysOpen ) {
                                active.toggleClass(settings.selectedClass);
                                var toHide = active.nextUntil(settings.header);
                                var toShow = active = $([]);
                                toggle( toShow, toHide );
                                return;
                        }
                        // get the click target
                        var clicked = $(event.target);
                        
                        // due to the event delegation model, we have to check if one
                        // of the parent elements is our actual header, and find that
                        if ( clicked.parents(settings.header).length )
                                while ( !clicked.is(settings.header) )
                                        clicked = clicked.parent();
                        
                        var clickedActive = clicked[0] == active[0];
                        
                        // if animations are still active, or the active header is the target, ignore click
                        if(running || (settings.alwaysOpen && clickedActive) || !clicked.is(settings.header))
                                return;

                        // switch classes
                        active.parent().andSelf().toggleClass(settings.selectedClass);
                        if ( !clickedActive ) {
                                clicked.parent().andSelf().addClass(settings.selectedClass);
                        }

                        // find elements to show and hide
                        var toShow = clicked.nextUntil(settings.header),
                                toHide = active.nextUntil(settings.header),
                                data = [clicked, active, toShow, toHide],
                                down = headers.index( active[0] ) > headers.index( clicked[0] );
                        
                        active = clickedActive ? $([]) : clicked;
                        toggle( toShow, toHide, data, clickedActive, down );

                        return !toShow.length;
                };
                function activateHandler(event, index) {
                        // IE manages to call activateHandler on normal clicks
                        if ( arguments.length == 1 )
                                return;
                        // call clickHandler with custom event
                        clickHandler({
                                target: findActive(index)[0]
                        });
                };

                return container
                        .bind(settings.event, clickHandler)
                        .bind("activate", activateHandler);
        },
        activate: function(index) {
                return this.trigger('activate', [index]);
        }
});

})(jQuery);

