/*
 * jQuery UI Accordion 1.7.1
 *
 * 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.1",
						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);
