/**
sprintf() for JavaScript 0.7-beta1
http://www.diveintojavascript.com/projects/javascript-sprintf

Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of sprintf() for JavaScript nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Alexandru Marasteanu BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


Changelog:
2010.09.06 - 0.7-beta1
  - features: vsprintf, support for named placeholders
  - enhancements: format cache, reduced global namespace pollution

2010.05.22 - 0.6:
 - reverted to 0.4 and fixed the bug regarding the sign of the number 0
 Note:
 Thanks to Raphael Pigulla <raph (at] n3rd [dot) org> (http://www.n3rd.org/)
 who warned me about a bug in 0.5, I discovered that the last update was
 a regress. I appologize for that.

2010.05.09 - 0.5:
 - bug fix: 0 is now preceeded with a + sign
 - bug fix: the sign was not at the right position on padded results (Kamal Abdali)
 - switched from GPL to BSD license

2007.10.21 - 0.4:
 - unit test and patch (David Baird)

2007.09.17 - 0.3:
 - bug fix: no longer throws exception on empty paramenters (Hans Pufal)

2007.09.11 - 0.2:
 - feature: added argument swapping

2007.04.03 - 0.1:
 - initial release
**/

var sprintf = (function() {
	function get_type(variable) {
		return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
	}
	function str_repeat(input, multiplier) {
		for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
		return output.join('');
	}

	var str_format = function() {
		if (!str_format.cache.hasOwnProperty(arguments[0])) {
			str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
		}
		return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
	};

	str_format.format = function(parse_tree, argv) {
		var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
		for (i = 0; i < tree_length; i++) {
			node_type = get_type(parse_tree[i]);
			if (node_type === 'string') {
				output.push(parse_tree[i]);
			}
			else if (node_type === 'array') {
				match = parse_tree[i]; // convenience purposes only
				if (match[2]) { // keyword argument
					arg = argv[cursor];
					for (k = 0; k < match[2].length; k++) {
						if (!arg.hasOwnProperty(match[2][k])) {
							throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
						}
						arg = arg[match[2][k]];
					}
				}
				else if (match[1]) { // positional argument (explicit)
					arg = argv[match[1]];
				}
				else { // positional argument (implicit)
					arg = argv[cursor++];
				}

				if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
					throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
				}
				switch (match[8]) {
					case 'b': arg = arg.toString(2); break;
					case 'c': arg = String.fromCharCode(arg); break;
					case 'd': arg = parseInt(arg, 10); break;
					case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
					case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
					case 'o': arg = arg.toString(8); break;
					case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
					case 'u': arg = Math.abs(arg); break;
					case 'x': arg = arg.toString(16); break;
					case 'X': arg = arg.toString(16).toUpperCase(); break;
				}
				arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
				pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
				pad_length = match[6] - String(arg).length;
				pad = match[6] ? str_repeat(pad_character, pad_length) : '';
				output.push(match[5] ? arg + pad : pad + arg);
			}
		}
		return output.join('');
	};

	str_format.cache = {};

	str_format.parse = function(fmt) {
		var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
		while (_fmt) {
			if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
				parse_tree.push(match[0]);
			}
			else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
				parse_tree.push('%');
			}
			else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
				if (match[2]) {
					arg_names |= 1;
					var field_list = [], replacement_field = match[2], field_match = [];
					if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
						field_list.push(field_match[1]);
						while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
							if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
								field_list.push(field_match[1]);
							}
							else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
								field_list.push(field_match[1]);
							}
							else {
								throw('[sprintf] huh?');
							}
						}
					}
					else {
						throw('[sprintf] huh?');
					}
					match[2] = field_list;
				}
				else {
					arg_names |= 2;
				}
				if (arg_names === 3) {
					throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
				}
				parse_tree.push(match);
			}
			else {
				throw('[sprintf] huh?');
			}
			_fmt = _fmt.substring(match[0].length);
		}
		return parse_tree;
	};

	return str_format;
})();

var vsprintf = function(fmt, argv) {
	argv.unshift(fmt);
	return sprintf.apply(null, argv);
};
/**
 * @namespace Singleton object for holding the Elgg javascript library
 */
var elgg = elgg || {};

/**
 * Pointer to the global context
 *
 * @see elgg.require
 * @see elgg.provide
 */
elgg.global = this;

/**
 * Convenience reference to an empty function.
 *
 * Save memory by not generating multiple empty functions.
 */
elgg.nullFunction = function() {};

/**
 * This forces an inheriting class to implement the method or
 * it will throw an error.
 *
 * @example
 * AbstractClass.prototype.toBeImplemented = elgg.abstractMethod;
 */
elgg.abstractMethod = function() {
	throw new Error("Oops... you forgot to implement an abstract method!");
};

/**
 * Merges two or more objects together and returns the result.
 */
elgg.extend = jQuery.extend;

/**
 * Check if the value is an array.
 *
 * No sense in reinventing the wheel!
 *
 * @param {*} val
 *
 * @return boolean
 */
elgg.isArray = jQuery.isArray;

/**
 * Check if the value is a function.
 *
 * No sense in reinventing the wheel!
 *
 * @param {*} val
 *
 * @return boolean
 */
elgg.isFunction = jQuery.isFunction;

/**
 * Check if the value is a "plain" object (i.e., created by {} or new Object())
 *
 * No sense in reinventing the wheel!
 *
 * @param {*} val
 *
 * @return boolean
 */
elgg.isPlainObject = jQuery.isPlainObject;

/**
 * Check if the value is a string
 *
 * @param {*} val
 *
 * @return boolean
 */
elgg.isString = function(val) {
	return typeof val === 'string';
};

/**
 * Check if the value is a number
 *
 * @param {*} val
 *
 * @return boolean
 */
elgg.isNumber = function(val) {
	return typeof val === 'number';
};

/**
 * Check if the value is an object
 *
 * @note This returns true for functions and arrays!  If you want to return true only
 * for "plain" objects (created using {} or new Object()) use elgg.isPlainObject.
 *
 * @param {*} val
 *
 * @return boolean
 */
elgg.isObject = function(val) {
	return typeof val === 'object';
};

/**
 * Check if the value is undefined
 *
 * @param {*} val
 *
 * @return boolean
 */
elgg.isUndefined = function(val) {
	return val === undefined;
};

/**
 * Check if the value is null
 *
 * @param {*} val
 *
 * @return boolean
 */
elgg.isNull = function(val) {
	return val === null;
};

/**
 * Check if the value is either null or undefined
 *
 * @param {*} val
 *
 * @return boolean
 */
elgg.isNullOrUndefined = function(val) {
	return val == null;
};

/**
 * Throw an exception of the type doesn't match
 *
 * @todo Might be more appropriate for debug mode only?
 */
elgg.assertTypeOf = function(type, val) {
	if (typeof val !== type) {
		throw new TypeError("Expecting param of " +
							arguments.caller + "to be a(n) " + type + "." +
							"  Was actually a(n) " + typeof val + ".");
	}
};

/**
 * Throw an error if the required package isn't present
 *
 * @param {String} pkg The required package (e.g., 'elgg.package')
 */
elgg.require = function(pkg) {
	elgg.assertTypeOf('string', pkg);

	var parts = pkg.split('.'),
		cur = elgg.global,
		part, i;

	for (i = 0; i < parts.length; i += 1) {
		part = parts[i];
		cur = cur[part];
		if (elgg.isUndefined(cur)) {
			throw new Error("Missing package: " + pkg);
		}
	}
};

/**
 * Generate the skeleton for a package.
 *
 * <pre>
 * elgg.provide('elgg.package.subpackage');
 * </pre>
 *
 * is equivalent to
 *
 * <pre>
 * elgg = elgg || {};
 * elgg.package = elgg.package || {};
 * elgg.package.subpackage = elgg.package.subpackage || {};
 * </pre>
 *
 * @example elgg.provide('elgg.config.translations')
 *
 * @param {string} pkg The package name.
 */
elgg.provide = function(pkg, opt_context) {
	elgg.assertTypeOf('string', pkg);

	var parts = pkg.split('.'),
		context = opt_context || elgg.global,
		part, i;


	for (i = 0; i < parts.length; i += 1) {
		part = parts[i];
		context[part] = context[part] || {};
		context = context[part];
	}
};

/**
 * Inherit the prototype methods from one constructor into another.
 *
 * @example
 * <pre>
 * function ParentClass(a, b) { }
 *
 * ParentClass.prototype.foo = function(a) { alert(a); }
 *
 * function ChildClass(a, b, c) {
 *     //equivalent of parent::__construct(a, b); in PHP
 *     ParentClass.call(this, a, b);
 * }
 *
 * elgg.inherit(ChildClass, ParentClass);
 *
 * var child = new ChildClass('a', 'b', 'see');
 * child.foo('boo!'); // alert('boo!');
 * </pre>
 *
 * @param {Function} childCtor Child class.
 * @param {Function} parentCtor Parent class.
 */
elgg.inherit = function(Child, Parent) {
	Child.prototype = new Parent();
	Child.prototype.constructor = Child;
};

/**
 * Converts shorthand urls to absolute urls.
 *
 * If the url is already absolute or protocol-relative, no change is made.
 *
 * elgg.normalize_url('');                   // 'http://my.site.com/'
 * elgg.normalize_url('dashboard');          // 'http://my.site.com/dashboard'
 * elgg.normalize_url('http://google.com/'); // no change
 * elgg.normalize_url('//google.com/');      // no change
 *
 * @param {String} url The url to normalize
 * @return {String} The extended url
 * @private
 */
elgg.normalize_url = function(url) {
	url = url || '';
	elgg.assertTypeOf('string', url);

	// jslint complains if you use /regexp/ shorthand here... ?!?!
	if ((new RegExp("^(https?:)?//", "i")).test(url)) {
		return url;
	}

	// 'javascript:'
	else if (url.indexOf('javascript:') === 0) {
		return url;
	}

	// watch those double escapes in JS.

	// 'install.php', 'install.php?step=step'
	else if ((new RegExp("^[^\/]*\\.php(\\?.*)?$", "i")).test(url)) {
		return elgg.config.wwwroot + url.ltrim('/');
	}

	// 'example.com', 'example.com/subpage'
	else if ((new RegExp("^[^/]*\\.", "i")).test(url)) {
		return 'http://' + url;
	}

	// 'page/handler', 'mod/plugin/file.php'
	else {
		// trim off any leading / because the site URL is stored
		// with a trailing /
		return elgg.config.wwwroot + url.ltrim('/');
	}
};

/**
 * Displays system messages via javascript rather than php.
 *
 * @param {String} msgs The message we want to display
 * @param {Number} delay The amount of time to display the message in milliseconds. Defaults to 6 seconds.
 * @param {String} type The type of message (typically 'error' or 'message')
 * @private
 */
elgg.system_messages = function(msgs, delay, type) {
	if (elgg.isUndefined(msgs)) {
		return;
	}

	var classes = ['elgg-message'],
		messages_html = [],
		appendMessage = function(msg) {
			messages_html.push('<li class="' + classes.join(' ') + '"><p>' + msg + '</p></li>');
		},
		systemMessages = $('ul.elgg-system-messages'),
		i;

	//validate delay.  Must be a positive integer.
	delay = parseInt(delay || 6000, 10);
	if (isNaN(delay) || delay <= 0) {
		delay = 6000;
	}

	//Handle non-arrays
	if (!elgg.isArray(msgs)) {
		msgs = [msgs];
	}

	if (type === 'error') {
		classes.push('elgg-state-error');
	} else {
		classes.push('elgg-state-success');
	}

	msgs.forEach(appendMessage);

	$(messages_html.join('')).appendTo(systemMessages)
		.animate({opacity: '1.0'}, delay).fadeOut('slow');
};

/**
 * Wrapper function for system_messages. Specifies "messages" as the type of message
 * @param {String} msgs  The message to display
 * @param {Number} delay How long to display the message (milliseconds)
 */
elgg.system_message = function(msgs, delay) {
	elgg.system_messages(msgs, delay, "message");
};

/**
 * Wrapper function for system_messages.  Specifies "errors" as the type of message
 * @param {String} errors The error message to display
 * @param {Number} delay  How long to dispaly the error message (milliseconds)
 */
elgg.register_error = function(errors, delay) {
	elgg.system_messages(errors, delay, "error");
};

/**
 * Meant to mimic the php forward() function by simply redirecting the
 * user to another page.
 *
 * @param {String} url The url to forward to
 */
elgg.forward = function(url) {
	location.href = elgg.normalize_url(url);
};

/**
 * Returns a jQuery selector from a URL's fragement.  Defaults to expecting an ID.
 *
 * Examples:
 *  http://elgg.org/download.php returns ''
 *	http://elgg.org/download.php#id returns #id
 *	http://elgg.org/download.php#.class-name return .class-name
 *	http://elgg.org/download.php#a.class-name return a.class-name
 *
 * @param {String} url The URL
 * @return {String} The selector
 */
elgg.getSelectorFromUrlFragment = function(url) {
	var fragment = url.split('#')[1];

	if (fragment) {
		// this is a .class or a tag.class
		if (fragment.indexOf('.') > -1) {
			return fragment;
		}

		// this is an id
		else {
			return '#' + fragment;
		}
	}
	return '';
};

/**
 * Triggers the init hook when the library is ready
 *
 * Current requirements:
 * - DOM is ready
 * - languages loaded
 *
 */
elgg.initWhenReady = function() {
	if (elgg.config.languageReady && elgg.config.domReady) {
		elgg.trigger_hook('init', 'system');
		elgg.trigger_hook('ready', 'system');
	}
}/**
 * Create a new ElggEntity
 * 
 * @class Represents an ElggEntity
 * @property {number} guid
 * @property {string} type
 * @property {string} subtype
 * @property {number} owner_guid
 * @property {number} site_guid
 * @property {number} container_guid
 * @property {number} access_id
 * @property {number} time_created
 * @property {number} time_updated
 * @property {number} last_action
 * @property {string} enabled
 * 
 */
elgg.ElggEntity = function(o) {
	$.extend(this, o);
};/**
 * Create a new ElggUser
 *
 * @param {Object} o
 * @extends ElggEntity
 * @class Represents an ElggUser
 * @property {string} name
 * @property {string} username
 */
elgg.ElggUser = function(o) {
	elgg.ElggEntity.call(this, o);
};

elgg.inherit(elgg.ElggUser, elgg.ElggEntity);/**
 * Priority lists allow you to create an indexed list that can be iterated through in a specific
 * order.
 */
elgg.ElggPriorityList = function() {
	this.length = 0;
	this.priorities_ = [];
};

