/**
 * Form Generator
 * 
 * @author Sascha Nordquist <sascha[at]nordquist[dot]de>
 * 
 */

/**
 * Libary Path
 */
var form_path = "/libs/form/";

/**
 *  background color on error
 */
var error_color = "#EB6E6E";

/**
 * error notification type
 */
var error_notification = new Array();

/**
 * container of all fields to be checked
 */
check_fields = new Array();

/**
 *  container of required fields 
 *  required[formid][] = new Array(id,errormsg)
 *  id: id of the element
 *  errormsg: message on error
 */
check_fields["required"] = new Array();

/** 
 *  container of fields to check by length 
 *  lengthcheck[formid][] = new Array(id,type,num,label)
 *  id: id of the element
 *  type: min/max
 *  num: limit (example: 10)
 *  label: label of the field (errormessage is created with this label)
 */
check_fields["checklength"] = new Array();

/**
 *  container of fields to be checked by a specified attribute (example: equal).
 *
 */
check_fields["attribute"] = new Array();

/**
 *  container of fields to be checks by datatype
 */
check_fields["datatype"] = new Array();


/**
 * clear all form information
 * 
 * @param formid
 * @return
 */
function clearFormJs(formid)
{
	delete check_fields["required"][formid];
	delete check_fields["checklength"][formid];
	delete check_fields["attribute"][formid];
	delete check_fields["datatype"][formid];	
	upload_check[formid] = new Array();
	uploadTimeout[formid] = new Array();
}

/**
 * set notification type
 * 
 * @param formid
 * @param type
 * @return
 */
function setErrorNotification(formid,type)
{
	checkArr(error_notification,formid);
	error_notification[formid] = type;
}

/**
 * add a required field to form which will be checked on submit
 * 
 * @param formid
 * @param id
 * @param errormsg
 * @return
 */
function addRequired(formid,id,errormsg)
{
	form = $(formid);
	if (typeof form != 'undefined')
	{
		form.setAttribute('onSubmit', "return testForm(this)");
		checkArr(check_fields["required"],formid);
		check_fields["required"][formid].push(new Array(id,errormsg));
	}
}

/**
 * add a field to form. its length be checked on submit
 * 
 * @param formid
 * @param id
 * @param type
 * @param num
 * @param label
 * @return
 */
function addLengthCheck(formid,id,type,num,label)
{
	form = $(formid);
	if (typeof form != 'undefined')
	{
		form.setAttribute('onSubmit', "return testForm(this)");
		checkArr(check_fields["checklength"],formid);
		if (typeof label == 'undefined') label = id;
		check_fields["checklength"][formid].push(new Array(id,type,num,label));
	}
}

/**
 * add a field to be checked by a specified type
 * 
 * @param formid
 * @param type
 * @param fields
 * @return
 */
function addCheckFields(formid,type,fields)
{
	form = $(formid);
	if (typeof form != 'undefined')
	{
		form.setAttribute('onSubmit', "return testForm(this)");
		checkArr(check_fields["attribute"],formid);
		check_fields["attribute"][formid].push(new Array(type,fields))
	}
}

/**
 * add field to be checked by datatype
 * 
 * @param formid
 * @param id
 * @param datatype
 * @param label
 * @return
 */
function addCheckDataType(formid,id,datatype,label)
{
	form = $(formid);
	if (typeof form != 'undefined')
	{
		form.setAttribute('onSubmit', "return testForm(this)");
		checkArr(check_fields["datatype"],formid);
		check_fields["datatype"][formid].push(new Array(id,datatype,label))
	}
}


/**
 * add AutoComplete 
 * 
 * @param id
 * @param url
 * @return
 */
function addAutoComplete(id,url)
{
	new Ajax.Autocompleter(id, "autocomplete_choices_"+id, url, {
	  paramName: "value",
	  minChars: 1,
	  tokens: ','
	  /*updateElement: addItemToList, */
	  /*indicator: 'indicator_'+id */
	});
}


/**
 * checks if arr[key] is an array and creates if it is not 
 * 
 * @param arr
 * @param key
 * @return
 */
function checkArr(arr,key)
{
	if (typeof arr[key] == 'undefined') arr[key] = new Array();
}

/**
 * checks if array contains the element (see php in_array)
 * 
 * @param element
 * @param arr
 * @return
 */
function in_array(element,arr)
{
	for(i=0;i<arr.length;++i)
	{
		if (arr[i] === element)
		{
			return true;
		}
	}
	return false;
}

/**
 * submits a form
 * 
 * @param form
 * @return
 */
