/*
	jQuery UI Marble 0.5

	Copyright (c) 2010 Ernesto (http://dienstleistung-kultur.de)

	This library is free software; you can redistribute it and/or modify
	it under the same terms as jQuery/UI itself.

	http://dienstleistung-kultur.de/jquery/ui/marble

*/

/*
	The function marble() adds a marble background to every selected object.

	To prevent the same boring background, the background-position is
	recalculated for every selected object. So each object shows a different
	cut-out of the marble plate, which is not repeated, if the background
	image is big enough.

	For hidden elements random positions are used.

	By using a part-transparent background image, the background colour
	of an object follows the standard ui-class changes as well.

	Usage:

	$('.ui-button, #my-button, .any-other-class').marble();

	Of course this function is chainable:

	$('#my-button').marble().hide();

	To reset the background-positions, use de_marble:

	$('.ui-marble').de_marble();

	Moreover another class containing a different picture can be passed as option hash:

	$('.ui-button').marble ( { new_class: 'special-background-for-buttons' } );
	$('.special-div').de_marble ( { new_class: 'special-background-without-offset' } );

	To change a background class, the option last_class must be given:

	$('.ui-button').marble ( { new_class: 'first-background' } );

	... later ...

	$('.ui-button').marble ( { new_class: 'second-background', last_class: 'first-background' } );

	... later ...

	$('.ui-button').marble ( { new_class: 'first-background', last_class: 'second-background' } );

	This is the first public release, so use with care!

*/

/*
	For testing in firebug, please
	load jquery.dump.js,
	uncomment //xrlog here
	and define somewhere a function like:
*/
/*
	function //xrlog ( text )
	{
		if ( window.console )		console.log ( text );
	}
*/

(function($) {

$.fn.marble = function ( params )
{
	var $options	=
	{
		new_class	: 'ui-marble-default',
		last_class	: undefined,
		de_marble	: false
	};

	$options = $.extend( true, {}, $options, params );

	var $marble	=
	{
		background	:	function ( $obj )
		{
			var self	= this;

			var w = 0, h = 0, x = 0, y = 0;

			if ( ! $options.de_marble )
			{
				w		= parseInt( $obj.outerWidth	( true ) );
				h		= parseInt( $obj.outerHeight	( true ) );

				if ( ( w > 0 ) && ( h > 0 ) )
				{
					if ( self.x >= ( self.w - w ) )		//	width exceeded
					{
						self.x	= 0;
						self.y	= self.y + h;
					}

					if ( self.y >= ( self.h - h ) )		//	height exceeded
					{
						self.x	= 0;
						self.y	= 0;
					}
				}
				else		//	handle hidden elements !
				{
					self.x	= Math.floor ( Math.random() * self.w );
					self.y	= Math.floor ( Math.random() * self.h );
				}

				x	= self.x > 0 ? - self.x : 0;
				y	= self.y > 0 ? - self.y : 0;
			}

			//xrlog ( 'self.background: ' + $.dump ( { self.w:self.w, self.h:self.h, self.x:self.x, self.y:self.y, w:w, h:h, x:x, y:y } ) );
			//xrlog ( 'self.background ' + $.dump ( { x:x, y:y } ) );

			$obj.css ( 'background-position', x + 'px ' + y + 'px' );

			self.x	= self.x + w;
		},
		w		:	null,
		h		:	null,
		x		:	null,
		y		:	null,
		image	:	null
	};

	var cnt	= 0;

	//xrlog ( 'FN.marble START ' + cnt + ' ' + $.dump ( { $options:$options, $marble:$marble } ) );

	this.each(function()
	{
		cnt++;

		var $that	= $(this);

		$that.addClass('ui-marble').addClass('ui-marble-default');

		if ( $options.last_class )
			$that.removeClass($options.last_class);

		if ( $options.new_class )
			$that.removeClass('ui-marble-default').addClass($options.new_class);

		//	if we have no base values, try to get them from the background image defined at .ui-marble
		//
		if ( ! $marble.w )
		{
			//	if the image object is not defined, create one
			//
			if ( ! $marble.image )
			{
				$marble.image	= $('<img />');
			}

			//	put each object to be marbled on a "stack" aka succes-callback
			//
			$($marble.image)
			.bind('load readystatechange', function (e)
			{
				//xrlog ( 'marble: IMG event=' + e.type + ' complete=' + this.complete + ' readyState=' + this.readyState );

				if (this.complete || (this.readyState == 'complete' && e.type == 'readystatechange'))
				{
					//	get the base values, if they're not already set by another callback
					//
					if ( ! $marble.w )
					{
						$marble.w	= parseInt ( this.width );
						$marble.h	= parseInt ( this.height );
						$marble.x	= $marble.h + 1;
						$marble.y	= $marble.w + 1;

						//xrlog ( 'marble: IMG LOADED' );
					}

					//xrlog ( 'marble: IMG SUCCESS ' + $.dump ( { $marble.w:$marble.w, $marble.h:$marble.h, $marble.x:$marble.x, $marble.y:$marble.y } ) );
					//xrlog ( 'marble: IMG SUCCESS' );

					//	this is the "stack" aka do your thing now
					//
					$marble.background ( $that );

					cnt--;

					//xrlog ( '$marble.background AF ' + cnt );
				}
			})
			.bind('error', function ()
			{
				//	on error we just set 0-values - just in case...
				//
				if ( ! $marble.w )
				{
					$marble.w	= -1;
					$marble.h	= -1
					$marble.x	= $marble.h + 1;
					$marble.y	= $marble.w + 1;

					//xrlog ( 'marble: IMG ERROR ' + $.dump ( { $marble.w:$marble.w, $marble.h:$marble.h, $marble.x:$marble.x, $marble.y:$marble.y } ) );
				}

				//	here we don't call the "stack", because the calculations in $marble.background won't change anything

				//xrlog ( 'marble: IMG ERROR' );

				cnt--;

				//xrlog ( '$marble.background AF ' + cnt );
			});
		}
		else
		{
			//	we come here, if the global image object already exists and all base values are set
			//
			//xrlog ( 'marble: VALID ' + $.dump ( [ $marble.w, $marble.h, $marble.x, $marble.y ] ) );
			//xrlog ( 'marble: VALID' );

			$marble.background ( $that );

			//xrlog ( '$marble.background AF ' + cnt );
		}

	});

	if ( ! $marble.w )
	{
		$($marble.image).each ( function()
		{
			//xrlog ( 'marble: IMG RELOAD B4' );

			var bg	= $('.ui-marble:first').css ( 'background-image' );

			//xrlog ( 'marble: BG "' + bg + '"...' );

			var url	= bg.replace	( /^url\(\"?/, "" );
			url		= url.replace	( /\"?\)$/, "" );

			//xrlog ( 'marble: LOADING "' + url + '"...' );

			this.src	= url + '?' + ( new Date );	//	force reload

			//xrlog ( 'marble: IMG RELOAD AF' );
		});
	}

	//xrlog ( 'FN.marble DONE ' + cnt );

	return this;		//	make it chainable
};

$.fn.de_marble = function ( params )
{
	//xrlog ( 'FN.de_marble START' );

	var $options	=
	{
		de_marble	: true
	};

	$options = $.extend( true, {}, $options, params );

	this.marble ( $options );

	//xrlog ( 'FN.de_marble DONE' );

	return this;		//	make it chainable
};

})(jQuery);

$(document).ready(function()
{
	//xrlog ( 'START MARBLE...' );
});

