// Per compatibilità con MSIE...
if ('undefined' == typeof Node)
    Node = { ELEMENT_NODE: 1, TEXT_NODE: 3 };

MSG_BLANK = ' è vuoto.';
MSG_NOT_A_DATE = ' non è una data.';
MSG_NOT_A_DOUBLE = ' non è un numero.';
MSG_NOT_AN_INTEGER = ' non è un numero intero.';
MSG_NOT_AN_EMAIL = ' non è una email valida.';
MSG_TOO_LOW = ' è troppo piccolo.';
MSG_TOO_HIGH = ' è troppo grande.';
MSG_PRIVACY = 'Devi accettare le condizioni';

REGEX_AUTO_FIELD = /^[^_]+(_Req)?(_(Int|Dbl|Date|Email)(_[0-9.]+){0,2})?$/;
REGEX_BLANK = /^\s*$/;
REGEX_DAY = /^(0?[1-9]|[1-2][0-9]|3[01])$/;
REGEX_MONTH = /^(0?[1-9]|1[0-2])$/;
REGEX_EMAIL = /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/;
REGEX_TYPED_FIELD = /_(Int|Dbl|Date|Email)(_([0-9.]+))?(_([0-9.]+))?$/;
REGEX_YEAR = /^[0-9]{2,4}$/;

function addListener(element, baseName, handler) {
    if (element.addEventListener)
        element.addEventListener(baseName, handler, false);
    else if (element.attachEvent)
        element.attachEvent('on' + baseName, handler);
} // addListener

function delListener(element, baseName, handler) {
    if (element.removeEventListener)
        element.removeEventListener(baseName, handler, false);
    else if (element.detachEvent)
        element.detachEvent('on' + baseName, handler);     
} // delListener

function addFormChecks() {
    var forms = document.forms;
    
    for (var index = 0; index < forms.length; ++index) {
        var form = forms.item(index);
        addListener(form, 'submit', checkForm);
        
        // aggiunge i listeners per le etichette fantasma
        for (var idx = 0; idx < form.elements.length; ++idx) {
          var field = form.elements.item(idx);
            if (field.id.match(/_Ghost/)){
              field.style.color = '#999999';       
              addListener(field, 'focus', clearLabel);
              addListener(field, 'blur', restoreLabel);
            }          
        }
    }
} // addFormChecks

function checkForm(e) {
    // Compatibilità con MSIE e gli altri...
    e = e || window.event;
    var form = e.target || e.srcElement;
    var errors = '';
    var faulty = null;
    for (var index = 0; index < form.elements.length; ++index) {
        var field = form.elements.item(index);
        
        if (field.id.match(/_btn_Req/) && field.checked == false) {
            errors += MSG_PRIVACY + '\n';
            faulty = faulty || field;
            continue;
        } 
        
        // Campo ghost? (con label dentro il box) (prima della verifica perché non rispetta la regexp)
        if (field.id.match(/_Ghost/) && field.value == field.title){
            field.value = '';        
        }                    
        // Verifica sintassi
        if (!field.id.match(REGEX_AUTO_FIELD))
            continue;
                    
        var value = getFieldValue(field);
                  
        // Campo obbligatorio?
        if (field.id.match(/_Req/) && value.match(REGEX_BLANK)) {
            errors += getFieldName(field) + MSG_BLANK + '\n';
            field.className += ' warnfield';
            faulty = faulty || field;
            continue;
        } else field.className = field.className.replace(' warnfield', '');
        
      	// Campo tipizzato?
      	var match = field.id.match(REGEX_TYPED_FIELD);
      	if (match) {
      	    var type = match[1];
      	    var min = match[3];
      	    var max = match[5];
      	    var error = checkTypedField(value, type, min, max);
      	    if (error) {
          		errors += getFieldName(field) + error + '\n';
          		field.className += ' warnfield';
          		faulty = faulty || field;
      	    } else field.className = field.className.replace(' warnfield', '');
      	}
    }
    if (!faulty)
        return;
    stopEvent(e);
    alert(errors);
    faulty.focus();
} // checkForm