/**
 * Inserts an element into the priority list at the priority specified.
 *
 * @param {Object} obj          The object to insert
 * @param {Number} opt_priority An optional priority to insert at.
 * 
 * @return {Void}
 */
elgg.ElggPriorityList.prototype.insert = function(obj, opt_priority) {
	var priority = parseInt(opt_priority || 500, 10);

	priority = Math.max(priority, 0);

	if (elgg.isUndefined(this.priorities_[priority])) {
		this.priorities_[priority] = [];
	}

	this.priorities_[priority].push(obj);
	this.length++;
};

/**
 * Iterates through each element in order.
 *
* Unlike every, this ignores the return value of the callback.
 *
 * @param {Function} callback The callback function to pass each element through. See
 *                            Array.prototype.every() for details.
 * @return {Object}
 */
elgg.ElggPriorityList.prototype.forEach = function(callback) {
	elgg.assertTypeOf('function', callback);

	var index = 0;

	this.priorities_.forEach(function(elems) {
		elems.forEach(function(elem) {
			callback(elem, index++);
		});
	});

	return this;
};

/**
 * Iterates through each element in order.
 *
 * Unlike forEach, this returns the value of the callback and will break on false.
 *
 * @param {Function} callback The callback function to pass each element through. See
 *                            Array.prototype.every() for details.
 * @return {Object}
 */
elgg.ElggPriorityList.prototype.every = function(callback) {
	elgg.assertTypeOf('function', callback);

	var index = 0;

	return this.priorities_.every(function(elems) {
		return elems.every(function(elem) {
			return callback(elem, index++);
		});
	});
};

/**
 * Removes an element from the priority list
 *
 * @param {Object} obj The object to remove.
 * @return {Void}
 */
elgg.ElggPriorityList.prototype.remove = function(obj) {
	this.priorities_.forEach(function(elems) {
		var index;
		while ((index = elems.indexOf(obj)) !== -1) {
			elems.splice(index, 1);
			this.length--;
		}
	});
};/**
 * Interates through each element of an array and calls a callback function.
 * The callback should accept the following arguments:
 *	element - The current element
 *	index	- The current index
 *
 * This is different to Array.forEach in that if the callback returns false, the loop returns
 * immediately without processing the remaining elements.
 *
 *	@param {Function} callback
 *	@return {Bool}
 */
if (!Array.prototype.every) {
	Array.prototype.every = function(callback) {
		var len = this.length, i;

		for (i = 0; i < len; i++) {
			if (i in this && !callback.call(null, this[i], i)) {
				return false;
			}
		}

		return true;
	};
}

/**
 * Interates through each element of an array and calls callback a function.
 * The callback should accept the following arguments:
 *	element - The current element
 *	index	- The current index
 *
 * This is different to Array.every in that the callback's return value is ignored and every
 * element of the array will be parsed.
 *
 *	@param {Function} callback
 *	@return {Void}
 */
if (!Array.prototype.forEach) {
	Array.prototype.forEach = function(callback) {
		var len = this.length, i;

		for (i = 0; i < len; i++) {
			if (i in this) {
				callback.call(null, this[i], i);
			}
		}
	};
}

/**
 * Left trim
 *
 * Removes a character from the left side of a string.
 * @param {String} str The character to remove
 * @return {String}
 */
if (!String.prototype.ltrim) {
	String.prototype.ltrim = function(str) {
		if (this.indexOf(str) === 0) {
			return this.substring(str.length);
		} else {
			return this;
		}
	};
}
/*
 * Javascript hook interface
 */

elgg.provide('elgg.config.hooks');

/**
 * Registers an hook handler with the event system.
 *
 * The special keyword "all" can be used for either the name or the type or both
 * and means to call that handler for all of those hooks.
 *
 * @param {String}   name     Name of the plugin hook to register for
 * @param {String}   type     Type of the event to register for
 * @param {Function} handler  Handle to call
 * @param {Number}   priority Priority to call the event handler
 * @return {Bool}
 */
elgg.register_hook_handler = function(name, type, handler, priority) {
	elgg.assertTypeOf('string', name);
	elgg.assertTypeOf('string', type);
	elgg.assertTypeOf('function', handler);

	if (!name || !type) {
		return false;
	}

	var priorities =  elgg.config.hooks;

	elgg.provide(name + '.' + type, priorities);

	if (!(priorities[name][type] instanceof elgg.ElggPriorityList)) {
		priorities[name][type] = new elgg.ElggPriorityList();
	}

	return priorities[name][type].insert(handler, priority);
};

/**
 * Emits a hook.
 *
 * Loops through all registered hooks and calls the handler functions in order.
 * Every handler function will always be called, regardless of the return value.
 *
 * @warning Handlers take the same 4 arguments in the same order as when calling this function.
 * This is different to the PHP version!
 *
 * Hooks are called in this order:
 *	specifically registered (event_name and event_type match)
 *	all names, specific type
 *	specific name, all types
 *	all names, all types
 *
 * @param {String} name   Name of the hook to emit
 * @param {String} type   Type of the hook to emit
 * @param {Object} params Optional parameters to pass to the handlers
 * @param {Object} value  Initial value of the return. Can be mangled by handlers
 *
 * @return {Bool}
 */
elgg.trigger_hook = function(name, type, params, value) {
	elgg.assertTypeOf('string', name);
	elgg.assertTypeOf('string', type);

	// default to true if unpassed
	value = value || true;

	var hooks = elgg.config.hooks,
		tempReturnValue = null,
		returnValue = value,
		callHookHandler = function(handler) {
			tempReturnValue = handler(name, type, params, value);
		};

	elgg.provide(name + '.' + type, hooks);
	elgg.provide('all.' + type, hooks);
	elgg.provide(name + '.all', hooks);
	elgg.provide('all.all', hooks);

	var hooksList = [];
	
	if (name != 'all' && type != 'all') {
		hooksList.push(hooks[name][type]);
	}

	if (type != 'all') {
		hooksList.push(hooks['all'][type]);
	}

	if (name != 'all') {
		hooksList.push(hooks[name]['all']);
	}

	hooksList.push(hooks['all']['all']);

	hooksList.every(function(handlers) {
		if (handlers instanceof elgg.ElggPriorityList) {
			handlers.forEach(callHookHandler);
		}
		return true;
	});

	return (tempReturnValue !== null) ? tempReturnValue : returnValue;
};
/**
 * Hold security-related data here
 */
elgg.provide('elgg.security');

elgg.security.token = {};

elgg.security.tokenRefreshFailed = false;

/**
 * Sets the currently active security token and updates all forms and links on the current page.
 *
 * @param {Object} json The json representation of a token containing __elgg_ts and __elgg_token
 * @return {Void}
 */
elgg.security.setToken = function(json) {	
	//update the convenience object
	elgg.security.token = json;

	//also update all forms
	$('[name=__elgg_ts]').val(json.__elgg_ts);
	$('[name=__elgg_token]').val(json.__elgg_token);

	// also update all links that contain tokens and time stamps
	$('[href*="__elgg_ts"][href*="__elgg_token"]').each(function() {
		this.href = this.href
			.replace(/__elgg_ts=\d*/, '__elgg_ts=' + json.__elgg_ts)
			.replace(/__elgg_token=[0-9a-f]*/, '__elgg_token=' + json.__elgg_token);
	});
};

/**
 * Security tokens time out, so lets refresh those every so often.
 * 
 * @todo handle error and bad return data
 */
elgg.security.refreshToken = function() {
	elgg.action('security/refreshtoken', function(data) {

		// @todo might want to move this to setToken() once http://trac.elgg.org/ticket/3127
		// is implemented. It's here right now to avoid soggy code.
		if (!data || !(data.output.__elgg_ts && data.output.__elgg_token)) {
			elgg.register_error(elgg.echo('js:security:token_refresh_failed', [elgg.get_site_url()]));
			elgg.security.tokenRefreshFailed = true;

			// don't setToken because we refresh every 5 minutes and tokens are good for 1
			// hour by default
			return;
		}

		// if had problems last time, let them know it's working now
		if (elgg.security.tokenRefreshFailed) {
			elgg.system_message(elgg.echo('js:security:token_refreshed', [elgg.get_site_url()]));
			elgg.security.tokenRefreshFailed = false;
		}
		
		elgg.security.setToken(data.output);
	});
};


/**
 * Add elgg action tokens to an object or string (assumed to be url data)
 *
 * @param {Object|string} data
 * @return {Object} The new data object including action tokens
 * @private
 */
elgg.security.addToken = function(data) {

	// 'http://example.com?data=sofar'
	if (elgg.isString(data)) {
		var args = [];
		if (data) {
			args.push(data);
		}
		args.push("__elgg_ts=" + elgg.security.token.__elgg_ts);
		args.push("__elgg_token=" + elgg.security.token.__elgg_token);

		return args.join('&');
	}

	// no input!  acts like a getter
	if (elgg.isUndefined(data)) {
		return elgg.security.token;
	}

	// {...}
	if (elgg.isPlainObject(data)) {
		return elgg.extend(data, elgg.security.token);
	}

	// oops, don't recognize that!
	throw new TypeError("elgg.security.addToken not implemented for " + (typeof data) + "s");
};

elgg.security.init = function() {
	//refresh security token every 5 minutes
	//this is set in the js/elgg PHP view.
	setInterval(elgg.security.refreshToken, elgg.security.interval);
};

elgg.register_hook_handler('boot', 'system', elgg.security.init);
/*globals vsprintf*/
/**
 * Provides language-related functionality
 */
elgg.provide('elgg.config.translations');

elgg.config.language = 'en';

/**
 * Analagous to the php version.  Merges translations for a
 * given language into the current translations map.
 */
elgg.add_translation = function(lang, translations) {
	elgg.provide('elgg.config.translations.' + lang);

	elgg.extend(elgg.config.translations[lang], translations);
};

/**
 * Load the translations for the given language.
 *
 * If no language is specified, the default language is used.
 * @param {string} language
 * @return {XMLHttpRequest}
 */
elgg.reload_all_translations = function(language) {
	var lang = language || elgg.get_language();

	elgg.getJSON('ajax/view/js/languages', {
		data: {
			language: lang
		},
		success: function(json) {
			elgg.add_translation(lang, json);
			elgg.config.languageReady = true;
			elgg.initWhenReady();
		}
	});
};

/**
 * Get the current language
 * @return {String}
 */
elgg.get_language = function() {
	var user = elgg.get_logged_in_user_entity();

	if (user && user.language) {
		return user.language;
	}

	return elgg.config.language;
};

/**
 * Translates a string
 *
 * @param {String} key      The string to translate
 * @param {Array}  argv     vsprintf support
 * @param {String} language The language to display it in
 *
 * @return {String} The translation
 */
elgg.echo = function(key, argv, language) {
	//elgg.echo('str', 'en')
	if (elgg.isString(argv)) {
		language = argv;
		argv = [];
	}

	//elgg.echo('str', [...], 'en')
	var translations = elgg.config.translations,
		dlang = elgg.get_language(),
		map;

	language = language || dlang;
	argv = argv || [];

	map = translations[language] || translations[dlang];
	if (map && map[key]) {
		return vsprintf(map[key], argv);
	}

	return key;
};

elgg.config.translations.init = function() {
	elgg.reload_all_translations();
};

elgg.register_hook_handler('boot', 'system', elgg.config.translations.init);
/*globals elgg, $*/
elgg.provide('elgg.ajax');

/**
 * @author Evan Winslow
 * Provides a bunch of useful shortcut functions for making ajax calls
 */

/**
 * Wrapper function for jQuery.ajax which ensures that the url being called
 * is relative to the elgg site root.
 *
 * You would most likely use elgg.get or elgg.post, rather than this function
 *
 * @param {string} url Optionally specify the url as the first argument
 * @param {Object} options Optional. {@see jQuery#ajax}
 * @return {XmlHttpRequest}
 */
elgg.ajax = function(url, options) {
	options = elgg.ajax.handleOptions(url, options);

	options.url = elgg.normalize_url(options.url);
	return $.ajax(options);
};
/**
 * @const
 */
elgg.ajax.SUCCESS = 0;

/**
 * @const
 */
elgg.ajax.ERROR = -1;

/**
 * Handle optional arguments and return the resulting options object
 *
 * @param url
 * @param options
 * @return {Object}
 * @private
 */
elgg.ajax.handleOptions = function(url, options) {
	var data_only = true,
		data,
		member;

	//elgg.ajax('example/file.php', {...});
	if (elgg.isString(url)) {
		options = options || {};

	//elgg.ajax({...});
	} else {
		options = url || {};
		url = options.url;
	}

	//elgg.ajax('example/file.php', function() {...});
	if (elgg.isFunction(options)) {
		data_only = false;
		options = {success: options};
	}

	//elgg.ajax('example/file.php', {data:{...}});
	if (options.data) {
		data_only = false;
	} else {
		for (member in options) {
			//elgg.ajax('example/file.php', {callback:function(){...}});
			if (elgg.isFunction(options[member])) {
				data_only = false;
			}
		}
	}

	//elgg.ajax('example/file.php', {notdata:notfunc});
	if (data_only) {
		data = options;
		options = {data: data};
	}

	if (url) {
		options.url = url;
	}

	return options;
};

/**
 * Wrapper function for elgg.ajax which forces the request type to 'get.'
 *
 * @param {string} url Optionally specify the url as the first argument
 * @param {Object} options {@see jQuery#ajax}
 * @return {XmlHttpRequest}
 */
elgg.get = function(url, options) {
	options = elgg.ajax.handleOptions(url, options);

	options.type = 'get';
	return elgg.ajax(options);
};

/**
 * Wrapper function for elgg.get which forces the dataType to 'json.'
 *
 * @param {string} url Optionally specify the url as the first argument
 * @param {Object} options {@see jQuery#ajax}
 * @return {XmlHttpRequest}
 */
elgg.getJSON = function(url, options) {
	options = elgg.ajax.handleOptions(url, options);

	options.dataType = 'json';
	return elgg.get(options);
};

/**
 * Wrapper function for elgg.ajax which forces the request type to 'post.'
 *
 * @param {string} url Optionally specify the url as the first argument
 * @param {Object} options {@see jQuery#ajax}
 * @return {XmlHttpRequest}
 */
elgg.post = function(url, options) {
	options = elgg.ajax.handleOptions(url, options);

	options.type = 'post';
	return elgg.ajax(options);
};

