/**
 * @copyright Affinitive, LLC (support@beaffinitive.com)
 * @author Rob Marscher (rmarscher@beaffinitive.com)
 * @package Enclave
 * modified from http://php.scripts.psu.edu/rja171/widgets/rating.php
 * which in turn was taken from http://sandbox.wilstuckey.com/jquery-ratings/
 * 
 * TODO: support full star increments - this seems to only work with half increments
 *       abstract the star part of it keeping the core rating part
 *       this would allow support for non-star based controls (thumbs up/down, plus minus, etc)
 * 
 * NOTE: the "cancel" option is still in here... but it's not supported currently 
 */
jQuery.fn.rating = function(url, options) {
	var rating;
	this.each(function() {
		var x = null;
		rating = new Affinitive_Rating(this, url, options);
		rating.init();
		this.affRating = rating;
	});
	return this;
};
Affinitive_Rating = function(container, url, options) {
	if (url === null) { return; }
	
	this.settings = {
		ratingType       : 'stars', // 'stars' or 'thumbs' currently supported
		itemType         : null, // type of item being rated - not used yet, but here if we need it
		itemId           : null, // id of item being rated - not used yet, but here if we need it
		url              : url,  // post changes to 
		increment        : 1,    // value to increment by
		maxvalue         : 5,    // max number of stars
		curvalue         : 0,    // currentRating value
		curvalueUp       : 0,    // thumbs up count
		curvalueDown     : 0,    // thumbs down count
		curvalueType     : "overallValue",
		hideOverallValue : false,
		overallValue     : 0,    // overallRating value
		overallValueUp   : 0,    // overall thumbs up
		overallValueDown : 0,    // overall thumbs down
		overallVotes     : 0,    // total votes
		userValue        : 0,    // userRating value
		authorized       : true, // rating is authorized
		groupOverall     : null, // optional container to an overall rating that needs to be refreshed
		controlsLabel    : '',   // optional label/html to prepend to the controls
		thanksMsg        : 'Thanks!', // user feedback that shows the rating was successful
		voteCallback     : null, // optional function to call on receiving vote response
		postVoteCallback : null, // optional function to call after receiving vote response (called by voteCallback)
		lr: function(container) { 
			if (!fpglobals.loggedIn) {
				lr(container, 'boxB', null, 'popAbsoluteLeft');
				return false;
			} else {
				return true;
			} 
		} // function to call to check login status, must return boolean
	};
	
	if (options) {
		jQuery.extend(this.settings, options);
	}
	jQuery.extend(this.settings, {cancel: (this.settings.maxvalue > 1) ? true : false});

	this.container = container;
	this.jContainer = jQuery(container);
	this.initialized = false; 
};
Affinitive_Rating.prototype = {
	init: function() {
		this.settings.increment = (this.settings.increment < 0.75) ? 0.5 : 1;
		// this.initialized allows init to be run again after new settings are loaded
		if (this.initialized === false) {
			this._generateControls();
		}
		// set curvalue based on curvalueType
		if (this.settings.curvalueType == "overallValue") {
			this.settings.curvalue = this.settings.overallValue;
		} else {
			this.settings.curvalue = this.settings.userValue;
		}

		// set this to affRating since "this" is overridden the event context with the DomElement
		var affRating = this;
		if (this.settings.authorized) {
			this.jContainer.removeClass('not-authorized');
			this.controls
				.mouseover(function() {
					affRating.drain();
					affRating.fill(this);
				})
				.mouseout(function() {
					affRating.drain();
					affRating.reset();
				})
				.focus(function() {
					affRating.drain();
					affRating.fill(this);
				})
				.blur(function() {
					affRating.drain();
					affRating.reset();
				});
		
			this.controls.click(function() {
				if (affRating.settings.lr(affRating.container)) {
					if (affRating.settings.ratingType == 'stars') {
						affRating.settings.curvalue = (affRating.controls.index(this) * affRating.settings.increment) + affRating.settings.increment;
					} else if (affRating.settings.ratingType == 'thumbs') {
						affRating.settings.curvalue = (affRating.controls.index(this) === 0) ? 1 : -1;
					}
					affRating.settings.userValue = affRating.settings.curvalue;
					affRating.settings.curvalueType = 'userValue';
					affRating.drain();
					affRating.reset();
					if (affRating.settings.voteCallback === null) {
						affRating.voteCallback(affRating.settings.curvalue, affRating);
					} else {
						affRating.settings.voteCallback(affRating.settings.curvalue, affRating);
					}
				}
				return false;
			});
			// cancel button events
			if (this.cancel) {
				this.cancel
					.mouseover(function() {
						affRating.drain();
						jQuery(this).addClass('on');
					})
					.mouseout(function() {
						affRating.reset();
						jQuery(this).removeClass('on');
					})
					.focus(function() {
						affRating.drain();
						jQuery(this).addClass('on');
					})
					.blur(function() {
						affRating.reset();
						jQuery(this).removeClass('on');
					});
	
				// click events.
				this.cancel.click(function() {
					affRating.drain();
					affRating.settings.curvalue = 0;
					jQuery.post(affRating.settings.url, {
						"rating": jQuery(this).children('a')[0].href.split('#')[1] 
					});
					return false;
				});
			}
		} else {
			this.jContainer.addClass('not-authorized');
			this.controls.unbind();
			this.controls.click(function() { return false; });
		}
		this.drain();
		this.reset();
		this.initialized = true;
	},
	_generateControls: function() {
		if (this.settings.ratingType == 'stars') {
			this._generateStarsControls();
		} else if (this.settings.ratingType == 'thumbs') {
			this._generateThumbsControls();
		}
	},
	_generateStarsControls: function() {
		var s = 0;
		if (!this.settings.hideOverallValue) {
			this.jContainer.attr("title", this.settings.overallValue + "/" + this.settings.maxvalue + " out of " + this.settings.overallVotes + " vote" + (this.settings.overallVotes != 1 ? "s" : ""));
		}
		for (var i = 0; i <= this.settings.maxvalue; i++) {
			if (i === 0) {
				if (this.settings.cancel === true) {
					var div = '<div class="cancel"><a href="#0" title="Cancel Rating">Cancel Rating</a></div>';
					this.jContainer.empty().append(div);
				}
			} else {
				var jQuerydiv = jQuery('<div class="star"></div>')
					.append('<a href="#'+i+'">'+i+'</a>')
					.appendTo(this.container);
				if (this.settings.increment == (0.5)) {
					if (s % 2) {
						jQuerydiv.addClass('star-left');
					} else {
						jQuerydiv.addClass('star-right');
					}
				}
			}
			i = i - 1 + this.settings.increment;
			s++;
		}
		if (this.settings.controlsLabel != '') {
			this.jContainer.prepend('<div class="ratingLabel">' + this.settings.controlsLabel + '</div>');
		}
		this.controls = this.jContainer.children('.star');
		this.cancel = this.jContainer.children('.cancel');
	},
	_generateThumbsControls: function() {
		if (!this.settings.hideOverallValue) {
			this.jContainer.attr("title", this.settings.overallValue + " out of " + this.settings.overallVotes + " vote" + (this.settings.overallVotes != 1 ? "s" : ""));
		}
		this.jContainer.html(
			'<span class="thumbs"><a class="thumbsUp" href="#1">' + this.settings.overallValueUp + '</a></span>'
			+ '<span class="thumbs"><a class="thumbsDown" href="#-1"> ' + this.settings.overallValueDown + '</a></span>'
		);
		this.controls = this.jContainer.find('.thumbs');
		this.cancel = false;
	},
	voteCallback: function(rating, affRating) {
		var ratingThanks = this.jContainer;
		// locking in the size of the container so that the page formatting doesn't shift while the thanks message displays
		// if this causes problems, then let's change the thanks message to be some type of popup/modal 
		this.jContainer.css({height:this.jContainer.height(), width:this.jContainer.width(), overflow: 'hidden'})
		jQuery.post(
			affRating.settings.url,
			{"rating": rating},
			function(response, status) {
				if (status == 'success') {
					if (affRating.settings.groupOverall !== null) {
						affRating.settings.groupOverall.affRating.refresh();
					}
					if (affRating.settings.postVoteCallback !== null) {
						affRating.settings.postVoteCallback(response);
					}
					
					ratingThanks.html('<span class="ratingThanks">'+ affRating.settings.thanksMsg +'</span>');
					setTimeout(function(){
						jQuery(ratingThanks).find('.ratingThanks').fadeTo(400,0.1,function(){
							affRating.update(response);
						});
					},900);
				}
			},
			"json"
		);
	},
	update: function(settings) {
		if (settings) {
			this.initialized = false;
			jQuery.extend(this.settings, settings);
			this.init();
		}
	},
	refresh: function() {
		var affRating = this;
		jQuery.getJSON(this.settings.url, function(json) {affRating.update(json);});
	},
	fill: function(el) { // fill to the current mouse position.
		var index = this.controls.index(el);
		if (this.settings.ratingType == 'stars') {
			this.controls
				.children('a').css('width', '100%').end()
				.slice(0, index + 1).addClass('hover').end();
		} else {
			this.controls
				.slice(index, index + 1).addClass('hover');
		}
	},
	drain: function() { // drain all the stars.
		this.controls
			.filter('.on').removeClass('on').end()
			.filter('.hover').removeClass('hover').end();
	},
	reset: function(show) { // Reset the stars to the default index.
		if (this.settings.ratingType == 'stars') {
			if (show == undefined) {
				if (this.settings.curvalueType != 'userValue') {
					this.controls.slice(0, this.settings.overallValue / this.settings.increment).addClass('on').end();
				}
				this.controls.slice(0, this.settings.userValue / this.settings.increment).addClass('hover').end();
			} else {
				if (this.settings.curvalueType != 'userValue') {
					this.controls.slice(0, this.settings.curvalue / this.settings.increment).addClass('on').end();
				} else {
					this.controls.slice(0, this.settings.curvalue / this.settings.increment).addClass('hover').end();
				}
			}
		} else if (this.settings.ratingType == 'thumbs') {
			if (this.settings.curvalue > 0) {
				this.controls.slice(0, 1).addClass('on').find('a').html(this.settings.overallValueUp);
			} else if (this.settings.curvalue < 0) {
				this.controls.slice(1, 2).addClass('on').find('a').html(this.settings.overallValueDown);
			}
		}
	},
	setValue: function(value) {
		this.settings.curvalue = value;
		this.drain();
		this.reset();
	},
	showUserValue: function() {
		this.settings.curvalueType = 'userValue';
		this.setValue(this.settings.userValue);
	},
	showOverallValue: function() {
		this.settings.curvalueType = 'overallValue';
		this.setValue(this.settings.overallValue);
	},
	toggleValueType: function() {
		if (this.settings.curvalueType == 'overallValue') {
			this.showUserValue();
		} else {
			this.showOverallValue();
		}
	}
};

