/**
 * Skrypt waliduje formularz na podstawie nadanych inputom klas
 * Istniejące filtry:
 * required 	- pole wymagane
 * int 			- liczba calkowita
 * basicChars 	- podstawowe znaki (przydatne przy weryfikacji loginu)
 * validEmail 	- poprawny adres email
 * maxLength:xx	- ograniczenie do xx znakow
 * minLength:xx	- minimum xx znakow
 * sameAs_field	- pole musi byc identyczne z "field"
 * np <input type="text" class="required basicChars maxLength_30"/>
 *
 * @author Michal Borek
 * @version pre alfa
 */
var FormValidator = {
    toValidate: new Array(),
    validators: new Array(),
    validatorKeys: new Array(),
    init: function(){
        var forms = $$('form.observe');
        forms.each(function(form, index){
            if (!form.id) 
                form.id = 'form' + Math.round(Math.random() * 3000 + 1);
            Event.observe(form, 'submit', FormValidator.checkForm);
            //FormValidator.toValidate[form.id] = $$('#' + form.id + ' input:not([type~=submit])', '#' + form.id + ' select', '#' + form.id + ' textarea', '#' + form.id + ' fieldset');
            FormValidator.toValidate[form.id] = form.getElements();
            FormValidator.toValidate[form.id].each(function(tv){
                FormValidator.addElementRules(tv, tv.classNames().toArray());
                Event.observe(tv, 'blur', FormValidator.checkInput);
            });
        });
    },
    /**
     * Uruchamia funkcje testujace
     */
    checkInput: function(ev){
    
        var valid = true;
        var el = (ev.id) ? ev : Event.element(ev);
        el.invalid = false;
        var tmp = el;
        while (tmp.nodeName != 'FORM') {
            if (!tmp.visible()) 
                return true;
            tmp = tmp.up();
        }
        if (el.rules) {
            el.rules.each(function(rule, index){
                if (!el.invalid) {
                    if (!rule.check(el, el.rulesParams[index].toString())) {
                        FormValidator.showError(el, rule);
                        valid = false;
                    }
                    else 
                        FormValidator.removeError(el, rule);
                }
            });
        }
        return valid;
    },
    /**
     * Sprawdza caly formularz w poszukiwaniu bledow
     */
    checkForm: function(ev){
        var valid = true;
        var f = (ev.id) ? ev : Event.element(ev);
        if (f.nodeName != 'FORM') 
            f = f.form;
        FormValidator.toValidate[f.id].each(function(tv){
            if (!FormValidator.checkInput(tv)) 
                valid = false;
        });
        if (!valid) {
            if (!ev.id) {
                var firstError = document.getElementsByClassName('errorInput')[0];
                while (firstError.parentNode && firstError.nodeName != 'FORM' && (!firstError.visible() || firstError.type == 'hidden')) {
                    firstError = firstError.parentNode;
                }
                firstError.up().previous().scrollTo();
                Event.stop(ev);
            }
            return false;
        }
        return true;
    },
    /**
     * Usuniecie poprzednio dodanego bledu
     */
    removeError: function(el, validator){
        if (validator.key == 'requiredArray') {
            el = validator.parentWindow;
        }
        el.removeClassName('errorInput');
        if ($(el.id + 'Error')) 
            $(el.id + 'Error').hide();
        el.invalid = false;
    },
    /**
     * Dodanie informacji o bledzie
     */
    showError: function(el, validator){
        if (validator.key == 'requiredArray') {
            el = validator.parentWindow;
        }
        el.addClassName('errorInput');
        if ($(el.id + 'Error')) {
            $(el.id + 'Error').update(validator.messageTemp);
            $(el.id + 'Error').show();
            
        }
        else {
            if (el.type != 'checkbox') {
                new Insertion.After(el, '<div class="errorDiv" id="' + el.id + 'Error">' + validator.messageTemp + '</div>');
            }
            else {
                new Insertion.After(el.next(), '<div class="errorDiv" id="' + el.id + 'Error">' + validator.messageTemp + '</div>');
            }
        }
        el.invalid = true;
    },
    /**
     * Dodanie nowego walidatora
     */
    add: function(v){
        FormValidator.validatorKeys.push(v.key);
        FormValidator.validators.push(v);
    },
    
    /**
     * Usunięcie walidatorów z podanego pola
     * @param {Object} el
     * @param array|string rules
     */
    removeElementRules: function(el, rules){
        if (!Object.isArray(el.rules)) {
            el.rules = new Array();
            el.rulesParams = new Array();
        }
        if (!Object.isArray(rules)) {
            rules = new Array(rules);
        }
        rules.each(function(r){
            el.rules.each(function(e, index){
                if (e.key == r) {
                    el.rules = el.rules.without(e);
                    el.rulesParams = el.rulesParams.without(el.rulesParams[index]);
                    el.removeClassName(r);
                }
            });
        });
    },
    /**
     * Dodanie walidatorów do podanego pola
     * @param {Object} el
     * @param array|string rules
     */
    addElementRules: function(el, rules){
        if (!Object.isArray(rules)) {
            rules = new Array(rules);
        }
        if (!el.id) 
            el.id = 'id' + Math.round(Math.random() * 3000 + 1);
        if (!Object.isArray(el.rules)) {
            el.rules = new Array();
            el.rulesParams = new Array();
        }
        rules.each(function(cl){
            var params = cl.toString().split(':');
            var ind = FormValidator.validatorKeys.indexOf(params.shift());
            if (ind != -1) {
                if (el.rules.indexOf(FormValidator.validators[ind]) == -1) {
                    el.rulesParams.push(params);
                    el.rules.push(FormValidator.validators[ind]);
                    
                    el.addClassName(cl);
                }
            }
        });
    }
};
/**
 * Funkcje testujące dla walidatora
 */
