////////////////////////////////////////////////////////////////
// Copyright © 2008-2010 ReFreezed.com
////////////////////////////////////////////////////////////////







/* GENERAL
********************************************************************************************************************************/



function default_boolean(value, defaultValue)
{
	if (!isset(value))
		return defaultValue;
	else
		return Boolean(value);
}



function default_number(value, defaultValue, canReturnNaN)
{
	canReturnNaN = default_boolean(canReturnNaN, false);
	if (!isset(value))
		return defaultValue;
	else if (Number(value) === NaN && !canReturnNaN)
		return 0;
	else
		return Number(value);
}



function default_string(value, defaultValue, emptyIsUndefined)
{
	emptyIsUndefined = default_boolean(emptyIsUndefined, true);
	if (!isset(value) || (emptyIsUndefined == true && value === ''))
		return defaultValue;
	else
		return String(value);
}



function default_value(value, defaultValue)
{
	if (!isset(value))
		return defaultValue;
	else
		return value;
}



function delay_function(func)
{
	return function()
	{
		window.setTimeout(func, 1);
	};
}



function in_array(needle, haystack, strict)
{
	strict = default_boolean(strict, false);
	var len = haystack.length;
	if (strict)
	{
		for (var i = 0; i < len; i++)
		{
			if (needle === haystack[i])
				return true;
		}
	}
	else
	{
		for (var i = 0; i < len; i++)
		{
			if (needle == haystack[i])
				return true;
		}
	}
	return false;
}



function isset(val)
{
	return !(val === undefined || val === null);
}



// Example: print_var({func: function(){}, arr: ['!', {n: 'no', y: 'yes'}, '?'], booboo: false, numbah: 57, wat: undefined, nil: null}, 'body');
function print_var(v, target)
{
	var recursion_depth = 0;
	var html_arr = [];
	html_arr.push('<div style="font-family: monospace;">');
	print_variable(v);
	html_arr.push('</div>');
	$(target).html(html_arr.join(''));

	function print_variable(v, member)
	{
		recursion_depth++;
		if (recursion_depth > 100)
			return;
		if (member !== undefined)
			member = '['+String(member).asText()+'] =&gt; ';
		else
			member = '';
		switch (typeof v)
		{
			case 'boolean':
				html_arr.push('<div>'+member+'<i>'+((v) ? 'TRUE' : 'FALSE')+'</i></div>');
				break;
			case 'function':
				html_arr.push('<div>'+member+'Function()</div>');
				break;
			case 'number':
				html_arr.push('<div>'+member+v+'</div>');
				break;
			case 'object':
				if (v === null)
				{
					html_arr.push('<div>'+member+'<i>NULL</i></div>');
				}
				else if (v.ownerDocument === window.document) // Part of the DOM
				{
					html_arr.push('<div>'+member+'&lt;HTML_ELEMENT&gt;</div>');
				}
				else if ($.isArray(v))
				{
					html_arr.push('<div>'+member+'Array<div>(');
					html_arr.push('<div style="padding-left: 4em;">');
					for (var i = 0; i < v.length; i++)
						print_variable(v[i], i);
					html_arr.push('</div>'); // end padding
					html_arr.push(')</div></div>');
				}
				else
				{
					html_arr.push('<div>'+member+'Object<div>{');
					html_arr.push('<div style="padding-left: 4em;">');
					for (var m in v)
						print_variable(v[m], m);
					html_arr.push('</div>'); // end padding
					html_arr.push('}</div></div>');
				}
				break;
			case 'string':
				html_arr.push('<div>'+member+''+v.asText()+'</div>');
				break;
			case 'undefined':
				html_arr.push('<div>'+member+'<i>UNDEFINED</i></div>');
				break;
			default:
				html_arr.push('<div>'+member+'<i>UNKNOWN</i></div>');
		}
	}

}







/* COOKIES
********************************************************************************************************************************/



function delete_cookie(name)
{
	var expires = new Date();
	expires.setTime(expires.getTime()-1000*60*60*24); // Set expiration date to one day ago
	document.cookie = name+'=; expires='+expires.toGMTString()+'; path=/; domain=.refreezed.com';
}



function get_cookie(name)
{
	var cookies = document.cookie.split('; ');
	for (var i = 0; i < cookies.length; i++)
	{
		var cookie = cookies[i].split('=');
		if (cookie[0] == name)
			return unescape(cookie[1]);
	}
	return false; // The cookie couldn't be found; it was never set before, or it expired
}



function set_cookie(name, value, expires)
{
	if (expires == undefined)
	{
		expires = new Date(); // Delete after the current session
	}
	else
	{
		switch (expires) // Check for predefined values
		{
			case 'hour':    expires = new Date(); expires.setTime(expires.getTime()+1000*60*60);        break; // Delete after one hour
			case 'day':     expires = new Date(); expires.setTime(expires.getTime()+1000*60*60*24);     break; // Delete after one day
			case 'week':    expires = new Date(); expires.setTime(expires.getTime()+1000*60*60*24*7);   break; // Delete after one week
			case 'month':   expires = new Date(); expires.setTime(expires.getTime()+1000*60*60*24*30);  break; // Delete after one month
			case 'year':    expires = new Date(); expires.setTime(expires.getTime()+1000*60*60*24*365); break; // Delete after one year
			case 'session': expires = new Date(); break; // Delete after the current session
			default: // If we're here we assume that 'expires' already is a date object
		}
	}
	document.cookie = name+'='+escape(value)+'; expires='+expires.toGMTString()+'; path=/; domain=.refreezed.com';
}







/* DOM ELEMENTS
********************************************************************************************************************************/



function fade_and_remove_element(element, callback)
{
	$(element).animate({opacity: 0}, 750, 0, function()
	{
		$(this).remove();
		if (callback)
			callback();
	});
}







/* FORM
********************************************************************************************************************************/



