// We don't need prototype.js yet, so I'll just define what I need until we decide we need enough
// to justify the whole thing.
function $(elname) {
	return document.getElementById(elname);
}

// Precache images for faster swapping
function preload_images() {
	var len = arguments.length;
	var tmp_img;
	for(var i = 0; i < len; i++) {
		tmp_img = new Image();
		tmp_img.src = arguments[i];
		document.images[document.images.length] = tmp_img;
	}
}

// Simple confirm box.  Make sure item_name is url-escaped.
function confirm_delete(item_name, extra_text) {
	if(extra_text == undefined) {
		extra_text = '';
	}
	return confirm('Are you sure you want to delete ' + unescape(item_name) + '?' + extra_text);
}

// Shifts the selected value(s) from one multi-select box into another.  This is used in our
// has-and-belongs-to-many widget.
function multi_select_shift(src_id, dest_id) {
	var src = $(src_id);
	var dest = $(dest_id);

	var i;
	var len = src.length;
	for(i = 0; i < len; i++) {
		if(src.options[i].selected) {
			dest.options[dest.options.length] = new Option(src[i].text, src[i].value, false, false);
			src.options[i] = null;
			--i;
			--len;
		}
	}

	sort_select_list(dest);

	return false;
}

// Sorts a select list.  Even though the 'options' parameter behaves exactly like an array, it
// has no sort() method.  So we have to do it the hard way.  You need to copy the options into a
// temporary array, call this function, then delete and re-create the options list.
function sort_select_list(el) {
	var len = el.options.length;
	var temp_options = new Array();
	for(var i = 0; i < len; i++) {
		temp_options.push(new Array(el.options[i].text, el.options[i].value));
	}

	temp_options.sort(select_sorter);

	el.options.length = 0;
	for(i = 0; i < len; i++) {
		el.options[el.options.length] = new Option(temp_options[i][0], temp_options[i][1], false, false);
	}
}

// Used as a callback to sort the options in a select list alphabetically by their text label.
function select_sorter(a, b) {
	var a_text = a[0].toLowerCase();
	var b_text = b[0].toLowerCase();
	return (a_text == b_text) ? 0 : ((a_text > b_text) ? 1 : -1);
}

// This is used to add the "selected" attribute to the categories array for the add/edit candidate screens.
function initialise_candidate_selected_categories() {
	var i, j, k;
	var i_len, j_len;
	var k_len = arguments.length;
	if(k_len > 0) {
		i_len = cs.length;
		for(i = 0; i < i_len; i++) {
			j_len = cs[i][2].length;
			for(j = 0; j < j_len; j++) {
				cs[i][2][j][2] = false;
				for(k = 0; k < k_len; k++) {
					if(cs[i][2][j][0] == arguments[k]) {
						cs[i][2][j][2] = true;
						break;
					}
				}
			}
		}
	}
}

/*
	Adds a category into the candidates HABTM list.
	New interface: see Trac #173.
*/
function add_candidate_category() {
	var src_parent = $('JobParentCategoryId');
	var src_child = $('JobCategoryId');
	var dest = $('CategoryCategory');

	var parent_id = src_parent.options[src_parent.selectedIndex].value;
	var child_id = src_child.options[src_child.selectedIndex].value;

	var array_to_search = cs[csi[parent_id]][2];
	var len = array_to_search.length;
	for(var i = 0; i < len; i++) {
		if(array_to_search[i][0] == child_id) {
			array_to_search[i][2] = true;
			break;
		}
	}
	return refresh_candidate_selected_categories();
}

/*
	Removes a category from the candidates HABTM list.
	New interface: see Trac #173.
*/
function remove_candidate_categories() {
	var src = $('CategoryCategory');

	var array_to_search, search_len, child_id;
	var len = src.options.length;
	for(var i = 0; i < len; i++) {
		if(src.options[i].selected) {
			array_to_search = cs[csi[src.options[i].parentID]][2];
			var search_len = array_to_search.length;
			for(j = 0; j < search_len; j++) {
				if(array_to_search[j][0] == src.options[i].value) {
					array_to_search[j][2] = false;
					break;
				}
			}
		}
	}
	return refresh_candidate_selected_categories();
}