var FVPlugins = {
    /**
     * Sprawdzenie czy pole jest puste
     */
    required: new Object({
        key: 'required',
        message: 'To pole jest wymagane',
        messageTemp: null,
        check: function(el){
            this.messageTemp = this.message;
            if (el.type == "checkbox") {
                return el.checked;
            }
            return el.value != '';
        }
    }),
    /**
     * Sprawdzenie wystąpienia zaznaczenia w grupie checkbox lub input
     */
    requiredArray: {
        key: 'requiredArray',
        message: 'Musisz zaznaczyć to pole.',
        messageTemp: null,
        parentWindow: null,
        check: function(el, params){
            this.parentWindow = el.parentNode.parentNode;
            this.messageTemp = this.message;
            var fForm = el.parentNode;
            while (fForm.nodeName != 'FORM' && fForm.nodeName != 'BODY') 
                fForm = fForm.parentNode;
            var toCheck = fForm.getElementsByClassName('requiredArray:' + params);
            var valid = false;
			
            for (var i = 0; i < toCheck.length; i++) {
                if (toCheck[i].checked) {
                    valid = true;
                }
            };
            return valid;
        }
    },
    /**
     * Sprawdzenie czy ciag ma tylko podstawowe znaki (alfanumeryczne i _-.)
     */
    basicChars: {
        key: 'basicChars',
        message: 'Dozwolone znaki: litery, cyfry oraz "_", "-"',
        messageTemp: null,
        check: function(el){
            this.messageTemp = this.message;
            var pattern = new RegExp('^[a-zA-Z0-9-_]+$');
            return el.value.match(pattern);
        }
    },
    /**
     * Sprawdzenie czy podany email jest poprawny
     * @param {Object} ev
     * @return bool
     */
    email: {
        key: 'validEmail',
        message: 'Niepoprawny adres email.',
        messageTemp: null,
        check: function(el){
            this.messageTemp = this.message;
            var pattern = new RegExp('^([a-zA-Z0-9]+[.-]{0,1})+@([a-zA-Z0-9-]+[.]{1})+([a-zA-Z]){2,4}$');
            return !el.value || el.value.match(pattern);
        }
    },
    /**
     * Sprawdzenie czy ciag jest liczba calkowita
     */
    validInt: {
        key: 'validInt',
        message: 'To pole musi zawierać liczby całkowite.',
        messageTemp: null,
        check: function(el){
            this.messageTemp = this.message;
            return !el.value || (parseInt(el.value) == el.value);
        }
    },
    /**
     * Sprawdzenie czy ciag jest liczba calkowita
     */
    validFloat: {
        key: 'validFloat',
        message: 'To pole może zawierać tylko liczby.',
        messageTemp: null,
        check: function(el){
            this.messageTemp = this.message;
            el.value = el.value.gsub(',', '.');
            return !el.value || (parseFloat(el.value) == el.value);
        }
    },
    /**
     * Sprawdza czy wpisany tekst nie przekracza okreslonej wartosci
     */
    maxLength: new Object({
        key: 'maxLength',
        message: 'Maksymalna ilość znaków to: %value1',
        messageTemp: null,
        check: function(el, params){
            this.messageTemp = this.message.gsub('%value1', params);
            return (el.value.length <= params);
        }
    }),
    /**
     * Sprawdza czy wpisany tekst przekracza okresloną długość
     */
    minLength: new Object({
        key: 'minLength',
        message: 'Minimalna ilość znaków to: %value1',
        messageTemp: null,
        check: function(el, params){
            this.messageTemp = this.message.gsub('%value1', params);
            return (el.value.length >= params);
        }
    }),
    /**
     * Sprawdzenie czy ciag jest taki sam jak drugi (okreslony przez nazwe klasy)
     */
    sameAs: new Object({
        key: 'sameAs',
        message: 'Pola "%value1" i "%value2" nie są identyczne.',
        messageTemp: null,
        check: function(el, params){
            this.messageTemp = this.message.gsub('%value1', $$('label[for="' + el.id + '"]')[0].innerHTML.gsub(':', ''));
            this.messageTemp = this.messageTemp.gsub('%value2', $$('label[for="' + params + '"]')[0].innerHTML.truncate(':', ''));
            if (el.value != $(params).value) {
                $(params).addClassName('errorInput');
                return false;
            }
            else {
                $(params).removeClassName('errorInput');
                FormValidator.checkInput($(params));
                return true;
            }
        }
    }),
    validZipCode: new Object({
        key: 'validZipCode',
        message: 'Wprowadź kod w formacie xx-xxx',
        messageTemp: null,
        check: function(el, params){
            this.messageTemp = this.message;
            return !el.value || el.value.match(/^[0-9]{2}-[0-9]{3}$/);
        }
    }),
    validPhone: new Object({
        key: 'validPhone',
        message: 'Wprowadź numer telefonu w formacie (xxx) xxx-xx-xx lub xxx-xxx-xxx',
        messageTemp: this.message,
        check: function(el, params){
            this.messageTemp = this.message;
            return !($F(el).replace(/[^0-9]/g, '').length < 9 && !$F(el).blank());
        }
    }),
    validPesel: new Object({
        key: 'validPesel',
        message: 'Podany PESEL jest niepoprawny',
        messageTemp: null,
        check: function(el, params){
            this.messageTemp = this.message;
            multiplers = Array(1, 3, 7, 9, 1, 3, 7, 9, 1, 3, 1);
            pesel = el.value;
            if (!pesel) 
                return true;
            if (pesel.length != 11) 
                return false;
            pesel = pesel.toArray();
            sum = 0;
            for (i = 0; i < pesel.length; i++) {
                sum += parseInt(pesel[i]) * multiplers[i];
            }
            return (sum % 10 == 0);
        }
    }),
    validNip: new Object({
        key: 'validNip',
        message: 'Podany NIP jest niepoprawny',
        messageTemp: null,
        check: function(el, params){
            this.messageTemp = this.message;
            multiplers = Array(6, 5, 7, 2, 3, 4, 5, 6, 7);
            number = el.value
            if (!number) 
                return;
            if (number.match(/[^0-9-]/)) 
                return false;
            number = number.replace(/[^0-9]/g, '');
            if (number.length != 10) 
                return false;
            number = number.toArray();
            sum = 0;
            for (i = 0; i < multiplers.length; i++) {
                sum += parseInt(number[i]) * multiplers[i];
            }
            sum = sum % 11;
            return (sum % 10 == number[i]);
        }
    })

}
FormValidator.add(FVPlugins.required);
FormValidator.add(FVPlugins.requiredArray);
FormValidator.add(FVPlugins.basicChars);
FormValidator.add(FVPlugins.email);
FormValidator.add(FVPlugins.validInt);
FormValidator.add(FVPlugins.validFloat);
FormValidator.add(FVPlugins.sameAs);
FormValidator.add(FVPlugins.maxLength);
FormValidator.add(FVPlugins.minLength);
FormValidator.add(FVPlugins.validZipCode);
FormValidator.add(FVPlugins.validPesel);
FormValidator.add(FVPlugins.validPhone);
FormValidator.add(FVPlugins.validNip);
$(document).observe('dom:loaded', FormValidator.init);