function checkTypedField(value, type, min, max) {
    // Valori predefiniti
    min = min || Number.NEGATIVE_INFINITY;
    max = max || Number.POSITIVE_INFINITY;
    var val;
    if ('Int' == type) {
        try {
            val = parseInt(value, 10);
	    if (String(val) != value)
	    	throw val;
        } catch (e) {
            return MSG_NOT_AN_INTEGER;
        }
    }
    if ('Dbl' == type) {
        try {
            val = parseFloat(value);
	    if (String(val) != value)
	    	throw val;
        } catch (e) {
            return MSG_NOT_A_DOUBLE;
        }
    }
    if ('Int' == type || 'Dbl' == type) {
        if (val < min)
            return MSG_TOO_LOW;
        if (val > max)
            return MSG_TOO_HIGH;
    }
    if ('Date' == type) {
        var comps = value.split('/');
        if (3 != comps.length || !comps[0].match(REGEX_DAY) ||
            !comps[1].match(REGEX_MONTH) ||
            !comps[2].match(REGEX_YEAR))
            return MSG_NOT_A_DATE;
    }
    if ('Email' == type) {
        if (null === value.match(REGEX_EMAIL))
            return MSG_NOT_AN_EMAIL;
    }    
    if ('Ghost' == type) {
        if (null === value.match(REGEX_EMAIL))
            return MSG_NOT_AN_EMAIL;
    }        
    return null;
} // checkTypedField

function getFieldName(field) {
    var label = getLabelFor(field);
    if (!label)
        return field.name;
    var text = '';
    var node = label.firstChild;
    // Percorso in profondità, eliminata la ricorsione, del frammento sotto l'etichetta
    while (true) {
        if (Node.ELEMENT_NODE == node.nodeType && node.hasChildNodes())
            node = node.firstChild;
        else if (Node.TEXT_NODE == node.nodeType)
            text += node.nodeValue;
        if (node.nextSibling)
            node = node.nextSibling;
        else {
            node = node.parentNode;
            if (node == label)
                break;
            node = node.nextSibling;
        }
    }
    return text;
} // getFieldName

function getFieldValue(field) {
    if ('INPUT' == field.tagName || 'TEXTAREA' == field.tagName)
        return field.value;
    if ('SELECT' == field.tagName) {
        var value = '';
        if (-1 < field.selectedIndex) {
            var opt = field.options[field.selectedIndex];
            value = opt.value;
            if (!value && !('value' in opt))
                value = opt.text;
        }
        return value;
    }
    return '';
} // getFieldValue

function getLabelFor(field) {
    var labels = document.getElementsByTagName('label');
    for (var index = 0; index < labels.length; ++index) {
        var label = labels.item(index);
        if (label.htmlFor == field.id)
            return label;
    }
    return null;
} // getLabelFor

function stopEvent(e) {
    if (e.stopPropagation) {
        e.stopPropagation();
        e.preventDefault();
    } else {
        e.cancelBubble = true;
        e.returnValue = false;
    }
} // stopEvent



function clearLabel(e) {
  e = e || window.event;
  var field = e.target || e.srcElement;
  
  if (field.value.match(field.title)){
    field.value = '';
    field.style.color = ''; 
  }  
}

function restoreLabel(e) {
  e = e || window.event;
  var field = e.target || e.srcElement;
  
  if (field.value.match(REGEX_BLANK)){
    field.value = field.title;    
    field.style.color = '#999999';
  }
}

addListener(window, 'load', addFormChecks);


// DECORATOR
function decorateLabels() {
    var labels = document.getElementsByTagName('label');
    for (var index = 0; index < labels.length; ++index) {
        var label = labels[index];
        if (label.accessKey) {
            var ak = label.accessKey.toUpperCase();
            decorateNodeForAccessKey(label, ak);
        }
        if (label.htmlFor) {
            var elt = document.getElementById(label.htmlFor);
            if (!elt)
                continue;
            if (elt.id.match(/Req/))
                label.className += ' required';
        }
    }
} // decorateLabels

function decorateNodeForAccessKey(elt, key) {
    if (Node.ELEMENT_NODE == elt.nodeType) {
        var node = elt.firstChild;
        while (node && !decorateNodeForAccessKey(node, key))
            node = node.nextSibling;
        // Se node non è nullo, si è trovato l'AK in un discendente
        // e lo si decora: si restituisce non-null equivalente a true
        return node;
    }
    if (Node.TEXT_NODE != elt.nodeType)
        return false;
    var pos = elt.nodeValue.toUpperCase().indexOf(key);
    if (-1 == pos)
        return false;
    var suffix = elt.nodeValue.substring(pos + 1);
    var akSpan = document.createElement('span');
    akSpan.className = 'accessKey';
    akSpan.appendChild(document.createTextNode(elt.nodeValue.charAt(pos)));
    // Si evita node.splitText e node.deleteData su MSIE... Si manipola
    // nodeValue e si crea manualmente il secondo nodo testuale.
    elt.nodeValue = elt.nodeValue.substring(0, pos);
    elt.parentNode.appendChild(akSpan);
    elt.parentNode.appendChild(document.createTextNode(suffix));
    // Molto importante per evitare una ricorsione infinita!
    return true;
} // decorateNodeForAccessKey

addListener(window, 'load', decorateLabels);