/**
 * Perform an action via ajax
 *
 * @example Usage 1:
 * At its simplest, only the action name is required (and anything more than the
 * action name will be invalid).
 * <pre>
 * elgg.action('name/of/action');
 * </pre>
 *
 * The action can be relative to the current site ('name/of/action') or
 * the full URL of the action ('http://elgg.org/action/name/of/action').
 *
 * @example Usage 2:
 * If you want to pass some data along with it, use the second parameter
 * <pre>
 * elgg.action('friend/add', { friend: some_guid });
 * </pre>
 *
 * @example Usage 3:
 * Of course, you will have no control over what happens when the request
 * completes if you do it like that, so there's also the most verbose method
 * <pre>
 * elgg.action('friend/add', {
 *     data: {
 *         friend: some_guid
 *     },
 *     success: function(json) {
 *         //do something
 *     },
 * }
 * </pre>
 * You can pass any of your favorite $.ajax arguments into this second parameter.
 *
 * @note If you intend to use the second field in the "verbose" way, you must
 * specify a callback method or the data parameter.  If you do not, elgg.action
 * will think you mean to send the second parameter as data.
 *
 * @note You do not have to add security tokens to this request.  Elgg does that
 * for you automatically.
 *
 * @see jQuery.ajax
 *
 * @param {String} action The action to call.
 * @param {Object} options
 * @return {XMLHttpRequest}
 */
elgg.action = function(action, options) {
	elgg.assertTypeOf('string', action);

	// support shortcut and full URLs
	// this will mangle URLs that aren't elgg actions.
	// Use post, get, or ajax for those.
	if (action.indexOf('action/') < 0) {
		action = 'action/' + action;
	}

	options = elgg.ajax.handleOptions(action, options);

	options.data = elgg.security.addToken(options.data);
	options.dataType = 'json';

	//Always display system messages after actions
	var custom_success = options.success || elgg.nullFunction;
	options.success = function(json, two, three, four) {
		if (json && json.system_messages) {
			elgg.register_error(json.system_messages.error);
			elgg.system_message(json.system_messages.success);
		}

		custom_success(json, two, three, four);
	};

	return elgg.post(options);
};

/**
 * Make an API call
 *
 * @example Usage:
 * <pre>
 * elgg.api('system.api.list', {
 *     success: function(data) {
 *         console.log(data);
 *     }
 * });
 * </pre>
 *
 * @param {String} method The API method to be called
 * @param {Object} options {@see jQuery#ajax}
 * @return {XmlHttpRequest}
 */
elgg.api = function (method, options) {
	elgg.assertTypeOf('string', method);

	var defaults = {
		dataType: 'json',
		data: {}
	};

	options = elgg.ajax.handleOptions(method, options);
	options = $.extend(defaults, options);

	options.url = 'services/api/rest/' + options.dataType + '/';
	options.data.method = method;

	return elgg.ajax(options);
};

/**
 * Provides session methods.
 */
elgg.provide('elgg.session');

/**
 * Helper function for setting cookies
 * @param {string} name
 * @param {string} value
 * @param {Object} options
 * 
 *  {number|Date} options[expires]
 * 	{string} options[path]
 * 	{string} options[domain]
 * 	{boolean} options[secure]
 * 
 * @return {string} The value of the cookie, if only name is specified
 */
elgg.session.cookie = function (name, value, options) {
	var cookies = [], cookie = [], i = 0, date, valid = true;
	
	//elgg.session.cookie()
	if (elgg.isUndefined(name)) {
		return document.cookie;
	}
	
	//elgg.session.cookie(name)
	if (elgg.isUndefined(value)) {
		if (document.cookie && document.cookie !== '') {
			cookies = document.cookie.split(';');
			for (i = 0; i < cookies.length; i += 1) {
				cookie = jQuery.trim(cookies[i]).split('=');
				if (cookie[0] === name) {
					return decodeURIComponent(cookie[1]);
				}
			}
		}
		return undefined;
	}
	
	// elgg.session.cookie(name, value[, opts])
	options = options || {};
	
	if (elgg.isNull(value)) {
		value = '';
		options.expires = -1;
	}
	
	cookies.push(name + '=' + value);
	
	if (elgg.isNumber(options.expires)) {
		if (elgg.isNumber(options.expires)) {
			date = new Date();
			date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
		} else if (options.expires.toUTCString) {
			date = options.expires;
		} else {
			valid = false;
		}
		
		if (valid) {
			cookies.push('expires=' + date.toUTCString());
		}
	}
	
	// CAUTION: Needed to parenthesize options.path and options.domain
	// in the following expressions, otherwise they evaluate to undefined
	// in the packed version for some reason.
	if (options.path) {
		cookies.push('path=' + (options.path));
	}

	if (options.domain) {
		cookies.push('domain=' + (options.domain));
	}
	
	if (options.secure) {
		cookies.push('secure');
	}
	
	document.cookie = cookies.join('; ');
};

/**
 * Returns the object of the user logged in.
 *
 * @return {ElggUser} The logged in user
 */
elgg.get_logged_in_user_entity = function() {
	return elgg.session.user;
};

/**
 * Returns the GUID of the logged in user or 0.
 *
 * @return {number} The GUID of the logged in user
 */
elgg.get_logged_in_user_guid = function() {
	var user = elgg.get_logged_in_user_entity();
	return user ? user.guid : 0;
};

/**
 * Returns if a user is logged in.
 *
 * @return {boolean} Whether there is a user logged in
 */
elgg.is_logged_in = function() {
	return (elgg.get_logged_in_user_entity() instanceof elgg.ElggUser);
};

/**
 * Returns if the currently logged in user is an admin.
 *
 * @return {boolean} Whether there is an admin logged in
 */
elgg.is_admin_logged_in = function() {
	var user = elgg.get_logged_in_user_entity();
	return (user instanceof elgg.ElggUser) && user.isAdmin();
};

/**
 * @deprecated Use elgg.session.cookie instead
 */
jQuery.cookie = elgg.session.cookie;
/**
 * Provides page owner and context functions
 *
 * @todo This is a stub. Page owners can't be fully implemented until
 * the 4 types are finished.
 */

/**
 * @return {number} The GUID of the logged in user
 */
elgg.get_page_owner_guid = function() {
	return elgg.page_owner.guid || 0;
};


elgg.provide('elgg.config');

/**
 * Returns the current site URL
 *
 * @return {String} The site URL.
 */
elgg.get_site_url = function() {
	return elgg.config.wwwroot;
}
elgg.provide('elgg.ui');

elgg.ui.init = function () {
	elgg.ui.initHoverMenu();

	//if the user clicks a system message, make it disappear
	$('.elgg-system-messages li').live('click', function() {
		$(this).stop().fadeOut('fast');
	});

	$('.elgg-system-messages li').animate({opacity: 0.9}, 6000);
	$('.elgg-system-messages li').fadeOut('slow');

	$('[rel=toggle]').live('click', elgg.ui.toggles);

	$('[rel=popup]').live('click', elgg.ui.popsUp);

	$('.elgg-menu-page .elgg-menu-parent').live('click', elgg.ui.toggleMenu);

	$('.elgg-requires-confirmation').live('click', elgg.ui.requiresConfirmation);

	$('.elgg-autofocus').focus();

	if ($('.elgg-input-date').length) {
		elgg.ui.initDatePicker();
	}
}

/**
 * Toggles an element based on clicking a separate element
 *
 * Use rel="toggle" on the toggler element
 * Set the href to target the item you want to toggle (<a rel="toggle" href="#id-of-target">)
 *
 * @param {Object} event
 * @return void
 */
elgg.ui.toggles = function(event) {
	event.preventDefault();

	// @todo might want to switch this to elgg.getSelectorFromUrlFragment().
	var target = $(this).toggleClass('elgg-state-active').attr('href');

	$(target).slideToggle('medium');
}

/**
 * Pops up an element based on clicking a separate element
 *
 * Set the rel="popup" on the popper and set the href to target the
 * item you want to toggle (<a rel="popup" href="#id-of-target">)
 *
 * This function emits the getOptions, ui.popup hook that plugins can register for to provide custom
 * positioning for elements.  The handler is passed the following params:
 *	targetSelector: The selector used to find the popup
 *	target:         The popup jQuery element as found by the selector
 *	source:         The jquery element whose click event initiated a popup.
 *
 * The return value of the function is used as the options object to .position().
 * Handles can also return false to abort the default behvior and override it with their own.
 *
 * @param {Object} event
 * @return void
 */
elgg.ui.popsUp = function(event) {
	event.preventDefault();
	event.stopPropagation();

	var target = elgg.getSelectorFromUrlFragment($(this).toggleClass('elgg-state-active').attr('href'));
	var $target = $(target);

	// emit a hook to allow plugins to position and control popups
	var params = {
		targetSelector: target,
		target: $target,
		source: $(this)
	};

	var options = {
		my: 'center top',
		at: 'center bottom',
		of: $(this),
		collision: 'fit fit'
	}

	options = elgg.trigger_hook('getOptions', 'ui.popup', params, options);

	// allow plugins to cancel event
	if (!options) {
		return;
	}

	// hide if already open
	if ($target.is(':visible')) {
		$target.fadeOut();
		$('body').die('click', elgg.ui.popupClose);
		return;
	}

	$target.appendTo('body')
		.fadeIn()
		.position(options);

	$('body')
		.die('click', elgg.ui.popupClose)
		.live('click', elgg.ui.popupClose);
}

/**
 * Catches clicks that aren't in a popup and closes all popups.
 */
elgg.ui.popupClose = function(event) {
	$eventTarget = $(event.target);
	var inTarget = false;
	var $popups = $('[rel=popup]');

	// if the click event target isn't in a popup target, fade all of them out.
	$popups.each(function(i, e) {
		var target = elgg.getSelectorFromUrlFragment($(e).attr('href')) + ':visible';
		var $target = $(target);

		if (!$target.is(':visible')) {
			return;
		}

		// didn't click inside the target
		if ($eventTarget.closest(target).length > 0) {
			inTarget = true;
			return false;
		}
	});

	if (!inTarget) {
		$popups.each(function(i, e) {
			var $e = $(e);
			var $target = $(elgg.getSelectorFromUrlFragment($e.attr('href')) + ':visible');
			if ($target.length > 0) {
				$target.fadeOut();
				$e.removeClass('elgg-state-active');
			}
		});

		$('body').die('click', elgg.ui.popClose);
	}
}

/**
 * Toggles a child menu when the parent is clicked
 *
 * @param {Object} event
 * @return void
 */
elgg.ui.toggleMenu = function(event) {
	$(this).siblings().slideToggle('medium');
	$(this).toggleClass('elgg-menu-closed elgg-menu-opened');
	event.preventDefault();
}

/**
 * Initialize the hover menu
 *
 * @param {Object} parent
 * @return void
 */
elgg.ui.initHoverMenu = function(parent) {
	if (!parent) {
		parent = document;
	}

	// avatar image menu link
	$(parent).find(".elgg-avatar").live('mouseover', function() {
		$(this).children(".elgg-icon-hover-menu").show();
	})
	.live('mouseout', function() {
		$(this).children(".elgg-icon-hover-menu").hide();
	});


	// avatar contextual menu
	$(".elgg-avatar > .elgg-icon-hover-menu").live('click', function(e) {
		// check if we've attached the menu to this element already
		var $hovermenu = $(this).data('hovermenu') || null;

		if (!$hovermenu) {
			var $hovermenu = $(this).parent().find(".elgg-menu-hover");
			$(this).data('hovermenu', $hovermenu);
		}

		// close hovermenu if arrow is clicked & menu already open
		if ($hovermenu.css('display') == "block") {
			$hovermenu.fadeOut();
		} else {
			$avatar = $(this).closest(".elgg-avatar");

			// @todo Use jQuery-ui position library instead -- much simpler
			var offset = $avatar.offset();
			var top = $avatar.height() + offset.top + 'px';
			var left = $avatar.width() - 15 + offset.left + 'px';

			$hovermenu.appendTo('body')
					.css('position', 'absolute')
					.css("top", top)
					.css("left", left)
					.fadeIn('normal');
		}

		// hide any other open hover menus
		$(".elgg-menu-hover:visible").not($hovermenu).fadeOut();
	});

	// hide avatar menu when user clicks elsewhere
	$(document).click(function(event) {
		if ($(event.target).parents(".elgg-avatar").length == 0) {
			$(".elgg-menu-hover").fadeOut();
		}
	});
}

/**
 * Calls a confirm() and prevents default if denied.
 *
 * @param {Object} e
 * @return void
 */
elgg.ui.requiresConfirmation = function(e) {
	var confirmText = $(this).attr('rel') || elgg.echo('question:areyousure');
	if (!confirm(confirmText)) {
		e.preventDefault();
	}
};

/**
 * Repositions the login popup
 *
 * @param {String} hook    'getOptions'
 * @param {String} type    'ui.popup'
 * @param {Object} params  An array of info about the target and source.
 * @param {Object} options Options to pass to
 *
 * @return {Object}
 */
elgg.ui.LoginHandler = function(hook, type, params, options) {
	if (params.target.attr('id') == 'login-dropdown-box') {
		options.my = 'right top';
		options.at = 'right bottom';
		return options;
	}
	return null;
};

/**
 * Initialize the date picker
 *
 * Uses the class .elgg-input-date as the selector.
 *
 * If the class .elgg-input-timestamp is set on the input element, the onSelect
 * method converts the date text to a unix timestamp in seconds. That value is
 * stored in a hidden element indicated by the id on the input field.
 *
 * @return void
 */
elgg.ui.initDatePicker = function() {
	$('.elgg-input-date').datepicker({
		// ISO-8601
		dateFormat: 'yy-mm-dd',
		onSelect: function(dateText) {
			if ($(this).is('.elgg-input-timestamp')) {
				// convert to unix timestamp
				var date = $.datepicker.parseDate('yy-mm-dd', dateText);
				var timestamp = $.datepicker.formatDate('@', date);
				timestamp = timestamp / 1000;

				var id = $(this).attr('id');
				$('input[name="' + id + '"]').val(timestamp);
			}
		}
	});
}


elgg.register_hook_handler('init', 'system', elgg.ui.init);
elgg.register_hook_handler('getOptions', 'ui.popup', elgg.ui.LoginHandler);
elgg.provide('elgg.ui.widgets');

/**
 * Widgets initialization
 *
 * @return void
 */