function form_submit(form)
{
	if (testForm(form)) form.submit();
}

/** 
 * ajax info 
 * 
 */
ajax_info = new Array();

/**
 * set ajax info
 * 
 * @param formid
 * @param action
 * @param resultid
 * @return
 */
function setAjaxInfo(formid,action,resultid)
{
	ajax_info[formid] = new Array(action,resultid);
}

/**
 * submits a form with ajax
 * 
 * @param formid
 * @return
 */
function form_ajax(formid)
{
	action = ajax_info[formid][0];
	resultid = ajax_info[formid][1];

	/* get all inputs */
	form = $(formid);
	inputs = form.getElementsByTagName('INPUT');
	selects = form.getElementsByTagName('SELECT');
	
	data = new Array();
	
	/* fetching data from form */
	/*for(i=0;i<inputs.length;i++) 
	{
		if (inputs[i].type == 'radio' || inputs[i].type == 'checkbox') 
		{
			if (inputs[i].checked)
			{
				data[inputs[i].name] = inputs[i].value;
			}
		}
		else
		{
			data[inputs[i].name] = inputs[i].value;
		}
	}
	for(i=0;i<selects.length;i++) data[selects[i].name] = selects[i].options[selects[i].selectedIndex].value;
	sdata = serialize(data);
	sdata = urlencode(sdata);*/

	sdata = form.serialize();

	/* starting ajax updater */
	new Ajax.Updater(resultid, action, {
		parameters: { formdata: sdata },
		evalScripts: true
	});


	if (typeof resultid != 'undefined')
	{
		element = $(resultid);
		if (element && typeof element != 'undefined')
		{
			/* showing indicator */
			element.innerHTML = '<img src="'+form_path+'images/indicator.gif" alt="Loading..." />';
		}
	}
	
	return false;
}

/**
 * checks form data
 * @param form - object/tag
 * @return
 */
