/**
 * => fieldChecker object: used for input validation
 * => va.processKeyup(): 			if a field is editted again remove the warnings/messages immediately:
 * => va.createFieldChecker(): 	function used for creating a fieldChecker obj in one statement
 * => va.checkFormFields() : 		validates and checks all required fields when form is submitted and shows warnings
 * other checks:
 * => copies a mandatory-gif to all fields with class required
 * => accept only numeric input in input fields with class 'number'
 * => day, month, year checker for input fields with class 'day', 'month' or 'year' 
 * 
 * uses: 	genjs.js		=> some js array and string object extension functions
 * 			jquery-1.3.2.js
 * example of html:
           <span class="field">
               <input id="txtPagina1" name="txtPagina1" type="text" />
               <span class="popup">Tijdens installatie....</span>
               <span class="field-err-text">Wachtwoord moet minimaal 8 tekens bevatten!</span> 
           </span>
 */

var va = va || {};                 // VAita namespace 
va.errorFields = {};

va.addHoverOnButton = function($btn) {
     $btn.hover(
      function() { $btn.addClass('ui-state-hover'); }, 
      function() { $btn.removeClass('ui-state-hover'); }
   );      
};

// geen naamspace va.FieldChecker = .. omdat dan Aptana intellisense niet werkt.
var FieldChecker = function($field) {
   this.$field = $field;
   this.value = $field.val();
   this.resultSpanID = this.$field.attr('id') + 'Result';
   this.$div = this.$field.closest('div');     						// gets the closest ancestor div. This is: <div class="input-line">
   this.$label = this.$div.find('label'); 
   this.okText = this.$div.find('.field-ok-text').text();		//eg: <span class="field-ok-text">deze gebruikersnaam is ok</span>
   this.errText = this.$div.find('.field-err-text').text(); 	//eg: <span class="field-err-text">gebruikersnaam moet minimaal 5 en maximaal 25 karakters zijn</span>
   /**
    * adds a SPAN that shows checkresults to the end of the surrounding DIV.
    * @param {bool} forSuccess
    */
   this.addResultSpan = function(forSuccess){
      this.clearResults();                                  // remove the Result span and label color if it is already present      
      this.$div.find('.field-explanation').remove();   		// remove the Explanation span if there is any
      this.$resultSpan = $('<span></span>')
            .addClass('field-result')
            .attr('id', this.resultSpanID);
      this.$div.find('.field').append(this.$resultSpan);     // insert the resultspan at the end of the <span class='field'>..</span> tag
      if (arguments.length > 0) {                           // Do Not Mark: only add span but don't mark it for success or failure
         this.updateResultSpan({success: forSuccess});
      };
   };   
   this.updateResultSpan = function(params) {
      if (params.success === true ) {
         this.$resultSpan.addClass("check-success");
         if (this.okText !== '') {
            this.$resultSpan.html(this.okText);
         };
      } else {
         this.$resultSpan.addClass("check-failure");
         this.$resultSpan.html(this.errText);
      };
      this.setErrorField(params.success);                  
      this.setLabelResult(params.success);
      if (params.afterAjaxCall) {
         this.$resultSpan.unbind();
      };
   };   
   this.clearResults = function() {
      this.removeResultSpan();                              // remove the Result span if it is already present
      this.setLabelResult(true);                            // also remove the labelresult if it was set
      this.$field.removeClass('inputRequired');             // form submit() added class 'inputRequired' to all empty fields
   };
   this.clearTexts = function() {
      this.errText = '';
      this.okText = '';
   };
   this.removeResultSpan = function() {
      $('#' + this.resultSpanID).remove();         
   };
   this.setLabelResult = function(success) {
      if (success) {
         this.$label.removeClass('check-failure');
      } else {
         this.$label.addClass("check-failure");   
      };
   };
   /**
    * accepts a string with a javascript check, evaluates it and adds a resultspan that shows the resulttext.
    * The resulttext (errText or okText) has to be set prior to calling this method.
    * The javascript string has to use the 'val' param for the field value!
    * @param {string} evalIsError
    */
   this.checkField = function(evalIsError) {
      var val = this.value;
      var hasError = eval(evalIsError);
      this.setFieldCheckResult(!hasError);
      return !hasError;
   };
   /**
    * add's a resultspan after a fieldcheck. Text to display (errText or okText) has to be set
    * before this method is called
    * @param {bool} isOk
    */
   this.setFieldCheckResult = function(isOk) {
      if (!isOk) {
         this.addResultSpan(false);            
      } else {
         if (this.okText !== '') {
            this.addResultSpan(true);
         } else {
				this.removeResultSpan();
            this.setErrorField(true);
         };
      };
   };
   /**
    * adds the JQuery .ajaxStart() to the resultSpan and displays the text 'aan het laden'
    */
   this.setAJAXfeedback = function() {
      this.clearTexts();
      if (typeof this.$resultSpan === "undefined") {
         this.addResultSpan();
      };
      this.$resultSpan.ajaxStart(function(){
          $(this).text('aan het laden...');
      });
   };
   this.setErrorField = function(success) {
      va.errorFields[this.$label.text()] = (success) ? 'ok' : 'err' ;
   };
   /** 
    * accepts the PHP Ajax return value and updates the resultSpan with the result
    * @param {JSON Object} returnData JSON contains params 'result': true or false; 'resultText': optional text returned from PHP
    */
   this.ajaxCallback = function(returnData){
      var res;
      if (returnData['result']) {
         res = true;
         if (returnData['resultText']) {
            this.okText = returnData['resultText'];
         };
      } else {
         res = false;
			if (returnData['resultText']) {
         	this.errText = returnData['resultText'];
			};
      };
      this.updateResultSpan( {success: res, afterAjaxCall: true} );
   };
}; //end FieldChecker