function clean_up_input(input) // Usually called by .input elements on themselves
{
	var val = input.value;
	val = val.trim();
	val = val.replace(/ {2,}/g, ' '); // Replace succeeding spaces to single space
	input.value = val;
}



function clean_up_tag_input(input) // Usually called by .tagInput elements on themselves
{
	var val = input.value;
	val = val.toLowerCase();
	val = val.replace(/[^, a-z0-9]/g, ' '); // Remove unwanted characters (and replace them with spaces)
	val = val.replace(/ *,[, ]*/g, ','); // Replace succeeding spaces and commas with a single comma
	val = val.replace(/ {2,}/g, ' '); // Replace succeeding spaces (inside tags) into a single space
	val = val.trim(' ,');
	var tags = val.split(',');
	tags = tags.unique();
	tags = tags.sort();
	input.value = tags.join(', ');
	/* IF ALLOWING HYPHENS... */
	//var val = input.value;
	//val = val.toLowerCase();
	//val = val.replace(/[^-, a-z0-9]/g, ' '); // Remove unwanted characters (and replace them with spaces)
	//val = val.replace(/[ -]*,[, -]*/g, ','); // Replace succeeding spaces, hyphens and commas with a single comma
	//val = val.replace(/ [ -]+/g, ' '); // Replace succeeding spaces and hyphens (inside tags) into a single space
	//val = val.trim(' ,-');
	//var tags = val.split(',');
	//tags = tags.unique();
	//tags = tags.sort();
	//input.value = tags.join(', ');
}



/**** OLD ****/
function focusInput(id){
	$('#'+id).focus().select();
}
/**** OLD ****/



function focus_input(input)
{
	input = $(input); // Make sure it's a jQuery object
	input.focus().select();
}



function get_checkbox_input_value(form, name)
{
	var input = $(form).find('input:checkbox[name="'+name+'"]:checked');
	if (input.length == 0)
		return '';
	else
		return input.val();
}



function get_inputs(form) // TODO: Make a get_input_values() function
{
	form = $(form); // Make sure it's a jQuery object
	var inputs = form.find('input[name], select[name], textarea[name]');
	if (inputs.length == 0)
		return false;
	var inputs_to_return = {};
	inputs.each(function()
	{
		inputs_to_return[this.name] = this;
	});
	return inputs_to_return;
}



function get_radio_input_value(form, name)
{
	var input = $(form).find('input:radio[name="'+name+'"]:checked');
	if (input.length == 0)
		return '';
	else
		return input.val();
	/*
	var input_elements = $(form).find('input[name="'+name+'"]').get();
	var len = input_elements.length;
	if (len == 0)
		return false;
	for (var i = 0; i < len; i++)
	{
		if (input_elements[i].checked)
			return input_elements[i].value;
	}
	return false; // None was checked
	*/
}



function get_select_input_value(form, name)
{
	var input = $(form).find('select[name="'+name+'"] option:selected');
	if (input.length == 0)
		return '';
	else
		return input.val();
}



/**** OLD ****/
function send_ajax_form(form, notify, refresh)
{
	send_form_through_ajax(form, false, notify, refresh)
}
/**** OLD ****/



/**
* @desc   Really easy function for sending HTTP requests
*         There are two ways of calling this function:
*           send_http_request(action, data, success, error)
*           send_http_request([{action1, data1, success1, error1}, {action2, data2, success2, error2}, n...])
*
* @param  action  string   required The action to be performed AKA where to send the request
*                                   'comic/addComment'
* @param  data    object   optional Data to be sent along with the request
*                                   {id: 5, name: 'Carl'}
* @param  success function optional Function to execute on success
*                                   function(data, textStatus){ alert('Success!'); }
* @param  error   function optional Function to execute on error
*                                   function(XMLHttpRequest, textStatus, errorThrown){ alert('Error!'); }
*
* @return void
*/
function send_http_request(action, data, success, error)
{
	var requests = [];
	if (typeof action == 'object' && action.length != undefined) // If 'action' is an array
	{
		requests = action;
	}
	else
	{
		requests = [{action: action, data: data, success: success, error: error}];
	}
	for (var i = 0; i < requests.length; i++)
	{
		if (typeof requests[i].action != 'string') // The action is required
			continue;
		if (typeof requests[i].data != 'object')
			requests[i].data = {};
		if (typeof requests[i].success != 'function')
			requests[i].success = function(){};
		if (typeof requests[i].error != 'function')
			requests[i].error = function(){};
		$.ajax({
			cache: false,
			contentType: 'application/x-www-form-urlencoded',
			data: requests[i].data,
			type: 'post',
			url: '/ajax/'+requests[i].action+'.php',
			success: requests[i].success,
			error: requests[i].error
		});
	}
}



