"use strict";

/* Setup namespaces */
if (typeof(BCNTRY) === 'undefined') {
	BCNTRY = {};
}
if (typeof(BCNTRY.instantReview) === 'undefined') {
	BCNTRY.instantReview = {};
}

(function () {
	BCNTRY.instantReview = function () {
		return this;
	};

	BCNTRY.instantReview.prototype = {
		obj: {
			id: null,
			body: null,
			'class': 'InstantReview',
			dateCreated: null,
			lastUpdated: null,
			dealId: null,
			isFlagged: false,
			isThumbsUp: null,
			user: null
		},

		init: function (attr) {
			if (this.isValid(attr)) {
				for (var a in attr) {
					if (typeof(attr[a]) !== 'function') {
						if (a === 'class') {
							continue;
						}
						this.obj[a] = attr[a];
					}
				}
			}
		},

		/**
		 * Method for initializing an instant review from cookie data. The cookie data is expected
		 * to be a JSON serialized object. The user attribute will always be set to the current
		 * logged in user. This works for the current use case, but may have to be altered in the
		 * future if there is a need to pass an instant review by cookie that was not submitted
		 * by the current user.
		 */
		initByCookie: function (cookieName) {
			var obj = YAHOO.lang.JSON.parse(BCNTRY.util.readCookie(cookieName));
			if (!obj) {
				return;
			}
			obj.isFlagged = obj.isFlagged ? true : false;
			obj.isThumbsUp = obj.isThumbsUp ? true : false;
			obj.usedRealName = obj.usedRealName ? true : false;
			obj.user = BCNTRY.odatComm.currentUser;
			this.init(obj);
		},
	
		/**
		* Method for initializing a new instant review from a form.
		* This will put the instant review object in a state to be saved.
		*/
		initByForm: function (form) {
			if (form.elements.length > 0) {
				this.init({
					isThumbsUp: form.elements.isThumbsUp.value === '1' ? true : false,
					body: form.elements.reviewComment.value,
					dealId: BCNTRY.page_data.odat_id,
					user: BCNTRY.odatComm.currentUser
				});
			}
		},

		initById: function (id) {
			BCNTRY.odatComm.instantReviewManager.setIndexById();
			var review = BCNTRY.odatComm.instantReviewManager.indexById[id];
			this.init(review);
		},

		isValid: function (source) {
			if (typeof(source.id) !== 'undefined' && source.id !== null) {
				if (! YAHOO.lang.isNumber(parseInt(source.id, 10))) {
					return false;
				}
			}
			if (typeof(source.dealId) !== 'undefined' && source.dealId !== null) {
				if (! YAHOO.lang.isNumber(parseInt(source.dealId, 10))) {
					return false;
				}
			}
			else {
				return false;
			}
			if (source.body === null || source.body === "") {
				return false;
			}
			if (!source.user['class'].match(/User$/)) {
				return false;
			}
			if (source.isThumbsUp === null) {
				return false;
			}
			
			return true;
		},

		asJSON: function () {
			return YAHOO.lang.JSON.stringify(this.obj);
		},

		postSubmit: function (o) {
			var irm, irdm;
			irm = BCNTRY.odatComm.instantReviewManager;
			irdm = BCNTRY.odatComm.instantReviewDomManager;
			irm.mergeLatestIntoExisting();
			irm.setLatest(o.responseText);
			irdm.processLatest();
		},

		message: null, 
		
		submit: function (callback) {
			var submit_url, originalInstance;
			submit_url = '/' + BCNTRY.site.catalog + '/instantReview';
			originalInstance = this;
			BCNTRY.odatComm.asyncRequest('POST', submit_url, {
				success: function (o) {
					originalInstance.postSubmit(o);
					if (callback && callback.success) {
						callback.success(o);
					}
				},
				failure: function (o) {
					if (callback && callback.failure) {
						callback.failure(o);
					}
				},
				error: function (o) {
					if (callback && callback.error) {
						callback.error(o);
					}
				}
			}, this.asJSON());
		},
		
		asHTML: function () {
			return TrimPath.processDOMTemplate("review_full", this.obj);
		},

		/* Post a vote for helpful/unhelpful */
		castVote: function (callback, isHelpful) {
			var helpfulURL, args, originalInstance;
			helpfulURL = "/" + BCNTRY.site.catalog + "/instantReview/" + this.obj.id + "/vote";
			args = YAHOO.lang.JSON.stringify({
				'class': "InstantReviewVote",
				helpfulVote: isHelpful,
				user: BCNTRY.odatComm.currentUser
			});
			originalInstance = this;
			BCNTRY.odatComm.asyncRequest(
				'POST',
				helpfulURL,
				callback,
				args);
		},
		
		// Flag a review
		flag: function () {
			var flagURL, originalInstance, callback;
			if (!this.obj.id) {
				//TODO: real error handling
				if (window.console) {
					console.log('invalid review, it does not have an ID');
				}
				return;
			}
			flagURL = "/" + BCNTRY.site.catalog + "/instantReview/" + this.obj.id + "/toggleFlag";
			originalInstance = this;
			callback = {
				success: function (o) {
					BCNTRY.odatComm.instantReviewManager.updateInstantReviewData(o.responseText);
					BCNTRY.odatComm.instantReviewDomManager.redrawInstantReview(originalInstance.obj.id);
				},
				failure: function (o) {
					//TODO: real error handling
					if (window.console) {
						console.log('Failure to submit flag for instant review: ' + originalInstance.asJSON);
					}
				},
				error: function (o) {
					//TODO: real error handling
					if (window.console) {
						console.log('An error occurred when trying to flag instant review: ' + originalInstance.asJSON);
					}
				}
			};
			BCNTRY.odatComm.asyncRequest('PUT', flagURL, callback);
		},
		
		// Sets an error message.If the element passed is not "error_message",
		// it first recursively checks children for a div who's class is "error_message"
		set_error_message: function (el, message) {
			var s;
			if (el.className !== 'error_message') {
				el = YAHOO.util.Dom.getElementsByClassName('error_message', 'div', el)[0];
			}
	
			s = "<p>${message}</p>".process({ message: message});
			el.innerHTML = s;
		}
	};

	BCNTRY.InstantReviewManager = function () {
		this.latest = {};
		this.latestByThumb = {
			up: [],
			down: []
		};
		this.toBeUpdated = [];
		this.existing = BCNTRY.page_data.instant_reviews;
		this.indexById = {};
		return this;
	};

	BCNTRY.InstantReviewManager.prototype = {
		BUCKET_SIZE: 5,
		setLatest: function (irDataOrJSON) {
			var irData;
			if (typeof irDataOrJSON === 'string') {
				try {
					irData = YAHOO.lang.JSON.parse(irDataOrJSON);
				}
				catch (err) {
					if (typeof(console) !== 'undefined') {
						console.log("There was an error parsing some JSON: " + err);
					}
					return;
				}
			}
			else {
				irData = irDataOrJSON;
			}
			this.latest = irData;
			this.removeDuplicates();
			this.setIndexById();
		},

		addToLatest: function (irObj) {
			var epoch, bucket, upDown;
			BCNTRY.dc = irObj.dateCreated;
			epoch = Date.parse(irObj.dateCreated) / 1000;
			bucket = this.getBucket(epoch);
			upDown = irObj.isThumbsUp ? 'up' : 'down';
			irObj.secondsDateCreated = epoch;
			//make sure bucket exists
			if (typeof(this.latest.buckets[bucket]) === 'undefined') {
				this.latest.buckets[bucket] = {};
			}
			//make sure sub-bucket exists (up or down)
			if (typeof(this.latest.buckets[bucket][upDown]) === 'undefined') {
				this.latest.buckets[bucket][upDown] = [];
			}
			//add this ir
			this.latest.buckets[bucket][upDown].push(irObj);
			//update total_thumbs_[up/down]
			this.latest['total_thumbs_' + upDown] += 1;

			//this causes it to not show up in the bubble area, but I can't figure
			//out how to make it show there w/out it showing twice below, so I'm
			//leaving this for now. -Dustin
			this.removeDuplicates();
		},

		existsInLatest: function(irObj) {
			var foundMatch = false;
			this.navigateBucketsToReview(this.latest.buckets, function(review, bucketId, arrayIndex) {
				if (review.id == irObj.id) {
					foundMatch = true;
				}
			});
			return foundMatch;
		},
	
		fetchLatest: function (irObjToInject) {
			var fetch_url, originalInstance, index;
			//the fetch url has a cache buster because we were having problems
			//with IE caching when we didn't want it to.
			fetch_url = '/' + BCNTRY.site.catalog +
				 //'/instantReview/deal/' +
				 //BCNTRY.page_data.odat_id +
				 //'/' + (parseInt(BCNTRY.odat.refreshInterval, 10) / 1000) * 2;
				 '/instantReview/currentDealRecent.js';
			this.toBeUpdated = [];
			originalInstance = this;
			BCNTRY.odatComm.asyncRequest('GET', fetch_url, {
				success: function (o) {
					originalInstance.mergeLatestIntoExisting();
					originalInstance.setLatest(o.responseText);
					if (irObjToInject && !originalInstance.existsInLatest(irObjToInject)) {
						originalInstance.addToLatest(irObjToInject);
					}
					BCNTRY.odatComm.instantReviewDomManager.processLatest();
					BCNTRY.odatComm.instantReviewDomManager.updateAllTimeAgo();
					BCNTRY.odatComm.instantReviewDomManager.renderLatestBubbles();

					// update existing instant reviews
					for (index in originalInstance.toBeUpdated) {
						if (typeof(originalInstance.toBeUpdated[index]) !== 'function') {
							originalInstance.updateInstantReviewData(
								originalInstance.toBeUpdated[index]
							);
							BCNTRY.odatComm.instantReviewDomManager.redrawInstantReview(
								originalInstance.toBeUpdated[index].id);
						}
					}
				},
				failure: function (o) {
					if (window.console) {
						console.log('Fail');
					}
				},
				error: function (o) {
					if (window.console) {
						console.log('Error!');
					}
				}
			});
		},

		mergeLatestIntoExisting: function () {
			var bucketId, existing_ids, i, id;
			for (bucketId in this.latest.buckets) {
				// All buckets that don't already exist copy to existing list.
				if (typeof this.existing.buckets[bucketId] === 'undefined') {
					this.existing.buckets[bucketId] = this.latest.buckets[bucketId];
					//console.log('copied bucket ID: ' + bucketId + 'into existing');
				}
				else {
					if (typeof this.existing.buckets[bucketId].up === 'undefined') {
						this.existing.buckets[bucketId].up = this.latest.buckets[bucketId].up;
						//console.log('copied up from bucket: ' + bucketId + 'into existing');
					}
					else {
						existing_ids = {};
						for (i in this.existing.buckets[bucketId].up) {
							if (typeof(this.existing.buckets[bucketId].up[i]) !== 'function') {
								id = this.existing.buckets[bucketId].up[i].id;
								existing_ids[id] = i;
							}
						}
						for (i in this.latest.buckets[bucketId].up) {
							if (typeof(this.latest.buckets[bucketId].up[i]) !== 'function') {
								id = this.latest.buckets[bucketId].up[i].id;
								if (typeof existing_ids[id] === 'undefined') {
									this.existing.buckets[bucketId].up.push(
										this.latest.buckets[bucketId].up[i]
									);
								}
							}
						}
					}

					if (typeof this.existing.buckets[bucketId].down === 'undefined') {
						this.existing.buckets[bucketId].down = this.latest.buckets[bucketId].down;
						//console.log('copied down from bucket: ' + bucketId + 'into existing');
					}
					else {
						existing_ids = {};
						for (i in this.existing.buckets[bucketId].down) {
							if (typeof(this.existing.buckets[bucketId].down[i]) !== 'function') {
								id = this.existing.buckets[bucketId].down[i].id;
								existing_ids[id] = i;
							}
						}
						for (i in this.latest.buckets[bucketId].down) {
							if (typeof(this.latest.buckets[bucketId].down[i]) !== 'function') {
								id = this.latest.buckets[bucketId].down[i].id;
								if (typeof existing_ids[id] === 'undefined') {
									this.existing.buckets[bucketId].down.push(
										this.latest.buckets[bucketId].down[i]
									);
								}
							}
						}
					}
				}
			}
			this.setIndexById();
			this.existing.total_thumbs_up += this.latest.total_thumbs_up || 0;
			this.existing.total_thumbs_down += this.latest.total_thumbs_down || 0;
		},

		setIndexById: function () {
			var originalInstance, loopCallback;
			originalInstance = this;
			loopCallback = function (review, bucketId, arrayIndex) {
				originalInstance.indexById[review.id] = review;
			};
			this.navigateBucketsToReview(this.latest.buckets, loopCallback);
			this.navigateBucketsToReview(this.existing.buckets, loopCallback);
		},

		removeDuplicates: function () {
			var existingInstantReviewsById, existing, latest, deleteMap, bucket, thumbArray, i, id, latestIR, existingIR, deletedInBucket, dobj;
			existingInstantReviewsById = {}; 
			existing = this.existing.buckets;
			latest = this.latest.buckets;

			this.navigateBucketsToReview(existing, function (review, bucketId, index) {
				existingInstantReviewsById[review.id] = review;
			});

			deleteMap = [];
			BCNTRY.util.foreach(latest, function (bucket, bucketId) {
				BCNTRY.util.foreach(bucket, function (thumbArray, upDown) {
					BCNTRY.util.foreach(thumbArray, function (ir, i) {
						if (typeof(existingInstantReviewsById[ir.id]) !== 'undefined') {
							latestIR = ir;
							existingIR = existingInstantReviewsById[ir.id];
							if (existingIR.lastUpdated !== latestIR.lastUpdated) {
								this.toBeUpdated.push(latestIR);
							}
							deleteMap.push({"bucket": bucketId, "thumbArray": upDown, "index": i});
						}
					}, this);
				}, this);
			}, this);

			deletedInBucket = {};
			BCNTRY.util.foreach(deleteMap, function (dobj, i) {
				if (typeof deletedInBucket[dobj.bucket] === 'undefined') {
					deletedInBucket[dobj.bucket] = 0;
				}

				latest[dobj.bucket][dobj.thumbArray].splice((dobj.index - deletedInBucket[dobj.bucket]), 1);
				//console.log('removed index: ' + dobj.index + 'from bucket ' + dobj.bucket + ' in thumb' + dobj.thumbArray);
				deletedInBucket[dobj.bucket] += 1;
				if (typeof this.latest['total_thumbs_' + dobj.thumbArray] !== 'undefined') {
					this.latest['total_thumbs_' + dobj.thumbArray] -= 1;
				}

				if (latest[dobj.bucket][dobj.thumbArray].length === 0) {
					delete latest[dobj.bucket][dobj.thumbArray];
					//console.log('removed thumb: ' + dobj.thumbArray + 'from bucket: ' + dobj.bucket);
				}
				if (
					typeof(latest[dobj.bucket].up) === 'undefined' &&
					typeof(latest[dobj.bucket].down) === 'undefined') {
					delete latest[dobj.bucket];
					//console.log('removed bucket: ' + dobj.bucket);
				}
			}, this);
		},

		// Iterator for going though a bucket list and getting at a review.
		navigateBucketsToReview: function (bucketList, callback) {
			var sortedBuckets, bucketId, index, thumbArray, i, sortNumericallyDesc;

			sortNumericallyDesc = function (a, b) {
				var i1, i2, result;
				i1 = parseInt(a, 10);
				i2 = parseInt(b, 10);
				result = ((i1 > i2) ? 1 : (i1 < i2) ? - 1 : 0);
				return result;
			};

			sortedBuckets = [];
			BCNTRY.util.foreach(bucketList, function (bucket, bucketId) {
				sortedBuckets.push(bucketId);
			});
			sortedBuckets.sort(sortNumericallyDesc);

			BCNTRY.util.foreach(sortedBuckets, function (bucketId) {
				BCNTRY.util.foreach(bucketList[bucketId], function (thumbArray) {
					BCNTRY.util.foreach(thumbArray, function (ir, i) {
						// Call callback and pass in instant review;
						callback(ir, bucketId, i);
					});
				});
			});
		},

		getBucket: function (time) {
			if (typeof(time) !== 'number') {
				time = Date.parse(time) / 1000;
			}
			return parseInt(time / this.BUCKET_SIZE, 10) * this.BUCKET_SIZE;
		},

		updateInstantReviewData: function (irDataOrJSON) {
			var irData;
			if (typeof irDataOrJSON === 'string') {
				try {
					irData = YAHOO.lang.JSON.parse(irDataOrJSON);
				}
				catch (err) {
					if (typeof(console) !== 'undefined') {
						console.log("There was an error parsing some JSON: " + err);
					}
					return;
				}
			}
			else {
				irData = irDataOrJSON;
			}
			if (typeof irData.secondsDateCreated === 'undefined') {
				irData.secondsDateCreated = Date.parse(irData.dateCreated) / 1000;
			}
			this.indexById[irData.id] = irData;
		},

		getLatestByThumb: function () {
			var originalInstance, loopCallback, thumb;
			if (typeof this.latest.buckets !== 'undefined') {
				originalInstance = this;
				loopCallback = function (review, bucketId, arrayIndex) {
					thumb = review.isThumbsUp ? 'up' : 'down';
					if (typeof review !== 'undefined') {
						originalInstance.latestByThumb[thumb].push(review);
					}
				};
				this.navigateBucketsToReview(this.latest.buckets, loopCallback);
				return originalInstance.latestByThumb;
			}
		},

		getBubbleDataForDisplay: function () {
			var bubbleArray, newThumb;
			bubbleArray = [];
			if (this.latestByThumb.up.length > 0) {
				bubbleArray.push(this.latestByThumb.up.shift());
			}
			if (this.latestByThumb.down.length > 0) {
				bubbleArray.push(this.latestByThumb.down.shift());
			}
			if (bubbleArray.length === 0) {
				return;
			}
			if (bubbleArray.length === 1) {
				newThumb = bubbleArray[0].isThumbsUp ? 'up' : 'down';
				if (this.latestByThumb[newThumb].length > 0) {
					bubbleArray.push(this.latestByThumb[newThumb].shift());
				}
			}

			return bubbleArray;
		}
	};

	BCNTRY.InstantReviewDomManager = function (irm) {
		this.instantReviewManager = irm;
		return this;
	};

	BCNTRY.InstantReviewDomManager.prototype = {
		DISPLAY_BUBBLES_FOR: 8000, // In ms
		SLEEP_BETWEEN_BUBBLES: 7000, // In ms
		addBucket: function (bucketId) {
			var newBucketDiv, upDiv, downDiv, lastBucketDiv, originalInstance;
			if ($('bucket_' + bucketId) !== null) {
				// Bucket exists;
				return; 
			}
			originalInstance = this;

			newBucketDiv = document.createElement('div');
			YAHOO.util.Dom.setAttribute(newBucketDiv, 'id', 'bucket_' + bucketId);
			YAHOO.util.Dom.addClass(newBucketDiv, 'reviews_bucket');

			upDiv = document.createElement('div');
			YAHOO.util.Dom.addClass(upDiv, 'bucketUp');
			YAHOO.util.Dom.setAttribute(upDiv, 'id', 'bucket_' + bucketId + '_up');

			downDiv = document.createElement('div');
			YAHOO.util.Dom.addClass(downDiv, 'bucketDown');
			YAHOO.util.Dom.setAttribute(downDiv, 'id', 'bucket_' + bucketId + '_down');

			newBucketDiv.appendChild(upDiv);
			newBucketDiv.appendChild(downDiv);

			lastBucketDiv = YAHOO.util.Dom.getNextSibling(YAHOO.util.Dom.getFirstChild('reviews_wall'));
			if (lastBucketDiv !== null) {
				YAHOO.util.Dom.insertBefore(newBucketDiv, lastBucketDiv);
			}
			else {
				$('reviews_wall').appendChild(newBucketDiv);
			}
		},
		addInstantReview: function (irData, bucketId) {
			var newReviewDiv, innerHtml, originalInstance;
			if (! $('bucket_' + bucketId)) {
				throw ('Could not find element with id: ' + bucketId);
			}
			if (!YAHOO.lang.isNumber(parseInt(irData.id, 10))) {
				throw ('Instant review is not valid. ID is: ' + irData.id);
			}

			originalInstance = this;
			newReviewDiv = document.createElement('div');
			YAHOO.util.Dom.setAttribute(newReviewDiv, 'id', 'instant_review_' + irData.id);
			YAHOO.util.Dom.addClass(newReviewDiv, 'review');
			YAHOO.util.Dom.addClass(newReviewDiv, originalInstance.getBubblePosition());

			innerHtml = this.processInstantReviewTemplate(irData);			
			newReviewDiv.innerHTML = innerHtml;
			if (Boolean(irData.isThumbsUp)) {
				$('bucket_' + bucketId + '_up').appendChild(newReviewDiv);
			}
			else {
				$('bucket_' + bucketId + '_down').appendChild(newReviewDiv);
			}
		},
		processInstantReviewTemplate: function (templateData) {
			templateData.time_ago = this.calcTimeAgo(templateData);
			return TrimPath.processDOMTemplate("review_full", templateData);
		},
		calcTimeAgo: function (irData) {
			var seconds, now, secondsAgo, minutesAgo, hoursAgo, dateString;
			if (YAHOO.lang.isNumber(irData.secondsDateCreated)) {
				seconds = irData.secondsDateCreated;
				now = new Date();
				//convert from ms to sec.
				now = parseInt(now.getTime() / 1000, 10);
				secondsAgo = ((now - seconds) - BCNTRY.page_data.offset_seconds);
				if (secondsAgo < 0) {
					secondsAgo = 0;
				}
				minutesAgo = parseInt((secondsAgo / 60), 10);
				hoursAgo = parseInt((minutesAgo / 60), 10);
				dateString = new Date();
				dateString.setTime(seconds * 1000);

				if (secondsAgo < 60) {
					return secondsAgo + " seconds ago"; 
				}
				if (minutesAgo < 60) {
					return minutesAgo + " minutes ago"; 
				}
				if (hoursAgo < 24) {
					return hoursAgo + " hours ago"; 
				}
				return dateString.toDateString();
			}
		},
		updateAllTimeAgo: function () {
			var indexById, index;
			indexById = this.instantReviewManager.indexById;
			BCNTRY.util.foreach(indexById, function (ir, index) {
				$('ir_' + index + '_dateCreated').innerHTML =
					this.calcTimeAgo(ir);
			}, this);
		},
		processLatest: function () {
			var latest, originalInstance;
			latest = this.instantReviewManager.latest.buckets;
			originalInstance = this;
			this.instantReviewManager.navigateBucketsToReview(latest,
				function (review, bucketId) {
					originalInstance.addBucket(bucketId);
					originalInstance.addInstantReview(review, bucketId);
				}
			);
			this.updateTotalThumbCounts();
		},
		updateTotalThumbCounts: function () {
			var latest, existing, totalUp, totalDown;
			latest = this.instantReviewManager.latest;
			existing = this.instantReviewManager.existing;
			totalUp = latest.total_thumbs_up + existing.total_thumbs_up;
			totalDown = latest.total_thumbs_down + existing.total_thumbs_down;
			$('review_totalUp').innerHTML = totalUp;
			$('review_totalDown').innerHTML = totalDown;
			$('thumbsUp_total').innerHTML = totalUp;
			$('thumbsDown_total').innerHTML = totalDown;
		},
		redrawInstantReview: function (instantReviewId) {
			var irData;
			irData = this.instantReviewManager.indexById[instantReviewId];
			$('instant_review_' + instantReviewId).innerHTML =
				this.processInstantReviewTemplate(irData);
			if (Boolean(irData.isFlagged) === true) {
				BCNTRY.odatComm.instantReviewDomManager.toggleFlaggedDisplay(irData.id, true);
			}
		},
		renderLatestBubbles: function () {
			var originalInstance, addBubblesToDOM, startBubbleDisplay;
			originalInstance = this;

			addBubblesToDOM = function (irDataArray) {
				var bubblesToAnimate, irIndex, ir, bubbleDiv;
				bubblesToAnimate = [];

				for (irIndex in irDataArray) {
					if (typeof irDataArray[irIndex] !== 'undefined') {
						ir = irDataArray[irIndex];
						ir.thumbDirection = ir.isThumbsUp ? 'up' : 'down';
						bubbleDiv = document.createElement('div');
						YAHOO.util.Dom.addClass(bubbleDiv, 'bubble_' + ir.thumbDirection);

						// Assign a "random" position
						YAHOO.util.Dom.addClass(bubbleDiv, originalInstance.getBubblePosition());

						bubbleDiv.innerHTML = TrimPath.processDOMTemplate("review_bubble", ir);
						$('bubbles_up_down').appendChild(bubbleDiv);
						bubblesToAnimate.push(bubbleDiv);
					}
				}
				return bubblesToAnimate;
			};

			startBubbleDisplay = function () {
				var currentBubbleArray, bubblesToAnimate, toTop;
				if (BCNTRY.page_data.bubbleDisplayState === 'off') {
					return;
				}
				currentBubbleArray = originalInstance.instantReviewManager.getBubbleDataForDisplay();

				if (
					typeof currentBubbleArray !== 'undefined' &&
						currentBubbleArray.length > 0 &&
						typeof currentBubbleArray[0] !== 'undefined') {

					bubblesToAnimate = addBubblesToDOM(currentBubbleArray);
					toTop = [60, 60];
					if (bubblesToAnimate.length > 1 &&
							bubblesToAnimate[0].className === bubblesToAnimate[1].className) {
						toTop[0] = 60;
						toTop[1] = 200;
					}
					originalInstance.fadeInAndUp(bubblesToAnimate[0], toTop[0]);
					setTimeout(
						function () {
							originalInstance.fadeInAndUp(
								bubblesToAnimate[1],
								toTop[1]
							);
						},
						500);
					setTimeout(
						originalInstance.clearBubbles,
						originalInstance.DISPLAY_BUBBLES_FOR);
				}
			};
			this.instantReviewManager.getLatestByThumb();

			startBubbleDisplay();
			setTimeout(
				startBubbleDisplay,
				(this.DISPLAY_BUBBLES_FOR + this.SLEEP_BETWEEN_BUBBLES)
			);
		},

		getBubblePosition: function () {
			var positions, bubble_position;
			positions = [];
			positions = [ 
				"bubble_position_1", 
				"bubble_position_2",
				"bubble_position_3", 
				"bubble_position_4"
			];
			bubble_position = positions[Math.floor(Math.random() * positions.length)];
			return bubble_position;
		},

		fadeInAndUp: function (el, topTo) {
			var anim;
			anim = new YAHOO.util.Anim(el);
			anim.attributes.top = { to: topTo, from: 380 };
			anim.attributes.opacity = { to: 1, from: 0 };
			anim.duration = 1;
			anim.method = YAHOO.util.Easing.easeOut;
			anim.onStart.subscribe(function () {
				YAHOO.util.Dom.setStyle(el, 'display', 'block');
			});
			anim.animate();
		},

		clearBubbles: function () {
			fade_out('bubbles_up_down');
			$('bubbles_up_down').innerHTML = '';
			fade_in('bubbles_up_down');
		},
		
		toggleFlaggedDisplay: function (reviewId, isDisplayed) {
			var displayString, displayString2;
			displayString = Boolean(isDisplayed) ? 'block' : 'none';
			displayString2 = Boolean(!isDisplayed) ? 'block' : 'none';
			YAHOO.util.Dom.setStyle('bubble_' + reviewId + '_flagged', 'display', displayString);
			YAHOO.util.Dom.setStyle('bubble_' + reviewId + '_contents', 'display', displayString2);
		}
	};
})();

