(function($){
	var Elastic_Rate = function(element, instructions){
		$(element).trigger('elastic_rate:beforeInitialize');
		
		var rateInstance = this;
		this.element     = $(element);
		
		if($('.mask', element).length == 0){
			this.element.html('<div class="value">&nbsp;</div>'
			                + '<div class="selection">&nbsp;</div>'
			                + '<div class="mask">&nbsp;</div>');
		}
		
		this.maskElement      = $('.mask', element);
		this.selectionElement = $('.selection', element);
		this.valueElement     = $('.value', element);
		
		this.maskElement
		.bind('click', function(event){
			rateInstance.setValue( (event.clientX - rateInstance.element[0].offsetLeft) / rateInstance.maskElement[0].offsetWidth );
		})
		.bind('mousemove', function(event){
			rateInstance.selectionElement.css('width', event.clientX - rateInstance.element[0].offsetLeft);
			rateInstance.valueElement.css('opacity', '0');
		})
		.bind('mouseout', function(){
			rateInstance.selectionElement.css('width', '');
			rateInstance.valueElement.css('opacity', '1');
		});
		
		if(instructions){
			if(instructions.value){
				this.setValue(instructions.value, false);
			}
		}
		
		$(element).trigger('elastic_rate:afterInitialize');
	};
	
	Elastic_Rate.prototype = {
		element          : null,
		maskElement      : null,
		selectionElement : null,
		valueElement     : null,
		getValue         : function(){
			return this.valueElement[0].clientWidth / this.element[0].clientWidth;
		},
		setValue         : function(value, trigger_event){
			this.valueElement.css('width', value * this.element[0].clientWidth );
			if(trigger_event !== false){
				this.element.trigger('elastic_rate:setValue');
			}
		}
	};
		
	$.fn.elastic_rate = function(instructions, params){
		if(instructions == 'getValue'){
			if(!this[0].elastic || !this[0].elastic.rateInstance){
				return null;
			}
			return this[0].elastic.rateInstance.getValue();
		}
		if(instructions == 'setValue'){
			if(!this[0].elastic || !this[0].elastic.rateInstance){
				return null;
			}
			return this[0].elastic.rateInstance.setValue(params.value, params.trigger_event);
		}
		
		this.each(function(){
			if(this.elastic && this.elastic.rateInstance){
				return this;
			}
			else{
				if(!this.elastic){
					this.elastic = {};
				}
				this.elastic.rateInstance = new Elastic_Rate(this, instructions);
			}
		});
		
		return this;
	};
	
})(jQuery);