// Send a form through Ajax
// The refresh and notify arguments are only used if no code is sent back from the server
// The 'form' argument can be the actual form or an element inside the form which is to be submitted
// Note that this function does not validate any inputs in the form
// Also note that the POST method is always used and that forms containing file inputs are submitted normally
function send_form_through_ajax(form, action, notify, refresh)
{
	form = $(form); // Make sure it's a jQuery object
	if (form.get(0).tagName != 'FORM') // If 'form' isn't a form then we assume that 'form' is somewhere INSIDE the actual form
		form = form.parents('form').eq(0);
	if (form.hasClass('busy')) // Note: We set this class here below while we're sending the form through Ajax
		return;
	if (action == undefined || action == false)
		action = form.attr('action').trim('/'); // (Default value)
	if (notify == undefined)
		notify = false; // (Default value)
	if (refresh == undefined)
		refresh = false; // (Default value)
	var data = {};
	var inputs = form.find('input, textarea, select');
	form.addClass('busy'); // Aaaaand here we make the form busy
	// Get the value from all inputs and set cookies
	inputs.each(function()
	{
		var name = this.name;
		if (this.tagName == 'INPUT')
		{
			if (this.type == 'radio' && this.checked == false)
				return;
			if (this.type == 'checkbox' && this.checked == false)
				return;
		}
		if (name) // Only use inputs that has a name (e.g. not the submit button)
		{
			var val = this.value;
			data[name] = val;
			if (val && $(this).hasClass('useCookie')) // Only set cookie if a value and .useCookie is present
				set_cookie(name, val, 'month');
		}
	});
	if (inputs.filter('[type=file]').length > 0) // If any file inputs exists... (Note that we cannot send files through Ajax so we have to submit the form the normal way)
	{
		form.attr({
			action: '/ajax/'+action+'.php',
			enctype: 'multipart/form-data',
			method: 'post'
		}).submit();
	}
	else // If no file inputs exist => yay, we can send the form through Ajax!
	{
		inputs.not('[type=hidden]').attr('disabled', 'disabled');
		var success = function(data, textStatus)
		{
			if (data.charAt(0) != ':') // If no :code: was returned... (The data should be normal text here)
			{
				if (notify)
					alert(data);
				if (refresh)
				{
					location.reload();
				}
				else
				{
					inputs.not('[type="hidden"]').removeAttr('disabled'); // Enable inputs
					form.removeClass('busy');
				}
			}
			else // If a :code: was returned
			{
				var end = data.indexOf(':', 1)+1; // We want to know where the code ends and the message begins (Example of returned data: ":0:An error occured.")
				var code = Number(data.substring(1, end-1));
				data = data.substr(end);
				switch (code)
				{
					// 0: Failure (0 = false)
					// 1: Success (1 = true)
					// 2: Failure + reload
					// 3: Success + reload
					// 4: Secret failure (no notification)
					// 5: Secret success (no notification)
					// 6: Secret failure + reload (no notification)
					// 7: Secret success + reload (no notification)
					// 8: Failure + redirect (no notification)
					// 9: Success + redirect (no notification)
					case 0: // Failure
						alert('ERROR\n\n'+data);
						inputs.not('[type="hidden"]').removeAttr('disabled'); // Enable inputs
						form.removeClass('busy');
						break;
					case 1: // Success
						alert(data);
						inputs.not('[type="hidden"]').removeAttr('disabled'); // Enable inputs
						form.removeClass('busy');
						break;
					case 2: // Failure + reload
						alert('ERROR\n\n'+data);
						location.reload();
						break;
					case 3: // Success + reload
						alert(data);
						location.reload();
						break;
					case 4: // Secret failure
						inputs.not('[type="hidden"]').removeAttr('disabled'); // Enable inputs
						form.removeClass('busy');
						break;
					case 5: // Secret success
						inputs.not('[type="hidden"]').removeAttr('disabled'); // Enable inputs
						form.removeClass('busy');
						break;
					case 6: // Secret failure + reload
						location.reload();
						break;
					case 7: // Secret success + reload
						location.reload();
						break;
					case 8: // Failure + redirect
						// Continue...
					case 9: // Success + redirect
						var i = data.indexOf('#');
						if (i != -1)
						{
							var url_without_hash = data.substring(0, i);
							if (url_without_hash == location.href.substring(0, location.href.length-location.hash.length))
							{
								location.assign(data);
								location.reload(); // If assign() only changed the hash then we need to reload the page here
							}
							else
							{
								location.assign(data);
							}
						}
						else
						{
							location.assign(data);
						}
						break;
					default: 
						alert('ERROR\n\nAn unknown message was recieved when the form was submitted. Please contact ReFreezed about this.');
				}
			}
		};
		var error = function(XMLHttpRequest, textStatus, errorThrown)
		{
			if (notify)
			{
				if (XMLHttpRequest.responseText)
					alert('ERROR\n\nThe form wasn\'t submitted correctly: '+XMLHttpRequest.responseText);
				else
					alert('ERROR\n\nThe form wasn\'t submitted correctly. Please try again later.');
			}
			inputs.not('[type="hidden"]').removeAttr('disabled'); // Enable inputs
			form.removeClass('busy');
		};
		send_http_request(action, data, success, error);
	}
}



function toggle_text_preview(buttonElement, target, mode, wordWrap, flags)
{
	var preview_exists = $(target).next().hasClass('textPreview');
	if (!preview_exists)
	{
		$(buttonElement).attr('disabled', 'disabled').blur();

		var data = {};
		if (isset(flags))
		{
			data['flags'] = [];
			for (var flag in flags)
				data['flags'].push(flag+':'+flags[flag]);
			data['flags'] = data['flags'].join(',');
		}
		data['mode'] = mode;
		data['text'] = $(target).val();
		data['wordWrap'] = wordWrap;

		var success_func = function(data, textStatus)
		{
			$(target).hide().after($('<div class="textPreview spacedBlocks" style="padding: 0 10px 10px;"></div>').html(data));
			$(buttonElement).removeAttr('disabled').val('Edit');
		};

		var error_func = function(XMLHttpRequest, textStatus, errorThrown)
		{
			error('Could not contact the server at the moment.');
		};

		FormUpload.SubmitData('get-text-preview', data, success_func, error_func);
	}
	else
	{
		$(target).show().next().remove();
		$(buttonElement).removeAttr('disabled').val('Preview');
		focus_input(target);
	}
}



function update_characters_left_count(input, target, maxChars)
{
	input = $(input);
	target = $(target);
	var char_count = maxChars-input.val().length;
	target.html(String(char_count));
	if (char_count < 0)
		target.css('color', 'red');
	else
		target.css('color', '');
}



/**** OLD ****/
// Validate an input tag with the associated id
function validateInput(id, mode){
	var result = false;
	var val = $('#'+id).val();
	// Test the value accordingly to the mode
	switch(mode){
		case 'number': result = false; break;
		case 'opturl': result = ((val == '') || (val != '' && val.substr(0, 7) == 'http://')); break;
		default: result = (val) ? true : false;
	}
	// Alert if the test resulted negatively
	if(!result){
		focusInput(id);
		alert('Please fill the form correctly.');
	}
	// Return test result
	return result;
}
/**** OLD ****/



