var Formpage = {
	form_fields: new Array(), /* form_fields array populated inline, in Form layout Data component */
	err_messages: new Array(), /* err_messages array populated inline, in Form layout Data component */
	form_name: "",
	form: null,
	datepickers: new Array(),
	datepickerindex: new Array(),
	re_url:	  /^(http(s?)\:\/\/|~\/|\/)?([\w]+:\w+@)?([a-zA-Z]{1}([\w\-]+\.)+([\w]{2,5}))(:[\d]{1,5})?((\/?\w+\/)+|\/?)(\w+\.[\w]{3,4})?((\?\w+=\w+)?(&\w+=\w+)*)?$/i,
	re_email: /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i,
	re_date: /^(0?\d|[12]\d|3[01])[-\/](0?\d|1[012])[-\/](\d{2}|\d{4})$/i,
	// re_date: /^(?:(31)(\\D)(0?[13578]|1[02])\\2|(29|30)(\\D)(0?[13-9]|1[0-2])\\5|(0?[1-9]|1\\d|2[0-8])(\\D)(0?[1-9]|1[0-2])\\8)((?:1[6-9]|[2-9]\\d)?\\d{2})$|^(29)(\\D)(0?2)\\12((?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:16|[2468][048]|[3579][26])00)$/i,
	re_numeric: /\b[0-9\,\.]\b/i,
	errs:		0,
	first_error: null,
	date_picked: false,
	
	init: function(form_name){
		this.form_name = form_name;
		this.form = $(this.form_name);
		Event.observe(this.form, "submit", function(){Formpage.copy_dates();return Formpage.validate();});
		document.getElementsByClassName('datebutton').each(function(b){
			Event.observe(b, "click", function(){Formpage.toggle_datepicker(b);});
			b.previous().readOnly=true;
		});
	},

	copy_dates: function(){
		document.getElementsByClassName('smalldate').each(function(el){
			s = '';
			$(el).up('td').down('span').childElements().each(function(item){
				if(item.selectedIndex>=0){
					v = item.options[item.selectedIndex].value;
					if(v==''){v = item.options[item.selectedIndex].text;}
					if(s==''){s = v;}else{s = s + '/' + v;}
				}
			});
			el.value = s;
		});
	},

	toggle_datepicker: function(button){
		var field = button.previous();
		if(this.datepickers[field.id] != undefined){
			if(this.datepickers[field.id]["state"] == "open"){
				this.close_datepicker(field);
			}else
				this.open_datepicker(button, field);
		}else{
			this.open_datepicker(button, field);
		}
	},
		
	open_datepicker: function(button, field){
		$A(this.datepickerindex).each(function(i){
			if(Formpage.datepickers[i]["state"] == "open" && Formpage.datepickers[i]["field"].id != field.id) Formpage.close_datepicker(Formpage.datepickers[i]["field"]);
		});
		var val = field.value;
		if(this.datepickers[field.id]==undefined){
			this.datepickerindex[this.datepickerindex.length] = field.id;
			this.datepickers[field.id] = new Array();
			var dp = new DatePicker();
			var el = $(dp.create());
			el.id = "dp_" + field.id;
			this.datepickers[field.id]["field"] = field;
			this.datepickers[field.id]["dp"] = el;
			el.onclick = function(e){Formpage.close_if_picked(e, dp, field);};
			dp.onchange = function(){Formpage.get_date(dp, field);};
			// we don't need the footer buttons for this datepicker, nor the last empty table row. remove them
			el.getElementsByClassName("footer")[0].remove();
			var grid_table = el.getElementsByClassName("gridTable")[0];
			$A($(grid_table.childNodes[0].childNodes[grid_table.childNodes[0].childNodes.length-1]).childNodes).each(function(td){
				td.className = "jsnodisplay";
			});
		}else{
			el = this.datepickers[field.id]["dp"];
		}
		button.parentNode.appendChild( el );
		this.datepickers[field.id]["state"] = "open";
	},
		
	close_datepicker: function(field){
		$("dp_" + field.id).remove();
		this.datepickers[field.id]["state"] = "closed";
	},

	get_date: function(dp,field){
		var dt = dp.getDate();
		field.value = (dt.getDate()) + "/" + (dt.getMonth()+1) + "/" + (dt.getFullYear());
	},
	
	close_if_picked: function(e, dp, field){
		/* this function uses the MouseEvent object to track down the DOM element which is triggering the event. We only want to close the datepicker windows if the user clicks on a date in the calendar (as opposed the previous/next month buttons) */
		if(e==null) e = document.parentWindow.event;
		var el = e.target != null ? e.target : e.srcElement;
		while (el.nodeType != 1) el = el.parentNode;
		while(el != null && el.tagName && el.tagName.toLowerCase() != "td") el = el.parentNode;
		if (el != null && el.tagName != null && el.tagName.toLowerCase() == "td" && parseInt(el.innerHTML).toString() != "NaN")
			this.close_datepicker(field);
	},

	get_error: function(id){
		var field_marker = "[field]";
		var amount_marker = "[amount]";
		var sing_plur_marker_open = "[sing|plur]";
		var sing_plur_marker_close = "[/sing|plur]";
		var label = (arguments.length==2 ? arguments[1]:'');
		var limit = (arguments.length==3 ? arguments[2]:1);
		var sing = ""; var plur = ""; var sp_block = "";
		if(this.err_messages[id].indexOf(sing_plur_marker_open) != -1){
			sp_block =  this.err_messages[id].substring(this.err_messages[id].indexOf(sing_plur_marker_open),this.err_messages[id].indexOf(sing_plur_marker_close)+sing_plur_marker_close.length);
			sp = sp_block.substring(sing_plur_marker_open.length, sp_block.indexOf(sing_plur_marker_close));
			sing = sp.substring(0, sp.indexOf("|"));
			plur = sp.substring(sp.indexOf("|")+1);
		}
		return this.err_messages[id].replace(field_marker, label).replace(amount_marker, limit).replace(sp_block, limit==1?sing:plur)
	},

	validate: function(){
		// example of the javascript array to be generated on the form page by the application
		// Formpage.form_fields[Formpage.form_fields.length] = {id: "map['firstname']", label: 'First Name', type: 'text', data_type: 'text', min_occurs: 1, max_occurs: 1};
		this.errs = 0;
		$A(this.form_fields).each(function(n,i){
			el = Formpage.form.elements[n.id];
			switch(n.type.toLowerCase()){
				case 'text':
				case 'date':
				case 'textarea':
				case 'password':
				case 'file':
					Formpage.toggle_error(el, (n.min_occurs > 0 && el.value == ""), Formpage.get_error('field_required', n.label));
					if(el.value != ""){
						switch(n.data_type.toLowerCase()){
							case 'email':
								Formpage.toggle_error(el, !Formpage.re_email.test(el.value),Formpage.get_error('email_invalid'));					
								break;
							case 'date':
								Formpage.toggle_error(el, !Formpage.re_date.test(el.value),Formpage.get_error('date_invalid'));					
								break;
							case 'number':
								Formpage.toggle_error(el, !Formpage.re_numeric.test(el.value),Formpage.get_error('numeric_invalid', n.label));					
								break;
						}
					}
				break;
				case 'radio':
					checked = false;
					$A(el).each(function(x){ if(x.checked){ checked = true; $break;}});
					Formpage.toggle_error(el[0], (n.min_occurs > 0 && !checked), Formpage.get_error('not_selected', n.label));
				break;
				case 'checkbox':
					checked = 0;
					if(el[0]==undefined) el = new Array(el);
					$A(el).each(function(x){;if(x.checked)checked++;});
					Formpage.toggle_error(el[0], (n.min_occurs > checked),Formpage.get_error('too_few_selected', n.label, n.min_occurs));
					if(n.min_occurs <= checked)
					Formpage.toggle_error(el[0], (n.max_occurs < checked),Formpage.get_error('too_many_selected', n.label, n.max_occurs));		
				break;
				case 'select':
					selected = 0;
					$A(el.childNodes).each(function(x){ if(x.selected) selected++;});
					val = el.options[el.selectedIndex].value;
					if (val == "") val = el.options[el.selectedIndex].text;
					val = val.replace(/^\s+|\s+$/,'');
					if (val == unescape('%A0')) val = "";
					Formpage.toggle_error(el, (val == ""), Formpage.get_error('field_required', n.label));
					if(val != "") {
						Formpage.toggle_error(el, (n.min_occurs > selected),Formpage.get_error('too_few_selected', n.label, n.min_occurs));
						if(n.min_occurs <= selected)
						Formpage.toggle_error(el, (n.max_occurs < selected),Formpage.get_error('too_many_selected', n.label, n.max_occurs))
					}
				break;
			}
		});
		if(this.errs > 0) document.documentElement.scrollTop = Position.cumulativeOffset(Formpage.first_error)[1] - 10;
		return (this.errs==0);
	},
	
	get_container_row: function(el){
		while((el = el.parentNode) != null){
			if(el.tagName.toLowerCase() == "tr" && el.parentNode.parentNode.className=="form") break;
		}
		if(el.tagName.toLowerCase() == "tr" && el.parentNode.parentNode.className=="form") return el; else return null;
	},
	
	toggle_error: function(el, has_error, msg){
		row = $(Formpage.get_container_row(el));
		if(row != null){
			message_cell = row.getElementsByClassName("message")[0];
			if(has_error){
				row.addClassName("alert");
				if (BrowserDetect.browser == "Firefox"){ // Force Firefox to rewrite content of the <tr>.
					var range = document.createRange();
					range.selectNode(row);
					var parsedHTML = range.createContextualFragment('<td style="display: none;"></td>');
					row.appendChild(parsedHTML);
				}
				message_cell.update(msg);
				if(this.errs==0)this.first_error = row;
				this.errs++;
			}else{
				row.removeClassName("alert");
				message_cell.update("");
			}
		}
	}
}