var readableMonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];

// Stores all active timers
var activeTimers = [];

// Stores the active message timer
var message_timer = null;

/**
 * Extension for Number to return 'st', 'nd', 'rd', or 'th'
 */
Number.prototype.getSuffix = function() {
	switch ((this.valueOf() + '').substr(-2) - 0) {
		case 11:
		case 12:
		case 13:
			return 'th';
	}
	switch ((this.valueOf() + '').substr(-1) - 0) {
		case 1:
			return 'st';
		case 2:
			return 'nd';
		case 3:
			return 'rd';
		default:
			return 'th';
	}
}

/**
 * Extensions for Number to add commas
 */
Number.prototype.addCommas = function() {
	nStr = this.valueOf() + '';
	x = nStr.split('.');
	x1 = x[0];
	x2 = x.length > 1 ? '.' + x[1] : '';
	var rgx = /(\d+)(\d{3})/;
	while (rgx.test(x1)) {
		x1 = x1.replace(rgx, '$1' + ',' + '$2');
	}
	return x1 + x2;
}

/**
 * Handles failed AJAX Requests
 *
 * @return bool If false is returned, the flow of execution should be completely halted
 */
function handleAjaxFailure (transport, json) {
	var details;
	try {
		if (transport.status == 409) {
			// Conflict, page reload necessary
			// Kill all active timers
			while (identifier = activeTimers.pop()) {
				clearInterval(identifier);
			}
			// Display Error
			alert ("Due to an update, the page you are viewing is out of date.\nThe page will now be automatically updated, but you may lose some changes you have made.");
			// Reload Page
			document.location.reload(true);
		}
		if (json) {
			if (json.details) {
				details = json.details;
			}
			if (json.status) {
				if (json.status == AUTHENTICATION_NO_USER) {
					message = (details) ? details : 'You are not logged in.';
					message += '<form id="login_form" name="login" action="/" method="post"></form>';
					Windows.closeAll();
					Dialog.confirm(message, {
						className: 'cityred',
						width: 300,
						height: 160,
						hideEffect: Element.hide,
						okLabel: 'Login',
						onShow: function (win) {
							Event.observe('login_form', 'submit', loginpopup_submit);
							loginFields = FormFields.objectifyFormFieldGroups(json.loginfields);
							FormFields.createForm('login_form', loginFields);
						},
						onOk: function (win) {
							loginpopup_submit();
							return false;
						},
						onCancel: function (win) {
							document.location.href = '/';
						}
					});
					return false;
				}
			}
			if (json.reloadpage) {
				// Reload Page
				document.location.reload(true);
			}
		} else {
			details = 'Could not connect to server. Please try again in a moment.' + "\n" + transport.responseText;
		}
		displayMessage(details);
	} catch (err) {
	}
	
	return true;
}

/**
 * Shows a login dialog, but doesn't reload the page when login is complete.
 */
function loginpopup_submit (event) {
	if (event !== undefined) {
		Event.stop(event);
	}
	if (Authentication.validateLoginForm($('login_form'))) {
		Dialog.info('Logging in...<br /><br /><img src=\'/images/loading.gif\' alt=\'\' />', {
			className: 'cityred',
			width: 300,
			hideEffect: Element.hide
		});
		Authentication.authenticateUser($('login_form').serialize(true), $('login_form'), {
			onSuccess: function(message) {
				Windows.closeAll();
				if (message) {
					Dialog.alert(message, {
						className: 'cityred',
						width: 300
					});
				}
			},
			onFailure: function(message) {
				Dialog.closeInfo();
				if (message) {
					Dialog.alert(message, {
						className: 'cityred',
						width: 300
					});
				}
			}
		});
	}
}

/**
 * Displays a message in the element defined by message_container, message_inside and message_content
 */
function displayMessage (message, duration) {
	if (duration == undefined) {
		duration = 500; // 5
	}
	duration = duration * 1000;
	
	if ($(message_container) && $(message_inside) && $(message_content)) {
		if (message_timer) {
			activeTimers = $A(activeTimers).without(message_timer);
			clearTimeout(message_timer);
			message_timer = null;
		}
		
		$(message_content).update(message);
		new Effect.Appear(message_inside, {
			duration: 0.5,
			afterFinish: function() {
				message_timer = setTimeout(
					function() {
						hideMessage(2);
					},
					duration
				);
				activeTimers.push(message_timer);
			}
		});
	}
}

