/*!
 * This software is a work of authorship by MD Health Evolution, or
 * duly licensed for use by MD Health Evolution, and is protected by
 * the copyright laws of the United States and foreign jurisdictions.
 *  
 * Copyright (c) 2008 MD Health Evolution or LICENSOR.
 * All rights reserved.
 */
/* Comment above is preserved after compression */

/*
 * The following software is the confidential and proprietary information of
 * Starfield Consulting/Dolf Starreveld and may not be used, reproduced,
 * modified, distributed, publicly displayed or otherwise disclosed without the
 * express written consent of Starfield Consulting or Dolf Starreveld.
 * 
 * This software is a work of authorship by Starfield Consulting/ Dolf
 * Starreveld and is protected by the copyright laws of the United States and
 * foreign jurisdictions.
 * 
 * Copyright (c) 2008 Starfield Consulting/Dolf Starreveld. All rights reserved.
 */
/**
 * Internet Explorer and Opera have a bug whereby their getElementById method
 * will not only return elements with that id, but also elements with a 'name'
 * attribute equal to the id. Here we replace the implementation with a
 * correctly functioning alternative, except that if that node has a child with
 * such an name attribute it will test that child rather than the element's
 * attribute.
 */
if (Prototype.Browser.IE || Prototype.Browser.Opera) {
	document.nativeGetElementById = document.getElementById;
	document.getElementById = function(id) {
		var el = document.nativeGetElementById(id);
		if (el) {
			if (el.attributes['id'] && el.attributes['id'].value == id)
				return el;
			var l = document.all[id];
			for ( var i = 1; i < l.length; ++i) {
				if (l[i].attributes['id'] && l[i].attributes['id'].value == id)
					return l[i];
			}
		}
		return null;
	};
}

/*
 * Set focus in a form of specified name and field of specified name. If no form
 * specified, first form on page is used. If no field is specified, first usable
 * field in form is used.
 */
function focusFirst(form, field) {
	form = $$(!form ? 'form' : form).first();
	if (!form)
		return;
	if (!field)
		form.focusFirstElement();
	else
		$(form[field]).activate();
}
function getProperty(props, key, def) {
	if ((props !== undefined) && props[key])
		return props[key];
	return def;
}

/*
 * Open a URL in a new window with specified title (name) and properties.
 */
var popups = new Array();
function showInWindow(url, target, properties) {
	var openProps = '';
	if (properties) {
		var keys = [ 'width', 'height', 'left', 'top', 'toolbar', 'status',
				'menubar', 'scrollbars', 'resizable' ];
		$A(keys).each( function(value) {
			if (properties[value] !== undefined)
				openProps += value + '=' + properties[value] + ',';
		});
		if (openProps.length > 0)
			openProps = openProps.substring(0, openProps.length - 1);
	}

	var entry = getProperty(popups, target, undefined);
	if ((entry === undefined) || entry.window.closed || (entry.url != url)) {
		var w = window.open(url, target, openProps);
		if (target)
			popups[target] = {
				window : w,
				url : url
			};
		return w;
	}
	entry.window.focus();
	return entry.window;
}
function showDateSelector(element, range) {
	new CalendarDateSelect(element, {
		year_range : range,
		date : element.value,
		onchange : function() {
			this.fire('cal:change', this.value);
		}
	});
}
function attachCalendars(selector, range, cal_img) {
	var properties = {
		'class' : 'calendar_image',
		src : cal_img
	};
	$$(selector).each( function(el) {
		var img = new Element('img', properties);
		img.observe('click', function(event) {
			showDateSelector(el, range);
		});
		el.insert( {
			after : img
		});
	});
}
function attachCalendar(element, range, cal_img) {
	attachCalendars('#' + element, range, cal_img);
}

/**
 * Class that sets up selected image elements for automatic rollovers. The
 * images are designated by a CSS selector. The rollover image is expected to
 * have the same name, but with "_over" appended. This code handles both regular
 * images, and versioned static images.
 */
