/**
 * P.I.C.S. JS Framework 5.0.0 - form extension
 * Copyright(c) 2009 P.I.C.S. EDV GmbH
 * http://www.pics.co.at
 * 
 * @author Ing. Christian Grösswang
 * 
 * 20100204,gc - v5.00.00		rework of pics.form v1.11
 * 20100506,gc - v5.00.01		changed pics.Form.save to new pics.json-return-format
 * 20100512,gc - v5.00.02		small bugfixes in ajax/json-routines
 */

/**
 * @class pics.Form
 * function for form-handling
 * @singleton
 */
pics.Form = {
    		version 	: '5.0.0'			//* @type String	version of the framework
    		,lastValue	: ''				//* @type String	last value
		};	// pics.ajax
			
		

	/**
	 * pics.Form.hasChanged()
	 *		check if the content of a form has changed
     * 		@param 	{Mixed} 	pElement 			element or ID of the Form
 	 *		@return	{Bool}		true if form has been changed
	 */
	pics.Form.hasChanged = function(pElement)
	{
		var oForm=pics.obj(pElement);
		if (!oForm) return false;
		// walk through the form elements
		for (var i=0;i<oForm.elements.length;i++)
		{
			var oElement=oForm.elements[i];
			// on select we have to check the options
			if (oElement.tagName=="SELECT")
			{
				for (var j=0;j<oElement.options.length;j++)
				{	
					var oOption=oElement.options[j];
					if (oOption.selected!=oOption.defaultSelected) return true;
				} // for options
			} // if select
			else
			{
				if ((oElement.value!=oElement.defaultValue) || (oElement.checked!=oElement.defaultChecked)) return true;
			} // else select
		} // for
		return false;
	}; // pics.Form.hasChanged


	/**
	 * pics.Form.fieldChanged()
	 *		check if the given field was changed
     * 		@param 	{Mixed} 	pField 			element 
 	 *		@return	{Bool}		true if form has been changed
	 */
	pics.Form.fieldChanged = function(pField)
	{
		var oElement=pField;
		// on select we have to check the options
		if (oElement.tagName=="SELECT")
		{
			for (var j=0;j<oElement.options.length;j++)
			{	
				var oOption=oElement.options[j];
				if (oOption.selected!=oOption.defaultSelected) return true;
			} // for options
		} // if select
		else
		{
			if ((oElement.value!=oElement.defaultValue) || (oElement.checked!=oElement.defaultChecked)) return true;
		} // else select
		return false;
	}; // pics.Form.fieldChanged


	/**
	 * pics.Form.markUnchanged()
	 *		set all values as default, so that the form looks like unchanged
     * 		@param 	{Mixed} 	pElement 			element or ID of the Form
 	 *		@return	{Bool}		true
	 */
	pics.Form.markUnchanged = function(pElement)
	{
		var oForm=pics.obj(pElement);
		if (!oForm) return false;
		// walk through the form elements
		for (var i=0;i<oForm.elements.length;i++)
		{
			var oElement=oForm.elements[i];
			// on select we have to check the options
			if (oElement.tagName=="SELECT")
			{
				for (var j=0;j<oElement.options.length;j++)
				{	
					var oOption=oElement.options[j];
					if (oOption.selected!=oOption.defaultSelected) 	oOption.defaultSelected=oOption.selected;
				} // for options
			} // if select
			else
			{
				if (oElement.value!=oElement.defaultValue) 		oElement.defaultValue=oElement.value;
				if (oElement.checked!=oElement.defaultChecked) 	oElement.defaultChecked=oElement.checked;
			} // else select
		} // for
		return true;
	}; // pics.Form.markUnchanged



	/**
	 * pics.Form.convert2Params()
	 *		create a param-string for GET/POST of the fields
     * 		@param 	{Mixed} 	pElement 			element or ID of the Form
     * 		@param 	{Bool} 		pChangedOnly		return only changed fields
 	 *		@return	{Bool}		true if form has been changed
	 */
	pics.Form.convert2Params = function(pElement, pChangedOnly)
	{
		if (pics.isUndefined(pChangedOnly))	pChangedOnly=false;
		
		var oForm=pics.obj(pElement);
		if (!oForm) return false;

		var lParams='';

		// walk through the form elements
		for (var i=0;i<oForm.elements.length;i++)
		{
			var oElement=oForm.elements[i];
			// only fields with a name set
			if (oElement.name!='')
			{
				switch(oElement.type)
				{
					case "select-one":			// on select we have to check the options
					case "select-multiple":
						for (var j=0;j<oElement.options.length;j++)
						{	
							var oOption=oElement.options[j];
							if ((oOption.selected!=oOption.defaultSelected)  || (pChangedOnly==false)) 
							{
								if (oOption.selected) lParams+="&"+oElement.name+"="+encodeURIComponent(oOption.value);
							}
						}
						break;
					case "checkbox":		// on checkboxes we have to fetch the checked-property
					case "radio":			// on radio-buttons we have to fetch the checked-property
						if ((oElement.value!=oElement.defaultValue) || (oElement.checked!=oElement.defaultChecked) || (pChangedOnly==false))
						{
							if (oElement.checked) lParams+="&"+oElement.name+"="+encodeURIComponent(oElement.value);
						}
						break;
					default:
						if ((oElement.value!=oElement.defaultValue) || (oElement.checked!=oElement.defaultChecked) || (pChangedOnly==false))
						{
							lParams+="&"+oElement.name+"="+encodeURIComponent(oElement.value);
						}
				}	//switch element-type
			} // if name
		} // for
		return lParams;
	}; // pics.Form.convert2Params


	/**
	 *	save the form via Ajax and return the result
	 *		@param	{Mixed}		pForm			id or element of the form with the data to POST
	 *		@param	{String}	pMsg			message to display in the save-box
	 *		@param	{String}	pUrl			url for the save-handler, if missing taken from the form.action
	 *		@param	{String}	pKey			name of the ID-Field like fAID
	 *		@param	{String}	pCallback		callback-function if successful
	 *		@return	
	 *	@return	
	 */
	pics.Form.save = function(pForm, pMsg, pUrl, pKey, pCallback) 
	{
		var oForm=pics.obj(pForm);
		if (!oForm) return false;
		if (pics.isUndefined(pMsg))			pMsg='loading, please wait ...';
		if (pics.isUndefined(pUrl))			pUrl=oForm.action;
		if (pics.isUndefined(pKey))			pKey='';
		if (pics.isUndefined(pCallback))	pCallback='';

		var lStatus=true;
		// check if form has changed
		if (pics.Form.hasChanged(oForm))
		{
			// show the info-message during prepare / save
			var oSaveInfo=pics.Windows.infoBox("winInfoSave");
			oSaveInfo.create(400,100,300,0,'speichern...','Datensatz wird gespeichert',true);
			// validate form
			oSaveInfo.setContent("Daten werden geprüft...");				
			// build the params to post
			lParams=pics.Form.convert2Params(pForm);
			// show saving
			oSaveInfo.setContent("Daten werden gespeichert...");				
			// and save
			var lResult=pics.Ajax.request_sync(pUrl, "POST", lParams);
			var oJson	=	pics.JSON.loadFinished(lResult, '', oForm);
			var lMsg	=	oJson.msg;
			var lStatus	= 	oJson.success;

			// if successfully saved, destroy the infobox
			if (lStatus==true) 
			{
				// hide the infobox
				oSaveInfo.destroy();
			}
			else // otherwise set the error-message of the request and add an OK button
			{
				// update the info-box
				oSaveInfo.setContent(lMsg);
				oSaveInfo.addButton("OK");
			}
		} // if (pics.Form.hasChanged('formAdressen'))
		else
		{
			// no save needed
			oSaveInfo=pics.Windows.msgBox('Daten wurden nicht geändert!', false, false, 1);
/*			
			oSaveInfo=pics.Windows.infoBox("winInfoSave");
			// ToDo - use res
			oSaveInfo.create(400,100,300,50,'Daten wurden nicht geändert!');
			window.setTimeout('oSaveInfo.hide()',1000);
*/
			lStatus=false;
		} // else
		return lStatus;
	}; // pics.Form.save
	

	/**
	 * pics.Form.savejson_v1()
	 *		save the form via Ajax and return the result
	 *		@param	{Mixed}		pForm			id or element of the form with the data to POST
	 *		@param	{String}	pMsg			message to display in the save-box
	 *		@param	{String}	pUrl			url for the save-handler, if missing taken from the form.action
	 *		@param	{String}	pKey			name of the ID-Field like fAID
	 *		@param	{String}	pCallback		callback-function if successful
	 *		@return	
	 *	@return	
	 */
	pics.Form.savejson_v1 = function(pForm, pMsg, pUrl, pKey, pCallback) 
	{
		var oForm=pics.obj(pForm);
		if (!oForm) return false;
		if (pics.isUndefined(pMsg))			pMsg='loading, please wait ...';
		if (pics.isUndefined(pUrl))			pUrl=oForm.action;
		if (pics.isUndefined(pKey))			pKey='';
		if (pics.isUndefined(pCallback))	pCallback='';

		var lStatus=true;
		// check if form has changed
		if (pics.Form.hasChanged(oForm))
		{
			// show the info-message during prepare / save
			var oSaveInfo=pics.Windows.infoBox("winInfoSave");
			oSaveInfo.create(400,100,300,0,'speichern...','Datensatz wird gespeichert',true);
			// dann validieren wir das Formular
			oSaveInfo.setContent("Daten werden geprüft...");				

			// build the params to post
			lParams=pics.Form.convert2Params(pForm);

			// show saving
			oSaveInfo.setContent("Daten werden gespeichert...");				

			// and save
			var lStatus=false;
			var lMsg='';
			var aJavascript=new Array();
			var lResult=pics.Ajax.request_sync(pUrl, "POST", lParams);
			try {
				var aReturn=pics.JSON.decode(lResult);
			} // try
			catch(e)
			{
				var aReturn=new Array();
				lMsg="<b>save error</b><br>"+e;
			}

			for (var lType in aReturn)
			{
				switch(lType)
				{
					case "success":				// check the success of the save
						lStatus=aReturn[lType];
						break;
					case "msg":					// return message
						lMsg=aReturn[lType];
						break;
					case "data":				// fields and values must be set 
						if (lStatus==true)
						{
							// walk through all the fields
							for (var lVar in aReturn[lType])
							{
								var lValue = aReturn[lType][lVar];
								// is it a single field or a array of fields
								if (pics.isArray(lValue))
								{
									// array => get the fields
									var aField=pics.findByName(oForm, lVar, false);
									for (var j=0;j<aFields.length;j++)
									{
										aFields[j].value=lValue[j];
									} // for
								} // if
								else
								{
									// single field - get the field
									var oField=pics.findByName(oForm, lVar, true);
									oField.value=lValue;
									// oForm.elements[lVar].value=lValue;
								} // else
							} // for
							
						}
						break;
					case "js":			// execute the javascript after loading, format is JS: command 
							aJavascript=aReturn[lType];
						break;
				} // switch
			} // for
			// update the info-box
			oSaveInfo.setContent(lMsg);
			if (lStatus==true) 
			{
				// execute the javascripts
				for (var i=0;i<aJavascript.length;i++)
				{
					eval(aJavascript[i]);
				}				
				// hide the infobox
				oSaveInfo.hide();
			}
			else
			{
				oSaveInfo.addButton("OK");
			}
		} // if (pics.Form.hasChanged('formAdressen'))
		else
		{
			// no save needed
			oSaveInfo=pics.Windows.infoBox("winInfoSave");
			// ToDo - use res
			oWin.create(400,100,300,50,'Daten wurden nicht geändert!');
			window.setTimeout('oSaveInfo.hide()',1000);
			lStatus=false;
		} // else
		return lStatus;
	}; // pics.Form.savejson_v1

	/**
	 * pics.Form.save_old()
	 *		save the form via Ajax and return the result
	 *		@param	{Mixed}		pForm			id or element of the form with the data to POST
	 *		@param	{String}	pMsg			message to display in the save-box
	 *		@param	{String}	pUrl			url for the save-handler, if missing taken from the form.action
	 *		@param	{String}	pKey			name of the ID-Field like fAID
	 *		@param	{String}	pCallback		callback-function if successful
	 *		@return	
	 *	@return	
	 */
	pics.Form.save_old = function(pForm, pMsg, pUrl, pKey, pCallback) 
	{
		var oForm=pics.obj(pForm);
		if (!oForm) return false;
		if (pics.isUndefined(pMsg))			pMsg='loading, please wait ...';
		if (pics.isUndefined(pUrl))			pUrl=oForm.action;
		if (pics.isUndefined(pKey))			pKey='';
		if (pics.isUndefined(pCallback))	pCallback='';

		var lStatus=true;
		// check if form has changed
		if (pics.Form.hasChanged(pForm))
		{
			// show the info-message during prepare / save
			var oSaveInfo=pics.Windows.infoBox("winInfoSave");
			oSaveInfo.create(400,100,300,0,'speichern...','Datensatz wird gespeichert',true);
			// dann validieren wir das Formular
			oSaveInfo.setContent("Daten werden geprüft...");				

			// build the params to post
			lParams=pics.Form.convert2Params(pForm);

			// show saving
			oSaveInfo.setContent("Daten werden gespeichert...");				

			// and save
			var lResult=pics.Ajax.request_sync(pUrl, "POST", lParams);
			// analyze the result
			var aLines=lResult.split('\n');
			var lStatus=false;
			var lMsg='';
			var lRecordID=0;
			var aJavascript=new Array();
			for (var i=0;i<aLines.length;i++)
			{
				aCols=aLines[i].split(":");
				switch(aCols[0])
				{
					case "SAVE":		// the return has the format SAVE:ID:Message and Message is OK or the description of the error
						if (aCols[2]=="OK")
						{
							lRecordID=aCols[1];
							// set the id if given
							if (pKey!='')
							{
								var oField=pics.o(pKey);
								oField.value=lRecordID;
							}
							lStatus=true;
						}
						else
						{
							lStatus=false;
							lMsg=aCols[2];
						}
						break;
					case "DATA":	// return data for a field-array, format is DATA:Field:ID1,ID2, ...
						if (lStatus==true)
						{
							// IDs aufsplitten und in die fAKID-Felder eintragen
							var aIDs=aCols[2].split(",");
							var aFields=document.getElementsByName(aCols[1]);
							// alle Elemente durchlaufen
							for (var j=0;j<aFields.length;j++)
							{
								aFields[j].value=aIDs[j];
							} // for
						}
						break;
					case "FIELD":		// return a value for a field, format is FIELD:Field:ID
						if (lStatus==true)
						{
							oForm.elements[aCols[1]].value=aCols[2];
						}
						break;
					case "INFO":		// return a message from the server, format is INFO:Message 
						lMsg+=aCols[1]+'<br />';
						break;
					case "JS":			// execute the javascript after loading, format is JS: command 
							aJavascript[aJavascript.length]=aCols[1];
						break;
				} // switch
			} // for
			// update the info-box
			oSaveInfo.setContent(lMsg);
			if (lStatus==true) 
			{
				// execute the javascripts
				for (var i=0;i<aJavascript.length;i++)
				{
					eval(aJavascript[i]);
				}				
				// hide the infobox
				oSaveInfo.hide();
			}
			else
			{
				oSaveInfo.addButton("OK");
			}
		} // if (pics.Form.hasChanged('formAdressen'))
		else
		{
			// no save needed
			oSaveInfo=pics.Windows.infoBox("winInfoSave");
			// ToDo - use res
			oWin.create(400,100,300,50,'Daten wurden nicht geändert!');
			window.setTimeout('oSaveInfo.hide()',1000);
			lStatus=false;
		} // else
		return lStatus;
	}; // pics.Form.save_old