function hideMessage (duration) {
	if (duration == undefined) {
		duration = 1;
	}
	
	if (message_timer) {
		activeTimers = $A(activeTimers).without(message_timer);
		clearTimeout(message_timer);
		message_timer = null;
	}
	if ($(message_container) && $(message_inside) && $(message_content)) {
		new Effect.Fade(message_inside, {
			duration: duration
		});
	}
}

/**
 * Gets an element by it's id, or checks for it's existence
 *
 * @param string|object id The object's id or a reference to the object
 * @return bool|object False if the element does not exist, otherwise a reference to the object
 */
function el (id) {
	return (typeof(id) == 'string') ? document.getElementById(id) : $(id);
}

/**
 * Creates an element with the supplied properties, with Prototype extensions
 *
 * Supported Custom Properties:
 * hidden: Initially hides the element
 * parent: Adds the element as the last child of the specified element
 */
function createExtendedElement (type, properties) {
	/*var parent = false;
	var hidden = false;
	var innerHTML = null;
	
	if (properties.parent != undefined) {
		parent = $(properties.parent);
		delete properties.parent;
	}
	if (properties.hidden != undefined) {
		hidden = properties.hidden;
		delete properties.hidden;
	}
	if (properties.innerHTML != undefined) {
		innerHTML = properties.innerHTML;
		delete properties.innerHTML;
	}
	
	if (innerHTML) {
		var element = $(Builder.node(type, properties, innerHTML));
	} else {
		var element = $(Builder.node(type, properties));
	}
	
	if (hidden) {
		element.hide();
	}
	if (parent) {
		$(parent).insert(element);
	}
	
	return element;/**/
	
	var element = document.createElement(type);
	//Element.extend(element);
	if (properties) {
		for (var key in properties) {
			if (key == 'hidden') {
				if (properties[key]) {
					$(element).hide();
				}
			} else if (key != 'parent') {
				element[key] = properties[key];
			}
		};
		// Append element to parent last, so it doesn't get rendered until all other
		// properties have been processed
		if (properties.parent !== undefined) {
			if (el(properties.parent)) {
				el(properties.parent).appendChild(element);
			}
		}
	}
	return element;
}

/**
* Function : dump()
* Arguments: The data - array,hash(associative array),object
*    The level - OPTIONAL
* Returns  : The textual representation of the array.
* This function was inspired by the print_r function of PHP.
* This will accept some data as the argument and return a
* text that will be a more readable version of the
* array/hash/object that is given.
*/
function dump(arr,level, objects) {
	var dumped_text = "";
	if (!level) {
		level = 0;
	}
	if (!objects) {
		objects = [];
	}
	
	// The padding given at the beginning of the line.
	var level_padding = '';
	for (var j=0; j < level + 1; j++) {
		level_padding += '    ';
	}
	
	if (typeof(arr) == 'object') {
		// Array/Hashes/Objects
		for (var item in arr) {
			var value = arr[item];
	
			if (typeof(value) == 'object') {
				//If it is an array,
				dumped_text += level_padding;
				if (isNaN(item)) {
					dumped_text += '\'' + item + '\'';
				} else {
					dumped_text += item + '';
				}
				if (value === false) {
					dumped_text += " => false\n";
				} else if (value === true) {
					dumped_text += " => true\n";
				} else if (value === null) {
					dumped_text += " => null\n";
				} else {
					// Prevent Recursion
					for (var i = 0; i < objects.length; i++) {
						if (objects[i] == value) {
							dumped_text += " => [...recursion...]\n";
							return dumped_text;
						}
					}
					objects.push(value);
				
					dumped_text += ' => ' + typeof(value) + " (\n";
					dumped_text += dump(value, level+1, objects);
					dumped_text += level_padding + ")\n";
				}
			} else if (typeof(value) != 'function') {
				dumped_text += level_padding
				if (isNaN(item)) {
					dumped_text += '\'' + item + '\'';
				} else {
					dumped_text += item + '';
				}
				dumped_text += ' => "' + value + "\"\n";
			}
		}
	} else {
		//Stings/Chars/Numbers etc.
		dumped_text = '===>' + arr + '<===(' + typeof(arr) + ')';
	}
	return dumped_text;
}