RollOverMgr = Class.create( {
	initialize : function(options) {
		this.setOptions(options);
	},
	setOptions : function(options) {
		this.options = {
			overSuffix : '_over'
		};
		Object.extend(this.options, options || {});
	},
	addOne : function(el) {
		var src = el.src;
		var parts = src.match(/^(.*)((-\d+)\.(gif|jpg|png))$/i);
		if (!parts)
			parts = src.match(/^(.*)(\.(gif|jpg|png))$/i);
		if (parts) {
			var newsrc = parts[1] + this.options.overSuffix + parts[2];
			el._rollmgr = this; /* Forces a reference so we stay around */
			el._rollsrc1 = el.src;
			el._rollsrc2 = newsrc;
			(new Image()).src = newsrc; /* Start preload */
			el.observe('mouseover', this.moveIn);
			el.observe('mouseout', this.moveOut);
		}
	},
	addFromSelector : function(selector) {
		$$(selector).each(this.addOne.bind(this));
	},
	moveIn : function(e) {
		var img = e.element();
		if (img._rollsrc2)
			img.src = img._rollsrc2;
	},
	moveOut : function(e) {
		var img = e.element();
		if (img._rollsrc1)
			img.src = img._rollsrc1;
	}
});
ToggleImage = Class.create( {
	initialize : function(el, hideimg, initialOn) {
		this.image = el;
		(new Image()).src = hideimg; /* Start preload */
		this.onsrc = el.src;
		this.offsrc = hideimg;
		this.state = initialOn;
		if (!initialOn)
			this.toggle();
		el.observe('click', this.toggle.bindAsEventListener(this));
	},
	toggle : function(e) {
		this.image.src = this.state ? this.offsrc : this.onsrc;
		this.state = !this.state;
	}
});
CheckBoxGroup = Class.create( {
	/**
	 * The events must be observed on the form because IE will, in some
	 * scenarios, not bubble the event to the checkbox target. One such example
	 * is in forms generated with Zend_Form where a hidden field with the
	 * unchecked value, but same name as the checkbox is present. If the hidden
	 * field is not there, things would work fine.
	 */
	initialize : function(form, master, slaves) {
		this.form = form;
		this.master = $(master);
		this.slaves = slaves.without(master);
		this.checkedcount = 0;
		this.observeSlaves();
		this.maxcount = this.slaves.length;
		this.observeMaster();
		this.fireChange();
		this.master.enable();
		return this;
	},
	fireChange : function() {
		this.master.fire('checkboxgroup:change', {
			group : this
		});
	},
	disableAll : function(v) {
		this.master.disabled = v;
		this.slaves.each( function(cb) {
			cb.disabled = v;
		});
	},
	numSelected : function() {
		return this.checkedcount;
	},
	hasSelected : function() {
		return this.checkedcount != 0;
	},
	masterChanged : function(e) {
		var target = $(e.element());
		if (target === this.master) {
			var v = target.checked;
			this.slaves.each( function(el) {
				el.checked = v;
			}.bind(this));
			this.checkedcount = v ? this.maxcount : 0;
			this.fireChange();
		}
	},
	slaveChanged : function(e) {
		var newstate = null;
		var target = $(e.element());
		if (target.checked) {
			if (++this.checkedcount == this.maxcount) {
				newstate = true;
			}
		} else {
			if (--this.checkedcount == 0) {
				newstate = false;
			}
		}
		if (newstate !== null)
			this.master.checked = newstate;
		this.fireChange();
	},
	observeSlaves : function() {
		var listener = this.slaveChanged.bindAsEventListener(this);
		this.slaves.each( function(cb) {
			if (cb.checked)
				this.checkedcount++;
			if (cb != this.master)
				cb.observe('click', listener);
		}.bind(this));
	},
	observeMaster : function() {
		this.master.observe('click', this.masterChanged
				.bindAsEventListener(this));
	}
});
RadioGroup = Class
		.create( {
			initialize : function(parent, radios) {
				this.parent = parent;
				this.radios = $A(radios);
				this.count = this.countTrue();
				this.radios.invoke('observe', 'change', this.hasChanged
						.bindAsEventListener(this));
				this.parent.fire('radiogroup:anytrue', {
					anyTrue : this.anyTrue()
				});
			},
			hasChanged : function(e) {
				var n = this.countTrue();
				if (this.count != n) {
					this.count = n;
					this.parent.fire('radiogroup:anytrue', {
						anyTrue : this.anyTrue()
					});
				}
				return false;
			},
			boolValue : function(v) {
				return !((v == 'n') || (v == 'N') || (v == 'f') || (v == 'F') || (v == 0));
			},
			isTrue : function(radio) {
				return radio.checked && this.boolValue(radio.value);
			},
			anyTrue : function() {
				return this.count != 0;
			},
			countTrue : function() {
				var c = 0;
				this.radios.each( function(r) {
					if (this.isTrue(r))
						c++;
				}.bind(this));
				return c;
			}
		});