/* 
 * ==================================================================================================================
 * 		functions for form rows
 * ==================================================================================================================
 */

	/**
	 * pics.Form.addFormRow()
	 *		search the hidden row with pID and duplicate the row
     * 		@param 	{Mixed} 	pElement 			element or ID of the Form
     * 		@param 	{String} 	pNewID				id for the new row
 	 *		@return	
	 *	@return	
	 */
	pics.Form.addFormRow = function(pElement, pNewID)
	{
		if (pics.isUndefined(pNewID))	pNewID='';

		var oElement=pics.obj(pElement);
		
		var oNew = oElement.cloneNode(true);				// duplicate
		oNew.id=pNewID;										// add the new id
		oNew.style.display="";								// show
		oElement.parentNode.insertBefore(oNew, oElement);	// insert before	
	}; // pics.Form.addFormRow

	/**
	 * pics.Form.addFormRowLimited()
	 *		search the hidden row with pID and duplicate the row, but only if there are not more than pLimit Fields
     * 		@param 	{Mixed} 	pElement 			element or ID of the Form
     * 		@param 	{String} 	pField				id for the field to check
     * 		@param 	{Int} 		pLimit 				max amount of fields
 	 *		@return	
	 *	@return	
	 */
	pics.Form.addFormRowLimited = function(pElement, pField, pLimit)
	{
		var oField=document.getElementByName(pField);		// get the element by fieldname
		if (oField.length<pLimit) 	pics.Form.addFormRow(pElement);
	}; // pics.Form.addFormRowLimited
	
	
	/**
	 * pics.Form.deleteFormRow()
	 *		remove the current form row
     * 		@param 	{Mixed} 	pElement 			element or ID of the Form
     * 		@param 	{String} 	pField				field with the primary key
     * 		@param 	{Mixed} 	pNewValue 			value vor the primary key, default is multiply -1
     * 		@param 	{Bool}	 	pConfirm			ask for delete
 	 *		@return	
	 *	@return	
	 */
	pics.Form.deleteFormRow = function(pElement, pField, pNewValue,pConfirm)
	{
		if (pics.isUndefined(pField))		pField='';
		if (pics.isUndefined(pNewValue))	pNewValue='--INVERT--';
		if (pics.isUndefined(pConfirm))		pConfirm=true;

		var oElement=pics.obj(pElement);
		
		// find the according row 
		var oRow=pics.findParent(pElement, "TR");

		// TODO: use ressource-string instead of fixed value
		if (pConfirm)
		{
			var lOldClass=oRow.className;
			oRow.className=lOldClass+' p-list-marked';
			var rc = confirm("Wollen Sie den Eintrag wirklich löschen?");
			// restore the old style
			oRow.className=lOldClass;
			if (rc==false) return false;
		}
	
		// hide the row
		oRow.style.display='none';
		// find the id-field and reset it
		if (pField!='')
		{
			var oField=pics.findByName(oRow, pField, true);
			if (pNewValue=='--INVERT--')
			{
				oField.value=-oField.value;
			}
			else
			{
				oField.value=pNewValue;
			}
		}
		return true;
	}; // pics.Form.deleteFormRow
		

	/**
	 * toggle visibility of a fieldset 
     * 		@param 	{Mixed} 	pElement 			element or ID of the Form
     *		@return	
	 */
	pics.Form.toggle = function(pElement)
	{
		var oFieldset=pics.findParent(pElement,"FIELDSET");
		if (pElement.className=='p-tb p-tb-collapse')
		{
			pElement.className='p-tb p-tb-expand';
			oFieldset.className='p-fieldset p-fieldset-collapsed';
		}
		else
		{
			pElement.className='p-tb p-tb-collapse';			
			oFieldset.className='p-fieldset';
		}
	}; // pics.Form.toggle
	

/* 
 * ==================================================================================================================
 * 		functions for comboboxes
 * ==================================================================================================================
 */

	/**
	 * pics.Form.clearCombo()
	 *		clear all entries from a combobox
     * 		@param 	{Mixed} 	pElement 			element or ID of the Combobox
 	 *		@return	
	 *	@return	
	 */
	pics.Form.clearCombo = function(pElement)
	{
		var oElement=pics.obj(pElement);
		oElement.length=0;
	}; // pics.Form.clearCombo

	/**
	 * pics.Form.add2Combo(pElement, pValue, pText)
	 *		add an entry to the combobox
     * 		@param 	{Mixed} 	pElement 			element or ID of the Form
     * 		@param 	{Mixed} 	pValue				value for the entry
     * 		@param 	{String} 	pText 				text for the entry
 	 *		@return	
	 *	@return	
	 */
	pics.Form.add2Combo = function(pElement, pValue, pText)
	{
		var oElement=pics.obj(pElement);

		var lEntry = new Option(pText, pValue); 
		oElement.options[oElement.length] = lEntry; 
	}; // pics.Form.add2Combo
			
	