function validate_input(input, rule)
{
	input = $(input); // Make sure it's a jQuery object
	var result = false;
	var val = input.val();
	switch (rule) // Test the value accordingly to the rule
	{

		// DATE (optional)
		case 'OPT_DATE':
			if (val == '')
			{
				result = true;
				break;
			}
			// else continue...

		// DATE
		case 'DATE':
			if (val == '')
			{
				result = false;
			}
			else
			{
				var pattern = new RegExp('^\\d{4}-[01][0-9]-[0-3]\\d$'); // Match the YYYY-MM-DD format
				result = pattern.test(val); // Test the date as YYYY-MM-DD format
				if (!result)
				{
					result = pattern.test('20'+val); // Test the date as YY-MM-DD format
					if (result)
						input.val((val.substr(0, 2) >= 70 ? '19' : '20')+val);
				}
				if (!result)
				{
					result = pattern.test(val.substr(0, 4)+'-'+val.substr(4, 2)+'-'+val.substr(6, 2)); // Test the date as YYYYMMDD format
					if (result)
						input.val(val.substr(0, 4)+'-'+val.substr(4, 2)+'-'+val.substr(6, 2));
				}
				if (!result)
				{
					result = pattern.test('20'+val.substr(0, 2)+'-'+val.substr(2, 2)+'-'+val.substr(4, 2)); // Test the date as YYMMDD format
					if (result)
						input.val((val.substr(0, 2) >= 70 ? '19' : '20')+val.substr(0, 2)+'-'+val.substr(2, 2)+'-'+val.substr(4, 2));
				}
			}
			break;

		// DATE AND TIME (optional)
		case 'OPT_DATE_TIME':
			if (val == '')
			{
				result = true;
				break;
			}
			// else continue...

		// DATE AND TIME
		case 'DATE_TIME':
			if (val == '')
			{
				result = false;
			}
			else
			{
				var pattern = new RegExp('^\\d{4}-[01][0-9]-[0-3]\\d [0-2]\\d:[0-5]\\d:[0-5]\\d$'); // Match the YYYY-MM-DD HH:mm:SS format
				result = pattern.test(val); // Test the date as YYYY-MM-DD HH:mm:SS format
				if (!result)
				{
					result = pattern.test('20'+val); // Test the date as YY-MM-DD HH:mm:SS format
					if (result)
						input.val((val.substr(0, 2) >= 70 ? '19' : '20')+val);
				}
				if (!result)
				{
					result = pattern.test(val.substr(0, 4)+'-'+val.substr(4, 2)+'-'+val.substr(6, 2)+' '+val.substr(8, 2)+':'+val.substr(10, 2)+':'+val.substr(12, 2)); // Test the date as YYYYMMDDHHmmSS format
					if (result)
						input.val(val.substr(0, 4)+'-'+val.substr(4, 2)+'-'+val.substr(6, 2)+' '+val.substr(8, 2)+':'+val.substr(10, 2)+':'+val.substr(12, 2));
				}
				if (!result)
				{
					result = pattern.test('20'+val.substr(0, 2)+'-'+val.substr(2, 2)+'-'+val.substr(4, 2)+' '+val.substr(6, 2)+':'+val.substr(8, 2)+':'+val.substr(10, 2)); // Test the date as YYMMDDHHmmSS format
					if (result)
						input.val((val.substr(0, 2) >= 70 ? '19' : '20')+val.substr(0, 2)+'-'+val.substr(2, 2)+'-'+val.substr(4, 2)+' '+val.substr(6, 2)+':'+val.substr(8, 2)+':'+val.substr(10, 2));
				}
			}
			break;

		// NUMBER
		case 'NUMBER':
			if (val == '')
			{
				result = false;
			}
			else
			{
				var pattern = new RegExp('^-?\\d+(\\.\\d+)?$');
				result = pattern.test(val);
			}
			break;

		// URL (optional)
		case 'OPT_URL':
			if (val == '')
			{
				result = true;
				break;
			}
			// else continue...

		// URL
		case 'URL':
			if (val == '')
			{
				result = false;
			}
			else
			{
				result = (val.substr(0, 7) == 'http://');
			}
			break;

		// NOT EMPTY
		default:
			result = (val) ? true : false;

	}
	if (!result) // Notify in case the test resulted negatively
	{
		alert('Please fill the form correctly.');
		focus_input(input);
	}
	return result; // Also return the test result
}



// Validate a form using predefined rules
// The 'form' argument can be an element inside the form which is to be submitted
function validate_form(form)
{
	form = $(form); // Make sure it's a jQuery object
	if (form.get(0).tagName != 'FORM') // If 'form' isn't a form then we assume that 'form' is somewhere INSIDE the actual form
		form = form.parents('form').eq(0);
	var rulesAndModes = [
		['nonEmpty', ''],
		['date', 'DATE'],
		['dateTime', 'DATE_TIME'],
		['number', 'NUMBER'],
		['url', 'URL'],
		['optDate', 'OPT_DATE'],
		['optDateTime', 'OPT_DATE_TIME'],
		['optUrl', 'OPT_URL']
	]
	for (var i = 0; i < rulesAndModes.length; i++) // Loop through all rules
	{
		var inputs = form.find('.rule-'+rulesAndModes[i][0]);
		for (var innerI = 0; innerI < inputs.length; innerI++) // Apply rules to inputs
		{
			if (!validate_input(inputs.eq(innerI), rulesAndModes[i][1]))
				return false;
		}
	}
	return true; // If we're here then the form is valid
}







/* FRAMES
********************************************************************************************************************************/



function get_iframe_document(iframeElement)
{
	return iframeElement.contentWindow.document || iframeElement.contentDocument;
}



