//
// Some usefull ECMA(Java)script function for AWE2 applications.
//
// Mostly form-validation.
//
// Validation is accomplished by setting certain class-names on the form elements.
//
// The name 'required-field' indicates that the field is required and
// that on submit of the form a check should be made to ensure that
// the field is filled.  The check is either the default (not blank)
// or a field-specific function if such exists. The field-specific
// function has the name 'required_<fieldname>' and is called with the
// field as argument.
//
// Field validation is done for each class-name in the form
// 'valid-<test>' where a function by hte name 'valid_<test>'
// exists. The function is called with the field as argument.
//
// Also events can be added to fields by setting classes in the form
// '<event>-<handler>' on the form-element. This results in adding a
// call to the method '<event>_<handler>' to the onEvent of the
// form-element - if the function exists. Also a check is made on the
// existence of function with names '<event>_<fieldname>'. If found
// then these are added to the eventhandler for the field.


// Add to (or set) window.onload functions.
// Taken from Dom Scripting.
//
// The new function is executed last.
function addLoadEvent(func) {
	$().ready(func);
}


// Add an onSubmit eventhandler to a form.
//
// The newest handler is executed first, execution stops when a
// handler doesn't return true.         (this parenthetic remark to get VIM's syntax coloring back in sync)
function addSubmit(thisform, func) {
//   alert("addSubmit("+thisform.name+"):"+func.toString());
  $(thisform).submit(func);
}

// Add an event to an object. 
//
// The new event is executed first.  If it returns false then
// execution of the eventqueue is stopped.  else the execution
// continues with the previous eventhandler if any.
function addEvent(event, element, func) {
	$(element)[event](func);
}

// AWE2.Object - constructor.
function AWE2() {}

// Discover whether the method exists.
//
// Returns the method if found (after normalising the methodname, so
// that alle non-alphanumeric characters are replaced by underscores
// ('_')) or null.
AWE2.prototype.can=function(methodName) {
  var method =methodName.replace(/[^a-zA-Z0-9_]+/g, "_");
  var prop = this[method];
  if (prop && typeof(prop) == 'function') return method;
  return null;
}

// Normalise a fieldname
//
// Field names can contain a serialnumber as a suffix (in the form
// ':\d+') if found then the suffix is removed. After that the field
// name is normalised, ie any nonalphanumeric character is replaced by
// an underscore ('_').
AWE2.prototype.fieldName=function(name) {
  var fieldname=name;
  if (fieldname && fieldname.match(":[0-9]+$")) {
	var reg=fieldname.match("^(.*):[0-9]+$");
	fieldname=reg[1];
  }
  if (fieldname)
    fieldname=fieldname.replace(/[^a-zA-Z0-9_]+/g, "_");
  return fieldname;
}

// Add validation to a page.
//
// Should be called as part of the onLoad handler.
//
// Adds a call to the AWE2.validate method on submit for every form.
// All form elements are checked to see if they should have event
// handlers added as described above.

function addSubmitClosure(form) {
	addSubmit(form, function() { return AWE2.validate(form) });
}

AWE2.prototype.addValidation=function() {
  var events = Array("click", "change", "keypress", "focus", "blur");
  for (var i=0; i<document.forms.length; i++) {
	var thisform = document.forms[i];
	addSubmitClosure(thisform);
//	addSubmit(thisform, function(myform) { return AWE2.validate(myform) });
	for (var j=0; j<thisform.elements.length; j++) {
	  var element=thisform.elements[j];
      if (element.className.indexOf("title-as-default") != -1) {
        AWE2.titleField(element);
      }
	  var name=AWE2.fieldName(element.name);
	  for (var k=0; k<events.length; k++) {
	    var event=events[k];
	    var method=AWE2.can(event+"-"+name);
	    if (method) {
	      var elem=element;
	      var meth=method;
	      addEvent(event, element, AWE2[meth]);
	    }
	    AWE2.addCheck(event, element);
	  }
	}
  }
}

