﻿/*
 * formcheck.js
 * ---
 * updated 2010/11 to more robust format
 * ---
 * requires:
 *   jquery.js
 * ---
 */

/*jslint browser: true */
/*global window: false, $: false, ESSENCE: true, alert: false */
/**/

if (typeof ESSENCE === 'undefined') { 
	ESSENCE = {}; 
}
ESSENCE.FormCheck = (function () {
    'use strict';
    var MAIN, CONST, INNER;

    CONST = {
        attr_nam: 'fc_name',
        attr_mnd: 'fc_mandatory',
        attr_mnd_msg: 'fc_mandatory_msg',
        attr_rgx: 'fc_regex',
        attr_rgx_msg: 'fc_regex_msg',
        attr_grp: 'fc_group',
        attr_grp_mnd: 'fc_group_mandatory',
        attr_exclude: 'fc_exclude',
        clsErrHilite: 'fc_err',
        selDefaultInfo: '#FormCheckInfoArea'
    };

    INNER = {
        mandatory: [],
        regex: [],
        groups: [],
        active: true,
        preSubmit: [],
        postSubmit: [],
        qinfo: null
    };

    // *** setup trim function

    function hiliteError(qel, passed) {
        if (typeof passed !== 'boolean' || passed) {
            qel.focus();
        }
        qel.addClass(CONST.clsErrHilite);
    }

    function revertError(qel) {
        qel.removeClass(CONST.clsErrHilite);
    }

    function getName(qel) {
        var name = qel.attr(CONST.attr_nam);
        return (name === null ? null : (name === '' ? qel.attr('id') : name));
    }

    function getRegex(qel) {
        return qel.attr(CONST.attr_rgx);
    }

    function checkRegex(qel) {
        var regex = new RegExp('^' + getRegex(qel) + '$', 'g');
        return (qel.val().match(regex) !== null);
    }

    function getMandatoryMessage(qel) {
        var msg = qel.attr(CONST.attr_mnd_msg), text;
        text = getName(qel) + ': ';
        if (!msg) {
            text += MAIN.textMandatory;
        } else {
            text += msg;
        }
        return text;
    }

    function getRegexMessage(qel) {
        var msg = qel.attr(CONST.attr_rgx_msg), text;
        text = getName(qel) + ': ';
        if (!msg) {
            text += MAIN.textBadFormat + ' (' + getRegex(qel) + ')';
        } else {
            text += msg;
        }
        return text;
    }

    function showFailureInfo(qinfo, message) {
        if (message) {
            if (qinfo && qinfo.length > 0) {
                var tmp = message.replace(/\n/g, '<br/>');
                qinfo.html(tmp);
            } else {
                alert(message);
            }
        } else {
            alert(MAIN.textFailure);
        }
    }

    function checkFuncArray(array) {
        var result = true;
        $.each(array, function (i0, func) {
            if (typeof func !== 'function' || !func()) {
                result = false;
                return false;
            }
        });
        return result;
    }

    function isExcluded(qel) {
        while (qel !== null && qel.length > 0) {
            if (qel.attr(CONST.attr_exclude) === '1') {
                return true;
            }
            if (typeof ESSENCE.Hider !== 'undefined' && typeof ESSENCE.Hider.isHidden === 'function') {
                if (ESSENCE.Hider.isHidden(qel)) {
                    return true;
                }
            }
            qel = qel.parent();
        }
        return false;
    }

    // *** mandatory fields checking
    function chkMandatory(mandatory, msgs, passed) {
        $.each(mandatory, function (i0, qel) {
            if (!isExcluded(qel)) {
                if (qel.val() === '') {
                    hiliteError(qel, passed);
                    msgs.push(getMandatoryMessage(qel));
                    passed = false;
                } else {
                    revertError(qel);
                }
            }
        });
        return passed;
    }

    // *** regex checking
    function chkRegex(regex, msgs, passed) {
        $.each(regex, function (i0, qel) {
            if (!isExcluded(qel)) {
                if (qel.val() !== '') {
                    if (!checkRegex(qel)) {
                        hiliteError(qel, passed);
                        msgs.push(getRegexMessage(qel));
                        passed = false;
                    } else {
                        revertError(qel);
                    }
                }
            }
        });
        return passed;
    }

    // is given group active = is any field of group nonempty
    function isGrpActive(grp) {
        var result = false;
        $.each(grp.elements, function (i0, qel) {
            var val = qel.val();
            if (!isExcluded(qel) && (typeof val !== 'undefined') && (val !== null) && (val !== '')) {
                result = true;
                return false;
            }
        });
        return result;
    }

    // set event status - propagate / cancel
    function recall(evt, passed) {
        if (!passed) {
            evt.preventDefault();
            evt.stopPropagation();
            return false;
        } else {
            return true;
        }
    }

    function checkPreSubmit(fc) {
        return checkFuncArray(fc.preSubmit);
    }

    function checkPostSubmit(fc) {
        return checkFuncArray(fc.postSubmit);
    }

    // perform all form checks
    function checkSubmit(evt) {
        var fc = evt.data, passed = true, msgs = [];
        if (!fc.active) {
            return recall(evt, true);
        } else if (!checkPreSubmit(fc)) {
            return recall(evt, false);
        } else {
            passed = chkMandatory(fc.mandatory, msgs, passed);
            passed = chkRegex(fc.regex, msgs, passed);
            // *** grouped mandatory fields checking
            $.each(fc.groups, function (i0, grp) {
                if (isGrpActive(grp)) {
                    passed = chkMandatory(grp.mandatory, msgs, passed);
                } else {
                    $.each(grp.elements, function (i1, qel) {
                        revertError(qel);
                    });
                }
            });
            if (!passed) {
                var tmp = msgs.join('\n');
                showFailureInfo(fc.qinfo, tmp);
            } else {
                passed = checkPostSubmit(fc);
            }
            return recall(evt, passed);
        }
    }

    // get existing named group or create one
    function getGroup(grpname) {
        var fc = INNER, grp = null, i;
        for (i = 0; i < fc.groups.length; i++) {
            grp = fc.groups[i];
            if (grp.name === grpname) {
                return grp;
            }
        }
        grp = {
            name: grpname,
            mandatory: [],
            elements: []
        };
        fc.groups.push(grp);
        return grp;
    }

    // process form - init checking data
    function addForm(form, info) {
        var fc = INNER;
        if (typeof form === 'undefined') {
            form = document;
        }
        if (typeof info === 'undefined') {
            info = CONST.selDefaultInfo;
        }
        fc.qinfo = $(info);
        $('*', $(form)).filter(function () {
            return !!getName($(this));
        }).each(function () {
            var qel = $(this), aman, areg, agrp, grp, agm;
            aman = qel.attr(CONST.attr_mnd);
            areg = qel.attr(CONST.attr_rgx);
            agrp = qel.attr(CONST.attr_grp);
            if (aman === 'true') {
                fc.mandatory.push(qel);
            }
            if (areg) {
                fc.regex.push(qel);
            }
            if (agrp) {
                grp = getGroup(agrp);
                grp.elements.push(qel);
                agm = qel.attr(CONST.attr_grp_mnd);
                if (agm === 'true') {
                    grp.mandatory.push(qel);
                }
            }
        });
        $(form).bind('submit', fc, checkSubmit);
    }

    // enable/disable form checking
    function enable(state) {
        INNER.active = state;
    }

    // add pre-submit check function
    function addPreSubmit(func) {
        if (typeof func !== 'function') {
            throw 'parameter is not a function!';
        }
        INNER.preSubmit.push(func);
    }

    // add post-submit check function
    function addPostSubmit(func) {
        if (typeof func !== 'function') {
            throw 'parameter is not a function!';
        }
        INNER.postSubmit.push(func);
    }

    MAIN = {
        textMandatory: 'povinné pole',
        textBadFormat: 'nesprávný formát',
        textFailure: 'ověření formuláře selhalo!',
        enable: enable,
        addPreSubmit: addPreSubmit,
        addPostSubmit: addPostSubmit,
        addForm: addForm,
        getMandatoryMsg: getMandatoryMessage,
        hiliteErr: hiliteError,
        revertErr: revertError
    };

    $(function () {
        addForm($('form'));
    });

    return MAIN;
} ());