elgg.ui.widgets.init = function() {

	// widget layout?
	if ($(".elgg-widgets").length == 0) {
		return;
	}

	$(".elgg-widgets").sortable({
		items:                'div.elgg-module-widget.elgg-state-draggable',
		connectWith:          '.elgg-widgets',
		handle:               'div.elgg-head',
		forcePlaceholderSize: true,
		placeholder:          'elgg-widget-placeholder',
		opacity:              0.8,
		revert:               500,
		stop:                 elgg.ui.widgets.move
	});

	$('.elgg-widgets-add-panel li.elgg-state-available').click(elgg.ui.widgets.add);

	$('a.elgg-widget-delete-button').live('click', elgg.ui.widgets.remove);
	$('.elgg-widget-edit > form ').live('submit', elgg.ui.widgets.saveSettings);
	$('a.elgg-widget-collapse-button').live('click', elgg.ui.widgets.collapseToggle);

	elgg.ui.widgets.equalHeight(".elgg-widgets");
};

/**
 * Adds a new widget
 *
 * Makes Ajax call to persist new widget and inserts the widget html
 *
 * @param {Object} event
 * @return void
 */
elgg.ui.widgets.add = function(event) {
	// elgg-widget-type-<type>
	var type = $(this).attr('id');
	type = type.substr(type.indexOf('elgg-widget-type-') + "elgg-widget-type-".length);

	// if multiple instances not allow, disable this widget type add button
	var multiple = $(this).attr('class').indexOf('elgg-widget-multiple') != -1;
	if (multiple == false) {
		$(this).addClass('elgg-state-unavailable');
		$(this).removeClass('elgg-state-available');
		$(this).unbind('click', elgg.ui.widgets.add);
	}

	elgg.action('widgets/add', {
		data: {
			handler: type,
			owner_guid: elgg.get_page_owner_guid(),
			context: $("input[name='widget_context']").val(),
			default_widgets: $("input[name='default_widgets']").val() || 0
		},
		success: function(json) {
			$('#elgg-widget-col-1').prepend(json.output);
		}
	});
	event.preventDefault();
}

/**
 * Persist the widget's new position
 *
 * @param {Object} event
 * @param {Object} ui
 *
 * @return void
 */
elgg.ui.widgets.move = function(event, ui) {

	// elgg-widget-<guid>
	var guidString = ui.item.attr('id');
	guidString = guidString.substr(guidString.indexOf('elgg-widget-') + "elgg-widget-".length);

	// elgg-widget-col-<column>
	var col = ui.item.parent().attr('id');
	col = col.substr(col.indexOf('elgg-widget-col-') + "elgg-widget-col-".length);

	elgg.action('widgets/move', {
		data: {
			widget_guid: guidString,
			column: col,
			position: ui.item.index()
		}
	});

	// @hack fixes jquery-ui/opera bug where draggable elements jump
	ui.item.css('top', 0);
	ui.item.css('left', 0);
}

/**
 * Removes a widget from the layout
 *
 * Event callback the uses Ajax to delete the widget and removes its HTML
 *
 * @param {Object} event
 * @return void
 */
elgg.ui.widgets.remove = function(event) {
	var $widget = $(this).parent().parent();

	// if widget type is single instance type, enable the add buton
	var type = $widget.attr('class');
	// elgg-widget-instance-<type>
	type = type.substr(type.indexOf('elgg-widget-instance-') + "elgg-widget-instance-".length);
	$button = $('#elgg-widget-type-' + type);
	var multiple = $button.attr('class').indexOf('elgg-widget-multiple') != -1;
	if (multiple == false) {
		$button.addClass('elgg-state-available');
		$button.removeClass('elgg-state-unavailable');
		$button.unbind('click', elgg.ui.widgets.add); // make sure we don't bind twice
		$button.click(elgg.ui.widgets.add);
	}

	$widget.remove();

	// elgg-widget-delete-button-<guid>
	var id = $(this).attr('id');
	id = id.substr(id.indexOf('elgg-widget-delete-button-') + "elgg-widget-delete-button-".length);

	elgg.action('widgets/delete', {
		data: {
			widget_guid: id
		}
	});
	event.preventDefault();
}

/**
 * Toggle the collapse state of the widget
 *
 * @param {Object} event
 * @return void
 */
elgg.ui.widgets.collapseToggle = function(event) {
	$(this).toggleClass('elgg-widget-collapsed');
	$(this).parent().parent().find('.elgg-body').slideToggle('medium');
	event.preventDefault();
}

/**
 * Save a widget's settings
 *
 * Uses Ajax to save the settings and updates the HTML.
 *
 * @param {Object} event
 * @return void
 */
elgg.ui.widgets.saveSettings = function(event) {
	$(this).parent().slideToggle('medium');
	var $widgetContent = $(this).parent().parent().children('.elgg-widget-content');

	// stick the ajax loader in there
	var $loader = $('#elgg-widget-loader').clone();
	$loader.attr('id', '#elgg-widget-active-loader');
	$loader.removeClass('hidden');
	$widgetContent.html($loader);

	var default_widgets = $("input[name='default_widgets']").val() || 0;
	if (default_widgets) {
		$(this).append('<input type="hidden" name="default_widgets" value="1">');
	}

	elgg.action('widgets/save', {
		data: $(this).serialize(),
		success: function(json) {
			$widgetContent.html(json.output);
		}
	});
	event.preventDefault();
}

/**
 * Make all elements have the same min-height
 *
 * This addresses the issue of trying to drag a widget into a column that does
 * not have any widgets.
 *
 * @param {String} selector
 * @return void
 */
elgg.ui.widgets.equalHeight = function(selector) {
	var maxHeight = 0;
	$(selector).each(function() {
		if ($(this).height() > maxHeight) {
			maxHeight = $(this).height();
		}
	})
	$(selector).css('min-height', maxHeight);
}

elgg.register_hook_handler('init', 'system', elgg.ui.widgets.init);


elgg.version = '2011092500';
elgg.release = '1.8.1b1';
elgg.config.wwwroot = 'http://www.doenersnet.nl/';
elgg.security.interval = 5 * 60 * 1000; elgg.config.domReady = false;
elgg.config.languageReady = false;

//After the DOM is ready
$(function() {
	elgg.config.domReady = true;
	elgg.initWhenReady();
});

elgg.register_hook_handler('init', 'system', function() {
	// only do this on the profile page's widget canvas.
	if ($('.profile').length) {
		$('#elgg-widget-col-1').css('min-height', $('.profile').outerHeight(true) + 1);
	}
});//<script>
elgg.provide('elgg.messageboard');

elgg.messageboard.init = function() {
	var form = $('form[name=elgg-messageboard]');
	form.find('input[type=submit]').live('click', elgg.messageboard.submit);

	// remove the default binding for confirmation since we're doing extra stuff.
	// @todo remove if we add a hook to the requires confirmation callback
	form.parent().find('a.elgg-requires-confirmation')
		.click(elgg.messageboard.deletePost)

		// double whammy for in case the load order changes.
		.unbind('click', elgg.ui.requiresConfirmation)
		.removeClass('elgg-requires-confirmation');
}

elgg.messageboard.submit = function(e) {
	var form = $(this).parents('form');
	var data = form.serialize();

	elgg.action('messageboard/add', {
		data: data,
		success: function(json) {
			// the action always returns the full ul and li wrapped annotation.
			var ul = form.next('ul.elgg-list-annotation');

			if (ul.length < 1) {
				form.parent().append(json.output);
			} else {
				ul.prepend($(json.output).find('li:first'));
			};
			form.find('textarea').val('');
		}
	});

	e.preventDefault();
}

elgg.messageboard.deletePost = function(e) {
	var link = $(this);
	var confirmText = link.attr('title') || elgg.echo('question:areyousure');

	if (confirm(confirmText)) {
		elgg.action($(this).attr('href'), {
			success: function() {
				$(link).closest('li').remove();
			}
		});
	}

	e.preventDefault();
}

elgg.register_hook_handler('init', 'system', elgg.messageboard.init);

elgg.provide('elgg.uservalidationbyemail');

elgg.uservalidationbyemail.init = function() {
	$('.unvalidated-users-checkall').click(function() {
		checked = $(this).attr('checked');
		$('form[name=unvalidated-users]').find('input[type=checkbox]').attr('checked', checked);
	});

	$('.unvalidated-users-bulk-post').click(function(event) {
		$form = $('form[name=unvalidated-users]');
		event.preventDefault();

		// check if there are selected users
		if ($form.find('input[type=checkbox]:checked').length < 1) {
			return false;
		}

		// confirmation
		if (!confirm($(this).attr('title'))) {
			return false;
		}

		$form.attr('action', $(this).attr('href')).submit();
	});
}

elgg.register_hook_handler('init', 'system', elgg.uservalidationbyemail.init);
// Profile Manager More Info tooltips
$(document).ready(function(){
	$("span.custom_fields_more_info").live('mouseover', function(e) {
			var tooltip = $("#text_" + $(this).attr('id'));
			$("body").append("<p id='custom_fields_more_info_tooltip'>"+ $(tooltip).html() + "</p>");
		
			if (e.pageX < 900) {
				$("#custom_fields_more_info_tooltip")
					.css("top",(e.pageY + 10) + "px")
					.css("left",(e.pageX + 10) + "px")
					.fadeIn("medium");	
			}	
			else {
				$("#custom_fields_more_info_tooltip")
					.css("top",(e.pageY + 10) + "px")
					.css("left",(e.pageX - 260) + "px")
					.fadeIn("medium");		
			}			
		}).live('mouseout', function() {
			$("#custom_fields_more_info_tooltip").remove();
		}
	);	
	
	$("#profile_manager_profile_edit_tabs a").click(function(){
		var id = $(this).attr("href").replace("#", ""); 
		$("#profile_manager_profile_edit_tabs li").removeClass("elgg-state-selected");
		$(this).parent().addClass("elgg-state-selected");
	
		$('#profile_manager_profile_edit_tab_content_wrapper>div').hide();
		$('#profile_manager_profile_edit_tab_content_' + id).show();
	});
	
	$("#profile_manager_profile_edit_tabs a:first").click();
});

function changeProfileType(){
	var selVal = $('#custom_profile_type').val();
	
	$('.custom_fields_edit_profile_category').hide();
	$('.custom_profile_type_description').hide();

	if(selVal != ""){
		$('.custom_profile_type_' + selVal).show();
		$('#custom_profile_type_description_'+ selVal).show();
	}
	
	if($("#profile_manager_profile_edit_tabs li.elgg-state-selected:visible").length == 0){
		$("#profile_manager_profile_edit_tabs a:first").click();
	}
}//<script>
function translation_editor_disable_language(){
	var url = elgg.security.addToken("http://www.doenersnet.nl/action/translation_editor/disable_languages?");
	
	var lan = new Array();
	$('#translation_editor_language_table input[name="disabled_languages[]"]:checked').each(function(index, elm){
		lan.push($(this).val());
	});

	$.post(url, {'disabled_languages[]': lan });
}

function toggleViewMode(mode){
	$("#translation_editor_plugin_toggle a").removeClass("view_mode_active");
	$("#view_mode_" + mode).addClass("view_mode_active");
	
	if(mode == "all"){
		$("#translation_editor_plugin_form tr").show();
	} else {
		$("#translation_editor_plugin_form tr").hide();
		$("#translation_editor_plugin_form tr[rel='" + mode + "']").show();
		$("#translation_editor_plugin_form tr:first").show();
	}
}

function translationEditorJQuerySave(){
	var url = $('#translation_editor_plugin_form').attr("action") + "?jquery=yes";
	var formData = $('#translation_editor_plugin_form').serialize();

	$.post(url, formData, function(data){}, "json");
}

function translationEditorJQuerySearchSave(){
	var url = $('#translation_editor_search_result_form').attr("action") + "?jquery=yes";
	var formData = $('#translation_editor_search_result_form').serialize();

	$.post(url, formData, function(data){}, "json");
}
function socialink_toggle_network_configure(elem, network){
	if($(elem).val() == "yes"){
		$('#socialink_' + network + '_sync_configure').addClass('socialink_network_sync_allow');
	} else {
		$('#socialink_' + network + '_sync_configure').removeClass('socialink_network_sync_allow');
		$('#socialink_' + network + '_sync_fields').hide();
	}
}//<script>

/**
 * This retrieves the members of a group to display in a form.
 *
 * @param Node group_element
 * @param targetElement
 */
function updateGroupMembers(group_element) {
	group_id = $(group_element).val();
	
	// Collect selected contacts
	contacts = new Array();
	$('input.contact-selected').each(function () {
		contacts.push($(this).val());
	});

	// Collect selected admins
	admins = new Array();
	$('input.manager-selected').each(function () {
		admins.push($(this).val());
	});

	$.getJSON(own_url + "activiteiten/ajax/list_group_members/" + group_id,
		function (data) {
			// Do Contacts
			targetElement = '#activity_form_edit_contact_person';
		
			// Find default option (text)
			defaultText = $(targetElement +' option[value=""]').remove();
			
			// truncate contacts-select
			$(targetElement +' option').remove();
			
			// Add default
			$(targetElement).append(defaultText);
			
			// Add group-members
			for (i=0;i<data.length;i++) {
				name = data[i].name;
				id = data[i].guid;

				// skip already-selected ids
				if (in_array(id, contacts)) {
					continue;
				}

				$(targetElement).append('<option value="'+ id +'">'+ name +'</option>');
			}

			// Do admins
			targetElement = '#activity_form_edit_manager';

			// Find default option (text)
			defaultText = $(targetElement +' option[value=""]').remove();

			// truncate contacts-select
			$(targetElement +' option').remove();

			// Add default
			$(targetElement).append(defaultText);

			// Add group-members
			for (i=0;i<data.length;i++) {
				name = data[i].name;
				id = data[i].guid;

				// skip selected ids
				if (in_array(id, admins)) {
					continue;
				}

				$(targetElement).append('<option value="'+ id +'">'+ name +'</option>');
			}
		}
	);
}

/**
 * This function locks the contact to the activity by replacing the form elements with hidden fields.
 * It also duplicates the form-element and reinitialises the available options.
 *
 * @param Node source
 * @return boolean false to stop propagation
 */
function add_contact(source) {
	if (is_valid_contact(source)) {
		duplicate_form_segment(source)
		lock_contact(source);
	}

	return false;
}

/**
 * Deletes contact from list and feeds the name and ID back into the other selectboxes
 *
 * @param source origin of event
 */
function del_contact(source) {
	dat = $(source).parents('.contact-segment').eq(0);
	dat_extra = dat.next('.contact-segment-extra').eq(0);
	
	dat_extra.remove();
	
	name = $('.contact', dat).eq(0).text();
	id = $('.hidden-id', dat).eq(0).val();
	
	dat.remove();
	
	$('.contact-segment select').append($("<option value=\""+ id +"\">"+ name +"</option>"));
	return false;
}

/** 
 * Verifies if contact in the selectbox is actually a contact.
 *
 * @param source the source lement
 * @return true or false, answering above question.
 */