// Part of AWE2.addValidation
// Checks for eventhandlers in classNames.
AWE2.prototype.addCheck=function(event, element) {
  var last=0;
  var start=-1;
  while ((start=element.className.indexOf(event+"-", last)) != -1) {
	var last=element.className.indexOf(" ", start);
	if (last == -1) last=element.className.length;
	var methodname=element.className.substring(start, last);
	var method=AWE2.can(methodname);
	if (method) {
	  addEvent(event, element, AWE2[method]);
	}
  }
}

// Validates a form on submit
//
// Added by addValidation
// 
// Checks for required fields and calls 'requireField' to check
// whether the field is filled, for all required fields.
// Then checks for 'valid-<test>' classNames and executes the
// corresponding method (if found). A corresponding check is made for
// 'valid-<fieldname>' methods.
AWE2.prototype.validate=function(thisform) {
  if (thisform.target) thisform=thisform.target;
 // alert("validate("+thisform.name+")");
  var ok=true;

  var preValidate=AWE2.can('preValidate_'+thisform.id) ||
    AWE2.can('preValidate_'+thisform.name) ||
    AWE2.can('preValidate');
  if (preValidate) ok=AWE2[preValidate](ok, thisform);

  for (var i=0; i<thisform.elements.length; i++) {
	var element = thisform.elements[i];
	if (element.className.indexOf("title-as-default") != -1) {
      element.value = '';
	}

	if (element.className.indexOf("required-field") != -1) {
	  var noError=AWE2.requireField(element);
	  //	  alert("required="+noError);
	  if(!noError) {
	    AWE2.errorField(ok, element);
	    ok = false;
	  }
	}
	var last=0;
	var start=-1;
	while ((start=element.className.indexOf("valid-", last)) != -1) {
	  var last=element.className.indexOf(" ", start);
	  if (last == -1) last=element.className.length;
	  var methodname=element.className.substring(start, last);
	  var method=AWE2.can(methodname);
	  if (method) {
		// alert("validate.valid("+element.name+","+element.id+"):"+method);
	    if (!AWE2[method](element,thisform)) {
		  this.errorField(ok, element);
		  ok = false;
	    }
	  }
	}
	if (element.className.indexOf("title-as-default") != -1) {
      element.value = element.title;
	}
  }
  var postValidate=AWE2.can('postValidate_'+thisform.id) ||
    AWE2.can('postValidate_'+thisform.name) ||
    AWE2.can('postValidate');
  if (postValidate) ok=AWE2[postValidate](ok, thisform);
  return ok;
}

// Marks a form element as an error
//
// If first is true, the field is given focus: Focus at first error-field.
// The field has added the className 'invalid' and any other class
// given in the argument 'classes'. An onChange-handler is added to
// remove the error-classes after change of the field.
AWE2.prototype.errorField=function(first, element, classes) {
  if (first) element.focus();
  var addclass=" invalid";
  if (classes) addclass += " "+classes;
  element.className += addclass;
  var regex=new RegExp(addclass, "g");
  var oldonkeypress=element.onkeypress;
  var oldonchange=element.onchange;
  element.onkeypress = function() {
    element.className = element.className.replace(regex, '');
	element.onchange = oldonchange;
	element.onkeypress = oldonkeypress;
	if (oldonkeypress) return oldonkeypress();
	return true;
  };
  element.onchange = function() {
    element.className = element.className.replace(regex, '');
	element.onchange = oldonchange;
	element.onkeypress = oldonkeypress;
	if (oldonchange) return oldonchange();
	return true;
  }
}

// Set the title-attribute-value as a labelvalue for the element.
// The titlevalue is removed when the user touches the element
AWE2.prototype.titleField=function(element) {
  element.value = element.title;
  var oldonfocus=element.onfocus;
  element.onfocus = function() {
	element.value='';
    element.className = element.className.replace(/title-as-default/g, '');
	element.onfocus = oldonfocus;
	if (oldonfocus) return oldonfocus();
	return true;
  };
}

