﻿
var LS = {}


LS.RegistrationForm = function(options) {

    LS.RegistrationType = {}
    LS.RegistrationType.Course = 0;
    LS.RegistrationType.Newsletter = 1;

    var defaultOptions = {
        validationErrorDisplay: "summary",
        dateFormat: "d MMMM, h:mm tt",
        newsletterOnlyRegistrationsEnabled: false,
        fields: {
            scheduleItem: {
                label: "Date",
                newsletterOptionText: "Register for newsletter"
            },
            firstName: {
                label: "First name"
            },
            lastName: {
                label: "Last name"
            },
            email: {
                label: "E-mail"
            },
            organisation: {
                label: "Organisation",
                required: true
            },
            phoneNumber: {
                label: "Phone number",
                required: true
            },
            position: {
                label: "Position",
                required: false
            },
            newsletter: {
                label: "Sign up for newsletter"
            }
        },
        submit: {
            element: jQuery(document.createElement("input")).attr({ type: "submit", value: "Register" }),
            path: "/register"
        }
    };

    options = this._parseOptions(options, defaultOptions);

    this._element = options.element;
    this._courseCode = options.courseCode;
    this._platformUrl = options.platformUrl;
    this._validationErrorDisplay = options.validationErrorDisplay;
    this._fieldOptions = options.fields;
    this._submitOptions = options.submit;
    this._dateFormat = options.dateFormat;
    this._disableSubmit = true;
    this._registrationType = LS.RegistrationType.Course;
    this._newsletterOnlyRegistrationsEnabled = options.newsletterOnlyRegistrationsEnabled;

    if (this._validationErrorDisplay == null) {
        this._validationErrorDisplay = defaultOptions.validationErrorDisplay;
    }
    if (this._submitOptions == null) {
        this._submitOptions = defaultOptions.submit;
    }
    if (this._dateFormat == null) {
        this._dateFormat = defaultOptions.dateFormat;
    }

    this._scheduleItemsElement = null;
    this._initCallback = null;
    this._formID = "registrationForm_" + Math.floor(Math.random() * 10000000);
    this._serverValidationResult = null;
    this._submittingForm = false;
    this._emailInputTimerID = null;

}