// if a field is editted again remove the warnings/messages immediately:
va.processKeyup = function() {
   var fc = new FieldChecker($(this));
   fc.clearResults();
   fc.clearTexts();
   $(this).unbind('keyup');       // unbind the keyup eventhandler so that the keyup event only fires once after it has been changed
   // console.log('processkeyup runs for ' + this.name);
};
   
va.createFieldChecker = function($field, evalIsError, errTxt) {
   var fc = new FieldChecker($field);
	// first look if an errortext has been defined in the html. If not it can be passed to this function
	if ($field.next().hasClass('field-err-text')) {
		fc.errText = $field.next().text();
	} else {
		if (typeof errTxt !== "undefined" ) fc.errText = errTxt;
	}   
   fc.checkField(evalIsError);
};

va.checkSecondPasswordField = function(pswFieldName, showOK) {
   var psw2Field = pswFieldName + "2";
   fc = new FieldChecker($('#' + psw2Field));
   var psw1 = $('#' + pswFieldName).val();
   var psw2 = $('#' + psw2Field).val();
   if ( psw1 !== psw2 ) {
      fc.errText = "beiden wachtwoorden komen niet overeen!";
      fc.setFieldCheckResult(false);
   } else {
      if (showOK) {
         fc.okText = "OK, beide wachtwoorden zijn hetzelfde";
      }
      fc.setFieldCheckResult(true);
   };      
};
          
/**
 * show warning messages if the form is submitted for: 
 * - required fields that are empty
 * - fields with incorrect values. For an incorrect field the va.errorFields['labeltext'] == 'err'
 * 
 * @param	context	-> contextdiv that contains all fields to check 	
 * #param	texts		-> textstrings to show to the user = map :  {requiredFields : 'txt'}  
 * precondition: form is submitted by a click on a tag with class 'submitBtn'
 * 
 * gebruik voorbeeld:
   $('#frmRegister').submit(function(){
      if (va.checkFormFields($('#inputFormBlock'), {requiredFields : "u heeft nog geen domeinnaam ingevuld!"} ) === false) {
         return false;   // do not submit the form
      };
   });   
   aanroep kan ook zonder texts, in dit geval worden de default texts gebruikt:
   va.checkFormFields.call(this); => werkt niet meer! gebruik nu:
   if (va.checkFormFields($('#inputFormBlock')) === false)    #inputFormBlock is hier een div (met class='form-block')
   
   aanroep kan ook voor een willekeurige div met velden dus het hoeft geen form te zijn
   if (va.checkFormFields.call($(this).parent().get()) === false) {   // parent =  partsContainer
 */ 
