rangex = new RegExp("^[ ]*\\(?[ ]*(-?\\d+(\\.\\d+)?)[ ]*\\)?[ ]*(-|to)[ ]*\\(?[ ]*(-?\\d+(\\.\\d+)?)[ ]*\\)?[ ]*$");
regExpMetachars = ['^', '$', '.', '|', '[', ']', '(', ')', '{', '}', '*', '+', '?', '\\'];

$(document).ready(function(){
    $("[validation]").bind("blur", function(){
        setupValidation(this);
    });
});

function validateall(containerId, successCallback, errorCallback) {
    if (!containerId)
        containerId = 'lxform';

    var valid = true;
    var numErrors = 0;
    $('#' + containerId + ' [validation]').each(function(){
        if(!validate($(this))) {
            numErrors++;
            valid = false;
        }
    });
    if(valid){
        (successCallback && successCallback(containerId));
        return true;
    } else {
        (errorCallback && errorCallback(containerId, numErrors));
        return false;
    }
};

function validate(obj) {
    var validation = (obj.attr("validation") ? evaluate(obj, obj.attr("validation")) : null);
    var validateHidden = (obj.attr("validate") && obj.attr("validate") == "always");
    var errdiv = '_'+obj.attr("id")+'_error';
    if (obj.get(0).disabled || (!validateHidden && (obj.get(0).offsetHeight == obj.get(0).offsetWidth && obj.get(0).offsetWidth == 0))) {
        $("#"+errdiv).remove();
        removeClass(obj.get(0), 'invalid');
        return true;
    }
    if (validation != null) {
        var valid = validation.split(" OR ");
        var value = obj.val() || '';
        if(obj.attr('type') == 'checkbox') {
            value = (obj.attr('checked') ? value : '');
        }
        for(var i = 0; i < valid.length; i++) {
            var v = valid[i];
            // if v matches the rangex regular expression, treat it as a range
            // otherwise treat it as a regular expression
            if(v.match(rangex)) {
                var m = rangex.exec(v);
                var s = m[1]*1;
                var e = m[4]*1;
                value = value*1;
                if(s <= value && value <= e) {
                    $("#"+errdiv).remove();
                    removeClass(obj.get(0), 'invalid');
                    return true;
                }
            } else {
                re = new RegExp(v, "i");
                re.multiline = false;
                if(value.match(re)) {
                    $("#"+errdiv).remove();
                    removeClass(obj.get(0), 'invalid');
                    return true;
                }
            }
        }
        // If we haven't returned "true" at this point, we haven't found a match and should
        // set the error message.
        if($("#"+errdiv).length < 1) {
            var errmessage = ''+obj.attr('error');
            if(errmessage == 'undefined' || errmessage == '') {
                errmessage = 'Invalid Entry';
            }
            obj.parent().append('<div class="field_error rer" id="'+errdiv+'">'+errmessage+'</div>');
        }
        addClass(obj.get(0), 'invalid');
        return false;
    }
    // No validation, return true
    removeClass(obj.get(0), 'invalid');
    return true;
};

function setupValidation(element) {
    validate($(element));
    /*
    if($("div.rer:visible").size() > 0) {
        $(".errors_on_page").show();
    } else {
        $(".errors_on_page").hide();
    }
    */
};

function evaluate(obj, str) {
    var delimiter = '##';
    var sections = str.split(delimiter);
    for (i in sections) {
        if (i % 2) {
            var retVal;
            var val = evalF.apply(obj.get(0), [sections[i]]);
            if (typeof(val) == "boolean") {
                if (val) {
                    val = '.*'; // match anything
                }
                else {
                    val = '$a'; // match nothing
                }
            } else {
                val = cleanRegExpStr(val);
            }
            sections[i] = val;
        }
    }
    return sections.join('');
};

function evalF(str) {
    var retVal;
    return eval(str);
};

function addClass(elem, className) {
    var classes = elem.className.split(' ');
    if (arrIndex(classes, className) == -1)
        classes.push(className);
    elem.className = classes.join(' ');
};

function removeClass(elem, className) {
    var classes = elem.className.split(' ');
    var index = arrIndex(classes, className);
    if (index > -1) {
        removeItems(classes, index);
        elem.className = classes.join(' ');
    }
};

function cleanRegExpStr(str) {
    return str.replace(new RegExp('\\' + regExpMetachars.join('|\\'), 'g'), function(match) {
        return '\\' + match;
    });
};

function arrIndex(arr, obj) {
    for (i in arr) {
        if (obj == arr[i])
            return i;
    };
    return -1;
};

// taken from Array Remove - By John Resig (MIT Licensed)
function removeItems(arr, from, to) {
  var rest = arr.slice((to || from) + 1 || arr.length);
  arr.length = from < 0 ? arr.length + from : from;
  return arr.push.apply(arr, rest);
};
