iocdev = (function() {

    if (typeof iocdev !== 'undefined') return iocdev;

    return {

        form: undefined,

        setForm: function(form) {
            iocdev.form = form;
        },

        extend: function(name, fn) {
            if (name in iocdev.local) {
                throw new Error(name + ' already defined in iocdev.local');
            }

            iocdev.local[name] = fn;
        },

        eventQueue: function() {
            return {
                queue: [],

                add: function(fn) {
                    this.queue.push(fn);
                    return this;
                },

                run: function() {
                    this.queue.forEach(function(fn) {
                        return fn();
                    });
                }
            };
        },

        mrvs: {

            move: function(mrvsName, afterName) {
                var mrvs, after;

                if (iocdev.helpers.isPortal()) {
                    jQuery('#' + mrvsName).detach().insertAfter('#' + afterName);
                    return;
                }

                mrvs = iocdev.form.nameMap.filter(function(o) {
                    return o.prettyName === mrvsName;
                }).pop();

                after = iocdev.form.nameMap.filter(function(o) {
                    return o.prettyName === afterName;
                }).pop();

                if (mrvs && after) {
                    jQuery('#element\\.' + mrvs.realName.replace(/([.:])/, '\\$&')).detach().insertAfter('#element\\.' + after.realName.replace(/([.:])/, '\\$&'));
                }
            },

            get: function(name) {

                if (iocdev.helpers.isPortal()) {
                    return iocdev.form.getField(name);
                }

                var table = iocdev.form.nameMap.filter(function(o) {
                    return o.prettyName === name;
                }).reduce(new Function);

                return TableVariableService.get(table.questionID, NOW.sysId);
            },

            set: function(mrvs, value) {

                if (iocdev.helpers.isPortal()) {
                    return iocdev.form.setValue(mrvs, JSON.stringify(value));
                }

                iocdev.mrvs.get(mrvs).stagedValue = value;
                iocdev.mrvs.get(mrvs).buildRows(JSON.stringify(value));
            },
        },

        helpers: {

            isPortal: function() {
                return 'portal_id' in NOW;
            },

            isNewRecord: function() {
                if (iocdev.helpers.isPortal()) return true;
                if (iocdev.form.isNewRecord() === null) return true;
                return iocdev.form.isNewRecord();
            },

            getControl: function(name) {
                return iocdev.form.getControl(name);
            },

            getAllVarNames: function() {
                if (iocdev.helpers.isPortal()) return iocdev.form.getFieldNames();
                return iocdev.form.nameMap.map(function(entry) {
                    return entry.prettyName;
                });
            },

            scrollToSection: function(headerText) {

                if (iocdev.helpers.isPortal()) return;

                var node = jQuery('b:visible[data-cdev-header]:contains("' + headerText + '")');

                node[0] && node[0].scrollIntoView({
                    behavior: 'smooth',
                });
            },

            setDefault: function(field, val) {
                if (!iocdev.form.getValue(field)) {
                    iocdev.form.setValue(field, val);
                }
            },

            setHelpMessage: function(field, txt) {

                if (iocdev.helpers.isPortal()) {
                    iocdev.form.getField(field).instructions = txt;
                    jQuery('#' + field).find('p.ng-binding').text(txt);
                    return;
                }

                jQuery(iocdev.form.getHelpTextControl(field)).text(txt);
            },

            failValidation: function(field, msg) {
                iocdev.form.clearValue(field);
                iocdev.form.showFieldMsg(field, msg, 'error');
                iocdev.helpers.getControl(field).focus();
            },
        },

        validators: {

            isNotMultipleOf8: function(val) {
                return (val % 8 !== 0);
            },

            containsNonNumeric: function(val) {
                return (val.search(/[^0-9]/) !== -1);
            },

            containsSemiColon: function(val) {
                return (val.indexOf(';') !== -1);
            },

            containsNonAlphaNumeric: function(val) {
                return (val.search(/[^a-z0-9]/i) !== -1);
            },

            incorrectLength: function(val, desiredLen) {
                return (val.length !== desiredLen);
            },

            notAnInteger: function(val) {
                return (val % 1 !== 0);
            },

            notInRange: function(val, floor, ceiling) {
                return (val < floor || val > ceiling);
            },
        },

        validates: {

            numberInRange: function(field, val, floor, ceiling) {
                iocdev.validators.notInRange(val, floor, ceiling) && iocdev.helpers.failValidation(
                    field, 'Value must be in range ' + floor.toLocaleString() + '-' + ceiling.toLocaleString() + '.'
                );
            },

            onlyMultiplesOf8: function(field, val) {
                iocdev.validators.isNotMultipleOf8(val) && iocdev.helpers.failValidation(
                    field, 'Value must be a multiple of 8.'
                );
            },

            noSemiColons: function(field, val) {
                iocdev.validators.containsSemiColon(val) && iocdev.helpers.failValidation(
                    field, 'Field does not allow a semi-colon to be entered.'
                );
            },

            numbersOnly: function(field, val) {
                iocdev.validators.containsNonNumeric(val) && iocdev.helpers.failValidation(
                    field, 'Numeric Text Only.'
                );
            },

            noNonAlphaNumeric: function(field, val) {
                iocdev.validators.containsNonAlphaNumeric(val) && iocdev.helpers.failValidation(
                    field, 'Value must be alphanumeric characters.'
                );
            },

            isAnExactLength: function(field, val, len) {
                iocdev.validators.incorrectLength(val, len) && iocdev.helpers.failValidation(
                    field, 'Value must be ' + len + ' characters.'
                );
            },

            isAnAppCode: function(field, val) {
                if (iocdev.validators.containsNonAlphaNumeric(val) || iocdev.validators.incorrectLength(val, 3)) {
                    iocdev.helpers.failValidation(
                        field, 'Value must be 3 alphanumeric characters.'
                    );
                }
            },

            isAnInteger: function(field, val) {
                iocdev.validators.notAnInteger(val) && iocdev.helpers.failValidation(
                    field, 'Value must be a whole number.'
                );
            },
        },

        local: {}
    };
}());