PopupMgr = Class.create( {
	initialize : function(targets, properties) {
		this.properties = properties;
		this.attach($A(targets));
	},
	popit : function(e, anchor) {
		/**
		 * The event.element points at the actual element clicked, wich is not
		 * the anchor if the anchor contains tags inside of it. So we ass the
		 * anchor.
		 */
		var a = anchor;
		if ('function' == typeof this.properties)
			this.properties(a.href);
		else
			showInWindow(a.href, a.target, this.properties);
		e.stop(); // Prevent <A> from firing the regular way
},
attach : function(targets) {
	targets.each( function(t) {
		Element.observe(t, 'click', this.popit.bindAsEventListener(this, t));
	}.bind(this));
}
});
/**
 * Detects changes to font sizes when user changes browser settings Fires the
 * "text:resized" event with the following memo:
 * 
 * base : base font size delta : difference in pixels from previous setting size :
 * size in pixel of text
 * 
 * Adapted from http://www.alistapart.com/articles/fontresizing Requires
 * Prototype library 1.6.0 or later
 */
TextResizeMgr = Class.create( {
	initialize : function(element, freq) {
		this.createControlElement(element);
		this.interval = (freq) ? freq : 1;
		this.currentSize = this.base = -1;
		this.pe = null;
		this.start();
	},
	createControlElement : function(parent) {
		this.el = new Element('span', {
			id : 'textResizeControl'
		}).update('&nbsp;').setStyle( {
			position : 'absolute',
			left : '-9999px'
		});
		$(parent || document.body).appendChild(this.el);
		this.base = this.currentSize = this.getSize();
	},
	getSize : function() {
		return this.el.offsetHeight;
	},
	detect : function(thepe) {
		var newSize = this.getSize();
		if (newSize !== this.currentSize) {
			document.fire('text:resized', {
				base : this.base,
				delta : (this.currentSize != -1 ? newSize - this.currentSize
						: 0),
				size : this.currentSize = newSize
			});
		}
	},
	start : function() {
		if (!this.pe)
			this.pe = new PeriodicalExecuter(this.detect.bind(this),
					this.interval);
	},
	stop : function() {
		this.pe.stop();
		this.pe = null;
	}
});
function fixStdFormLabels() {

	var m = function(el) {
		// Only do this if not set to block (presumably: inline-block)
		if (!el.getStyle('display').endsWith('block')) {
			var span = new Element('span', {
				'style' : 'display:block;width:' + el.getStyle('width')
			});
			el.update(span.update(el.innerHTML)).setStyle(
					'display:-moz-inline-box');
		}
	};
	var forms = $$('form.stdForm');
	forms.invoke('hide');
	forms.each( function(f) {
		f.select('li label:not(.nofix)').each(m);
	});
	forms.invoke('show');
}
FormWatch = Class.create({
	initialize : function(form, options) {
		this.submitted = false;
		this.form = $(form);
		// Let's serialize this.form and store it...
		this.formcontents = $(form).serialize();
		// Observe beforeunload event...
		this.form.observe('submit', function() {
			this.submitted = true;
		}.bind(this));
		window.onbeforeunload = this.confirmExit.bind(this);
   },
   confirmExit : function(ev) {
	   this.newcontents = this.form.serialize();
	   if ((this.formcontents != this.newcontents) && !this.submitted) {
		   return 'You have not saved your changes on this page.';
      }
	  // Do not return anything if you don't want the message: NO RETURN STATEMENT
   }
});