function testForm(form)
{
	formid = form.id;
	errors = 0;
	errormsg = new Array();
	errorfields = new Array();
	
	/* check required fields */
	if (typeof check_fields["required"][formid] != 'undefined')
	{
		check_fields["required"][formid].each(function(id) 
		{
			element = $(id[0]);
			if (
				(element.tagName == 'INPUT') && 
				(typeof element.type == 'undefined' | element.type == 'text' || element.type == 'password') && 
				element.value == ""
			)
			{
				/* required text,password not entered */
				errorfields.push(element);
				if (id[1]) errormsg.push(id[1]);
				element.style.backgroundColor = error_color;
			}
			else if (element.tagName == 'TEXTAREA' && !element.value)
			{
				/* required textarea not entered */
				errorfields.push(element);
				if (id[1]) errormsg.push(id[1]);
				element.style.backgroundColor = error_color;				
			}
			else if (element.tagName == 'INPUT' && (element.type=='checkbox' || element.type=='radio') && !element.checked)
			{
				/* required checkbox or radio button not checked */
				errorfields.push(element);
				if (id[1]) errormsg.push(id[1]);
				element.style.backgroundColor = error_color;
			}
			else if (element.tagName == 'SELECT' && !element.options[element.selectedIndex].value)
			{
				errorfields.push(element);
				if (id[1]) errormsg.push(id[1]);
				element.style.backgroundColor = error_color;				
			}
			else if (!in_array(element,errorfields)) element.style.backgroundColor = "";
		});
	}
	/* required fields checked */

	/* length checks */
	if (typeof check_fields["checklength"][formid] != 'undefined')
	{
		check_fields["checklength"][formid].each(function(id)
		{
			element = $(id[0]);
			type = id[1];
			num = id[2];
			label = id[3];
			if (typeof label == 'undefined') label = id[0];
		
			if (type == 'min' && element.value.length < num)
			{
				/* not enough characters */
				errorfields.push(element);
				errormsg.push(label + " muss mindestens " + num + " Zeichen lang sein");
				element.style.backgroundColor = error_color;
			}
			else if (type == 'max' && element.value.length > num)
			{
				/* to much characters */
				errorfields.push(element);
				errormsg.push(label + " darf maximal " + num + " Zeichen lang sein");
				element.style.backgroundColor = error_color;
			}
			else if (!in_array(element,errorfields)) element.style.backgroundColor = "";
		});
	}
	/* end length checks */

	/* check for datatypes */
	if (typeof check_fields["datatype"][formid] != 'undefined')
	{
		check_fields["datatype"][formid].each(function(id)
		{
			element = $(id[0]);
			datatype = id[1];
			label = id[2];
			if (typeof label == 'undefined' || !label) label = id[0]; // if label not set, label = element id
			switch (datatype)
			{
				case 'int':
				{
					if (!form_isInt(element.value))
					{
						errorfields.push(element);
						errormsg.push(label + " muss eine Ganzzahl sein");
						element.style.backgroundColor = error_color;
					}
					break;
				}
				case 'float':
				{
					if (!form_isFloat(element.value))
					{
						errorfields.push(element);
						errormsg.push(label + " muss eine Zahl sein");
						element.style.backgroundColor = error_color;
					}
					break;
				}
				case 'nospecials':
				{
					if (form_hasSpecials(element.value))
					{
						errorfields.push(element);
						errormsg.push(label + " darf keine Sonderzeichen enthalten");
						element.style.backgroundColor = error_color;
					}
					break;
				}
				case 'email':
				{
					if (!form_isEmail(element.value))
					{
						errorfields.push(element);
						errormsg.push(label + " muss eine Email-Adresse sein");
						element.style.backgroundColor = error_color;
					}
					break;
				}
			}
			if (!in_array(element,errorfields))  element.style.backgroundColor = "";
		});
	}
	/* end datatype checks */
	
	/* check for attributes */
	if (typeof check_fields["attribute"][formid] != 'undefined')
	{
		check_fields["attribute"][formid].each(function(id)
		{
			type = id[0];
			elements = id[1];
			element = new Array();
			for (i=0;i<elements.length;i++)	element[i] = $(elements[i]);
			switch (type)
			{
				case 'equal':
				{
					/* checks elements on equal */
					for (i=0;i<element.length;i++)
					{
						x=i+1;
						if (typeof element[i] != 'undefined' && typeof element[x] != 'undefined')
						{
							if (element[i].value != element[x].value)
							{
								if (element[i].type == 'password') errormsg.push("Passwörter stimmen nicht überein");
								else errormsg.push(element[i].id + " != "+ element[x].id);
								element[i].style.backgroundColor = error_color;
								element[x].style.backgroundColor = error_color;
							}
							else
							{
								e1 = element[i];
								e2 = element[x];
								if (!in_array(e1,errorfields)) e1.style.backgroundColor = "";
								if (!in_array(e2,errorfields)) e2.style.backgroundColor = "";
							}
						}
					}
					break;
				}
			}
		});
	}
	/* end attribute checks */

	/* printing errors */
	if (errormsg.length>0)
	{
		notification = error_notification[formid];
		if (notification=="none") return false;
		msg = "Es sind folgende Fehler aufgetreten: \n";
		container = $(notification);
		if (typeof notification != 'undefined' && container && typeof container != 'undefined' && typeof container.innerHTML != 'undefined') 
		{
			msg = nl2br(msg);
			$(notification).innerHTML = msg+genHTMLErrorMessage(errormsg);
		}
		else alert(msg+genErrorMessage(errormsg));

		/* stop submit */
		return false;
	}
	/* continue submit */
	return true;
}

/**
 * build error messages from array 
 * 
 * @param arr
 * @return
 */
function genErrorMessage(arr)
{
	str = "";
	for(i=0;i<arr.length;i++)
	{
		str += (i+1) + ". " + arr[i] + "\n";
	}
	return str;
}

/**
 * build error message in html style
 * 
 * @param arr
 * @return
 */
function genHTMLErrorMessage(arr)
{
	str = "<ol>";
	for(i=0;i<arr.length;i++)
	{
		str += "<li>" + arr[i] + "</li>\n";
	}
	str += "</ol>";
	return str;
}

/**
 * checks if str is an integer
 * 
 * @param str
 * @return
 */
function form_isInt(str)
{
	return (parseInt(str) == str);
}

/**
 * checks if str is a float
 * 
 * @param str
 * @return
 */
function form_isFloat(str)
{
	str = str.replace(",", ".");
	return (form_isInt(str) || (parseFloat(str)==str));
}

/**
 * checks if str contains special characters
 * 
 * @param str
 * @return
 */
function form_hasSpecials(str)
{
	return !(str.match("^[a-zA-Z0-9]+$")==str);
}

/**
 * checks if str is an email
 * 
 * @param str
 * @return
 */
function form_isEmail(str)
{
	/* should work but could possibly be better */
	return (str.search(/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/) != -1);
}


/* some stuff for FormInputTextContainer */

/** 
 * limit container 
 */
textContainerLimit = new Array();

/** 
 * text Container autocomplete container 
 */
textContainerAutoComplete = new Array();