/*
	Refreshes the list of selected categories for candidates.
	This has been simplified a bit for the new interface: see Trac #173.
*/
function refresh_candidate_selected_categories() {
	var dest = $('CategoryCategory');
	delete_all_child_nodes(dest);

	i_len = cs.length;
	var dest_optgroup, tmp_option;

	for(i = 0; i < i_len; i++) {
		j_len = cs[i][2].length;
		// We create two optgroups, and the options get shuffled into each of them
		// depending on whether they are selected.  If either of them has no options,
		// it won't be appended to its select element.
		dest_optgroup = document.createElement('optgroup');
		dest_optgroup.label = cs[i][1];
		for(j = 0; j < j_len; j++) {
			if(cs[i][2][j][2]) {
				tmp_option = document.createElement('option');
				tmp_option.value = cs[i][2][j][0];
				tmp_option.text = cs[i][2][j][1];
				tmp_option.innerText = cs[i][2][j][1]; // IE ^&*(%$
				tmp_option.parentID = cs[i][0]; // This is our own custom attribute, used for indexing.
				dest_optgroup.appendChild(tmp_option);
			}
		}
		if(dest_optgroup.childNodes.length > 0) {
			dest.appendChild(dest_optgroup);
		}
	}

	return false;
}

function delete_all_child_nodes(el) {
	var len = el.childNodes.length;
	for(var i = 0; i < len; i++) {
		el.removeChild(el.firstChild);
	}
}

// Selects all of the options in the specified select element so the data will actually be sent to the server.
function select_all(el_id) {
	var el = $(el_id);

	var len = el.options.length;

	for(var i = 0; i < len; i++) {
		el.options[i].selected = true;
	}

	return true;
}

// Checks whether the "I accept the terms & conditions" checkbox is checked before allowing the
// form to proceed.
function check_t_c(element_id) {
	var el = $(element_id);
	if(!el.checked) {
		alert('Please ensure you agree to our terms & conditions before continuing.');
		return false;
	}
	return true;
}

// activates the chosen tab (intended for the /admin/members/edit screen).  It is assumed that
// tab #1 is the initially-displayed tab, unless you override this variable in your view.
var active_tab = 1;
function activate_tab(num) {
	if(num == active_tab) {
		return;
	}
	if(active_tab) {
		$('tab_' + active_tab).style.display = 'none';
		$('tab_heading_' + active_tab).className = 'tab-inactive';
	}
	$('tab_' + num).style.display = 'block';
	$('tab_heading_' + num).className = 'tab-active';
	active_tab = num;
}

// Sets up the parent categories for the add/edit job screens.
// parent_selected_value is only needed for the job/candidate radar screens where we add some
// extra subcategories that have IDs of 0, to indicate "search all categories".
function init_job_categories(parent_id, child_id, child_selected_value, parent_selected_value) {
	var parent_node = $(parent_id);
	var len = cs.length;
	var c_len;
	var i, j;
	var selected_parent_id = null;

	// Find out which parent to select
	if(parent_selected_value) {
		selected_parent_id = parent_selected_value;
	}
	else {
		if(child_selected_value != null) {
			for(i = 0; i < len; i++) {
				c_len = cs[i][2].length;
				for(j = 0; j < c_len; j++) {
					if(cs[i][2][j][0] == child_selected_value) {
						selected_parent_id = cs[i][0];
						break;
					}
				}
				if(selected_parent_id != null) {
					break;
				}
			}
		}
	}

	// Remove the "initialising" text
	delete_all_child_nodes(parent_node);
	// Trac #327
	setTimeout("fill_parent_categories('" + parent_id + "'," + selected_parent_id + ")", 100);
	// This might be a little risky (it MUST occur after fill_parent_categories() has completed) but it saves us passing through a whole bunch of parameters.
	setTimeout("populate_job_subcategories('" + parent_id + "','" + child_id + "'," + child_selected_value + ")", 200);
	return false;
}