function get_iframe_window(iframeElement)
{
	return iframeElement.contentWindow || iframeElement.contentDocument.parentWindow;
}







/* IMAGES
********************************************************************************************************************************/



(function(){
	var preloaded_images = new Array();
	window.preload_images = function()
	{
		var offset = preloaded_images.length;
		var len = arguments.length;
		for (var i = 0; i < len; i++)
		{
			preloaded_images[offset+i] = new Image();
			preloaded_images[offset+i].src = arguments[i];
		}
	}
})();







/* MOUSE
********************************************************************************************************************************/



function get_mouse_coords(e)
{
	if (e.pageX || e.pageY)
	{
		return {x: e.pageX, y: e.pageY};
	}
	else
	{
		return {x: e.clientX+document.body.scrollLeft-document.body.clientLeft, y: e.clientY+document.body.scrollTop-document.body.clientTop};
	}
}







/* NAVIGATION
********************************************************************************************************************************/



function redirect(url)
{
	$('#thinkingInAction').html('*redirecting*').show();
	location.assign(url); // Load new location
}



/**** OLD ****/
function scrollToElement(selection, onlyY){
	selection = selection.eq(0); // There must be only one element
	var offset = selection.offset();
	window.scrollTo((onlyY) ? 0 : offset.left, offset.top);
}
/**** OLD ****/



function scroll_to_element(element, skipX, skipY)
{
	if (skipX == undefined)
		skipX = false; // (Default value)
	if (skipY == undefined)
		skipY = false; // (Default value)
	var offset = $(element).offset();
	window.scrollTo((skipX) ? 0 : offset.left, (skipY) ? 0 : offset.top);
}







/* NOTIFICATION
********************************************************************************************************************************/



// (Always returns false)
function error(message)
{
	if (message == undefined)
		alert('ERROR');
	else
		alert('ERROR: '+message);
	return false;
}




























/* :: LOCAL ::
********************************************************************************************************************************/







function add_bb_code_bold(input_id)
{
	var input = $('#'+input_id);
	if (input.length == 0)
		return;
	if (input.parents('form').length > 0 && input.parents('form').hasClass('busy'))
		return;
	var text = '';
	var text_selection_range = input.getSelection();
	if (text_selection_range.length == 0) // If no text is selected...
	{
		text = prompt('Enter the text you\'d like to appear in bold.', '');
		if (text === null)
		{
			input.focus();
			return;
		}
	}
	else // If some text is selected..
	{
		text = text_selection_range.text;
	}
	input.replaceSelection('[b]'+text+'[/b]');
	input.focus();
}



function add_bb_code_email(input_id)
{
	var input = $('#'+input_id);
	if (input.length == 0)
		return;
	if (input.parents('form').length > 0 && input.parents('form').hasClass('busy'))
		return;
	var email = '';
	var label = '';
	var text_selection_range = input.getSelection();
	if (text_selection_range.length > 0) // If some text is selected...
	{
		if (text_selection_range.text.indexOf('@') != -1) // If '@' is present then we assume that an e-mail address is selected
			email = text_selection_range.text;
		else
			label = text_selection_range.text;
	}
	do
	{
		email = prompt('Enter the e-mail address you\'d like to link to.', email);
		if (email === null)
		{
			input.focus();
			return;
		}
	}
	while (email === '')
	label = prompt('Enter a label (or leave blank).', label);
	if (label === null)
	{
		input.focus();
		return;
	}
	if (label == '')
		input.replaceSelection('[email]'+email+'[/email]');
	else
		input.replaceSelection('[email='+email+']'+label+'[/email]');
	input.focus();
}



function add_bb_code_italic(input_id)
{
	var input = $('#'+input_id);
	if (input.length == 0)
		return;
	if (input.parents('form').length > 0 && input.parents('form').hasClass('busy'))
		return;
	var text = '';
	var text_selection_range = input.getSelection();
	if (text_selection_range.length == 0) // If no text is selected...
	{
		text = prompt('Enter the text you\'d like to appear in italic.', '');
		if (text === null)
		{
			input.focus();
			return;
		}
	}
	else // If some text is selected..
	{
		text = text_selection_range.text;
	}
	input.replaceSelection('[i]'+text+'[/i]');
	input.focus();
}



function add_bb_code_strikethrough(input_id)
{
	var input = $('#'+input_id);
	if (input.length == 0)
		return;
	if (input.parents('form').length > 0 && input.parents('form').hasClass('busy'))
		return;
	var text = '';
	var text_selection_range = input.getSelection();
	if (text_selection_range.length == 0) // If no text is selected...
	{
		text = prompt('Enter the text you\'d like to appear in strikethrough.', '');
		if (text === null)
		{
			input.focus();
			return;
		}
	}
	else // If some text is selected..
	{
		text = text_selection_range.text;
	}
	input.replaceSelection('[s]'+text+'[/s]');
	input.focus();
}



function add_bb_code_underline(input_id)
{
	var input = $('#'+input_id);
	if (input.length == 0)
		return;
	if (input.parents('form').length > 0 && input.parents('form').hasClass('busy'))
		return;
	var text = '';
	var text_selection_range = input.getSelection();
	if (text_selection_range.length == 0) // If no text is selected...
	{
		text = prompt('Enter the text you\'d like to appear underlined.', '');
		if (text === null)
		{
			input.focus();
			return;
		}
	}
	else // If some text is selected..
	{
		text = text_selection_range.text;
	}
	input.replaceSelection('[u]'+text+'[/u]');
	input.focus();
}



