/*
Name		:	Component - Game Ratings
Author/s	:	Yang Wong
Related		:	php, css, js
*/

// CLASS //

var COM_CIPHERCITIES_GAMERATINGS = Class.create();
COM_CIPHERCITIES_GAMERATINGS.prototype =
{

	// CONSTRUCTOR //

	initialize: function()
	{
		// CONSTANTS //

		this.LEVEL_VIEW					= 1; // view
		this.LEVEL_DELETE				= 2; // view, delete
		this.LEVEL_EDIT					= 3; // view, delete, edit

		this.RATINGS_SORTID				= COM_CIPHERCITIES_GLOBALS.SORT_LATEST;
		this.RATINGS_SHOWTOTAL			= 3;
		this.RATINGS_SHOWTOTALPAGES		= 10;

		this.COMMENT_TOTALLENGTH		= 300;

		this.DEFAULT_RATING				= 5;

		this.ERROR_RATINGSNOTRETRIEVED	= 'Rating(s) could not be retrieved. Please try again later.';
		this.ERROR_RATINGNOTADDED		= 'Rating could not be added. Please try again later.';
		this.ERROR_RATINGNOTEDITED		= 'Rating could not be edited. Please try again later.';
		this.ERROR_RATINGNOTDELETED		= 'Rating could not be deleted. Please try again later.';
		this.ERROR_COMMENTEMPTY			= 'Please write a comment and try again.';
		this.ERROR_COMMENTTOOLONG		= 'Comment contains too many characters.';
		this.ERROR_COMMENTINVALID		= 'Comment contains html/script elements.';

		this.SUCCESS_RATINGADDED		= 'Rating was successfully added.';
		this.SUCCESS_RATINGDELETED		= 'Rating was successfully deleted.';
		this.SUCCESS_RATINGEDITED		= 'Rating was successfully edited.';

		// PROPERTIES //

		this.ratingSlider 				= null;
	},

	// INITIALISATION //

	init: function()
	{
		// Initialise status
		$('gameratingsstatus').hide();
		$('gameratingsstatus').removeClassName('com_hidden');

		// Initialise ratings
		var i = 0;
		while ($('gameratingsrating'+i))
		{
			// Control
			if ($('gameratingsratingmodify'+i))
			{
				Event.observe('gameratingsratingmodify'+i, 'click', this.toggleRatingControl.bind(this, i));
			}
			$('gameratingsratingcontrol'+i).hide();
			$('gameratingsratingcontrol'+i).removeClassName('hidden');
			// Actions
			if ($('gameratingsratingedit'+i))
			{
				Event.observe('gameratingsratingedit'+i, 'click', this.editRating.bind(this, i));
			}
			if ($('gameratingsratingdelete'+i))
			{
				Event.observe('gameratingsratingdelete'+i, 'click', this.deleteRating.bind(this, i));
			}
			i++;
		}

		// Initialise pages
		if ($('gameratingspagetotal'))
		{
			var i = 1;
			while ($('gameratingspage'+i))
			{
				Event.observe('gameratingspage'+i, 'click', this.getRatings.bind(this, i));
				i++;
			}
			var numPages = Math.ceil($('gameratingspagetotal').innerHTML / this.RATINGS_SHOWTOTAL);
			if (numPages > i)
			{
				Event.observe('gameratingspage'+numPages, 'click', this.getRatings.bind(this, numPages));
			}
		}

		// Initialise input
		if ($('gameratingsinput'))
		{
			// Slider
			this.ratingSlider = new Control.Slider('gameratingsinputhandle','gameratingsinputtrack', {range:$R(0, 10), sliderValue:$('gameratingsuserrating').innerHTML, alignX:7, values:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]});
			this.ratingSlider.options.onSlide = this.updateRatingSlider.bind(this);
			this.ratingSlider.setValue($('gameratingsuserrating').innerHTML);
			// Actions
			Event.observe('gameratingsinputcomment', 'keydown', COM_CIPHERCITIES_COMMON.updateCharacterCount.bind(this, $('gameratingsinputcomment'), $('gameratingscharcount'), this.COMMENT_TOTALLENGTH));
			Event.observe('gameratingsinputcomment', 'keyup', COM_CIPHERCITIES_COMMON.updateCharacterCount.bind(this, $('gameratingsinputcomment'), $('gameratingscharcount'), this.COMMENT_TOTALLENGTH));
			COM_CIPHERCITIES_COMMON.updateCharacterCount($('gameratingsinputcomment'), $('gameratingscharcount'), this.COMMENT_TOTALLENGTH);
			if ($('gameratingsaddrating'))
			{
				Event.observe('gameratingsaddrating', 'click', this.addRating.bind(this));
			}
			if ($('gameratingseditrating'))
			{
				Event.observe('gameratingseditrating', 'click', this.editUserRating.bind(this));
			}
			if ($('gameratingsdeleterating'))
			{
				Event.observe('gameratingsdeleterating', 'click', this.deleteUserRating.bind(this));
			}
		}
	},

	// HELPER //

	formatComment: function(comment)
	{
		comment = COM_CIPHERCITIES_COMMON.shortenLength(comment, this.COMMENT_TOTALLENGTH);
		return COM_CIPHERCITIES_COMMON.insertIntoWordsOfLength(comment, '<br />', 23);
	},

	unformatComment: function(comment)
	{
		return comment.replace(/<BR>/gi, '');
	},

	canModify: function(accessLevelID)
	{
		return (accessLevelID == this.LEVEL_DELETE || accessLevelID == this.LEVEL_EDIT);
	},

	canEdit: function(accessLevelID)
	{
		return (accessLevelID == this.LEVEL_EDIT);
	},

	canDelete: function(accessLevelID)
	{
		return (accessLevelID == this.LEVEL_DELETE || accessLevelID == this.LEVEL_EDIT);
	},

	showStatusError: function(message)
	{
		COM_CIPHERCITIES_COMMON.showStatusError('gameratingsstatus', message);
	},

	showStatusSuccess: function(message)
	{
		COM_CIPHERCITIES_COMMON.showStatusSuccess('gameratingsstatus', message);
	},

	showStatusLoading: function(message)
	{
		COM_CIPHERCITIES_COMMON.showStatusLoading('gameratingsstatus', message);
	},

	clearStatus: function()
	{
		COM_CIPHERCITIES_COMMON.clearStatus('gameratingsstatus');
	},

	formatRatingLabel: function(value)
	{
		switch (value)
		{
		case 0 :
		case 1 :
			return 'Terrible';
		case 2 :
		case 3 :
			return 'Poor';
		case 4 :
		case 5 :
			return 'Okay';
		case 6 :
		case 7 :
			return 'Good';
		case 8 :
		case 9 :
			return 'Great';
		case 10 :
			return 'Brilliant';
		default :
			return null;
		}
	},

	// ACTIONS //

	toggleRatingControl: function(i)
	{
		// Toggle visibility
		$('gameratingsratingcontrol'+i).toggle();

		// If showing controls
		if ($('gameratingsratingmodify'+i).src.split('/').pop() == COM_CIPHERCITIES_GLOBALS.BT_MAXIMISE_I)
		{
			// Clear status
			this.clearStatus();

			// Switch image
			$('gameratingsratingmodify'+i).src = COM_CIPHERCITIES_GLOBALS.PA_COMMONIMAGES+COM_CIPHERCITIES_GLOBALS.BT_MINIMISE_I;

			// Switch classes
			$('gameratingsratingmiddle'+i).removeClassName('gameratingsratingmiddledisplay');
			$('gameratingsratingmiddle'+i).addClassName('gameratingsratingmiddleedit');

			// Store current rating and set rating to editable
			var rating = $('gameratingsratingratingrating'+i).innerHTML;
			var html = '';
			html += '<div id="gameratingsratingratingstored'+i+'" class="com_hidden">'+rating+'</div>';
			html += '<select class="gameratingsratingratinginput" id="gameratingsratingratinginput'+i+'">';
			for (var j=0; j<11; j++)
			{
				html += '<option value="'+j+'"';
				if (j == rating) html += ' selected';
				html += '>['+j+'] '+this.formatRatingLabel(j)+'</option>';
			}
			html += '</select>';
			$('gameratingsratingrating'+i).update(html);

			// Store current comment and set comment to editable
			var comment = $('gameratingsratingcomment'+i).immediateDescendants()[0].innerHTML;
			var html = '';
			html += '<div id="gameratingsratingcommentstored'+i+'" class="hidden">'+comment+'</div>';
			html += '<div id="gameratingsratingtimestampstored'+i+'" class="com_hidden">'+$('gameratingsratingtimestamp'+i).innerHTML+'</div>';
			html += '<textarea id="gameratingsratingcommentinput'+i+'">'+this.unformatComment(comment)+'</textarea>';
			html += '<div class="com_charcount">Characters Left: <span id="gameratingsratingcharcount'+i+'"></span></div>';
			$('gameratingsratingcomment'+i).update(html);
			COM_CIPHERCITIES_COMMON.updateCharacterCount($('gameratingsratingcommentinput'+i), $('gameratingsratingcharcount'+i), this.COMMENT_TOTALLENGTH);
			Event.observe('gameratingsratingcommentinput'+i, 'keydown', COM_CIPHERCITIES_COMMON.updateCharacterCount.bind(this, $('gameratingsratingcommentinput'+i), $('gameratingsratingcharcount'+i), this.COMMENT_TOTALLENGTH));
			Event.observe('gameratingsratingcommentinput'+i, 'keyup', COM_CIPHERCITIES_COMMON.updateCharacterCount.bind(this, $('gameratingsratingcommentinput'+i), $('gameratingsratingcharcount'+i), this.COMMENT_TOTALLENGTH));
		}

		// If hiding controls
		else
		{
			// Clear status
			this.clearStatus();

			// Switch image
			$('gameratingsratingmodify'+i).src = COM_CIPHERCITIES_GLOBALS.PA_COMMONIMAGES+COM_CIPHERCITIES_GLOBALS.BT_MAXIMISE_I;

			// Switch classes
			$('gameratingsratingmiddle'+i).removeClassName('gameratingsratingmiddleedit');
			$('gameratingsratingmiddle'+i).addClassName('gameratingsratingmiddledisplay');

			// Set rating to uneditable and remove stored rating
			var rating = $('gameratingsratingratingstored'+i).innerHTML;
			var html = '<span class="gameratingsratingratinglabel">[<span id="gameratingsratingratingrating'+i+'">'+rating+'</span>] '+this.formatRatingLabel(parseInt(rating))+'</span>';
			$('gameratingsratingrating'+i).update(html);

			// Set comment to uneditable and remove stored comment
			var html = '';
			html += '<p>'+$('gameratingsratingcommentstored'+i).innerHTML+'</p>';
			html += '<div class="com_timestamp" id="gameratingsratingtimestamp'+i+'">';
			html += $('gameratingsratingtimestampstored'+i).innerHTML;
			html += '</div>';
			$('gameratingsratingcomment'+i).update(html);
		}
	},

	updateRatingSlider: function(value)
	{
		var rating = '[<span id="gameratingsuserrating">'+value+'</span>] ';
		switch (value)
		{
		case 0 :
		case 1 :
			rating += "Terrible";
			break;
		case 2 :
		case 3 :
			rating += "Poor";
			break;
		case 4 :
		case 5 :
			rating += "Okay";
			break;
		case 6 :
		case 7 :
			rating += "Good";
			break;
		case 8 :
		case 9 :
			rating += "Great";
			break;
		case 10 :
			rating += "Brilliant";
			break;
		}
		$('gameratingsinputrating').update(rating);
	},

	getRatings: function(page)
	{
		// Draw loading state
		this.showStatusLoading();
		$('gameratingsratings').hide();
		$('gameratingspages').hide();

		// Get Ratings
		var target = 'getGameRatings';
		var data = new Object();
		data.gameID = $('gameratingsgameid').innerHTML;
		data.sortID = this.RATINGS_SORTID;
		data.start = (page-1)*this.RATINGS_SHOWTOTAL;
		data.size = this.RATINGS_SHOWTOTAL;
		var args =
		{
			method: 'get',
			parameters: {target: target, data: Object.toJSON(data), v: Date()},
			onSuccess: this.processGetRatings.bindAsEventListener(this, page)
		}
		new Ajax.Request(COM_CIPHERCITIES_GLOBALS.HANDLER_MAIN, args);
	},

	processGetRatings: function(data, page)
	{
		var response = data.responseText.evalJSON(true);

		if (response.logout)
		{
			COM_CIPHERCITIES_COMMON.loadURLLogout();
			return;
		}

		if (!response.success)
		{
			this.showStatusError(this.ERROR_RATINGSNOTRETRIEVED);
			return;
		}

		this.drawRatings(response.data, page);
	},

	drawRatings: function(data, page)
	{
		// Ratings <
		var html = '';

			// If there are no ratings
			if (data.ratings.length < 1)
			{
				html += '<div class="com_empty_list">No Ratings</div>';
			}

			// If there are ratings
			else
			{
				var i = 0;
				while (i < this.RATINGS_SHOWTOTAL)
				{
					var rating = data.ratings[i];

					// If there are no more ratings to draw
					if (rating == null) break;

					// If there is a rating to draw

					// Rating <
					html += '<div id="gameratingsrating'+i+'" class="com_node'+(i % 2)+'">';

						// Wrapper <
						html += '<div class="node_wrapper">';

						// Variables <
						html += '<div class="hidden">';
							html += '<div id="gameratingsratingusername'+i+'">'+rating.username+'</div>';
						html += '</div>';
						// > Variables

						// Top <
						var username = COM_CIPHERCITIES_COMMON.shortenLength(rating.username, 29, true);
						html += '<div class="gameratingsratingtop">';
							html += '<a href="'+COM_CIPHERCITIES_COMMON.getURLUserProfile(rating.username)+'" class="gameratingsratingusername">'+username+'</a>';
							if (this.canModify(rating.accessLevelID))
							{
								html += '<img src="'+COM_CIPHERCITIES_GLOBALS.PA_COMMONIMAGES+COM_CIPHERCITIES_GLOBALS.BT_MAXIMISE_I+'" alt="Modify Rating" id="gameratingsratingmodify'+i+'" />';
							}
						html += '</div>';
						// > Top

						// Middle <
						html += '<div class="gameratingsratingmiddledisplay" id="gameratingsratingmiddle'+i+'">';

							// Middle Left <
							html += '<div class="gameratingsratingmiddleleft">';
								html += '<a href="'+COM_CIPHERCITIES_COMMON.getURLUserProfile(rating.username)+'">';
									html += '<img src="'+COM_CIPHERCITIES_COMMON.getImageUserMedium(rating.image)+'" alt="'+rating.username+'" class="com_img_frame" />';
								html += '</a>';
							html += '</div>';
							// > Middle Left

							// Middle Right <
							html += '<div class="gameratingsratingmiddleright">';
								html += '<div id="gameratingsratingrating'+i+'">';
									html += '<span class="gameratingsratingratinglabel">[<span id="gameratingsratingratingrating'+i+'">'+rating.rating+'</span>] '+this.formatRatingLabel(parseInt(rating.rating))+'</span>';
								html += '</div>';
								html += '<div id="gameratingsratingcomment'+i+'">';

									html += '<p>'+this.formatComment(rating.comment)+'</p>';

									if (rating.edited == null)
									{
										var status = 'Added ';
										var timestamp = COM_CIPHERCITIES_COMMON.getTimeAgo(
																						   COM_CIPHERCITIES_COMMON.formatTimestamp(rating.posted),
																						   COM_CIPHERCITIES_COMMON.formatTimestamp(data.servertime),
																						   2
																						   );
									}
									else
									{
										var status = 'Edited ';
										var timestamp = COM_CIPHERCITIES_COMMON.getTimeAgo(
																						   COM_CIPHERCITIES_COMMON.formatTimestamp(rating.edited),
																						   COM_CIPHERCITIES_COMMON.formatTimestamp(data.servertime),
																						   2
																						   );
									}
									html += '<div class="com_timestamp" id="gameratingsratingtimestamp'+i+'">';
										html += status+timestamp;
									html += '</div>';

								html += '</div>';
							html += '</div>';
							// > Middle Right

						html += '</div>';
						// > Middle

						html += '</div>';
						// > Wrapper

						// Clear <
						html += '<span class="com_float_clear"></span>';
						// > Clear

						// Bottom <
						html += '<div class="gameratingsratingbottom hidden" id="gameratingsratingcontrol'+i+'">';
							html += '<div id="gameratingsratingactions'+i+'">';
								if (this.canDelete(rating.accessLevelID))
								{
									html += '<input type="button" value="Delete" id="gameratingsratingdelete'+i+'" class="com_button_style" />';
								}
								if (this.canEdit(rating.accessLevelID))
								{
									html += '<input type="button" value="Edit" id="gameratingsratingedit'+i+'" class="com_button_style" />';
								}
							html += '</div>';
						html += '</div>';
						// > Bottom

					html += '</div>';
					// > Rating

					i++;
				}
			}

		// Update ratings block
		$('gameratingsratings').update(html);

		// Set events
		var i = 0;
		while ($('gameratingsrating'+i))
		{
			// Control
			if ($('gameratingsratingmodify'+i))
			{
				Event.observe('gameratingsratingmodify'+i, 'click', this.toggleRatingControl.bind(this, i));
			}
			$('gameratingsratingcontrol'+i).hide();
			$('gameratingsratingcontrol'+i).removeClassName('hidden');
			// Actions
			if ($('gameratingsratingedit'+i))
			{
				Event.observe('gameratingsratingedit'+i, 'click', this.editRating.bind(this, i));
			}
			if ($('gameratingsratingdelete'+i))
			{
				Event.observe('gameratingsratingdelete'+i, 'click', this.deleteRating.bind(this, i));
			}
			i++;
		}
		// > Ratings

		// Pages <
		var html = '';

		// If there is at least 1 rating
		if (data.totalRatings > 0)
		{
			var label = (data.totalRatings > 1) ? 'Ratings' : 'Rating';
			html += '<div class="gameratingspages">';
				html += '<ul>';
					html += '<li id="gameratingspagetotal">'+data.totalRatings+'</li>';
					html += '<li class="com_pages_total">'+label+'</li>';
					html += '<li>|</li>';
					html += '<li>Page</li>';
					html += '<li>|</li>';

					// Determine which page counters to draw
					var numPages = Math.ceil(data.totalRatings / this.RATINGS_SHOWTOTAL);
					var pageCounters = new Array();
					if (numPages > this.RATINGS_SHOWTOTALPAGES)
					{
						var edge = 1;
						pageCounters.push(1);
						pageCounters.push(numPages);
						if (page != 1 && page != numPages) pageCounters.push(page);
						while (pageCounters.length < this.RATINGS_SHOWTOTALPAGES)
						{
							// If upper page to draw is less than the last
							if (page + edge < numPages) pageCounters.push(page + edge);
							// If lower page to draw is greater than the first
							if (page - edge > 1) pageCounters.push(page - edge);
							// Increment edge
							edge++;
						}
						pageCounters.sort(COM_CIPHERCITIES_COMMON.sortNumber);
					}
					else
					{
						for (var i=1; i<=numPages; i++) pageCounters.push(i);
					}

					// Draw page counters
					var last = 0;
					var ratingNum;
					for (var i=0; i<pageCounters.length; i++)
					{
						ratingNum = pageCounters[i];
						// If ratingnum skips an increment draw ellipsis
						if (ratingNum > last + 1) html += '<li>...</li>';
						// Draw page counter
						html += '<li'+((ratingNum == page) ? ' class="gameratingspagecurrent"' : '')+'>';
						html += '<a href="#" onclick="return false;" id="gameratingspage'+ratingNum+'">'+ratingNum+'</a>';
						html += '</li>';
						// Store last ratingnum
						last = ratingNum;
					}

					html += '<li>|</li>';
				html += '</ul>';
			html += '</div>';
			// > Bottom

			// Update pages block
			$('gameratingspages').update(html);

			// Set events
			for (var i=0; i<pageCounters.length; i++)
			{
				ratingNum = pageCounters[i];
				Event.observe('gameratingspage'+ratingNum, 'click', this.getRatings.bind(this, ratingNum));
			}

		} 
		// > Pages

		this.clearStatus();
		$('gameratingsratings').show();
		$('gameratingspages').show();
	},

	addRating: function()
	{
		// Set references
		var rating = this.ratingSlider.value;
		var comment = $('gameratingsinputcomment').value;

		// If comment is blank
		if (comment.blank())
		{
			this.showStatusError(this.ERROR_COMMENTEMPTY);
			return;
		}

		// If comment is too long
		if (comment.length > this.COMMENT_TOTALLENGTH)
		{
			this.showStatusError(this.ERROR_COMMENTTOOLONG);
			return;
		}

		// If comment contains illegal elements
		if (
			comment.length != comment.stripTags().length ||
			comment.length != comment.stripScripts().length
			)
		{
			this.showStatusError(this.ERROR_COMMENTINVALID);
			return;
		}

		// If comment is valid
		this.clearStatus();

		// Format comment
		comment = COM_CIPHERCITIES_COMMON.sanitize(comment.stripScripts().stripTags());

		// Draw loading state
		this.showStatusLoading();
		$('gameratingsinputactions').hide();

		// Add Rating
		var target = 'addGameRating';
		var data = new Object();
		data.gameID = $('gameratingsgameid').innerHTML;
		data.rating = rating;
		data.comment = comment;
		var args =
		{
			method: 'post',
			parameters: {target: target, data: Object.toJSON(data)},
			onSuccess: this.processAddRating.bindAsEventListener(this)
		}
		new Ajax.Request(COM_CIPHERCITIES_GLOBALS.HANDLER_MAIN, args);
	},

	processAddRating: function(data)
	{
		var response = data.responseText.evalJSON(true);

		if (response.logout)
		{
			COM_CIPHERCITIES_COMMON.loadURLLogout();
			return;
		}

		if (!response.success)
		{
			this.showStatusError(this.ERROR_RATINGNOTADDED);
			$('gameratingsinputactions').show();
		}
		else
		{
			var html = '';
			html += '<input type="button" value="Delete" id="gameratingsdeleterating" class="com_button_style" />';
			html += '<input type="button" value="Edit" id="gameratingseditrating" class="com_button_style" />';
			$('gameratingsinputactions').update(html);
			Event.observe('gameratingsdeleterating', 'click', this.deleteUserRating.bind(this));
			Event.observe('gameratingseditrating', 'click', this.editUserRating.bind(this));
			$('gameratingsinputactions').show();

			this.getRatings(1);
		}
	},

	deleteRating: function(i)
	{
		// Determine action access
		var canDelete = ($('gameratingsratingdelete'+i) != null);
		var canEdit = ($('gameratingsratingedit'+i) != null);

		// Draw loading state
		this.showStatusLoading();
		$('gameratingsratingactions'+i).hide();
		$('gameratingsratingmodify'+i).hide();

		// Delete Rating
		var target = 'deleteGameRating';
		var data = new Object();
		data.gameID = $('gameratingsgameid').innerHTML;
		data.username = $('gameratingsratingusername'+i).innerHTML;
		var args =
		{
			method: 'post',
			parameters: {target: target, data: Object.toJSON(data)},
			onSuccess: this.processDeleteRating.bindAsEventListener(this, i, canDelete, canEdit)
		}
		new Ajax.Request(COM_CIPHERCITIES_GLOBALS.HANDLER_MAIN, args);
	},

	processDeleteRating: function(data, i, canDelete, canEdit)
	{
		var response = data.responseText.evalJSON(true);

		if (response.logout)
		{
			COM_CIPHERCITIES_COMMON.loadURLLogout();
			return;
		}

		if (!response.success)
		{
			this.showStatusError(this.ERROR_RATINGNOTDELETED);
			$('gameratingsratingactions'+i).show();
			$('gameratingsratingmodify'+i).show();
		}
		else
		{
			this.clearStatus();
			$('gameratingsrating'+i).remove();

			// Change total ratings
			$('gameratingspagetotal').update($('gameratingspagetotal').innerHTML-1);

			// Default input
			this.ratingSlider.setValue(this.DEFAULT_RATING);
			this.updateRatingSlider(this.DEFAULT_RATING);
			$('gameratingsinputcomment').value = '';
			COM_CIPHERCITIES_COMMON.updateCharacterCount($('gameratingsinputcomment'), $('gameratingscharcount'), this.COMMENT_TOTALLENGTH);
			var html = '<input type="button" value="Add" id="gameratingsaddrating" class="com_button_style" />';
			$('gameratingsinputactions').update(html);
			Event.observe('gameratingsaddrating', 'click', this.addRating.bind(this));
		}
	},

	deleteUserRating: function()
	{
		// Determine action access
		var canDelete = ($('gameratingsdeleterating') != null);
		var canEdit = ($('gameratingseditrating') != null);

		// Draw loading state
		this.showStatusLoading();
		$('gameratingsinputactions').hide();

		// Delete Rating
		var target = 'deleteGameRating';
		var data = new Object();
		data.gameID = $('gameratingsgameid').innerHTML;
		data.username = COM_CIPHERCITIES_COMMON.getUsername();
		var args =
		{
			method: 'post',
			parameters: {target: target, data: Object.toJSON(data)},
			onSuccess: this.processDeleteUserRating.bindAsEventListener(this, canDelete, canEdit)
		}
		new Ajax.Request(COM_CIPHERCITIES_GLOBALS.HANDLER_MAIN, args);
	},

	processDeleteUserRating: function(data, canDelete, canEdit)
	{
		var response = data.responseText.evalJSON(true);

		if (response.logout)
		{
			COM_CIPHERCITIES_COMMON.loadURLLogout();
			return;
		}

		if (!response.success)
		{
			this.showStatusError(this.ERROR_RATINGNOTDELETED);
			$('gameratingsinputactions').show();
		}
		else
		{
			this.clearStatus();

			// Draw actions
			this.ratingSlider.setValue(this.DEFAULT_RATING);
			this.updateRatingSlider(this.DEFAULT_RATING);
			//$('gameratingsinputcomment').update();
			$('gameratingsinputcomment').value = '';
			COM_CIPHERCITIES_COMMON.updateCharacterCount($('gameratingsinputcomment'), $('gameratingscharcount'), this.COMMENT_TOTALLENGTH);
			var html = '<input type="button" value="Add" id="gameratingsaddrating" class="com_button_style" />';
			$('gameratingsinputactions').update(html);
			Event.observe('gameratingsaddrating', 'click', this.addRating.bind(this));
			$('gameratingsinputactions').show();

			// Delete rating in summary if shown
			for (var i=0; i<this.RATINGS_SHOWTOTAL; i++)
			{
				var rating = $('gameratingsrating'+i);
				if (rating == null) break;
				// If rating is in summary
				if ($('gameratingsratingusername'+i).innerHTML == COM_CIPHERCITIES_COMMON.getUsername())
				{
					// Delete rating summary
					$('gameratingsrating'+i).remove();
					break;
				}
			}

			// Change total ratings
			$('gameratingspagetotal').update($('gameratingspagetotal').innerHTML-1);
		}
	},

	editRating: function(i)
	{
		// Set references
		var rating = $('gameratingsratingratinginput'+i).options[$('gameratingsratingratinginput'+i).selectedIndex].value;
		var comment = $('gameratingsratingcommentinput'+i).value;

		// If comment is blank
		if (comment.blank())
		{
			this.showStatusError(this.ERROR_COMMENTEMPTY);
			return;
		}

		// If comment is too long
		if (comment.length > this.COMMENT_TOTALLENGTH)
		{
			this.showStatusError(this.ERROR_COMMENTTOOLONG);
			return;
		}

		// If comment contains illegal elements
		if (
			comment.length != comment.stripTags().length ||
			comment.length != comment.stripScripts().length
			)
		{
			this.showStatusError(this.ERROR_COMMENTINVALID);
			return;
		}

		// If comment is valid
		this.clearStatus();

		// Format comment
		comment = COM_CIPHERCITIES_COMMON.sanitize(comment.stripScripts().stripTags());

		// Draw loading state
		this.showStatusLoading();
		$('gameratingsratingcommentinput'+i).disabled = true;
		$('gameratingsratingratinginput'+i).disabled = true;
		$('gameratingsratingactions'+i).hide();
		$('gameratingsratingmodify'+i).hide();

		// Edit Rating
		var target = 'editGameRating';
		var data = new Object();
		data.gameID = $('gameratingsgameid').innerHTML;
		data.username = $('gameratingsratingusername'+i).innerHTML;
		data.rating = rating;
		data.comment = comment;
		var args =
		{
			method: 'post',
			parameters: {target: target, data: Object.toJSON(data)},
			onSuccess: this.processEditRating.bindAsEventListener(this, i)
		}
		new Ajax.Request(COM_CIPHERCITIES_GLOBALS.HANDLER_MAIN, args);
	},

	processEditRating: function(data, i)
	{
		var response = data.responseText.evalJSON(true);

		if (response.logout)
		{
			COM_CIPHERCITIES_COMMON.loadURLLogout();
			return;
		}

		if (!response.success)
		{
			this.showStatusError(this.ERROR_RATINGNOTEDITED);
		}
		else
		{
			this.clearStatus();

			// Set references
			var data = response.data;
			var rating = $('gameratingsratingratinginput'+i).options[$('gameratingsratingratinginput'+i).selectedIndex].value;
			var comment = $('gameratingsratingcommentinput'+i).value;

			// Set stored rating, comment, timestamp
			if (data.edited != null)
			{
				var timestamp = COM_CIPHERCITIES_COMMON.getTimeAgo(
																   COM_CIPHERCITIES_COMMON.formatTimestamp(data.edited),
																   COM_CIPHERCITIES_COMMON.formatTimestamp(data.servertime),
																   2
																   );
				$('gameratingsratingtimestampstored'+i).innerHTML = 'Edited '+timestamp;
			}
			$('gameratingsratingratingstored'+i).innerHTML = rating;
			$('gameratingsratingcommentstored'+i).innerHTML = this.formatComment(data.comment);

			// Modify rating input if edited own rating and can rate
			if ($('gameratingsratingusername'+i).innerHTML == COM_CIPHERCITIES_COMMON.getUsername())
			{
				if ($('gameratingsinput'))
				{
					this.ratingSlider.setValue(rating);
					this.updateRatingSlider(parseInt(rating));
					//$('gameratingsinputcomment').value = this.formatComment(comment);
					$('gameratingsinputcomment').value = data.comment;
					COM_CIPHERCITIES_COMMON.updateCharacterCount($('gameratingsinputcomment'), $('gameratingscharcount'), this.COMMENT_TOTALLENGTH);
				}
			}
		}

		$('gameratingsratingactions'+i).show();
		$('gameratingsratingmodify'+i).show();
		this.toggleRatingControl(i);
	},

	editUserRating: function()
	{
		// Set references
		var rating = this.ratingSlider.value;
		var comment = $('gameratingsinputcomment').value;

		// If comment is blank
		if (comment.blank())
		{
			this.showStatusError(this.ERROR_COMMENTEMPTY);
			return;
		}

		// If comment is too long
		if (comment.length > this.COMMENT_TOTALLENGTH)
		{
			this.showStatusError(this.ERROR_COMMENTTOOLONG);
			return;
		}

		// If comment contains illegal elements
		if (
			comment.length != comment.stripTags().length ||
			comment.length != comment.stripScripts().length
			)
		{
			this.showStatusError(this.ERROR_COMMENTINVALID);
			return;
		}

		// If comment is valid
		this.clearStatus();

		// Format comment
		comment = COM_CIPHERCITIES_COMMON.sanitize(comment.stripScripts().stripTags());

		// Draw loading state
		this.showStatusLoading();
		$('gameratingsinputactions').hide();

		// Edit Rating
		var target = 'editGameRating';
		var data = new Object();
		data.gameID = $('gameratingsgameid').innerHTML;
		data.username = COM_CIPHERCITIES_COMMON.getUsername();
		data.rating = rating;
		data.comment = comment;
		var args =
		{
			method: 'post',
			parameters: {target: target, data: Object.toJSON(data)},
			onSuccess: this.processEditUserRating.bindAsEventListener(this)
		}
		new Ajax.Request(COM_CIPHERCITIES_GLOBALS.HANDLER_MAIN, args);
	},

	processEditUserRating: function(data)
	{
		var response = data.responseText.evalJSON(true);

		if (response.logout)
		{
			COM_CIPHERCITIES_COMMON.loadURLLogout();
			return;
		}

		if (!response.success)
		{
			this.showStatusError(this.ERROR_RATINGNOTEDITED);
		}
		else
		{
			this.clearStatus();

			// Modify related rating in summary if shown
			for (var i=0; i<this.RATINGS_SHOWTOTAL; i++)
			{
				var rating = $('gameratingsrating'+i);
				if (rating == null) break;
				// If rating is in summary
				if ($('gameratingsratingusername'+i).innerHTML == COM_CIPHERCITIES_COMMON.getUsername())
				{
					// Update rating summary
					var data = response.data;
					$('gameratingsratingmodify'+i).src = COM_CIPHERCITIES_GLOBALS.PA_COMMONIMAGES+COM_CIPHERCITIES_GLOBALS.BT_MAXIMISE_I;
					$('gameratingsratingmiddle'+i).removeClassName('gameratingsratingmiddleedit');
					$('gameratingsratingmiddle'+i).addClassName('gameratingsratingmiddledisplay');
					$('gameratingsratingrating'+i).update('<span class="gameratingsratingratinglabel">[<span id="gameratingsratingratingrating'+i+'">'+this.ratingSlider.value+'</span>] '+this.formatRatingLabel(this.ratingSlider.value)+'</span>');
					//$('gameratingsratingcomment'+i).update('<p>'+this.formatComment($('gameratingsinputcomment').value)+'</p>');
					var timestamp = COM_CIPHERCITIES_COMMON.getTimeAgo(
																	   COM_CIPHERCITIES_COMMON.formatTimestamp(data.edited),
																	   COM_CIPHERCITIES_COMMON.formatTimestamp(data.servertime),
																	   2
																	   );
					timestamp = 'Edited '+timestamp;
					var html = '';
					html += '<p>'+this.formatComment($('gameratingsinputcomment').value)+'</p>';
					html += '<div class="com_timestamp" id="gameratingsratingtimestamp'+i+'">';
					html += timestamp;
					html += '</div>';
					$('gameratingsratingcomment'+i).update(html);
					$('gameratingsratingcontrol'+i).hide();
					break;
				}
			}
		}

		$('gameratingsinputactions').show();
	}

}

// MAIN //

var content = new COM_CIPHERCITIES_GAMERATINGS();
Event.observe(window, 'load', content.init.bind(content));