// Sets up the child categories for the add/edit job screens.
function populate_job_subcategories(parent_id, child_id, child_selected_value) {
	var opt = null;
	var i;

	// Find out which parent is selected
	var parent_node = $(parent_id);
	var len = parent_node.options.length;
	for(i = 0; i < len; i++) {
		if(parent_node.options[i].selected) {
			opt = parent_node.options[i].value;
			break;
		}
	}

	if(opt == null) {
		return false;
	}

	var child_node = $(child_id);
	delete_all_child_nodes(child_node);
	// Trac #327
	setTimeout("fill_child_categories('" + child_id + "'," + opt + "," + child_selected_value + ")", 100);

	return false;
}

// This is here because the javascript is being a pain: it's not allowing us to delete the categories then 
// repopulate them in the same function (mainly seems to be IE6 but has been observed in FF).  So this has been
// split out and called with a setTimeout(). -- Trac #327
function fill_parent_categories(parent_id, selected_parent_id) {
	var parent_node = $(parent_id);
	var len = cs.length;
	for(i = 0; i < len; i++) {
		parent_node.options[parent_node.options.length] = new Option(cs[i][1], cs[i][0], false, (cs[i][0] == selected_parent_id));
	}
	return false;
}

// See comments for fill_parent_categories()
function fill_child_categories(child_id, parent_selected_value, child_selected_value) {
	var child_node = $(child_id);
	var len = cs[csi[parent_selected_value]][2].length;
	for(i = 0; i < len; i++) {
		child_node.options[child_node.options.length] = new Option(cs[csi[parent_selected_value]][2][i][1], cs[csi[parent_selected_value]][2][i][0], false, (cs[csi[parent_selected_value]][2][i][0] == child_selected_value));
	}
}

// Write a value to a node (innerHTML is not strictly supported under XHTML and browser compatibility varies)
function write_value(el, value) {
	if(el.innerText) {
		el.innerText = value;
	}
	else {
		el.textContent = value;
	}
}

var current_thread = 0;
// Reveal a message thread in the job/candidate detail views.
function show_thread(uid) {
	if(!uid || (uid == current_thread)) {
		return false;
	}
	if(current_thread) {
		var el = $('thread-' + current_thread);
		el.style.display = 'none';
		el.style.backgroundColor = '';
		el = $('tab-' + current_thread);
		el.style.backgroundColor = '';
	}

	el = $('thread-' + uid);
	el.style.display = 'block';

	el = $('tab-' + uid);
	// If el is no good it means there are no tabs (ie this agent does not own the job).
	if(el) {
		el.style.backgroundColor = '#DDDDDD';

		el = $('message_reply_heading');
		// If the position was filled then the message box is hidden so this stuff will generate errors.
		if(el) {
			el.innerHTML = 'Reply to ' + message_users[uid];

			el = $('message_reply_agent');
			el.value = uid;
		}
	}

	current_thread = uid;
	return false;
}

// Trac #484: trim spaces from the login fields.
function trim_fields() {
	trim_field('User.email');
	trim_field('password');
	return true;
}

function trim_field(id) {
	var el = $(id);
	// I tried a regexp but it doesn't seem possible to match whitespace at the end of the string without
	// also taking out whitespace in the middle.
	while((el.value.length > 0) && (el.value.indexOf(' ') == 0)) {
		el.value = el.value.slice(1);
	}
	while((el.value.length > 0) && (el.value.lastIndexOf(' ') == el.value.length - 1)) {
		el.value = el.value.slice(0, el.value.length - 1);
	}
}