//va.checkFormFields = function(texts){
va.checkFormFields = function(context, texts){

	if (typeof context === 'undefined') {
		context = this;
	};
	
   $('#submit-message').remove();                                          // if a submit message is still shown remove it
   var emptyFields = [];
   // Kijk voor alle verplichte velden (class = 'required') of deze gevuld zijn.
	// kijk voor radio btns of er ten minste een CHECKED is.
	// get the parent <div class='input-line'> of each <span class='required'>
   $('.required', context).parent().each(function(){									// this refers to the FORM, zie aanroep via va.checkFormFields.call(this,..)
   
	   var $label = $('label:first', this);                                 // get the Jlabel. the radio buttons also have labels so makes sure to get the first label
      var labelText = $label.text(); 
      if ($(':input:radio', this).length > 0) {                              // if there are any radio inputs
         if ($('input:checked', this).length == 0 ) {                        // if no radio button is selected
            $label.addClass('check-failure');
            emptyFields.pushUnique(labelText);               
         };
      };
		
		$('select', this).each(function() {                        //a value has to be chosen in a select box 
         if ($(this).val() === null || $(this).val() === '-') {
            $label.addClass('check-failure');
            emptyFields.pushUnique(labelText);
         };            
      }); 
      
		$(':input:not(:radio, select, button)', this ).each(function (){     // input line can have more input fields eg. geboortedatum
         if ($(this).val() == "") {
            //addResultSpan.call(this, false).text("verplicht veld!");
            $label.addClass('check-failure');
            $(this).addClass('inputRequired');                              // class inputRequired gives the empty field another backgroundcolor and border
            emptyFields.pushUnique(labelText);
         };            
      }); 
   });
	
   // array errorFields[] is gevuld door FieldChecker aanroepen. Iedere aanroep bewaard zijn status ('ok' of 'err')
	// in een errorFields array element waarvan de key gevormd wordt door de label text van het betreffende veld.
	// show messages for all empty fields and for all fields that are not filled out correctly (va.errorFields[] === 'err')
   var arrErrors = []; msgErrFields = ''; msgEmptyFields = '';
	
	//-- define default texts. Possibly texts is not passed or not all texts are filled out
	var texts = texts || {};	
	if (typeof texts.correctErrors === 'undefined') texts.correctErrors = "Corrigeer aub de onjuiste invoer in de volgende %s velden";
	if (typeof texts.correctError === 'undefined') texts.correctError = "Corrigeer aub de onjuiste invoer in het veld '%s' ";
	if (typeof texts.requiredFields === 'undefined') texts.requiredFields = "Vul aub de volgende %s verplichte velden in";
	if (typeof texts.requiredField === 'undefined') texts.requiredField = "Vul aub het verplichte veld '%s' in";
	//--
	
   for (var lt in va.errorFields) {                                    // lt = label.text() used as key in errorfields obj
      if (va.errorFields[lt] === 'err') {
         arrErrors.push(lt);
      };
   };
   if (arrErrors.length > 0) {
		if (arrErrors.length == 1) {
         msgErrFields = texts.correctError.insertParam(arrErrors[0]) + "<br />"; 
      }  else {
         msgErrFields = texts.correctErrors.insertParam(arrErrors.length) + ":<br />";
         msgErrFields += "&bull; " + arrErrors.join('<br />&bull; ') + "<br />";
      }
   };
   if (emptyFields.length > 0 ) {
      if (emptyFields.length == 1) {
         msgEmptyFields = texts.requiredField.insertParam(emptyFields[0]) + "<br />"; 
      }  else {
         msgEmptyFields = texts.requiredFields.insertParam(emptyFields.length) + ":<br />";
         msgEmptyFields += "&bull; " + emptyFields.join('<br />&bull; ') + "<br />";
      }
   };
   if (msgEmptyFields || msgErrFields) {
		va.showSubmitErrortext.call(this, msgEmptyFields + msgErrFields);
      return false; 
   };
	
	// everything is ok so make sure to remove all previously displayed error indicator colors:
	$('.check-failure').removeClass('check-failure');
	$('.inputRequired').removeClass('inputRequired');
	return true;
}; //end checkFormFields

/** show error text before the submit button
 * needs submitbutton with class='submitBtn'!
 * 
 * usage: va.showSubmitErrortext.call(this, "vul aub saldo in")   => this refers to the form  
 */
va.showSubmitErrortext = function(text) {
	var $errDiv =  $('<div></div>')
	   .attr('id', 'submit-message')
		.addClass('check-failure')
	   .append(text);
	$('.submitBtn', this).before($errDiv);
}

/* indien een custom fieldcheck is uitgevoerd kan het resultaat getoond worden met showFieldError.
 * 
 * gebruik: test...;
 * 			if (msg.length > 2) {
					va.showFieldError($(this), msg);
				}; 
 * 
 */
va.showFieldError = function($field, errTxt) {
	 var fc = new FieldChecker($field);
	 fc.errText = errTxt;
	 fc.setFieldCheckResult(false);
};


$(document).ready(function() {
	va.setupDefaultInputValidation();
}); //end document.ready