function is_valid_contact(source){
	retval = false;

	contact_form = $(source).parents('.contact-segment').eq(0);
	if ($('.basic-contact', contact_form).val() != "") {
		retval = true;
	}
	
	return retval;
}

/**
 * This converts selectboxes into plain text with hidden fields and adds a remove-link.
 */
function lock_contact(source) {
	contact_form = $(source).parents('.contact-segment').eq(0);

	// Turn self into plain-text with two added fields
	dat = contact_form.find('.basic-contact :selected', contact_form).eq(0);
	fieldname = contact_form.find('.basic-contact', contact_form).eq(0).attr('name');
	name = dat.text();
	val = dat.attr('value');
	
	select_field = $('.basic-contact', contact_form);
	
	$("<p class=\"contact\">"+ name +" <a href=\"#\" class=\"minus_link\" title=\"-\" onclick=\"return del_contact(this);\"></a></p>").insertBefore(select_field);
	$("<input type=\"hidden\" class=\"hidden-id contact-selected\" name=\""+ fieldname +"\" value=\""+ val +"\"/>").insertBefore(select_field);
	
	select_field.next('a.plus_link').remove();
	select_field.remove();
}

/**
 * This duplicates a form-segment and removes double options from form-items.
 *
 * @param node the node to duplicate
 */
function duplicate_form_segment(segment) {
	// Get original
	contact_form = $(segment).parents('.contact-segment').eq(0);
	contact_form_extra = contact_form.next('.contact-segment-extra').eq(0);
	
	last_extra = $('.contact-segment-extra').eq($('.contact-segment-extra').size()-1);
	
	// duplicate
	new_part = contact_form.clone();
	new_extra = contact_form_extra.clone();
	new_part.insertAfter(last_extra);
	new_extra.insertAfter(new_part);
	
	// set defaults and remove used username in the dropdown
	$('.extra-phone', new_extra).val(own_strings.activity_form_contact_phone);
	$('.extra-email', new_extra).val(own_strings.activity_form_contact_email);
	
	var used_members = [];
	$('.basic-contact').each(function () {
		val = $(':selected', this).val();
		if (val != "") {
			used_members.push(parseInt(val, 10));
		}
	});
	
	$('.basic-contact option', new_part).each(function () {
		if (in_array(parseInt($(this).attr('value'), 10), used_members)) {
			$(this).remove();
		}
	});
}

function in_array(needle, haystack) {
	for (var i=0;i<haystack.length;i++) {
		if (haystack[i] == needle) {
			return true;
		}
	}
	
	return false;
}

/**
 * Adds a link field
 *
 * @param source the parent element
 */
function add_link_field(source) {
	ctr = $('.form-links');
	blocks = ctr.find('.field_set');
	last_block = blocks.eq(blocks.size()-1);
	new_block = last_block.clone().insertAfter(last_block);

	new_block.find('input').eq(0).attr('value', '');

	return false;
}

/**
 * Clears an input field if the current value is the "default" value.
 *
 * @param element triggering element
 * @return void
 */
function clearme(element){
	var elval = $(element).val();
	if ($(element).hasClass('extra-phone') && elval == own_strings.activity_form_contact_phone) {
		$(element).val('');
	} else if ($(element).hasClass('extra-phone') && elval == vac_own_strings.vacancy_form_contact_phone) {
		$(element).val('');
	} else if ($(element).hasClass('extra-email') && elval == own_strings.activity_form_contact_email) {
		$(element).val('');
	} else if ($(element).hasClass('extra-email') && elval == vac_own_strings.vacancy_form_contact_email) {
		$(element).val('');
	}
}

/**
 * locks the manager field and adds a new selectbox.
 *
 * @param source triggering element
 * @return false if everything went ok (to stop propagation)
 */
function add_manager(source) {
	if (is_valid_manager(source)) {
		list_manager(source);
		remove_manager_from_select(source);
	}
	
	return false;
}

function list_manager(source) {
	select = $(source).prev('select').eq(0);
	option = $(':selected', select);
	
	name = option.text();
	id = option.attr('value');
	
	text = "<div>"+ name +" <a href=\"#\" class=\"minus_link\" title=\"-\" onclick=\"return del_manager(this);\"></a>";
	text += "<input type=\"hidden\" name=\"activity_form_edit_manager[]\" class=\"manager-selected\" value=\""+ id +"\"/>";
	text += "</div>"

	$(text).insertBefore(select);
}

function remove_manager_from_select(source) {
	$(source).prev('select').eq(0).find(':selected').remove();
}

/**
 * Deletes the manager from the fields and puts it back in the selectbox
 */
function del_manager(source) {
	// Removes parent p-tag and adds name/id to the selectbox
	dat = $(source).parents('div').eq(0);
	
	id = dat.find('input').val();
	name = dat.text();
	
	$('.basic-manager').append($("<option value=\""+ id +"\">"+ name +"</option>"));
	
	dat.remove();
	return false;
}

/** 
 * Verifies if selected manager in the selectbox is actually a manager
 */
function is_valid_manager(source) {
	retval = false;
	if ($(source).prev('select').eq(0).val() != "") {
		retval = true;
	}
	
	return retval;
}

/**
 * Enables and disables the "to" date field
 *
 * @param source element triggering the event
 */
function daterange_change(source) {
	range = $('.date-range:checked').attr('value');
	if (range == "single") {
		$('#datetime_end').attr("disabled", "disabled");
		$('div.datepicker_field_end_container').css("display","none");
		$('span.from_date').addClass('hidden');
	} else {
		$('#datetime_end').removeAttr('disabled');
		$('div.datepicker_field_end_container').css("display","block");
		$('span.from_date').removeClass('hidden');
	}
	
	update_num_days();

}

/**
 * Enables and disables the time-range fields.
 *
 * @param source element triggering the event
 */
function timerange_change(source) {
	range = $('.time-range-radio:checked').attr('value');
	if (range != "same") {
		$('.time-range').attr("disabled", "disabled");
	} else {
		$('.time-range').removeAttr('disabled');
	}
	
	if (range == "shifts") {
		$('#activity_form_available_reservations_number').attr("disabled", "disabled");
		$('#activity_form_available_reservations_friends').attr("disabled", "disabled");
		$('#activity_form_available_reservations_friends').removeAttr('checked');
		$('#activity_form_available_reservations_number').val("0");
		$('p.reservations_number_extra_text').removeClass("hidden");
	} else {
		$('#activity_form_available_reservations_number').removeAttr('disabled');
		$('#activity_form_available_reservations_friends').removeAttr('disabled');
		$('p.reservations_number_extra_text').addClass("hidden");
	}
	
	// toggle shift forms
	toggleShiftFormsVisibility();
}

/**
 * Enables or disables the publish-date field
 */
function publish_change() {
	range = $('.publish-radio:checked').attr('value');
	
	if (range == 'postpone') {
		$('input[name="publish-date"]').removeAttr('disabled');
	} else {
		$('input[name="publish-date"]').attr('disabled', 'disabled');
	}
}

/**
 * Enables or disables the reaction-date field
 */
function reaction_change() {
	range = $('.reaction-radio:checked').attr('value');
	
	if (range == 'date') {
		$('input[name="reaction-date"]').removeAttr('disabled');
	} else {
		$('input[name="reaction-date"]').attr('disabled', 'disabled');
	}
}

/** @{ messages */
/**
 * Returns the base for other functions based on the triggering element
 *
 * @param source the triggering element
 * @return string
 */
function getBase(source) {
	base = "activity_";
	
	return base;
}

/**
 * replies to selected messages
 *
 * @param source Element triggering the event
 */
function messagesReply(source){
	base = getBase(source);
	ajaxurl = 'activiteiten/ajax/';
	
	recps = new Array();
	$('#'+ base +'message_inbox_table_container input.message-checkbox:checked').each(function () {
		message_guid = parseInt($(this).attr('id').match(/_([0-9]+)/)[1], 10);
		recps.push(message_guid);
	});

	$('#recipient-list .recipient-line').remove();

	// Load user-guids, connect them to message-guids and make sure add/remove functionality gets this.
	// We require message-guids later during sending to provide the sender with subjects.
	$.getJSON(own_url + "activiteiten/ajax/get_message_owners/" + array_serialize(recps),
		function (data) {
			var excludes = new Array();
			for (i=0;i<data.length;i++) {
				this_item = data[i];
				
				id = this_item[0];
				name = this_item[1];
				
				excludes.push(id);

				dat = '<dd class="recipient-line"><input type="hidden" name="'+ base +'reply_message_receiver[]" value="'+ id +'"/>'+ name +'<a href="#" onclick="return remRecipient(this);" class="remove" title="verwijderen"><span class="hidden">x</span></a></dd>';
				
				$('#recipient-list').append(dat);
			}

			$('#'+ base +'reply_message_receiver option').each(function() {
				if (this.value != '') {
					$(this).remove();
				}
			})

			// Create list for selectbox
			$.getJSON(own_url + 'activiteiten/ajax/get_senders/'+ cur_entity_guid,
				function (subdata) {
					for (i=0;i<subdata.length;i++) {
						this_item = subdata[i];

						// Skip if item in exclude-array
						if (in_array(this_item[0], excludes)) {
							continue;
						}

						// Add item to selectbox
						dat = '<option value="'+ this_item[0] +'">'+ this_item[1] +'</option>';
						$('#'+ base +'reply_message_receiver').append(dat);
					}
				}
			);
		}
	);

	// Hide and show relevant fields
	$('#message-compose-new').hide();
	$('#message-compose-reply').show();
	$('input[name='+ base +'new_message_subject]').hide();
	$('.subject-label').hide();

	// Fill recipient-hidden with guids
	$('#'+ base +'message_new_message_overlay .message-guids').val(array_serialize(recps));
	
	// Display form
	showOverlay(base +'message_new_message_overlay');
}

/**
 * replies to selected applicants
 *
 * @param source Element triggering the event
 */
function messagesApplicants(source){
	base = getBase(source);
	
	ajaxurl = 'activiteiten/ajax/';
	
	recps = new Array();
	$('.applicants input.message-checkbox:checked').each(function () {
		message_guid = parseInt($(this).attr('id').match(/_([0-9]+)/)[1], 10);
		recps.push(message_guid);
	});
	
	$('#recipient-list .recipient-line').remove();

	// Load user-guids, connect them to message-guids and make sure add/remove functionality gets this.
	// We require message-guids later during sending to provide the sender with subjects.
	$.getJSON(own_url + "activiteiten/ajax/get_message_owners/" + array_serialize(recps),
		function (data) {
			var excludes = new Array();
			for (i=0;i<data.length;i++) {
				this_item = data[i];
				
				id = this_item[0];
				name = this_item[1];

				excludes.push(id);

				dat = '<dd class="recipient-line"><input type="hidden" name="'+ base +'reply_message_receiver[]" value="'+ id +'"/>'+ name +'<a href="#" onclick="return remRecipient(this);" class="remove" title="verwijderen"><span class="hidden">x</span></a></dd>';
				
				$('#recipient-list').append(dat);
			}

			$('#'+ base +'reply_message_receiver option').each(function() {
				if (this.value != '') {
					$(this).remove();
				}
			})

			// Create list for selectbox
			$.getJSON(own_url + 'activiteiten/ajax/get_senders/'+ cur_entity_guid,
				function (subdata) {
					for (i=0;i<subdata.length;i++) {
						this_item = subdata[i];

						// Skip if item in exclude-array
						if (in_array(this_item[0], excludes)) {
							continue;
						}
						// Add item to selectbox
						dat = '<option value="'+ this_item[0] +'">'+ this_item[1] +'</option>';
						$('#'+ base +'reply_message_receiver').append(dat);
					}
				}
			);
		}
	);

	// Hide and show relevant fields
	$('#message-compose-new').hide();
	$('#message-compose-reply').show();
	$('input[name='+ base +'new_message_subject]').hide();
	$('.subject-label').hide();

	// Fill recipient-hidden with guids
	$('#'+ base +'message_new_message_overlay .message-guids').val(array_serialize(recps));

	// Display form
	showOverlay(base +'message_new_message_overlay');
}

/**
 * Adds recipient
 */
function addRecipient(source) {
	name = getBase(source) + 'reply_message_receiver';

	sel = $(source).prev('select').eq(0);
	
	cur = $('option:selected', sel);
	
	dat = '<dd class="recipient-line"><input type="hidden" name="'+ name +'[]" value="'+ cur.val() +'"/>'+ cur.html() +'<a href="#" onclick="return remRecipient(this);" class="remove" title="verwijderen"><span class="hidden">x</span></a></dd>';

	$('#recipient-list').append(dat);
	
	cur.remove();
}

/**
 * Adds recipient
 */
function addRecipientInvite(source) {
	name = getBase(source) + 'reply_message_receiver';

	sel = $(source).prev('select').eq(0);
	
	cur = $('option:selected', sel);
	
	dat = '<dd class="recipient-line"><input type="hidden" name="'+ name +'[]" value="'+ cur.val() +'"/>'+ cur.html() +'<a href="#" onclick="return remRecipient(this);" class="remove" title="verwijderen"><span class="hidden">x</span></a></dd>';

	$('#recipient-list-applicants').append(dat);
	
	cur.remove();
}

/**
 * Removes recipient
 */
function remRecipient(source) {
	dd = $(source).parents('dd');
	
	el_id = '#' + getBase(source) + 'reply_message_receiver';
	
	$(source).remove();
	
	name = dd.text();
	id = $('input', dd).eq(0).val();
	
	dd.remove();
	
	dat = '<option value="'+ id +'">'+ name +'</option>';
	if (source.name.match(/^activity_/)) {
		$(el_id).append(dat);
	} else {
		$(el_id).append(dat);
	}
}

/**
 * archives selected messages
 *
 * @param source Element triggering the event
 */
function messagesArchive(source) {

	base = getBase(source);
	if (base == "activity_") {
		tableid = "activity_message_inbox-table";
	} else {
		tableid = "vacancy_message_inbox_table";
	}

	messages = new Array();
	$('#'+ tableid +' .message-checkbox:checked').each(function () {
		messages.push(parseInt($(this).attr('name').match(/_([0-9]+)$/)[1], 10));
	});
	
	console.debug(messages);

	// Disable button
	$(source).attr('disabled', 'disabled');

	// Archive the messages
	$.ajax({
		async: false,
		url: own_url + "action/activiteiten/archive",
		type: 'POST',
		data: { messages: array_serialize(messages) }
	});
	
	// Reload inbox and archive segments
	ajaxurl = "activiteiten/ajax/";
	
	$('#'+ base +'message_inbox_form_container').load(own_url + ajaxurl +'list_inbox/' + cur_entity_guid);
	$('#'+ base +'message_inbox-archived-messages').load(own_url + ajaxurl + 'list_archive/' + cur_entity_guid);
	
	// Enable button
	$(source).removeAttr('disabled');
	location.reload(true);
}

