// ---------------------------------------------------------------------
// Validator-klasse
// ---------------------------------------------------------------------

GT = new GTjs("no.ravn.learningmodule.validation");

/** ----------------------------------------------------------
 * Nytt rammeverk for validering.
 *
 * Valideringsfunksjonene må registreres i malen. De blir kalt automatisk
 * når brukeren lagrer stofftypen.
 * Eksempel:
 * <input type="hidden" name="validate[]"
 * value="use_as_title_for_€id€:validate_nbstring:{max_length: 30, min_length: 20}:Eksterne lenker må ha en tittel." />
 * Alle parametrene som skal valideres må legges til som hidden-felt (i malen).
 * Formatet er "id:valideringsfunksjon:{parametrene}:melding"
 * id og valideringsfunksjon må oppgis, paramentrene og melding KAN oppgis.
 * parametrene må være i JSON-format og sendes til valideringsfunksjonen. Se
 * http://en.wikipedia.org/wiki/JSON for mer informasjon om JSON.
 */
Validator = Class.create();
Validator.prototype = {
    // Hvis det oppstår feil, blir feilmeldingene vist med hjelp av
    // message_box. message_box må være av typen MessageBox
    initialize: function(message_box) {
        this.validations = [];
        this.message_box = message_box;
    },

    clean_msg_container: function() {
        this.message_box.clear_msg();
    },

    /*
     * Parser arrayet med valideringsinformasjon og lagrer denne informasjonen i et javascript-array.
     */
    prepare_validation: function(form_id) {
        this.validations = [];
        var form = $(form_id);
        if (form === null) { return false; }
        //Dette feiler i Safari 3.1: var elements = form.select('[name="validate[]"]');
        var elements = $A(form.getElementsByTagName('input'));
        for (i=0; i<elements.length; i++) {
            if (elements[i].name != 'validate[]') {
                continue;
            }
            // id'n kan være en enkel id som ikke inneholder :. Hvis : brukes som en
            // del av navnet må id'en stå i paranteser. F.eks. slik:
            // (inplace:ny-tmp_48bcf092a7457-10001:topic:basename)
            var e=/^(\(([a-zA-Z0-9:_\-]+)\)|([^:]+)):([^:]+)(:(\{[^\}]*\}))?(:(.*))?$/;
            if (elements[i].value.match(e)) {
                var params = null;
                var id = RegExp.$2 || RegExp.$3;
                var func = RegExp.$4;
                var melding = RegExp.$8;
                if (RegExp.$6) {
                    var param_str = RegExp.$6;
                    params = param_str.evalJSON();
                }
                this.register_validation(id, func, params, melding);
            }
        }
    },

    /**
     * Registerer et felt som skal valideres sammen med en funksjon
     * som kalles for å validere feltet.
     * func er navnet på valideringsfunksjonen (ingen referanse).
     * params er et objekt med parametrene for valideringsfunksjonen og kan også være null.
     * melding er meldingen som brukeren får se når valideringen feiler. Hvis melding
     * er null så vises default-meldingen som blir returnert av valideringsfunksjonen.
     */
    register_validation: function(id, func, params, melding) {
        //alert("register_validation: "+id);
        var validering = [];
        validering.id = id;
        validering.func = func;
        validering.params = params;
        validering.melding = melding;
        this.validations[this.validations.length] = validering;
        return true;
    },

    /*
     * Fjerner valideringen av et element (felt). Funksjonen returnerer
     * true hvis elementet ble funnet og fjernet, eller false.
     */
    remove_validation: function(form_id, id) {
        //alert("remove_validation: "+id);
        var form = $(form_id);
        if (form === null) { return false; }
        var elements = form.select('[name="validate[]"]');
        for (i=0; i<elements.length; i++) {
            var e=/^([^:]+):([^:]+)(:(\{[^\}]*\}))?(:(.*))?$/;
            if (elements[i].value.match(e)) {
                if (id == RegExp.$1) { elements[i].value = ""; }
            }
        }
        return false;
    },

    // denne funksjonen blir kallt når brukeren klikker på lagre
    validate: function(form_id) {
        this.prepare_validation(form_id);
        this.clean_msg_container();
        var validates = true;
        var domnode = null;
        // Sjekk om vi må legge til <ul> til containeren
        var first_error = true;
        for (var i = 0; i < this.validations.length; i++) {
            var validering = this.validations[i];
            var elem = $(validering.id);
            //alert("validering.id = "+validering.id);
            if (elem) {
                //alert(validering.func);
                var func = this[validering.func];
                if (!func || typeof func !== 'function') {
                    alert("Intern feil: Ugyldig valideringsfunksjon "+func);
                    continue;
                }
                //alert("kaller "+func);
                var result = func(form_id, elem, validering.params);
                if ( !result.validerer ) {
                    elem.addClassName('valideringsfeil');
                    // TODO Her har vi flere muligheter:
                    // 1. Vi bruker alert til å varsle om feilen og stopper valideringen ved første feil
                    // 2. Vi går gjennom alle elementer og samler feilmeldingene.
                    // 3. Isteden for alert kunne vi også vise feilmeldingen direkte på siden
                    //alert('Feil: '+(validering.melding?validering.melding:result.melding));
                    if (first_error) {
                        first_error = false;
                        var ul = new Element("ul");
                        domnode = ul;
                    }
                    var li = new Element('li');
                    li.insert({top: (validering.melding?validering.melding:result.melding)});
                    domnode.insert({bottom: li});
                    //return false;
                    validates = false;
                } else {
                    // Fjern CSS-klassen (kan være sett fra forrige valideringer)
                    elem.removeClassName('valideringsfeil');
                }
            }
        }
        if (!validates) { this.message_box.show_dom_msg(domnode, 'feilmelding'); }
        return validates;
    },

    /*
     * Dette er en av de nye valideringsfunksjonene. Node er DOM-noden til elementet
     * som skal valideres.
     * Params kan brukes for å konfigurere valideringen (f.eks. kunne validate_length bruke params.max_len og
     * params.minlen).
     * Hvis params.allow_empty er satt er resultatet for tomme strenger true.
     * Merk at funksjonen returnerer et objekt som består av valideringsresultatet og en default-
     * melding.
     */

    validate_nbstring: function(form_id, node, params) {
        if (node.value && node.value !== '') {
            if (params && params.min_length && node.value.length < params.min_length) {
                return {validerer: false, melding: GT._("Felt må ha minst #{mintegn} tegn").interpolate({mintegn: params.min_length})};
            }
            if (params && params.max_length && node.value.length > params.max_length) {
                return {validerer: false, melding: GT._("Felt må ha maksimalt #{maxtegn} tegn.").interpolate({maxtegn: params.max_length})};
            }
            return {validerer: true};
        }
        var res = (node.value === '');
        if (node && node.value === '' && params && params.allow_empty) {
            return {validerer: true};
        }
        return {validerer: false, melding: GT._("Felt kan ikke være tomt.")};
    },

    /**
     * Sjekker om en streng er blank eller inneholder mellomrom.
     */
    validate_nbword: function(form_id, node, params) {
        var val = node.value.strip();
        if (val && !val.blank()) {

            if (val.match(/\s+/)) {
                return {validerer: false, melding: GT._("Felt må ikke inneholde mellomrom.") };
            }
            return {validerer: true};
        }
        return {validerer: false, melding: GT._("Felt kan ikke være tomt.") };
    },

    /**
     * Sjekker om et annet felt har samme verdi som node. Kan brukes for å
     * sjekke at brukeren har gjentatt passordet sitt riktig.
     * Id'en til felt nr to oppgis som parameter 'otherfield'.
     */
    validate_equals: function(form_id, node, params) {
        //alert("validate_equals");
        if (params && params.otherfield) {
            var otherfield = $(params.otherfield);
            if (otherfield.value == node.value) {
                return {validerer: true};
            }
            // TODO: finn bedre default-melding
            return {validerer: false, melding: GT._("Feltene er ikke like") };
        }
        return {validerer: false, melding: GT._("Feil oppsett av valideringsfunksjon.") };
    },

    /**
    * Sjekker om node eller otherfield er satt. OBS! Krever prototype!
    */
    validate_one_nbstring: function(form_id, node, params) {
        if (params && params.otherfield) {
            var otherfield = $(params.otherfield);
            if (!otherfield.value.blank() || !node.value.blank()) {
                return {validerer: true};
            }
            return {validerer: false, melding: GT._("Du må velge minst en av to felt.")};
        }
    },

    /**
     * Sjekker om minst en av flere sjekkbokser er valgt.
     */
    validate_selected: function(form_id, node, params) {
        var k = document.getElementsByName(params.radio_group);
        var sjekket = false;
        for (l=0; l<k.length;l++) {
            if (k[l].checked) {
                sjekket = true;
            }
        }
        if (!sjekket) {
            return {validerer: false, melding: GT._("Du må velge minst ett av alternativene.")};
        }
        return {validerer:true};
    },

    /**
     * Sjeker om en epost-addresse er syntaktisk gyldig. Gammel funksjon som
     * ble gjenbrukt her. Den ble skrevet til et tidspunkt hvor whitespaces
     * var dyre.
     */
    validate_email: function(form_id, node, params) {
        var email = node.value;
	while(email.charAt(0)==" ") {
            email=email.substr(1,email.length);
        }
	while(email.charAt(email.length-1)==" ") {
            email=email.substr(0,email.length-1);
        }
	var okChars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-_0123456789@., ";
	var alphaCount=0;
	var message="";
        for(var i=0;i<email.length;i++) {
            var charOK=false;
            if (email.charAt(i)=="@") { alphaCount++; }
            for(var j=0;j<okChars.length;j++){
                if(email.charAt(i)==okChars.charAt(j)) { charOK=true; }
            }
            if(!charOK) { message+="<li>" +GT._("kan ikke inneholde tegnet:")+" "+email.charAt(i)+"</li>"; }
        }
        if(email.indexOf(".")==-1) { message+="<li>"+GT._("mangler punktum")+"</li>"; }
        if(email.indexOf(",")>-1) {
            message+="<li>"+GT._("komma brukes ikke i epostadresser (antakelig skal det være punktum)")+"</li>";
        }
	if(email.indexOf(" ")>-1) {
            message+="<li>"+GT._("mellomrom brukes ikke i epostadresser")+"</li>";
        }
	if(email.charAt(0)==".") {
            message+="<li>"+GT._("kan ikke starte med punktum")+"</li>";
        }
	else if(email.charAt(0)=="@") {
            message+="<li>"+GT._("kan ikke starte med \"@\"")+"</li>";
        }
	if(email.charAt(email.length-1)==".") {
            message+="<li>"+GT._("kan ikke slutte med punktum")+"</li>";
        }
	else if(email.charAt(email.length-1)=="@") {
            message+="<li>"+GT._("kan ikke slutte med \"@\"")+"</li>";
        }
	if(email.indexOf(".@")>-1) {
            message+="<li>"+GT._("kan ikke ha punktum rett før \"@\"")+"</li>";
        }
	if(email.indexOf("@.")>-1) {
            message+="<li>"+GT._("kan ikke ha punktum rett etter \"@\"")+"</li>";
        }
	if(email.indexOf("..")>-1) {
            message+="<li>"+GT._("kan ikke ha to punktum etter hverandre")+"</li>";
        }
	if(email.indexOf("@@")>-1) {
            message+="<li>"+GT._("kan ikke ha flere \"@\" etter hverandre")+"</li>";
        } else if(alphaCount>1) {
            message+="<li>"+GT._("kan ikke inneholde mer enn én \"@\"")+"</li>";
        } else if(email.indexOf("@")==-1) {
            message+="<li>"+GT._("mangler \"@\"")+"</li>";
        }
	if(message!==''){
        return {validerer: false, melding: GT._("Feil i epost-adressen:")+" <ul>"+message+"</ul>"};
	}
        return {validerer:true};
    },

    validate_regex: function(form_id, node, params) {
        var regex_str = params.regex;
        var regex = new RegExp(regex_str);
        if (regex.test(node.value)) {
            return {validerer: true};
        }
        return {validerer: false, melding: GT._("Felt har ugyldig verdi.")};
    },

    /**
    * Sjekker om feltet er en ISO-dato
    */
    validate_isodate: function(form_id, node, params) {
        var val = node.value.strip();
        var objDate;
        var day, month, year;
        var datePattern = /^(\d{4})(-)(\d{1,2})(-)(\d{1,2})$/;

        if (val && !val.blank()) {

            var matchArray = val.match(datePattern);

            if (matchArray == null) {
                return {validerer: false, melding: GT._("Feltet må inneholde en gyldig ISO-dato (yyyy.mm.dd)") };
            }

            year = matchArray[1];
            month = matchArray[3];
            day = matchArray[5];
            month--;

            objDate=new Date(year,month,day);
            if ((day==objDate.getDate()) && (month==objDate.getMonth()) && (year==objDate.getFullYear())) {
                return {validerer: true};
            } else {
                return {validerer: false, melding: GT._("Feltet må inneholde en gyldig ISO-dato (yyyy.mm.dd)") };
            };
        }
        if (params.allow_empty) {
            return {validerer: true};
        }
        return {validerer: false, melding: GT._("Feltet kan ikke være tomt") };
    },

    /**
    * Sjekker om feltet er en norsk dato (dd.mm.åååå).
    *
    * Funksjonen er bare så bra som javascripts Date-klasse, og det er ikke
    * imponerende. 30.2.2009 er en gyldig dato, nemlig 2.3.2009.
    */
    validate_nordate: function(form_id, node, params) {
        var val = node.value.strip();
        var objDate;
        var day, month, year;
        var datePattern = /^(\d{1,2})(\.)(\d{1,2})(\.)(\d{4})$/;

        if (val && !val.blank()) {

            var matchArray = val.match(datePattern);

            if (matchArray == null) {
                return {validerer: false, melding: GT._("Feltet må inneholde en gyldig dato (dd.mm.åååå)") };
            }

            day = matchArray[1];
            month = matchArray[3];
            year = matchArray[5];
            month--;

            objDate = new Date(year,month,day);
            if ((day == objDate.getDate()) && (month == objDate.getMonth()) && (year == objDate.getFullYear())) {
                return {validerer: true};
            } else {
                return {validerer: false, melding: GT._("Feltet må inneholde en gyldig dato (dd.mm.åååå)") };
            };
        }
        if (params.allow_empty) {
            return {validerer: true};
        }
        return {validerer: false, melding: GT._("Feltet må inneholde en gyldig dato (dd.mm.åååå)") };
    },

    validate_integer: function(form_id, node, params) {
        var val = node.value;
        var regex_str = '\\d+';
        var regex = new RegExp(regex_str);
        if (val && !val.blank()) {
            if (regex.test(val)) {
                return {validerer: true};
            }
            return {validerer: false, melding: GT._("Felt har ugyldig verdi.")};
        }
        if (params.allow_empty) {
            return {validerer: true};
        }
        return {validerer: false, melding: GT._("Felt har ugyldig verdi.")};
    },

    /**
    * Sjekker om fil er av riktig type (Ikke innholdet. Kun filnavnet)
    */
    validate_file_extension: function(form_id, node, params) {
        // Todo: utvid for å sjekke innholdet av filen
        var val = node.value.strip();
        var exArr=new Array('gif', 'hhh');
        var tmpArr=new Array();

        if (params && params.exArr && params.exArr.length) {
            tmpArr=params.exArr.split(",");
            if (tmpArr.length > 0) {
                exArr = tmpArr;
            }
        }

        if (val && !val.blank()) {
            // loop igjennom endelsene og sjekk mot verdien
            for ( var i=0, len=exArr.length; i<len; ++i ) {
              if (val.indexOf('.' + exArr[i]) != -1) {
                  return {validerer: true};
              }
            }
            return {validerer: false, melding: GT._("Filnavnet har ikke en gyldig endelse") };
        } else {
            if (params && params.min_length && node.value.length < params.min_length) {
                return {validerer: false, melding: GT._("Feltet kan ikke vært blankt") };
            }
            return {validerer: true};
        }
    },

    /* Kun atilsynet */
    validate_foretaksnummer: function(form_id, node, params) {
        // Spesial for validering av et org oppslag
        var val = node.value.strip();
        if (val && !val.blank()) {
            var re = /(Ikke funnet)|(Sjekker...)/;
            var felt = $('soap_orgnavn');
            if (!felt) {
                return {validerer: false, melding: GT._("Systemfeil. Manglende felt:") + " " + melding};
            }
            if (re.test(felt.innerHTML)) {
                return {validerer: false, melding: GT._("Foretaksnummer kunne ikke valideres mot enhetsregisteret.")};
            } else {
                return {validerer: true};
            }
        }
        return {validerer: false, melding: GT._("Foretaksnummer kunne ikke valideres mot enhetsregisteret.") };
    }
};
