/**
 * Title: CPLAT
 * Copyright: Copyright (c) 2008
 * Company: BBC Worldwide Ltd
 * Description:	BaseObject to provide common hijax and ajax management
 * @author: NgAW1
 * @version: $Revision: $
 * @date: 10 June 2008 16:51:45
 */


/**
 * This define the BBCWORLDWIDE_CPLAT.BaseObject Class, which is a singleton object
 * providing common hijax and ajax management
 * @return this {@link BBCWORLDWIDE_CPLAT.BaseObject}
 */
BBCWORLDWIDE_CPLAT.BaseObject = function() {

    var self = this;
    var clientConfigParams;

    // Getter for clientConfigParams
    this.getClientConfigParams = function() {
        return clientConfigParams;
    };

    // Setter clientConfigParams
    this.setclientConfigParams = function(p_clientConfigParams) {
        clientConfigParams = p_clientConfigParams;
    };

    /**
     * Add Custom email validator to be use in place of JQuery ones that had a bug
     * @return boolean {@link boolean}
     */
    jQuery.validator.addMethod("customEmailCheck", function(value, element) {
        return this.optional(element) || /^[_A-Za-z0-9-]+(\.[_A-Za-z0-9-]+)*@[_A-Za-z0-9-]+(\.[_A-Za-z0-9-]+)*(\.[A-Za-z]{2,3})/.test(value);
    }, "Please enter valid email address, yourname@hostname");


    /**
     * Add Custom validator to check whether there are spaces on input element
     * @return boolean {@link boolean}
     */
    jQuery.validator.addMethod("customSpaceCheck", function(value, element) {
        return this.optional(element) || value.indexOf(" ") == -1;
    }, "No space is allowed");


    /**
     * Custom password validator method- checks is password contains minimum number of required numeric characters
     * @return boolean {@link boolean}
     */
    jQuery.validator.addMethod("minNumeric", function(value, element, param) {
        var numericChars = 0;
        numbers = "1234567890";
        for (n = value.length - 1; n >= 0; n--) {
            var cDigit = value.charAt(n);
            if (numbers.indexOf(cDigit) > -1) {
                numericChars = numericChars + 1;
            }
        }
        return numericChars >= param;
    });

    /**
     * Custom password validator method- checks is password contains minimum number of required non-alphaNumeric characters
     * @return boolean {@link boolean}
     */
    jQuery.validator.addMethod("minNonAlphaNumeric", function(value, element, param) {
        var nonAlphaNumChars = 0;
        alphabets = "abcdefghijklmnopqrstuvwxyz";
        numbers = "1234567890";
        for (n = value.length - 1; n >= 0; n--) {
            var cDigit = value.charAt(n);
            if (numbers.indexOf(cDigit) < 0 && alphabets.indexOf(cDigit) < 0) {
                nonAlphaNumChars = nonAlphaNumChars + 1;
            }
        }
        return nonAlphaNumChars >= param;
    });


    /**
     * Template method to support hijax of form submit, it calls addValidation and addScreenHandler that can be overridden by inheriting object
     */
    this.hijax = function() {
        self.getClientConfigParams().cplatContainer.find("form").each(function() {
            self.addValidation(this);
            self.addScreenHandler(this);
        });
    };

    /**
     * Default no validation required, need to override to provide screen specific validation
     */
    this.addValidation = function (oForm) {
    };

    /**
     * Default no validation required, need to override to provide screen specific validation
     */
    this.ajaxSaveCallback = function (oForm) {
    };

    /**
     * Override this if you want to add specific processing steps for Screen Handler, this just validate inputs within a form and call form submit
     */
    this.addScreenHandler = function(oForm) {
        var oSubmitButton = $(oForm).find("input[type='submit']");
        if (oSubmitButton.get(0) != null) {
            oSubmitButton.click(function() {
                if ($(oForm).valid()) {
                    oForm.submit();
                }
                return false;
            });
        }
    };

    /**
     * Retrieve Validation Messages form with xhtml fragment
     * @return messages {@link messages}
     */
    this.getValidationMessages = function () {
        if (typeof(BBCWORLDWIDE_CPLAT_getValidationMessages) === 'function') {
            return BBCWORLDWIDE_CPLAT_getValidationMessages();
        } else {
            return {};
        }
    };

    /**
     * Retrieve Validation Rules from with xhtml fragment
     * @return messages {@link messages}
     */
    this.getValidationRules = function () {
        if (typeof(BBCWORLDWIDE_CPLAT_getValidationRules) === 'function') {
            return BBCWORLDWIDE_CPLAT_getValidationRules();
        } else {
            return {};
        }
    };


    /**
     *  Private Method to Clean Ajax Status Message
     */
    var showHide = function() {
        var showDetails = $(this).parent().parent().next('.cplat-editable');
        if (showDetails.is(':visible')) {
            showDetails.slideUp('slow');			
        } else {
            showDetails.slideDown('slow');
			showDetails.find('p.cplatAjaxSuccessMessage').remove();
			showDetails.prev().slideUp('slow');			
        }
        return false;
    };

    /**
     *  Private Method to Clean Ajax Status Message
     */
    var hide = function() {
        var hideDetails = $(this).parent().parent('.cplat-editable');
        if (hideDetails.is(':visible')) {
            hideDetails.slideUp('slow');
			hideDetails.prev().slideDown('slow');
        }
        return false;
    };


    /**
     *  Add event handler to toggle Change / hide link to show hide next sibling so that submit button can be clicked
     *   - to see in action look at editPersonDetails page on test client
     */
    this.ajaxToggleChangeLink = function(oForm, submitAction, submitMethod, redirectPath) {
        // Show the change link but hide the inputs - default to support non javascripts, change link is hidden and input is displayed
        $(oForm).find('div.changeClick').show();
        $(oForm).find("input[type='button']").show();
        $(oForm).find('div.cplat-editable').hide();
		$(oForm).find("div.buttons").show();
		$(oForm).find("#cplat-details-submit").hide();

        // Show the input when change link is clicked
        $(oForm).find("a.bChange").click(showHide);
        $(oForm).find("input.cplat-cancel-button").click(hide);

        // When the button is clicked, make call to save via AJAX
        $(oForm).find("input.cplat-save-button").click(function() {
            var requestParameters = "";

            // Allow subclass to retrieve application specific request parameter based on specific logic, SEE EditPersonalDetails.js where this is being used.
            if (typeof(self.retrieveApplicationSpecificRequestParameter) === 'function') {
                requestParameters = self.retrieveApplicationSpecificRequestParameter($(this).parent().parent());
            } else {
                // Default just read request parameters from supplied container div
                requestParameters = self.retrieveRequestParametersFromContainer($(this).parent().parent());
            }


            //Appending InitialHashCode - as it will not always be present in the container being sent to retreiveRequestParams (eg in EditPersonalDetails form)
            if ($(oForm).find("input[name='cplat-initialHashCode']").get(0) !== undefined) {
                requestParameters = requestParameters + "&cplat-initialHashCode=" + $(oForm).find("input[name='cplat-initialHashCode']").val();
            }

            // Make call to ajaxSave to persist the change
            self.ajaxSave($(this).parent().parent(), submitAction, submitMethod, requestParameters, redirectPath);
        });
    };

    /**
     *  Wrap standard JQuery Ajax to provide customised CPLAT saving and error handling capability
     */
    this.ajaxSave = function(divContainer, submitAction, submitMethod, requestParameters, redirectPath) {
        clearAjaxStatusMessages($(divContainer));
        var sSavingMessage = "<p class='cplatAjaxInfoMessage'>Saving, please wait ...</p>";
		$(divContainer).find("div.buttons").after(sSavingMessage);
        $.ajax({
            type: submitMethod,
            url: submitAction,
            data: requestParameters,
            cache: false,
            success: function(data) {
                //if email redirect immediately on success
                if (($(divContainer).find("#cplat_email").get(0) !== undefined)){
                       window.location = redirectPath;
                    }

                clearAjaxStatusMessages($(divContainer));
                var sSuccessMessage = "<p class='cplatAjaxSuccessMessage'>Successfully saved</p>";
                $(divContainer).find("div.buttons").after(sSuccessMessage);
                var oFirstInputValue = $(divContainer).find("select:first").get(0);
                var replaceText = "";
                // It is a select box
                if ((oFirstInputValue !== undefined)) {
                    replaceText = oFirstInputValue.options[oFirstInputValue.selectedIndex].text;
                    if (((replaceText == 'other') || (replaceText == 'Other')) && $(divContainer).find(":text").get(0) !== undefined) {
                        replaceText = "";
                    }
                    $(divContainer).find(":text").each(function() {
                        replaceText += " " + $(this).val();
                    });
                } else {
                    $(divContainer).find(":text").each(function() {
                        replaceText += $(this).val() + " ";
                    });
                }

                $(divContainer).prev().find("span.changeValue").html(replaceText);
				$(divContainer).animate({opacity:1.0}, 1000);
                $(divContainer).prev().find("a.bChange").trigger("click");
				$(divContainer).prev().slideDown('slow');

            },
            error: function(XMLHttpRequest, textStatus, errorThrown) {
                var resultXML = XMLHttpRequest.responseXML;
                clearAjaxStatusMessages($(divContainer));
                var nodes = $(resultXML).find("error invalidFields invalidField").each(function() {
                    var originalFieldName = $(this).attr("originalFieldName");
                    var errorMessageHTML = "<p class='error'>" + $(this).find("errorMessage").text()  + "</p>";
                    $(divContainer).find("input[name='" + originalFieldName + "']").after(errorMessageHTML);
                });
                //Cleaning conflict error message in case of other errors. Should be displayed only in case of 409
                $("#cplat-xhtml-container").find("div[name='cplat-dynamicConflictMsg']").html("");
                //Adding error message for Conflict error
                if (XMLHttpRequest.status === 409) {
                    var conflictErrorMessage = "Sorry, your changes couldn't be saved. Please try again later.";
                    $("#cplat-xhtml-container").find("div[name='cplat-dynamicConflictMsg']").html(conflictErrorMessage);

                }
            },
            complete: function(XMLHttpRequest, textStatus) {

                if (XMLHttpRequest.getResponseHeader("cplat_initialHashCode") !== null) {
                    $("#cplat-xhtml-container").find("input[name='cplat_initialHashCode']").val(XMLHttpRequest.getResponseHeader("cplat_initialHashCode"));
                }
            }


        });
    };


    /**
     *  Wrapper to the standard JQuery AJAX, providing CPLAT specific error handling
     */
    this.ajaxSubmit = function(submitButton,
                               submitAction,
                               submitMethod,
                               requestParameters,
                               successCallBackFunc,
                               errorCallBackFunc) {
        clearAjaxStatusMessages($(submitButton).form);
        $.ajax({
            type: submitMethod,
            url: submitAction,
            data: requestParameters,
            cache: false,
            success: function(data) {
                if (typeof(successCallBackFunc) === 'function') {
                    successCallBackFunc(data);
                }
            },
            error: function(XMLHttpRequest, textStatus, errorThrown) {
                var resultXML = XMLHttpRequest.responseXML;
                clearAjaxStatusMessages($(submitButton).form);
                var nodes = $(resultXML).find("error invalidFields invalidField").each(function() {
                    var originalFieldName = $(this).attr("originalFieldName");
                    var errorMessageHTML = "<p class='error'>" + $(this).find("errorMessage").text() + "</p>";
                    $($(submitButton).form).find("input[name='" + originalFieldName + "']").after(errorMessageHTML);
                });

                if (typeof(errorCallBackFunc) === 'function') {
                    errorCallBackFunc(XMLHttpRequest, textStatus, errorThrown);
                }
            }
        });
    };

    /**
     *  Wrapper to the standard JQuery AJAX call to retrieve a screen
     */
    this.ajaxGet = function(url,
                            method,
                            requestParameters,
                            successCallBackFunc,
                            errorCallBackFunc,
                            applicationSuccessCallBackFunc,
                            xhrCompleteCallBackFunc) {
        return $.ajax({
            type: method,
            url: url,
            data: requestParameters,
            cache: false,
            success: function(data) {
                if (typeof(successCallBackFunc) === 'function') {
                    successCallBackFunc(data);
                }

                if (typeof(applicationSuccessCallBackFunc) === 'function') {
                    applicationSuccessCallBackFunc(data);
                }
            },
            error: function(XMLHttpRequest, textStatus, errorThrown) {
                if (typeof(errorCallBackFunc) === 'function') {
                    errorCallBackFunc(XMLHttpRequest, textStatus, errorThrown);
                }
            },
            complete: function(XMLHttpRequest, textStatus) {
                if (typeof(xhrCompleteCallBackFunc) === 'function') {
                    xhrCompleteCallBackFunc(XMLHttpRequest, textStatus);
                }
            }
        });

    };

    /**
     *  Support retrieve of request Parameters from within a DOM container
     * @return string {@link string}
     */
    this.retrieveRequestParametersFromContainer = function(oContainer) {
        var sRequestParameters = "ajaxRequest=true";
        oContainer.find("input").each(function () {
            if ((($(this).attr("type") !== "checkbox") && ($(this).attr("type") !== "radio")) ||
                (($(this).attr("type") === "checkbox") && ($(this).get(0).checked)) ||
                (($(this).attr("type") === "radio") && ($(this).get(0).checked))) {
                if ($(this).attr("type") !== undefined) {
                    sRequestParameters = sRequestParameters + "&" + $(this).attr("name") + "=" + $(this).val();
                }
            }
        });

        oContainer.find("select").each(function () {
            if (sRequestParameters.length == 0) {
                sRequestParameters = sRequestParameters + $(this).attr("name") + "=" + $(this).val();
            } else {
                sRequestParameters = sRequestParameters + "&" + $(this).attr("name") + "=" + $(this).val();
            }
        });
        return sRequestParameters;
    };

    /**
     *  Wrapper to the JQuery Password Strength plugin
     */
    this.addPasswordStrength = function(p_oInput) {

        if (p_oInput.get(0) != null) {
            var oForm = p_oInput.get(0).form;
            if (oForm != null) {
                var oPasswordStrengthDiv = $(oForm).find("div[id='password-strength']");
                if (oPasswordStrengthDiv.get(0) === undefined) {
                    p_oInput.pstrength();
                }
            }
        }
    };


    /**
     * Make AJAX call to validate field
     */
    this.addRemoteValidation = function(url, method, p_oInput) {
        $(p_oInput).blur(function() {
            var fieldname = $(p_oInput).attr("name");
            var validationUrl = url + fieldname  + "=" + $(p_oInput).attr("value");
            // cplatRequestDateTime is passed to prevent caching of value
            // NOTE - the server-side call must return JSON
            $.getJSON(validationUrl,
            {cplatRequestTime: (new Date()).getTime()},
                    function(data) {
                        var field = data[fieldname];
                        $(p_oInput).nextAll("p.ajaxError").remove();
                        if ((field !== undefined) && (field.validate === true)) {
                            var errorMessageHTML = "<p class='error ajaxError'>" + field.errorMessage + "</p>";
                            $(p_oInput).after(errorMessageHTML);
                        } 
                    });
        });
    };


    /**
     *  Private Method to Clean Ajax Status Message
     */
    var clearAjaxStatusMessages = function(p_oContainer) {
        $(p_oContainer).find(".cplatAjaxInfoMessage").remove();
        $(p_oContainer).find(".cplatAjaxSuccessMessage").remove();
        $(p_oContainer).find("p.error").remove();
    };

    return this;
}();