function add_bb_code_url(input_id)
{
	var input = $('#'+input_id);
	if (input.length == 0)
		return;
	if (input.parents('form').length > 0 && input.parents('form').hasClass('busy'))
		return;
	var url = 'http://';
	var label = '';
	var text_selection_range = input.getSelection();
	if (text_selection_range.length > 0) // If some text is selected...
	{
		if (text_selection_range.text.indexOf('http://') === 0 || text_selection_range.text.indexOf('https://') === 0
			|| text_selection_range.text.indexOf('www.') === 0)
		{
			url = text_selection_range.text;
		}
		else
		{
			label = text_selection_range.text;
		}
	}
	do
	{
		url = prompt('Enter the URL you\'d like to link to.', url);
		if (url === null)
		{
			input.focus();
			return;
		}
	}
	while (url === '' || url == 'http://' || url == 'https://')
	if (!(url.substr(0, 7) == 'http://' || url.substr(0, 8) == 'https://'))
		url = 'http://'+url;
	label = prompt('Enter a label (or leave blank).', label);
	if (label === null)
	{
		input.focus();
		return;
	}
	if (label == '')
		input.replaceSelection('[url]'+url+'[/url]');
	else
		input.replaceSelection('[url='+url+']'+label+'[/url]');
	input.focus();
}



function comment_ban_ip(id)
{
	alert('This feature is not ready yet...');
}



function comment_ban_user(id)
{
	alert('This feature is not ready yet...');
}



function delete_comic_strip(id)
{
	if (!confirm('Delete comic strip?'))
		return;
	var action = 'comic-strips/delete-strip';
	var data = {id: id};
	var success = function(data, textStatus)
	{
		execute_data_from_server(data, true, false);
	};
	var error = function(XMLHttpRequest, textStatus, errorThrown)
	{
		alert('An error ocurred while contacting the server. Please try again.');
	};
	send_http_request(action, data, success, error);
}



function delete_comment(id)
{
	if (!confirm('Delete comment?'))
		return;
	var action = 'delete-comment';
	var data = {id: id};
	var success = function(data, textStatus)
	{
		execute_data_from_server(data, true, false);
	};
	var error = function(XMLHttpRequest, textStatus, errorThrown)
	{
		alert('An error ocurred while contacting the server. Please try again.');
	};
	send_http_request(action, data, success, error);
}



function delete_post(id)
{
	if (!confirm('Delete post?'))
		return;
	var action = 'forum/delete-post';
	var data = {id: id};
	var success = function(data, textStatus)
	{
		execute_data_from_server(data, true, false);
	};
	var error = function(XMLHttpRequest, textStatus, errorThrown)
	{
		alert('An error ocurred while contacting the server. Please try again.');
	};
	send_http_request(action, data, success, error);
}



function delete_thread(id)
{
	if (!confirm('Delete the whole thread?'))
		return;
	var action = 'forum/delete-thread';
	var data = {id: id};
	var success = function(data, textStatus)
	{
		execute_data_from_server(data, true, false);
	};
	var error = function(XMLHttpRequest, textStatus, errorThrown)
	{
		alert('An error ocurred while contacting the server. Please try again.');
	};
	send_http_request(action, data, success, error);
}



function execute_data_from_server(data, notify, refresh)
{
	var parsed_data = parse_data_from_server(data);
	var code = parsed_data.code;
	data = parsed_data.data;
	if (code === false) // If no :code: was returned...
	{
		if (notify)
			alert(data);
		if (refresh)
		{
			location.reload();
		}
	}
	else // If a :code: was returned
	{
		switch (code)
		{
			// 0: Failure (0 = false)
			// 1: Success (1 = true)
			// 2: Failure + reload
			// 3: Success + reload
			// 4: Secret failure (no notification)
			// 5: Secret success (no notification)
			// 6: Secret failure + reload (no notification)
			// 7: Secret success + reload (no notification)
			// 8: Failure + redirect (no notification)
			// 9: Success + redirect (no notification)
			case 0: // Failure
				alert('ERROR\n\n'+data);
				break;
			case 1: // Success
				alert(data);
				break;
			case 2: // Failure + reload
				alert('ERROR\n\n'+data);
				location.reload();
				break;
			case 3: // Success + reload
				alert(data);
				location.reload();
				break;
			case 4: // Secret failure
				break;
			case 5: // Secret success
				break;
			case 6: // Secret failure + reload
				location.reload();
				break;
			case 7: // Secret success + reload
				location.reload();
				break;
			case 8: // Failure + redirect
				// Continue...
			case 9: // Success + redirect
				var i = data.indexOf('#');
				if (i != -1)
				{
					var url_without_hash = data.substring(0, i);
					if (url_without_hash == location.href.substring(0, location.href.length-location.hash.length))
					{
						location.assign(data);
						location.reload(); // If assign() only changed the hash then we need to reload the page here
					}
					else
					{
						location.assign(data);
					}
				}
				else
				{
					location.assign(data);
				}
				break;
			default: 
				alert('ERROR\n\nAn unknown message was recieved when the form was submitted. Please contact ReFreezed about this.');
		}
	}
}



function hide_comment(id)
{
	alert('This feature is not ready yet...');
}



function lock_thread(id)
{
	if (!confirm('Lock thread?'))
		return;
	var action = 'forum/lock-thread';
	var data = {id: id};
	var success = function(data, textStatus)
	{
		execute_data_from_server(data, true, false);
	};
	var error = function(XMLHttpRequest, textStatus, errorThrown)
	{
		alert('An error ocurred while contacting the server. Please try again.');
	};
	send_http_request(action, data, success, error);
}



function parse_data_from_server(data)
{
	if (data.charAt(0) != ':') // If no :code: was returned... (The data should be normal text here)
	{
		var code = false;
	}
	else // If a :code: was returned
	{
		var end = data.indexOf(':', 1)+1; // We want to know where the code ends and the message begins (Example of returned data: ":0:An error occured.")
		var code = Number(data.substring(1, end-1));
		data = data.substr(end);
	}
	return {code: code, data: data};
}