va.setupDefaultInputValidation = function() {	
	// this normally runs when called by $(document).ready(). However this logic in separate function because we have to call 
	// this function when new HTML tabcontents has been loaded by AJAX. $(document).ready() doesn't fire when a tab is loaded, but 
	// only when the hosting page is loaded. 
   
	/** alle inputs met class = required krijgen het mandatory-gifje geplaats achter de labeltext
   * 
   * requires: <img> tag naar het gifje. Deze komt in de pagina onder de velden om de betekenis van het sterretje aan te geven:  
   * <div class="input-block">
   * <p><img id="mandatory-gif" src="../images/mandatory.gif" alt="sterretje voor verplicht veld"/>&nbsp;= Deze velden zijn verplicht.</p>
   * </div>
   */
   var $gifje = $('#mandatory-gif');
   $('.required label').each(function() { 
      $(this).after($gifje.clone());
   });
   
	// alle ok en error texten gebruikt in validatie hiden:
	$('.field-ok-text').hide();		
	$('.field-err-text').hide();
	
   // voor alle numerieke inputs met class = validate-number (=$('input.validate-number')) alleen cijfers als input accepteren:
   $('input.validate-number').keypress(function(event){
      if (event.charCode && !((event.charCode >= 48 && event.charCode <= 57) || event.charCode == 44)) {  	// also allow comma (=44) 	
         event.preventDefault();
      };
   });

  // voor alle numerieke inputs met class = validate-number (=$('input.validate-number')) alleen cijfers als input accepteren:
   $('input.validate-time').keypress(function(event){
      if (event.charCode && !((event.charCode >= 48 && event.charCode <= 57) || event.charCode == 58)) {  	// also allow : (=58) 	
         event.preventDefault();
      };
   });
      
   /** input validation for days, months and years  
    *  error texts can be passed in the html with a <span class="field-err-text"> tag. If not the default message from the validate functions is used
    */
   $('input.validate-day').change(function(){
      var isError = "val && (val < 1 || val > 31)";
      va.createFieldChecker($(this), isError, 'vul aub een geldige dag in');
   });
   $('input.validate-month').change(function(){
      var isError = "val && (val < 1 || val > 12)";
      va.createFieldChecker($(this), isError, 'vul aub een geldige maand in');      
   });
   $('input.validate-year').change(function(){
      var isError = "val && (val < 1900 || val > 2020)";
      va.createFieldChecker($(this), isError, 'vul aub een geldig jaar in');
   });
   // end input validation day/month/year
         
   // bind the keyup event to an input field only when the contents has changed. In this way the keyup fires only once after 
   // field has been edited
   $('form :input').change(function(){
      $(this).keyup(function(){ 
         va.processKeyup.call(this); 
      });
   });
	$(':radio, select').click(function(){
		va.processKeyup.call(this);
	});
	
	/** input validation for email fields */	
   $('.validate-email').change(function() {
      var email = $(this).val();
      var fc = new FieldChecker($(this));
		// add errortext if it is not defined in the html in a <span class="field-err-text"> tag.
		if (fc.errText == '') fc.errText = "onjuist email adres. Mogelijke syntax: jan.devries@comp-it.co.uk";
      // gek genoeg levert deze regexp in safari een probleem op met de 4 in: fred.edith@xs4all.nl 
		// var result = (/^\w+[\.-]?\w+@[a-zA-Z_-]+?(\.[a-zA-Z]{2,6}){1,2}$/.test(email));
		var result = (/^\w+[\.-]?\w+@(\w|\d|-)+?(\.[a-zA-Z]{2,6}){1,2}$/.test(email));
      fc.setFieldCheckResult(result);               // geen fc.checkField maar custom check dus nu setFieldCheckResult zelf aanroepen
   });

/** gebuik voorbeeld: validatie van een username invoer veld:

   $('#txtUserName').change(function() {
      var evalIsError = "val.length < 5 || val.length > 25";
      var fc = new FieldChecker($(this));
      fc.errText = "gebruikersnaam moet minimaal 5 en maximaal 25 karakters zijn";
      if (fc.checkField(evalIsError)) {
         // field input is OK, so now check if the username is unique in the database via AJAX
         fc.setAJAXfeedback();
         
         fc.okText = "OK, deze gebruikersnaam bestaat nog niet";
         // do the ajax call. the FieldChecker has a callBack function to process the result
         $.getJSON('register.php', {'un': fc.value}, function(data){
            fc.ajaxCallback(data);
         });
      }
   });
*/   
} // end setupDefaultInputValidation