/**
 * sets maximum number of input texts in a dynamic text container
 * 
 * @param elementid
 * @param limit
 * @return
 */
function addTextContainerLimit(elementid, limit)
{
	textContainerLimit[elementid] = parseInt(limit);
}

/**
 * autocompletion for text container
 * 
 * @param elementid
 * @param url
 * @return
 */
function addTextContainerAutoComplete(elementid, url)
{
	textContainerAutoComplete[elementid] = url;
}


/**
 * adds an input text field to a FormInputTextContainer
 * 
 * @param elementid
 * @param input
 * @return
 */
function newTextContainerItem(elementid, input)
{
	textid = input.id;
	/* parse number of current input */
	num = parseInt(textid.substring((elementid.length+1)));
	newnum = num+1;

	/* stop if limit is reached */
	if (typeof textContainerLimit[elementid] != 'undefined' && textContainerLimit[elementid] <= newnum) return;

	newid = elementid+"_"+newnum;
	element = $(newid);
	/* if the next element doesnt exist */
	if (typeof element == 'undefined' || !element)
	{
		/* new element */
		newElement = document.createElement("tr");
		newElement.id = 'tr_'+newid;
		newElement.style.display = "none"; /* for Effect.Appear */
		$('tbody_'+elementid).appendChild(newElement); /* add new row to table */
		
		/* adding autocomplete extras if nessesary */
		if (typeof textContainerAutoComplete[elementid] != 'undefined') autocomplete_html = '<span id="indicator_'+newid+'" style="display: none"><img src="'+form_path+'indicator.gif" alt="Loading..." /></span><div id="autocomplete_choices_'+newid+'" class="autocomplete"></div>';
		else autocomplete_html = '';
		
		/* setting content of row */
		newElement.innerHTML = '<td><input type="'+input.type+'" id="'+newid+'" name="'+input.name+'" onkeyup="'+input.getAttribute('onKeyUp')+'" />'+autocomplete_html+'</td>';

		/* makes appear more sexy */
		Effect.Appear("tr_"+newid, {duration: 0.5});
		
		/* adding autocomplete handler  if nessesary */
		if (typeof textContainerAutoComplete[elementid] != 'undefined')	addAutoComplete(newid,textContainerAutoComplete[elementid]);
	}
}

/* some stuff for FormInputTextContainer */

/** 
 * limit container 
 */
selectContainerLimit = new Array();

/**
 * sets maximum number of input texts in a dynamic text container
 * 
 * @param elementid
 * @param limit
 * @return
 */
function addSelectContainerLimit(elementid, limit)
{
	selectContainerLimit[elementid] = parseInt(limit);
}

/**
 * adds an input text field to a FormInputTextContainer
 * 
 * @param elementid
 * @param input
 * @return
 */
function newSelectContainerItem(elementid, input)
{
	selectid = input.id;
	/* parse number of current input */
	num = parseInt(selectid.substring((elementid.length+1)));
	newnum = num+1;

	/* stop if limit is reached */
	if (typeof selectContainerLimit[elementid] != 'undefined' && selectContainerLimit[elementid] <= newnum) return;

	newid = elementid+"_"+newnum;
	element = $(newid);
	/* if the next element doesnt exist */
	if (typeof element == 'undefined' || !element)
	{
		/* new element */
		newElement = document.createElement("tr");
		newElement.id = 'tr_'+newid;
		newElement.style.display = "none"; /* for Effect.Appear */
		$('tbody_'+elementid).appendChild(newElement); /* add new row to table */

		opts = "";
		for (i=0;i<input.options.length;i++)
		{
			opts += '<option value="'+input.options[i].value+'">'+input.options[i].innerHTML+'</option>';
		}
		
		/* setting content of row */
		newElement.innerHTML = '<td><select id="'+newid+'" name="'+input.name+'" onchange="'+input.getAttribute('onChange')+'" />'+opts+'</select></td>';		
		
		/* makes appear more sexy */
		Effect.Appear("tr_"+newid, {duration: 0.5});
	}
}

/**
 *  file upload 
 *  
 */
upload_check = new Array();
uploadTimeout = new Array();

/**
 * clears upload timeout
 * 
 * @param id
 * @return
 */
function clearUploadTimeout(id)
{
	if (typeof uploadTimeout[id] != 'undefined') 
	{
		clearTimeout(uploadTimeout[id]);
	}
}

/**
 * adds a new upload
 * 
 * @param formid
 * @param id
 * @param path
 * @param filename
 * @param filetype
 * @param preview
 * @param imagesize
 * @param previewsize
 * @return
 */
