(function(Y){
	
	Y.widget.Rating = (function(){
		
		var Dom = Y.util.Dom, Event = Y.util.Event, Lang = Y.lang;
		
		var rater = function(el, cfg) {
			rater.prototype.init.call(this, el, cfg);
		};
		
		rater.prototype = {
			lastXY: [0,0],
			
			stars: {},
			
			running: false,
			
			init: function (el, cfg) {
				if ( Lang.isString(el) )
					el = Dom.get(el);
				
				this.config = Lang.merge({
						snapTo: 20,
						roundTo: 'ceil'
				}, cfg||{});
				
				this.element = el;
				
				this.id = this.element.id;
				
				this.initElements();
				
				this.initEvents();
			},
			
			initElements: function() {
				
				var el = this.element.firstChild;
				
				do {
					
					if ( el && el.nodeType == 1 ) {
						if ( Dom.hasClass( el, 'rtg-stars-average' ) )
							this.stars.average = el;
						else if ( Dom.hasClass(el, 'rtg-stars-total' ) )
							this.stars.total = el;
						else if ( Dom.hasClass(el, 'rtg-stars-active' ) )
							this.stars.active = el;
					}
					
				} while( (el = el.nextSibling) );
				
			},
			
			initEvents: function() {
				
				Event.on( this.element, 'mouseover', this.start, this, true );
				Event.on( this.element, 'click', this.handleClick, this, true );
				
			},
			
			start: function()
			{
				if ( this.timeout && this.timeout.cancel ) {
					this.timeout.cancel();;
					this.timeout = false;
				}
				
				if ( this.running )
					return;
				
				Event.on( this.element, 'mousemove', this.handleMove, this, true );
				Event.on( this.element, 'mouseout', this.stop, this, true );
				
				this.xy = Dom.getXY(this.element);
				this.width = Dom.get(this.element).offsetWidth;
				
				this.hide('average').show('active');
			},
			
			stop: function()
			{
				var timeout = function () {
					Event.removeListener( this.element, 'mousemove', this.handleMove );
					
					this.hide('active').show('average');
					
					this.running = false;
				};
				
				//this.timeout = Lang.later( 1000, this, timeout );
				timeout.call(this);
			},
			
			update: function()
			{
				if ( this.running )
					return;
				
				var delta = [
					this.lastXY[0] - this.xy[0],
					this.lastXY[1] - this.xy[1]
				];
				
				var cur_width = this.getWidth('active'),
					new_width = Math.round((delta[0] / this.width) * 100);
					
				var width = this.calcWidth( new_width, cur_width );
				
				if ( width != cur_width )
					this.setWidth('active', width);
			},
			
			handleClick: function (evt)
			{
				var el = Event.getTarget(evt);
				
				if ( Dom.isAncestor( this.element, el ) ) {
					var form = Dom.getAncestorByTagName( this.element, 'form' );
					
					if ( form ) {
						if ( form.elements['data[Rating][rating]'] ) {
							var rating = form.elements['data[Rating][rating]'];
							
							rating.value = this.calc();
						}
						
						form.submit();
					}
				}
			},
			
			handleMove: function (evt)
			{
				this.lastXY = Event.getXY(evt);
				
				this.update();
			},
			
			calc: function (width)
			{
				return this.calcWidth( width || parseInt( this.getWidth( 'active' ), 10 ) );
			},
			
			calcWidth: function ( width )
			{
				var snapTo = this.config.snapTo;
				
				if ( width % snapTo === 0 )
					return width;
				
				var mod = width % snapTo;
				
				if ( mod > snapTo / 2 || this.config.roundTo == 'ceil' )
					return Math.round( width - mod + snapTo );
				
				return Math.round( width - mod );
			},
			
			getWidth: function (key)
			{
				return parseInt( this.getStyle(key, 'width'), 10 );
			},
			
			setWidth: function (key, width) 
			{
				this.style(key, {width: width + "%"});
			},
			
			hide: function (key)
			{
				return this.style(key, {display:'none'});
			},
			
			show: function (key)
			{
				return this.style(key, {display:'block'});
			},
			
			style: function (key, styles)
			{
				var el = this.getEl(key);
				
				if ( el )
				{
					for (var attr in styles)
						Dom.setStyle(el, attr, styles[attr]);
				}
				
				return this;
			},
			
			getStyle: function (key, attr)
			{
				var el = this.getEl(key);
				
				if ( el )
				{
					return Dom.getStyle(el, attr);
				}
				
				return false;
			},
			
			getEl: function (key)
			{
				var el = this.stars[key];
				
				return el;
			}
			
		};
		
		return {
			
			_elements: {},
			
			init: function (el) {
				
				if ( Lang.isString(el) )
					el = Dom.get(el);
				
				new rater(el);
				
			},
			
			watch: function () {
				
				var ids = [].slice.apply(arguments);
				
				for (var i = 0; i < ids.length; i++) {
					var el = ids[i];
					
					Event.onAvailable(el, Y.widget.Rating.init, el, Y.widget.Rating);
				}
			}
			
		}
	})();
		
	Y.register('ui-rating', Y.widget.Rating, {version:"1.0.1"});
})(YAHOO);