/**** OLD ****/
/*(function(){
	var shoutbox_first = 1;
	var shoutbox_amount = 10;
	window.refreshShoutMessages = function(pageOffset){
		// Disable inputs
		$('#shoutbox input').attr('disabled', 'disabled');
		// Update #shoutboxEntries and #currentShoutDate (Observe the callbacks)
		if(pageOffset)
			shoutbox_first = Math.max(shoutbox_first += pageOffset*shoutbox_amount, 1);
		$('#shoutEntries').html('<div class="yellow" style="margin: 0 -1px;">LOADING</div>');
		$('#currentShoutDate').load('http://www.refreezed.com/gadget/shoutbox.php #currentShoutDate-inner', {'first': 1, 'amount': 1}, function(){
			$('#shoutEntries').load('http://www.refreezed.com/gadget/shoutbox.php #shoutEntries-inner', {'first': shoutbox_first}, function(){
				// Enable inputs
				$('#shoutbox input').removeAttr('disabled');
				// Focus shoutbox message input
				focusInput('shoutbox-message');
			});
		});
	};
})();*/
/**** OLD ****/



function split_code_and_content(data)
{
	data = String(data); // The data could be an object if it was returned from the server, so we ensure it's a string here
	if (!/^<ref:[\d\w]+>/.test(data)) // If no <ref:code> was returned...
	{
		var code = false;
		var content = data;
	}
	else // If a <ref:code> was returned...
	{
		var code = String(/^<ref:[\d\w]+>/.exec(data));
		var content = data.substr(code.length);
		if (/<\/ref:[\d\w]+>$/.test(content))
			content = content.substr(0, content.length-(code.length+1));
		code = code.substring(5, code.length-1);
	}
	return {code: code, content: content};
}