/*
 * The following software is the confidential and proprietary information of MD
 * Health Evolution and may not be used, reproduced, modified, distributed,
 * publicly displayed or otherwise disclosed without the express written consent
 * of duly authorized personnel of MD Health Evolution.
 * 
 * This software is a work of authorship by MD Health Evolution and is protected
 * by the copyright laws of the United States and foreign jurisdictions.
 * 
 * Copyright (c) 2008 MD Health Evolution. All rights reserved.
 */

/*
 * Make columns in a YUI grids layout equal height.
 */
function fixsizes(e) {
	var sb = $$("#sidebar").reduce();
	if (!sb)
		return;
	var c = $$("#innercontent").reduce();
	if (!c)
		return;
	/* IE needs to be auto first, so they get recalculated */
	if (Prototype.Browser.IE) {
		c.style.height = "auto";
		sb.style.height = "auto";
	}
	var sbh = sb.getHeight();
	var ch = c.getHeight();
	sb.style.height = c.style.height = Math.max(ch, sbh) + "px";
}

/*
 * Play a video in a window of specified height and width, with a given window
 * title.
 */
function FP_playVideo(w, h, target, url) {
	popupWindow(url, target, {
		width : w,
		height : h,
		toolbar : 'no',
		status : 'no',
		menubar : 'no',
		scrollbars : 'no',
		resizable : 'no'
	});
}
/*
 * Play a video in a window of specified height and width, with a given window
 * title.
 * Resizable is ignored in Safari.
 */
function playVideo(url) {
	popupWindow(url, 'popupvideo', {
		width : 480,
		height : 305,
		toolbar : 'no',
		status : 'no',
		menubar : 'no',
		scrollbars : 'no',
		resizable : 'no'
	});
}

/*
 * Convenience for legacy code.
 */
function popup_window(url) {
	popupWindow(url, 'popup', {
		scrollbars : 'yes'
	});
}

/*
 * Simplified version of showInWindow, which supplies default width=850, and
 * height=900 and centers the window on the screen
 */
function popupWindow(url, target, properties) {
	var width = getProperty(properties, 'width', 850);
	var height = getProperty(properties, 'height', 900);
	var t = (screen.height - height) / 2;
	var l = (screen.width - width) / 2;
	if (properties === undefined)
		properties = new Object();
	properties.width = width;
	properties.height = height;
	properties.top = t;
	properties.left = l;
	nw = showInWindow(url, target, properties);
	return nw;
}

