/*
 * Expandable, a jQuery plugin to dynamically group and hide web content
 * Copyright (C) 2009  Marc Diethelm
 * License: (GPL 3, http://www.gnu.org/licenses/gpl-3.0.txt) see license.txt
 */

(function(jQuery)
{

	// BUG:
	// worksforme? nested expanders: icon of inner expander way too low, header to tall (innerHeight is wrong!)

	// TO DO:
	// create a mechanism using css to make expandable invisible before creation (but have height); use .css() to make it visible when finished (as I did with new-nav in my portfolio)
	// option: content css [add inline]
	// use line-height on title... (if not empty)
	// customizable icon on right side of header (throbber, add icon, etc) with onclick callback

	// going UI will break the callback arg#2

	jQuery.fn.expandable = function()
	{

		//console.log(typeof jQuery.ui);

		var action;
		var userOptions = {};

		if ( arguments.length == 1 ) {

			action = ( arguments[0].constructor == String ? arguments[0] : null );
			userOptions = ( arguments[0].constructor == Object ? arguments[0] : null );
		} else if ( arguments.length == 2 ) {

			action = ( arguments[0].constructor == String ? arguments[0] : null );
			userOptions = arguments[1];
		}



		// apply options vs. settings

        //if (userOptions) {
        //    var options = jQuery.extend({}, jQuery.fn.expandable.defaults, userOptions);
        //}

        var options = jQuery.extend({}, jQuery.fn.expandable.defaults, userOptions);


		return this.each( function() {

			if (action == "destroy") { // this certainly is not the way it's done. But I don't know better for now, and it works.
				// restore original element
				jQuery(this).removeClass("ui-widget ui-expandable ui-expandable-open");

				jQuery(".ui-widget-content", this).remove().contents().appendTo(this);

				if ( jQuery(this).data("elTitle") ) {
					jQuery(".ui-widget-header", this).unbind("click").remove();
					jQuery(this).prepend( jQuery(this).data("elTitle") );
				}

				return this;

			} else if (action == "close") {

				this.closeExpandable();
				return this;

			} else if (action == "open") {

				this.openExpandable(null, options); // hack for restore onload, with arg "open" and one-time options (eg: {duration: 0})
				return this;
			}


			jQuery(this).hide() // hide everything quickly
			.addClass("ui-expandable ui-widget");

			var title = "";

			// user has created a title child. replaced later.
			if ( jQuery(".ui-expandable-title", this).length > 0 ) {
				var jQuerytitle = jQuery(".ui-expandable-title", this).eq(0).remove();
				title = jQuerytitle.text();
				jQuery(this).data("elTitle", jQuerytitle);
				delete jQuerytitle;
			}

			title = options.title || title;

			// wrap the content in an animatable box
			if ( jQuery(".ui-widget-content", this).length == 0 ) {

				//jQuery(this).wrapInner('<div class="ui-widget-content ui-helper-clearfix"></div>'); // fails if there is no content. jQuery bug #3552
				// workaround (same as my patch to jQuery trunk)
				var html = '<div class="ui-widget-content ui-helper-clearfix"></div>';
				var jQuerythis = jQuery( this );

				if ( jQuerythis.contents().length ) {
					jQuerythis.contents().wrapAll( html );
				} else {
					jQuerythis.html( html );
				}
			}

			var jQuerycontent = jQuery(".ui-widget-content", this);

			if ( options.startopen ) {
				jQuery(this).addClass("ui-expandable-open");
			} else {
				jQuerycontent.hide();
			}

			if ( options.uiIconClosed && options.uiIconOpen ) {
				//console.log("ui closed = %s, ui open = %s, %s", options.uiIconClosed, options.uiIconOpen, jQuery(this).attr("id"))
				var iconstartclass = ( options.startopen ? options.uiIconOpen : options.uiIconClosed );
				var iconclosedclass = options.uiIconClosed;
				var iconopenclass = options.uiIconOpen;
			} else {
				//console.log("default icon (non UI), %s", jQuery(this).attr("id"))
				var iconstartclass = ( options.startopen ? "icon-open" : "icon-closed" );
				var iconclosedclass = "icon-closed";
				var iconopenclass = "icon-open";
			}

			var extra_icon = "";

			if ( options.extraIcon ) {
				extra_icon = " ui-icon " + options.extraIcon;
			}

			//var jQuerytitle = jQuery('<div class="ui-state-default ui-widget-header" title="'+options.tooltip+'"><div class="ui-icon '+iconstartclass+'"></div><div class="ui-expandable-title">'+title+'</div></div>');


			var jQuerytitle = jQuery(
				'<div class="ui-state-default ui-widget-header" title="'+options.tooltip+'">' +
				'	<div class="ui-expandable-icon ui-icon '+iconstartclass+'"></div>' +
				'	<div class="ui-expandable-title">'+title+'</div>' +
				'	<div class="ui-expandable-extraIcon'+extra_icon+'"></div>' +
				'</div>'
			);

			jQuery(".ui-widget-header", this).length ? jQuery(".ui-widget-header", this).replaceWith(jQuerytitle) : jQuery(this).prepend(jQuerytitle);

			jQuery(this).show(); // show the finished expander

			// adjust vertical position of the icon to look nice // produces weird bug in nested expanders, grr.
			var jQueryicon = jQuery(".ui-icon", this);
			//jQuerytitle.css("background-color", "red");
			//jQueryicon.css("background-color", "yellow");
			var y_offset = Math.floor(((jQuerytitle.innerHeight() - jQueryicon.height()) / 2 ));
			//console.log("title innerHeight = %i", jQuerytitle.innerHeight());
			//console.log("title height = %i", jQuerytitle.height());
			//console.log(jQuerytitle.get(0));
			if (y_offset > 0) {
				jQueryicon.css("margin-top", y_offset);
			}


			// I wish I understood the scope complexities better...
			// maybe it can be cleaned up...
			var jQueryexpandable = jQuery(this);
			var jQueryself = this; // actually it should be self not jQueryself, but self is the window

			if (options.close) {
				this._close = options.close; // I need 'this' in the callback to be the one from this scope. // ...use call
			};

			if (options.open) {
				this._open = options.open;
			}


			jQuerytitle.bind("click", null, function(event)
			{ // register clicks on title

				if ( jQueryexpandable.hasClass("ui-expandable-open") ) {

					jQueryself.closeExpandable(event);

				} else {

					jQueryself.openExpandable(event, options);
				};
			});


			this.closeExpandable = function(_event)
			{

				jQuery(".ui-expandable-icon", jQuerytitle).removeClass(iconopenclass).addClass(iconclosedclass);

				// closing now
				jQuerycontent.animate(options.animationClose, options.duration, options.easing, function () {

					jQueryexpandable.removeClass("ui-expandable-open");
					// user callback
					if (options.close) {
						jQueryself._close(_event, options);
					}
				});
			};


			this.openExpandable = function(_event, options)
			{

				jQuery(".ui-expandable-icon", jQuerytitle).removeClass(iconclosedclass).addClass(iconopenclass);

				// opening now
				jQuerycontent.animate(options.animationOpen, options.duration, options.easing, function()
				{

					jQueryexpandable.addClass("ui-expandable-open");
					// user callback
					if (options.open) {
						jQueryself._open(_event, options);
					}
				});
			};


			jQuerytitle.hover(
				function() {
					jQuery(this)
					.removeClass("ui-state-default")
					.addClass("ui-state-hover");
				},
				function() {
					jQuery(this)
					.removeClass("ui-state-hover")
					.addClass("ui-state-default");
				}
			);

			return this;

		});

	};



	jQuery.fn.expandable.defaults = {
		startopen: false,
		title: null,
		tooltip: "Click to expand",
		uiIconClosed: "ui-icon-triangle-1-e",
		uiIconOpen: "ui-icon-triangle-1-s",
		/*uiIconClosed: null,
		uiIconOpen: null,*/
		animationClose: { height: "hide" },
		animationOpen: { height: "show" },
		duration: 500,
		easing: "swing",
		open: null, // callbacks: also not the way it's done it seems... (but works alright)
		close: null,
		extraIcon: null
	};


})(jQuery);