// Checks if a required field is filled with data.
//
// if a method called 'required_<fieldname>' exists then that is
// called, else it is checked that the field has some content.
AWE2.prototype.requireField=function(field) {
  var fieldname=this.fieldName(field.name);
  var method = this.can("required_"+fieldname);
  if (method) return AWE2[method](field);
  if (field.value && field.value != '') return true;
  return false;
}

// Sundry validations
//
AWE2.prototype.pattern_check = function(field, pattern) {
  if (field.value) {
	if (field.value.match(/\n/)) {
		var lines=field.value.split(/\r?\n\r?/);
		for (var i=0; i<lines.length; i++) {
			if (!pattern.test(lines[i])) return false;
		}
		return true;
	} else return (pattern.test(field.value));
  } else {
	return true;
  }
}

AWE2.prototype.valid_email = function(field) {
  var pattern = /^[^ \r\t\n\f]+@[\d\w\._\-]+\.[\d\w\._]+$/;
  return AWE2.pattern_check(field, pattern);
}

AWE2.prototype.valid_int = function(field) {
  var pattern = /^[+-]?\d+$/;
  return AWE2.pattern_check(field, pattern);
}

AWE2.prototype.valid_price = function(field) {
  var pattern = /^[+-]?[\d.]+(?:\,\d+)?$/;
  return AWE2.pattern_check(field, pattern);
}

AWE2.prototype.change_price = function(e) {
  var field;
  if (window.event) field=window.event.srcElement;
  else if (e) field=e.target;
  else return true;
  if (field.value != '') field.value = AWE2.nicePrice(AWE2.deNicePrice(field.value));
  return true;
}

AWE2.prototype.keypress_int = function(e) {
  var key;
  if (window.event) key = window.event.keyCode;
  else if (e) key = e.which;
  else return true;

  if ((key==null) || (key==0) || (key==8) || (key==9) || (key==13) || (key==27) ) return true;
  var ch=String.fromCharCode(key);
  if ("+-0123456789".indexOf(String.fromCharCode(key)) >= 0) return true;

  if (window.event) window.event.returnValue = false;
  return false;
}

AWE2.prototype.keypress_price = function(e) {
  var key;
  if (window.event) key = window.event.keyCode;
  else if (e) key = e.which;
  else return true;

  if ((key==null) || (key==0) || (key==8) || (key==9) || (key==13) || (key==27) ) return true;
  var ch=String.fromCharCode(key);
  if ("+-.,0123456789".indexOf(String.fromCharCode(key)) >= 0) return true;

  if (window.event) window.event.returnValue = false;
  return false;
}

// Utility functions to handle numbers
AWE2.prototype.nicePriceDigits=2; // A reasonable default...
AWE2.prototype.nicePrice=function(p, d) {
  var dig=d;
  if (!dig) dig=AWE2.nicePriceDigits;
  var pr=Math.round(Number(p)*Math.pow(10,dig))/Math.pow(10,dig);
  var nice=pr.toFixed(dig).replace(/\./,",");
  while (nice!=(pr=nice.replace(/(\d)(\d\d\d)([^\d]|,)/,"$1.$2$3"))) nice=pr;
  return nice;
}

AWE2.prototype.deNicePrice=function(val) {
  var v=val.replace(/\./g, "");
  v=v.replace(/,/,".");
  v=v.replace(/,/g, "");
  return Number(v);
}

AWE2.prototype.addNicePrice=function(n1, n2) {
  var p1=this.deNicePrice(n1);
  var p2=this.deNicePrice(n2);
  var sum=p1+p2;
  return this.nicePrice(sum);
}

AWE2.prototype.subNicePrice=function(n1, n2) {
  var p1=this.deNicePrice(n1);
  var p2=this.deNicePrice(n2);
  var dif=p1-p2;
  return this.nicePrice(dif);
}

// Instantiate the object and start everything...
AWE2=new AWE2();
AWE2.nicePriceDigits=2; // A reasonable default...
addLoadEvent(AWE2.addValidation);

