/// <reference path="../JQueryCore/jquery-latest.js" />
/// <reference path="../JQueryCore/jquery-latest-vsdoc.js" />
/// <reference path="../Global/Global.js" />
/// <reference path="../Global/ObserverCore.js" />

(function($) {
    // The 3 variables below are initialised on page load to the system date.
    // They are changes when a validate zipped is entered to the date and time in the zipcode time zone.
    var localDay = 0;
    var localMonth = 0;
    var localYear = 0;
    var userReturning = false;

    var getWidgetContextEndPoint = "WidgetService.asmx/GetQuoteContext";
    var saveWidgetContextEndPoint = "WidgetService.asmx/SaveQuoteContext";
    var rulesServiceEntryPoint = 'RuleService.asmx/GetRules';
    var wizardServiceEntryPoint = 'QuoteWizard.asmx'; // Used for retrieving saved quotes
    var initialContext = null; // Session context for the widget, used temporarily and is set to null after use
    var zipCodeResultList = null; // Stores the results of the zip code search
    //var myAccountUrl = "/user/myaccount"; // Provides the redirect url for the MyAccount page
    var acceptedmessagestypes = 'LogonSuccessful'; // The WelcomeWidget accepts messages of these types
    var planFinderUrl = "https://express.rwsol.com/roi/getSeniorIntroduction.do"; // URL to Unicare PlanFinder
    var genericValidationError;
    var invalidZipCodeMessage;
    var missingRequiredFieldsMessage;
    var selectProductTypeMessage;
    var validDateOfBirthMessage;
    var validDateMessage;
    var dateOfBirthInFutureMessage;
    var coverageDateInPastMessage;
    var coverageDateInFutureMessage;
    var coverageDatePreOctoberMessage;
    var navigateToKansasStateMessage;
    var navigateToKansasCityMessage;

    // Message type constants
    var MessageType = {
        InvalidZipCode: "InvalidZipCode",
        ValidationError: "ValidationError",
        RuleViolation: "RuleViolation",
        InvalidCoverageDate: "InvalidCoverageDate"
    };

    // Validation style css names
    var ValidationStyle = {
        Valid: "valid",
        Error: "warning",
        ZipCodeInvalid: "zipcodeInvalid"
    };

    // Product types
    var ProductType = {
        NotSet: -1,
        Medical: 0,
        Health: 3
    };

    // Coverage types
    var CoverageType = {
        All: 0,
        MED_SUPP: 1,
        MA: 2,
        PDP: 3,
        MAPD: 4,
        ORIG_MEDICARE: 5
    };

    // Post logon action types
    var PostLogonActionType = {
        None: 0,
        SaveForLater: 1,
        SaveToCart: 2,
        EnrollNow: 3,
        RetrieveSettings: 4
    };

    // Quote area type
    var QuoteAreaType = {
        QuoteWizard: 0,
        QuickQuote: 1
    };

    // Brand definitions
    var Brand = {
        Anthem: "abcbs",
        EmpireBlue: "eblue",
        Unicare: "unicare",
        Georgia: "bcbsga",
        Kansas: "bcbsks",
        KansasCity: "bcbskc",
        Unbranded: "unbranded"
    };

    /********************************
    Executes once the form has loaded
    *********************************/
    $(document).ready(function() {

        localDay = parseInt($('#Widget1_hdnLocalDay').val());
        localMonth = parseInt($('#Widget1_hdnLocalMonth').val());
        localYear = parseInt($('#Widget1_hdnLocalYear').val());

        DisableInputForm($("#divWidget :input[name='optShopTypeGroup']"));

        pageobserver.subscribe(fn, acceptedmessagestypes, 'WelcomeWidgetForm');
        initialiseLocalisedMessages();
        initialiseContentForCurrentBrand();
        configureControls();
        subscribeEvents();
        addCustomValidationMethods();
        addValidation();
        initialiseExistingValues();
        // set the my account url on the link
        $('#lnkViewSavedQuote').attr('href', myAccountUrl);

        // Mac only hack to change width of month dropdown.
        if (navigator.appVersion.toLowerCase().indexOf("mac") > 0) {
            $('#cboCBMonth').css("width", "75px");
        }

        EnableInputForm($("#divWidget :input[name='optShopTypeGroup']"));

        showMedicareYearEndMessageInDateRange();
    });

    /*****************************************************************
    Handles the form submit once validation has completed successfully
    ******************************************************************/
    function handleSubmit(form) {
        // Ensure the zip code and coverage start date are valid before submitting.
        // Zip code is not part of general validation as there was a requirement to have it checked as the user types.
        // Coverage start date is not part of validation because the requirements want it displayed as information.
        if (validateZipCode() === false) {
            $('#divPageErrors').text('');
            highlightInvalidZipCode();
            return false;
        }

        // Ensure the coverage start date is valid before submitting (not necessary for the health product type).
        if (getProductType() !== ProductType.Health && validateCoverageDate(nextYearPlansAvailableMonth) === false) {
            return false;
        }

        var selectedCountyIndex = $("#cboCounty").attr("selectedIndex");
        var state = (zipCodeResultList === null) ? null : zipCodeResultList[selectedCountyIndex].stateCode;
        var planYear = $("#cboCBYear").val();

        switch ($("#aspnetForm").attr("data-submitButton")) {
            case $("#cmdHelpMeChoose")[0].id:
                {
                    AjaxWorkingStart($("#divWidgetButtons"), "Loading...");
                    if (brand === Brand.Unicare || brand === Brand.KansasCity || brand === Brand.Kansas) {
                        saveIdentityContextWithRedirect('/Shop/CostAndBenefits?state=' + state + '&planyear=' + planYear + '&medicareplantype=pdp', QuoteAreaType.QuoteWizard); // unicare / kansas pdp
                    }
                    else {
                        saveIdentityContextWithRedirect('/Shop/PlanSelection?state=' + state + '&planyear=' + planYear, QuoteAreaType.QuoteWizard);
                    }
                    break;
                }
            case $("#cmdGetQuickQuote")[0].id:
                {
                    // For Unicare 2010 if Medicare Advantage has been chosen then navigate to the planfinder page. 
                    if (brand === Brand.Unicare) {
                        configureUnicare2010();
                    }
                    AjaxWorkingStart($("#divWidgetButtons"), "Loading...");
                    saveIdentityContextWithRedirect('/Shop/PlanResults?state=' + state + '&planyear=' + planYear, QuoteAreaType.QuickQuote);
                    break;
                }
            default:
                break;
        }

        return true;
    }

    /****************************************************************************************
    Handler for messages that are displayed at the top and bottom of the widget.
    This includes messages generated by the zip control, rules engine, coverage date and
    validation messages. Error messages (validation and zip control) are shown at the top
    while informational message (coverage date and rule engine violations are at the bottom).
    ****************************************************************************************/
    function displayWidgetMessage(messageStyle, message, element) {
        var tooltip;
        switch (messageStyle) {
            case MessageType.InvalidZipCode:
                $('#divCountyDropDown').hide();
                tooltip = invalidZipCodeMessage;
                message = '<div class="' + ValidationStyle.Error + ' ' + ValidationStyle.ZipCodeInvalid + '">' + message + '</div>';
                dehightlightDiv('divWidgetContainer', ValidationStyle.Error, ValidationStyle.Valid);
                displayWidgetErrorMessage(element, message, tooltip);
                DisableInputForm('#divWidget :input', '#divWidget .hasDatepicker');
                $('#txtZipCode').removeAttr("disabled");
                highlightElement(element[0], ValidationStyle.Error);
                $('#txtZipCode').blur();
                break;

            case MessageType.RuleViolation:
                // Hide the page errors div since it cannot be displayed with divPageMessages (no room for both).
                $('#divPageErrors').hide();
                $('#divPageMessages > div').remove();

                // Hide particular elements when showing a rule violation message.
                $('#divWidgetGender').addClass('hiddenForZipCodeRuleViolation');
                $('#divWidgetDateOfBirth').addClass('hiddenForZipCodeRuleViolation');
                $('#divWidgetCoverageBegins').addClass('hiddenForZipCodeRuleViolation');
                $('#HomeMedicareYearEnd').addClass('hiddenForZipCodeRuleViolation');
                //$('#divCountyDropDown').hide();
                $('#divWidgetButtons').hide();
                $('#divGoButton').hide();

                // Inject agent connect parameters
                message = InjectAgentConnectParameters(message);

                // Show the message in a slide-down manner to avoid flicker.
                $('#divPageMessages').hide();
                DisplayInfoMessage('#divPageMessages', message);
                $('#divPageMessages').slideDown("fast");
                break;

            case MessageType.InvalidCoverageDate:
                // Hide the page errors div since it cannot be displayed with divPageMessages (no room for both).
                $('#divPageErrors').hide();
                $('#divPageMessages > div').remove();
                DisplayInfoMessage('#divPageMessages', message);

                // Display the 'Learn More' help icon after the text.
                $('#divLearnMoreHelp').clone(true).appendTo('#divPageMessages > div');
                $('#divLearnMoreHelp').show();
                break;

            default:
                // Validation error
                tooltip = 'Error message not available.';
                if (message.length > 0 && message[0]) {
                    tooltip = message[0].title;
                }
                message[0].innerHTML = genericValidationError;
                displayWidgetErrorMessage(element, message, tooltip);
                break;
        }
    }

    /**********************************************************************
    Displays an error message in the widget and highlights the element that
    was the cause of the error/message.
    ***********************************************************************/
    function displayWidgetErrorMessage(element, messageHtml, tooltip) {
        // If there is an invalid zip code message displayed then exit as it has the priority.
        $('#divPageErrors').show();
        if ($('#divPageErrors > div.zipcodeInvalid').length > 0) {
            $('#divPageErrors > div.zipcodeInvalid').show();
            return;
        }

        // Add the message
        $('#divPageErrors').html(messageHtml);

        // Add the error icon and set the tooltip.
        var widgetRowDiv = $(element).closest(".widgetRow");
        widgetRowDiv.addClass('error');
        if (widgetRowDiv.find('#errorsymbol').length === 0) {
            widgetRowDiv.prepend('<div id="errorsymbol" title="' + tooltip + '" class="error_symbol">&nbsp;&nbsp;</div>');
        }
    }

    /************************************************************
    Clears the invalid highlight styling for the zip code control
    *************************************************************/
    function clearInvalidZipCode() {
        // Remove any existing invalid zip code message and dehighlight the zip code controls.
        // Also remove any informational message (shown at the bottom of the widget) and
        // show any divs that were hidden due to the ZipCode rule violation message.
        $('#divPageErrors > div.zipcodeInvalid').remove();
        $('#divPageMessages > div').remove();
        $('.hiddenForZipCodeRuleViolation').removeClass('hiddenForZipCodeRuleViolation');
        displayButtons();
        dehighlightElement($("#txtZipCode")[0], ValidationStyle.Error, ValidationStyle.Valid);
        EnableInputForm('#divWidget :input', '#divWidget .hasDatepicker');
    }

    /************************************************************
    Highlights the label of an element that has failed validation
    *************************************************************/
    function highlightElement(element, errorClass) {
        // Highlight the label (the first label that matches the criteria).
        $(element.form).find("label[for=" + element.id + "]:first").addClass('error');
    }

    /*************************************************************************
    Dehighlights the label of an element that had previously failed validation
    **************************************************************************/
    function dehighlightElement(element, errorClass, validClass) {
        // Add a valid class to the element
        $(element).removeClass(errorClass).addClass(validClass);

        // Remove the error icon
        var widgetRowDiv = $(element).closest(".widgetRow");
        widgetRowDiv.removeClass('error');
        if (widgetRowDiv.find('#errorsymbol').length === 1) {
            widgetRowDiv.find('#errorsymbol').remove();
        }

        // Remove the highlight from the associated label
        $(element.form).find("label[for=" + element.id + "]").removeClass('error');

        // Remove the error message
        $('div[htmlFor=' + element.name + ']').remove();

        // Hide the errors div if it is has no errors to display.
        if ($('#divPageErrors > div:visible').length === 0) {
            $('#divPageErrors').hide();
        }
    }

    /***********************************************
    Dehighlights all elements within a specified div
    ************************************************/
    function dehightlightDiv(div, errorClass, validClass) {
        $('#' + div + ' input').each(function(index) {
            dehighlightElement(this, errorClass, validClass);
        });
    }

    /***********************************************************************************
    Callback method for handling login successful notification.

  Profile info is loaded into QuoteSessionInfo on Login. A LogonSuccessful message is
    fired to this welcomeWidget which informs this control to re-load QuoteSessionInfo.
    This defaults the ZipCode controls and others on the page i.e. loadIdentityContext()
    ************************************************************************************/
    var fn = function(message) {
        var m = JSON.parse(message);

        switch (m.messagetype) {
            case "LogonSuccessful":
                // Get the shopper profile and load it into the identity context.
                getShopperProfile();
                break;
            default:
                break;
        }
    };

    /*************************************************************************************
    Provides an Ajax function to retrieve user shopper profile and update QuoteSessionInfo
    **************************************************************************************/
    function getShopperProfile() {
        CallWCFModel('POST', "LogonService.asmx/getShopperProfile", "{}", loadIdentityContext);
    }

    /*************************************************************************
    Initialises localised messages which are read from hidden fields/resources
    **************************************************************************/
    function initialiseLocalisedMessages() {
        genericValidationError = $("#divWidget input[id*=hdnGenericValidationError]").val();
        invalidZipCodeMessage = $("#divWidget input[id*=hdnInvalidZipCodeMessage]").val();
        missingRequiredFieldsMessage = $("#divWidget input[id*=hdnMissingRequiredFieldsMessage]").val();
        selectProductTypeMessage = $("#divWidget input[id*=hdnSelectProductTypeMessage]").val();
        validDateOfBirthMessage = $("#divWidget input[id*=hdnValidDateOfBirthMessage]").val();
        validDateMessage = $("#divWidget input[id*=hdnValidDateMessage]").val();
        dateOfBirthInFutureMessage = $("#divWidget input[id*=hdnDateOfBirthInFutureMessage]").val();
        coverageDateInPastMessage = $("#divWidget input[id*=hdnCoverageDateInPastMessage]").val();
        coverageDateInFutureMessage = $("#divWidget input[id*=hdnCoverageDateInFutureMessage]").val();
        coverageDatePreOctoberMessage = $("#divWidget input[id*=hdnCoverageDatePreOctoberMessage]").val();
        navigateToKansasStateMessage = $("#divWidget input[id*=hdnNavigateToKansasStateMessage]").val();
        navigateToKansasCityMessage = $("#divWidget input[id*=hdnNavigateToKansasCityMessage]").val();
    }

    /*********************************************************************************
    Initialises existing values. If there is a zip code in the
    query string then the zip code is initialised with that value. If not then it is
    initialised with the value from the session context (if that exists).
    **********************************************************************************/
    function initialiseExistingValues() {
        // Get the zip code from the query string.
        var zipCode = GetQueryStringParameter('ZipCode');
        if (zipCode !== null && zipCode !== "") {
            // The zip code exists in the query string for redirections from another brand. This
            // only happens for Medicare product type so this can be always be assumed. For now
            // set the other fields to null. Eventually these should be passed (e.g. via form post).
            populateControls(ProductType.Medical, zipCode, null, null, null);
        }
        else {
            loadIdentityContext();
        }

        var gender = GetQueryStringParameter('gender');
        if (gender !== null && gender !== "") {
            if (gender == 'm') {
                $("#optMale").attr('checked', 'checked');
            } else {
                $("#optFemale").attr('checked', 'checked');
            }
        }

        var dob = GetQueryStringParameter('dob');
        if (dob !== null && dob !== "") {
            $("#txtWidgetDateOfBirth").val("01/01/" + dob);
        }

        var cboMonth = GetQueryStringParameter('cbomonth');
        if (cboMonth !== null && cboMonth !== "") {
            $("#cboCBMonth").val(cboMonth);
        }

        var cboYear = GetQueryStringParameter('cboyear');
        if (cboYear !== null && cboMonth !== "") {
            $("#cboCBYear").val(cboYear);
        }

        // Make sure zip code information is updated.
        $('#divWidget').show();
    }

    /*********************************************************************
    Configures the look of widget & the logo to display based on the brand
    **********************************************************************/
    function initialiseContentForCurrentBrand() {
        // Initialise image controls
        var logoImage = $('#logoImage');
        var logoLink = $('#logoLink');
        var shopForImage = $('#imgShopFor');
        logoImage.hide();
        logoImage.attr('alt', brand + ' Logo');

        // Hide unwanted divs initially
        $("#divUnicare2010").hide();
        $("#divLearnMoreHelp").hide();

        switch (brand) {
            case Brand.Anthem:
                logoImage.attr('src', '/ols/Content/olspublic/images/home/logo_AnthemBCBS.png');
                logoLink.attr('href', 'http://www.anthem.com');
                logoImage.attr('title', 'Anthem.Com Home');
                shopForImage.attr('src', '/ols/images/quote/shop_for_header.png');
                logoImage.show();

                // Show the minimized widget if no product type is selected.
                if (getProductType() == ProductType.NotSet) {
                    $('#divWidgetContainer').hide();
                    hideMedicareYearEndMessage();
                }

                if (brandState === "ca") {
                    logoImage.attr('src', '/ols/Content/olspublic/images/home/logo_AnthemBC.png');
                    logoLink.attr('href', 'http://www.anthem.com/ca');
                    logoImage.attr('title', 'Anthem.Com California Home');
                    logoImage.show();
                }
                break;

            case Brand.Unicare:
                logoImage.attr('src', '/ols/Content/olspublic/images/home/logo_Unicare.png');
                logoLink.attr('href', 'http://www.unicare.com');
                logoImage.attr('title', 'Unicare.Com Home');
                shopForImage.attr('src', '/ols/images/quote/Shop_for_Medicare_Prescription_Drugs.png');
                $("#dlWidgetShopFor dt").text('Shop for Medicare<br />Prescription Drug Plans');
                logoImage.show();
                // For Unicare there is specific configuration for the year 2010.
                configureUnicare2010();
                break;

            case Brand.EmpireBlue:
                logoImage.attr('src', '/ols/Content/olspublic/images/home/logo_EmpireBCBS.png');
                logoLink.attr('href', 'http://www.empireblue.com');
                logoImage.attr('title', 'EmpireBlue.Com Home');
                shopForImage.attr('src', '/ols/images/quote/Shop_for_Medicare_Solutions.png');
                logoImage.show();
                break;

            case Brand.Georgia:
                logoImage.attr('src', '/ols/Content/olspublic/images/home/logo_BCBSGA.png');
                logoLink.attr('href', 'http://www.bcbsga.com');
                logoImage.attr('title', 'bcbsga.Com Home');
                shopForImage.attr('src', '/ols/images/quote/Shop_for_Medicare_Solutions.png');
                logoImage.show();

                // Show the minimized widget if no product type is selected.
                if (getProductType() == ProductType.NotSet) {
                    $('#divWidgetContainer').hide();
                    hideMedicareYearEndMessage();
                }
                break;

            case Brand.Kansas:
                logoLink.attr('href', 'http://www.partdcoverage.com/');
                logoImage.attr('src', '/ols/Content/olspublic/images/home/logo_BluecrossKansas.png');
                logoImage.attr('title', 'bcbsks.Com Home');
                logoImage.show();
                shopForImage.attr('src', '/ols/images/quote/Shop_for_Medicare_Prescription_Drugs.png');
                $("#dlWidgetShopFor dt").text('Shop for Medicare Solutions');
                break;

            case Brand.KansasCity:
                logoLink.attr('href', 'http://www.partdcoverage.com/');
                logoImage.attr('src', '/ols/Content/olspublic/images/home/logo_BluecrossKansasCity.png');
                logoImage.attr('title', 'bcbskc.Com Home');
                shopForImage.attr('src', '/ols/images/quote/Shop_for_Medicare_Prescription_Drugs.png');
                logoImage.show();
                $("#dlWidgetShopFor dt").text('Shop for Medicare Solutions');
                break;

            case Brand.Unbranded:
                shopForImage.attr('src', '/ols/images/quote/Shop_for_Medicare_Prescription_Drugs.png');
                $("#dlWidgetShopFor dt").text('Shop for Medicare Solutions');
                break;

            default:
                logoImage.attr('src', '/ols/Content/olspublic/images/home/logo_AnthemBCBS.png');
                shopForImage.attr('src', '/ols/images/quote/shop_for_header.png');
                logoImage.show();
                break;
        }

    }

    /********************************************
    Configures controls that appear in the widget
    *********************************************/
    function configureControls() {
        configureZipCode();
        configureDateOfBirth();
        configureCoverageDate();

        // Display the expanded widget once a product has been selected.
        $("#divWidget :input[name='optShopTypeGroup']").click(function() {
            shopTypeChanged();
            // If we have a zip code and medicare or dental is selected then check the location rules.
            if ($('#txtZipCode').val().length !== 0) {
                // Check if there are any problems with the location chosen by the user.
                if ($('#lblSingleCountyState').text().length !== 0) {
                    checkLocationRules(getProductType());
                }
            }
            else {
                showExpandedWidget();
                displayButtons();
            }
        });

        // Handle redirects for the saved quote link.
        // The live() method attaches a handler to the event for all current and future hyperlink elements.
        // Bind to hyperlinks that may appear in the the saved quote link.
        $('#lnkViewSavedQuote').live('click', function(e) {
            e.preventDefault();
            viewSavedQuote();
        });

        // Store the button that causes a submit action in an HTML-5 compliant custom attribute. 
        $("#divWidget :button").live('click', function(e) {
            $("#aspnetForm").attr("data-submitButton", e.currentTarget.id);
        });

        // Display Ezine in a modal if the 'learn more' button is clicked.
        $("#cmdLearnMore").click(function(e) {
            displayEzine();
        });

        // Handle the click event of the 'Go' button.
        $("#cmdGo").live('click', function(e) {
            handleGoButtonClick();
        });

        // Handle the Unicare product type selection (relevent for Unicare in year 2010 only).
        $("#divWidget :input[name='optUnicareProductGroup']").click(function(e) {
            // Dehighlight any existing failed validation.
            dehightlightDiv('divUnicare2010', ValidationStyle.Error, ValidationStyle.Valid);
            // Check if there are any problems for Unicare for year 2010 (this is not covered by rules)
            configureUnicare2010();
        });

        // Give the focus to the first available element.
        $("#divWidget :input:visible:enabled:first").focus();
    }

    /*******************************
    Initialises the zip code control
    ********************************/
    function configureZipCode() {
        $("#lblZipCode").prepend("<span class=\"error_asterix\">*</span> ");
        $("#lblCounty").prepend("<span class=\"error_asterix\">*</span> ");
    }

    /************************************
    Configures the coverage date controls
    *************************************/
    function configureDateOfBirth() {
        // Add a format mask to the date of birth text box.
        $("#txtWidgetDateOfBirth").mask("99/99/9999", { placeholder: " " });
        $("#txtWidgetDateOfBirth").val("mm/dd/yyyy");
        $("#txtWidgetDateOfBirth").blur(function() {
            if ($("#txtWidgetDateOfBirth").val().length === 0) {
                $("#txtWidgetDateOfBirth").val("mm/dd/yyyy");
            }
        });

        // [27-May-2010.AOC] Bug 8861: Hide the date picker when a key is pressed.
        $("#txtWidgetDateOfBirth").keydown(function(event) {
            $("#txtWidgetDateOfBirth").datepicker("hide");
        });

        // Configure the date picker.
        //var curDate = new Date();
        var currentMonth = localMonth;
        if (currentMonth.toString().length === 1) {
            currentMonth = '0' + currentMonth;
        }
        var currentDay = localDay;
        if (currentDay.toString().length === 1) {
            currentDay = '0' + currentDay;
        }
        var currentYear = localYear;
        $(function() {
            $("#txtWidgetDateOfBirth").datepicker({
                showOn: 'button',
                changeMonth: true,
                changeYear: true,
                defaultDate: '-65y',
                yearRange: '1905:' + currentYear, // Absolute year range
                buttonImage: '/ols/images/common/calendar_icon.gif',
                buttonImageOnly: true,
                buttonText: 'Date of Birth Calendar',
                showButtonPanel: true,
                closeText: 'Close',
                prevText: 'Previous',
                // Update the date of birth text box to be equal to the default date when opening the date picker.
                beforeShow: function(input, inst) {
                    if ($("#txtWidgetDateOfBirth").val() === "mm/dd/yyyy") {
                        $("#txtWidgetDateOfBirth").val(currentMonth + '/' + currentDay + '/' + (currentYear - 65));
                    }
                },
                onClose: function(dateText, inst) {
                    // A valid date has now been chosen so if it was shown as invalid then clear it.
                    dehighlightElement($("#txtWidgetDateOfBirth")[0], ValidationStyle.Error, ValidationStyle.Valid);
                }
            });
            // Remove the tooltip from the associated calender image.
            $('img.ui-datepicker-trigger').removeAttr("title");
        });
    }

    /************************************
    Configures the date of birth controls
    *************************************/
    function configureCoverageDate() {
        //var curDate = new Date();
        var currentMonth = localMonth;
        if (currentMonth.toString.length === 1) {
            currentMonth = '0' + currentMonth;
        }

        var currentYear = localYear;

        // Add years to the coverage year drop down.
        $("#cboCBYear").empty();
        $("#cboCBYear").append('<option value=' + currentYear + '>' + currentYear + '</option>');
        $("#cboCBYear").append('<option value=' + (currentYear + 1) + '>' + (currentYear + 1) + '</option>');

        // get the coverage year
        var coverageYear = currentYear;

        // For the coverage drop down, select the next to current month (the month index starts at zero).
        var nextMonth = (localMonth + 1) % 12;

        // if the next month is 0, then we should be at last month
        if (nextMonth == 0) nextMonth = 12;

        // if the next month is 1, then we should be at next year
        if (nextMonth == 1 && coverageYear == localYear) {
            coverageYear = parseInt(coverageYear) + 1;
        }

        // set the coverage month
        $("#cboCBMonth").val(nextMonth);

        // set the selected coverage year
        $("#cboCBYear").val(coverageYear);

        // If the coverage date changes and is valid then ensure that 'Learn More' button is hidden.
        $("#cboCBMonth,#cboCBYear").change(function(e) {
            if ($("#divLearnMoreButton:visible").length > 0) {
                $('#divPageMessages > div.info').remove();
                validateCoverageDate(nextYearPlansAvailableMonth);
            }
        });
    }

    //  function configureCoverageDate() {
    //    var curDate = new Date();
    //    var currentMonth = (new Date().getMonth());
    //    if (currentMonth.toString.length === 1) {
    //      currentMonth = '0' + currentMonth;
    //    }

    //    var currentYear = (new Date().getFullYear());

    //    // Add years to the coverage year drop down.
    //    $("#cboCBYear").append('<option value=' + currentYear + '>' + currentYear + '</option>');
    //    $("#cboCBYear").append('<option value=' + (currentYear + 1) + '>' + (currentYear + 1) + '</option>');

    //    // For the coverage drop down, select the next to current month (the month index starts at zero).
    //    var nextMonth = (curDate.getMonth() + 2) % 12;
    //    $("#cboCBMonth").val(nextMonth);
    //    if (curDate.getMonth() === 12) {
    //      $("#cboCBYear").val(currentYear + 1);
    //    }

    //    // If the coverage date changes and is valid then ensure that 'Learn More' button is hidden.
    //    $("#cboCBMonth,#cboCBYear").change(function(e) {
    //      if ($("#divLearnMoreButton:visible").length > 0) {
    //        $('#divPageMessages > div.info').remove();
    //        validateCoverageDate(nextYearPlansAvailableMonth);
    //      }
    //    });
    //  }

    /***********************************************
    Handles events that are raised by child controls
    ************************************************/
    function subscribeEvents() {
        // Unbind all events initially.
        $('body').unbind();

        // Subscribe to the 'zipCodeServiceCompleted' custom event
        // This event occurs after a call to the zip code service has completed.
        $('body').bind('zipCodeServiceCompleted', function(e, response) {
            zipCodeServiceCompletedHandler(response);
        });

        // Subscribe to the 'zipCodeKeyPressed' custom event
        // This event occurs after a valid key press in the zip code text box.
        $('body').bind('zipCodeKeyPressed', function(e, response) {
            // Remove any information messages.
            $('#divPageErrors > div[class=info]').remove();
            // Remove any rule engine messages.
            $('#divRuleEngineMessages > div[class=info]').remove();
            // Ensure the Learn More button is hidden.
            $("#divLearnMoreButton").hide();
        });

        // Subscribe to the selectedCountyChanged event.
        $('body').bind('selectedCountyChanged', function(e, response) {
            // Check if there are any problems with the product type/location chosen by the user.
            if ($('#lblSingleCountyState').text().length !== 0) {
                checkLocationRules(getProductType());
            }
        });
    }

    /*****************************************
    Handles the zipCodeService completed event
    ******************************************/
    function zipCodeServiceCompletedHandler(response) {
        zipCodeResultList = JSON.parse(response);
        clearInvalidZipCode();

        if (zipCodeResultList !== null && zipCodeResultList.length !== 0) {

            var localDate = new Date(Date.parse(zipCodeResultList[0].currentDateTimeinZone));
            localYear = localDate.getFullYear();
            localMonth = localDate.getMonth() + 1; // javascript is zero based
            localDay = localDate.getDate();

            if (!userReturning) {
                configureCoverageDate();
            }
            else {
                userReturning = false;
            }

            // If the initial context is populated then restore the county specified in the context.
            if (initialContext !== null) {
                $("#cboCounty").val(initialContext.County);
                initialContext = null;
            }

            // For anthem or bcbsga, make sure that the widget is expanded.
            if (brand === Brand.Anthem || brand === Brand.Georgia) {
                showExpandedWidget();
                displayButtons();
            }

            // Check if there are any problems with the product type/location chosen by the user.
            checkLocationRules(getProductType());

            // Check if there are any problems for Unicare for year 2010 (this is not covered by rules)
            configureUnicare2010();
        }
        else {
            // A zip code that does not exist or some other problem has occurred.
            if (validateZipCode() === false) {
                $('#divPageErrors').text('');
                highlightInvalidZipCode();
                return false;
            }
        }

        // Initialise to medicare for the anthem/bcbsga brands only (other brands remain unselected).
        if (brand === Brand.Anthem || brand === Brand.Georgia) {
            // Only do this if no radio button was already checked.
            if (getProductType() == ProductType.NotSet) {
                $('#optShopForMedicare').attr('checked', true);
                // fire event on the shop type changed
                shopTypeChanged();
            }
        }

        return true;
    }


    /**********************************************************
    Updates the CoverageBeginDate based on zipcode TimeZone returned from Utility Service
    ***********************************************************/
    function UpdateCoverageBeginDatesBasedOnTimeZone() {



    }

    /**********************************************************
    Fires when the radio button Medicare - non-Medicare changes
    ***********************************************************/
    function shopTypeChanged() {
        if (brand === Brand.Anthem || brand === Brand.Georgia) {
            if (getProductType() == ProductType.Medical) {
                // Add rules pertinent to Medical.
                addRequiredRule("#optMale", missingRequiredFieldsMessage);
                addRequiredRule("#optFemale", missingRequiredFieldsMessage);
                addRequiredDateRules("#txtWidgetDateOfBirth");
            }
            else {
                // Remove rules that are pertinent to Medical.
                removeRule('#optMale', 'required');
                removeRule('#optFemale', 'required');
                removeRule('#txtWidgetDateOfBirth', 'required dateUSA dateInFuture');
            }
        }
    }

    /*** Hide the medicare year end message ***/
    function hideMedicareYearEndMessage() {
        clearInterval(positionMedicareYearEndMessageTimer);
        $("#HomeMedicareYearEnd").hide();
    }

    /*** Show the medicare year end message ***/
    function showMedicareYearEndMessage() {
        $("#HomeMedicareYearEnd").show();
        positionMedicareYearEndMessage();
        clearInterval(positionMedicareYearEndMessageTimer);
        positionMedicareYearEndMessageTimer = setInterval(positionMedicareYearEndMessage, 1000);
    }

    var positionMedicareYearEndMessageTimer;

    /*** Show the medicare year end message only if current date between 1 oct and 30 nov ***/
    function showMedicareYearEndMessageInDateRange() {
        var currentDate = new Date();
        var currentYear = localYear;
        var MinWarningDate = new Date(currentYear, 10 - 1, 1, 0, 0, 0, 0); // 1 Oct
        var MaxWarningDate = new Date(currentYear, 11 - 1, 30, 23, 59, 59); // 30 Nov
        if ($("#divWidgetCoverageBegins").is(':visible') &&
      (currentDate >= MinWarningDate && currentDate <= MaxWarningDate)) {
            showMedicareYearEndMessage();
        } else {
            hideMedicareYearEndMessage();
        }
    }

    /*** Positions this message box to be to the right of the date entry ***/
    function positionMedicareYearEndMessage() {
        if ($("#HomeMedicareYearEnd").is(':visible')) {
            var targetY = $("#divWidgetCoverageBegins").offset().top + ($("#divWidgetCoverageBegins").outerHeight(false) / 2);
            var anchorY = $("#HomeMedicareYearEnd").css("margin-right").replace("px", "");
            var offsetParent = $("#HomeMedicareYearEnd").offsetParent().offset().top;
            $("#HomeMedicareYearEnd").css("top", targetY - anchorY - offsetParent);
        }
        if ($("#divWidgetCoverageBegins").is(':visible') == false) {
            $("#HomeMedicareYearEnd").hide();
        }
    }

    /************************************************************************
    Returns the current product type selected by the user (Medical or Health)
    *************************************************************************/
    function getProductType() {
        // Get the currently selected product type (if any). Assume medical as the default.
        var productType = $("#divWidget :input[name='optShopTypeGroup']:checked").val();

        // Determine the product type selected (if it was selected at all and if the option exists).
        if (typeof (productType) === 'undefined' || productType === null) {
            if (brand === Brand.Anthem || brand === Brand.Georgia) {
                return ProductType.NotSet;  // This value signifies no product type was selected.
            }
            else {
                // Other brands do do not have this option so assume Medical.
                return ProductType.Medical;
            }
        }
        else if (productType == ProductType.Medical) {
            return ProductType.Medical;
        }
        else if (productType == ProductType.Health) {
            return ProductType.Health;
        }
        else {
            return ProductType.NotSet;
        }
    }

    /*******************************
    Displays Ezine in a modal dialog
    ********************************/
    function displayEzine() {
        var width = screen.width;

        width = 780;

        var $dialog = $('<div></div>')
    .load('/ols/nav.cds?site=olspublic&cat=ezine&page=modal&edoc=medicare-info', function() { $.EzineReady(); })
    .dialog({
        width: width,
        draggable: false,
        modal: true,
        dialogClass: 'olsmodal',
        position: 'top',
        autoOpen: false,
        title: 'Learn more',
        buttons: { "Close": function() {
            $(this).dialog("close");
            $dialog.remove();
        }
        }
    });

        $dialog.dialog('open');
    }

    /***************************************
    Configures the validation for the widget
    ****************************************/
    function addValidation() {
        $("#aspnetForm").validate({
            // Override the onfocusout event so that it does nothing. Previously it was firing 
            // validation on the datepicker when a date was clicked.
            onfocusout: false,
            errorClass: ValidationStyle.Error,
            validClass: ValidationStyle.Valid,
            errorElement: "div",
            errorPlacement: function(error, element) {
                displayWidgetMessage(MessageType.ValidationError, error, element);
            },
            highlight: function(element, errorClass) {
                highlightElement(element, errorClass);
                // This prevents the error message being modified to display the rule message. 
                // i.e. there should be one generic message displayed for validation errors.
                $('#divPageErrors').html('');
            },
            unhighlight: function(element, errorClass, validClass) {
                dehighlightElement(element, errorClass, validClass);
            },
            submitHandler: handleSubmit,
            rules: {
                txtZipCode: {
                    required: true,
                    digits: true,
                    minlength: 5
                },
                optUnicareProductGroup: {
                    required: true
                },
                optShopTypeGroup: {
                    required: true
                }
            },
            messages: {
                txtZipCode: {
                    required: missingRequiredFieldsMessage,
                    minlength: invalidZipCodeMessage
                },
                optUnicareProductGroup: {
                    required: selectProductTypeMessage
                },
                optShopTypeGroup: {
                    required: missingRequiredFieldsMessage
                }
            }
        });

        // Add rules for optGenderGroup and txtWidgetDateOfBirth
        addRequiredRule("#optMale", missingRequiredFieldsMessage);
        addRequiredRule("#optFemale", missingRequiredFieldsMessage);
        addRequiredDateRules("#txtWidgetDateOfBirth");

        // Change rules for different brands.
        var settings = $('#aspnetForm').validate().settings;
        var currentYear = (new Date().getFullYear());
        if (brand === Brand.Unicare || brand === Brand.Kansas || brand === Brand.KansasCity) {
            delete settings.rules.optGenderGroup;
            delete settings.messages.optGenderGroup;
            delete settings.rules.txtWidgetDateOfBirth;
            delete settings.messages.txtWidgetDateOfBirth;
        }

        if (!(brand === Brand.Unicare && currentYear === 2010)) {
            delete settings.rules.optUnicareProductGroup;
            delete settings.messages.optUnicareProductGroup;
        }

        // If the non-medicare option has been selected then remove gender and data or birth validation.
        if (brand === Brand.Anthem || brand === Brand.Georgia) {
            if (getProductType() == ProductType.Health) {
                removeRule('#optMale', 'required');
                removeRule('#optFemale', 'required');
                removeRule('#txtWidgetDateOfBirth', 'required dateUSA dateInFuture');
            }
        }

        if (!(brand === Brand.Anthem && brandState === 'ca')) {
            delete settings.rules.optShopTypeGroup;
            delete settings.messages.optShopTypeGroup;
        }

    }

    /**********************************************
    Adds a 'Required' validation rule to a selector
    ***********************************************/
    function addRequiredRule(selector, message) {
        $(selector).rules("add", { required: true, messages: { required: message} });
    }

    /*****************************************************
    Removes the specified validation rules from a selector
    ******************************************************/
    function removeRule(selector, toRemove) {
        $(selector).rules("remove", toRemove);
    }

    /*********************************************************************
    Adds a 'Required' validation rule to an element (or group of elements)
    **********************************************************************/
    function addRequiredDateRules(selector) {
        $(selector).rules("add", {
            customRequired: true,
            dateUSA: true,
            dateInFuture: true,
            messages: {
                customRequired: missingRequiredFieldsMessage,
                dateUSA: validDateOfBirthMessage,
                dateInFuture: dateOfBirthInFutureMessage
            }
        });
    }


    /**********************************************
    Adds customised validation methods for controls
    ***********************************************/
    function addCustomValidationMethods() {

        // Date require a custom validation for required that checks for "mm/dd/yyyy" in the textbox
        $.validator.addMethod(
        "customRequired",
        function(value, element) {
            return this.optional(element) || (jQuery.trim(value).length > 0 && value != "mm/dd/yyyy" && jQuery.trim(value) != "/ /");
        }
      );

        // Date should be validated appropriately 1900 onwards
        AddDateValidationMethod("dateUSA", validDateMessage);

        // Method to determine if the date of birth is in the future.
        AddDateInFutureValidationMethod("dateInFuture", dateOfBirthInFutureMessage);
    }

    /****************************************************************************
    Expands the Anthem widget which initially only shows the types of insurance
    required. Once an option is selected the remainder of the widget is displayed
    *****************************************************************************/
    function showExpandedWidget() {
        // Hide buttons
        $("#divLearnMoreButton").hide();
        $("#divGoButton").hide();
        $('#divWidgetButtons').hide();

        // Expand the widget depending on the product type chosen.
        if (getProductType() == ProductType.Medical) {
            $('#divWidgetContainer').height(120).fadeIn('fast', function() {
                // Animation complete.
                $("#widgetFormBot").css("display", "block");
                $('#divWidgetContainer').attr("style", "display:block");
            });

            // Hide all controls apart from the zip code (and county)
            $('.hiddenForNonMedicare').removeClass('hiddenForNonMedicare');
            $("#divWidgetSavedQuoteLink").show();
            showMedicareYearEndMessageInDateRange();
        }
        else if (getProductType() == ProductType.Health) {
            $('#divWidgetContainer').height(130).fadeIn('slow', function() {
                // Animation complete.
                $("#widgetFormBot").css("display", "block");
            });

            // Hide all controls apart from the zip code (and county)
            $("#divWidgetSavedQuoteLink").hide();
            $("#divWidgetGender").addClass('hiddenForNonMedicare');
            $("#divWidgetDateOfBirth").addClass('hiddenForNonMedicare');
            $("#divWidgetCoverageBegins").addClass('hiddenForNonMedicare');
            $("#HomeMedicareYearEnd").addClass('hiddenForNonMedicare');
            $("#divWidgetSavedQuoteLink").show();
        }
    }

    /************************************************************************************
    Displays the buttons at the bottom of the widget (product type dependent).
    This is called seperately to showExpandedWidget in order to reduce flicker caused
    by momentarily showing buttons and hiding them again due to a rule violation message.
    *************************************************************************************/
    function displayButtons() {
        if (getProductType() == ProductType.Medical) {
            $('#divWidgetButtons').show();
            // hide the message - bug fix 11102
            $('#divPageMessages').hide();
        }
        else if (getProductType() == ProductType.Health) {
            $('#divGoButton').show();
        }
        // For Unicare in the year 2010 there is a different configuration.
        configureUnicare2010();
        showMedicareYearEndMessageInDateRange();
    }

    /******************************
    Checks if the zip code is valid
    *******************************/
    function validateZipCode() {
        var errors = false;
        var zipCode = $("#txtZipCode").val();

        if (zipCodeResultList === null || zipCodeResultList.length === 0 || zipCode.length < 5) {
            highlightInvalidZipCode();
            errors = true;
        }

        return !errors;
    }

    /**********************************************************************
    Checks that the coverage start date is not more than 12 months from now
    ***********************************************************************/
    function validateCoverageDate(nextYearPlansStartMonth) {
        //var curDate = new Date();
        var currentMonth = localMonth;
        var currentYear = localYear;
        var currentMonthStartDate = (new Date(currentYear, currentMonth, 1));
        var coverageMonth = $("#cboCBMonth").val();
        var coverageYear = $("#cboCBYear").val();
        var coverageDate = new Date(coverageYear, coverageMonth, 1);
        var message = null;

        // For the coverage drop down, select the next to current month (the month index starts at zero).
        var nextMonth = (localMonth + 1) % 12;

        // if the next month is 0, then we should be at last month
        if (nextMonth == 0) nextMonth = 12;

        var nextYear = localYear;

        // if the next month is 1, then we should be at next year
        if (nextMonth == 1 && coverageYear == localYear) {
            nextYear = parseInt(nextYear) + 1;
        }

        // normailise as months index starts at 0 not 1
        nextMonth = nextMonth - 1;

        if (dateDifference(currentMonthStartDate, coverageDate, "months") >= 13 && (brand != Brand.Kansas && brand != Brand.KansasCity)) {
            // If the coverage date is set to be more than 12 months in the future then display an error.
            // An exception to this is bcbsks.
            message = coverageDateInFutureMessage.replace('{0}',
        $("#cboCBMonth option")[currentMonth].text + ' ' + coverageYear);
        }
        else if (dateDifference(currentMonthStartDate, coverageDate, "months") <= 0) {
            // If the coverage date is equal to the current month or earlier then display an error.
            message = coverageDateInPastMessage.replace('{0}',
          $("#cboCBMonth option")[nextMonth].text + ' ' + nextYear);
        }
        else if ((brand == Brand.Unicare || brand == Brand.Kansas || brand === Brand.KansasCity) && (currentMonth < nextYearPlansStartMonth) && coverageYear == (currentYear + 1)) {
            // For unicare and bcbsks if the current date is before October 1st and the coverage
            // year is next year then display an error.
            // todo: re-enable this message when done with hack for 2012 testing
            //message = coverageDatePreOctoberMessage.replace('{0}', currentYear);
        }

        if (message !== null) {
            displayWidgetMessage(MessageType.InvalidCoverageDate, message + ' ', null);
            $('#divPageErrors').show();
            $('#divLearnMoreButton').show();
            $('#divWidgetButtons').hide();
            return false;
        }
        else {
            $('#divLearnMoreButton').hide();
            $('#divWidgetButtons').show();
            return true;
        }
    }

    /*****************************************************************
    Saves the current user input in the quote identity session context
    ******************************************************************/
    function saveIdentityContext(callbackFunction) {
        CallWCFModel('POST', saveWidgetContextEndPoint, buildWidgetRequestObject(), callbackFunction);
    }

    /*********************************************************
    Saves the current user input in the quote identity session
    context and then redirects to a specified URL.
    **********************************************************/
    function saveIdentityContextWithRedirect(url, quotearea) {
        CallWCFModel('POST', saveWidgetContextEndPoint, buildWidgetRequestObject(quotearea), function(resultJSON) {
            serviceSaveQuoteContextSucceededRedirect(resultJSON, url);
        }
    );
    }

    /*******************************************************************
    Loads the current user input from the quote identity session context
    ********************************************************************/
    function loadIdentityContext() {
        // Call the WCF service
        CallWCFModel('POST', getWidgetContextEndPoint, "{}", serviceLoadQuoteContextSucceeded);
    }

    /*********************************************************************
    Builds the JSON request object (used when saving the identity context)
    **********************************************************************/
    function buildWidgetRequestObject(quoteAreaType) {
        // Get the input form field values
        var dateOfBirth = $('#txtWidgetDateOfBirth').val();
        var gender = $("#divWidget :input[name='optGenderGroup']:checked").val();
        var zipCode = $("#txtZipCode").val();
        var county = $('#cboCounty :selected').val() ? $('#cboCounty :selected').val() : $('#lblSingleCountyName').text();
        var selectedCountyIndex = $("#cboCounty").attr("selectedIndex");
        var city = (zipCodeResultList === null) ? null : zipCodeResultList[selectedCountyIndex].city;
        var state = (zipCodeResultList === null) ? null : zipCodeResultList[selectedCountyIndex].stateCode;
        var coverageDate = $("#cboCBMonth").val() + '/01/' + $("#cboCBYear").val();
        var senior = 0; // SENIOR enumerator
        var preferenceId = 0;
        var productType = getProductType();

        if (gender === null || gender === undefined) {
            gender = 0;
        }

        if (quoteAreaType === null || quoteAreaType === undefined) {
            quoteAreaType = QuoteAreaType.QuoteWizard;
        }

        var selectedCoverage = CoverageType.All;

        if (brand === Brand.Unicare || brand === Brand.KansasCity || brand === Brand.Kansas) {
            selectedCoverage = CoverageType.PDP;
        }

        // Build the request JSON object
        var requestObject = { "widgetData": {
            "DateOfBirth": dateOfBirth,
            "Gender": gender,
            "MarketSegment": senior,
            "ProductType": productType,
            "ZipCode": zipCode,
            "City": city,
            "County": county,
            "State": state,
            "CoverageEffectiveDate": coverageDate,
            "SelectedCoverage": selectedCoverage,
            "PreferenceId": preferenceId,
            "UserQuoteArea": quoteAreaType
        },
            "updatePersonalInfo": true
        };

        return JSON.stringify(requestObject);
    }

    /********************************************************************
    Check if there are any issues with the location selected by the user.
    This is done by making an AJAX call to the rules engine.
    *********************************************************************/
    function checkLocationRules(productType) {
        // Remove any existing messages
        $('#divPageMessages > div').remove();

        var countyValue = $('#cboCounty :selected').val() ? $('#cboCounty :selected').val() : $('#lblSingleCountyName').text();
        var stateValue = $('#cboCounty :selected').text() ? ($('#cboCounty :selected').text().substr($('#cboCounty :selected').text().length - 2)) : $('#lblSingleCountyState').text();

        var ruleRequest = '{ "ruleRequest": {' +
                          '"County": "' + countyValue + '", ' +
                          '"State": "' + stateValue + '", ' +
                          '"ZipCode": "' + $("#txtZipCode").val() + '", ' +
                          '"ProductType": "' + productType + '" } }';
        CallWCFModel('POST', rulesServiceEntryPoint, ruleRequest, ruleQueryCompleted);
    }

    /************************************************************************
    Acts as the callback for the JQuery save context call to the WCF service.
    It is called once the quote user identity context has been successfully 
    saved in the session. If a redirection URL is specified then navigation
    to that URL occurs.
    *************************************************************************/
    function serviceSaveQuoteContextSucceededRedirect(resultJSON, redirectionURL) {
        if (redirectionURL.length !== null) {
            NavigateWithReferrer(redirectionURL);
        }
    }

    /**********************************************************************
    This function is the callback for the JQuery call to the WCF service.
    It is called once the quote user identity context has been successfully
    loaded from the session.
    ***********************************************************************/
    function serviceLoadQuoteContextSucceeded(quoteContext) {
        if (quoteContext !== null && quoteContext.ZipCode !== null && quoteContext.ZipCode.length > 0) {
            initialContext = quoteContext;
            // Populate the controls with data from the session.
            // Note that the we cannot restore the county at this point because the zip code
            // service needs to be called in order to get the counties. Thus, the county drop is
            // restored once the zip code query service has completed.
            populateControls(quoteContext.ProductType, quoteContext.ZipCode, quoteContext.Gender,
        quoteContext.DateOfBirth, quoteContext.CoverageEffectiveDate);
        }
        else {
            // Ensure the radio buttons are cleared if there is no context.
            $("#divWidget :input:radio").attr("checked", "");

            if (quoteContext !== null && quoteContext.CoverageEffectiveDate != null) {
                var dateParams = quoteContext.CoverageEffectiveDate.split("/");
                $("#cboCBMonth").val(parseInt(dateParams[0], 10));
                $("#cboCBYear").val(parseInt(dateParams[2], 10));
            }
        }
        // Ensure the widget is displayed
        $("#divWidget").show();
    }

    /**************************************
    Populates the widget controls with data
    ***************************************/
    function populateControls(productType, zipCode, gender, dateOfBirth, coverageDate) {
        // Set the product type
        if (productType == ProductType.Medical) {
            $('#divWidget :input[name="optShopTypeGroup"]')[0].checked = true;
        }
        else if (productType == ProductType.Health) {
            $('#divWidget :input[name="optShopTypeGroup"]')[1].checked = true;
        }

        // Ensure the zip code details are retrieved.
        $("#txtZipCode").val(zipCode ? zipCode : $("#txtZipCode").val());

        // Set the gender
        if (gender !== null) {
            $('#divWidget :input[name="optGenderGroup"]')[gender].checked = true;
        }

        // Set the date of birth
        $("#txtWidgetDateOfBirth").val(dateOfBirth ? dateOfBirth : $("#txtWidgetDateOfBirth").val());

        // Set the coverage date
        if (coverageDate !== null) {
            userReturning = true;
            var dateParams = coverageDate.split("/");
            $("#cboCBMonth").val(parseInt(dateParams[0], 10));
            $("#cboCBYear").val(parseInt(dateParams[2], 10));
        }

        // Enable the form. Ensure the widget is displayed (show the expanded widget ifor Anthem & BCBSGA).
        EnableInputForm('#divWidget :input', '#divWidget .hasDatepicker');
        if (brand === Brand.Anthem || brand === Brand.Georgia) {
            if (zipCode === 0) {
                $('#divWidgetContainer').show();
            }
            showExpandedWidget();
            displayButtons();
        }
    }

    /*******************************************************************************
    This function is the callback for the JQuery call to the rule engine WCF service
    ********************************************************************************/
    function ruleQueryCompleted(response) {
        // Remove any previous classes that were added due to rule validation errors.
        $('.hiddenForZipCodeRuleViolation').removeClass('hiddenForZipCodeRuleViolation');

        // Process the different types of messages returned in the response.
        processMessageActions(response.MessageActionCollection);
        processCSSActions(response.CssActionCollection);

        // Ensure the widget is displayed  
        $("#divWidget").show();
    }

    /***********************************************************************
    Handles message rules that were returned as broken (message rules return
    a message to be displayed if a rule is matched/broken).
    ************************************************************************/
    function processMessageActions(messageActionList) {
        // Process the message actions returned from the rules engine.
        var emptyMessage = false;
        if (messageActionList !== null && messageActionList.length !== 0) {
            var urlInfo = messageActionList[0].Url;
            if (urlInfo !== null && urlInfo.ImmediateRedirect !== null && urlInfo.ImmediateRedirect === true) {
                // A rule has been broken and there is to be an immediate redirection. No message or button is shown.
                if (urlInfo.OpenWindow === true) {
                    // There is an immediate redirection, no need to show a message.
                    openBrowserWithRedirect(urlInfo.Link);
                }
                else {
                    // Navigate to the new link within the current page.
                    NavigateWithReferrer(urlInfo.Link);
                }
            }
            else if (messageActionList[0].Message === null || messageActionList[0].Message.length === 0) {
                // This is where a rule has been broken and there is no message to display. In this case just
                // display the 'Go' button. When the user clicks it they are redirected to the URL from the rule.
                emptyMessage = true;
                $("#cmdGo").attr("data-redirectURL", urlInfo.Link);
                $("#cmdGo").attr("data-openWindow", urlInfo.OpenWindow);
                $("#cmdGo").attr("data-isExternalLink", urlInfo.IsExternalLink);
                $("#cmdGo").attr("data-showDisclaimer", urlInfo.ShowDisclaimer);
            }
            else {
                // A rule has been broken. Display the message returned by the rule.
                displayWidgetMessage(MessageType.RuleViolation, messageActionList[0].Message, null);
            }

            // Dehighlight any existing failed validation elements.
            dehightlightDiv('divWidgetContainer', ValidationStyle.Error, ValidationStyle.Valid);

            // Disable the form (but enable the txtZipCode, learn more button and product type radio buttons)
            DisableInputForm('#divWidget :input', '#divWidget .hasDatepicker');
            $('#txtZipCode').removeAttr("disabled");
            $('#cboCounty').removeAttr("disabled");
            $('#txtZipCode').blur();
            $('#optShopForMedicare').removeAttr("disabled");
            $('#optShopForOther').removeAttr("disabled");
            $('#optDrugPlan').removeAttr("disabled");
            $('#optAdvantage').removeAttr("disabled");
            $('#cmdLearnMore').removeAttr("disabled");

            // Store the Id of the broken rule.
            $("#divPageMessages").attr("data-RuleId", messageActionList[0].Id);
        }
        else {
            // Re-enable the form
            EnableInputForm('#divWidget :input', '#divWidget .hasDatepicker');
        }

        // Ensure the widget is displayed (it may have been hidden to avoid flicker).
        if (brand === Brand.Anthem || brand === Brand.Georgia) {
            showExpandedWidget();
        }

        // Display the correct buttons (product type dependent) if there is no rule violation.
        if (messageActionList === null || messageActionList.length === 0) {
            displayButtons();
        }

        // For a broken rule with an empty message the 'Go' button is to be shown. 
        // Clicking on this navigates to the redirect URL. This is commonly used to go to PlanFinder.
        if (emptyMessage === true) {
            $("#divGoButton").show();
            EnableInputForm('#divWidget :input', '#divWidget .hasDatepicker');
        }
    }

    /************************************************************************
    Handles css rules that were returned as matches (css rules return styling
    and configuration data if a rule is matched).
    *************************************************************************/
    function processCSSActions(cssActionList) {
        // Process the css actions returned from the rules engine.
        var logoImage = $('#logoImage');
        var redirectionUrl = null;
        if (cssActionList !== null && cssActionList.Length !== 0) {
            if (cssActionList[0].LogoUrl !== null && role !== 'unbranded' && cssActionList[0].LogoUrl != '') {
                logoImage.attr('src', cssActionList[0].LogoUrl);
                logoImage.show();
            }
            redirectionUrl = cssActionList[0].RedirectionUrl;
        }

        // If the role is unbranded and the brand is BCBSKS and the user has entered a Kansas State
        // or Kansas City zip code then the user is to be redirected to the relevent Kansas site.
        if (role == 'unbranded' && brand == Brand.Kansas) {
            var selectedCountyIndex = $("#cboCounty").attr("selectedIndex");
            var city = (zipCodeResultList === null) ? null : zipCodeResultList[selectedCountyIndex].city;
            var state = (zipCodeResultList === null) ? null : zipCodeResultList[selectedCountyIndex].stateCode;

            var qstring = '?ZipCode=' + $('#txtZipCode').val() + '&State=' + state;

            var exceptionToRule = redirectionUrl.indexOf('partdkansascity');

            if ((city === 'Kansas City' && exceptionToRule !== -1) || exceptionToRule !== -1) {
                displayWidgetMessage(MessageType.RuleViolation, navigateToKansasCityMessage.replace('{0}', redirectionUrl).replace('{1}', qstring), null);
            }
            if ((state === "KS" && city !== 'Kansas City' && exceptionToRule === -1) || (state === "KS" && city === 'Kansas City' && exceptionToRule === -1)) {
                displayWidgetMessage(MessageType.RuleViolation, navigateToKansasStateMessage.replace('{0}', redirectionUrl).replace('{1}', qstring), null);
            }
        }
    }

    /******************
    Views a saved quote
    *******************/
    function viewSavedQuote() {
        // Save the current context first.
        saveIdentityContext(saveIdentityContextSavedViewQuote);
    }

    /****************************************
    Callback when saving the identity context
    after clicking on the view quote link.
    *****************************************/
    function saveIdentityContextSavedViewQuote(reponse) {
        var postLogOnAction = '{ "request" : { "RedirectUrl" : "' + myAccountUrl + '", "ActionType" : ' + '"RetrieveSettings"' + ' } }';
        SavePostLogOnAction(postLogOnAction);
    }

    /**************************************************
    Saves the current log on action and the current Url
    so that the login page can redirect back to here.
    ***************************************************/
    function SavePostLogOnAction(postLogOnAction) {
        CallWCFModel('POST', wizardServiceEntryPoint + '/PersistPostLogOnAction', postLogOnAction, SavePostLogOnActionSuccess(postLogOnAction));
    }

    /*****************************************************************
    This method handles the success of save post-logon
    action. The user will be redirected to their account page. If they
    are not logged on then SiteMinder will detect this and will direct
    them automatically to the log-in page.
    ******************************************************************/
    function SavePostLogOnActionSuccess(response) {
        NavigateWithReferrer(myAccountUrl);
    }

    /************************************************************
    Opens a new browser window and redirects to the specified URL
    *************************************************************/
    // Open a new browser window and navigate to the link.
    // The code below sidesteps the IE popup blocker by creating a fake link and clicking it.
    function openBrowserWithRedirect(url) {
        // Open a new browser window and navigate to the link.
        // The code below sidesteps the IE popup blocker by creating a fake link and clicking it.

        // Bug Fix DL.24.06.2011 - This function was checking if fakeLink.click() returned 'undefined' as apparently IE was the only browser to do so.
        // FF5 now returns a function for fakeLink.click() so this was causing FF5 into the IE specific hack.
        // Changed to use $ browser detection.
        // Similar change made in function NavigateWithReferrer(url) in global.js
        var fakeLink = document.createElement("a");
        if ($.browser.msie) {
            fakeLink.href = url;
            fakeLink.target = "_blank";
            document.body.appendChild(fakeLink);
            fakeLink.click();   // click() method is defined in IE only - nope, FF5 does too
        } else {
            window.open(url);  // For non-IE browsers
        }
    }

    /*************************************************************************
    Configures Unicare for the year 2010. All relevent configuration goes here
    **************************************************************************/
    function configureUnicare2010() {
        if (brand === Brand.Unicare && new Date().getFullYear() === 2010) {
            $("#divUnicare2010").show();
            $("#dlWidgetShopFor").hide();
            $("#divWidgetSavedQuoteLink").show();

            // hide the Go button
            $("#divGoButton").hide();

            var selectedUnicareType = $("#divWidget :input[name='optUnicareProductGroup']:checked").val();

            if (selectedUnicareType === null) {
                $('#imgShopFor').attr('src', '/ols/images/quote/shop_for_header.png');
                $("#divWidgetCoverageBegins").hide();
                $('#divWidgetButtons').hide();
                hideMedicareYearEndMessage();
            }
            else if ($("#optAdvantage").is(':checked')) {
                $("#divWidgetCoverageBegins").hide();
                $('#divWidgetButtons').hide();
                $("#divWidgetSavedQuoteLink").hide();
                hideMedicareYearEndMessage();

                // For unicare 2010 there is a special case not covered in the rules (it is not in the
                // rules because it applied to the year 2010 only). For MA do an immediate redirect.
                var planFinderURLWithZip = planFinderUrl + '?brand=UNICARE';
                //LeavingSiteModal(planFinderURLWithZip); // Shows leaving site message
                // openBrowserWithRedirect(planFinderURLWithZip); // Does not show leaving site message

                // show the Go button
                $("#divGoButton").show();

                // set attributes on go button
                $("#cmdGo").attr("data-redirectURL", planFinderURLWithZip);
                $("#cmdGo").attr("data-openWindow", "False");
                $("#cmdGo").attr("data-isExternalLink", "False");
                $("#cmdGo").attr("data-showDisclaimer", "False");
            }
            else {
                // The Drug Plan option is selected
                $("#divWidgetCoverageBegins").show();
                $('#divWidgetButtons').show();
                showMedicareYearEndMessageInDateRange();
            }
        }
    }

    /****************************************
    Acts as handler for the 'Go' button click
    *****************************************/
    function handleGoButtonClick() {
        // The 'Go' button is only used for the non-Medicare option. The URL to redirect to is
        // determined from a call to the rules engine. Here we process the redirect.
        var redirectUrl = $("#cmdGo").attr("data-redirectURL");

        // Inject agent connect parameters
        redirectUrl = InjectAgentConnectParameters(redirectUrl);

        // if the brand is unicare
        if (brand === Brand.Unicare && new Date().getFullYear() === 2010) {
            // populate the link with zip code
            if ($("#txtZipCode").val() !== null && $("#txtZipCode").val().length > 0) {
                redirectUrl += '&zipcode=' + $("#txtZipCode").val();
            }
            else {
                // we want the zip code, reset the redirect url
                redirectUrl = undefined;
            }
        }

        var openWindow = $("#cmdGo").attr("data-openWindow");
        var isExternalLink = $("#cmdGo").attr("data-isExternalLink");
        var showDisclaimer = $("#cmdGo").attr("data-showDisclaimer");
        if (redirectUrl != undefined && redirectUrl !== null && redirectUrl.length !== 0) {
            if (isExternalLink) {
                if (showDisclaimer == true) {
                    if (openWindow == true) {
                        // External URL so show a disclaimer message. Open in a new browser window.
                        LeavingSiteModal(redirectUrl, 'True');
                    }
                    else {
                        // External URL so show a disclaimer message. Open in the current browser window.
                        LeavingSiteModal(redirectUrl, 'False');
                    }
                }
                else {
                    if (openWindow == true) {
                        // External URL but do not show a disclaimer message. Open in a new browser window.
                        window.open(redirectUrl);
                    }
                    else {
                        window.location.href = redirectUrl;
                    }
                }
            }
            else {
                // Redirect using the existing window.
                saveIdentityContextWithRedirect(redirectUrl, null);
            }
        }
    }

    /*******************************************************************
    Acts as an error handler for any failed JQuery calls to WCF services
    ********************************************************************/
    function serviceFailed(error) {
        // Ensure the widget is displayed  
        $("#divWidget").show();
        alert("An error occurred:\r\n\r\n" + error.Message);
    }

    /****************************************************************
    Shows an error message when an invalid zip code has been detected
    *****************************************************************/
    function highlightInvalidZipCode() {
        displayWidgetMessage(MessageType.InvalidZipCode, genericValidationError, $("#txtZipCode"));
    }

    /****************************************************************
    Take a string (url, message, etc) and injects agent connect parameters if required
    *****************************************************************/
    function InjectAgentConnectParameters(request) {
        // Append the agent connect url if required
        if (request.indexOf('AgentConnect=') != -1) {
            var agentConnectUrl = $("#divWidget input[id*=hdnAgentConnectUrl]").val();

            if (agentConnectUrl.length > 0) {
                // Deserialise the agent connect string
                agentConnectUrl = JSON.parse(agentConnectUrl);

                if (agentConnectUrl.length > 0) {
                    // Check if state is already part of the request - if so remove state from agentConnectUrl
                    if (request.indexOf('&state=') != -1) {
                        var regex = new RegExp('[\\?&]state=([^&#]*)');
                        var state = regex.exec(agentConnectUrl);

                        if (state != null) {
                            agentConnectUrl = agentConnectUrl.replace(state[0], '');
                        }
                    }
                }
            }

            // Encode the agent connect url
            agentConnectUrl = encodeURI(agentConnectUrl);

            request = request.replace('&AgentConnect=', agentConnectUrl);
        }

        return request;
    }

})(jQuery);