function messageCompose(source){
	showOverlay('activity_message_new_message_overlay');
}

function messageReply(source){
	base = getBase(source);

	// Load message
	sender_guid = $(source).nextAll('input[name=sender_guid]').val();
	message_guid = $(source).nextAll('input[name=message_guid]').val();
	
	var message = {};
	
	// Load reply screen with AJAX
	$.getJSON(own_url + 'activiteiten/ajax/reply_message/'+ message_guid,
		function (data) {
			// Fill data
			$('input[name='+ base +'new_message_subject]').val(data.subject);
			//tinyMCE.get(base +'new_message_text').execCommand('mceSetContent',false, data.content);

			$('#message-compose-new').hide();
			$('#message-compose-reply').show();

			// list possible recipients
			sender_name = "";
			for (i=0;i<data.applicants.length;i++) {
				if (data.applicants[i].guid == data.sender) {
					sender_name = data.applicants[i].name;
					continue;
				}
				dat = "<option value=\""+ data.applicants[i].guid +"\">"+ data.applicants[i].name +"</option>";
				$('#'+ base +'reply_message_receiver').append(dat);
			}
			
			// Add original sender.
			dat = '<dd class="recipient-line"><input type="hidden" name="'+ base +'reply_message_receiver[]" value="'+ data.sender +'"/>'+ sender_name +'<a href="#" onclick="return remRecipient(this);" class="remove" title="verwijderen"><span class="hidden">x</span></a></dd>';
			
			$('#recipient-list').append(dat);

			// ReplaceWith doesn't work! We extract HTML and replace it.
			showOverlay(base +'message_new_message_overlay');
		}
	);
	
	// Close view-message screen
	closeOverlay(source);
	
	// Done!
	return false;
}

function sentView(id, activity){
	if (activity) {
		subId = '#activity_message_view_overlay';
		act = true;
	} else {
		subId = '#vacancy_message_view_overlay';
		act = false;
	}

	// Load message
	$.getJSON(own_url + "activiteiten/ajax/get_sent_message/" + id,
		function (data) {
			if (data == 'err') {
				alert("helaas is het niet gelukt het bericht te laden");
				// Display an error?
				return false;
			}
			
			$(subId +' .subject').html(data.subject);
			$(subId +' .message-contents').html(data.content);
			$(subId +' .message-date').html(data.timeCreated);
			if (data.timeCreated != data.timeUpdated) {
				$(subId +' .message-change-date').show();
				$(subId +' .message-change-date-label').show();
				$(subId +' .message-date-updated').html(data.timeUpdated);
			} else {
				$(subId +' .message-change-date').hide();
				$(subId +' .message-change-date-label').hide();
			}
			
			$(subId +' .sender-guid').val(parseInt(data.senderGuid, 10));
			
			if (act) {
				showOverlay('activity_message_view_overlay');
			} else {
				showOverlay('vacancy_message_view_overlay');
			}
		}
	);
	
	return false;
}

function messageView(id, activity){
	if (activity) {
		subId = '#activity_message_view_overlay';
		act = true;
	}

	// Load message
	$.getJSON(own_url + "activiteiten/ajax/get_message/" + id,
		function (data) {
			if (data == 'err') {
				alert("helaas is het niet gelukt het bericht te laden");
				// Display an error?
				return false;
			}
			
			$(subId +' .subject').html(data.subject);
			$(subId +' .message-contents').html(data.content);
			$(subId +' .message-date').html(data.timeCreated);
			if (data.timeCreated != data.timeUpdated) {
				$(subId +' .message-change-date').show();
				$(subId +' .message-change-date-label').show();
				$(subId +' .message-date-updated').html(data.timeUpdated);
			} else {
				$(subId +' .message-change-date').hide();
				$(subId +' .message-change-date-label').hide();
			}
			
			$(subId +' .sender-guid').val(parseInt(data.senderGuid, 10));
			$(subId +' .message-guid').val(parseInt(id, 10));
			
			if (act) {
				showOverlay('activity_message_view_overlay');
			}
			
			$("tr#message_row_"+id).removeClass("unread");
		}
	);
	
	return false;
}

/**
 * serializes an one dimensional array
 *
 * @param array in
 * @return string serialized data
 */
function array_serialize(input){
	var out = "";
	var total = 0;
	for (var key in input)	{
		++ total;
		out = out + "s:" +
			String(key).length + ":\"" + String(key) + "\";s:" +
			String(input[key]).length + ":\"" + String(input[key]) + "\";";
	}
	out = "a:" + total + ":{" + out + "}";
	return out;
}

/**
 * Sends the message with settings from popup
 *
 * @param source the triggering element
 */
function sendMessage(source){
	$(source).parents('form').get(0).submit();
}

/**
 * Checks or unchecks all checkboxes in the parent-table of the triggering element.
 * It will uncheck when _all_ checkboxes have been checked.
 */
function checkAll(source) {
	if ($(source).attr('checked')) {
		$(source).parents('table').eq(0).find('.message-checkbox').attr('checked', 'checked');
	} else {
		$(source).parents('table').eq(0).find('.message-checkbox').removeAttr('checked');
	}
}

function closeOverlay(source){
	$(source).parents('.overlay_box').eq(0).addClass('hidden');
	
	return false;
}

function showOverlay(elementId){
	if (elementId == "activity_edit_user_data") {
		$('#'+elementId).css('top', 'auto');
		$('#'+elementId).css('bottom', 200);
	}
	
	$.fancybox({content: $('#'+elementId).html()});
}

/**
 * serializes the contact info form and put it in the hidden contact_info field of the application form
 *
 * @param source the triggering element
 */
function saveContactInfo(source){
	var str = $("form#activity_edit_user_data_form").serialize();
	$("input#contact_info_string").val(str);
	
	$("td#td_confact_info_name").html($("input#user_name").val() + " " + $("input#user_prefix").val() + " " + $("input#user_surname").val());
	$("td#td_confact_info_address").html($("input#user_streetname").val() + " " + $("input#user_streetnumber").val() + " " + $("input#user_streetnumber_suffix").val() + "<br/> " + $("input#user_postcode_number").val() + " " + $("input#user_place").val() + "<br/> " + $("input#user_country").val());
	$("td#td_confact_info_email").html('<a href="mailto:' + $("input#user_email").val() + '">' + $("input#user_email").val() + '</a>');
	$("td#td_confact_info_phone").html($("input#user_phone").val());
	$("td#td_confact_info_mobile_phone").html($("input#user_mobile_phone").val());
	
	if ($("input#user_change_profile:checked").val() == "Change profile") {

		$.post(own_url + "activiteiten/ajax/save_contact_info",
			{ 
				user_name: $("input#user_name").val(), 
				user_prefix: $("input#user_prefix").val(),
				user_surname: $("input#user_surname").val(),
				user_streetname: $("input#user_streetname").val(),
				user_streetnumber: $("input#user_streetnumber").val(),
				user_streetnumber_suffix: $("input#user_streetnumber_suffix").val(),
				user_postcode: $("input#user_postcode_number").val(),
				user_place: $("input#user_place").val(),
				user_country: $("input#user_country").val(),
				user_email: $("input#user_email").val(),
				user_phone: $("input#user_phone").val(),
				user_mobile_phone: $("input#user_mobile_phone").val()
			});
	}
	
	closeOverlay(source);
}

function submitActivityManageApplicationForm(input,action){
	form = $(input).parent().parent();
	
	// Hier moet nog een check of er wel iets geselecteerd is.
	var n = $("#" + form.attr('id') + " input:checked").length;
	if (!n) {
		alert ('Niets geselecteerd!');
		return false;
	}
	
	if (action == 'reserve') {
		$(form).attr("action",own_url + "action/activiteiten/reserve_application");
		
		if (confirm('Weet je zeker dat je de geselecteerde aanmeldingen op de reservelijst wilt plaatsen?')) {
			$(form).submit();
		}
	}
	if (action == 'delete') {
		$(form).attr("action",own_url + "action/activiteiten/delete_application");
		
		if (confirm('Weet je zeker dat je de geselecteerde aanmeldingen wilt verwijderen?')) {
			$(form).submit();
		}
	}
	if (action == 'invite') {
		$(form).attr("action",own_url + "action/activiteiten/invite_application");
		
		if (confirm('Weet je zeker dat je de geselecteerde Doeners wilt uitnodigen?')) {
			$(form).submit();
		}
	} else {
		return false;
	}
}

/** @{ shifts */
/**
 * Displays the default shift forms when selecting the shifts radio button
 */
function toggleShiftFormsVisibility()
{
	radio_btn = document.getElementById("activity_form_edit_time_span_03");
	if (radio_btn.checked) {
		$("div#form_section_2").removeClass('hidden');
		$("div#activity_form_mandatory_shifts").removeClass('hidden');
	} 
	else {
		
		$("div#form_section_2").addClass('hidden');
		$("div#activity_form_mandatory_shifts").addClass('hidden');
	}
}

/**
 * Builds the shift type form
 */
function add_shift_type_form(){
	d = new Date();
	newId = 'new_' + d.getTime();
	
	startdate = $("#datetime_start").val();
	enddate = $("#datetime_end").val();

	if (enddate == "") {
		enddate = startdate;
	}

	num_shifts = $("select#activity_form_create_shiftgroup_day_" + newId + " option:selected").text();
	
	$("p#add_shift_type_link").before('<div id="activity_form_create_shiftgroup_' + newId +'"><p>Laden...</p></div>');
	$("p#add_shift_type_link").before('<div id="activity_form_shifts_table" class="activity_form_shifts_table_' + newId + '"></div>');

	$("div#activity_form_create_shiftgroup_" + newId).load(own_url + "activiteiten/ajax/get_shift_type_form/"  + newId + "/" + startdate + "/" + enddate + "/" + num_shifts + "/1");
	return false;
}

/**
 * Builds the shifts form for a shift_type
 */
function build_shifts_form(form_id, activity_id){
	/* TODO: Bestaande shifts eerst netjes weggooien, ook te reserveringen op deze shifts. Of, shifts opnieuw opbouwen wanneer er al aanmeldingen zijn niet meer mogelijk. */
	
	if (activity_id > 0) {
		do_build = confirm('Zeker weten dat je het schema opnieuw wilt maken? De huidige shifts en de bijbehorende aanmeldingen gaan verloren!')
	} else {
		do_build = 1;
	}
	
	if (do_build) {
		$("div.activity_form_shifts_table_" + form_id).html("<p>laden...</p>");
		sameDay = $("input[name='activity_form_create_shiftgroup_schedule_"+form_id+"']:checked").val();
		
		startdate = $("#datetime_start").val();
		enddate = $("#datetime_end").val();
		
		if (enddate == "") {
			enddate = startdate;
		}
		
		num_shifts = $("select#activity_form_create_shiftgroup_day_" + form_id + " option:selected").text();
		
		numShiftsString = '';
		if (sameDay == 'false') {
			$("div#shift_scheme_"+form_id+" select[name^=activity_form_create_shiftgroup_day_]").each(
				function() {
					if (numShiftsString == '') {
						numShiftsString = numShiftsString + $(this).val();
					} else { 
						numShiftsString = numShiftsString + ',' + $(this).val();
					}
				}
			);
			numShiftsString = '?shifts_per_day=' + numShiftsString;
		}

		$("div.activity_form_shifts_table_" + form_id).load(own_url + "activiteiten/ajax/build_shifts/" + form_id + "/" + startdate + "/" + enddate + "/" + num_shifts + "/1"+numShiftsString);
		
	}
}

/**
 * Gets the shifts form for a shift_type
 */
function get_shifts_form(form_id){
	$("div.activity_form_shifts_table_" + form_id).html("<p>laden...</p>");
	
	startdate = $("#datetime_start").val();
	enddate = $("#datetime_end").val();
	
	if (enddate == "") {
		enddate = startdate;
	} 
	
	num_shifts = $("select#activity_form_create_shiftgroup_day_" + form_id + " option:selected").text();
		
	$.get(own_url + "activiteiten/ajax/build_shifts/" + form_id + "/" + startdate + "/" + enddate + "/" + num_shifts + "/1/false",
		function(data){
			$("div.activity_form_shifts_table_" + form_id).html(data);
			updateTotalPeople(form_id);
		}
	);
}

/**
 * Remove shifts from the form
 */
function remove_shifts(shift_type_id){
	$("div.activity_form_shifts_table_" + shift_type_id).remove();
	$("div#activity_form_create_shiftgroup_" + shift_type_id).remove();
}

/**
 * Change the time of the shifts
 */
function change_shifttimes(shift_type,old_timestamp,when,col){
	stamp = new Date();
	stamp.setTime(old_timestamp * 1000);

	old_hours = stamp.getHours();
	old_minutes = stamp.getMinutes();
	if (old_minutes == '0') {
		old_minutes = '00'
	}

	time1 = old_hours + ':' + old_minutes;
	time2 = prompt("Nieuwe tijd (uu:mm): ",time1);

	if (!time2) {
		return;
	}
	
	time = time2.split(':')
	newHour = time[0];
	newMinute = time[1];

	newDate = stamp;
	newDate.setHours(newHour);
	newDate.setMinutes(newMinute);
	newDate.setSeconds(0);

	newStamp = newDate.getTime() / 1000;

	fieldName = "shift_" + when + "time_" + shift_type + "_" + col;

	// Update the date for every shift
	$("input[id^='" + fieldName + "']").each(function () {
		thisOldTimestamp = $(this).val();
		thisOldDate = new Date();
		thisOldDate.setTime(thisOldTimestamp * 1000);
		
		thisNewDate = thisOldDate;
		thisNewDate.setHours(newHour);
		thisNewDate.setMinutes(newMinute);
		thisNewDate.setSeconds(0);
		
		thisNewTimestamp = thisNewDate.getTime() / 1000;
		
		$(this).val(thisNewTimestamp);
	});
	
	$("a#" + when + "time_" + shift_type + "_" + col).html(time2);
}

/**
 *
 */
function switch_shift_table (table_id){
	$("a[id^='switchlink_']").removeClass("selected");
	$("table[id^='shifts_table_']").removeClass("active");
	$("table[id^='shifts_table_']").addClass("inactive");
	
	$("a[id='switchlink_" + table_id + "']").addClass("selected");
	$("table[id='shifts_table_" + table_id + "']").removeClass("inactive");
	$("table[id='shifts_table_" + table_id + "']").addClass("active");
}

