﻿/**@fileoverview
  *
  * Provides a few basic functions to be available on all public-facing
  * pages.
  *
  * 2010-04-25: Support for new form return system.
  *
  * 2010-04-13: Pass latest JSLint. No code / interface changes.
  *             Removed dependance on $.
  */

/*global window, document, Dom, Event, Image, Lang, YAHOO */



if (!Array.prototype.indexOf) {
	/** Returns the first index at which a given element can be found in the
	  * array, or -1 if it is not present.
	  * This algorithm is exactly the one used in Firefox and SpiderMonkey.
	  * @param  {Object}    elt    Element to locate in the array.
	  * @param  {Integer}  [from]  The index at which to begin the search.
	  *                            Defaults to 0, i.e. the whole array will be
	  *                            searched. If the index is greater than or
	  *                            equal to the length of the array, -1 is
	  *                            returned, i.e. the array will not be
	  *                            searched. If negative, it is taken as the
	  *                            offset from the end of the array. Note that
	  *                            even when the index is negative, the array
	  *                            is still searched from front to back. If
	  *                            the calculated index is less than 0, the
	  *                            whole array will be searched.
	  * @return {Number} */
	Array.prototype.indexOf = function (elt /*, from*/) {
		var len = this.length,
		from = Number(arguments[1]) || 0;

		from = (from < 0) ? Math.ceil(from) : Math.floor(from);

		if (from < 0) {
			from += len;
		}

		for (; from < len; from++) {
			if (from in this && this[from] === elt) {
				return from;
			}
		}
		return -1;
	};
}


if (!Array.prototype.lastIndexOf) {
	/** Returns the last index at which a given element can be found in the
	  * array, or -1 if it is not present. The array is searched backwards,
	  * starting at fromIndex. This algorithm is exactly the one used in
	  * Firefox and SpiderMonkey.
	  *
	  * @param  {Object}    elt    Element to locate in the array.
	  *
	  * @param  {Integer}  [from]  The index at which to start searching
	  *                            backwards. Defaults to the array's length,
	  *                            i.e. the whole array will be searched. If
	  *                            the index is greater than or equal to the
	  *                            length of the array, the whole array will
	  *                            be searched. If negative, it is taken as
	  *                            the offset from the end of the array. Note
	  *                            that even when the index is negative, the
	  *                            array is still searched from back to front.
	  *                            If the calculated index is less than 0, -1
	  *                            is returned, i.e. the array will not be
	  *                            searched.
	  *
	  * @return {Number}
	  */
	Array.prototype.lastIndexOf = function (elt /*, from*/) {
		var len = this.length,
		from = Number(arguments[1]);

		if (isNaN(from)) {
			from = len - 1;
		} else {
			from = (from < 0) ? Math.ceil(from) : Math.floor(from);

			if (from < 0) {
				from += len;
			} else if (from >= len) {
				from = len - 1;
			}
		}

		for (; from > -1; from--) {
			if (from in this && this[from] === elt) {
				return from;
			}
		}
		return -1;
	};
}


if (!Array.prototype.some) {
	/** Tests whether some element in the array passes the test implemented by
	  * the provided function. This algorithm is exactly the one used in
	  * Firefox and SpiderMonkey.
	  *
	  * @param  {Function}  fun     Function to test for each element.
	  *
	  * @param  {Object}   [thisp]  Object to use as this when executing fun.
	  *
	  * @return {Boolean}
	  */
	Array.prototype.some = function (fun /*, thisp*/) {
		var len = this.length,
		thisp   = arguments[1],
		i;

		if (typeof fun !== "function") {
			throw new TypeError();
		}

		for (i = 0; i < len; i++) {
			if (i in this && fun.call(thisp, this[i], i, this)) {
				return true;
			}
		}

		return false;
	};
}



if (!Array.prototype.every) {
	/** Tests whether all elements in the array pass the test implemented by
	  * the provided function. This algorithm is exactly the one used in
	  * Firefox and SpiderMonkey.
	  *
	  * @param  {Function}  fun     Function to test for each element.
	  *
	  * @param  {Object}   [thisp]  Object to use as this when executing fun.
	  *
	  * @return {Boolean}
	  */
	Array.prototype.every = function (fun /*, thisp*/) {
		var len = this.length,
		thisp   = arguments[1],
		i;

		if (typeof fun !== "function") {
			throw new TypeError();
		}

		for (i = 0; i < len; i++) {
			if (i in this && !fun.call(thisp, this[i], i, this)) {
				return false;
			}
		}

		return true;
	};
}