LS.RegistrationForm.prototype = {

    //Returns true if it is a DOM node
    _isNode: function(o) {
        return (typeof Node === "object" ? o instanceof Node : typeof o === "object" && typeof o.nodeType === "number" && typeof o.nodeName === "string");
    },

    //Returns true if it is a DOM element    
    _isElement: function(o) {
        return (typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2    
                typeof o === "object" && o.nodeType === 1 && typeof o.nodeName === "string");
    },

    _parseOptions: function(userOptions, defaultOptions) {
        if (userOptions == null) {
            userOptions = defaultOptions;
        }
        else {
            for (var opt in defaultOptions) {
                var defaultValue = defaultOptions[opt];
                if (typeof (userOptions[opt]) == "undefined") {
                    userOptions[opt] = defaultValue;
                }
                else if (typeof (defaultValue) == "object" && !this._isNode(defaultValue) && !this._isElement(defaultValue)) {
                    userOptions[opt] = this._parseOptions(userOptions[opt], defaultValue);
                }
            }
        }
        return userOptions;
    },

    init: function(callback) {

        this._initCallback = callback;
        var self = this;

        if (this._element == null) {
            return;
        }
        jQuery(this._element).append(this._createForm(this._platformUrl + this._submitOptions.path));

        //Put placeholder event handler in place to prevent the form from submitting until the validation code loads
        jQuery(this._element).find("form").bind("submit", function() { return false; });

        this._initScheduleItems();
        this._attachManualValidators();
        if (!jQuery.isFunction(jQuery.validator)) {
            jQuery.getScript(this._platformUrl + "/Website/Resources/Scripts/jquery.validate.min.js", function() { self._initValidation(); });
        }
        else {
            this._initValidation();
        }
    },


    _initValidation: function(b) {

        var form = this._element.find("form");
        var self = this;
        form.unbind("submit");

        if (jQuery.isFunction(form.validate)) {

            var validationOptions = {
                submitHandler: function(form) {
                    self._formSubmit(form);
                },
                onkeyup: false,
                onfocusout: false,
                errorElement: "label",
                rules: {
                    firstName: "required",
                    lastName: "required",
                    email: {
                        required: true,
                        email: true,
                        uniqueRegistration: true
                    },
                    organisation: {
                        required: this._fieldOptions.organisation.required
                    },
                    position: {
                        required: this._fieldOptions.position.required
                    },
                    phoneNumber: {
                        required: this._fieldOptions.phoneNumber.required
                    },
                    scheduleItem: {
                        required: true,
                        scheduleItemValid: true
                    }
                },
                messages: {
                    scheduleItem: {
                        required: "Please wait for the list of dates to be loaded...",
                        scheduleItemValid: function() { return self._getFirstServerErrorForField("ScheduleItem"); }
                    },
                    firstName: "Please enter your first name.",
                    lastName: "Please enter your last name.",
                    email: {
                        required: "Please enter a valid e-mail address.",
                        email: "Please enter a valid e-mail address.",
                        uniqueRegistration: function() { return self._getFirstServerErrorForField("Email"); }
                    },
                    organisation: "Please enter your " + this._fieldOptions.organisation.label.toLowerCase() + " name.",
                    position: "Please enter your " + this._fieldOptions.organisation.label.toLowerCase() + " position.",
                    phoneNumber: "Please enter your contact phone number."

                }

            };

            if (this._validationErrorDisplay == "summary") {
                validationOptions.errorContainer = "#" + this._formID + " .errorMessageBox";
                validationOptions.errorLabelContainer = "#" + this._formID + " .errorMessageBox ul";
                validationOptions.wrapper = "li";
                validationOptions.invalidHandler = function(form, validator) { self._formInvalid(form, validator); };
            }

            jQuery.validator.addMethod(
                "uniqueRegistration",
                function(value, element) {
                    if (self._submittingForm && self._registrationType == LS.RegistrationType.Course) {
                        return self._serverValidField("Email");
                    }
                    return true;
                },
                "");

            jQuery.validator.addMethod(
                "scheduleItemValid",
                function(value, element) {
                    if (self._submittingForm && self._registrationType == LS.RegistrationType.Course) {
                        return self._serverValidField("ScheduleItem");
                    }
                    return true;
                },
                "");

            form.validate(validationOptions);



            this._inputChanged();

        }

        if (this._initCallback != null) {
            try {
                this._initCallback();
            }
            catch (e) { }
        }

        //Trigger forced validation once the document is ready to cover scenarios
        //of Back button use and page refereshes in IE. In these scenarios, IE
        //can fill in fields on the form using cached values and the keyhandlers and
        //change triggers on form elements don't fire, so neither does any
        //validation occur. This forced call will execute after any cached values are
        //put in the form by IE.
        jQuery(document).ready(function() {
            self._validateRegistration();
        });
    },

    _setRegistrationType: function(type) {
        this._registrationType = type;
        if (type != null) {
            jQuery("input#registrationType").val(type.toString());
        }
        else {
            jQuery("input#registrationType").val("");
        }
        if (this._registrationType == LS.RegistrationType.Newsletter) {
            jQuery("input#newsletter").attr("checked", "checked");
        }
    },

    _serverValidField: function(field) {
        if (this._serverValidationResult != null && this._serverValidationResult.IsValid == false) {
            var errors = this._serverValidationResult.ValidationErrors;
            if (errors != null && errors.length > 0) {
                for (var i = 0; i < errors.length; i++) {
                    var error = errors[i];
                    if (error.Field == field) {
                        return false;
                    }
                }
            }
        }
        return true;
    },

    _getFirstServerErrorForField: function(field) {
        if (this._serverValidationResult != null && this._serverValidationResult.IsValid == false) {
            var errors = this._serverValidationResult.ValidationErrors;
            if (errors != null && errors.length > 0) {
                for (var i = 0; i < errors.length; i++) {
                    var error = errors[i];
                    if (error.Field == field) {
                        return error.Message;
                    }
                }
            }
        }
    },

    _attachManualValidators: function() {
        var self = this;
        var emailInput = this._element.find("input#email");
        emailInput.keypress(function() { self._emailInputKeyUp(); });
        var scheduleItemList = this._scheduleItemsElement;
        scheduleItemList.bind("change", function() { self._scheduleItemChanged(); });
    },

    _emailInputKeyUp: function() {
        if (this._emailInputTimerID != null) {
            window.clearTimeout(this._emailInputTimerID);
            this._emailInputTimerID = null;
        }
        var self = this;
        this._emailInputTimerID = window.setTimeout(function() { self._inputChanged(); }, 250);
    },

    _scheduleItemChanged: function() {
        var scheduleItemList = this._scheduleItemsElement;
        var selectedValue = scheduleItemList.children("[selected]").val();
        if (selectedValue == "Newsletter") {
            this._setRegistrationType(LS.RegistrationType.Newsletter);
        }
        else {
            this._setRegistrationType(LS.RegistrationType.Course);
        }

        this._validateRegistration();
    },

    _inputChanged: function() {
        if (this._emailInputTimerID != null) {
            window.clearTimeout(this._emailInputTimerID);
            this._emailInputTimerID = null;
        }

        this._validateRegistration();
    },

    _validateRegistration: function() {
        if (!this._submittingForm && this._registrationType == LS.RegistrationType.Course) {
            this._serverValidationResult = null;

            var scheduleItemDropDown = this._scheduleItemsElement;
            var emailInput = this._element.find("input#email");
            if (scheduleItemDropDown.length == 0 || emailInput.length == 0) {
                return;
            }
            var scheduleItemID = scheduleItemDropDown.val();
            var emailValue = emailInput.val();
            var serviceUrl = this._platformUrl + "/Website/Resources/Services/RegistrationFormService.svc";
            if (emailValue.length == 0 || (scheduleItemID == null || scheduleItemID.length == 0)) {
                return;
            }
            jQuery.getScript(serviceUrl + "/ValidateRegistration?courseCode=" + escape(this._courseCode) + "&scheduleItemID=" + scheduleItemID + "&email=" + escape(emailValue) + "&callback=" + escape("LS.RegistrationForm._validateRegistrationCallback") + "&callbackParam=" + escape(this._formID));
        }
    },

    _validateRegistrationInternal: function(r) {
        if (!this._submittingForm) {
            //Cannot update validation result while submitting form (race condition)
            this._serverValidationResult = r;
        }
    },

    _createForm: function(actionUrl) {
        var self = this;
        var formElement = jQuery(document.createElement("form"));
        formElement.attr("method", "post");
        formElement.attr("action", actionUrl);
        formElement.attr("id", this._formID);
        formElement[0].obj = this;
        formElement.append(this._createHiddenInputFormField("courseCode", this._courseCode));
        formElement.append(this._createHiddenInputFormField("returnUrl", window.location.href));
        formElement.append(this._createHiddenInputFormField("returnTitle", document.title));
        formElement.append(this._createHiddenInputFormField("registrationType", ""));

        if (this._validationErrorDisplay == "summary") {
            formElement.append(this._createValidationSummaryElement());
        }

        formElement.append(this._createScheduleItemsField(this._fieldOptions.scheduleItem.label, "scheduleItem"));
        this._scheduleItemsElement = formElement.find("select");

        formElement.append(this._createTextFormField(this._fieldOptions.firstName.label, "firstName", 128));
        formElement.append(this._createTextFormField(this._fieldOptions.lastName.label, "lastName", 128));
        formElement.append(this._createTextFormField(this._fieldOptions.email.label, "email", 128));
        formElement.append(this._createTextFormField(this._fieldOptions.phoneNumber.label, "phoneNumber", 128));
        formElement.append(this._createTextFormField(this._fieldOptions.organisation.label, "organisation", 128));
        formElement.append(this._createTextFormField(this._fieldOptions.position.label, "position", 128));
        formElement.append(this._createCheckboxFormField(this._fieldOptions.newsletter.label, "newsletter"));

        formElement.append(this._createSubmit());
        return formElement;
    },

    _createValidationSummaryElement: function() {
        var outerDiv = jQuery(document.createElement("div"));
        outerDiv.attr("class", "errorMessageBox");
        outerDiv.css("display", "none");
        var innerDiv = jQuery(document.createElement("div"));
        innerDiv.attr("class", "inner");
        var ul = jQuery(document.createElement("ul"));
        innerDiv.append(ul);
        outerDiv.append(innerDiv);
        return outerDiv;
        return input;
    },

    _createHiddenInputFormField: function(inputName, value) {
        var input = jQuery(document.createElement("input"));
        input.attr("id", inputName);
        input.attr("name", inputName);
        input.attr("type", "hidden");
        input.attr("value", value);
        return input;
    },

    _createTextFormField: function(labelText, inputName, maxLength) {
        var container = jQuery(document.createElement("div"));
        container.attr("class", "field " + inputName + "Field");

        var label = jQuery(document.createElement("label"));
        label.attr("for", inputName);
        label.append(labelText);

        var valueContainer = jQuery(document.createElement("div"));
        valueContainer.attr("class", "controls");

        var input = jQuery(document.createElement("input"));
        input.attr("class", "inputField");
        input.attr("type", "text");
        input.attr("id", inputName);
        input.attr("name", inputName);
        input.attr("maxLength", maxLength);
        valueContainer.append(input);

        container.append(label);
        container.append(valueContainer);

        return container;
    },

    _createCheckboxFormField: function(labelText, inputName) {
        var container = jQuery(document.createElement("div"));
        container.attr("class", "field " + inputName + "Field");

        var valueContainer = jQuery(document.createElement("div"));
        valueContainer.attr("class", "controls");

        var input = jQuery(document.createElement("input"));
        input.attr("class", "inputField");
        input.attr("type", "checkbox");
        input.attr("id", inputName);
        input.attr("name", inputName);
        valueContainer.append(input);

        var label = jQuery(document.createElement("label"));
        label.attr("for", inputName);
        label.append(labelText);
        valueContainer.append(label);

        container.append(valueContainer);

        return container;
    },

    _createScheduleItemsField: function(labelText, inputName) {
        var container = jQuery(document.createElement("div"));
        container.attr("class", "field " + inputName + "Field");

        var label = jQuery(document.createElement("label"));
        label.attr("for", inputName);
        label.append(labelText);

        var valueContainer = jQuery(document.createElement("div"));
        valueContainer.attr("class", "controls");

        var select = jQuery(document.createElement("select"));
        select.attr("class", "inputField");
        select.attr("id", inputName);
        select.attr("name", inputName);
        valueContainer.append(select);

        container.append(label);
        container.append(valueContainer);

        return container;
    },

    _createSubmit: function() {
        var container = jQuery(document.createElement("div"));
        container.attr("class", "submitContainer");
        var button = this._submitOptions.element;
        container.append(button);
        return container;
    },

    _initScheduleItems: function() {
        var select = this._scheduleItemsElement[0];
        var serviceUrl = this._platformUrl + "/Website/Resources/Services/RegistrationFormService.svc";
        var selectElement = this._element.find("select");

        jQuery.getScript(serviceUrl + "/GetCourseScheduleItems?courseCode=" + escape(this._courseCode) + "&dateFormat=" + escape(this._dateFormat) + "&callback=" + escape("LS.RegistrationForm._initScheduleItemsCallback") + "&callbackParam=" + escape(this._formID));
    },

    _initScheduleItemsCallbackInternal: function(r) {
        var element = this._element.find("select");

        if (element.length > 0) {
            var select = element[0];
            if (r.Success) {
                var options = r.Result;
                if (options.length == 0) {
                    var option = jQuery(document.createElement("option"));
                    option.attr("value", "");
                    option.attr("text", "(No dates available)");
                    select.add(option[0]);
                    this._showEmptyScheduleMessage();
                }
                else {
                    for (var i = 0; i < options.length; i++) {
                        var item = options[i];
                        var option = jQuery(document.createElement("option"));
                        option.attr("value", item.ScheduleItemID);
                        option[0].text = item.City + " - " + item.StartDateTimeText;
                        try {
                            select.add(option[0], null); // standards compliant browsers   
                        }
                        catch (ex) {
                            select.add(option[0]); // IE6 only   
                        }

                    }
                }
            }

            if (this._newsletterOnlyRegistrationsEnabled) {
                var option = jQuery(document.createElement("option"));
                option.attr("value", "Newsletter");
                option[0].text = this._fieldOptions.scheduleItem.newsletterOptionText;
                try {
                    select.add(option[0], null); // standards compliant browsers   
                }
                catch (ex) {
                    select.add(option[0]); // IE6 only   
                }
            }

            if (select.options.length > 0) {
                this._disableSubmit = false;

                if (element.find("[selected]").val() == "Newsletter") {
                    this._setRegistrationType(LS.RegistrationType.Newsletter);
                }
                else {
                    this._setRegistrationType(LS.RegistrationType.Course);
                }
            }
            else {
                element.attr("disabled", "disabled");
            }
        }



        this._validateRegistration();
    },

    _showEmptyScheduleMessage: function() {
        this._element.find("input,label,select").attr("disabled", "disabled");
        this._element.find("form").hide();
        var messageElement = jQuery(document.createElement("div")).attr("class", "emptySchedule").append("<p>Registrations are not being accepted at this time. Please check back soon.</p>");
        this._element.append(messageElement);
    },

    _showSummaryValidation: function() {
        this._element.find(".errorMessageBox").css("display", "block");
    },

    _hideSummaryValidation: function() {
        this._element.find(".errorMessageBox").css("display", "none");
    },

    _formSubmit: function(form) {
        if (this._disableSubmit) {
            return false;
        }
        var isValid = true;
        try {
            if (jQuery.isFunction(jQuery(form).validate)) {
                this._submittingForm = true;
                isValid = this._element.find("form").validate().form();
            }
        }
        catch (e) { }
        this._submittingForm = false;

        if (isValid) {
            form.submit();
            //Disable further submits
            this._disableSubmit = true;
        }
    },

    _formInvalid: function(form, validator) {

    }

}


LS.RegistrationForm._initScheduleItemsCallback = function(r, elementID) {
    var form = jQuery("form#" + elementID);
    if (form.length == 0) {
        return;
    }

    var instance = form[0].obj;
    if (instance == null || !jQuery.isFunction(instance._validateRegistrationInternal)) {
        return;
    }

    instance._initScheduleItemsCallbackInternal(r);
}


LS.RegistrationForm._validateRegistrationCallback = function(r, elementID) {
    var form = jQuery("form#" + elementID);
    if (form.length == 0) {
        return;
    }

    var instance = form[0].obj;
    if (instance == null || !jQuery.isFunction(instance._validateRegistrationInternal)) {
        return;
    }

    instance._validateRegistrationInternal(r);
}