function disableState(cntry, state) {
	var disabled = cntry.options[cntry.selectedIndex].value != 'us';
	state.disabled = disabled;
	if (disabled)
		state.options.selectedIndex = 0;
}
function linkCountryToStateSelect(country, state) {
	disableState(country, state);
	country.observe('change', function(e) {
		disableState(Event.element(e), state);
	});
}
TableForm = Class.create( {
	initialize : function(f) {
		this.form = f;
		this.action = $(f['action']);
		this.actionOptions = $A(this.action.options);
		var fields = this.getNewRowFields();
		if (fields.size() == 0) {
			this.newentry = null;
		} else {
			this.newentry = {
				fields : fields
			};
		}
		var master = $(f['header-checkall']);
		this.checks = new CheckBoxGroup(f, master, f
				.select('td input[type=checkbox]'));
		this.hasChecked = this.checks.hasSelected();
		master.observe('checkboxgroup:change', this.checksChange
				.bindAsEventListener(this));
		this.newentry.listener = this.lastRowChange.bindAsEventListener(this);
		this.complete();
		if (this.newentry) {
			this.newentry.empty = this.newEntryEmpty();
			this.linkToNewEntry(this.newentry.fields);
		}
		this.updateActionMenu();
	},
	getNewRowFields : function() {
		alert('Must override');
	},
	complete : function() {
	},
	isNewEmpty : function() {
		return !this.newentry || this.newentry.empty;
	},
	newEntryEmpty : function() {
		if (this.newentry) {
			return this.newentry.fields.all( function(el) {
				return el.value.blank();
			});
		}
		return true;
	},
	updateActionMenu : function() {
		var hasNew = !this.isNewEmpty();
		this.actionOptions.find( function(o) {
			return o.value == 'delete_checked';
		}).disabled = !this.hasChecked || hasNew;
		this.checks.disableAll(hasNew);
	},
	checksChange : function(e) {
		var old = this.hasChecked;
		this.hasChecked = e.memo.group.hasSelected();
		if (old != this.hasChecked)
			this.updateActionMenu();
	},
	lastRowChange : function(e) {
		if (this.newentry) {
			var old = this.isNewEmpty();
			this.newentry.empty = this.newEntryEmpty();
			if (old != this.newentry.empty)
				this.updateActionMenu();
		}
	},
	linkToNewEntry : function(fields) {
		fields.invoke('observe', 'change', this.newentry.listener);
	}
});
GoalsForm = Class.create(TableForm, {
	complete : function($super) {
		this.newentry.radios = this.form.select('tr.new input[type=radio]');
		this.radios = new RadioGroup(this.form, this.form
				.select('tr.old input[type=radio]'));
		this.hasCompleted = this.radios.anyTrue();
		this.form.observe('radiogroup:anytrue', this.radiosChange
				.bindAsEventListener(this));
		this.linkToNewEntry(this.newentry.radios);
		this.viewDisabled = this.actionOptions.find( function(o) {
			return o.value == 'archive';
		}).disabled;
		$super();
	},
	getNewRowFields : function() {
		return this.form.select('tr.new input[type=text], tr.new textarea');
	},
	isNewEmpty : function($super) {
		return $super() && (this.newentry.radios.find( function(r) {
			return r.checked;
		}) === undefined);
	},
	updateActionMenu : function($super) {
		var newEmpty = this.isNewEmpty();
		this.actionOptions.find( function(o) {
			return o.value == 'delete_checked';
		}).disabled = !this.hasChecked || !newEmpty;
		this.actionOptions.find( function(o) {
			return o.value == 'archive';
		}).disabled = !this.hasCompleted || !newEmpty;
		this.actionOptions.find( function(o) {
			return o.value == 'view';
		}).disabled = this.viewDisabled;
		$super();
	},
	radiosChange : function(e) {
		var old = this.hasCompleted;
		this.hasCompleted = e.memo.anyTrue;
		if (old != this.hasCompleted)
			this.updateActionMenu();
	}
});
BMICalc = Class.create( {
	initialize : function(age, messageHandler) {
		this.ageField = age;
		this.messageHandler = (messageHandler === undefined) ? this.dumpMessage
				: messageHandler;
		this.observeAge();
		this.observers = new Array();
	},
	addRatedBMI : function(field, rate) {
		this.observers[this.observers.length] = [ field, rate ];
		return this;
	},
	dumpMessage : function(msg) {
	},
	calc : function(rate) {
		return Math.round((220 - this.ageField.value) * rate, 0);
	},
	isValid : function() {
		return this.ageValid;
	},
	validate : function() {
		var v = this.ageField.value.strip();
		if (v == '')
			return false;
		v = parseInt(v);
		if (isNaN(v)) {
			this.messageHandler('Enter numbers only please');
			this.ageField.focus();
			return false;
		}
		if ((v < 1) || (v > 99)) {
			this.messageHandler('Age should be in the range 1-99');
			this.ageField.focus();
			return false;
		}
		return true;
	},
	start : function() {
		this.onAgeChange();
		return this;
	},
	onAgeChange : function() {
		this.ageValid = this.validate();
		this.observers.each( function(item) {
			item[0].value = this.ageValid ? this.calc(item[1]) : '';
		}.bind(this));
	},
	observeAge : function() {
		this.ageField.observe('change', this.onAgeChange
				.bindAsEventListener(this));
	}
});
CalorieObserver = Class.create( {
	initialize : function(f, inputField, factor, calorieElement) {
		this.form = f;
		this.input = inputField;
		this.factor = factor;
		this.value = calorieElement;
		this.updateCalories();
		inputField.observe('change', this.update.bindAsEventListener(this));
		return this;
	},
	updateCalories: function() {
		this.value.innerHTML = this.input.value * this.factor;
	},
	update : function(e) {
		this.updateCalories();
		this.form.fire('calorie:change');
	},
	get : function() {
		return this.input.value * this.factor;
	}
});
FoodLogForm = Class.create( {
	initialize : function(f) {
		this.form = f;
		this.counts = $A(
				[ [ 'grains', 80 ], [ 'vegetables', 25 ], [ 'fruits', 60 ],
						[ 'dairy', 90 ], [ 'meats', 150 ], [ 'fats', 45 ],
						[ 'sweets', 80 ] ])
				.map(
						function(i) {
							return this.createCalorieObserver(this.form,
									this.form.select(
											'select[name=' + i[0] + ']')[0], i[1]);
						}.bind(this));
		this.total = $('cal_total');
		this.form.select('input[name=date]')[0].observe('cal:change',
				this.dateChanged.bindAsEventListener(this))
		this.form.observe('calorie:change', this.caloriesChanged
				.bindAsEventListener(this));
		this.caloriesChanged();
	},
	createCalorieObserver : function(f, sel, factor) {
		var name = sel.name;
		return new CalorieObserver(f, sel, factor, $('cal_' + name));
	},
	caloriesChanged : function(e) {
		var sum = 0;
		this.counts.each( function(i) {
			sum += i.get();
		});
		this.total.innerHTML = sum;
	},
	dateChanged : function(e) {
		window.location.href = this.form.action + '?date=' + e.memo;
	}
});
LiveItForm = Class.create( {
	initialize : function(f) {
		this.chkboxAttr = 'chkbox';
		this.form = f;
		f.select('textarea[' + this.chkboxAttr +'], input[type=text]').each( function(el) {
			el._box = $(el.readAttribute(this.chkboxAttr));
			el.observe('change', this.textChanged.bindAsEventListener(this));
			el.observe('keyup', this.textChanged.bindAsEventListener(this));
		}.bind(this));
		f.select('input[type=radio], input[type=checkbox]').each( function(el) {
			el._box = $(el.readAttribute(this.chkboxAttr));
			el.observe('change', this.radioChanged.bindAsEventListener(this));
		}.bind(this));
		f.select('a[' + this.chkboxAttr +']').each( function(el) {
			el._box = $(el.readAttribute(this.chkboxAttr));
			el.observe('click', this.linkClicked.bindAsEventListener(this));
		}.bind(this));
		return this;
	},
	toggleCheck : function(el, newState) {
		if (el._box.checked != newState) {
			el._box.checked = newState;
		}
	},
	textChanged : function(e) {
		var el = e.element();
		this.toggleCheck(el, $F(el).length > 0);
	},
	radioChanged : function(e) {
		var el = e.element();
		this.toggleCheck(el, el.checked);
	},
	linkClicked: function(e) {
		this.toggleCheck(e.element(), true);
	}
});
QAMgr = Class.create( {
	initialize : function(lists) {
		if (lists === null)
			return;
		var attachFunc = this.attach.bind(this);
		lists.each( function(el) {
			el.select('.question').each(attachFunc);
		});
	},
	getAnswers : function(question) {
		return question.select('.answer');
	},
	clickedQuestion : function(e) {
		var target = $(e.element());
		target.state = !target.state;
		this.getAnswers(target)
				.each(target.state ? Element.show : Element.hide);
	},
	attach : function(question) {
		question.observe('click', this.clickedQuestion
				.bindAsEventListener(this));
		question.state = false;
		this.getAnswers(question).each(Element.hide);
	}
});