/**
 *
 */
function click_shift(shift_id) {
	do_click = 1;
	selectedManA = 0;
	selectedManB = 0;
	
	shiftsRowId = $("a#shift_"+shift_id).parent().parent().attr("id");
	shiftsRowNumber = shiftsRowId.split("_");
	shiftsRowNumber = shiftsRowNumber[2];
	
	// Check if there is already an shift selected on this day
	$("tr[id$='_"+shiftsRowNumber+"'] > td > a.selected").each(
		function () {
			do_click = 0;
		}
	);
	
	num_shifts = 0;
	selectedShiftsString = $("input#selected_shifts").val();
	if (selectedShiftsString == "") {
		num_shifts = 0;
	} else {
		selectedShiftsArray = selectedShiftsString.split(",");
		num_shifts = selectedShiftsArray.length;
	}
	
	inArray = 0;
	atPosition = 0;
	if (num_shifts > 0) {
		for (i=0;i<=num_shifts;i++) {
			if (selectedShiftsArray[i] == shift_id) {
				inArray = 1;
				atPosition = i;
			}
		}
	}
	
	if (inArray == 1) {
		$("a#shift_"+shift_id).removeClass('selected');
	}
	else {
		if (num_shifts == glNumShifts) {
			alert("Je zit aan het maximaal aantal shifts dat je mag draaien.");
			return false;
		}
		if (do_click == 0) {
			alert("Je mag maar 1 shift per dag selecteren.");
			return false;
		}
		$("a#shift_"+shift_id).addClass('selected');
	}
	
	shiftsTable = $("a#shift_"+shift_id).parent().parent().parent().parent().attr("id");
	newShiftsString = "";
	$("div#activity_shifts_table > table > tbody > tr > td > a.selected").each(
		function () {
			if (newShiftsString != "") {
				newShiftsString = newShiftsString + ",";
			}
			shifId = $(this).attr("id").split("_");
			newShiftsString = newShiftsString + shifId[1];
			
			if ($(this).hasClass("a-shift")) {
				selectedManA = selectedManA + 1;
			}
			if ($(this).hasClass("b-shift")) {
				selectedManB = selectedManB + 1;
			}
			if ($(this).hasClass("ab-shift")) {
				selectedManA = selectedManA + 1;
				selectedManB = selectedManB + 1;
			}
		}
	);
	
	if ($("span#mandatory_a")) {
		$("span#mandatory_a").html(selectedManA);
	}
	if ($("span#mandatory_b")) {
		$("span#mandatory_b").html(selectedManB);
	}
	
	$("input#selected_shifts").val(newShiftsString);
	
	selectedShiftsArray = newShiftsString.split(",");
	totalShifts = selectedShiftsArray.length;
	if (newShiftsString == "") {
		totalShifts = 0;	
	}
	$("span#total_shifts").html(totalShifts);
	
	if (totalShifts == glNumShifts) {
		$("span#total_shifts").removeClass("red");
		$("span#total_shifts").addClass("green");
	}
	else {
		$("span#total_shifts").removeClass("green");
		$("span#total_shifts").addClass("red");
	}
	
	// Gewone verplichte shiftstellers bijwerken
	shiftsTableAr = shiftsTable.split("_");
	shiftTypeId = shiftsTableAr[2];
	selectedShiftsString = "";
	$("table#"+shiftsTable+" > tbody > tr > td > a.selected").each(
		function () {
			if (selectedShiftsString != "") {
				selectedShiftsString = selectedShiftsString + ",";
			}
			shifId = $(this).attr("id").split("_");
			selectedShiftsString = selectedShiftsString + shifId[1];
		}
	);
	selectedShiftsArray = selectedShiftsString.split(",");
	numSelectedShifts = selectedShiftsArray.length;
	if (selectedShiftsString == "") {
		numSelectedShifts = 0;
	}
	
	numNeededShifts = $("span#shift_needed_total_"+shiftTypeId).html();
	
	$("span#shift_total_"+shiftTypeId).html(numSelectedShifts);
	shiftsNeeded = parseInt(parseInt(numNeededShifts) - parseInt(numSelectedShifts));
	if (shiftsNeeded < 0) {
		shiftsNeeded = 0;
	}
	$("span#shift_needed_"+shiftTypeId).html(shiftsNeeded);
	
	if (parseInt(numSelectedShifts) > 0) {
		$("p#mandetory_info_"+shiftTypeId).removeClass("hidden");
	}
	else {
		$("p#mandetory_info_"+shiftTypeId).addClass("hidden");
	}
	
	if (shiftsNeeded == 0) {
		$("span#shift_needed_"+shiftTypeId).removeClass("red");
		$("span#shift_needed_"+shiftTypeId).addClass("green");
		$("span#shift_title_mandetory_"+shiftTypeId).removeClass("red");
		$("span#shift_title_mandetory_"+shiftTypeId).addClass("green");
	}
	else {
		
		$("span#shift_needed_"+shiftTypeId).removeClass("green");
		$("span#shift_needed_"+shiftTypeId).addClass("red");
		$("span#shift_title_mandetory_"+shiftTypeId).removeClass("green");
		$("span#shift_title_mandetory_"+shiftTypeId).addClass("red");
	}
	
	return false;
}

function init_shifts_form() {
	selectedManA = 0;
	selectedManB = 0;

	selectedShiftsString = $("input#selected_shifts").val();
	if (selectedShiftsString == "") {
		num_shifts = 0;
	} else {
		selectedShiftsArray = selectedShiftsString.split(",");
		num_shifts = selectedShiftsArray.length;
	}
	
	$("span#total_shifts").html(num_shifts);
	if (num_shifts >= glNumShifts) {
		$("span#total_shifts").removeClass("red");
		$("span#total_shifts").addClass("green");
	}
	
	for (i=0;i<num_shifts;i++) {
		shift_id = selectedShiftsArray[i];
		$("a#shift_"+shift_id).addClass('selected');
		
		// Enable click_shift() for full shifts if the shift is already selected by the user.
		if ($("a#shift_"+shift_id).html() == "VOL"){
			$("a#shift_"+shift_id).click( 
				function() {
					temp_id = $(this).attr("id");
					temp_id2 = temp_id.split("_");
					shift_id = temp_id2[1];	
					click_shift(shift_id);
					return false;
				}
			);
		}
	}
	
	// Enable click_shift() for full shifts if the shift is already selected by the user.
	for (i=0;i<num_shifts;i++) {
		shift_id = selectedShiftsArray[i];
		if ($("a#shift_"+shift_id).html() == "-1 open" || $("a#shift_"+shift_id).html() == "-2 open" || $("a#shift_"+shift_id).html() == "-3 open") {
			$("a#shift_"+shift_id).click( 
				function() {
					temp_id = $(this).attr("id");
					temp_id2 = temp_id.split("_");
					shift_id = temp_id2[1];	
					click_shift(shift_id);
					return false;
				}
			);
		}	
	}
	
	// Verplichte shifs voor shift_type updaten
	$("div#activity_shifts_table > table").each(
		function () {
			tableId = $(this).attr("id");
			tmpTableId = tableId.split("_");
			shiftTypeId = tmpTableId[2];
			thisNumShifts = $("span#shift_needed_total_"+shiftTypeId).html();//$("span#shift_total_"+shiftTypeId).html();
			thisShiftName = $("a#switchlink_"+shiftTypeId).html();

			selectedShiftsString = "";
			$("table#"+tableId+" > tbody > tr > td > a.selected").each(
				function () {
					if (selectedShiftsString != "") {
						selectedShiftsString = selectedShiftsString + ",";
					}
					shifId = $(this).attr("id").split("_");
					selectedShiftsString = selectedShiftsString + shifId[1];
					
					if ($(this).hasClass("a-shift")) {
						selectedManA = selectedManA + 1;
					}
					if ($(this).hasClass("b-shift")) {
						selectedManB = selectedManB + 1;
					}
					if ($(this).hasClass("ab-shift")) {
						selectedManA = selectedManA + 1;
						selectedManB = selectedManB + 1;
					}
				}
			);
			selectedShiftsArray = selectedShiftsString.split(",");
			numSelectedShifts = selectedShiftsArray.length;
			if (selectedShiftsString == "") {
				numSelectedShifts = 0;
			}
			
			numNeededShifts = $("span#shift_needed_total_"+shiftTypeId).html();
	
			$("span#shift_total_"+shiftTypeId).html(numSelectedShifts);
			shiftsNeeded = parseInt(parseInt(numNeededShifts) - parseInt(numSelectedShifts));
			if (shiftsNeeded < 0) {
				shiftsNeeded = 0;
			}
			$("span#shift_needed_"+shiftTypeId).html(shiftsNeeded);
			
			if (parseInt(numSelectedShifts) > 0) {
				$("p#mandetory_info_"+shiftTypeId).removeClass("hidden");
			}
			else {
				$("p#mandetory_info_"+shiftTypeId).addClass("hidden");
			}
			
			if (shiftsNeeded == 0) {
				$("span#shift_needed_"+shiftTypeId).removeClass("red");
				$("span#shift_needed_"+shiftTypeId).addClass("green");
				$("span#shift_title_mandetory_"+shiftTypeId).removeClass("red");
				$("span#shift_title_mandetory_"+shiftTypeId).addClass("green");
			}
			else {
				
				$("span#shift_needed_"+shiftTypeId).removeClass("green");
				$("span#shift_needed_"+shiftTypeId).addClass("red");
				$("span#shift_title_mandetory_"+shiftTypeId).removeClass("green");
				$("span#shift_title_mandetory_"+shiftTypeId).addClass("red");
			}
		}
	);
	
	showManatoryText = 0;
	if ($("span#mandatory_a")) {
		$("span#mandatory_a").html(selectedManA);
		showManatoryText = 1;
	}
	if ($("span#mandatory_b")) {
		$("span#mandatory_b").html(selectedManB);
		showManatoryText = 1;
	}
	
	if (showManatoryText) {
		$("div#activity_interest").append("<div class='elgg-subtext'>Verplichte shifts zijn gemarkeerd met een letter. Van iedere letter moet je minimaal 1 shift doen. 1 shift met beide letters voldoet ook.</div>");
	}
}

function update_num_days() {
	date1 = new Date();
	date2 = new Date();

	date_start = $("#datetime_start").val();
	date_end = $("#datetime_end").val();
	
	radio_btn = $("input.date-range:checked").val();

	if (radio_btn == "single") {
		date_end = date_start;
		$("#datetime_end").val($("#datetime_start").val());
	}
	
	if (date_start != "") {
		date_start_split = date_start.split("-");
		date_end_split = date_end.split("-");	
		day1 = date_start_split[2];
		month1 = date_start_split[1] -1; //document.getElementById("in_datetime_start_id_month").value -1; // date fix 23-04-2008 @ 9:00
		year1 = date_start_split[0];
		
		day2 = date_end_split[2];
		month2 = date_end_split[1] -1;
		year2 = date_end_split[0];
		
		date1.setFullYear(year1,month1,day1);
		date2.setFullYear(year2,month2,day2);
		
		if (date1 > date2) {
			date2 = date1;
			$("input#datetime_end").val($("input#datetime_start").val());
		}
		
		days = date2 - date1;
		days = (((days / 1000) / 3600) / 24) + 1; 
	} else {
		days = 1;
	}

	shift_el = document.getElementById("activity_form_number_compulsory_shifts");
	
	max_shifts = days;
	
	for (i=0;i<=days;i=i+1) {
		selectedString = "";
		
		if (i == max_shifts) {
			selectedString = ' selected="selected"';
		}
	
		if (i == 0) {
			shiftElOptions = '<option value="' + i + '"' + selectedString + '>0</option>';
		} else {
			optionText = "";
			shiftElOptions = shiftElOptions + '<option value="' + i + '"' + selectedString + '>' + i + optionText + '</option>';
		}
	}
	shift_el.parentNode.innerHTML = 'Iedere deelnemer moet <select name="activity_form_number_compulsory_shifts" size="1" id="activity_form_number_compulsory_shifts" title="activity_form_number_compulsory_shifts" class="small">' + shiftElOptions + '</select> shifts doen tijdens deze activiteit.';
}

/** @} */

function update_activity_searchfilter(getType,getGroup,getPlace) {
	elm_search_type = $("select#activity_search_type");
	elm_search_group = $("select#activity_search_group");
	elm_search_place = $("select#activity_search_place");
	
	time_span = $("input[name='activity_search_radio']:checked").val();
	type = elm_search_type.val();
	group = elm_search_group.val();
	place = elm_search_place.val();
	
	if (type == '') {
		type = "no_val";
	}
	if (group < 1) {
		group = 0;
	}
	if (place == '') {
		place = "no_val";
	}
	if (time_span == '') {
		time_span = "upcomming";
	}
	
	if(time_span == "managed" || time_span == "applied"){
		elm_search_type.hide();
		elm_search_group.hide();
		elm_search_place.hide();
	} else {
		elm_search_type.empty().show();
		elm_search_type.append('<option>Bezig met laden...</option>');
		elm_search_group.empty().show();
		elm_search_group.append('<option>Bezig met laden...</option>');
		elm_search_place.empty().show();
		elm_search_place.append('<option>Bezig met laden...</option>');
		
		$.get(own_url + "activiteiten/ajax/update_activity_search/"+type+"/"+group+"/"+place+"/"+time_span, 
			function(data){
				topResult = data.split('||||');
				typeOptions = topResult[0].split('//');
				placeOptions = topResult[1].split('//');
				groupOptions = topResult[2].split('//');
				
				elm_search_type.empty();
				elm_search_type.append('<option value="">Soort bijeenkomst</option>');
				for (i=0;i<typeOptions.length;i++) {
					typeSelected = '';
					if (typeOptions[i] == type) {
						typeSelected = ' selected="selected"';
					}
					elm_search_type.append('<option value="'+typeOptions[i]+'"'+typeSelected+'>'+typeOptions[i]+'</option>');
				}
				
				elm_search_group.empty();
				elm_search_group.append('<option value="-1" selected="selected">Organiserende groep</option>');
				for (i=0;i<groupOptions.length;i++) {
					groupValues = groupOptions[i].split("::");
					groupSelected = '';
					if (groupValues[1] == group) {
						groupSelected = ' selected="selected"';
					}
					elm_search_group.append('<option value="'+groupValues[1]+'"'+groupSelected+'>'+groupValues[0]+'</option>');
				}
				
				elm_search_place.empty();
				elm_search_place.append('<option value="">Locatie</option>');
				for (i=0;i<placeOptions.length;i++) {
					placeSelected = '';
					if (placeOptions[i] == place) {
						placeSelected = ' selected="selected"';
					}
					elm_search_place.append('<option value="'+placeOptions[i]+'"'+placeSelected+'>'+placeOptions[i]+'</option>');
				}
			}
		);
	}
}