function split_iframe_code_and_content(data)
{
	data = String(data); // The data could be an object if it was returned from the server, so we ensure it's a string here
	if (!/^<input /i.test(data)) // If no "code" was returned...
	{
		var code = false;
		var content = data;
	}
	else // If a "code" was returned...
	{
		var input = String(/^<input [^>]+>/i.exec(data)).toLowerCase();
		var code = String(/value="?[\d\w]+"?/i.exec(input));
		code = code.replace('value=', '');
		code = code.replace(/"/g, '');
		var content = data.substr(input.length);
	}
	return {code: code, content: content};
}



/**** OLD ****/
/*function submit_shoutbox(){
	// Validate inputs
	if(!validateInput('shoutbox-name')) return false;
	if(!validateInput('shoutbox-url', 'opturl')) return false;
	if(!validateInput('shoutbox-message')) return false;
	// Disable inputs
	$('#shoutbox input').attr('disabled', 'disabled');
	// Prepare data
	var data = {
		'shoutbox-name': $('#shoutbox-name').val(),
		'shoutbox-url': $('#shoutbox-url').val(),
		'shoutbox-message': $('#shoutbox-message').val()
	};
	// Set cookies
	set_cookie('name', data['shoutbox-name'], 'year');
	set_cookie('url', data['shoutbox-url'], 'year');
	// Send data through Ajax
	$.ajax({
		data: data,
		cache: false,
		type: 'post',
		url: 'http://www.refreezed.com/action/shout.php',
		success: function(content){
			if(content)
				alert(content);
			// Update #shoutboxEntries and #currentShoutDate
			$('#shoutEntries').load('http://www.refreezed.com/gadget/shoutbox.php #shoutEntries-inner');
			$('#currentShoutDate').load('http://www.refreezed.com/gadget/shoutbox.php #currentShoutDate-inner');
			// Reset inputs
			$('#shoutbox-message').val('');
			// Enable inputs
			$('#shoutbox input').removeAttr('disabled');
			// Focus shoutbox message input
			focusInput('shoutbox-message');
		},
		error: function(XMLHttpRequest, textStatus, errorThrown){
			// Alert user
			alert('An error occured! Please try again later.');
			// Enable inputs
			$('#shoutbox input').removeAttr('disabled');
		}
	});
	// Return false to prevent the browser from redirecting automatically
	return false;
}*/
/**** OLD ****/



function validate_add_wall_message_form()
{
	var form_id = 'userProfile-addMessage';
	var selector_prefix = '#'+form_id+'-';

	// Message
	var input = $(selector_prefix+'message');
	var value = input.val();
	if (value.length == 0)
	{
		alert('You must provide a message.');
		focus_input(input);
		return false;
	}

	return true;
}



function validate_add_reply_form()
{
	var form_id = 'forum-addReply';
	var selector_prefix = '#'+form_id+'-';

	// Message
	var input = $(selector_prefix+'content');
	var value = input.val();
	if (value.length == 0)
	{
		alert('You must provide a message.');
		focus_input(input);
		return false;
	}

	return true;
}



function validate_add_topic_form()
{
	var form_id = 'forum-newTopic';
	var selector_prefix = '#'+form_id+'-';

	// Subject
	var input = $(selector_prefix+'subject');
	var value = input.val();
	if (value.length == 0)
	{
		alert('You must provide a subject.');
		focus_input(input);
		return false;
	}

	// Message
	var input = $(selector_prefix+'content');
	var value = input.val();
	if (value.length == 0)
	{
		alert('You must provide a message.');
		focus_input(input);
		return false;
	}

	return true;
}



function validate_create_new_comic_form()
{
	var form_id = 'newComic';
	var selector_prefix = '#'+form_id+'-';

	// Title
	var input = $(selector_prefix+'title');
	var value = input.val();
	if (value == '')
	{
		alert('Please enter a title for the comic.');
		focus_input(input);
		return false;
	}

	return true;
}



function validate_edit_comic_form()
{
	var form_id = 'editComic';
	var selector_prefix = '#'+form_id+'-';

	// Title
	var input = $(selector_prefix+'title');
	var value = input.val();
	if (value == '')
	{
		alert('Please enter a title for the comic.');
		focus_input(input);
		return false;
	}

	return true;
}



function validate_edit_comic_strip_form()
{
	var form_id = 'editComicStrip';
	var selector_prefix = '#'+form_id+'-';

	// Title
	var input = $(selector_prefix+'title');
	var value = input.val();
	if (value == '')
	{
		alert('Please enter a title for the strip.');
		focus_input(input);
		return false;
	}

	return true;
}



function validate_join_form()
{
	var form_id = 'join';
	var selector_prefix = '#'+form_id+'-';

	// Username
	var input = $(selector_prefix+'username');
	var value = input.val();
	if (value == '')
	{
		alert('Please enter a username.');
		focus_input(input);
		return false;
	}
	if (value.length > 20)
	{
		alert('Your username cannot be longer than 20 characters.');
		focus_input(input);
		return false;
	}
	if (/^[^a-z0-9]|[^-a-z0-9]|[^a-z0-9]$/i.test(value))
	{
		alert('Your username can only contain letters, numbers and hyphens. It may not start or end with a hyphen.');
		focus_input(input);
		return false;
	}

	// Password
	var input1 = $(selector_prefix+'pass');
	var input2 = $(selector_prefix+'confirmPass');
	var value1 = input1.val();
	var value2 = input2.val();
	if (value1.length < 6)
	{
		alert('Your password must be 6 characters or longer.');
		focus_input(input1);
		return false;
	}
	if (value1 != value2)
	{
		input2.val('');
		alert('You entered the wrong password. Please confirm the new password you specified.');
		focus_input(input2);
		return false;
	}

	// E-mail (http://www.regular-expressions.info/email.html)
	var input = $(selector_prefix+'email');
	var value = input.val();
	if (value == '')
	{
		alert('Please enter your e-mail address.');
		focus_input(input);
		return false;
	}
	if (!/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i.test(value))
	{
		if (/[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/i.test(value))
		{
			if (confirm('The e-mail address '+value+' looks a bit strange but it is syntactically valid. You might want to check it for typos.\n\nAbort?'))
			{
				focus_input(input);
				return false;
			}
		}
		else
		{
			alert('Please enter a valid e-mail address.');
			focus_input(input);
			return false;
		}
	}

	// Gender
	var input1 = $(selector_prefix+'gender-male');
	var input2 = $(selector_prefix+'gender-female');
	var value1 = input1.attr('checked');
	var value2 = input2.attr('checked');
	if (!(value1 || value2))
	{
		alert('Please specify your gender.');
		focus_input(input1);
		return false;
	}

	return true;
}



function validate_new_comic_strip_form()
{
	var form_id = 'newComicStrip';
	var selector_prefix = '#'+form_id+'-';

	// Title
	var input = $(selector_prefix+'title');
	var value = input.val();
	if (value == '')
	{
		alert('Please enter a title for the strip.');
		focus_input(input);
		return false;
	}

	// Image
	var input = $(selector_prefix+'image');
	var value = input.val();
	if (value == '')
	{
		alert('Please specify an image file.');
		focus_input(input);
		return false;
	}

	return true;
}



function validate_sign_in_form()
{
	var form_id = 'signIn';
	var selector_prefix = '#'+form_id+'-';

	// Username
	var input = $(selector_prefix+'username');
	var value = input.val();
	if (value == '')
	{
		alert('Please enter your username.');
		focus_input(input);
		return false;
	}

	// Password
	var input = $(selector_prefix+'pass');
	var value = input.val();
	if (value == '')
	{
		alert('Please enter your password.');
		focus_input(input);
		return false;
	}

	return true;
}



function validate_update_profile_form()
{
	var form_id = 'account-general';
	var selector_prefix = '#'+form_id+'-';

	// Current password
	var input = $(selector_prefix+'currentPass');
	var value = input.val();
	if (value == '')
	{
		alert('You must enter your current password.');
		focus_input(input);
		return false;
	}

	// New password
	var input1 = $(selector_prefix+'newPass');
	var input2 = $(selector_prefix+'confirmNewPass');
	var value1 = input1.val();
	var value2 = input2.val();
	if (value1 != '')
	{
		if (value1.length < 6)
		{
			alert('Your password must be 6 characters or longer.');
			focus_input(input1);
			return false;
		}
		if (value1 != value2)
		{
			input2.val('');
			alert('You entered the wrong password. Please confirm the new password you specified.');
			focus_input(input2);
			return false;
		}
	}

	// E-mail (http://www.regular-expressions.info/email.html)
	var input = $(selector_prefix+'email');
	var value = input.val();
	if (value == '')
	{
		alert('Please enter your e-mail address.');
		focus_input(input);
		return false;
	}
	if (!/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i.test(value))
	{
		if (/[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/i.test(value))
		{
			if (confirm('The e-mail address '+value+' looks a bit strange but it is syntactically valid. You might want to check it for typos.\n\nAbort?'))
			{
				focus_input(input);
				return false;
			}
		}
		else
		{
			alert('Please enter a valid e-mail address.');
			focus_input(input);
			return false;
		}
	}

	// Birthday
	var input1 = $(selector_prefix+'birthMonth');
	var input2 = $(selector_prefix+'birthDay');
	var input3 = $(selector_prefix+'birthYear');
	var value1 = input1.val();
	var value2 = input2.val();
	var value3 = input3.val();
	if (!((value1 == '-' && value2 == '-' && value3 == '-') || (value1 != '-' && value2 != '-' && value3 != '-')))
	{
		alert('Please specify the exact date or no date at all. Note that your birthday won\'t be publicly visible, just your age.');
		if (value1 == '-')
			focus_input(input1);
		else if (value2 == '-')
			focus_input(input2);
		else
			focus_input(input3);
		return false;
	}

	// Web URL
	var input = $(selector_prefix+'webUrl');
	var value = input.val();
	if (value != '' && value.substr(0, 7) != 'http://')
	{
		alert('Please specify an URL as your website (beginning with "http://").');
		focus_input(input);
		return false;
	}

	return true;
}






