/**
 * jQuery UI Accordion 1.6 @ http://docs.jquery.com/UI/Accordion
 *
 * Copyright (c) 2007 Jörn Zaefferer
 *
 * Dual licensed under the MIT and GPL licenses:
 * - http://www.opensource.org/licenses/mit-license.php
 * - http://www.gnu.org/licenses/gpl.html
 */

;
(function ($) {
  $.ui = $.ui || {};
  $.fn.extend({
    accordion: function (options, data) {
      var args = Array.prototype.slice.call(arguments, 1);
      return this.each(function () {
        if (typeof options == "string") {
          var accordion = $.data(this, "ui-accordion");
          accordion[options].apply(accordion, args);
        } else if (!$(this).is(".ui-accordion")) $.data(this, "ui-accordion", new $.ui.accordion(this, options));
      });
    },
    activate: function (index) {
      return this.accordion("activate", index);
    }
  });
  $.ui.accordion = function (container, options) {
    this.options = options = $.extend({}, $.ui.accordion.defaults, options);
    this.element = container;
    $(container).addClass("ui-accordion");
    if (options.navigation) {
      var current = $(container).find("a.accordion").filter(options.navigationFilter);
      if (current.length) {
        if (current.filter(options.header).length) {
          options.active = current;
        } else {
          options.active = current.parent().parent().prev();
          current.addClass("current");
        }
      }
    }
    options.headers = $(container).find(options.header);
    options.active = findActive(options.headers, options.active);
    if (options.fillSpace) {
      var maxHeight = $(container).parent().height();
      options.headers.each(function () {
        maxHeight -= $(this).outerHeight();
      });
      var maxPadding = 0;
      options.headers.next().each(function () {
        maxPadding = Math.max(maxPadding, $(this).innerHeight() - $(this).height());
      }).height(maxHeight - maxPadding);
    } else if (options.autoheight) {
      var maxHeight = 0;
      options.headers.next().each(function () {
        maxHeight = Math.max(maxHeight, $(this).outerHeight());
      }).height(maxHeight);
    }
    options.headers.not(options.active || "").next().hide();
    options.active.parent().andSelf().addClass(options.selectedClass);
    if (options.event) $(container).bind((options.event) + ".ui-accordion", clickHandler);
  };
  $.ui.accordion.prototype = {
    activate: function (index) {
      clickHandler.call(this.element, {
        target: findActive(this.options.headers, index)[0]
      });
    },
    enable: function () {
      this.options.disabled = false;
    },
    disable: function () {
      this.options.disabled = true;
    },
    destroy: function () {
      this.options.headers.next().css("display", "");
      if (this.options.fillSpace || this.options.autoheight) {
        this.options.headers.next().css("height", "");
      }
      $.removeData(this.element, "ui-accordion");
      $(this.element).removeClass("ui-accordion").unbind(".ui-accordion");
    }
  }

  function scopeCallback(callback, scope) {
    return function () {
      return callback.apply(scope, arguments);
    };
  }

  function completed(cancel) {
    if (!$.data(this, "ui-accordion")) return;
    var instance = $.data(this, "ui-accordion");
    var options = instance.options;
    options.running = cancel ? 0 : --options.running;
    if (options.running) return;
    if (options.clearStyle) {
      options.toShow.add(options.toHide).css({
        height: "",
        overflow: ""
      });
    }
    $(this).triggerHandler("change.ui-accordion", [options.data], options.change);
  }

  function toggle(toShow, toHide, data, clickedActive, down) {
    var options = $.data(this, "ui-accordion").options;
    options.toShow = toShow;
    options.toHide = toHide;
    options.data = data;
    var complete = scopeCallback(completed, this);
    options.running = toHide.size() == 0 ? toShow.size() : toHide.size();
    if (options.animated) {
      if (!options.alwaysOpen && clickedActive) {
        $.ui.accordion.animations[options.animated]({
          toShow: jQuery([]),
          toHide: toHide,
          complete: complete,
          down: down,
          autoheight: options.autoheight
        });
      } else {
        $.ui.accordion.animations[options.animated]({
          toShow: toShow,
          toHide: toHide,
          complete: complete,
          down: down,
          autoheight: options.autoheight
        });
      }
    } else {
      if (!options.alwaysOpen && clickedActive) {
        toShow.toggle();
      } else {
        toHide.hide();
        toShow.show();
      }
      complete(true);
    }
  }

  function clickHandler(event) {
    var options = $.data(this, "ui-accordion").options;
    if (options.disabled) return false;
    if (!event.target && !options.alwaysOpen) {
      options.active.parent().andSelf().toggleClass(options.selectedClass);
      var toHide = options.active.next(),
          data = {
          instance: this,
          options: options,
          newHeader: jQuery([]),
          oldHeader: options.active,
          newContent: jQuery([]),
          oldContent: toHide
          },
          toShow = options.active = $([]);
      toggle.call(this, toShow, toHide, data);
      return false;
    }
    var clicked = $(event.target);
    if (clicked.parents(options.header).length) while (!clicked.is(options.header)) clicked = clicked.parent();
    var clickedActive = clicked[0] == options.active[0];
    if (options.running || (options.alwaysOpen && clickedActive)) return false;
    if (!clicked.is(options.header)) return;
    options.active.parent().andSelf().toggleClass(options.selectedClass);
    if (!clickedActive) {
      clicked.parent().andSelf().addClass(options.selectedClass);
    }
    var toShow = clicked.next(),
        toHide = options.active.next(),
        data = {
        instance: this,
        options: options,
        newHeader: clicked,
        oldHeader: options.active,
        newContent: toShow,
        oldContent: toHide
        },
        down = options.headers.index(options.active[0]) > options.headers.index(clicked[0]);
    options.active = clickedActive ? $([]) : clicked;
    toggle.call(this, toShow, toHide, data, clickedActive, down);
    return false;
  };

  function findActive(headers, selector) {
    return selector != undefined ? typeof selector == "number" ? headers.filter(":eq(" + selector + ")") : headers.not(headers.not(selector)) : selector === false ? $([]) : headers.filter(":eq(0)");
  }
  $.extend($.ui.accordion, {
    defaults: {
      selectedClass: "selected",
      alwaysOpen: true,
      animated: 'slide',
      event: "click",
      header: "a.accordion",
      autoheight: true,
      running: 0,
      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;
        }
        var hideHeight = options.toHide.height(),
            showHeight = options.toShow.height(),
            difference = showHeight / hideHeight;
        options.toShow.css({
          height: 0,
          overflow: 'hidden'
        }).show();
        options.toHide.filter(":hidden").each(options.complete).end().filter(":visible").animate({
          height: "hide"
        }, {
          step: function (now) {
            var current = (hideHeight - now) * difference;
            if ($.browser.msie || $.browser.opera) {
              current = Math.ceil(current);
            }
            options.toShow.height(current);
          },
          duration: options.duration,
          easing: options.easing,
          complete: function () {
            if (!options.autoheight) {
              options.toShow.css("height", "auto");
            }
            options.complete();
          }
        });
      },
      bounceslide: function (options) {
        this.slide(options, {
          easing: options.down ? "bounceout" : "swing",
          duration: options.down ? 1000 : 200
        });
      },
      easeslide: function (options) {
        this.slide(options, {
          easing: "easeinout",
          duration: 700
        })
      }
    }
  });
})(jQuery);