function addUpload(formid,id,path,filename,filetype,preview,imagesize,previewsize)
{
	if (typeof upload_check[formid] == 'undefined')
	{
		upload_check[formid] = new Array();
	}
	upload_check[formid][id] = new Array(path,filename,filetype,preview,imagesize,previewsize);
}


/**
 * starts upload
 * 
 * @param formid
 * @param id
 * @return
 */
function startUpload(formid,id)
{
	clearUploadTimeout(id);
	/*
	if (typeof upload_check[id] == 'undefined') 
	{
		alert('Bug: startUpload() [FormGenerator.js]');
		return;
	}
*/	
	preview = upload_check[formid][id][3];
	if (preview == '') preview = 'preview_'+id;
	if(preview != 'none')
	{
		element = $(preview);
		if (typeof element != 'undefined') /* preview is an html_element */
		{
			element.innerHTML = '<img src="'+form_path+'indicator.gif" alt="Loading..." />';
		}		
	}
	uploadTimeout[id] = window.setTimeout("checkUpload('"+formid+"','"+id+"')", 1000);	
}

/**
 * debug function
 * 
 * @param obj
 * @return
 */
function var_dump(obj) {
   if(typeof obj == "object") {
      return "Type: "+typeof(obj)+((obj.constructor) ? "\nConstructor: "+obj.constructor : "")+"\nValue: " + obj;
   } else {
      return "Type: "+typeof(obj)+"\nValue: "+obj;
   }
}//end function var_dump
 
/**
 * check if file was successfully uploaded
 * 
 * @param formid
 * @param id
 * @return
 */
function checkUpload(formid,id)
{
	path = upload_check[formid][id][0];
	filename = upload_check[formid][id][1];
	filetype = upload_check[formid][id][2];
	preview = upload_check[formid][id][3];
	imagesize = upload_check[formid][id][4];
	previewsize = upload_check[formid][id][5];
	
	url = form_path + "upload.php?checkpath="+path+"&checkfile="+filename+"&imagesize="+imagesize;

	/* get image sizes from a serialized array */
	imagesize = unserialize(base64_decode(urldecode(imagesize)));
	i=0;
	imgsize = new Array();
	while (imagesize && typeof imagesize[i] != 'undefined') 
	{
		imgsize.push(imagesize[i]);
		i++;
	}

	/* getting file information */
	new Ajax.Request(url, {
		method: 'get',
		onSuccess: function(data)
		{
			data = data.responseText;
			if (data == "0") /* not found */
			{
				clearUploadTimeout(id);
				uploadTimeout[id] = window.setTimeout("checkUpload('"+id+"')", 1000);	
			}
			else if(data != "")
			{
				data = unserialize(data);
				d = new Array();
				i=0;
				while (typeof data[i] != 'undefined') 
				{
					d[i] = data[i];
					i++;
				}
				/* images are getting type: /path/to/image1.jpg;/path/to/image2.jpg */
				$(id).value = implode(";",d);
				if (preview == '')
				{
					/* putting preview in the default box */
					preview = 'preview_'+id;
				}
				if (preview != 'none')
				{
					element = $(preview);
					if (typeof element != 'undefined') /* preview is an html_element */
					{
						element.innerHTML = "";
						if (imgsize.length > 0 && filetype=='image')
						{

							for (i=0;i<imgsize.length;i++)
							{
								if (!previewsize || previewsize == imgsize[i]) element.innerHTML += '<img src="/'+path+imgsize[i]+"/"+filename+'?'+Math.floor(Math.random() * 9999)+'" alt="'+imgsize[i]+'" /> ';
							}

						}
						else if (filetype=='image') element.innerHTML = '<img src="'+data+'?'+Math.floor(Math.random() * 9999)+'" alt="" />';
						else element.innerHTML = 'Upload erfolgreich';
					}
				}				
			}
		}
	});
}

/**
 * append the result of the url to innerHTML of resultid
 * 
 * @param resultid
 * @param url
 * @param arg
 * @return
 */
function form_ajax_append(resultid,url,arg)
{
	if (typeof arg != 'undefined' && arg)
	{
		if (!strpos(url,'?')) url += '?0='+arg;
		else
		{
			i=0;
			pos = strpos(url,'?');
			while (strpos(url,'?'+i.toString()+'=',pos) || strpos(url,'&'+i.toString()+'=',pos)) i++
			url+='&'+i+'='+arg;
		}
	}
	new Ajax.Updater(resultid,url, {
		insertion: 'bottom',
		evalScripts: true
	});
}