if (!Array.prototype.forEach) {
	/** Executes a provided function once per array element.
	  * This algorithm is exactly the one used in Firefox and SpiderMonkey.
	  * @param  {Function}  fun     Function to test for each element.
	  * @param  {Object}   [thisp]  Object to use as this when executing fun. */
	Array.prototype.forEach = function (fun /*, thisp*/) {
		var len = this.length,
		thisp = arguments[1],
		i;

		if (typeof fun !== "function") {
			throw new TypeError();
		}

		for (i = 0; i < len; i++) {
			if (i in this) {
				fun.call(thisp, this[i], i, this);
			}
		}
	};
}



if (!Array.prototype.filter) {
	/** Creates a new array with all elements that pass the test implemented
	  * by the provided function. This algorithm is exactly the one used in
	  * Firefox and SpiderMonkey.
	  *
	  * @param  {Function}  fun     Function to test for each element.
	  *
	  * @param  {Object}   [thisp]  Object to use as this when executing fun.
	  *
	  * @return {Array}
	  */
	Array.prototype.filter = function (fun /*, thisp*/) {
		var len = this.length,
		res     = [],
		thisp   = arguments[1],
		i, val;

		if (typeof fun !== "function") {
			throw new TypeError();
		}

		for (i = 0; i < len; i++) {
			if (i in this) {
				val = this[i]; // in case fun mutates this
				if (fun.call(thisp, val, i, this)) {
					res.push(val);
				}
			}
		}

		return res;
	};
}



if (!Array.prototype.map) {
	/** Creates a new array with the results of calling a provided function
	  * on every element in this array. This algorithm is exactly the one
	  * used in Firefox and SpiderMonkey.
	  *
	  * @param  {Function} fun
	  * @param  {Object}   [thisp]
	  * @return {Array}
	  */
	Array.prototype.map = function (fun /*, thisp*/) {
		var len = this.length,
		res     = [],
		thisp   = arguments[1],
		i;

		if (typeof fun !== "function") {
			throw new TypeError();
		}

		for (i = 0; i < len; i++) {
			if (i in this) {
				res[i] = fun.call(thisp, this[i], i, this);
			}
		}

		return res;
	};
}



if (!Array.prototype.reduce) {
	/** Apply a function simultaneously against two values of the array
	  * (from left-to-right) as to reduce it to a single value.
	  * This algorithm is exactly the one used in Firefox and SpiderMonkey.
	  *
	  * @param  {Function}  callback         Function to execute on each
	  *                                      value in the array.
	  *
	  * @param  {Object}   [initialValue]    Object to use as the first
	  *                                      argument to the first call of
	  *                                      the callback.
	  * @return {Object}
	  */
	Array.prototype.reduce = function (fun /*, initial*/) {
		var len = this.length,
		rv, i   = 0;
		if (typeof fun !== "function") {
			throw new TypeError();
		}

		// no value to return if no initial value and an empty array
		if (len === 0 && arguments.length === 1) {
			throw new TypeError();
		}

		if (arguments.length >= 2) {
			rv = arguments[1];
		} else {
			do {
				if (i in this) {
					rv = this[i++];
					break;
				}

				// if array contains no values, no initial value to return
				if (++i >= len) {
					throw new TypeError();
				}
			} while (true);
		}

		for (; i < len; i++) {
			if (i in this) {
				rv = fun.call(null, rv, this[i], i, this);
			}
		}

		return rv;
	};
}


if (!Array.prototype.reduceRight) {
	/** Apply a function simultaneously against two values of the array
	  * (from right-to-left) as to reduce it to a single value.
	  * This algorithm is exactly the one used in Firefox and SpiderMonkey.
	  *
	  * @param  {Function}  callback         Function to execute on each
	  *                                      value in the array.
	  *
	  * @param  {Object}   [initialValue]    Object to use as the first
	  *                                      argument to the first call of
	  *                                      the callback.
	  * @return {Object}
	  */
	Array.prototype.reduceRight = function (fun /*, initial*/) {
		var len = this.length,
		rv, i   = len - 1;
		if (typeof fun !== "function") {
			throw new TypeError();
		}

		// no value to return if no initial value, empty array
		if (len === 0 && arguments.length === 1) {
			throw new TypeError();
		}

		if (arguments.length >= 2) {
			rv = arguments[1];
		} else {
			do {
				if (i in this) {
					rv = this[i--];
					break;
				}

				// if array contains no values, no initial value to return
				if (--i < 0) {
					throw new TypeError();
				}
			} while (true);
		}

		for (; i >= 0; i--) {
			if (i in this) {
				rv = fun.call(null, rv, this[i], i, this);
			}
		}

		return rv;
	};
}