function update_shifts_per_day_form (shift_type_id, startdate, enddate) {
	startdate = $("input#datetime_start").val();
	enddate = $("input#datetime_end").val();
	sameDay = $("input[name='activity_form_create_shiftgroup_schedule_"+shift_type_id+"']:checked").val();
	$("div#shift_scheme_"+shift_type_id).empty();

	$("div#shift_scheme_"+shift_type_id).load(own_url + "activiteiten/ajax/update_shifts_per_day_form?shift_type_id="+shift_type_id+"&startdate="+startdate+"&enddate="+enddate+"&sameday="+sameDay);
}

function showMandetoryOverlay(elementId,current)
{
	$('#'+elementId).css('top', 'auto');
	$('#'+elementId).css('bottom', 200);
	group = elementId.split('_');
	group = group[2].replace(/\s+$/,'');
	group = group.replace(' ','');
	
	nameString = '';
	
	$('input[name^=shifttype_name]').each(
		function () {
			if (nameString == '') {
				nameString = nameString + $(this).val();
			}
			else { 
				nameString = nameString + ',' + $(this).val();
			}	
		}
	);
	
	returnHtml = "";
	$("div[class^=activity_form_shifts_table_]").each(
		function() {
			
			shiftTypeId = $(this).attr("class");
			shiftTypeIdAr = shiftTypeId.split("_");
			shiftTypeId = shiftTypeIdAr[4];
			if (shiftTypeId == 'new') {
				shiftTypeId = shiftTypeIdAr[4]+"_"+shiftTypeIdAr[5];
			}
			
			returnHtml = returnHtml + "<p><br/><strong>"+$("input#activity_form_create_shiftgroup_shiftname_"+shiftTypeId).val()+"</strong></p>";

			$("div[class=activity_form_shifts_table_"+shiftTypeId+"] > table").each(
				function() {

					tableId = $(this).attr("id");
					returnHtml = returnHtml + '<table style="width: 500px; border: 1px solid #01ADEF;" border="1" cellpadding="3" cellspacing="0"> ';
					// Header hier
					returnHtml = returnHtml + '<tr class="odd header">';

					$("table#"+tableId + " > tbody > tr.header > th").each(
						function() {
							returnHtml = returnHtml + '<th style="border-left: 1px dotted #B8B8B8;" scope="col" class="">'+$(this).html()+'</th>';
						}
					);
					
					returnHtml = returnHtml + '</tr>';
					
					// rest van de tabel hier
					rowClass = "even";
					$("table#"+tableId + " > tbody > tr.row").each(
						function() {
							rowId = $(this).attr("id");
							returnHtml = returnHtml + '<tr class="'+rowClass+'">';
							returnHtml = returnHtml + '<th scope="row" class="column1">'+$("tr#"+rowId+" > th").html()+'</th>';
							
							$("tr#"+rowId+" > td").each(
								function() {
									thisColumn = $(this).attr("class");
									shiftId = $("tr#"+rowId+" > td."+thisColumn+" > input[name^=shift_id]").val();
									
									manVal = 0;
									manVal = $("input#shift_group_"+group+"_"+shiftId).val();
									if (manVal == '1') {
										groupStatus = 'Ja';
									}
									else {
										groupStatus = 'Nee';
									}
								
									returnHtml = returnHtml + '<td style="border-left: 1px dotted #B8B8B8;" class="'+thisColumn+'"><a href="#" id="mandatory_link_'+group+'_'+shiftId+'">'+groupStatus+'</a></td>';
								}
							);
							
							returnHtml = returnHtml + '</tr>';
							
							if (rowClass == 'even') {
								rowClass = 'odd';
							}
							else {
								rowClass = 'even';
							}
						}
					);
					// einde van de rest
					
					returnHtml = returnHtml + '</table>';
				}
			);
		}
	);
	$('#'+elementId+" div").html(returnHtml);
	$('#'+elementId).removeClass('hidden');
	
	$('a[id^=mandatory_link]').click(
		function() {
			linkId = $(this).attr("id");
			allInfo = linkId.split("_");
			group = allInfo[2];
			shiftId = allInfo[3];
			if (shiftId == "new") {
				shiftId = allInfo[3]+"_"+allInfo[4];
			}
			thisLink = $(this);
			addMandetory(thisLink, group, shiftId);
			return false;
		}
	);
}

function sendMailQuestion() {
	if (confirm('Wil je dat alle aanmeldingen een e-mail ontvangen dat deze activiteit is gewijzigd??')) {
		$("input[name=send_mail]").val("yes");
	}
}

function updateTotalPeople(shift_type_id) {
	totalPeople = parseInt(0);

	$("input[class=num_people_"+shift_type_id+"]").each(
		function () {
			totalPeople = parseInt(totalPeople) + parseInt($(this).val());
		}
	);

numShifts = $("select#activity_form_number_compulsory_shifts").val();
	totalPeople = Math.round((totalPeople / parseInt(numShifts))*100) / 100;
	$("span#total_people_"+shift_type_id).html(totalPeople);
}

function check_application() {
	errorString = "";
	num_shifts = 0;
	selectedShiftsString = 0;
	cant_force_application = true;
	available_shifts = 0;
	selectedShiftsString = $("input#selected_shifts").val();
	if (selectedShiftsString) {
		selectedShiftsArray = selectedShiftsString.split(",");
		num_shifts = selectedShiftsArray.length;
	}

	$("table.shift_table > tbody > tr[id^=shiftrow_]").each(
		function() {
			this_id = $(this).attr("id");
			rowAvailable = 0;
			$("tr#"+this_id+" > td > a").each(
				function() {
					// inhoud van a tag controleren
					tagContent = $(this).html();
					
					if (tagContent != "VOL") {
						rowAvailable = 1;
					}
				}
			);
			
			if (rowAvailable > 0) {
				available_shifts = available_shifts + 1;
			}
		}
	);
	
	if (glNumShifts > available_shifts) {
		cant_force_application = false;
	}
	
	// Totaal aantal shifts check
	if (glNumShifts > num_shifts) {
		// Checken of het minimaal aantal shifts nog wel kan?
		if (cant_force_application) {
			errorString = errorString + "Je hebt nog niet genoeg shifts geselecteerd.\n";
		}
	}
	
	// Verplichte schifts per schift_type check
	selectedGroupA = 0;
	selectedGroupB = 0;
	$("div#activity_shifts_table > table").each(
		function () {
			tableId = $(this).attr("id");
			tmpTableId = tableId.split("_");
			shiftTypeId = tmpTableId[2];
			thisNumShifts = $("span#shift_needed_total_"+shiftTypeId).html();//$("span#shift_total_"+shiftTypeId).html();
			thisShiftName = $("a#switchlink_"+shiftTypeId).html();

			selectedShiftsString = "";
			$("table#"+tableId+" > tbody > tr > td > a.selected").each(
				function () {
					if (selectedShiftsString != "") {
						selectedShiftsString = selectedShiftsString + ",";
					}
					shifId = $(this).attr("id").split("_");
					selectedShiftsString = selectedShiftsString + shifId[1];
					
					// Verplichte shiftgroup check
					if ($(this).hasClass("a-shift")) {
						selectedGroupA = 1;
					}
					if ($(this).hasClass("b-shift")) {
						selectedGroupB = 1;
					}
					if ($(this).hasClass("ab-shift")) {
						selectedGroupA = 1;
						selectedGroupB = 1;
					}
				}
			);
			selectedShiftsArray = selectedShiftsString.split(",");
			numSelectedShifts = selectedShiftsArray.length;
			if (selectedShiftsString == "") {
				numSelectedShifts = 0;
			}
			
			if (thisNumShifts) {
				if (thisNumShifts > numSelectedShifts) {
					if (numSelectedShifts > 0) {
						if (cant_force_application) {
							errorString = errorString + "Je hebt nog niet genoeg shifts van '"+thisShiftName+"' geselecteerd.\n";
						}
					}
				}
			}
		}
	);
	
	// Verplichte shiftsgroepen check (A/B)
	if (glNeedGroupA == 1) {
		if (selectedGroupA == 0) {
			errorString = errorString + "Je moet een verplichte shift uit groep A selecteren.\n";
		}
	}
	if (glNeedGroupB == 1) {
		if (selectedGroupB == 0) {
			errorString = errorString + "Je moet een verplichte shift uit groep B selecteren.\n";
		}
	}
	
	// Zijn er foutmeldigen?
	if (errorString != "") {

		alert(errorString + " ");
		return false;
	}
}

function check_activity_submit() {
	// TODO: Hier al een check op de begin en einddatum?
	
	errorString = "";
	timeRange = $("input[name=activity_form_edit_time_span]:checked").val();
	
	if (timeRange == "shifts") {
		checkTable = $("table[id^=shift_table_]").attr('id');
		if (checkTable == undefined) {
			errorString = "Er zijn geen shifts aangemaakt!";
		}
	}
	
	// Zijn er foutmeldigen?
	if (errorString != "") {
		alert("Foutmelding: \n\n" + errorString);
		return false;
	}
}

function addMandetory(thisLink, group, shiftId) {
	manVal = $("input#shift_group_"+group+"_"+shiftId).val();
	if ($(thisLink).html() == 'Ja') { // groep uitzetten
		$(thisLink).html('Nee');
	}
	else { // group aanzetten
		$(thisLink).html('Ja');
	}
}

function switch_shift_mandatory(shiftTypeId) {
	checkedStatus = $("input#activity_form_shift_number_minimum_"+shiftTypeId).attr('checked');
	
	if (checkedStatus) {
		$("select#activity_form_edit_shifts_amount_"+shiftTypeId).removeAttr('disabled');
	} else {
		$("select#activity_form_edit_shifts_amount_"+shiftTypeId).attr('disabled','disabled');
	}
}

function switch_total_mandatory() {
	checkedStatus = $("input#activity_form_edit_shifts_mandatory").attr('checked');
	if (checkedStatus) {
		$(".mandatory_table_setup").removeClass('hidden');
	} else {
		$(".mandatory_table_setup").addClass('hidden');
	}
}

function build_mandatory_table(popup,shift_group) {
	// Huidige tabel leeggooien
	$("tr[id^='man_shift_"+shift_group+"']").remove();
	// Geselecteerde verplichte shifts resetten
	$("input[id^=shift_group_"+shift_group+"_]").val("0");
	
	newHTML = "";
	shiftClass = "odd";
	
	// Geselecteerde shifts zoeken
	$('a[id^=mandatory_link]').each(
		function () {
			if ($(this).html() == 'Ja') {
				if (shiftClass == "odd") {
					shiftClass = "even";
				} else {
					shiftClass = "odd";
				}
				
				// shift_id achterhalen
				shiftId = $(this).attr("id");
				shiftId = shiftId.split("_");
				if (shiftId[3] == "new") {
					shiftId = shiftId[3]+"_"+shiftId[4];
				} else {
					shiftId = shiftId[3]
				}
				
				$("input#shift_group_"+shift_group+"_"+shiftId).val("1"); // Verplichte shift ook echt instellen
				
				shiftTypeId = $("input[class=shifttype_"+shiftId+"]").val();
				shiftTypeTitle = $("input#activity_form_create_shiftgroup_shiftname_"+shiftTypeId).attr("value");
				
				startDate = new Date();
				endDate = new Date();
				
				startDate.setTime($("input.starttime_"+shiftId).val() * 1000);
				endDate.setTime($("input.endtime_"+shiftId).val() * 1000);
				
				shiftDate = addLeadingZero(startDate.getDate()) + "-"+addLeadingZero(startDate.getMonth()+1)+"-"+startDate.getFullYear();
				shiftStarttime = addLeadingZero(startDate.getHours())+":"+addLeadingZero(startDate.getMinutes());
				shiftEndtime = addLeadingZero(endDate.getHours())+":"+addLeadingZero(endDate.getMinutes());
				
				newHTML = newHTML + '';
				newHTML = newHTML + '<tr id="man_shift_'+shift_group+'_'+shiftId+'" class="'+shiftClass+'">';
				newHTML = newHTML + '<td><strong>'+shiftTypeTitle+' '+shiftDate+',</strong> '+shiftStarttime+' - '+shiftEndtime+'</td>';
				newHTML = newHTML + '<td>&nbsp;</td>';
				newHTML = newHTML + '</tr>';
			}
		}
	);
	
	$("table#activity_form_mandatory_shifts_table_"+shift_group).append(newHTML);
	
	closeOverlay(popup);
	
	$('#mandetory_shifts_'+shift_group+" div").html("<p>Shifts konden niet geladen worden...</p>");
}

function addLeadingZero (input) {
	output = input.toString();
	
	if (output.length < 2) {
		output = "0"+output;
	}
	return output;
}
elgg.provide('elgg.contact');

elgg.contact.check_required_fields = function(element)
{
	var result = true;
	
	$.each($('.contact_field_error'), function(i, value)
	{
		$input = $('#' + $(value).attr('id').replace('_error', ''));
		if($input.val() == '')
		{
			$(value).html(elgg.echo('contact:message:required_field'));
			$(value).css('visibility', 'visible');
			result = false;
		}
	});

	return result;
}

elgg.contact.init = function()
{
	$('#contact_form').submit(function(e)
	{
		if(elgg.contact.check_required_fields() != true)
		{
			e.preventDefault();
		}
	});

	$('.contact_required').bind('keyup blur', function(e)
	{
		if($(this).val() != '')
		{
			$('#' + $(this).attr('id') + '_error').css('visibility', 'hidden');
		}
		else
		{
			$('#' + $(this).attr('id') + '_error').html(elgg.echo('contact:message:required_field'));
			$('#' + $(this).attr('id') + '_error').css('visibility', 'visible');
		}
	});

	$('#contact_mail').bind('change blur', function()
	{
		var reg = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
		var address = $(this).val();

		if($(this).val() != '')
		{
			if(reg.test(address) == false)
			{
				$('#contact_mail_error').html(elgg.echo('registration:notemail'));
				$('#contact_mail_error').css('visibility', 'visible');
			}
		}
		else
		{
			$('#contact_mail_error').html(elgg.echo('contact:message:required_field'));
			$('#contact_mail_error').css('visibility', 'visible');
		}
	});
}

elgg.register_hook_handler('init', 'system', elgg.contact.init);
