;if(window.jQuery) (function($){

	// IE6 Background Image Fix
	// Thanks to http://www.fyneworks.com/jquery/star-rating and http://www.visualjquery.com/rating/rating_redux.html 
	if ($.browser.msie) try { document.execCommand("BackgroundImageCache", false, true)} catch(e) { };
	
	//********************************************************************************
	//*  main entry point for quickRating
	//********************************************************************************
	$.fn.quickRating = function(options)
	{
		if(this.length==0) return this; // quick fail
		
		// add the star rating control to each selected element
		return this.each(function()
		{
			var control = getQuickRatingControl.call(this);
			
			// handle destruction
			if (options && options.destroy)
			{
				if (control != null) control.remove();
				$(this).removeData('quickRating');
				return true;	// continue looping
			}
			
			if (control == null)
			{
				var settings = $.extend(true, {}, $.fn.quickRating.defaults, options || {});
				// allow element-specific options via the metadata plugin
				// to take advantage of this, you could specify markup like the following...
				//   <div class="ratings-holder { readOnly:'true', split:'0' }"></div>
				// and then in javascript, add the quickRating control as follows:
				//   $('.ratings-holder').quickRating();
				// the default options should be overridden by the options specified in the markup metadata
				settings = $.metadata ? $.extend({}, settings, $(this).metadata()) : settings;
				createControl.call(this, settings);
			}
			else
			{
				var settings = control.data('quickRatingSettings');
				settings = $.extend(true, settings, options);
				updateControl.call(this, settings, options);
			}
		});
	};
	
	//********************************************************************************
	//*  overridable default settings
	//********************************************************************************
	$.fn.quickRating.defaults = 
	{
		value:0,					// initial value of the control
		numStars:5,					// number of stars in the control
		split:0,                	// split each star into how many parts?
		valueChanged:function(){},	// callback called when the user changes the current value
		readOnly:false,				// whether or not this control is read-only
		hideClear:false,			// hide the clear button?
		destroy:false,				// pass as true to destroy the control
		
		// Control customization
		// Add to or change the control's attributes or CSS settings on up to a per-instance basis
		controlAttrs:
		{
			'class':'quickRatingControl'
		},		
		controlCSS:
		{
		},
		
		// Hover text customization
		clearTip:'Clear Rating', 									// text to use for the "clear" button
		customRatingTips:[],										// custom array of star hover text
		formatRatingTipCallback:$.fn.quickRating.formatRatingTip,	// callback to use when formatting the star hover text		
		
		// Width of star image in case the plugin can't work it out. This can happen if
		// the jQuery.dimensions plugin is not available OR the image is hidden at installation
		starWidth:16
	};
	
	//********************************************************************************
	//*  formats the title of a star (the star's tooltip)
	//*  'this' is the container element
	//********************************************************************************

	$.fn.quickRating.formatTitle = function(starIndex, settings)
	{
		// if the user specified custom rating text, simply use that
		if (settings.customRatingTips.length > 0)
		{
			return settings.customRatingTips[Math.min(starIndex, settings.customRatingTips.length - 1)];
		}
		
		// format the value appropriately
		var value = settings.readOnly ? settings.value : starIndex + 1;
		if (settings.split <= 1)
		{
			return "" + value + " / " + settings.numStars;
		}
		else if (settings.split == 2)
		{
			return "" + (value / 2).toFixed(1) + " / " + settings.numStars.toFixed(1);
		}
		return "" + (value / settings.split).toFixed(2) + " / " + settings.numStars.toFixed(2);
	};

	//********************************************************************************
	//*  operations on the control itself 
	//********************************************************************************

	clearStars = function(settings)
	{
		// clear all sibling star controls
		settings.control.children('.qr-star').removeClass('qr-star-on').removeClass('qr-star-hover');
	}
	
	redrawControl = function(settings)
	{
		// clear all siblings
		clearStars(settings);
		// now redraw the correct children as selected
		settings.control.children('.qr-star:lt(' + settings.value + ')').addClass('qr-star-on');
	}
	
	updateValue = function(settings, value)
	{
		settings.control.parent().data('quickRating', value);
		if (settings.value != value)
		{
			settings.value = value;
			settings.valueChanged.call(settings.control.parent().get(0), value);
		}
	}
	
	//********************************************************************************
	//*  operations on individual elements in the control 
	//********************************************************************************
	
	hoverTo = function(obj, settings) 
	{ 
		// clear all siblings
		clearStars(settings);
		// now draw all the stars up to the current one as "hovered"
		obj.prevAll().andSelf().filter('.qr-star').addClass('qr-star-hover');
	};

	//***********************************************************************************
	//*  returns the child rating control when 'this' points to a container DOM element
	//***********************************************************************************
		
	getQuickRatingControl = function()
	{
		var settings = null;
		$(this).children().each(function()
		{
			settings = $(this).data('quickRatingSettings');
			if (settings != null) return false;
		});
		if (settings != null) return settings.control;
		return null;
	}
	
	//********************************************************************************
	//*  control creation
	//********************************************************************************

	createControl = function(settings)
	{
		// build up the content of the control
		var content = "<span class='" + settings.controlAttrs['class'] + "'>";
		
		// add the clear button if this isn't read-only and the clear button shouldn't be hidden
		if (!settings.readOnly && !settings.hideClear)
		{
			content += "<div class='qr-clear'><a title='" + settings.clearTip + "'></a></div>";
		}
		
		var starCount = settings.numStars;
		if (settings.split > 1) starCount *= settings.split;
		for (var i = 0; i < starCount; i++)
		{
			content += "<div class='qr-star'><a title='" + $.fn.quickRating.formatTitle.call(this, i, settings) + "'></a></div>";
		}
		content += "</span>";

		// create the control from the content
		settings.control = $(content);
		
		// give each star an index
		settings.control.children('.qr-star')
			.each(function(n)
			{
				this.index = n;
			});
		
		// handle compressing the star widths if we're doing partial-stars
		if (settings.split > 1)
		{
			var starWidth = ($.fn.width ? settings.control.children('.qr-star:first').width() : 0) || settings.starWidth;
			var pixelsPerStar = Math.floor(starWidth / settings.split);
			settings.control.children('.qr-star').each(function()
			{
				var starPortionIndex = this.index % settings.split;
				$(this)
					.width(pixelsPerStar)
					.find('a').css({'margin-left':'-' + (starPortionIndex * pixelsPerStar) + 'px'});
			});
		}

		// apply the readonly CSS style to the stars if this is a read-only control
		// otherwise add the event handlers
		if (settings.readOnly)
		{
			settings.control.children('.qr-star').addClass('qr-readonly');
		}
		else
		{
			settings.control.children('.qr-clear')
				.bind('mouseover.quickRating', function()
				{
					clearStars(settings);
					$(this).addClass('qr-star-hover');
				})
				.bind('mouseout.quickRating', function()
				{
					$(this).removeClass('qr-star-hover');
					redrawControl(settings);
				})
				.bind('click.quickRating', function()
				{
					updateValue(settings, 0);
				});
				
			settings.control.children('.qr-star')
				.bind('mouseover.quickRating', function()
				{
					hoverTo($(this), settings);
				})
				.bind('mouseout.quickRating', function()
				{
					redrawControl(settings);
				})
				.bind('click.quickRating', function()
				{
					updateValue(settings, this.index + 1);
				});
		}
		
		// add the settings object to the control
		settings.control.data('quickRatingSettings', settings);
		
		// add any customized attributes and css
		settings.control.attr(settings.controlAttrs).css(settings.controlCSS);
		
		// add the control to the DOM
		$(this).append(settings.control);

		// draw the control in it's initial state
		updateValue(settings, settings.value);
		redrawControl(settings);
	};
	
	//********************************************************************************
	//*  updating an existing control
	//********************************************************************************

	updateControl = function(settings, updatedSettings)
	{
		// optimize the most common case of changing the control value, so we're not recreating the control
		var count = 0;
		for (k in updatedSettings) if (updatedSettings.hasOwnProperty(k)) { count++; if (count > 1) break; }
		if (count == 1 && typeof updatedSettings.value != 'undefined')
		{
			redrawControl(settings);
			return;
		}
		
		var control = getQuickRatingControl.call(this);
		if (control != null /*should never happen!*/) control.remove();
		createControl.call(this, settings);
	};
	
})(jQuery);