var PB = {
	JumpSelect: function (o) {
		if (o.value && o.value !== '') {
			document.location.href = o.value;
		}
	},

	CloseChild: function (o) {
		o.close();
	},

	ContentClass: 'layout_eWEP',
	FormFill: {
		fill: function (data) {
			function getLabel(field) {
				return field.label;
			}

			var required =
				data.fields.filter(function (field) {
					return field.missing;
				}).map(getLabel),

			bad =
				data.fields.filter(function (field) {
					return (field.validate === false);
				}).map(getLabel),

			message = [];

			if (required.length) {
				message.push(
					"The following fields are required:\n\t" +
					required.join("\n\t"));
			}

			if (bad.length) {
				message.push(
					"The following fields were submitted with " +
					"invalid data:\n\t" + bad.join("\n\t"));
			}

			if (data.extra && data.extra.length) {
				message.push(data.extra);
			}

			if (message.length) {
				window.alert(message.join("\n\n"));
			}

			data.fields.forEach(function (field) {
				PB.FormFill.Load(data.formID, field.name, field.value);
			});

		},
		Load: function (formID, fieldName, value) {
			var i, x, field, form;
			if (value === null) {
				return;
			}
			form = Dom.get('formID_' + formID.toString());
			if (form) {
				field = form[fieldName];
			}

			if (field) {
				switch (field.type) {
				case 'select-one':
					i = field.options.length;
					while (i--) {
						if (field[i].value === value ||
							field[i].text === value) {

							field.selectedIndex = i;
						}
					}
					break;

				case 'select-multiple':
					i = field.options.length;
					while (i--) {
						for (x = 0; x < value.split(', ').length; x++) {
							if (field[i].value === value.split(', ')[x] ||
								field[i].text === value.split(', ')[x]) {

								field.options[i].selected = true;
							}
						}
					}
					break;

				case 'radio':
				case 'checkbox':
					if (field.value === value) {
						field.checked = true;
					}
					break;

				case 'file':
					break;

				case undefined:
					// The form element is likely a nodelist.
					if (field.length && field.length > 0) {
						switch (field[0].type) {
						case 'radio':
							i = field.length;
							while (i--) {
								if (field[i].value === value) {
									field[i].checked = true;
								}
							}
							break;

						case 'checkbox':
							i = field.length;
							value = value.split(', ');
							while (i--) {
								x = value.length;
								while (x--) {
									if (field[i].value === value[x]) {
										field[i].checked = true;
									}
								}
							}
							break;
						}
					}
					break;

				default:
					field.value = value;
					break;
				}
			}
		}
	},
	MouseOvers: {
		elements:    [ ],
		waiting:     false,

		/** Add a mouseover effect
		  * @param  {string | img}  el
		  * @param  {string}        hoverURL
		  */
		add: function (el, hoverURL) {
			this.elements.push({
				el      : el,
				src     : null,
				hoverEl : null,
				hoverSrc: hoverURL,
				applied : false
			});
		},

		/** Applies all loaded mouse over effects that have not already been
		  * applied. Performs pre-loading of hover URLs that match elements
		  * that are found in the document.
		  *
		  * It is safe to call this whenever--any real work will be defered
		  * until the DOM is available.
		  */
		apply: function () {
			if (this.waiting === true) {
				return;
			}

			this.waiting = true;
			Event.onDOMReady(function () {
				var els = this.elements,
				x, z, el;
				this.waiting = false;
				for (x = 0; x < els.length; x++) {

					if (els[x].applied === true) {
						continue;
					}

					el = Dom.get(els[x].el);
					if (el === null || el.nodeName.toLowerCase() !== 'img') {
						continue;
					}

					z = els.length;
					while (z--) {
						if (els[z].el === el && els[z].applied === true) {
							els[x].applied = true;
							continue;
						}
					}

					els[x].el  = el;
					els[x].src = el.src;
					els[x].hoverEl = new Image(el.width, el.height);
					els[x].hoverEl.alt = el.alt;
					els[x].hoverEl.src = els[x].hoverSrc;
					els[x].hoverSrc    = els[x].hoverEl.src;
					Event.addListener(el, 'mouseover', this.doHover, els[x]);
					Event.addListener(el, 'mouseout',  this.doHover, els[x]);

					els[x].applied = true;
				}

			}, this, true);
		},
		doHover: function (e, o) {
			var target = Event.getTarget(e);
			target.src = (e.type === 'mouseover') ? o.hoverSrc : o.src;
		}
	},

	FontResizer: {

		data: {
			content: 'layout_Content',
			sizes: {
				size1: 'text_size_1',
				size2: 'text_size_2',
				size3: 'text_size_3',
				size4: 'text_size_4'
			},
			cssSizes: {
				size1: '10px',
				size2: '13px',
				size3: '16px',
				size4: '19px'
			}
		},

		init: function () {
			var k;

			function resolve(o) {
				for (var x in o) {
					if (Lang.hasOwnProperty(o, x)) {
						o[x] = Dom.get(o[x]);
					}
				}
			}

			resolve(this.data);
			resolve(this.data.sizes);

			// Abort if we don't have controls
			if (!this.data.sizes.size1) {
				return;
			}

			for (k in this.data.sizes) {
				if (this.data.sizes.hasOwnProperty(k)) {

					Event.addListener(this.data.sizes[k], 'click',
						this.doClick, this, true);

				}
			}

			this.findActiveState();
			if (this.currentState !== 'size2') {
				this.setState(this.currentState);
			}
		},

		findActiveState: function () {
			var idx, name, x,
			cookies  = document.cookie.split('; '),
			value    = null;

			// Read cookie
			for (x = 0; x < cookies.length; x++) {
				idx = cookies[x].indexOf('=');
				name = cookies[x].substr(0, idx);
				if (name !== 'FontSize') {
					continue;
				}
				value = cookies[x].substring(idx + 1);
				break;
			}

			if (value === null) {
				value = 'size2';
			}

			if (Lang.hasOwnProperty(this.data.sizes, value) === false) {
				value = 'size2';
			}

			this.currentState = value;
			document.cookie = 'FontSize=' + value;
		},

		doClick: function (e) {
			var target = Event.getTarget(e),
			x, value   = null;

			for (x in this.data.sizes) {
				if (Lang.hasOwnProperty(this.data.sizes, x) &&
					this.data.sizes[x] === target) {
					value = x;
				}
			}

			if (value === this.currentState || value === null) {
				return;
			}

			this.setState(value);

		},
		setState: function (value) {

			var size = this.data.cssSizes[value];
			if (!size) {
				return;
			}

			Dom.setStyle(this.data.content, 'fontSize', size);
			this.currentState = value;
			document.cookie = 'FontSize=' + value;
		}
	},
	dropMenus: {
		selects: null,
		init: function () {
			var el = Dom.get('layout_TopMenu'),
			x, li, selects, ie = YAHOO.env.ua.ie;

			if (ie > 6 || ie === 0 || !el) {
				return;
			}

			el = Dom.getElementsByClassName('Root', 'UL', el)[0];

			if (!el) {
				return;
			}

			li = [];
			x = el.childNodes.length;
			while (x--) {
				if (el.childNodes[x].nodeName === 'LI') {
					li.push(el.childNodes[x]);
				}
			}

			Event.addListener(li, 'mouseover', this.onMouseOver);
			Event.addListener(li, 'mouseout',  this.onMouseOut);

			selects = Dom.get('bd');
			if (!selects) {
				return;
			}
			selects = selects.getElementsByTagName('SELECT');
			if (selects.length) {
				this.selects = selects;
			}
		},
		onMouseOver: function () {
			Dom.addClass(this, 'hover');
			if (PB.dropMenus.selects) {
				Dom.addClass(PB.dropMenus.selects, 'hover');
			}
		},
		onMouseOut: function () {
			Dom.removeClass(this, 'hover');
			if (PB.dropMenus.selects) {
				Dom.removeClass(PB.dropMenus.selects, 'hover');
			}
		}
	}
};

Event.onDOMReady(PB.dropMenus.init, PB.dropMenus, true);

