//=== RequiredDependentRegexAttribute ===
$.validator.unobtrusive.adapters.add('requireddependentregex', ['siblingproperty', 'regexpattern'], function (options) {
    var params = {
        siblingproperty: options.params.siblingproperty,
        regexpattern: options.params.regexpattern
    };

    options.rules['requireddependentregex'] = params;
    options.messages['requireddependentregex'] = options.message ? options.message : "Field is required";

    //var $siblingProperty = $('[name="' + options.params.siblingproperty + '"], [name$=".' + options.params.siblingproperty + '"]');
    ////is radio
    //if ($siblingProperty.length > 1)
    //    $siblingProperty = $siblingProperty.filter(':checked, :selected');

    //!!! better to auto-validate sibling when needed, otherwise it could cause some stange issues like looping validation between 2 inputs !!!
    //$siblingProperty.blur(function (event) {
    //    $('[data-val-requireddependentregex-siblingproperty="' + options.params.siblingproperty + '"]').valid();
    //});
});
$.validator.addMethod('requireddependentregex', function (value, elem, param) {
    var siblingPropertyValue,
        regExp,
        match

    var isNullOrWhiteSpace = function (string) {
        if (!string)
            return true;

        if ($.trim(string) == "")
            return true;

        return false;
    };

    var $siblingProperty = $('[name="' + param['siblingproperty'] + '"], [name$=".' + param['siblingproperty'] + '"]');

    //is radio
    if ($siblingProperty.length > 1)
        siblingPropertyValue = $siblingProperty.filter(':checked, :selected').val();
    else
        siblingPropertyValue = $siblingProperty.val();

    if (isNullOrWhiteSpace(param['regexpattern'])) {
        if (isNullOrWhiteSpace(value) && isNullOrWhiteSpace(siblingPropertyValue)) {
            return false;
        }
    } else {
        regExp = new RegExp(param['regexpattern']);

        match = regExp.exec(siblingPropertyValue);

        if (match
            && match[0] == siblingPropertyValue
            && isNullOrWhiteSpace(value))
            return false;
    }

    return true;
});;
//=== MustBeTrueAttribute ===
$.validator.unobtrusive.adapters.add('mustbetrue', function (options) {
    options.rules['mustbetrue'] = options.params;
    options.messages['mustbetrue'] = options.message ? options.message : "Field is required";
});
$.validator.addMethod('mustbetrue', function (value, elem, param) {
    switch (elem.type) {
        case "checkbox":
            return elem.checked;
            break;//NOSONAR
        case "hidden":
            return (value.toLowerCase() == 'true');
            break;//NOSONAR
        default:
            return true;
            break;//NOSONAR
    }
});;
//=== RequireAtLeastOneCheckboxAttribute ===
$.validator.unobtrusive.adapters.add('requireatleastonecheckbox', ['checkboxnames'], function (options) {
    var params = {
        checkboxnames: options.params.checkboxnames
    };

    options.rules['requireatleastonecheckbox'] = params;
    options.messages['requireatleastonecheckbox'] = options.message ? options.message : "Field is required";
});
$.validator.addMethod('requireatleastonecheckbox', function (value, elem, param) {
    var checkboxnames = param["checkboxnames"].split(',');
    for (i = 0; i < checkboxnames.length; i++) {
        var input = $('[name="' + checkboxnames[i] + '"]:checked, [name$=".' + checkboxnames[i] + '"]:checked');
        if (input.length > 0) {
            return true;
        }
    }

    return false;
});;
(function ($) {
    $.widget('LandingPage.managedButton', {
        options: {
            validation: false
        },
        _create: function () {
            this.$errorDiv = $('<div class="form__error-summary padding-small"></div>');

            this.BindEvents();
        },

        _destroy: function () { },

        _setOption: function (key, value) { },

        BindEvents: function () {

            var me = this;

            this.element.click(function (e) {

                if ($(this).hasClass('is-disabled')) {
                    e.preventDefault();
                    return false;
                }

                if (me.options.validation) {
                    if (!$(this).closest("form").valid()) {
                        //allow default (validation will show error messages and scroll to invalid field)
                        return true;
                    }
                }

                me._ShowSpinnerAndDisableButton();
                return true;
            });
        },

        ShowErrorMessage: function (errorMessage) {
            this._RemoveSpinner();
            this.$errorDiv.html('<p>' + errorMessage + '</p>');
            this.element.before(this.$errorDiv);
        },

        ShowSuccess: function (errorMessage) {
            this._RemoveSpinner();
            this.RemoveErrorMessage();
        },

        RemoveErrorMessage: function (errorMessage) {
            this.$errorDiv.remove();
        },

        _ShowSpinnerAndDisableButton: function () {
            this.RemoveErrorMessage();
            //this.element.attr('disabled', 'disabled');
            this.element.addClass('btn--waiting is-disabled');
        },

        _RemoveSpinner: function () {
            //this.element.removeAttr('disabled');
            this.element.removeClass('btn--waiting is-disabled');
        }

    });
})(window.jQuery);;
(function ($) {
    $.widget("LocalBelgium.petitionForm", {
        options: {
            petitionSubmitBtnSelector: ".jq_petitionFormButton",
            petitionFormWrapperSelector: ".jq_petitionFormWrapper",
            petitionErrorSelector: ".jq_petitionFormError",
            petitionerNumberSelector: "#jq_petitionerNumber",
            petitionSignaturesCounterSelector: "#jq_signaturesCounter"
        },

        _create: function () {
            this.BindEvents();
            //refresh form widget to show as signed

        },

        HandleResult: function (data, xhr, status) {
            //replace form with confirmation message
            $(this.options.petitionFormWrapperSelector).html(data);
            $(this.options.petitionSubmitBtnSelector).managedButton("ShowSuccess");

            //refresh petitioner number
            var count = $(data).find('#jq_petitionerNumber').html();
            $(this.options.petitionSignaturesCounterSelector).html(count);

            //show the petition as signed
            $(this.options.petitionToSignWrapper).hide();
            $(this.options.petitionAlreadySignedWrapper).show();


        },

        OnError: function () {
            $(this.options.petitionSubmitBtnSelector).managedButton("ShowErrorMessage", $(this.options.petitionErrorSelector).html());
        },

        BindEvents: function () {
            $(this.options.petitionSubmitBtnSelector).managedButton({ validation: true });
        }
    });

    $.widget("LocalBelgium.petitionNewsletter", {
        options: {
            petitionNewsletterSubmitBtnClass: ".jq_petitionNewsletterFormButton",
            petitionNewsletterWrapperClass: ".jq_petitionNewsletterWrapper",
            petitionErrorSelector: ".jq_petitionNewsletterError"
        },

        _create: function () {
            this.BindEvents();
        },

        HandleResult: function (data, xhr, status) {
            //replace form with confirmation message
            $(this.options.petitionNewsletterWrapperClass).html(data);
            $(this.options.petitionNewsletterSubmitBtnClass).managedButton("ShowSuccess");
        },

        OnError: function () {
            $(this.options.petitionNewsletterSubmitBtnClass).managedButton("ShowErrorMessage", $(this.options.petitionErrorSelector).html());
        },

        BindEvents: function () {
            $(this.options.petitionNewsletterSubmitBtnClass).managedButton({ validation: true });
        }
    });
})(window.jQuery);
;
(function ($) {
    $.widget("LocalBelgium.insulationForm", {
        options: {
            formSubmitBtnSelector: ".jq_formButton",
            formWrapperSelector: ".jq_formWrapper",
            formErrorSelector: ".jq_formError"
        },

        _create: function () {
            this.BindEvents();
            //refresh form widget to show as signed
        },

        HandleResult: function (data, xhr, status) {
            this.CreateCookie($("#FormId").val(), 1, 120);
            //replace form with confirmation message
            $(this.options.formSignedWrapper).html(data);
            //$(this.options.formSubmitBtnSelector).managedButton("ShowSuccess");
            //show the petition as signed
            $(this.options.formToSignWrapper).hide();
            $(this.options.formSignedWrapper).show();
        },

        OnError: function () {
            $(this.options.formSubmitBtnSelector).managedButton("ShowErrorMessage", $(this.options.formErrorSelector).html());
        },

        BindEvents: function () {
            $(this.options.formSubmitBtnSelector).managedButton({ validation: true });
        },

        CreateCookie: function(name, value, days) {
            var expires;
            if (days) {
                var date = new Date();
                date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
                expires = "; expires=" + date.toGMTString();
            }
            else {
                expires = "";
            }
            document.cookie = name + "=" + value + expires + "; path=/";
        }
    });
})(window.jQuery);
;
(function ($) {
    $.widget("LocalBelgium.internetSpeedTest", {
        options: {
            debugMode: false,
            updateInterval: 100,
            donutSize: 250,
            tests: ['download', 'upload'],

            onTestDoneCallback: null,
            onTestProgressCallback: null,

            uploadMeterClass: '',
            downloadMeterClass: '',
            latencyClass: '',
            runButtonClass: '',
            statusClass: '',

            uploadProgressColor: '#4e967f',
            downloadProgressColor: '#4e7096',

            language: 'eng', // 'eng || fr || nl',

            translations: {
                runTest: {
                    eng: 'Run Test',
                    fr: 'Démarrer le test',
                    nl: 'Doe de test'
                },
                idle: {
                    eng: 'Idle',
                    fr: 'En attente',
                    nl: 'Wachtend'
                },
                latency: {
                    eng: 'Latency: ',
                    fr: 'Latence: ',
                    nl: 'Latency: '
                },
                testingUploadSpeed: {
                    eng: 'Testing Upload speed...',
                    fr: 'Test de la vitesse d\'upload en cours...',
                    nl: 'Testen van de upload speed...'
                },
                uploadTestDone: {
                    eng: 'Upload test done.',
                    fr: 'Test de la vitesse d\'upload fait.',
                    nl: 'Testen van de upload speed voltooid.'
                },
                testingDownloadSpeed: {
                    eng: 'Testing Download speed...',
                    fr: 'Test de la vitesse de download en cours...',
                    nl: 'Testen van de download speed...'
                },
                downloadTestDone: {
                    eng: 'Download test done.',
                    fr: 'Test de la vitesse de download fait.',
                    nl: 'Testen van de download speed voltooid.'
                },
                allTestsDone: {
                    eng: 'All tests done.',
                    fr: 'Tous les tests sont finis.',
                    nl: 'Alle testen zijn voltooid.'
                }
            }
        },

        _vars: {
            client: null,

            status: 'idle',
            s2cProcent: 0,
            c2sProcent: 0,

            remainingTests: [],
            currentTest: null,

            $uploadMeter: null,
            uploadProgress: null,
            $downloadMeter: null,
            downloadProgress: null,
            $latency: null,
            $runButton: null,
            $status: null
        },

        //jQuery Widget "constructor" => called by jq UI when instanciating widget
        _create: function () {
            this._init_ndtBowserClient()
                ._extend_ndtBowserClient()

                ._init_progressDonut()
                ._init_DOM()
                //start speed test as soon as widget is initialized
                .runTest();
        },

        _init_DOM: function () {
            var IST = this;

            //setup children
            $.extend(IST._vars, {
                $uploadMeter: $('<div id="internetspeed-meters-upload">')
                    .addClass('internetspeed-meter-wrapper')
                    .addClass(IST.options.uploadMeterClass),

                $downloadMeter: $('<div id="internetspeed-meters-download">')
                    .addClass('internetspeed-meter-wrapper')
                    .addClass(IST.options.downloadMeterClass),

                $latency: $('<div id="internetspeed-latency">')
                    .addClass(IST.options.latencyClass)
                    .html(IST.options.translations.latency[IST.options.language]),

                $runButton: $('<div id="internetspeed-run">')
                    .addClass(IST.options.runButtonClass)
                    .html(IST.options.translations.runTest[IST.options.language])
                    .click(function (event) {
                        event.preventDefault();

                        if (IST._vars.status === 'idle') {
                            IST.runTest();
                        }
                    }),

                $status: $('<div id="internetspeed-status">')
                    .addClass(IST.options.statusClass)
            });
            
            //build DOM
            IST.element.append(
                    IST._vars.$uploadMeter,
                    IST._vars.$downloadMeter,
                    IST._vars.$latency,
                    IST._vars.$runButton,
                    IST._vars.$status
                );

            return IST._reset();
        },

        
        _displayResults: function (results) {
            if (this.testResults.latency > 0)
                this._vars.$latency.html(this.options.translations.latency[this.options.language] + this.testResults.latency.toFixed(3) + ' ms');

            return this;
        },

        //=== MLAB SERVER ===
        _serverCACHE: {
            'type': undefined,
            'answer': undefined,
            'all': undefined,
        },
        _findServer: function (metroSelection) {
            var IST = this;

            var findDeferred = jQuery.Deferred();
            var temporaryCache, temporaryResponse;

            if (IST._serverCACHE.type === metroSelection && IST._serverCACHE.answer !== undefined) {
                if (IST._serverCACHE.all !== undefined) {
                    temporaryCache = IST._serverCACHE.all.filter(function (cachedResponse) { return cachedResponse.metro === IST._serverCACHE.answer.metro; });
                    temporaryResponse = temporaryCache[Math.floor(Math.random() * temporaryCache.length)];
                } else if (IST._serverCACHE.answer !== undefined) {
                    temporaryResponse = IST._serverCACHE.answer;
                }

                //console.log('cache hit for ' + metroSelection + ' on ' + IST._serverCACHE.answer.site + ' sending ' + temporaryResponse.fqdn);

                findDeferred.resolve(temporaryResponse);
            } else {
                //console.log('Missed cache for ' + metroSelection);
                var mlabNsUrl = 'https://mlab-ns.appspot.com/ndt_ssl?format=json';
                if (metroSelection && metroSelection !== "automatic") {
                    mlabNsUrl = 'https://mlab-ns.appspot.com/ndt_ssl?format=json&policy=metro&metro=' + metroSelection;
                }
                IST._serverCACHE.type = metroSelection;
                $.get(mlabNsUrl)
                .done(function (responseObject) {
                    //console.log('Received M-Lab answer ' + responseObject.fqdn + ' for ' + metroSelection);
                    responseObject.label = responseObject.city.replace('_', ' ');
                    responseObject.metro = responseObject.site.slice(0, 3);
                    IST._serverCACHE.answer = responseObject;
                    findDeferred.resolve(responseObject);
                })
                .fail(function (data) {
                    findDeferred.reject(data);
                });
            }
            return findDeferred.promise();
        },
        

        //=== NDT CLASS LIBRARY ===
        ndtBowserClient: null,
        _init_ndtBowserClient: function () {
            //Source: https://github.com/opentechinstitute/mlab-speedtest/blob/master/app/assets/js/ndt-browser-client.js
            var NDTjs = function (server, serverPort, serverProtocol, serverPath, callbacks,
               updateInterval) {
                this.server = server;
                this.serverPort = serverPort || 3001;
                this.serverPath = serverPath || '/ndt_protocol';
                this.serverProtocol = serverProtocol || 'ws';
                this.updateInterval = updateInterval / 1000.0 || false;
                this.results = {
                    c2sRate: undefined,
                    s2cRate: undefined
                };
                this.SEND_BUFFER_SIZE = 1048576;

                // Someone may want to run this test without callbacks (perhaps for
                // debugging). Since the callbacks are referenced in various places, just
                // create some empty ones if none were specified.
                if (callbacks === undefined) {
                    this.callbacks = {
                        'onstart': function () { return false; },
                        'onstatechange': function () { return false; },
                        'onprogress': function () { return false; },
                        'onfinish': function () { return false; },
                        'onerror': function () { return false; },
                    };
                } else {
                    this.callbacks = callbacks;
                }

                // Constants used by the entire program.
                this.COMM_FAILURE = 0;
                this.SRV_QUEUE = 1;
                this.MSG_LOGIN = 2;
                this.TEST_PREPARE = 3;
                this.TEST_START = 4;
                this.TEST_MSG = 5;
                this.TEST_FINALIZE = 6;
                this.MSG_ERROR = 7;
                this.MSG_RESULTS = 8;
                this.MSG_LOGOUT = 9;
                this.MSG_WAITING = 10;
                this.MSG_EXTENDED_LOGIN = 11;

                // An array to translate the constants back into strings for debugging.
                this.NDT_MESSAGES = [];
                this.NDT_MESSAGES[this.COMM_FAILURE] = 'COMM_FAILURE';
                this.NDT_MESSAGES[this.SRV_QUEUE] = 'SRV_QUEUE';
                this.NDT_MESSAGES[this.MSG_LOGIN] = 'MSG_LOGIN';
                this.NDT_MESSAGES[this.TEST_PREPARE] = 'TEST_PREPARE';
                this.NDT_MESSAGES[this.TEST_START] = 'TEST_START';
                this.NDT_MESSAGES[this.TEST_MSG] = 'TEST_MSG';
                this.NDT_MESSAGES[this.TEST_FINALIZE] = 'TEST_FINALIZE';
                this.NDT_MESSAGES[this.MSG_ERROR] = 'MSG_ERROR';
                this.NDT_MESSAGES[this.MSG_RESULTS] = 'MSG_RESULTS';
                this.NDT_MESSAGES[this.MSG_LOGOUT] = 'MSG_LOGOUT';
                this.NDT_MESSAGES[this.MSG_WAITING] = 'MSG_WAITING';
                this.NDT_MESSAGES[this.MSG_EXTENDED_LOGIN] = 'MSG_EXTENDED_LOGIN';
            }

            /**
             * Provide feedback to the console or the DOM.
             * @param {string} logMessage Message to pass to output mechanism.
             * @param {!boolean=} debugging Optional (may be undefined) Determines whether 
             *  to output messages or to operate silently.
             */
            NDTjs.prototype.logger = function (logMessage, debugging) {
                debugging = debugging || false;
                if (debugging === true) {
                    //console.log(logMessage);
                }
            };

            /**
             * Check that the browser supports the NDT test.
             * @returns {boolean} Browser supports necessary functions for test client.
             */
            NDTjs.prototype.checkBrowserSupport = function () {
                if (self.WebSocket === undefined && self.MozWebSocket === undefined) {
                    throw this.UnsupportedBrowser('No Websockets');
                }
                return true;
            };

            /**
             * Makes a login message suitable for sending to the server.  The login
             * messages specifies the tests to be run.
             * @param {number} desiredTests The types of tests requested from the server
             *   signaled based on a bitwise operation of the test ids.
             * @returns {Uint8Array} NDT login message signalling the desired tests.
             */
            NDTjs.prototype.makeLoginMessage = function (desiredTests) {
                // We must support TEST_STATUS (16) as a 3.5.5+ client, so we make sure
                // test 16 is desired.
                var i,
                  loginMessage = 'XXX { "msg": "v3.5.5", "tests": "' + (desiredTests | 16) +
                                 '" }',
                  loginData = new Uint8Array(loginMessage.length);

                loginData[0] = this.MSG_EXTENDED_LOGIN;
                loginData[1] = 0;  // Two bytes to represent packet length
                loginData[2] = loginMessage.length - 3;

                for (i = 3; i < loginMessage.length; i += 1) {
                    loginData[i] = loginMessage.charCodeAt(i);
                }
                return loginData;
            };

            /**
             * A generic message creation system for NDT.
             * (messageType, message body length [2], message body)
             * @params {number} messageType The type of message according to NDT's 
             *  specification.
             * @params {string} messageContent The message body.
             * @returns {array} An array of bytes suitable for sending on a binary
             *  websocket.
             */
            NDTjs.prototype.makeNdtMessage = function (messageType, messageContent) {
                var messageBody, ndtMessage, i;

                messageBody = '{ "msg": "' + messageContent + '" } ';
                ndtMessage = new Uint8Array(messageBody.length + 3);
                ndtMessage[0] = messageType;
                ndtMessage[1] = (messageBody.length >> 8) & 0xFF;
                ndtMessage[2] = messageBody.length & 0xFF;

                for (i = 0; i < messageBody.length; i += 1) {
                    ndtMessage[i + 3] = messageBody.charCodeAt(i);
                }
                return ndtMessage;
            };

            /**
             * Parses messages received from the NDT server.
             * @param {object} buffer The complete message received from the NDT server.
             * @returns {array} Parsed messaged.
             */
            NDTjs.prototype.parseNdtMessage = function (buffer) {
                var i,
                  response = [],
                  bufferArray = new Uint8Array(buffer),
                  message = String.fromCharCode.apply(null,
                                                       new Uint8Array(buffer.slice(3)));
                for (i = 0; i < 3; i += 1) {
                    response[i] = bufferArray[i];
                }
                response.push(message);
                return response;
            };

            /**
             * Exception related to low-level connectivity failures.
             * @param {string} message Specific failure messages passed in the course of
             *  receiving the exception.
             */
            NDTjs.prototype.ConnectionException = function (message) {
                this.logger(message);
                this.callbacks.onerror(message);
            };

            /**
             * Exception related to an unsupported browser.
             * @param {string} message Specific failure messages passed in the course of
             *  receiving the exception.
             */
            NDTjs.prototype.UnsupportedBrowser = function (message) {
                this.logger(message);
                this.callbacks.onerror(message);
            };

            /**
             * Exception related to test failures, such as behavior inconsistent with
             * expectations.
             * @param {string} message Specific failure messages passed in the course of
             *  receiving the exception.
             */
            NDTjs.prototype.TestFailureException = function (message) {
                this.logger(message);
                this.callbacks.onerror(message);
            };

            /**
             * A simple helper function to create websockets consistently.
             * @param {string} serverAddress The FQDN or IP of the NDT server.
             * @param {Number} serverPort The port expected for the NDT test.
             * @param {string} urlPath The path of the resource to request from NDT.
             * @param {string} protocol The WebSocket protocol to build for.
             * @returns {Websocket} The WebSocket we created;
             */
            NDTjs.prototype.createWebsocket = function (serverProtocol, serverAddress,
                                                        serverPort, urlPath, protocol) {
                var createdWebsocket = new WebSocket(serverProtocol + '://' +
                                                     serverAddress + ':' + serverPort +
                                                     urlPath, protocol);
                createdWebsocket.binaryType = 'arraybuffer';
                return createdWebsocket;
            };

            /**
             * NDT's Client-to-Server (C2S) Upload Test
             * Serves as a closure that will process all messages for the C2S NDT test.
             * @returns {boolean} The test is complete and the closure should no longer 
             *    be called.
             */
            NDTjs.prototype.ndtC2sTest = function () {
                var serverPort, testConnection, testStart, i,
                  dataToSend = new Uint8Array(this.SEND_BUFFER_SIZE),
                  that = this,
                  state = 'WAIT_FOR_TEST_PREPARE',
                  totalSent = 0,
                  nextCallback = that.updateInterval,
                  keepSendingData;

                for (i = 0; i < dataToSend.length; i += 1) {
                    // All the characters must be printable, and the printable range of
                    // ASCII is from 32 to 126.  101 is because we need a prime number.
                    dataToSend[i] = 32 + (i * 101) % (126 - 32);
                }

                /**
                 * The upload function for C2S, encoded as a callback instead of a loop.
                 */
                keepSendingData = function () {
                    var currentTime = Date.now() / 1000.0;
                    //proceed to upload only if connection is open
                    if (testConnection.readyState > 0) {
                    // Monitor the buffersize as it sends and refill if it gets too low.
                    if (testConnection.bufferedAmount < 8192) {
                        testConnection.send(dataToSend);
                        totalSent += dataToSend.length;
                    }
                    if (that.updateInterval && currentTime > (testStart + nextCallback)) {
                        that.results.c2sRate = 8 * (totalSent - testConnection.bufferedAmount)
                          / 1000 / (currentTime - testStart);
                        that.callbacks.onprogress('interval_c2s', that.results);
                        nextCallback += that.updateInterval;
                        currentTime = Date.now() / 1000.0;
                    }
                    }

                    if (currentTime < testStart + 10) {
                        setTimeout(keepSendingData, 0);
                    } else {
                        if (totalSent === 0)
                            that.callbacks.onerror('error_c2s', 'COULD_NOT_CONNECT_TO_SERVER');
                        return false;
                    }
                };

                /**
                 * The closure that processes messages on the control socket for the 
                 * C2S test.
                 */
                return function (messageType, messageContent) {
                    that.logger('CALLED C2S with ' + messageType + ' (' +
                                that.NDT_MESSAGES[messageType] + ') ' + messageContent.msg +
                                ' in state ' + state);
                    if (state === 'WAIT_FOR_TEST_PREPARE' &&
                        messageType === that.TEST_PREPARE) {
                        that.callbacks.onstatechange('preparing_c2s', that.results);
                        serverPort = Number(messageContent.msg);
                        testConnection = that.createWebsocket(that.serverProtocol, that.server,
                                                              serverPort, that.serverPath, 'c2s');
                        state = 'WAIT_FOR_TEST_START';
                        return false;
                    }
                    if (state === 'WAIT_FOR_TEST_START' && messageType === that.TEST_START) {
                        that.callbacks.onstatechange('running_c2s', that.results);
                        testStart = Date.now() / 1000;
                        keepSendingData();
                        state = 'WAIT_FOR_TEST_MSG';
                        return false;
                    }
                    if (state === 'WAIT_FOR_TEST_MSG' && messageType === that.TEST_MSG) {
                        that.results.c2sRate = Number(messageContent.msg);
                        that.logger('C2S rate calculated by server: ' + that.results.c2sRate);
                        state = 'WAIT_FOR_TEST_FINALIZE';
                        return false;
                    }
                    if (state === 'WAIT_FOR_TEST_FINALIZE' &&
                        messageType === that.TEST_FINALIZE) {
                        that.callbacks.onstatechange('finished_c2s', that.results);
                        state = 'DONE';
                        return true;
                    }
                    that.logger('C2S: State = ' + state + ' type = ' + messageType + '(' +
                        that.NDT_MESSAGES[messageType] + ') message = ', messageContent);
                };
            };

            /**
             * NDT's Server-to-Client (S2C) Download Test
             * Serves as a closure that will process all messages for the S2C NDT test.
             * @param {Websocket} ndtSocket A websocket connection to the NDT server.
             * @returns {boolean} The test is complete and the closure should no longer 
             *    be called.
             */
            NDTjs.prototype.ndtS2cTest = function (ndtSocket) {
                var serverPort, testConnection, testStart, testEnd, errorMessage,
                  state = 'WAIT_FOR_TEST_PREPARE',
                  receivedBytes = 0,
                  nextCallback = this.updateInterval,
                  that = this;

                /**
                * The closure that processes messages on the control socket for the 
                * C2S test.
                */
                return function (messageType, messageContent) {
                    that.logger('CALLED S2C with ' + messageType + ' (' +
                                that.NDT_MESSAGES[messageType] + ') in state ' + state);
                    if (state === 'WAIT_FOR_TEST_PREPARE' &&
                        messageType === that.TEST_PREPARE) {
                        that.callbacks.onstatechange('preparing_s2c', that.results);
                        serverPort = Number(messageContent.msg);
                        testConnection = that.createWebsocket(that.serverProtocol, that.server,
                                                              serverPort, that.serverPath, 's2c');
                        testConnection.onopen = function () {
                            that.logger('Successfully opened S2C test connection.');
                            testStart = Date.now() / 1000;
                        };
                        testConnection.onmessage = function (response) {
                            var hdrSize,
                              currentTime;
                            if (response.data.byteLength < 126) {
                                hdrSize = 2;
                            } else if (response.data.byteLength < 65536) {
                                hdrSize = 4;
                            } else {
                                hdrSize = 10;
                            }
                            receivedBytes += (hdrSize + response.data.byteLength);
                            currentTime = Date.now() / 1000.0;
                            if (that.updateInterval && currentTime > (testStart + nextCallback)) {
                                that.results.s2cRate = 8 * receivedBytes / 1000
                                  / (currentTime - testStart);
                                that.callbacks.onprogress('interval_s2c', that.results);
                                nextCallback += that.updateInterval;
                                //currentTime = Date.now() / 1000.0;
                            }
                        };

                        testConnection.onerror = function (response) {
                            errorMessage = that.parseNdtMessage(response.data)[3].msg;
                            throw that.TestFailureException(errorMessage);
                        };

                        state = 'WAIT_FOR_TEST_START';
                        return false;
                    }
                    if (state === 'WAIT_FOR_TEST_START' && messageType === that.TEST_START) {
                        that.callbacks.onstatechange('running_s2c', that.results);

                        state = 'WAIT_FOR_FIRST_TEST_MSG';
                        return false;
                    }
                    if (state === 'WAIT_FOR_FIRST_TEST_MSG' && messageType === that.TEST_MSG) {
                        that.logger('Got message: ' + JSON.stringify(messageContent));
                        state = 'WAIT_FOR_TEST_MSG_OR_TEST_FINISH';

                        if (testEnd === undefined) {
                            testEnd = Date.now() / 1000;
                        }
                        // Calculation per spec, compared between client and server
                        // understanding.
                        that.results.s2cRate = 8 * receivedBytes / 1000 / (testEnd - testStart);
                        that.logger('S2C rate calculated by client: ' + that.results.s2cRate);
                        that.logger('S2C rate calculated by server: ' +
                                    messageContent.ThroughputValue);
                        ndtSocket.send(that.makeNdtMessage(that.TEST_MSG,
                                                           String(that.results.s2cRate)));
                        return false;
                    }
                    if (state === 'WAIT_FOR_TEST_MSG_OR_TEST_FINISH' &&
                        messageType === that.TEST_MSG) {
                        var web100Record = messageContent.msg.split(': '),
                          web100Variable = web100Record[0],
                          web100Result = web100Record[1].trim();
                        that.results[web100Variable] = web100Result;
                        return false;
                    }
                    if (state === 'WAIT_FOR_TEST_MSG_OR_TEST_FINISH' &&
                        messageType === that.TEST_FINALIZE) {
                        that.callbacks.onstatechange('finished_s2c', that.results);
                        that.logger('NDT S2C test is complete: ' + messageContent.msg);
                        return true;
                    }
                    that.logger('S2C: State = ' + state + ' type = ' + messageType + '(' +
                      that.NDT_MESSAGES[messageType] + ') message = ', messageContent);
                };
            };

            /**
             * NDT's META (S2C) Download Test
             * Serves as a closure that will process all messages for the META NDT test, 
             *    which provides additional data to the NDT results.
             * @param {Websocket} ndtSocket A websocket connection to the NDT server.
             * @returns {boolean} The test is complete and the closure should no longer
             *    be called.
             */
            NDTjs.prototype.ndtMetaTest = function (ndtSocket) {
                var errorMessage,
                  that = this,
                  state = 'WAIT_FOR_TEST_PREPARE';

                return function (messageType, messageContent) {
                    if (state === 'WAIT_FOR_TEST_PREPARE' &&
                        messageType === that.TEST_PREPARE) {
                        that.callbacks.onstatechange('preparing_meta', that.results);
                        state = 'WAIT_FOR_TEST_START';
                        return false;
                    }
                    if (state === 'WAIT_FOR_TEST_START' && messageType === that.TEST_START) {
                        that.callbacks.onstatechange('running_meta', that.results);
                        // Send one piece of meta data and then an empty meta data packet
                        ndtSocket.send(that.makeNdtMessage(that.TEST_MSG,
                                                           'client.os.name:NDTjs'));
                        ndtSocket.send(that.makeNdtMessage(that.TEST_MSG, ''));
                        state = 'WAIT_FOR_TEST_FINALIZE';
                        return false;
                    }
                    if (state === 'WAIT_FOR_TEST_FINALIZE' &&
                        messageType === that.TEST_FINALIZE) {
                        that.callbacks.onstatechange('finished_meta', that.results);
                        that.logger('NDT META test complete.');
                        return true;
                    }
                    errorMessage = 'Bad state and message combo for META test: ' +
                      state + ', ' + messageType + ', ' + messageContent.msg;
                    throw that.TestFailureException(errorMessage);
                };
            };

            /**
             * Start a series of NDT tests.
             **/
            NDTjs.prototype.startTest = function () {
                var ndtSocket, activeTest, state, errorMessage, i,
                  testsToRun = [],
                  that = this;

                this.checkBrowserSupport();
                this.logger('Test started.  Waiting for connection to server...');
                this.callbacks.onstart(this.server);
                ndtSocket = this.createWebsocket(this.serverProtocol, this.server,
                                                 this.serverPort, this.serverPath, 'ndt');

                /** When the NDT control socket is opened, send a message requesting a
                 * TEST_S2C, TEST_C2S, and TEST_META.
                 */
                ndtSocket.onopen = function () {
                    that.logger('Opened connection on port ' + that.serverPort);
                    // Sign up for every test except for TEST_MID and TEST_SFW - browsers can't
                    // open server sockets, which makes those tests impossible, because they
                    // require the server to open a connection to a port on the client.
                    ndtSocket.send(that.makeLoginMessage(2 | 4 | 32));
                    state = 'LOGIN_SENT';
                };

                /** Process a message received on the NDT control socket.  The message should
                 * be handed off to the active test (if any), or processed directly if there
                 * is no active test.
                 */
                ndtSocket.onmessage = function (response) {
                    var tests,
                      message = that.parseNdtMessage(response.data),
                      messageType = message[0],
                      messageContent = JSON.parse(message[3]);

                    that.logger('type = ' + messageType + ' (' +
                                that.NDT_MESSAGES[messageType] + ') body = "' +
                                messageContent.msg + '"');
                    if (activeTest === undefined && testsToRun.length > 0) {
                        activeTest = testsToRun.pop();
                    }
                    if (activeTest !== undefined) {
                        // Pass the message to the sub-test
                        that.logger('Calling a subtest');
                        if (activeTest(messageType, messageContent) === true) {
                            activeTest = undefined;
                            that.logger('Subtest complete');
                        }
                        return;
                    }

                    // If there is an active test, hand off control to the test
                    // Otherwise, move the coordinator state forwards.
                    if (state === 'LOGIN_SENT') {
                        // Response to NDT_LOGIN should be SRV_QUEUE messages until we
                        // get SRV_QUEUE('0')
                        if (messageType === that.SRV_QUEUE) {
                            if (messageContent.msg === '9990') {
                                // Connection keepalive message
                                ndtSocket.send(that.makeNdtMessage(that.MSG_WAITING, ''));
                            } else if (messageContent.msg === '9977') {
                                // Test failed, leave now.
                                throw that.TestFailureException('Server terminated test ' +
                                  'with SRV_QUEUE 9977');
                            }
                            that.logger('Got SRV_QUEUE. Ignoring and waiting for ' +
                              'MSG_LOGIN.');
                        } else if (messageType === that.MSG_LOGIN) {
                            if (messageContent.msg[0] !== 'v') {
                                that.logger('Bad msg ' + messageContent.msg);
                            }
                            state = 'WAIT_FOR_TEST_IDS';
                        } else {
                            errorMessage = 'Expected type 1 (SRV_QUEUE) or 2 (MSG_LOGIN)' +
                                'but got ' + messageType + ' (' +
                                that.NDT_MESSAGES[messageType] + ')';
                            throw that.TestFailureException(errorMessage);
                        }
                    } else if (state === 'WAIT_FOR_TEST_IDS' &&
                               messageType === that.MSG_LOGIN) {
                        tests = messageContent.msg.split(' ');
                        for (i = tests.length - 1; i >= 0; i -= 1) {
                            if (tests[i] === '2') {
                                testsToRun.push(that.ndtC2sTest());
                            } else if (tests[i] === '4') {
                                testsToRun.push(that.ndtS2cTest(ndtSocket));
                            } else if (tests[i] === '32') {
                                testsToRun.push(that.ndtMetaTest(ndtSocket));
                            } else if (tests[i] !== '') {
                                errorMessage = 'Unknown test type: ' + tests[i];
                                throw that.TestFailureException(errorMessage);
                            }
                        }
                        state = 'WAIT_FOR_MSG_RESULTS';
                    } else if (state === 'WAIT_FOR_MSG_RESULTS' &&
                               messageType === that.MSG_RESULTS) {
                        that.logger(messageContent);
                        var lines = messageContent.msg.split('\n');
                        for (i = 0; i < lines.length; i++) {
                            var line = lines[i];
                            var record = line.split(': ');
                            var variable = record[0];
                            var result = record[1];
                            that.results[variable] = result;
                        }
                    } else if (state === 'WAIT_FOR_MSG_RESULTS' &&
                               messageType === that.MSG_LOGOUT) {
                        ndtSocket.close();
                        that.callbacks.onstatechange('finished_all', that.results);
                        that.callbacks.onfinish(that.results);
                        that.logger('All tests successfully completed.');
                    } else {
                        errorMessage = 'No handler for message ' + messageType +
                            ' in state ' + state;
                        throw that.TestFailureException(errorMessage);
                    }
                };

                ndtSocket.onerror = function (response) {
                    errorMessage = that.parseNdtMessage(response.data)[3].msg;
                    throw that.TestFailureException(errorMessage);
                };
            };


            //=== LocalBelgium.internetSpeedTest customization ===
            this.ndtBowserClient = NDTjs;
            return this;
        },
        _extend_ndtBowserClient: function () {
            var IST = this;

            //overrides
            IST.ndtBowserClient.prototype.initial_logger = IST.ndtBowserClient.prototype.logger;
            IST.ndtBowserClient.prototype.logger = function (logMessage, debugging) {
                this.initial_logger(logMessage, IST.options.debugMode);
            };

            IST.ndtBowserClient.prototype.initial_makeLoginMessage = IST.ndtBowserClient.prototype.makeLoginMessage;
            IST.ndtBowserClient.prototype.makeLoginMessage = function (desiredTests) {
                if (IST._vars.currentTest === "upload")
                    desiredTests = 2; //unique code for c2s test
                
                if (IST._vars.currentTest === "download")
                    desiredTests = 4; //unique code for s2c test
            
                return this.initial_makeLoginMessage(desiredTests);
            };

            return IST;
        },        

        _ndtClientOptions: {
            //hostname: null,
            port: 'https:' == location.protocol ? 3010 : 3001,
            protocol: 'https:' == location.protocol ? 'wss' : 'ws',
            path: '/ndt_protocol'
        },
        _ndtClientCallbacks: function () {
            var IST = this;
            return {
                'onstart': function (server) { },
                'onstatechange': function (state, results) {
                    if (state === 'running_s2c') {
                        //update progress visual (must be total of 10 sec based on interval)
                        var intervalDownload = setInterval(function () {
                            IST.testResults.download = results && results['s2cRate'] ? results['s2cRate'] / 1000 : 0;
                            IST._vars.downloadProgress.progress(IST._vars.s2cProcent, IST.testResults.download.toFixed(3).replace('\.', ',') + ' Mbps');
                            if (IST._vars.s2cProcent >= 100)
                                clearInterval(intervalDownload);
                            else
                                IST._vars.s2cProcent = IST._vars.s2cProcent + (IST.options.updateInterval / 100/*%*/) //+ 1;
                        }, IST.options.updateInterval)

                        IST._vars.$status.html(IST.options.translations.testingDownloadSpeed[IST.options.language]);
                    }

                    if (state === 'finished_s2c')
                        IST._vars.$status.html(IST.options.translations.downloadTestDone[IST.options.language]);

                    if (state === 'running_c2s') {
                        //update progress visual (must be total of 10 sec based on interval)
                        var intervalUpload = setInterval(function () {
                            IST.testResults.upload = results && results['c2sRate'] ? results['c2sRate'] / 1000 : 0;
                            IST._vars.uploadProgress.progress(IST._vars.c2sProcent, IST.testResults.upload.toFixed(3).replace('\.', ',') + ' Mbps');
                            if (IST._vars.c2sProcent >= 100)
                                clearInterval(intervalUpload);
                            else
                                IST._vars.c2sProcent = IST._vars.c2sProcent + (IST.options.updateInterval / 100/*%*/) //+ 1;
                        }, IST.options.updateInterval)


                        IST._vars.$status.html(IST.options.translations.testingUploadSpeed[IST.options.language]);
                    }

                    if (state == 'finished_c2s')
                        IST._vars.$status.html(IST.options.translations.uploadTestDone[IST.options.language]);
                },
                'onprogress': function (state, results) {
                    if (IST.options.onTestProgressCallback
                        && $.type(IST.options.onTestProgressCallback) === 'function')
                        IST.options.onTestProgressCallback.call();
                },
                'onfinish': function (passed_results) {
                    if (IST._vars.currentTest === "download") {
                        IST.testResults.latency = passed_results['SumRTT'] / passed_results['CountRTT'];
                    }

                    if (IST._vars.currentTest === "upload") {
                    }

                    //continue with remaining tests
                    if (IST._vars.remainingTests.length > 0) {
                        IST._selectAndRunTest();
                        return;
                    }

                    //no more test
                    //console.log('== All Tests Done ==');
                    //console.log('Download speed : ' + IST.testResults.download + ' Mb');
                    //console.log('Upload speed : ' + IST.testResults.upload + ' Mb');
                    //console.log('Latency time : ' + IST.testResults.latency + ' ms');


                    IST._displayResults();
                    IST._vars.status = 'idle';
                    IST._vars.$status
                        .html(IST.options.translations.allTestsDone[IST.options.language]);

                    if (IST.options.onTestDoneCallback
                        && $.type(IST.options.onTestDoneCallback) === 'function')
                        IST.options.onTestDoneCallback.call(undefined, passed_results);
                },
                'onerror': function (error_message) { }
            };
        },

        
        //=== VISUALS ===
        _visuals:{
            progressDonut: null,
        },
        _init_progressDonut: function () {
            var IST = this,
                progressDonut = function (container, options) {
                    var _this = this;

                    _this.options = $.extend({
                        size: 200,
                        title: 'Title',
                        progressColor: '#1abc9c',
                        titleColor: '#bdc3c7',
                        textColor: '#000',
                        textFont: 'Calibri, Verdana, sans-serif'
                    }, options);

                    _this._$elements = {
                        $container: $(container),
                        $wrapper: null,
                        $content: null,
                        $label: null,
                        $title: null,
                        $donut: null,
                        $halfcircleLeft: null,
                        $halfcircleRight: null,
                        $shadow: null
                    };

                    return _this._initialize();
                };

            progressDonut.prototype._initialize = function () {
                return this._initDOM()._initCSS();
            };

            progressDonut.prototype._initDOM = function () {
                var _this = this;

                _this._$elements.$wrapper =
                    $('<div>')
                    .addClass('progressdonut-wrapper')
                    .appendTo(_this._$elements.$container);

                //_this._$elements.$label =
                //    $('<span>')
                //    .addClass('progressdonut-label')
                //    .text('0 Mbps')
                //    .appendTo(_this._$elements.$wrapper);
                _this._$elements.$content =
                    $('<div>')
                    .addClass('progressdonut-content')
                    .appendTo(_this._$elements.$wrapper);
                _this._$elements.$label =
                    $('<div>')
                    .addClass('progressdonut-content-label')
                    .text('0 Mbps')
                    .appendTo(_this._$elements.$content);
                _this._$elements.$title =
                    $('<div>')
                    .addClass('progressdonut-content-title')
                    .text(_this.options.title)
                    .appendTo(_this._$elements.$content);

                _this._$elements.$donut =
                    $('<div>')
                    .addClass('progressdonut-donut')
                    .appendTo(_this._$elements.$wrapper);

                _this._$elements.$halfcircleLeft =
                    $('<div>')
                    .addClass('progressdonut-halfcircle progressdonut-halfcircle-left')
                    .appendTo(_this._$elements.$donut);

                _this._$elements.$halfcircleRight =
                    $('<div>')
                    .addClass('progressdonut-halfcircle progressdonut-halfcircle-right')
                    .appendTo(_this._$elements.$donut);

                _this._$elements.$shadow =
                    $('<div>')
                    .addClass('progressdonut-shadow')
                    .appendTo(_this._$elements.$wrapper);

                return _this;
            };

            progressDonut.prototype._initCSS = function () {
                var _this = this;

                _this._$elements.$container.css({
                    'font-size': _this.options.size + 'px'
                });

                _this._$elements.$wrapper.css({
                    'position': 'relative',
                    'width': '1em',
                    'height': '1em',
                    'margin': '0px auto',
                    'overflow': 'hidden'
                });

                //_this._$elements.$label.css({
                //    'position': 'absolute',
                //    'top': '0em',
                //    'right': '0em',
                //    'bottom': '0em',
                //    'left': '0em',
                //    'display': 'block',
                //    'background': 'none',
                //    'border-radius': '50%',
                //    'font-family': _this.options.textFont,
                //    'color': _this.options.textColor,
                //    'font-size': '0.1em',
                //    'line-height': _this.options.size + 'px',
                //    'text-align': 'center',
                //    'cursor': 'default',
                //    'z-index': '2'
                //});
                _this._$elements.$content.css({
                    'position': 'absolute',
                    'top': '0.4em',
                    'right': '0em',
                    'bottom': '0em',
                    'left': '0em',
                    'width': '1em',
                    'margin': 'auto',
                    'z-index': '2'
                });
                _this._$elements.$label.css({
                    'font-family': _this.options.textFont,
                    'color': _this.options.textColor,
                    'font-size': '0.1em',
                    'width': _this.options.size + 'px',
                    'text-align': 'center',
                    'cursor': 'default'
                });
                _this._$elements.$title.css({
                    'font-family': _this.options.textFont,
                    'font-weight': 'bold',
                    'text-transform': 'uppercase',
                    'color': _this.options.titleColor,
                    'font-size': '0.1em',
                    'width': _this.options.size + 'px',
                    'text-align': 'center',
                    'cursor': 'default'
                });

                _this._$elements.$donut.css({
                    'position': 'absolute',
                    'top': '0px',
                    'left': '0px',
                    'width': '1em',
                    'height': '1em',
                    'clip': 'rect(0, 1em, 1em, 0.5em)'
                });

                _this._$elements.$halfcircleLeft
                .add(_this._$elements.$halfcircleRight)
                    .css({
                    'position': 'absolute',
                    'top': '0px',
                    'left': '0px',
                    'width': '0.8em',
                    'height': '0.8em',
                    'border': '0.1em solid ' + _this.options.progressColor,
                    'border-radius': '50%',
                    'clip': 'rect(0em, 0.5em, 1em, 0em)',
                    'transform': 'rotate(0deg)'
                    });

                _this._$elements.$shadow.css({
                    'width': '0.8em',
                    'height': '0.8em',
                    'border': '0.1em solid #BDC3C7',
                    'border-radius': '50%'
                });

                return _this;
            };

            progressDonut.prototype.progress = function (percent, text) {
                var _this = this;

                percent = Math.round(percent);
                if (percent > 100) 
                    percent = 100;

                if (percent < 0)
                    percent = 0;

                var deg = Math.round(360 * (percent / 100));

                if (percent > 50) {
                    _this._$elements.$donut.css('clip', 'rect(auto, auto, auto, auto)');
                    _this._$elements.$halfcircleRight.css('transform', 'rotate(180deg)');
                }
                else {
                    _this._$elements.$donut.css('clip', 'rect(0, 1em, 1em, 0.5em)');
                    _this._$elements.$halfcircleRight.css('transform', 'rotate(0deg)');
                }

                text = text || percent;
                _this._$elements.$label.text(text);

                _this._$elements.$halfcircleLeft.css('transform', 'rotate(' + deg + 'deg)');
            };

            IST._visuals.progressDonut = progressDonut;
            return IST;
        },

        _reset: function () {
            var IST = this;

            for(var index in IST.testResults) {
                IST.testResults[index] = null;
            }

            IST._vars.currentTest = null;
            IST._vars.remainingTests = [];

            IST._vars.c2sProcent = 0;
            IST._vars.s2cProcent = 0;

            IST._vars.$uploadMeter.empty();
            IST._vars.$downloadMeter.empty();

            IST._vars.uploadProgress = new IST._visuals.progressDonut(IST._vars.$uploadMeter, {size: IST.options.donutSize, title: 'Upload', titleColor: '#1abc9c', progressColor: '#1abc9c' });
            IST._vars.downloadProgress = new IST._visuals.progressDonut(IST._vars.$downloadMeter, {size: IST.options.donutSize, title: 'Download', titleColor: '#4f67a3', progressColor: '#4f67a3' });

            return IST;
        },

        _selectAndRunTest: function () {
            var IST = this,
                allTestDone = false;

            //start first test
            if (IST._vars.currentTest == null)
                IST._vars.remainingTests = IST.options.tests.slice(); //.slice(no param || 0) is a trick to clone the array

            if (IST._vars.remainingTests.length > 0) {
                IST._vars.currentTest = IST._vars.remainingTests.shift();

                IST._vars.client.startTest();
            }
            else {
                IST._vars.currentTest = null;
            }
        },
            
        testResults: {
            upload: 0,
            download: 0,
            latency: 0
        },
        status: function () {
            return this._vars.status;
        },
        runTest: function () {
            var IST = this;

            IST._vars.status = 'running';

            IST._reset()
                ._findServer()
                .then(function () {
                    //console.log('== Getting Server ==');
                    //console.log(IST._serverCACHE.answer.fqdn);
                    //console.log(IST._serverCACHE.answer.label);
                    //console.log(IST._serverCACHE.answer.metro);
                    //console.log(IST._serverCACHE.answer.city);
                    //console.log(IST._serverCACHE.answer.country);
                    //console.log(IST._serverCACHE.answer.site);

                    //console.log('== Running Test... ==');

                    IST._vars.client = new IST.ndtBowserClient(
                        IST._serverCACHE.answer.fqdn,
                        IST._ndtClientOptions.port,
                        IST._ndtClientOptions.protocol,
                        IST._ndtClientOptions.path,
                        IST._ndtClientCallbacks(),
                        IST.options.updateInterval);

                    IST._selectAndRunTest();
                });
        },
    });
})(window.jQuery);

;
(function ($) {
    $.widget("LocalBelgium.policiesAndConsentsErrorRenderer", {
        options: {
            modelStateErrors: null
        },
        //jQuery Widget "constructor" => called by jq UI when instanciating widget
        _create: function () {
            this.renderValidationMessages();
        },

        renderValidationMessages: function () {
            var PC = this,
                errors = PC.options.modelStateErrors;

            for (const error of errors) {
                var key = error.Key,
                    $validationDiv = $('.divHidden[data-valmsg-for="' + key + '"]');

                $validationDiv.find('span').remove();

                var errorMessage = null;

                if ($.type(error.Value) === "string") {
                    errorMessage = error.Value;
                }
                else {
                    errorMessage = error.Value.Errors[0].ErrorMessage;
                }

                $validationDiv
                    .append("<span>" + errorMessage + "</span>")
                    .removeClass("divHidden");
            }
        }
    });
})(window.jQuery);;
