/* Minification failed. Returning unminified contents.
(6085,32-37): run-time error JS1137: 'catch' is a new reserved word and should not be used as an identifier: catch
(6186,34-39): run-time error JS1137: 'catch' is a new reserved word and should not be used as an identifier: catch
 */
if (!(window.SVGSVGElement)) {
    document.documentElement.className += ' no-svg'
} else {
    document.documentElement.className += ' yes-svg'
}

function isMobile() {
    return navigator.userAgent.match(/(iPhone)|(iPod)|(iPad)|(android)|(Android)|(webOS)|(IEMobile)/i);
}

function maxLengthCheck(object) {
    if (object.value.length > object.maxLength) {
        object.value = object.value.slice(0, object.maxLength);
    }
}

function formatSelectedValue(bulkpremium, briefCode) {
    var result = formatDollar(bulkpremium.fn.getSelectedValue(briefCode))
    if (result === "Unlimited") {
        return "Unlimited <sup>~</sup>";
    }

    return result;
}

function formatDollar(obj, stringify) {
    if (obj === null || obj === undefined) {
        return '—';
    }

    // observable object that has amount
    var str = obj;
    if (typeof (obj) === 'object' && obj.Amount !== undefined && typeof (obj.Amount) == 'function') {
        str = obj.Amount();
        if (parseFloat(str) == 0) {
            return '—'
        }
        if (obj.Text) {
            return ko.utils.unwrapObservable(obj.Text);
        }
    }

    if (typeof (str) != 'string') str = str.toString();

    if (stringify === true && str == '0') {
        return 'Nil';
    }

    if (stringify === true && /^[9]{6,}$/.test(str)) {
        return 'Unlimited';
    }

    return "$" + str.replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,").replace(".00", "");
};

$("document").ready(function () {

    if (isMobile()) {
        $('#PolicyBenefitPopupDiv').click(function () {
            $('li.highlighted').removeClass('highlighted');
            $(this).hide();
        });

        $('#BenefitPopupDiv').click(function () {
            $('.benefit-div.highlighted').removeClass('highlighted');
            $(this).hide();
        });

    }

});

function customViewCode(viewModel) {
    viewModel.MetaData.IsEditingTrip = ko.observable();
    viewModel.MetaData.DisplayMobileSummary = ko.observable();

    if ($('.top-widget-wrapper')[0] || $('#plan-summary')[0]) {

        viewModel.MetaData.Destinations = ko.computed(function () {
            var items = ko.utils.arrayFilter(viewModel.Destinations(), function (item) { return ko.unwrap(item.BriefCode) != null; });
            if (items.length > 0) {
                return formatPlanSummary(ko.utils.arrayMap(
                items, function (item) {
                    return ko.unwrap(item.Country.Description) + (item.Country.Location && item.Country.Location.Description ? ' (' + ko.unwrap(item.Country.Location.Description) + ')' : '');
                }));
            } else {
                return 'Not Selected';
            }
        }, null, { deferEvaluation: true });

        viewModel.MetaData.AllTravellerAges = ko.computed(function () {
            return ko.utils.arrayMap(viewModel.MetaData.AllTravellers(), function (item) {
                return item.MetaData.age();
            }).join(', ');
        })

        if (viewModel == $$.policy) {
            viewModel.MetaData.DestinationsLabelShowAll = ko.observable();
            viewModel.MetaData.DestinationsLabelShowAll.subscribe(function (newValue) {
                var div = $('.top-widget-wrapper .destination')[0];
                $(div).toggleClass('open');
            });

            viewModel.MetaData.showShowModeDestinationDetails = ko.observable();
            //Calculate if the countries list is too small for it's div and show/hide the show more buttons 
            viewModel.MetaData.Countries.subscribe(function () {
                fixDestinations(viewModel);
                var div = $('.top-widget-wrapper .destination')[0];
                if (div) {
                    var shouldShow = (div.scrollWidth > div.clientWidth || div.clientHeight > ($(div).css('line-height').replace('px', '') * 1));
                    viewModel.MetaData.showShowModeDestinationDetails(shouldShow);
                }
            });
        } else {
            viewModel.MetaData.Countries.subscribe(function () {
                fixDestinations(viewModel);
            });
        }

        var hasPlan = viewModel.Plan() && viewModel.Plan().PlanId;
        var hasBQQ = _session.quickQuote && _session.quickQuote.BulkPremiums && _session.quickQuote.BulkPremiums.length > 0;
        viewModel.MetaData.IsEditingTrip(!(hasPlan || hasBQQ));

        
        viewModel.MetaData.DisplayMobileSummary.subscribe(function (value) {
            if (!value) {
                viewModel.MetaData.IsEditingTrip(false);
            }
        });

        viewModel.MetaData.IsEditingTrip.subscribe(function (value) {
            viewModel.MetaData.quoteIsInvalid(value);
            viewModel.MetaData.DisplayMobileSummary(value);
            if (value) {
                $$.fn.CopyQuoteDataToQuote($$.policy, $$.newPolicy);
            }
            //block scroll when editing quote in mobile devices
            if (value && isMobile()) {
               $(".container.clearfix.content-wrapper").addClass('blockScroll')
            }
            else {
               $(".container.clearfix.content-wrapper").removeClass('blockScroll')
            }
            //force the scroll to re-evaluate to push the page down if required.
            setTimeout(function () { $(window).scroll() }, 100);
        });

        viewModel.MetaData.AllTravellersLabel = ko.computed(function () {

            var adultAges = viewModel.PolicyHolders().length;
            var dependantAges = viewModel.PolicyDependants().length;

            return adultAges + " " + (adultAges > 1 ? 'adults' : 'adult') + (dependantAges > 0 ? (" & " + dependantAges + " " + (dependantAges > 1 ? 'dependants' : 'dependant')) : '');
        },null, { deferEvaluation: true });

        viewModel.MetaData.TravellerAgeFlyOverText = ko.computed(function () {
            var words = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'];
            var adultAges = viewModel.PolicyHolders().length;
            var dependantAges = viewModel.PolicyDependants().length;

            return words[adultAges] + " " + (adultAges > 1 ? 'adults' : 'adult') + ' aged ' + formatPlanSummary(ko.unwrap(viewModel.MetaData.AdultTravellers)) + (dependantAges > 0 ? (" and " + words[dependantAges] + " " + (dependantAges > 1 ? 'dependants' : 'dependant')) + " aged " + formatPlanSummary(ko.unwrap(viewModel.MetaData.DependantTravellers)) : '');
        }, null, { deferEvaluation: true });
    }
}

function formatPlanSummary(items) {
    if (!$.isArray(items)) {
        items = items.split(",").filter(function (v) { return v !== '' })
    }
    return [items.slice(0, -1).join(', '), items.slice(-1)[0]].join(items.length < 2 ? '' : ' & ');

}

function sharedExtendViewModel(viewModel) {
    if (!ko.extenders.uppercase) {
        ko.extenders.uppercase = function (target, option) {
            target.subscribe(function (newValue) {
                if (newValue) target(newValue.toUpperCase());
            });
            return target;
        };
    }

    // Helper info for display device
    var isIE8 = null;
    viewModel.MetaData.IsIE8 = ko.computed(function () {
        if (isIE8 == null) {
            isIE8 = ($('html.ie8').length > 0);
        }
        return isIE8
    }, this).extend({ throttle: $$.Client.Util.ThrottleTime });

    viewModel.MetaData.quoteIsInvalid = ko.observable(true);
    viewModel.MetaData.isRecalculating = ko.observable(false);

    viewModel.MetaData.residentType = ko.computed(function () {
        var isResidentQuestion = $$.Utils.arrayFirstBriefCode(viewModel.Questions(), "RESID");
        if (isResidentQuestion && ko.unwrap(isResidentQuestion.Answer)) {

            if (ko.unwrap(isResidentQuestion.Answer().BriefCode) === "Y") {
                var isResidentReturningQuestion = $$.Utils.arrayFirstBriefCode(ko.unwrap($$.Utils.arrayFirstBriefCode(ko.unwrap(isResidentQuestion.Answers) || [], "Y").Questions) || [], "RSRTN");
                if (isResidentReturningQuestion && ko.unwrap(isResidentReturningQuestion.Answer) && ko.unwrap(isResidentReturningQuestion.Answer().BriefCode) === "Y") {
                    return ko.unwrap(isResidentReturningQuestion.BriefCode);
                }
                return ko.unwrap(isResidentQuestion.BriefCode);

            } else if (ko.unwrap(isResidentQuestion.Answer().BriefCode) === "N") {
                var isTemporaryResidentQuestion = $$.Utils.arrayFirstBriefCode(ko.unwrap($$.Utils.arrayFirstBriefCode(ko.unwrap(isResidentQuestion.Answers) || [], "N").Questions) || [], "TEMPR");
                if (isTemporaryResidentQuestion && ko.unwrap(isTemporaryResidentQuestion.Answer) && ko.unwrap(isTemporaryResidentQuestion.Answer().BriefCode) === "N") {
                    var isNonResidentQuestion = $$.Utils.arrayFirstBriefCode(ko.unwrap($$.Utils.arrayFirstBriefCode(ko.unwrap(isTemporaryResidentQuestion.Answers) || [], "N").Questions) || [], "NONRS");
                    if (isNonResidentQuestion && ko.unwrap(isNonResidentQuestion.Answer) && ko.unwrap(isNonResidentQuestion.Answer().BriefCode) === "Y") {
                        return ko.unwrap(isNonResidentQuestion.BriefCode);
                    }

                    return ko.unwrap(isTemporaryResidentQuestion.BriefCode);
                }
            }
        }

        return null;
    }, this);

    //specifiedItems - build
    viewModel.buildSpecifiedItemsForm = function () {
        var benefit = $$.policy.fn.getBenefit("SPITM");
        if (!benefit.fn.hasBenefitItems()) {
            for (var i = 0; i < 5; i++) {
                $$.policy.fn.addBenefitItem("SPITM");
            }
        }
        return true; //return true so radio sets the value
    };
    //specifiedItems - clear
    viewModel.clearSpecifiedItemsForm = function () {
        var benefit = $$.policy.fn.getBenefit("SPITM");
        while (benefit.fn.hasBenefitItems()) {
            benefit.BenefitItems.pop();
        }
        return true; //return true so radio sets the value
    };

    //Adult ages

    ko.bindingHandlers['multiAgeInput'] = {

        init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {

            var underlyingObservable = valueAccessor();
            var allBindings = allBindingsAccessor();

            var customerBindings = allBindings.customers;
            var maxTravallerNumber = allBindings.maxTraveller;

            var interceptor = ko.computed({
                read: function () {
                    var ageValue = []
                    ko.utils.arrayMap(customerBindings(), function (customer) {
                        if (customer.MetaData.age()) {
                            ageValue.push(customer.MetaData.age());
                        }
                    });
                    ageValue = ageValue.join(', ');
                    return underlyingObservable();
                }, write: function (newValue) {
                    //clearing existing customer age value before writing new values
                    ko.utils.arrayMap(customerBindings(), function (customer) { customer.MetaData.age(''); });

                    var ages = cleanseAgeString(newValue);
                    // format the input age values with comma delimiters
                    underlyingObservable(ages.join(', '));

                    // store the input age values into policy 
                    for (var i = 0; i < ages.length; i++) {
                        if (ages.length <= ko.unwrap(maxTravallerNumber())) {
                            var age = ages[i];
                            if (ko.unwrap(customerBindings) && ko.unwrap(customerBindings).length > 0) {
                                var customer = customerBindings()[i];
                                customer.MetaData.age(age);
                            }
                        }
                    }
                }
            });
            ko.applyBindingsToNode(element, { value: interceptor }, null)
            return ko.bindingHandlers['validationCore'].init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
        }

    };

    viewModel.MetaData.AdultTravellers = ko.observable(
        ko.utils.arrayMap(viewModel.PolicyHolders() || [], function (traveller) { return traveller.MetaData.age(); }).join(', '))
        .extend({
            required: {
                params: true,
                message: function () {
                    var minAdults = viewModel.MetaData.MinAdults();
                    return minAdults != null ? PrismApi.Validation.messages.travellers.invalidMinAdults.format(minAdults) : '';
                }
            },
            pattern: { params: /^[\d\s]+(?:,[\d\s]*)*$/, message: 'Please enter valid ages for adult traveller' },
            validation: [{
                validator: checkAgeValue,
                message: function () {
                    return PrismApi.Validation.messages.travellers.invalidMaxAge.format(viewModel.MetaData.MaxAdultAge(), 'an adult');
                },
                params: function () {
                    return viewModel.MetaData.MaxAdultAge()
                }
            }, {
                validator: function (ages) {
                    var adultAges = cleanseAgeString(ages);
                    return (adultAges.length <= viewModel.MetaData.MaxAdults())                    
                },
                message: function () {
                    var maxAdults = viewModel.MetaData.MaxAdults();
                    return maxAdults != null ? PrismApi.Validation.messages.travellers.invalidMaxAdults.format(maxAdults) : '';
                },
                params: function () {
                    return viewModel.MetaData.MaxAdults()
                }
            }]
        });
    viewModel.MetaData.AdultTravellers.subscribe(function (newValue) {
        if (newValue) {
            var travellersAges = cleanseAgeString(newValue);
            if (travellersAges.length > viewModel.MetaData.MaxAdults()) {
                openErrorModal("Group Policies", PrismApi.Validation.messages.groupPolicy.format(PartnerConfiguration.ContactPhone));
            }
        }
    });

    viewModel.MetaData.DependantTravellers = ko.observable(
        ko.utils.arrayMap(viewModel.PolicyDependants() || [], function (traveller) { return traveller.MetaData.age(); }).join(', '))
        .extend({
            pattern: { params: /^[\d\s]+(?:,[\d\s]*)*$/, message: 'Please enter valid ages for dependant traveller' },
            validation: [{
                validator: checkAgeValue,
                message: function () {
                    return PrismApi.Validation.messages.travellers.invalidMaxAge.format(viewModel.MetaData.MaxDependantAge(), 'a dependant');
                },
                params: function () {
                    return viewModel.MetaData.MaxDependantAge()
                }
            }, {
                validator: function (ages) {
                    var dependantAges = cleanseAgeString(ages);
                    return (dependantAges.length <= viewModel.MetaData.MaxDependants())
                },
                message: function () {
                    return PrismApi.Validation.messages.travellers.invalidMaxDependants.format(viewModel.MetaData.MaxDependants());
                },
                params: function () {
                    return viewModel.MetaData.MaxAdultAge()
                }
            }
            ]
        });

    viewModel.MetaData.DependantTravellers.subscribe(function (newValue, element) {
        var dependantAges = cleanseAgeString(newValue);
        if (dependantAges.length > viewModel.MetaData.DependantAges().length && dependantAges.length <= viewModel.MetaData.MaxDependants()) {
            while (dependantAges.length != viewModel.MetaData.DependantAges().length) {
                viewModel.MetaData.DependantAges.push(new PrismApi.Data.Customer(null, 'dependant'))
            }
        }
    });
    function checkAgeValue(ages, maxage) {
        if (typeof maxage == "function") maxage = maxage();

        var travellersAges = cleanseAgeString(ages)

        for (var i = 0; i <= travellersAges.length; i++) {
            var travellersAge = travellersAges[i]
            if (travellersAge > maxage) {
                return false;
            }
        }
        return true;
    };
    function cleanseAgeString($ages) {
        var $ageArray = [];
        var $cleanAgeString = $ages.trim().replace(/\./g, ',').replace(/\s+/g, ',').replace(/\//g, ',').replace(/\|/g, ',').replace(/\D/g, ','); // remove all instances of chars: '.', ' ', '/', '|'
        $ageArray = $cleanAgeString.split(',');
        $ageArray = $ageArray.filter(function (v) { return v !== '' }); // filter array and remove empty entries caused by 2 commas in a row
        return $ageArray
    }

    viewModel.MetaData.PromoAdjustments = ko.computed(function () {
        return ko.utils.arrayFilter(viewModel.Adjustments(), function (adjustment) {
            if (adjustment.BriefCode() == 'DUMMY') {
                if (!ko.isObservable(adjustment.MetaData.IsPromoValid)) {
                    adjustment.MetaData.IsPromoValid = ko.observable();
                }
                if (adjustment.Value() === '' || adjustment.Value() === null) {
                    adjustment.MetaData.IsPromoValid(true);
                }
           

                adjustment.Value.subscribe(function (newValue) {
                    adjustment.MetaData.IsPromoValid(undefined);
                });

                adjustment.MetaData.IsPromoValid.extend({
                    validation: {
                        validator: function (val) {
                            return val !== false;
                        },
                        message: PrismApi.Validation.messages.adjustments.invalidPromoCode
                    }
                });
            }
            return $.inArray(adjustment.BriefCode(), promoCodeBriefCodes) >= 0;
        });
    }, this).extend({ throttle: $$.Client.Util.ThrottleTime });

    viewModel.MetaData.ActiveMemberAdjustment = ko.observable("");
    viewModel.MetaData.MemberAdjustments = ko.computed(function () {
        var items = ko.utils.arrayFilter(viewModel.Adjustments(), function (adjustment) {
            if (ko.utils.unwrapObservable(adjustment.Question) && /^MEM*/.test(adjustment.Question.BriefCode())) {
                if (adjustment.Value.rules) {
                    // override min/max rule to have a common error message
                    $.each(adjustment.Value.rules(), function (item, data) {
                        if (data.rule === "minLength" || data.rule === "maxLength") {
                            data.message = PrismApi.Validation.messages.adjustments.invalidMemberAdjustment.format(adjustment.MetaData.ValueTitle());
                        }
                    });
                }
                if (ko.utils.unwrapObservable(adjustment.Value)) {
                    viewModel.MetaData.ActiveMemberAdjustment(adjustment.Question.BriefCode());
                }

                return true;
            } else {
                return false;
            }

        });
        if (items.length > 0) {
            return items.sortBy(function (n) { return n.BriefCode(); });
        } else {
            return items;
        }
    }, this).extend({ throttle: $$.Client.Util.ThrottleTime });

    viewModel.MetaData.ActiveMemberAdjustmentChanged = function () {
        $.each(viewModel.MetaData.MemberAdjustments(), function (index, item) {
            item.Value(null);
        });
        return true;
    }

    viewModel.MetaData.MemberAdjustmentOptions = ko.computed(function () {
        var items = [];
        $.each(viewModel.MetaData.MemberAdjustments(), function (index, item) {
            items.push({ value: item.Question.BriefCode(), text: item.Question.Description() });
        });
        return items;
    }, this).extend({ throttle: $$.Client.Util.ThrottleTime });

    if (ko.utils.arrayFirst(viewModel.MetaData.AllTravellers(), function (traveller) { return ko.utils.unwrapObservable(traveller.HasPeCondition) }) == null) {
        viewModel.MetaData.EmailPolicy.extend({ equal: { params: true, message: PrismApi.Validation.messages.travellers.requiredEmailDocuments } });
    }
    viewModel.MetaData.emailConfirm = ko.observable(viewModel.Email.EmailAddress());
    viewModel.MetaData.emailConfirm.extend({ equal: { params: viewModel.Email.EmailAddress, message: PrismApi.Validation.messages.travellers.matchEmail }, required: { params: true, message: PrismApi.Validation.messages.travellers.requiredEmail } });

    //phones
    var phones = viewModel.Phones();
    viewModel.Phones(new Array());
    phone = ko.utils.arrayFirst(phones, function (phone) { return phone.PhoneType() == 'MOB'; });
    viewModel.Phones.push(phone || new $$.Data.Phone().PhoneType('MOB'));
    var phone = ko.utils.arrayFirst(phones, function (phone) { return phone.PhoneType() == 'HOME'; });
    viewModel.Phones.push(phone || new $$.Data.Phone().PhoneType('HOME'));

    //address
    viewModel.Address.MetaData = {
        FullAddress: ko.observable(''),
        FilterBy: ko.observable('')
    };

    if ($$.policy.Address.MetaData.FullAddress.isValid != undefined) {
        $$.policy.Address.MetaData.FullAddress.isValid.subscribe(function (val) {
            window.sessionStorage["FullAddress"] = val ? $('#address').val() : '';
        });
    }
    if (window.sessionStorage["FullAddress"] && viewModel.Address.AddressLine1() != null && viewModel.Address.Suburb() != null && viewModel.Address.State() != null && viewModel.Address.Postcode() != null) {
        $$.policy.Address.MetaData.FullAddress(window.sessionStorage['FullAddress']);
    }
    viewModel.Address.MetaData.FilterBy.extend({
        minLength: {
            params: 4,
            message: PrismApi.Validation.messages.address.invalidPostCode
        },
        required: true
    });
    viewModel.Address.MetaData.FullAddress.extend({
        requiredAll: {
            params: [viewModel.Address.AddressLine1, viewModel.Address.Suburb, viewModel.Address.State, viewModel.Address.Postcode],
            message: PrismApi.Validation.messages.travellers.invalidFullAddress
        },
        required: true
    });

    if (_session.policy && _session.policy.Plan && _session.policy.Plan.Currency && _session.policy.Plan.Currency.BriefCode) {
        var pattern;
        var mobilePattern;
        var areapattern;
        switch (_session.policy.Plan.Currency.BriefCode) {
            case 'AUD':
                pattern = "[0-9]{8}";
                areapattern = "(0[2-5])|(0[7-8])";
                mobilePattern = "[0-9]{10}";

                break;
            case 'NZD':
                pattern = "[0-9]{7}";
                areapattern = "(0[3|4|6|7|9])";
                mobilePattern = "02[0-9]{7,9}";
                break;
            default:
                pattern = "[0-9]{8,10}";
                areapattern = "[0-9]{2}";
                mobilePattern = "[0-9]{8,12}";
        }

        var phoneFields =
            ko.utils.arrayMap(viewModel.Phones(), function (phone1) { return phone1.PhoneNumber; }).concat(
            ko.utils.arrayMap(ko.utils.arrayFilter(viewModel.Phones(), function (phone1) { return phone1.PhoneType() != 'MOB'; }), function (phone1) { return phone1.AreaCode; }))

        ko.utils.arrayForEach(viewModel.Phones(), function (phone) {
            var phoneType = phone.PhoneType() == 'HOME' ? PrismApi.Validation.messages.travellers.labelPhoneHome : phone.PhoneType() == 'WORK' ? PrismApi.Validation.messages.travellers.labelPhoneWork : PrismApi.Validation.messages.travellers.labelPhoneMobile;

            phone.PhoneNumber.extend({
                pattern: {
                    params : phone.PhoneType() == 'MOB' ? new RegExp("^" + mobilePattern + "$"): new RegExp("^" + pattern + "$"),
                    message: PrismApi.Validation.messages.travellers.invalidPhone.format(phoneType.toLowerCase() + (phone.PhoneType() == 'MOB' ? '' : PrismApi.Validation.messages.travellers.labelPhoneNumberTypeNumber), phone.PhoneType() == 'MOB' ? 10 : 10)
                },
                allOrNone: {
                    params: phone.PhoneType() != 'MOB' ? [phone.AreaCode, phone.PhoneNumber] : [phone.PhoneNumber],
                    message: function () { return PrismApi.Validation.messages.travellers.requiredAllOrNonePhone.format(phoneType.toLowerCase() + (phone.PhoneType() == 'MOB' ? '' : (phone.PhoneNumber() ? PrismApi.Validation.messages.travellers.labelPhoneNumberTypeArea : PrismApi.Validation.messages.travellers.labelPhoneNumberTypeNumber))); }
                }
            });

            if (phone.PhoneType() != 'MOB') {
                phone.AreaCode.extend({
                    pattern: {
                        params: new RegExp("^" + areapattern + "$"),
                        message: PrismApi.Validation.messages.travellers.invalidPhoneArea.format(phoneType.toLowerCase())
                    },
                    allOrNone: {
                        params: [phone.AreaCode, phone.PhoneNumber],
                        message: function () { return PrismApi.Validation.messages.travellers.requiredAllOrNonePhone.format(phoneType.toLowerCase() + (phone.PhoneNumber() ? PrismApi.Validation.messages.travellers.labelPhoneNumberTypeArea : PrismApi.Validation.messages.travellers.labelPhoneNumberTypeNumber)); }
                    }
                });
            }

            if (phone.PhoneType() != 'MOB') {
                phone.AreaCode.extend({
                    requiresOneOf: {
                        params: phoneFields,
                        message: PrismApi.Validation.messages.travellers.requiredPhoneOrMobile
                    },
                });
            }

            phone.PhoneNumber.extend({
                requiresOneOf: {
                    params: phoneFields,
                    message: PrismApi.Validation.messages.travellers.requiredPhoneOrMobile
                },
            });
            // to handle single input phone number where more than 10 digits
            phone.combinedPhoneNumber = ko.computed({
                read: function () {
                    if (ko.unwrap(phone.AreaCode) != null && ko.unwrap(phone.PhoneNumber) != null) {
                        return this.AreaCode() + this.PhoneNumber();
                    }
                    else {
                        return this.PhoneNumber();
                    }
                },
                write: function (value) {
                    if (value != null && value.length == 10 && !isNaN(value)) {
                        this.AreaCode(value.substring(0, 2)); // first 2 digits captured in "Area Code"
                        this.PhoneNumber(value.substring(2)); // remaining digits captured in "Phone Number"
                    }
                    else {
                        this.AreaCode(null);
                        !isNaN(value) ? this.PhoneNumber(value): this.PhoneNumber(null);
                    }
                },
                owner: phone
            }).extend({
                pattern: {
                    params: phone.PhoneType() == 'MOB' ? new RegExp(mobilePattern) : new RegExp("^" + areapattern + pattern + "$"),
                    message:PrismApi.Validation.messages.travellers.invalidPhone.format(phoneType.toLowerCase() + (phone.PhoneType() == 'MOB' ? '' : PrismApi.Validation.messages.travellers.labelPhoneNumberTypeNumber), phone.PhoneType() == 'MOB' ? 10 : 10)
                },
                requiresOneOf: {
                    params: phoneFields,
                    message: PrismApi.Validation.messages.travellers.requiredPhoneOrMobile
                }
            });
        });
        fixQuestionItems();
    }

    ko.bindingHandlers.hidden = {
        update: function (element, valueAccessor) {
            var value = ko.utils.unwrapObservable(valueAccessor());
            ko.bindingHandlers.visible.update(element, function () { return !value; });
        }
    };

    ko.bindingHandlers.dollars = {
        update: function (element, valueAccessor) {
            var value = ko.unwrap(valueAccessor());
            var textValue;
            if (value) {
                var splitValue = value.split('.');
                textValue = splitValue[0];
            }
            ko.bindingHandlers.text.update(element, function () { return formatDollar(textValue); });
        }
    };

    ko.bindingHandlers.cents = {
        update: function (element, valueAccessor) {
            var value = ko.unwrap(valueAccessor());
            var textValue;
            if (value) {
                var splitValue = value.split('.');
                if (splitValue.length == 1) splitValue.push('00');
                textValue = splitValue[1];
            }
            ko.bindingHandlers.text.update(element, function () { return textValue; });
        }
    };

    ko.bindingHandlers.slideVisible = {
        init: function (element, valueAccessor) {
            // Initially set the element to be instantly visible/hidden depending on the value
            var value = valueAccessor();
            $(element).toggle(ko.utils.unwrapObservable(value)); // Use "unwrapObservable" so we can handle values that may or may not be observable
        },
        update: function (element, valueAccessor) {
            // Whenever the value subsequently changes, slowly fade the element in or out
            var value = valueAccessor();
            ko.utils.unwrapObservable(value) ? $(element).slideDown() : $(element).slideUp();
        }
    };


    ko.bindingHandlers.bootstrapMaterialCheckbox = {
        init: function (element) {
            $.material.checkbox($(element));
        }
    };

    ko.bindingHandlers.bootstrapMaterial = {
        init: function (element, valueAccessor, allBindingsAccessor) {
            var underlyingObservable = valueAccessor();
            if (underlyingObservable) {
                underlyingObservable.extend({ validatable: true });
            }

            if ($(element).hasClass('form-control')) {
                if ($(element).is('select')) {
                    $(element).dropdown();
                } else {
                    $.material.input($(element));
                    $.material.options.validate = false;
                    $.material.attachInputEventHandlers();
                }
            }
        },
        update: function (element, valueAccessor, allBindingsAccessor) {
            var underlyingObservable = valueAccessor();
            var val = ko.unwrap(underlyingObservable);
            var isModified = false;
            var isValid = true;

            if (underlyingObservable) {
                isModified = ko.unwrap(underlyingObservable.isModified);
                isValid = ko.unwrap(underlyingObservable.isValid);
            }

            $(element).closest(".form-group")
                .toggleClass('is-empty', val == null || val == '')
                .toggleClass('has-error', isModified && !isValid);

            if ($(element).is('select') &&
                isModified &&
                $(element).find(":contains('" + val + "')").length) {

                $(element).siblings(".dropdownjs").find("input").val(val);
            }
        }
    };

    ko.bindingHandlers.block = {
        update: function (element, valueAccessor) {
            var value = ko.unwrap(valueAccessor());
            if (value) {
                $(element).first().block({
                    message: null,
                    overlayCSS: {
                        backgroundColor: '#FFF',
                        opacity: 0.6,
                        cursor: 'wait'
                    }
                });
            } else {
                $(element).first().unblock();
            }
        }
    };

    ko.bindingHandlers.mouseOverPolicyBenefit = {
        init: function (element, valueAccessor) {
            var tempPopupDiv = $(ko.utils.unwrapObservable(valueAccessor()));
            $(element).hover(
			    function () {
			        if ($(element).is('.highlighted')) {
			            return;
			        }

			        $('li.highlighted').removeClass('highlighted');

			        if (!$(element).data('featureRow') && $(element).data('featureRow') != 0) {
			            return;
			        }

			        var rows = $('li[data-feature-row=' + $(element).data('featureRow') + ']');
			        var row = rows.first();

			        if (window.innerWidth < 480) {
			            rows = $('li[data-feature-row=' + $(element).data('featureRow') + ']', $(element).parent());
			            var parent = $(element).parents('.column');
			            parent.append(tempPopupDiv);
			            tempPopupDiv.css('top', $(element).position().top + $(element).outerHeight()).show();
			        }
			        else {
			            $('#benefits-columns').append(tempPopupDiv);
			            var parent = $('.pricing-table').last();

			            while (parent && !parent.position().top) {
			                parent = parent.parent();
			            }

			            var extraHeight = parent.position().top;
			            tempPopupDiv.css('top', $(element).position().top + extraHeight + $(element).outerHeight()).show();
			        }

			        tempPopupDiv.addClass('wide');
			        rows.addClass('highlighted');
			        tempPopupDiv.find('.heading').html(row.first().data('feature'));
			        tempPopupDiv.find('.details').html(row.first().data('originalTitle'));

			        tempPopupDiv.show();
			    },
                function () {
                    if (!isMobile()) {
                        $('li[data-feature-row=' + $(element).data('featureRow') + ']').removeClass('highlighted');
                        tempPopupDiv.hide();
                    }
                }
            );
        }
    };

    ko.bindingHandlers.mouseOverPopup = {
        init: function (element, valueAccessor) {
            var tempPopupDiv = $(ko.utils.unwrapObservable(valueAccessor()));
            if (tempPopupDiv.length > 0) {
                $(element).hover(
				function () {

				    $('.benefit-div.highlighted').removeClass('highlighted');

				    if ($(element).is('.highlighted')) {
				        return;
				    }

				    $(this).parent().append(tempPopupDiv);

				    tempPopupDiv.css('top', $(this).position().top + $(this).outerHeight()).show();

				    if (window.innerWidth > 979) {
				        tempPopupDiv.addClass('wide');
				    } else {
				        tempPopupDiv.removeClass('wide');
				    }

				    $(this).addClass('highlighted');

				    var label = $(this).find('label').first();
				    if (label != null) {
				        tempPopupDiv.find('.heading').html(label.text());
				        tempPopupDiv.find('.details').html(label.attr('detail'));
				    }

				    tempPopupDiv.show();
				},
				function () {
				    if (!isMobile()) {
				        $(this).removeClass('highlighted');
				        tempPopupDiv.hide();
				    }
				}
			);
            }
        }
    };

    ko.bindingHandlers.select2 = {
        init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
            var obj = valueAccessor(),
				allBindings = allBindingsAccessor(),
				lookupKey = allBindings.lookupKey;

            $(element).select2(obj);

            if (lookupKey) {
                var value = ko.utils.unwrapObservable(allBindings.value);
                $(element).select2('data', ko.utils.arrayFirst(obj.data.results, function (item) {
                    return item[lookupKey] === value;
                }));
            }

            allBindings.value.subscribe(function () {
                $(element).trigger('change');
            })

            ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
                $(element).select2('destroy');
            });
        },
        update: function (element, valueAccessor, allBindingsAccessor) {
        }
    };

    ko.bindingHandlers.mobilenumpad = {
        init: function (element, valueAccessor, allBindingsAccessor) {
            var elem = $(element);
            if (isMobile()) {
                // check if we are using tel mode
                var keyType = ko.utils.unwrapObservable(valueAccessor()) === "tel" ? "tel" : "number";

                elem.attr("inputmode", "numeric");
                elem.on("focus", function (e) {
                    this.type = keyType;
                });
                elem.on("blur", function (e) {
                    this.type = "text";
                });
                elem.on("input", function (e) {
                    maxLengthCheck(e.target);
                });
            } else {
                elem.on("input", function (e) {
                    this.value = this.value.replace(/\D/g, "");
                });
            }
        }
    };

    ko.bindingHandlers.mouseOverBootstrapPopover = {
        init: function (element, valueAccessor) {
            var value = valueAccessor();

            if (value !== null && value !== undefined && value.length > 0) {
                var settings = popoverSettings;
                var container = $(ko.utils.unwrapObservable(valueAccessor()));
                settings.container = container;
                $(element).popover(settings);
            }
        }
    };

    //ko.bindingHandlers.AgeInput = {
    //    init: function (element) {
    //        $(element).on("keydown", function (event) {
    //            // Allow: space, backspace, delete, tab, escape, and enter
    //            if (event.keyCode == 32 || event.keyCode == 46 || event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 27 || event.keyCode == 13 ||
    //                // Allow: Ctrl+A
    //                (event.keyCode == 65 && event.ctrlKey === true) ||
    //                // Allow: . ,
    //                (event.keyCode == 188 || event.keyCode == 190 || event.keyCode == 110) ||
    //                // Allow: home, end, left, right
    //                (event.keyCode >= 35 && event.keyCode <= 39)) {
    //                // let it happen, don't do anything
    //                return;
    //            }
    //            else {
    //                // Ensure that it is a number and stop the keypress
    //                if (event.shiftKey || (event.keyCode < 48 || event.keyCode > 57) && (event.keyCode < 96 || event.keyCode > 105)) {
    //                    event.preventDefault();
    //                }
    //            }
    //        });
    //    }
    //};

    ko.bindingHandlers.bootstrapCollapseChange = {
        init: function (element, valueAccessor) {
            var elem = $(element);
            // Clickchange to all toggleable elements
            if ($(elem).data('toggle') != 'collapse') {
                // It's a grouping, as I place the data on the parent element
                var theParent = $(elem);
                // Find only the elements that are part of this grouping
                theParent
                    .find('[data-parent="#' + theParent.attr('id') + '"]')
                    .bootstrapCollapseChange(null, theParent);
            } else {
                // This covers stand alone elements
                $(elem).bootstrapCollapseChange();
            }
        }
    };

    ko.bindingHandlers.placeholder = {
        init: function (element, valueAccessor, allBindingsAccessor) {
            var underlyingObservable = valueAccessor();
            ko.applyBindingsToNode(element, { attr: { placeholder: underlyingObservable } });
        }
    };

    //This will disable any binding on any child elements
    //The reason for using this is if you want to call ko.applyBindings on an element contained within the bound DOM
    //Using containerless binding is probably the best way to go ie <!-- ko stopBinding: true -->
    //Used on the Pre-existing medical page as a separate hosted markup/viewmodel is bound
    ko.bindingHandlers.stopBinding = {
        init: function (element, valueAccessor) {
            var value = valueAccessor();
            return { controlsDescendantBindings: value };
        }
    };
    ko.virtualElements.allowedBindings.stopBinding = true;


    ko.bindingHandlers.toolTip = {
        update: function (element, valueAccessor) {
            // Whenever the value subsequently changes, slowly fade the element in or out
            var value = valueAccessor();
            var val = ko.unwrap(value);
            var options;
            $(element).popover('destroy');
            var baseOptions = {
                html:'true',
                trigger: 'hover',
                placement: 'right',
                container: 'body'
            };
            if (typeof (val) === 'string') {
                options = $.extend(baseOptions, { content: val });
            } else {
                options = $.extend(baseOptions, val);
            }
            $(element).popover(options);
        }
    };

    ko.bindingHandlers['coveredNotCovered'] = {
        init: function () {
            return { controlsDescendantBindings: true }
        }, update: function (element, valueAccessor) {
            var value = valueAccessor();
            var valueUnwrapped = ko.utils.unwrapObservable(value);
            var disarmedHtml = valueUnwrapped.replace(/<script(?=(\s|>))/i, '<script type="text/xml" ');
            ko.utils.setHtml(element, disarmedHtml)
        }
    };


    var setDefaultAge = function (customer) {
        var age = $$.quickQuoteOptions().DefaultAdultAge;
        if (customer.MetaData.Type() == 'dependant') {
            age = $$.quickQuoteOptions().DefaultDependantAge;
        }
        customer.DateOfBirth.formattedDate('1/1/' + (new Date().getFullYear() - age));
    };

    if ($$.quickQuoteOptions() && $$.quickQuoteOptions().DefaultAdultAge) {
        while (viewModel.PolicyHolders().length < $$.quickQuoteOptions().MinAdults) {
            var customer = new PrismApi.Data.Customer(null, "adult");
            setDefaultAge(customer);
            viewModel.PolicyHolders().push(customer);
        }
    }

    if ($$.quickQuoteOptions() && $$.quickQuoteOptions().DefaultDependantAge) {
        while (viewModel.PolicyHolders().length < $$.quickQuoteOptions().MinDependants) {
            var customer = new PrismApi.Data.Customer(null, "dependant");
            setDefaultAge(customer);
            viewModel.PolicyHolders().push(customer);
        }
    }

    ko.utils.arrayForEach(viewModel.MetaData.AllTravellers(), function (customer) {
        if (!customer.DateOfBirth()) {
            setDefaultAge(customer);
        }
    });

    var getQuestionValidators = function (briefCode) {
        if (briefCode == 'RESID') {
            return [{
                validator: function(answer) { 
                    if (answer && (ko.unwrap(answer.Questions) || []).length == 0) {
                        return ko.unwrap(answer.BriefCode) === 'Y';
                    }
                    return true;
                },
                message: function () {
                    return PrismApi.Validation.messages.travellers.invalidResidentsOfCountry;
                }
            }];
        }
        return [];        
    }
        
    var addQuestionValidation = function (questions) {
        ko.utils.arrayForEach(questions, function (question) {
            if (question.IsRequired == undefined || question.IsRequired()) {
                var briefCode = question.BriefCode();
                question.Answer.extend({
                    required: { params: true, message: getQuestionValidationErrorMsg(briefCode) },
                    validation: getQuestionValidators(briefCode)
                });
              
                if (question.Answers()) {
                    ko.utils.arrayForEach(question.Answers(), function (answer) {
                        if (ko.unwrap(answer.Questions)) {
                            addQuestionValidation(answer.Questions());
                        }
                    });
                }
            }
        });
    }
    addQuestionValidation(viewModel.Questions());
    viewModel.Questions.subscribe(function (newVal) {
        addQuestionValidation(viewModel.Questions());
    });

    viewModel.Adjustments.subscribe(function (newVal) {
        addAdjustmentValidationRules(viewModel);
    });

    ko.utils.arrayForEach(viewModel.PremiumExtraInfo, function (question) {
        if (question.IsRequired == undefined || question.IsRequired()) {
            question.Answer.extend({
                required: { params: true, message: getQuestionValidationErrorMsg(question.BriefCode()) }
            })
        }
    });


    for (var j = 0; j < viewModel.Questions().length; j++) {
        var question = viewModel.Questions()[j];
        question.Answer.extend({
            required: { params: true, message: getQuestionValidationErrorMsg(question.BriefCode()) }
        })
    }

    viewModel.Region.extend({
        required: { params: true, message: PrismApi.Validation.messages.requiredRegion }
    });

    viewModel.Region.subscribe(function (region) {
        if (region && region.Country && ko.isObservable(region.Country)) {
            region.Country.extend({
                required: { params: true, message: PrismApi.Validation.messages.requiredRegionMostTime }
            });
        }
    });

    ko.utils.arrayForEach(viewModel.Questions(), function (question) {
        question.Answer.extend({
            required: { params: true, message: getQuestionValidationErrorMsg(question.BriefCode()) }
        })
    });

    ko.validation.rules['ensureWorldwideRegionHasACountrySelected'] = {
        validator: function (val, params) {
            var selectedRegions = JSON.parse('[' + val.replace(/\|/g, ',') + ']');
            if (selectedRegions.length == 1) {
                return !(selectedRegions[0].BriefCode == 'WORLD' && (selectedRegions[0].Country == null || selectedRegions[0].Country.BriefCode == "WWID"));
            }
            return true;
        }, message: 'End Date must be greater than Start Date'
    };

    ko.validation.rules['mustEqual'] = {
        validator: function (val, mustEqualVal) {
            return val == ko.unwrap(mustEqualVal);
        },
        message: 'This field must equal {0}'
    };

    ko.validation.registerExtenders()

    viewModel.MetaData.Countries = ko.observable('');

    //To get validation working properly with the Select2 control we have to have a new field to bind the container to
    // so that the validation is shown only once and the title (error message) is set properly
    viewModel.MetaData.CountriesCopy = ko.computed({
        read: function () {
            return viewModel.MetaData.Countries();
        }, write: function (newValue) {
            viewModel.MetaData.Countries(newValue);
        }
    });
    viewModel.MetaData.CountriesCopy.extend({
        required: { params: true, message: PrismApi.Validation.messages.requiredCountry },
    });

    //Set the editor for the Options based on the configuration
    ko.utils.arrayForEach(viewModel.Benefits(), function (benefit) {
        var editorType = ko.utils.arrayFirst(PartnerConfiguration.OptionConfigurations, function (item) { return benefit.BriefCode() == item.BriefCode; });
        benefit.MetaData.Editor = (editorType || {}).Editor;
        benefit.MetaData.ImageUrl = (editorType || {}).ImageUrl;
    });

    //Add validation to specified items so that if they enable the item and don't add any items then it will error
    var increasedItemLimit = ko.utils.arrayFirst(viewModel.Benefits(), function (item) { return item.BriefCode() === 'ITEM'; });
    if (increasedItemLimit) {
        increasedItemLimit.MetaData.hasBenefitItems = ko.observable(increasedItemLimit.BenefitItems().length);
        increasedItemLimit.BenefitItems.subscribe(function (item) {
            increasedItemLimit.MetaData.hasBenefitItems(increasedItemLimit.BenefitItems().length > 0);
            if (increasedItemLimit.BenefitItems().length === 0) {
                //reset the validation when the items are removed.
                increasedItemLimit.MetaData.hasBenefitItems.isModified(false);
                increasedItemLimit.MetaData.checkNewEntryIsValid(true);
            }
        });
        increasedItemLimit.MetaData.hasBenefitItems.extend({ min: { params: 1, message: PrismApi.Validation.messages.benefits.requiredItemItem } });

        //Add the validation code for the un-added item
        //This basically watches the selected values in the dropdowns and wall warn if the user tries to move to the next page while they have items selected but not added.
        //We need to use an observable and set it to unmodified otherwise the validation will kick in while they are adding items.
        increasedItemLimit.MetaData.currentlySelectedTraveller = ko.observable();
        increasedItemLimit.MetaData.currentlySelectedItem = ko.observable();
        increasedItemLimit.MetaData.currentlySelectedValue = ko.observable();
        increasedItemLimit.MetaData.currentlySelectedIsValid = ko.observable(true);
        increasedItemLimit.MetaData.checkNewEntryIsValid = ko.observable(true);
        var checkCurrentlySelected = function (item) {
            var val = (!increasedItemLimit.MetaData.hasBenefitItems()) || (increasedItemLimit.MetaData.currentlySelectedTraveller() == null && increasedItemLimit.MetaData.currentlySelectedItem() == null && increasedItemLimit.MetaData.currentlySelectedValue() == null);
            increasedItemLimit.MetaData.currentlySelectedIsValid(val);
            increasedItemLimit.MetaData.currentlySelectedIsValid.isModified(false);
        }
        increasedItemLimit.MetaData.currentlySelectedTraveller.subscribe(checkCurrentlySelected);
        increasedItemLimit.MetaData.currentlySelectedItem.subscribe(checkCurrentlySelected);
        increasedItemLimit.MetaData.currentlySelectedValue.subscribe(checkCurrentlySelected);
        increasedItemLimit.MetaData.currentlySelectedIsValid.extend({ equal: { params: true, message: PrismApi.Validation.messages.benefits.requiredItemAdd } });
    }
    ko.utils.arrayForEach(viewModel.MetaData.AllTravellers(), function (traveller) {
        traveller.MetaData.PeOptions = ko.observableArray();

        if (ko.unwrap(traveller.HealixAssessment) && ko.unwrap(traveller.HealixAssessment().ScreeningResult) && ko.unwrap(traveller.HealixAssessment().ScreeningResult.PostScreeningCondition)) {
            traveller.HealixAssessment().ScreeningResult.MetaData = traveller.HealixAssessment().ScreeningResult.MetaData || {};
            traveller.HealixAssessment().ScreeningResult.MetaData.PostScreeningMentalCondition = ko.computed(function () {
                return ko.utils.arrayFilter(ko.unwrap(traveller.HealixAssessment().ScreeningResult.PostScreeningCondition), function (condition) {
                    return condition.IsMentalCondition();
                });
            });
            traveller.HealixAssessment().ScreeningResult.MetaData.PostScreeningPhysicalCondition = ko.computed(function () {
                return ko.utils.arrayFilter(ko.unwrap(traveller.HealixAssessment().ScreeningResult.PostScreeningCondition), function (condition) {
                    return !condition.IsMentalCondition();
                });
            });
        }
    });

    //Add validation to specified items so that if they enable the item and don't add any items then it will error
    var BusinessItem = ko.utils.arrayFirst(viewModel.Benefits(), function (item) { return item.BriefCode() === 'BUS'; });
    if (BusinessItem) {
        BusinessItem.MetaData.hasBenefitItems = ko.observable(BusinessItem.BenefitItems().length);
        BusinessItem.MetaData.ShowTravellerSelection = ko.computed(function () {
            return (viewModel.Plan().CoverType.BriefCode === "DUO" || viewModel.Plan().CoverType.BriefCode === "SGL") && viewModel.PolicyHolders().length > 1;
        }).extend({ throttle: $$.Client.Util.ThrottleTime });
        BusinessItem.MetaData.TravellerDataList = ko.observableArray();
        BusinessItem.MetaData.ResetTravellerDataList = function () {
            // find travellers not already in benefititems list
            var items = ko.utils.arrayFilter(BusinessItem.MetaData.TravellerOptions(), function (item) {
                foundCustomer = ko.utils.arrayFilter(BusinessItem.BenefitItems(), function (itemToFind) {
                    return item.MetaData.TravellerIndex.toString() === itemToFind.CustomerIndex().toString();
                });
                return foundCustomer.length == 0;
            });
            BusinessItem.MetaData.TravellerDataList(items);
        };
        // Add business pack
        BusinessItem.MetaData.IsEnabled.subscribe(function (item) {
            BusinessItem.MetaData.ResetTravellerDataList();
            if (BusinessItem.MetaData.IsEnabled()) {

                if ((BusinessItem.MetaData.IsPerAdultOnly && BusinessItem.MetaData.IsPerPersonChoice && BusinessItem.MetaData.TravellerOptions().length == 1)
                   || !(viewModel.Plan().CoverType.BriefCode === "DUO" && viewModel.PolicyHolders().length > 1)) {
                    for (var i = 1; i <= BusinessItem.MetaData.TravellerOptions().length; i++) {
                        var item = new PrismApi.Data.BenefitItem(BusinessItem);
                        item.CustomerIndex(i);
                        item.BriefCode(BusinessItem.BriefCode());
                        item.Description('Business Pack');
                        item.ValueText(BusinessItem.MetaData.Values[0].Value);
                        BusinessItem.BenefitItems.push(item);
                    }
                    RecalculateQuote();
                }
            }
        });

        BusinessItem.BenefitItems.subscribe(function (item) {
            BusinessItem.MetaData.hasBenefitItems(BusinessItem.BenefitItems().length > 0);
            if (BusinessItem.BenefitItems().length === 0) {
                //reset the validation when the items are removed.
                BusinessItem.MetaData.hasBenefitItems.isModified(false);
            }

            RecalculateQuote();
        });
        BusinessItem.MetaData.hasBenefitItems.extend({ min: { params: 1, message: PrismApi.Validation.messages.benefits.requiredBusinessPackTraveller } });

        //Add the validation code for the un-added item
        //This basically watches the selected values in the dropdowns and wall warn if the user tries to move to the next page while they have items selected but not added.
        //We need to use an observable and set it to unmodified otherwise the validation will kick in while they are adding items.
        BusinessItem.MetaData.currentlySelectedTraveller = ko.observable();
        BusinessItem.MetaData.currentlySelectedIsValid = ko.observable(true);
        var checkCurrentlySelected = function (item) {
            var val = (!BusinessItem.MetaData.hasBenefitItems()) || (BusinessItem.MetaData.currentlySelectedTraveller() == null);
            BusinessItem.MetaData.currentlySelectedIsValid(val);
            BusinessItem.MetaData.currentlySelectedIsValid.isModified(false);
        }
        BusinessItem.MetaData.currentlySelectedTraveller.subscribe(checkCurrentlySelected);
        BusinessItem.MetaData.currentlySelectedIsValid.extend({ equal: { params: true, message: PrismApi.Validation.messages.benefits.requiredItemAdd } });
    }

    viewModel.MetaData.unappliedPromoAdjustments = ko.computed(function () {
        var appliedAdjustments = _session.policy ? $.unique(ko.utils.arrayMap(_session.policy.Adjustments, function (adj) { if (adj.MetaData && adj.MetaData.InputBriefCode) { return adj.MetaData.InputBriefCode; } else { return adj.BriefCode; } })) : [];
        if (appliedAdjustments.length > 0) {
            return ko.utils.arrayFilter($$.policy.MetaData.PromoAdjustments(), function (adjustment) {
                return $.inArray(adjustment.BriefCode, appliedAdjustments) >= 0;
            });
        } else {
            return $$.policy.MetaData.PromoAdjustments();
        }
    }, this);

    ko.utils.arrayForEach(viewModel.Adjustments(), function (adjustment) {
        adjustment.MetaData.ValueUsedForPremium = ko.observable(adjustment.Value());
        adjustment.MetaData.IsPromoValid = ko.observable(adjustment.Value() != null ? parseFloat(adjustment.Premium()) > 0 && adjustment.Value() === adjustment.MetaData.ValueUsedForPremium() : true);

    });


    viewModel.MetaData.planCssClass = ko.computed(function () {
        switch (viewModel.MetaData.BulkPremiums().length) {
            case 1:
                return 'col-sm-6 col-xs-12';
            case 2:
                return 'col-sm-4 col-xs-12';
            case 3:
                return 'col-sm-3 col-xs-12';
            case 4:
                return 'col-sm-3 five-column-layout col-xs-12';
            default:
                return 'force-mobile-view col-sm-12 col-xs-12';
        }
    });

    viewModel.MetaData.forcePlanMobileView = ko.computed(function () {
        return viewModel.MetaData.BulkPremiums().length > 4;
    });

    ko.bindingHandlers.specialCSS = {
        init: function (element, valueAccessor) {
            var value = ko.utils.unwrapObservable(valueAccessor());
            if (typeof value == "object") {
                ko.utils.objectForEach(value, function (className, shouldHaveClass) {
                    if (className == 'specialCSS') {
                        ko.utils.toggleDomNodeCssClass(element, shouldHaveClass, true);
                    } else {
                        shouldHaveClass = ko.utils.unwrapObservable(shouldHaveClass);
                        ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);
                    }
                });
            } else {
                value = String(value || ''); // Make sure we don't try to store or set a non-string value
                ko.utils.toggleDomNodeCssClass(element, element[classesWrittenByBindingKey], false);
                element[classesWrittenByBindingKey] = value;
                ko.utils.toggleDomNodeCssClass(element, value, true);
            }
        }
    };

    //Run the custom view code
    customViewCode(viewModel);

    $('.policy-wrapper').first().each(function () {
        //ToDo, update the $$.newPolicy to the original values to overwrite any changes        
    });


    viewModel.MetaData.appliedPromoAdjustments = ko.computed(function () {
        return appliedAdjustments = ko.utils.arrayFilter(viewModel.Adjustments(), function (adjustment) { return adjustment.Value(); });
    }, this);

    viewModel.MetaData.listPromoAdjustments = ko.computed(function () {
        var adjustments = viewModel.MetaData.appliedPromoAdjustments(); //viewModel.Adjustments() || _session.policy.Adjustments;
        var appliedAdjustments = _session.policy ? $.unique(ko.utils.arrayMap(adjustments, function (adj) {
            if (adj.MetaData && adj.MetaData.InputBriefCode) {
                return adj.MetaData.InputBriefCode;
            } else {
                return adj.BriefCode;
            }
        })) : [];
        appliedAdjustments = ko.utils.arrayMap(appliedAdjustments, function (a) { return ko.unwrap(a); });
        if (appliedAdjustments.length > 0) {
            var usedPromos = ko.utils.arrayFilter(viewModel.MetaData.PromoAdjustments(), function (adjustment) {
                return $.inArray(ko.unwrap(adjustment.BriefCode), appliedAdjustments) >= 0;
            });

            return ko.utils.arrayMap(usedPromos, function (item) {
                return item.Description();
            }).join();
        } else {
            return 'No discounts applied';
        }
    }, this);

    viewModel.fn.FixTravellers = function () {
        ko.utils.arrayForEach(viewModel.MetaData.AllTravellers(), function (traveller) {
            if (traveller.MetaData.PeOptionsEnforced === undefined) {
                traveller.MetaData.PeOptionsEnforced = ko.observable(false);
                traveller.MetaData.HasPeConditionChangedValidation = ko.observable();

                // restore DateOfBirth.hasEntered from session storage if previously defined
                if (window.sessionStorage) {
                    traveller.DateOfBirth.hasEntered(window.sessionStorage['Travellers[' + traveller.MetaData.TravellerIndex + '].HasEnteredDOB'] === "true");
                }

                if (!traveller.MetaData.HasSetNewAge) {
                    var defaultMandatoryPEAge = ko.unwrap($$.policy.PeOptions) != null && $$.policy.PeOptions.PESystem() ? $$.policy.PeOptions.MetaData.MandatoryAssessmentAge() : undefined;
                    traveller.MetaData.age = ko.computed({
                        read: function () {
                            if (!traveller.DateOfBirth()) {
                                return undefined;
                            }
                            var origAge = new Date(Date.parse(traveller.DateOfBirth().toString())).age();
                            var dt = new Date(Date.parse(traveller.DateOfBirth()));
                            if (isNaN(dt)) {
                                return undefined;
                            }
                            // suppress validation on auto set
                            var changeValidation = traveller.MetaData.HasPeConditionChangedValidation;
                            traveller.MetaData.HasPeConditionChangedValidation = function () { };
                            if (defaultMandatoryPEAge !== undefined && dt.age() >= defaultMandatoryPEAge) {
                                traveller.MetaData.HasPeCondition("true");
                                traveller.MetaData.PeOptionsEnforced(true);
                            } else {
                                traveller.MetaData.PeOptionsEnforced(false);
                            }
                            traveller.MetaData.HasPeConditionChangedValidation = changeValidation;
                            return dt.age();
                        }, write: function (newValue) {
                            if (newValue === '' || typeof newValue === 'undefined') {
                                traveller.DateOfBirth(undefined)
                            }
                            else if (newValue >= 0 && newValue <= 999) {
                                traveller.DateOfBirth.formattedDate('1/1/' + ((new Date).getFullYear() - newValue))
                            }
                            else {
                                traveller.DateOfBirth(null)
                            }
                        }, owner: self
                    });
                    traveller.MetaData.HasSetNewAge = true;
                    viewModel.MetaData.AllTravellers.notifySubscribers();
                }
            }
        });
    }
    viewModel.MetaData.AllTravellers.subscribe(function () {
        viewModel.fn.FixTravellers();
    });

    viewModel.MetaData.forceHasOtherTravellers = ko.computed(function () {
        return ko.utils.arrayFirst(viewModel.MetaData.AllTravellers(), function (traveller) {
            return ko.unwrap(traveller.MetaData.PeOptionsEnforced) === true;
        }) != null;
    }, this);

    viewModel.fn.DoHealixAssessment = function (traveller) {
        var result = $.grep(viewModel.MetaData.AllTravellers(), function (e) {
            return (e.HealixAssessment() && e.HealixAssessment().ScreeningId() > 0)
        });
        var policyHolderCount = viewModel.PolicyHolders().length + viewModel.PolicyDependants().length;
        viewModel.PeOptions.FirstHolderFlag(result.length !== 0 || policyHolderCount === 1);
        $.each(viewModel.MetaData.AllTravellers(), function (i, value) {
            if (traveller == value) {
                value.HealixAssessment().PeId(1)
            } else {
                value.HealixAssessment().PeId(0)
            }
        });

        if (traveller.DateOfBirth() && (traveller.MetaData.age() >= viewModel.PeOptions.MetaData.MandatoryAssessmentAge())) {
            $$.Client.showHealixAssessment(traveller, undefined);
        } else {
            $$.Client.showHealixAssessment(traveller, 'false');
        }
    }
    ko.utils.arrayForEach(viewModel.MetaData.AllTravellers(), function (traveller) {
        var selected = traveller.HasPeCondition();
        if (selected === 'true' || selected === true) {
            traveller.HasPeCondition('true');
        }
        if (selected === 'false' || selected === false) {
            traveller.HasPeCondition('false');
        }

        traveller.MetaData.hasCompletedPeAssessment = ko.observable(true);
        traveller.MetaData.HasPeCondition.subscribe((function (newValue) {
            if (ko.unwrap(traveller.MetaData.HasPeCondition) === false || ko.unwrap(traveller.MetaData.HasPeCondition) === "false") {
                traveller.MetaData.hasCompletedPeAssessment(true);
            }
        }));

        traveller.MetaData.hasCompletedPeAssessment.extend({ 
            equal: { params: true, message: viewModel.MetaData.AllTravellers().length > 1 ? PrismApi.Validation.messages.travellers.requiredPEAssessmentCompleted: PrismApi.Validation.messages.travellers.requiredPEAssessmentCompletedForOneTraveller
            }
        });
    });

    viewModel.MetaData.showHealixAssessmentSummary = ko.observable()
}

function addAdjustmentValidationRules(viewModel) {
    ko.utils.arrayForEach(viewModel.Adjustments(), function (adjustment) {
        var question = typeof adjustment.Question === 'function' ? adjustment.Question() : adjustment.Question;
        var allPromos = ko.utils.arrayMap(viewModel.MetaData.PromoAdjustments(), function (item) { return item.Value; });
        if (question) {
            var errorMessage = getQuestionValidationErrorMsg(question.BriefCode());
            if (errorMessage.length == 0) {
                errorMessage = PrismApi.Validation.messages.travellers.requiredQuestion.format(question.Description());
            }

            question.Answer.extend({
                required: { params: true, message: errorMessage }
            })
        }

        if (adjustment.MetaData && adjustment.MetaData.ValueTitle) {
            var message = PrismApi.Validation.messages.adjustments.requiredAdjustment.format(ko.utils.unwrapObservable(adjustment.MetaData.ValueTitle));
            var isPromo = $.inArray(adjustment.BriefCode(), promoCodeBriefCodes) > -1;
            if (isPromo && allPromos.length == 1) {
                message = promoCodeErrorMessage;
            }
            if (!isPromo) {
                if (adjustment.MetaData.MinLength) {
                    var minLenRule = ko.utils.unwrapObservable(adjustment.MetaData.MinLength);
                    if (minLenRule) {
                        adjustment.Value.extend({
                            minLength: { params: minLenRule, message: PrismApi.Validation.messages.adjustments.invalidAdjustment.format(ko.utils.unwrapObservable(adjustment.MetaData.ValueTitle)) }
                        });
                    }
                }

            }
            if (adjustment.MetaData.MaxLength) {
                var maxLenRule = ko.utils.unwrapObservable(adjustment.MetaData.MaxLength);
                if (maxLenRule) {
                    adjustment.Value.extend({
                        maxLength: { params: maxLenRule, message: PrismApi.Validation.messages.adjustments.invalidAdjustment.format(ko.utils.unwrapObservable(adjustment.MetaData.ValueTitle)) }
                    });
                }
            }
        }
    });
};

function afterQuickQuoteOptionsLoaded(quickQuoteOptions) {
    var promoCodeAdjustment = ko.utils.arrayFirst($$.policy.Adjustments(), function (adjustments) { return adjustments.BriefCode() == 'DUMMY'; });
    if (promoCodeAdjustment) {
        promoCodeAdjustment.Value.extend({ uppercase: true });
    }

    //Add validationo
    if (quickQuoteOptions.MaxDurationDays == 365 || quickQuoteOptions.MaxDurationDays == 366) {
        var minDate = Date.create(PrismApi.Client.todayDateString).getDateOnly();
        var maxDate = Date.create(PrismApi.Client.todayDateString).advance({ day: -1, year: 1 }).getDateOnly();
        var durations = (maxDate - minDate) / 1000 / 60 / 60 / 24;
        $$.policy.EndDate.formattedDate.extend({
            maxDuration: {
                params: [$$.policy.StartDate, durations, 'day'],
                message: PrismApi.Validation.messages.maxDurationTravelDates1Year
            }
        });
    } else {
        $$.policy.EndDate.formattedDate.extend({
            maxDuration: {
                params: [$$.policy.StartDate, quickQuoteOptions.MaxDurationDays, 'day'],
                message: PrismApi.Validation.messages.maxDurationTravelDates.format(quickQuoteOptions.MaxDurationDays)
            }
        });
    }

    for (var travellerIndex = 0; travellerIndex < $$.quickQuoteOptions().MinAdults; travellerIndex++) {
        $$.policy.MetaData.AdultAges()[travellerIndex].MetaData.age.extend({
            required: { params: true, message: function () { var dependant = ko.utils.arrayFilter($$.policy.MetaData.DependantAges(), function (data) { return data.MetaData.age() != ""; }).length > 0; if (dependant) { return PrismApi.Validation.messages.travellers.invalidMinAdults.format($$.quickQuoteOptions().MinAdults); } else { return PrismApi.Validation.messages.travellers.requiredAtLeastOneTraveller } } }
        });
    }
    for (var travellerIndex = 0; travellerIndex < $$.quickQuoteOptions().MinDependants; travellerIndex++) {
        $$.policy.MetaData.DependantAges()[travellerIndex].MetaData.age.extend({
            required: { params: true, message: PrismApi.Validation.messages.travellers.invalidMinDependants.format($$.quickQuoteOptions().MinDependants) }
        });
    }

    $$.policy.MetaData.QuickQuoteOptionsReady(true);

    if ($$.newPolicy) {

        $$.newPolicy.fn.applyQuickQuoteOptionsToViewModel()

        $$.newPolicy.MetaData.MaxDependants($$.policy.MetaData.MaxDependants());
        $$.newPolicy.MetaData.MinDependants($$.policy.MetaData.MinDependants());

        $$.newPolicy.MetaData.MaxAdults($$.policy.MetaData.MaxAdults());
        $$.newPolicy.MetaData.MinAdults($$.policy.MetaData.MinAdults());

        var newPolicyPromoAdjustment = ko.utils.arrayFirst($$.newPolicy.Adjustments(), function (adjustments) { return adjustments.BriefCode() == 'DUMMY'; });
        if (newPolicyPromoAdjustment) {
            newPolicyPromoAdjustment.Value.extend({ uppercase: true });
        }

        addAdjustmentValidationRules($$.newPolicy);
    }

}

function fixDestinations(policy) {
    //move the destinations
    if (!policy) policy = $$.policy;

    var selectedRegions = JSON.parse('[' + policy.MetaData.Countries().replace(/\|/g, ',') + ']');
    var mostImportantRegion;
    policy.Destinations.removeAll();
    ko.utils.arrayForEach(selectedRegions, function (item) {
        var existingRegion = ko.utils.arrayFirst(policy.Destinations(), function (existingDestination) {
            if (ko.utils.unwrapObservable(existingDestination.BriefCode) == item.BriefCode) {
                if (existingDestination.Country && ko.utils.unwrapObservable(existingDestination.Country.BriefCode) == item.Country.BriefCode) {
                    if (item.Country && item.Country.Location && ko.utils.unwrapObservable(existingDestination.Country.Location) && ko.utils.unwrapObservable(existingDestination.Country.Location.BriefCode) == item.Country.Location.BriefCode) {
                        return true;
                    }
                }
            }
            return false;
        });
        if (item.Country && item.Country.Location && !ko.utils.unwrapObservable(item.Country.Location.BriefCode)) {
            item.Country.Location = null;
        }
        if (existingRegion) {

        } else {
            policy.Destinations.push(ko.mapping.fromJS(item));
        }
        var oldRegion = ko.utils.arrayFirst(policy.MetaData.Regions(), function (reg) { return ko.utils.unwrapObservable(reg.BriefCode) == ko.utils.unwrapObservable(item.BriefCode) });
        if (oldRegion && (mostImportantRegion == null || mostImportantRegion.SortOrder < oldRegion.SortOrder)) {
            mostImportantRegion = oldRegion;
        }
    });
    if (mostImportantRegion) {
        policy.Region(mostImportantRegion);
    }
}
function getQuestionValidationErrorMsg(briefCode) {
    if (briefCode == 'RESID')
        return PrismApi.Validation.messages.travellers.requiredResidentsOfCountry;
    else if (briefCode == 'TEMPR')
        return PrismApi.Validation.messages.travellers.requiredTempResidentsOfCountry;
    else if (briefCode == 'MEMBR')
        return PrismApi.Validation.messages.travellers.requiredPartnerMember;
    else if (briefCode == 'TRIP')
        return PrismApi.Validation.messages.travellers.requiredPurposeOfTrip;
    else if (briefCode == 'REFER')
        return PrismApi.Validation.messages.travellers.requiredPartnerReferer;
    else
        return "";
}

function getTextByBriefCode(briefCode, country) {
    if (briefCode == "RESID")
        return "A Resident of Australia is someone who currently resides in Australia and is eligible for an Australian Medicare Card.";
    else if (briefCode == "TEMPR")
        return "Cover is available if you are a temporary resident of Australia and you hold a return ticket to Australia, have a home address in Australia to which you intend to return, and you hold a current Australian visa which will remain valid beyond the period for your journey.";
    else
        return "";
}

function isLocalStorageNameSupported() {
    try {
        var testKey = 'test', storage = window.sessionStorage;
        storage.setItem(testKey, '1');
        storage.removeItem(testKey);
        return true;
    } catch (error) {
        return false;
    }
}

function isCookieSupported() {
    try {
        var cookieEnabled = (navigator.cookieEnabled) ? true : false;

        if (typeof navigator.cookieEnabled == "undefined" && !cookieEnabled) {
            document.cookie = "testcookie";
            cookieEnabled = (document.cookie.indexOf("testcookie") != -1) ? true : false;
        }
        return (cookieEnabled);
    } catch (error) {
        return false;
    }
}

function ValidatePromoCode(adjustment) {
  
    adjustment.MetaData.ValueUsedForPremium(adjustment.Value());
    //adjustment.MetaData.IsPromoValid(undefined);
    adjustment.Premium(undefined);

    $$.policy.MetaData.RecalculateTimer({
        "doPageValidation": false,
        "displayError":
            function (error) {
                $$.Client.displayError(error);
            },
        "onComplete": function () {
            //adjustment.Value.isModified(false);
            adjustment.MetaData.IsPromoValid(true);
        }
    });
}


function keepAlive() {
    PrismApi.Utils.ajaxCall("Session/KeepAlive").done(function (response) {
        console.log('keep-alive');
    });
}

initCountries = function (element, callback) {
    callback(this.initCountriesParser($$.policy));
};

initCountriesNewPolicy = function (element, callback) {
    callback(this.initCountriesParser($$.newPolicy));
};

initCountriesParser = function (viewModel) {
    var data = [];
    var regionItems = JSON.parse('[' + (viewModel.MetaData.Countries() || '').replace(/\|/g, ',') + ']');
    ko.utils.arrayForEach(regionItems, function (decodedItem) {
        data.push(EncodeLocation(decodedItem, decodedItem.Country, (decodedItem.Country && decodedItem.Country.Location && decodedItem.Country.Location.BriefCode) ? decodedItem.Country.Location : null));
    });

    return data;
};

this.EncodeRegion = function (region, country, location) {
    var item = { 'BriefCode': ko.utils.unwrapObservable(region.BriefCode), 'Description': ko.utils.unwrapObservable(region.Description) };
    if (country && ko.utils.unwrapObservable(country.BriefCode)) {
        item.Country = { 'BriefCode': ko.utils.unwrapObservable(country.BriefCode), Description: ko.utils.unwrapObservable(country.Description) };
    }

    if (country && location && ko.utils.unwrapObservable(location.BriefCode)) {
        item.Country.Location = { 'BriefCode': ko.utils.unwrapObservable(location.BriefCode), Description: ko.utils.unwrapObservable(location.Description) };
    }
    return JSON.stringify(item).replace(/,/g, '|');
};

this.EncodeLocation = function (region, country, location) {
    //Encode the id as a JSON object but replace the , with | so that it doens't stuff up the selection code in Select2
    var id = EncodeRegion(region, country, location);
    if (!country) return { 'id': id, 'text': '' };
    if (location && location.BriefCode) {
        return { 'id': id, 'text': country.Description + ' (' + location.Description + ')' }
    } else {
        return { 'id': id, 'text': country.Description }
    }
};
var countrySearchRegex = function (query) {
    return new RegExp("^" + query.term, 'i');
}
this.findCountries = function (query) {

    query.callback(findCountriesParse(query, $$.policy));
};

this.findCountriesNewPolicy = function (query) {

    query.callback(findCountriesParse(query, $$.newPolicy));
};

this.findCountriesParse = function (query, viewModel) {
    var results = [];
    if (query.term.length == 0) {
        // most popular
        var popularRegions = [];
        ko.utils.arrayForEach(viewModel.MetaData.Regions(), function (region) {
            var regionCountries = ko.utils.arrayFilter(ko.utils.unwrapObservable(region.Countries), function (country) {
                return ko.utils.unwrapObservable(country.Popularity) > 0;
            });
            if (regionCountries.length > 0) {
                var newRegion = jQuery.extend({}, region);
                newRegion.Countries = regionCountries;
                popularRegions.push(newRegion);
            }
        })
        popularRegions = popularRegions.sort(function (a, b) { return ko.utils.unwrapObservable(a.SortOrder) - ko.utils.unwrapObservable(b.SortOrder); });

        results.push({ 'text': 'Select from most popular' });

        ko.utils.arrayForEach(popularRegions, function (region) {
            var reg = { 'text': ko.utils.unwrapObservable(region.Description), 'children': [] }
            results.push(reg);

            ko.utils.arrayForEach(region.Countries, function (country) {
                if (country.Popularity > 0) {
                    reg.children.push(EncodeLocation(region, country));
                }
                if (country.Locations) {
                    ko.utils.arrayForEach(country.Locations, function (location) {
                        if (location.Popularity > 0) {
                            reg.children.push(EncodeLocation(region, country, location));
                        }
                    });
                }
            });
        });
    } else {
        var selectedRegions = JSON.parse('[' + viewModel.MetaData.Countries().replace(/\|/g, ',') + ']');

        ko.utils.arrayForEach(viewModel.MetaData.Regions(), function (region) {
            ko.utils.arrayForEach(ko.unwrap(region.Countries), function (country) {
                var found = ko.utils.arrayFirst(selectedRegions, function (selected) {
                    return selected.country === country.BriefCode;
                });

                if (!found) {
                    if (country.Description.search(countrySearchRegex(query)) >= 0) {
                        results.push(EncodeLocation(region, country));
                    }
                    if (country.Locations) {
                        ko.utils.arrayForEach(country.Locations, function (location) {
                            var found = ko.utils.arrayFirst(selectedRegions, function (selected) {
                                return selected.location === location.BriefCode;
                            });
                            if (location.Description.search(countrySearchRegex(query)) >= 0) {
                                results.push(EncodeLocation(region, country, location));
                            }
                        });
                    }
                }
            });
        });

        results = results.sort(function (a, b) {
            if (a.text < b.text) return -1;
            if (a.text > b.text) return 1;
            return 0;
        });
    }

    var data = { 'results': results };

    return data;
};



var showMap = function () {

    var offColor;
    var onColor;
    var strokeColor;
    var mapWidth;
    var mapHeight;
    var useSideText;
    var textAreaWidth;
    var textAreaPadding;
    var textAreaHeight;

    var mouseX = 0;
    var mouseY = 0;
    var current = null;

    var mapZoom = 1;
    var originW = 960;
    var originH = 480;
    var curMapX = 0;
    var curMapY = 0;
    var viewBoxCoords = [curMapX, curMapY, originW, originH];
    var maxTransX, maxTransY, minTransX, maxTransY;

    var maxX = 0;
    var scale = 1;
    var isOverCountry = false;
    var draggable = false;
    var _window = $(window);
    var dragStartX = 0;
    var dragStartY = 0;
    var curMouseX = 0;
    var curMouseY = 0;
    var mapOffset = 0;
    var map;
    var backPan;

    var r;
    var pan = {};
    var originViewBox = {};
    var isPanning = false;
    var strokeWidth = 0;

    var readyToAnimate = true;

    var regioncdcovered = '';
    var regioncdalsocovered = '';
    var isIE8 = false;

    offColor = '#CCCCCC';
    onColor = '#006600';
    strokeColor = '#24221f';
    mapWidth = '520';
    mapHeight = '260';
    useSideText = 'false';
    textAreaWidth = '300';
    textAreaPadding = '10';
    strokeWidth = '.5';
    textAreaHeight = '300';

    var mapCountries = [];
    ko.utils.arrayForEach($$.policy.MetaData.Regions(), function (region) {
        if (ko.utils.unwrapObservable(region.Countries)) {
            ko.utils.arrayForEach(ko.utils.unwrapObservable(region.Countries), function (country) {
                mapCountries.push(country);
            });
        }
    });

    ko.utils.arrayForEach(mapCountries, function (country) {

        if (country.RegionName == "Worldwide") {
            country.Mode = 'ON';
            country.Colors = onColor;
            country.OverColors = onColor;
            country.ClickedColors = onColor;
        } else {
            country.Mode = 'ON';
            country.Colors = offColor;
            country.OverColors = offColor;
            country.ClickedColors = offColor;
        }
    });

    map = $('#map');
    mapOffset = map.offset();

    createMap(mapCountries);

    function createMap(mapCountries) {

        //start map
        r = new ScaleRaphael('map', originW, originH);

        var resizePaper = function () {
            var win = $(this);
            r.changeSize($('.mapWrapper').width(), $('.mapWrapper').height(), true, false);
        }
        $(window).resize(resizePaper);

        var attributes = {
            fill: '#d9d9d9',
            cursor: 'pointer',
            stroke: strokeColor,
            'stroke-width': strokeWidth,
            'stroke-linejoin': 'round'
        };
        //arr = new Array();

        var countries = [];
        var isWorldwide = false;

        ko.utils.arrayForEach($$.policy.Destinations(), function (destination) {
            if (destination.Country && destination.Country.BriefCode()) {
                countries.push(destination.Country.BriefCode());
                if (destination.BriefCode() == 'WORLD') {
                    isWorldwide = true;
                }
            }
        });

        var fillColors = [];
        if ($('html.ie8').length > 0) {
            isIE8 = true;
            var $p = $("<div class='primary-region'></div>").hide().appendTo("body");
            fillColors.push($p.css("background-color"));
            $p.remove();
            var $p1 = $("<div class='secondary-region'></div>").hide().appendTo("body");
            fillColors.push($p1.css("background-color"));
            $p1.remove();
        }

        //Each country
        for (var country in paths) {
            countryProperty = paths[country];
            //Create obj
            var obj = r.path(paths[country].path);
            obj.attr(attributes);

            var country = ko.utils.arrayFirst(mapCountries, function (result) {
                return result.BriefCode == countryProperty.MidasCountry;
            });

            if (!country) {
                console.log('Unable to find: ' + country);
                continue;
            }

            //this won't work on IE8. The next line sort of works but it won't refresh properly.
            //obj.node.setAttribute("data-bind", "'attr': {'class': countries().indexOf('WWW') >= 0 ? 'worldwide' : countries().indexOf('" + country.MidasCountry + "') >= 0 ? 'selected-country' : 'unselected-country'}");
            //obj.node.setAttribute("data-bind", "'attr': {'fillcolor': countries().indexOf('WWW') >= 0 ? 'worldwide' : countries().indexOf('" + country.MidasCountry + "') >= 0 ? 'red' : 'blue'}");
            /*
			if (isWorldwide) {
				obj.node.setAttribute("class", "worldwide");
			} else {
				if (countries.indexOf(country.BriefCode) >= 0) {
					obj.node.setAttribute("class", "selected-country");
				} else {
					obj.node.setAttribute("class", "unselected-country");
				}
			}*/
            /*
			var regionBriefCode = '';
			if (country.BriefCode) {
				var region = ko.utils.arrayFirst($$.policy.MetaData.Regions(), function (region) { if (region.Countries()) return ko.utils.arrayFirst(region.Countries(), function (country1) { return country1.BriefCode == country.BriefCode; }) })
				regionBriefCode = region ? 'region-' + region.BriefCode() : '';
			};
			obj.node.setAttribute("class", 'country-' + country.BriefCode + ' ' + regionBriefCode);
			*/

            var regionBriefCode = '';
            if (country.BriefCode) {
                var region = ko.utils.arrayFirst($$.policy.MetaData.Regions(), function (region) { if (ko.utils.unwrapObservable(region.Countries)) return ko.utils.arrayFirst(ko.utils.unwrapObservable(region.Countries), function (country1) { return country1.BriefCode == country.BriefCode; }) })
                var pricingRegion = ko.utils.arrayFirst($$.policy.PricingRegions(), function (pregion) {
                    return pregion.BriefCode() == ko.utils.unwrapObservable(region.BriefCode);
                });
                if (pricingRegion) {
                    if (isWorldwide || pricingRegion.MetaData.IsPrimaryRegion()) {
                        regionBriefCode = 'primary-region';
                    } else {
                        regionBriefCode = 'secondary-region';
                    }
                    country.isSelected = true;
                }
            } else {
                country.isSelected = false;
            }

            // IF ie<9 need to explicitly set colour
            if (!isIE8) {
                var currentNodeAttr = obj.node.getAttribute("class");
                obj.node.setAttribute("class", currentNodeAttr + " " + regionBriefCode);
            }

            if (country.Mode == 'OFF') {
                obj.attr({
                    fill: offColor,
                    cursor: 'default'
                });

            } else {

                obj.attr({
                    fill: country.Colors,
                    font: 'arial'
                });

                obj.CountryName = country.Description + (country.isSelected === true ? ' - Covered' : ' - Not Covered');
                obj.CountryCode = country.BriefCode;
                obj.MidasCountry = country.BriefCode;
                obj.Colors = country.Colors;
                obj.OverColors = country.OverColors;
                obj.ClickedColors = country.ClickedColors;

                //Countries mouse over
                obj.mouseover(function (e) {

                    if (!isPanning) {
                        isOverCountry = true;
                        this.attr({
                            cursor: 'pointer'
                        });

                        //Animate if not already the current country
                        if (this != current) {
                            this.animate({
                                //fill: this.Colors
                            }, 500);
                        }

                        //tooltip
                        var point = this.getBBox(0);
                        $('#map').next('.map-label').remove();
                        $('#map').after($('<div />').addClass('map-label'));
                        //var cssObj = isIE8 ? { left: mouseX - 50, top: mouseY - 70 } : { left: mouseX - 650, top: mouseY - 110 };
                        var cssObj = { left: mouseX - 50, top: mouseY - 70 };
                        $('.map-label').html(this.CountryName).css(cssObj).fadeIn();
                    } else {
                        this.attr({
                            cursor: 'move'
                        });
                    }

                });

                //Countries mouse out
                obj.mouseout(function (e) {

                    if (!isPanning) {
                        isOverCountry = false;

                        if (this != current) {
                            this.animate({
                                //fill: this.Colors
                            }, 500);
                        }
                        $('#map').next('.map-label').remove();
                    }

                });

                //Country clicked
                obj.mouseup(function (e) {
                    if (!isPanning) {
                        current = this;
                        var items = $("#country-selector").val().split(',');
                        if ($("#country-selector").val() == '') items = [];
                        var index = items.indexOf(this.MidasCountry);
                        if (index >= 0) {
                            items.splice(index, 1);
                        } else {
                            items.push(this.MidasCountry);
                        }
                        $("#country-selector").val(items.join(',')).trigger("change");
                    }

                });
            }

            // IF IE < 9 need to explicitly set colour
            if (isIE8) {
                if (regionBriefCode === 'primary-region') {
                    obj.attr({
                        fill: fillColors[0]
                    });
                } else if (regionBriefCode === 'secondary-region') {
                    obj.attr({
                        fill: fillColors[1]
                    });
                }
            }
        }


        //Resize map first
        resizeMap(r);
        resizePaper();

        // reset originW/H for IE < 9
        if (isIE8) {
            originW = originW / 1.9;
            originH = originH / 1.9;
        }

        resetMap(r);

        $('.console').fadeIn();

        //Create invisible raphael rectangle for panning
        backPan = r.rect(viewBoxCoords[0], viewBoxCoords[1], viewBoxCoords[2], viewBoxCoords[3]).attr({
            fill: '#F00',
            'fill-opacity': 0,
            'stroke': 'none'
        }).data({
            disabled: true,
            'name': '_backpan'
        }).toBack();

        //Add panning event handlers
        backPan.drag(panMove, panStart, panEnd);

        //Add mouse wheel handler for zoom
        map.bind('mousewheel.map', function (event, delta, deltaX, deltaY) {

            if (readyToAnimate) {
                readyToAnimate = false;
                mapZoom += delta / 2;
                if (mapZoom <= 1) mapZoom = 1;
                if (mapZoom == 1) resetMap(r);
                if (mapZoom == 1 && delta < 0) return;

                if (!isIE8)
                    getViewBox();

                var vWidth = viewBoxCoords[2];
                var vHeight = viewBoxCoords[3];

                viewBoxCoords[2] = originW / mapZoom;
                viewBoxCoords[3] = originH / mapZoom;

                viewBoxCoords[0] += (vWidth - viewBoxCoords[2]) / 2;
                viewBoxCoords[1] += (vHeight - viewBoxCoords[3]) / 2;

                r.animateViewBox(originViewBox, viewBoxCoords[0], viewBoxCoords[1], viewBoxCoords[2], viewBoxCoords[3], 250, animationFinished);

                scale = originW / viewBoxCoords[2];
                scale = scale.toFixed(1);

                return false;
            }
        });


        //mouse move to change cursor for panning
        map.mousemove(function (event) {

            if (!isOverCountry && mapZoom != 1) {
                $(this).css('cursor', 'move');
            } else {
                $(this).css('cursor', 'default');
            }

        });


        //butons hacked from mister fish :P
        //zoom in
        $('#zoomerIn').click(function (e) {
            if (readyToAnimate) {
                readyToAnimate = false;
                mapZoom += .5;
                getViewBox();

                var vWidth = viewBoxCoords[2];
                var vHeight = viewBoxCoords[3];

                viewBoxCoords[2] = originW / mapZoom;
                viewBoxCoords[3] = originH / mapZoom;

                viewBoxCoords[0] += (vWidth - viewBoxCoords[2]) / 2;
                viewBoxCoords[1] += (vHeight - viewBoxCoords[3]) / 2;

                //r.setViewBox(viewBoxCoords[0], viewBoxCoords[1], viewBoxCoords[2], viewBoxCoords[3], false);
                r.animateViewBox(originViewBox, viewBoxCoords[0], viewBoxCoords[1], viewBoxCoords[2], viewBoxCoords[3], 250, animationFinished);

                scale = originW / viewBoxCoords[2];
                scale = scale.toFixed(1);

                e.stopPropagation();
                e.preventDefault();
            }
        });

        //zoom out
        $('#zoomerOut').click(function (e) {
            if (readyToAnimate) {
                readyToAnimate = false;
                if (mapZoom == 1) {
                    resetMap(r);
                    return;
                }
                mapZoom -= .5;
                getViewBox();
                var vWidth = viewBoxCoords[2];
                var vHeight = viewBoxCoords[3];

                viewBoxCoords[2] = originW / mapZoom;
                viewBoxCoords[3] = originH / mapZoom;

                viewBoxCoords[0] += (vWidth - viewBoxCoords[2]) / 2;
                viewBoxCoords[1] += (vHeight - viewBoxCoords[3]) / 2;


                //r.setViewBox(viewBoxCoords[0], viewBoxCoords[1], viewBoxCoords[2], viewBoxCoords[3], false);
                r.animateViewBox(originViewBox, viewBoxCoords[0], viewBoxCoords[1], viewBoxCoords[2], viewBoxCoords[3], 250, animationFinished);

                scale = originW / viewBoxCoords[2];
                scale = scale.toFixed(1);

                e.stopPropagation();
                e.preventDefault();
            }

        });

        //Reset zoom and pan
        $('#zoomerReset').click(function (e) {
            resetMap(r);

            e.stopPropagation();
            e.preventDefault();
        });

        //Manual panning not needed anymore

        $('#zoomerUp').click(function (e) {
            viewBoxCoords[1] -= 20;

            if (viewBoxCoords[1] <= 0) viewBoxCoords[1] = 0;
            r.setViewBox(viewBoxCoords[0], viewBoxCoords[1], viewBoxCoords[2], viewBoxCoords[3], false);

            e.stopPropagation();
            e.preventDefault();
        });

        //move down
        $('#zoomerDown').click(function (e) {
            viewBoxCoords[1] += 20;
            var limitY = originH - viewBoxCoords[3];

            if (viewBoxCoords[1] >= limitY) viewBoxCoords[1] = limitY;
            r.setViewBox(viewBoxCoords[0], viewBoxCoords[1], viewBoxCoords[2], viewBoxCoords[3], false);

            e.stopPropagation();
            e.preventDefault();
        });

        //move left
        $('#zoomerLeft').click(function (e) {
            viewBoxCoords[0] -= 20;

            if (viewBoxCoords[0] <= 0) viewBoxCoords[0] = 0;
            r.setViewBox(viewBoxCoords[0], viewBoxCoords[1], viewBoxCoords[2], viewBoxCoords[3], false);

            e.stopPropagation();
            e.preventDefault();
        });

        //move right
        $('#zoomerRight').click(function (e) {
            viewBoxCoords[0] += 20;
            var limitX = originW - viewBoxCoords[2];

            if (viewBoxCoords[0] >= limitX) viewBoxCoords[0] = limitX;
            r.setViewBox(viewBoxCoords[0], viewBoxCoords[1], viewBoxCoords[2], viewBoxCoords[3], false);

            e.stopPropagation();
            e.preventDefault();
        });

    }

    function getViewBox() {
        originViewBox.x = viewBoxCoords[0];
        originViewBox.y = viewBoxCoords[1];
        originViewBox.width = viewBoxCoords[2];
        originViewBox.height = viewBoxCoords[3];
    }

    function animationFinished(x, y, w, h) {
        originViewBox.x = x;
        originViewBox.y = y;
        originViewBox.width = w;
        originViewBox.height = h;

        readyToAnimate = true;
    }

    //Pan start handler
    function panStart() {
        pan.dx = viewBoxCoords[0];
        pan.dy = viewBoxCoords[1];

        isPanning = true;
    };

    //Pan move handler
    function panMove(dx, dy) {
        pan.dx = viewBoxCoords[0] - dx / scale;
        pan.dy = viewBoxCoords[1] - dy / scale;

        var limitY = originH - viewBoxCoords[3];
        var limitX = originW - viewBoxCoords[2];

        if (pan.dx >= limitX) pan.dx = limitX;
        if (pan.dx <= 0) pan.dx = 0;

        if (pan.dy >= limitY) pan.dy = limitY;
        if (pan.dy <= 0) pan.dy = 0;

        r.setViewBox(pan.dx, pan.dy, viewBoxCoords[2], viewBoxCoords[3], false);
    };

    //Pan end handler
    function panEnd() {
        isPanning = false;

        viewBoxCoords[0] = pan.dx;
        viewBoxCoords[1] = pan.dy;
    };


    //Reset zoom and pan
    function resetMap(map) {
        mapZoom = 1;

        viewBoxCoords[0] = -60;
        viewBoxCoords[1] = -10;
        viewBoxCoords[2] = originW;
        viewBoxCoords[3] = originH;

        originViewBox.x = 0;
        originViewBox.y = 0;
        originViewBox.width = originW;
        originViewBox.height = originH;

        //map.setViewBox(viewBoxCoords[0], viewBoxCoords[1], viewBoxCoords[2], viewBoxCoords[3], false);
        map.animateViewBox(originViewBox, viewBoxCoords[0], viewBoxCoords[1], viewBoxCoords[2], viewBoxCoords[3], 250, animationFinished);

        readyToAnimate = true;
    }

    // Set up for mouse capture
    if (document.captureEvents && Event.MOUSEMOVE) {
        document.captureEvents(Event.MOUSEMOVE);
    }

    // Main function to retrieve mouse x-y pos.s

    function getMouseXY(e) {
        var scrollTop = $(window).scrollTop();
        if (e && e.pageX && !(document.all && !window.atob)) {
            mouseX = e.pageX - $('#map').closest('.modal-content').offset().left;
            mouseY = e.pageY - scrollTop - $('#map').closest('.modal-content').offset().top;
        } else {
            mouseX = event.clientX + document.body.scrollLeft;
            mouseY = event.clientY + document.body.scrollTop;
        }
        // catch possible negative values
        if (mouseX < 0) {
            mouseX = 0;
        }
        if (mouseY < 0) {
            mouseY = 0;
        }

        //var cssObj = isIE8 ? { left: mouseX - 50, top: mouseY - 70 } : { left: mouseX - 650, top: mouseY - 110 };
        var cssObj = { left: mouseX - 50, top: mouseY - 70, 'z-index': 9999 };
        $('#map').next('.map-label').css(
		    cssObj
		);
    }

    // Set-up to use getMouseXY function onMouseMove
    document.body.onmousemove = getMouseXY;


    function resizeMap(paper) {
        paper.changeSize(mapWidth, mapHeight, true, false);

        if (useSideText == 'true') {
            $(".mapWrapper").css({
                'width': '100%',
                'height': mapHeight + 'px'
            });
        } else {
            $(".mapWrapper").css({
                'width': '100%',
                'height': mapHeight + 'px'
            });
        }
    }
};

// Jrespond wiring to helper observables on the viewmodel
(function ($, undefined) {
    'use strict';
    $$.Client = $$.Client || {};
    $$.Client.Util = $$.Client.Util || {};
    $$.Client.Util.MobileFunctions = $$.Client.Util.MobileFunctions || {};

    // jrespond helper functions
    $$.Client.Util.MobileFunctions.MobileView = ko.observable(false);
    $$.Client.Util.MobileFunctions.TabletView = ko.observable(false);
    $$.Client.Util.MobileFunctions.DesktopView = ko.observable(true);

    $$.Client.Util.MobileFunctions.Breakpoints = [
        {
            label: 'phone', enter: 0, exit: 767
        },
        {
            label: 'tablet', enter: 768, exit: 979
        },
        {
            label: 'desktop', enter: 980, exit: 1199
        }
    ];

    // Jrespond setup
    $$.Client.Util.MobileFunctions.jRespond = jRespond($$.Client.Util.MobileFunctions.Breakpoints);
    // Wire in observable changes on breakponts
    $$.Client.Util.MobileFunctions.jRespond.addFunc({
        breakpoint: ['phone'],
        enter: function () {
            $$.Client.Util.MobileFunctions.MobileView(true);
            $$.Client.Util.MobileFunctions.TabletView(false);
            $$.Client.Util.MobileFunctions.DesktopView(false);
        }
    });
    $$.Client.Util.MobileFunctions.jRespond.addFunc({
        breakpoint: ['tablet'],
        enter: function () {
            $$.Client.Util.MobileFunctions.MobileView(false);
            $$.Client.Util.MobileFunctions.TabletView(true);
            $$.Client.Util.MobileFunctions.DesktopView(false);
        }
    });
    $$.Client.Util.MobileFunctions.jRespond.addFunc({
        breakpoint: ['desktop'],
        enter: function () {
            $$.Client.Util.MobileFunctions.MobileView(false);
            $$.Client.Util.MobileFunctions.TabletView(false);
            $$.Client.Util.MobileFunctions.DesktopView(true);
        }
    });
})(jQuery);

;
/* 
 * Name: validation-messages.js
 * Description: Override PrismApi.Validation.Messages and extend with new messages
 *
 */
var PrismApi = PrismApi || {};
PrismApi.Validation = PrismApi.Validation || {};
PrismApi.Validation.messages = $.extend({}, PrismApi.Validation.messages, {
    requiredRegion: "Please select your travel region.",
    requiredRegionMostTime: "Please select where most time will be spent in.",
    requiredCountry: "Please enter destination countries.",
    requiredCountryForWorldwide: "You must include at least one additional destination country when Worldwide has been selected. Select the country where you will be spending the longest time in.",
    requiredTruePrivacyAgree: 'Please confirm you have read and understood the Product Disclosure Statement, Duty of Disclosure, Privacy Notice and Financial Services Guide.',
    labelStartDate: 'Departure date',
    labelEndDate: 'Return date',
    invalidStartDateFormat: 'Please enter a valid departure date (dd/mm/yyyy).',
    invalidEndDateFormat: 'Please enter a valid return date (dd/mm/yyyy).',
    invalidStartDate: "{1} must be within 12 months from today's date.",
    invalidStartDateLeadtime: "Departure date must be within {0} from today's date.",
    invalidEndDate: 'Please enter a valid return date (dd/mm/yyyy).',
    requiredPartner: 'Please select a partner',
    maxDurationTravelDates1Year: "Return date cannot be greater than 12 months from the departure date.",
    maxDurationTravelDates: "Return date cannot be greater than {0} days from the departure date",
    groupPolicy: 'We can provide a quote for a maximum of two adults online.<br/> <br/> If there are more than 2 adults travelling, please call our Sales team on {0} to arrange a group policy.',
    requiredEmailName: 'Please enter a name.'

});

PrismApi.Validation.messages.travellers = $.extend({}, PrismApi.Validation.messages.travellers, {
    requiredAtLeastOneTraveller: "Please enter the age of at least one adult traveller.",
    requiredEmailDocuments: "You must agree to receive the PDS and Certificate of Insurance by email before continuing. If you would like to update your email then please return to the Your Details screen.",
    requiredEmail: 'Please confirm your email address.', /* email */
    matchEmail: 'Please make sure the email confirmation field matches the email field.', /* email confirmation, email */
    requiredResidentsOfCountry: 'Please select if all travellers are residents of Australia.',
    invalidResidentsOfCountry: 'To be eligible for this insurance, all travellers must be citizens or residents of Australia.',
    requiredTempResidentsOfCountry: "Please select if any travellers are temporary residents of Australia.",
    requiredPartnerMember: "Please select if you are a {1}.",
    requiredPurposeOfTrip: "Please select the purpose of your trip.",
    requiredPartnerReferer: "Please select who referred you to us.",
    requiredQuestion: 'Please enter a value for {0}',
    invalidPhone: "Please enter a valid {0}. Field must be {1} numeric digits in length.",
    requiredPhoneOrMobile: "Please enter your phone or mobile number.",
    requiredAllOrNonePhone: "Please enter a {0}.",
    invalidPhoneArea: "Please enter a valid {0} (area code). Field must be 2 numeric digits in length.",
    labelPhoneNumberTypeNumber: ' (number)',
    labelPhoneNumberTypeArea: ' (area code)',
    labelPhoneWork: 'phone', /* used in invalid phone types */
    labelPhoneHome: 'phone', /* used in invalid phone types */
    labelPhoneMobile: 'mobile', /* used in invalid phone types */
    labelTravellerForOption: 'Traveller for item {0}',
    labelTravellerTitleGroup: 'Area for {0} {1}',
    labelTravellerTitle: 'Title for {0} {1}',
    labelTravellerGivenName: 'Given Name for {0} {1}',
    labelTravellerSurname: 'Surname for {0} {1}',
    labelTravellerGender: 'Gender for {0} {1}',
    labelTravellerDob: 'Date of Birth for {0} {1}',
    labelTravellerPreExistingCond: 'Please advise if {0} {1} has a Pre-existing medical condition',
    labelTravellerPreExistingAssess: 'Pre-existing assessment for {0} {1}',
    labelTravellerAddress1: 'Address Line 1',
    labelTravellerAddress2: 'Address Line 2',
    labelFullAddress: 'Street Address',
    labelPostcode: 'Postcode',
    requiredTitleGroup: "Please select an {1}.",
    requiredTitle: "Please select a {1}.",
    requiredFirstName: "Please enter a {1}.",
    requiredSurname: "Please enter a {1}.",
    requiredDob: "Please enter a {1}.",
    requiredGender: 'Please select a {1}.',
    requiredPreExisting: "{1}.",    
    invalidDobDate: 'Please enter a valid {1} (dd/mm/yyyy).',
    invalidAge: "The age for {1} traveller must be a numeric value.",
    invalidDobRange: 'The Date of Birth you have entered does not match the traveller age. If the quoted age is incorrect, please update your quote.',
    invalidFullAddress: 'Please enter a valid {1}.',
    requiredPreExistingOffer: "Please select if you would like to accept this offer?",
    requiredPreExistingExcessPremium: "Please select the excess amount.",
    requiredtravellersHavePE: "Please advise if any traveller has a Pre-existing medical condition.",
    requiredtravellersHavePEAssessmentCompleted: "You answered ‘Yes’ to a traveller/s having a pre-existing medical condition. Please select the travellers with a pre-existing medical condition.",
    requiredPEAssessmentCompletedForOneTraveller: "You answered ‘Yes’ to having a pre-existing medical condition. Please complete the medical assessment.",
    requiredPEAssessmentCompleted: "You indicated that this traveller has a pre-existing medical condition. Please complete the medical assessment.",
    noSalesAdultAge: "If you are aged {1} years or under, please call our contact centre on {0} to proceed with your quote.",
    noSalesDependantAge: "If you require a policy with dependant(s) older than the adult travellers, please call our contact centre on {0} to proceed with your quote."
});
PrismApi.Validation.messages.adjustments = $.extend({}, PrismApi.Validation.messages.adjustments, {
    requiredAdjustment: 'Please enter a value for {0}',
    invalidAdjustment: 'Please enter a valid {0}.',
    invalidMemberAdjustment: 'Please enter a valid membership number for {0}.',
    invalidPromoCode: "Please enter a valid Promo Code."
});
PrismApi.Validation.messages.benefits = $.extend({}, PrismApi.Validation.messages.benefits, {
    labelBenefitValue: '{0} {1}', /* benefit title */
    labelBenefitValueDollarAmount: 'with a value of ${0}', /* value placeholder for text labelBenefitValue */
    labelBenefitValueInput: '{0} for item {1}', /* value, benefit */
    // overwrite the API error messages - increased item limits
    requiredItemTraveller: "Please select the traveller.",
    requiredItemType: "Select the item type to be covered",
    requiredItemValue: "Select the item limit",
    requiredItemItem: "Please select the item type you wish to have covered.",
    requiredItemAdd: "This item has not been added. Click Add to cover this item, otherwise select Cancel",
    requiredBusinessPackTraveller: "Please add at least one adult traveller for the Business Pack."
});
;
var openModalFunction = function (title, content, isStatic, showLoading, showOkCancel) {
    window.hideSpinner();
    var myModal = $('.modal[id="myModal"]:last');

    // we need to remove the widget first if it exists to alter the configuration 'backdrop'
    if (myModal && $(myModal).data('bs.modal')) {
        $(myModal).data('bs.modal', null);
    }

    $("#myModalLabel", myModal).html('');
    $("#myModalContent", myModal).html('');

    $("#myModalLabel", myModal).html($.trim(title.replace('*', '')));
    $("#myModalContent", myModal).html(content);

    // static hides close and stops user from clicking outside the dialog area
    if (isStatic || showOkCancel) {
        myModal.modal({ backdrop: "static" }).on('shown.bs.modal', function (e) {
            $("#modal-close", myModal).hide();
            if (isMobile()) {
                $("html").css('overflow', 'hidden');
            }
        }).on('hidden.bs.modal', function (e) {
            if (isMobile()) {
                $("html").css('overflow', 'auto');
            }
        });
    } else {
        myModal.modal().on('shown.bs.modal', function (e) {
            $("#modal-close", myModal).show();
            if (isMobile()) {
                $("html").css('overflow', 'hidden');
            }
        }).on('hidden.bs.modal', function (e) {
            if (isMobile()) {
                $("html").css('overflow', 'auto');
            }
        });
    }

    if (showLoading) {
        $("#modal-loading", myModal).show();
    } else {
        $("#modal-loading", myModal).hide();
    }

    if (showOkCancel) {
        $('#okcancel', myModal).show();
        $('#modal-close', myModal).hide(); keepAliveInterval
    } else {
        $('#okcancel', myModal).hide();
        $('#modal-close', myModal).show();
    }
};

$("document").ready(function () {
    var sessionManager = require('sessionManager');
    sessionManager.setupDialogTimer({
        timeout: sessionTimeOut,//seconds
        countdown: sessionWarning,
        keep_alive_url: keepAliveUrl
    });

    $("span.tooltip-image").attr('tabindex', 0);
    $("#main-container").on("keypress", "span.tooltip-image", function (e) {
        if (e.which == 13) {
            $(this).click();
        }
    });

    $(".close-this-page").click(function () { window.close(); });

    $(document).on('click', ".btn-show-map", function (e) {
        var container = $('#MapPopupDiv');
        container.modal();
        if ($("#map", container).height() == 0) {
            window.showSpinner($(".mapWrapper", container), 'bar', false);
        }

        var policy = PrismApi.policy.fn.toJSONForContext("getQuickQuote");
        PrismApi.Utils.ajaxCall(PrismApi.Client.serviceUrls.QuickQuote, policy, "POST")
            .done(function (response) {

                if (response.PricingRegions) {
                    PrismApi.policy.PricingRegions(ko.mapping.fromJS(response.PricingRegions)());
                }

                $$.fn.getDestinations().done(function () {
                    showMap();
                    window.hideSpinner();
                });
            })
            .fail($$.Client.displayError);
    });

    /*=============
    MODAL
    ==============*/
    openModal = openModalFunction;

    window.showSpinner = function (control, type, appendAfter) {
        if (Modernizr.touch) {
            $('#myModalSpinner').modal({ backdrop: "static" });
        } else {
            if (control.siblings('.spinner').length == 0 && control.find('.inplace-spinner').length == 0) {
                var elem = type == 'bar' ? spinnerBar : spinner;
                if (appendAfter) {
                    control.after(elem);
                } else {
                    control.before(elem);
                }
            }
            control.find(".inplace-spinner").css('visibility', 'visible');
        }
    };

    window.hideSpinner = function (control) {
        if (window.Modernizr && window.Modernizr.touch) {
            $('#myModalSpinner').modal('hide');
            $(".spinner").css('visibility', 'hidden');
            $(".spinner-bar").css('display', 'none');
        } else {
            $(".appended-spinner.spinner").remove();
            $(".appended-spinner.spinner-bar").remove();
            $(".spinner").css('visibility', 'hidden');
            $(".spinner-bar").css('display', 'none');
            $(".inplace-spinner").css('visibility', 'hidden');
        }
    };

    window.openPurchaseModal = function () {
        openModal('Purchase request', 'Please wait… We are processing your purchase.<br/>', true, true);
    };

    window.openErrorModal = function (title, content) {
        openModal('<span style="color:#f54359">' + title + '</span>', content, false, false);
    };

    window.openPeModal = function (peSummary) {
        $('#peSummaryModal').modal();
    };

    window.openMessageBoxModal = function (title, content, acceptText, acceptAction, cancelText, cancelAction) {
        $("#modal-ok").unbind("click");
        $("#modal-cancel").unbind("click");
        if (acceptText) {
            $('#modal-ok').text(acceptText);
        } else {
            $('#modal-ok').text('Ok');
        }
        if (acceptAction) {
            $('#modal-ok').click(acceptAction);
        }
        if (cancelText) {
            $('#modal-cancel').text(cancelText);
        } else {
            $('#modal-cancel').text('Cancel');
        }
        if (cancelAction) {
            $('#modal-cancel').click(cancelAction);
        }
        openModal(title, content, false, false, true);
    };

    window.hideModal = function () {
        $('#myModal').modal("hide");
    };

});

function HideQuickQuotePlans(viewModel) {
    if (viewModel == null) viewModel = $$.policy;
    //$('#quickQuotePlans').hide();
    $$.policy.MetaData.quoteIsInvalid(true);
    viewModel.fn.updateQuickQuoteAssessment();
    return true;
}

function RemoveValidationElement(e) {
    var elem = e.currentTarget;
    $(elem).removeClass('validationElement');
}

var nextCounter = 0;
function GetNextCounter(reset) {
    if (reset) nextCounter = 0;
    return nextCounter++;
}

function fixBenefitTable() {
    if ($(this).width() >= 980) {
        $(".space-filler").remove();
    } else {
        if ($(".space-filler").length == 0) {
            $(".product-benefit-header").after("<div class='space-filler'></div>");
        }
    }
}

function fixQuestionItems() {
    // question-template needs different styles for quick quote/home and benefits questions
    $('.quickQuoteWidget .question-header').addClass('col-sm-5');
    $('.quickQuoteWidget .question-header span:last').hide();
    $('.quickQuoteWidget .question-body').addClass('col-sm-6');
    $('.benefit-row .question-header').addClass('col-sm-6 header');
    $('.benefit-row .question-body').addClass('col-sm-5 selectBox');
    $('.benefit-row .question-body select').addClass('pull-right');
    $('.benefit-row .question-header span:first').hide();
}

function getFullQuoteForPlanWithOptions(plan) {
    var tempPolicy = new PrismApi.Data.Policy(_session.policy);
    $$.tempPolicy = tempPolicy;
    $$.tempPolicy.Plan(plan.Plan);
    $$.tempPolicy.CancellationAmount(plan.MetaData.CancellationAmount());
    $$.tempPolicy.MaxTripDuration(plan.MetaData.MaxTripDuration() ? plan.MetaData.MaxTripDuration() : null)
    $$.tempPolicy.Excess(plan.MetaData.Excess());

    var tripPurpose = ko.utils.arrayFirst($$.tempPolicy.Questions(),
        function (question) {
            return question.BriefCode() == 'TRIP';
        });

    if (!tripPurpose) {
        var trip = new PrismApi.Data.Question();
        trip.BriefCode('TRIP');
        trip.Answer(_session.dataTransferObjects.Questions[0].Answer);
        trip.Answer().BriefCode = 'OTHER';
        trip.Answer().Description = 'Other';
        $$.tempPolicy.Questions().push(trip);
    }

    //resetting benefits to avoid duplicate benefit
    $$.tempPolicy.Benefits().length = [];
    ko.utils.arrayForEach(ko.unwrap(plan.Benefits) != undefined ? ko.unwrap(plan.Benefits) : [],
        function (benefit) {
            if (benefit.BriefCode() === 'RVEIN' &&
                benefit.MetaData.IsEnabled() &&
                isNaN(benefit.BenefitItems()[0].Value())) {
                benefit.MetaData.IsEnabled(false);
            }
            $$.tempPolicy.Benefits().push(benefit);
        });

    if (window.setSpinner) {
        clearInterval(window.setSpinner);
    }
    var ellipsis = [".", "..", "..."];
    plan.Premium.SellingGross(ellipsis[0]);
    window.setSpinner = setInterval(function () {
        var txt = plan.Premium.SellingGross();
        plan.Premium.SellingGross(txt.length < 3 ? ellipsis[txt.length] : ellipsis[0]);
    }, 2);

    var obj = $.Deferred();
    var policy = $$.tempPolicy.fn.toJSONForContext("getFullQuote");

    PrismApi.Utils.ajaxCall(PrismApi.Client.serviceUrls.FullQuote + "?rescore=false", policy, "POST").done(function (response) {
        clearInterval(window.setSpinner);
        plan.Premium.SellingGross(response.Premium.SellingGross);
        obj.resolve(response);
    }).fail(function (response) {
        if (window.setSpinner) {
            clearInterval(window.setSpinner);
        }
        PrismApi.policy.fn.applyViolationsToViewModel(response);
        var apiError = PrismApi.fn._getApiError(response);
        obj.reject(apiError);
        PrismApi.Utils.logError(apiError, ["PrismApi.getFullQuote()"])
    });
    return obj.promise();
}

function RecalculateQuoteImmediate(doPageValidation, displayError, performRescore) {

    console.log('trigger recalculate quote immediate...');

    $$.policy.MetaData.isRecalculating(true);

    var prom = $$.fn.getFullQuote(false, doPageValidation, performRescore).done(function(response) {

            ko.utils.arrayForEach($$.policy.MetaData.BulkPremiums(), function(bulkpremium) {
                if (bulkpremium.Plan.PlanId() === ko.unwrap($$.policy.Plan().PlanId)) {
                    bulkpremium.Premium.SellingGross(response.Premium.SellingGross);
                }
            });
        })
        .fail($$.Client.displayError)
        .always(function() {
                $$.policy.MetaData.isRecalculating(false);
        });

    return prom;
}

//This function will throttle how often the getFullQuote is called so that we don't hit the server too hard.
function RecalculateQuote(doPageValidation, displayError, performRescore) {

    if (doPageValidation === undefined)
        doPageValidation = true;

    if (performRescore === undefined)
        performRescore = false;


    // prevent recalculate if the policy is invalid
    if ($$.policy.errors.visibleNotValidMessages().length > 0 && doPageValidation) {
        var tripPurpose = ko.utils.arrayFirst($$.policy.Questions(),
            function (question) {
                return question.BriefCode() == 'TRIP';
            });
        tripPurpose.Answer.isModified(true);
        return;
    }

    // trigger recalculate timer with options    
    $$.policy.MetaData.RecalculateTimer({
        "doPageValidation": doPageValidation, "displayError": displayError, "performRescore": performRescore
    });
}

//This function is to do recal after PE status outcome
function UpdateTotalAfterPE() {
    $$.policy.MetaData.RecalculatePERescore(true);
    RecalculateQuote(false, false, true);
}



function healixcallback() {
    // clear back/reload prevention
    window.onbeforeunload = null;

    if ($$.policy.PeOptions.FatalFlag() === false) {

        var policy = PrismApi.policy.fn.toJSONForContext("getFullQuote");

        $$.policy.fn.updateHolderScreening(policy, $$.Client.serviceUrls.HealixAssessResult.format('b2c')).done(function () {

            var isPeAssessmentCancelled = cancelPeAssessmentFromBlackbox();

            if (!isPeAssessmentCancelled) {
                window.location.href = $$.baseUrl + "PreExisting/Assessment";
            }
        });
    } else {
        window.location.href = $$.baseUrl + "PreExisting/Assessment";
    }

    function cancelPeAssessmentFromBlackbox() {
        var isPeAssessmentCancelled = false;

        $.each($$.policy.MetaData.AllTravellers(), function (index, traveller) {

            if (traveller.HealixAssessment() && traveller.HealixAssessment().PeId() === 1 &&
                traveller.HealixAssessment().ScreeningResult.ScreeningStatus() === 'APPNP' &&
                traveller.HealixAssessment().ScreeningResult.PostScreeningCondition().length === 0) {

                clearScreeningResult(traveller);

                RecalculateQuoteImmediate(false).done(function () {
                    window.location.href = $$.baseUrl + "Details";
                }).fail(function (error) {
                    $$.Client.displayError(error);
                });

                isPeAssessmentCancelled = true;

                return false;
            }

            return true;
        });

        return isPeAssessmentCancelled;
    }

    function clearScreeningResult(traveller) {
        if (traveller.HealixAssessment()) {
            traveller.HealixAssessment().ScreeningId(0);
            traveller.HealixAssessment().ScreeningRev(0);
            traveller.HealixAssessment().PeId(0);
            traveller.HealixAssessment().ScreeningResult = null;
            traveller.HealixAssessment().CalculationOption = [];
        }

        if (traveller.MetaData && traveller.MetaData.HasPeCondition() !== undefined) {
            traveller.MetaData.HasPeCondition(undefined);

            if (traveller.HasPeCondition) {
                traveller.HasPeCondition(undefined);
            }
        }
    }
}

// Popover settings
var popoverSettings = {
    'html': true,
    'animation': false,
    'placement': 'bottom',
    'trigger': ($('html').hasClass('no-touch') && !navigator.userAgent.match(/(IEMobile)/i)) ? 'hover' : 'click',
    'container': '',
    template: $("#popoverTemplate").html()
};

var bootstrapSetup = function () {
    // remove other popovers on another one showing
    $(document).on('show.bs.popover', function (e) {
        $('.popover-holder').popover('hide');
    });
    // bootstrap wiring
    // Get rid of the left to make popover fit correctly
    $(document).on('shown.bs.popover', function (e) {
        // $('.popover').css('left', 0);

        if (popoverSettings.trigger == 'hover') {
            $('.popover .close').hide();
        } else {
            $('.popover .close').show();
        }

        $('.popover .close').click(function (event) {
            $('.popover-holder').popover('hide');
            $('.striped').popover('hide');
            return false; // stop propogation
        });
    });

    // Work around for reported bootstrap popover bug
    $(document).on('hidden.bs.popover', function () {
        $('.popover').removeClass('in').hide().detach();
    });
};

var fixTravellerTitle = function (item) {
    var itemTG = lookupTravellerTitleGroup(item)
    if (itemTG) {
        item.TitleGroup(itemTG.titleGroup);
    }

};

var lookupTravellerTitleGroup = function (item) {
    var titleAndGroup = null;
    // translate title / title group
    if (item.MetaData.TitleGroups && item.MetaData.TitleGroups()) {
        $.each(item.MetaData.TitleGroups(), function (index, itemTG) {
            var result = ko.utils.arrayFirst(itemTG.Titles, function (dataTitle) {
                return dataTitle.BriefCode == item.Title();
            });
            if (result) {
                titleAndGroup = { titleGroup: itemTG, title: result };
            }
        });
    }
    return titleAndGroup;
};

var getTravellerNameComputed = function (item, type, index) {
    return ko.computed(function () {
        var titleReplace = lookupTravellerTitleGroup(item);
        var titleOverride = { "DR": "Dr", "MSTR": "Mstr", "BLANK": "" };
        var title = titleReplace && titleReplace.title ? titleReplace.title.Description : (item.Title() ? item.Title().toLowerCase() : item.Title());
        if (title && titleReplace) {
            // check Display translation
            var override = titleOverride[titleReplace.title.BriefCode];
            if (override !== null && override !== undefined) {
                title = override;
            }
        }
        var nameFormatted = titleReplace ? title + $.camelCase(' -' + item.FirstName() + ' -' + item.LastName()) : $.camelCase('-' + title + ' -' + item.FirstName() + ' -' + item.LastName());
        return (title !== null && title !== undefined ? item.FirstName() ? item.LastName() ? nameFormatted : type + ' ' + (index + 1) : type + ' ' + (index + 1) : type + ' ' + (index + 1));
    }).extend({ throttle: $$.Client.Util.ThrottleTime });
};

/**
 * Project: Bootstrap Collapse Clickchange
 * Author: Ben Freke
 *
 * Dependencies: Bootstrap's Collapse plugin, jQuery
 *
 * A simple plugin to enable Bootstrap collapses to provide additional UX cues.
 *
 * License: GPL v2
 *
 * Version: 1.0.1
 */
(function ($) {

    var ClickChange = function () { };

    ClickChange.defaults = {
        'when': 'before',
        'targetclass': '',
        'parentclass': '',
        'iconchange': false,
        'iconprefix': 'glyphicon',
        'iconprefixadd': true,
        'iconclass': 'chevron-up chevron-down'
    };

    /**
     * Set up the functions to fire on the bootstrap events
     * @param options The options passed in
     * @param controller Optional parent which controls a groups options
     * @returns object For chaining
     */
    $.fn.bootstrapCollapseChange = function (options, controller) {
        // In a grouping, I've passed in the controller to get data from
        var settings = $.extend(
            {}
            , ClickChange.defaults
            , $(this).data()
            , (typeof controller == 'object' && controller) ? controller.data() : {}
            , typeof options == 'object' && options
        );

        // Now amend the icon class
        if (settings.iconclass.length && settings.iconprefixadd) {
            tmpArr = settings.iconclass.split(' ');
            settings.iconclass = '';
            for (elementIndex in tmpArr) {
                settings.iconclass += ' ' + settings.iconprefix + '-' + tmpArr[elementIndex];
            }
        }

        // When do we fire the event?
        var eventStart = (settings.when === 'after') ? 'shown' : 'show';
        var eventEnd = (settings.when === 'after') ? 'hidden' : 'hide';

        // Because it could be a group, we use each to iterate over the jQuery object
        $(this).each(function (index, element) {
            var clickElement = $(element);
            var targetID = clickElement.attr('id');
            // Get my target. This handles buttons and a
            var clickTarget = clickElement.attr('data-target') || clickElement.attr('href');

            // turn off previous events if we're re-initialising
            if (clickElement.data('clickchange')) {
                $(document).off('show.bs.collapse hide.bs.collapse', clickTarget);
                $(document).off('shown.bs.collapse hidden.bs.collapse', clickTarget);
            }
            clickElement.data('clickchange', 'yes');

            // As we're toggling, the same changes happen for both events
            $(document).on(eventStart + '.bs.collapse ' + eventEnd + '.bs.collapse', clickTarget, function (event) {
                var clickOrigin = clickElement;
                if (targetID) {
                    clickOrigin = $("#" + targetID);
                }

                // Stop the event bubbling up the chain to the parent collapse
                event.stopPropagation();

                // Toggle clickable element class?
                if (settings.parentclass) {
                    clickOrigin.toggleClass(settings.parentclass);
                }

                // Toggle the target class?
                if (settings.targetclass) {
                    $(event.target).toggleClass(settings.targetclass);
                }

                // Do I have icons to change?
                if (settings.iconchange && settings.iconclass.length) {
                    clickOrigin.find('.' + settings.iconprefix).toggleClass(settings.iconclass);
                }
            });
        });
        return this;
    };
}(jQuery));

(function ($, undefined) {
    'use strict';
    $$.Client = $$.Client || {};
    $$.Client.Util = $$.Client.Util || {};
    $$.Client.Util.PurchaseStepNames = { Home: "Home", QuickQuote: "QuickQuote", Details: "Details", Payment: "Payment", Confirmation: "Confirmation" };
    $$.Client.Util.PurchaseSteps = { Home: '', QuickQuote: 'QuickQuote', Details: 'Details', Payment: 'Payment', Confirmation: 'Confirmation' };
    $$.Client.Util.sessionTimeoutHandler = function () {
        console.log("session timed out");
        $$.Client.Util.navigateToPurchaseStep('Home', true, undefined, true);
    };
    $$.Client.Util.resetSessionData = function () {

        _session.policy = undefined;

        if (typeof (Storage) !== "undefined")
            sessionStorage.clear();
        if (window.localStorage && window.localStorage.clear)
            window.localStorage.clear();

        console.log("the policy in session has been reset.");
    };

    // extend ajaxCall in prism api to handle when session has expired, needs to be setup before any ajax calls are made on the page
    $$.Client.Util.setupSessionExpiryHandler = function () {
        var existingAjaxCallFunction = PrismApi.Utils.ajaxCall;
        PrismApi.Utils.ajaxCall = function (url, data, httpMethod) {
            var sessionManager = require('sessionManager');
            sessionManager.extend();
            var prom = existingAjaxCallFunction(url, data, httpMethod);
            prom.fail(function (jqXHR, textStatus, errorThrown) {
                if (jqXHR.status === 410) {
                    $$.Client.Util.resetSessionData();
                    $$.Client.Util.sessionTimeoutHandler();
                }
            });
            return prom;
        }
    }
    $$.Client.Util.navigateToPurchaseStep = function (step, resetSession, queryString, overrideNavPrevent) {
        if (overrideNavPrevent === true) {
            // clear back/reload prevention
            window.onbeforeunload = null;
        }
        var url = ($$.baseUrl ? $$.baseUrl : '') + ($$.Client.Util.PurchaseSteps ? $$.Client.Util.PurchaseSteps[step] : '');
        var qs = (resetSession != undefined ? (resetSession === true ? '' : '?session=true') : '');
        if (queryString !== undefined) {
            qs += (qs.length == 0 ? '?' : '&') + queryString;
        }
        window.location.href = url + qs;
    };

    $$.Client.Util.setDefaultQuestions = function () {

        function setDefaultAnswer(question) {

            var defaultQuestion = $$.Client.QuestionDefaults.find(function (defaultQuestion) {
                return defaultQuestion.QuestionBriefCode === question.BriefCode();
            });

            if (defaultQuestion) {
                var foundAnswer = PrismApi.Utils.arrayFirstBriefCode(question.Answers(),
                    defaultQuestion.DefaultAnswerBriefCode.toUpperCase());

                if (foundAnswer) {
                    question.Answer(foundAnswer);
                }
            }

            $.each(question.Answers(),
                function (index, answerToLookForChildQuestions) {
                    if (answerToLookForChildQuestions.Questions) {
                        $.each(answerToLookForChildQuestions.Questions(), function (index, questionToLookFor) {
                            setDefaultAnswer(questionToLookFor);
                        });
                    }
                });
        }

        // Set default question answers to viewmodel
        if ($$.Client.QuestionDefaults && $$.Client.QuestionDefaults.length > 0) {
            $.each($$.policy.Questions(), function (index, question) {
                setDefaultAnswer(question);
            });
        }

    };



    // blur handler to reset value
    $$.Client.Util.clearBlurHandler = function (data, event) {
        // check if there's a placeholder match if so reject it
        var placeholder = $(event.target).attr("placeholder");
        var currentValue = data();
        if (currentValue === "" || (placeholder && currentValue === placeholder) || currentValue === "OPTIONAL") {
            data(null);
        }
        return true;
    };

    $$.Client.Util.detectBootstrapViewSize = function () {
        var envs = ["xs", "sm", "md", "lg"];
        var envValues = ["xs", "sm", "md", "lg"];

        var el = $('<div>');
        el.appendTo($('body'));

        for (var i = envValues.length - 1; i >= 0; i--) {
            var envVal = envValues[i];

            el.addClass('hidden-' + envVal);
            if (el.is(':hidden')) {
                el.remove();
                return envs[i]
            }
        };
    };

    $$.Client.Util.Modal = $$.Client.Util.Modal || {};
    // Show the modal prompting user to agree to privacy used on home and select plan screens
    //$$.Client.Util.Modal.PrivacyModal = function (policy) {
    //    var promPrivacy = $.Deferred();
    //    if (policy.MetaData.privacyAgree() !== true) {
    //        openMessageBoxModal('Agreement Declaration', $("#modal-privacydisclosure-agree").html(),
    //            'Accept', function () {
    //                var modal = $('#myModal');
    //                $("#okcancel", modal).hide();
    //                policy.MetaData.privacyAgree(true);
    //                $('#myModal').on('hidden.bs.modal', function () {
    //                    $(".modal-footer > div").attr('style', '');
    //                    $('#myModal').off('hidden.bs.modal');
    //                    promPrivacy.resolve();
    //                });
    //            },
    //            'Decline', function () {
    //                policy.MetaData.privacyAgree(false);
    //                $('#myModal').on('hidden.bs.modal', function () {
    //                    $(".modal-footer > div").attr('style', '');
    //                    $('#myModal').off('hidden.bs.modal');
    //                    promPrivacy.reject();
    //                });
    //            }
    //        );
    //    } else {
    //        promPrivacy.resolve();
    //    }
    //    return promPrivacy;
    //};

})(jQuery);

// Sidebar quotesummary scroller
(function ($, undefined) {
    'use strict';
    var currentQuoteOffset, currentQuoteDiv;
    var isIE8 = false;
    $$.Client = $$.Client || {};
    $$.Client.Util = $$.Client.Util || {};
    $$.Client.Util.initialiseQuoteSummaryScroller = function () {
        isIE8 = $(".ie8").length > 0;
        currentQuoteDiv = $('#divScroller');
        if (currentQuoteDiv.length > 0) {
            currentQuoteOffset = currentQuoteDiv.offset().top - (isIE8 ? 180 : 160);
            scrollCurrentQuote(false, false);
            var positionQuoteSummary = function (force) {
                if ($(document).width() > 768) {
                    scrollCurrentQuote(true, force);
                }
            };
            if ($$.Client.Util.PostionQuoteSummary) $$.Client.Util.PostionQuoteSummary = positionQuoteSummary;
            $(window).scroll(function () { positionQuoteSummary(false); });
            positionQuoteSummary(true);
        } else if ($('.top-widget-wrapper').length > 0) {

            //Calculate Height of elements on top of top Widget

            var navbarHeight = $('.navbar').outerHeight(true);
            var bannerImageHeight = $('.banner').outerHeight(true);

            var distance = navbarHeight + bannerImageHeight;

            $(window).scroll(function () {
                var scrollTop = $(window).scrollTop();

                if (scrollTop < distance) {
                    $('#plan-summary').removeClass('sticky');
                    $('.purchase-path').css('margin-top', '');
                    $('.top-widget-wrapper').css('position', 'relative');
                    $('.top-widget-wrapper').css('top', '');
                }
                else {
                    $('#plan-summary').addClass('sticky').css('width', $('.container').width());
                    $('.purchase-path').css('margin-top', $('.top-widget-wrapper').height() + 15 + 'px');
                    $('.top-widget-wrapper').css('position', 'fixed');
                    $('.top-widget-wrapper').css('top', '120px');
                    $('.top-widget-wrapper').css('width', $('.container').width());
                }
            });
        }
        if ($('#plan-summary-mobile').length > 0) {
            $('#plan-summary-mobile').headroom({

                "offset": $('#plan-summary-mobile').offset().top,
                "tolerance": 15,
                "classes": {
                    "pinned": 'slideDown',
                    "unpinned": 'slideUp',
                    "initial": 'animated'
                }
            });

            $("#plan-summary-mobile").headroom("destroy");
        }
    };

    function currentQuoteEndRequest(sender, args) {
        currentQuoteDiv = $('#divScroller');
        scrollCurrentQuote(false);

    }

    var scrollCurrentQuoteTimeout;
    function scrollCurrentQuote(animate, force) {
        if (scrollCurrentQuoteTimeout != null) {
            clearTimeout(scrollCurrentQuoteTimeout);
        }
        scrollCurrentQuoteTimeout = setTimeout(function () {
            scrollCurrentQuoteTimeout = null;
            if (force === true) {
                currentQuoteDiv.css({ top: 0 + 'px' });
            }
            if ($('#divScroller').height() + 42 >= $('#main-container').height()) {
                currentQuoteDiv.css({ top: 0 + 'px' });
                return;
            }
            currentQuoteDiv.stop(true, false);
            var scrollTop = $(window).scrollTop();
            var topBarOffset = $('#main-container').offset().top + $(".nav-progress").height();
            var offset = scrollTop > (topBarOffset + currentQuoteOffset) ? scrollTop - (topBarOffset + currentQuoteOffset) : 0;

            var atBottom = (offset + $('#divScroller').height() + 42) >= $('#main-container').height();
            if (atBottom && force !== true) {
                offset = $('#main-container').height() - $('#divScroller').height() - 42;
            }

            if (animate && scrollTop > 0) {
                currentQuoteDiv.animate({ top: offset + 'px' }, 'slow');
            }
            else {
                currentQuoteDiv.css('top', offset + 'px');
            }
        }, 100);
    }

})(jQuery);

////top-plan-summary width (for Wordlcare Templates only)
//function resizePlanSummaryWidth() {
//    if ($('#plan-summary').length > 0 && $('.container').length > 0) {
//        $('#plan-summary').css('width', $('.container.clearfix.content-wrapper').innerWidth() + (($(document).innerWidth() - ($('.container.clearfix.content-wrapper').innerWidth())) / 2) - 15);
//        // Plan summary width is determinded from container class width and browser window width
//        $('#plan-summary .summary').css('width', $('#plan-summary').width() - $('#plan-summary .back-button').width() - $('#plan-summary .btn-trip-edit').width());
//    }
//}

//$(window).resize(function () {
//    //resizePlanSummaryWidth();
//    $('.top-widget-wrapper').css('width', $('.purchase-path').width());
//});
;
/*=============
PRISM API SETUP
==============*/
$("document").ready(function () {

    $$.Client.spinner = ".api-spinner";
    $$.Client.Util.ThrottleTime = 2000;

    //match the normal approach; so binding will work.. and for consistency.
    if (window.todayUtc) $$.Client.todayDateString = window.todayUtc;

    //ko validation settings
    $$.Validation.koValidationConfiguration = {
        decorateElement: true,
        insertMessages: false,
        registerExtenders: true
    };

    if (!isLocalStorageNameSupported()) {
        openErrorModal("Private Browsing Detected", "Private browsing has been enabled. This site cannot be used while private browsing has been enabled. <br/>Please disable private browsing in your browser settings and try again.");
    }

    if (!isCookieSupported()) {
        openErrorModal("Cookies are Disabled", "This site uses cookies and cannot be used with browsers that have disabled thier use. <br/>Please enable cookies in your browser settings and try again.");
    }

    // when a FPE error code is returned, check the list of handled errors and also look for the label definition of this
    $$.Client.handleMappedFPEError = function (error) {
        var item = ko.utils.arrayFilter($$.Client.FPEErrorMappings, function (item) {
            return item.Type === "Validation" && item.Code === error.MessageCode;
        });
        if (item.length == 1) {
            var targetLabel = "";
            var foundElem = null;
            // find the input
            if (error.ExceptionMessage && error.ExceptionMessage.indexOf(":") > 0) {
                var valueOfError = error.ExceptionMessage.substring(error.ExceptionMessage.indexOf(":") + 2);
                $("[data-fpe-code='" + item[0].Code + "']").each(function (index, item) {
                    foundElem = $(item);
                    if (foundElem.val() == valueOfError) {
                        foundElem.addClass("validationNotValid").addClass("validationElement");
                        if (foundElem.attr("data-fpe-label")) {
                            targetLabel = foundElem.attr("data-fpe-label");
                        }
                    }
                });
            }
            var errorFromServer = item[0].Message.format(targetLabel);
            if (foundElem) {
                foundElem.attr("title", errorFromServer);
                foundElem.attr("name", targetLabel);
            }
            return errorFromServer;
        } else {
            return error.ExceptionMessage;
        }
    }

    //ERROR HANDLING
    $$.Client.displayError = function (apiError) {
        if (apiError !== undefined) {
            if (apiError.StatusCode == 0) { //Call aborted
                return;
            }
            if (apiError.StatusCode == 400 && apiError.ModelState != null) { //Bad request
                var message = JSON.stringify(apiError.ModelState);
                dataLayer.push({
                    'event': 'prismError',
                    'eventCategory': 'PRISM API Data Error',
                    'eventAction': message
                });
                openErrorModal("Invalid data", message);
                return;
            }
            if (apiError.StatusCode == 422) { //Processing Error
                var msgs = "<ul>";
                if (apiError.Messages) {
                    ko.utils.arrayForEach(apiError.Messages, function (error) {
                        msgs += "<li>{0}</li>".format(error);
                    });
                    msgs += "</ul>";
                } else {
                    msgs = '';
                }

                var mappings = ko.utils.arrayFirst($$.Client.FPEErrorMappings, function (msg) {
                    return msg.Type === "Message" && msg.Code === apiError.MessageCode;
                });
                if (mappings) {
                    openModal('Your travel insurance enquiry', mappings.Message, false, false);
                    return;
                }

                var errorMessage = apiError.ExceptionMessage;
                if (errorMessage.indexOf("Sorry, policy cannot be purchased") > -1) {
                    openModal('Your travel insurance enquiry', "<p>Thank you for using our online quote facility. Unfortunately we are unable to offer you insurance online. If we are unable to offer you the cover you seek, it will be because the particular product offered is not designed to cover a particular risk or risks including, but not limited to, some geographical regions, some pre-existing medical conditions or some ages. In such a case, if you would like to discuss your options please <a href='" + $$.baseUrl + "ContactUs'>contact us</a>.</p>", false, false);
                    return;
                }

                errorMessage = $$.Client.handleMappedFPEError(apiError);
                if (apiError.MessageCode === 'FPPF_ADJ_PF_DUMMY') {
                    ko.utils.arrayFirst($$.policy.MetaData.PromoAdjustments(), function (adjustments) {
                        adjustments.BriefCode() === 'DUMMY' ? adjustments.MetaData.IsPromoValid(false) : '';
                    })
                    if ($$.policy.MetaData.IsEditingTrip()) {
                        ko.utils.arrayFirst($$.newPolicy.MetaData.PromoAdjustments(), function (adjustments) {
                            adjustments.BriefCode() === 'DUMMY' ? adjustments.MetaData.IsPromoValid(false) : '';
                            hideSpinner();
                        })
                    }
                    return false;
                }
                dataLayer.push({
                    'event': 'prismError',
                    'eventCategory': 'PRISM API Processing Error',
                    'eventAction': errorMessage
                });

                openErrorModal("Processing Error", errorMessage + msgs);
                return;
            }
            if (apiError.StatusCode == 500 && apiError.StackTrace != null) { //Server error		    
                var msgs = "<ul>";
                if (apiError.Messages) {
                    ko.utils.arrayForEach(apiError.Messages, function (error) {
                        msgs += "<li>{0}</li>".format(error);
                    });
                    msgs += "</ul>";
                } else {
                    msgs = '<br>';
                }

                dataLayer.push({
                    'event': 'prismError',
                    'eventCategory': 'PRISM API Server Error',
                    'eventAction': apiError.ExceptionMessage,
                    'eventLabel': apiError.StackTrace
                });

                openErrorModal("Error", apiError.ExceptionMessage + msgs +
                    "==============<br>" + apiError.StackTrace);
                return;
            }
            if (apiError.StatusCode == null && apiError.ExceptionMessage == null) { //JavaScript error.

                if (ko.utils.arrayFirst($$.policy.MetaData.AllTravellers(), function (traveller) { return traveller.MetaData.age() > $$.policy.MetaData.MaxAdultAge(); }) != null) {
                    openModal('Your travel insurance enquiry', $('#modal-enquiry').html(), false, false);
                    return;
                }

                var invalidEle = $("select.form-control.validationNotValid.validationElement,  input.validationNotValid.validationElement, div.validationNotValid input").first();


                invalidEle.focus();
                return;
            }
        }

        dataLayer.push({
            'event': 'prismError',
            'eventCategory': 'PRISM API Unexpected Error',
            'eventAction': "An error has occurred.",
        });

        PrismApi.Utils.logError(apiError);

        //catch-all
        openErrorModal("Error",
            "<p>An error has occurred. Please try again.</p><p>If this error persists, please contact us for assistance. Our details can be located on the <a href='" + $$.baseUrl + "ContactUs'>Contact Us Page</a>.</p>");
    };

    $$.Client.extendClientSettings = function (viewModel) {
        $$.Client.QuickQuoteSettings = $$.Client.QuickQuoteSettings || {};
        $$.Client.QuickQuoteSettings = $.extend({}, $$.Client.QuickQuoteSettings, { UseDobInput: false, MinAdults: 1, MinDependants: 1 });
        $$.Client.QuestionDefaults = $.extend([], $$.Client.QuestionDefaults, PartnerConfiguration.QuestionConfigurations);
        $$.Client.QuickQuoteSettings = $$.Client.FPEErrorMappings || {};
        $$.Client.FPEErrorMappings = $.extend([], $$.Client.FPEErrorMappings, [
            { Type: "Validation", Code: "FPPF_ADJ_PF_DUMMY", Message: PrismApi.Validation.messages.adjustments.invalidPromoCode },
            { Type: "Validation", Code: "FPPF_CALC_ADJ_VALUE", Message: PrismApi.Validation.messages.adjustments.invalidMemberAdjustment },
            { Type: "Message", Code: "FPPF_AGE_ADULT1_ERR", Message: PrismApi.Validation.messages.travellers.noSalesAdultAge.format(PartnerConfiguration.ContactPhone, 17) },
            { Type: "Message", Code: "FPPF_AGE_ADULT2_ERR", Message: PrismApi.Validation.messages.travellers.noSalesAdultAge.format(PartnerConfiguration.ContactPhone, 17) },
            { Type: "Message", Code: "FPPF_AGE_CHILD_ERR", Message: PrismApi.Validation.messages.travellers.noSalesDependantAge.format(PartnerConfiguration.ContactPhone) }
        ]);
    }

    //site specific view model extension
    $$.Client.extendViewModel = function (viewModel) {
        //Run the shared bit first
        sharedExtendViewModel(viewModel);

        $$.Client.extendClientSettings(viewModel);
        //Setup site url

        $$.fn.CopyQuoteDataToQuote = function (from, to) {
            for (var i = 0; i < from.MetaData.AdultAges().length; i++) {
                var traveller = from.MetaData.AdultAges()[i];
                var existingTraveller = to.MetaData.AdultAges()[i];
                if (!existingTraveller) {
                    existingTraveller = new PrismApi.Data.Customer(null, 'adult');
                    to.MetaData.AdultAges.push(existingTraveller);
                }
                existingTraveller.MetaData.age(traveller.MetaData.age());
            }
            for (var i = 0; i < from.MetaData.DependantAges().length; i++) {
                var traveller = from.MetaData.DependantAges()[i];
                var existingTraveller = to.MetaData.DependantAges()[i];
                if (!existingTraveller) {
                    existingTraveller = new PrismApi.Data.Customer(null, 'dependant');
                    to.MetaData.DependantAges.push(existingTraveller);
                }
                existingTraveller.MetaData.age(traveller.MetaData.age());
            }
            to.StartDate(from.StartDate());
            to.EndDate(from.EndDate());
            to.CoverStartDate(undefined);
            to.CoverEndDate(undefined);
            to.MetaData.Countries(from.MetaData.Countries());
            ko.utils.arrayForEach(from.Adjustments(), function (adjustment) {
                var toAdjustment = ko.utils.arrayFirst(to.Adjustments(), function (toAdjust) {
                    return ko.unwrap(toAdjust.BriefCode) == ko.unwrap(adjustment.BriefCode);
                })
                if (toAdjustment) {
                    toAdjustment.Value(adjustment.Value());
                    toAdjustment.Question.Answer(adjustment.Question.Answer());
                }
            });

            //populate Questions responses before updating quote
            ko.utils.arrayForEach(from.Questions(), function (question) {
                var toQuestion = ko.utils.arrayFirst(to.Questions(), function (toQuestion) {
                    return ko.unwrap(toQuestion.BriefCode) == ko.unwrap(question.BriefCode);
                })
                if (toQuestion) {
                    toQuestion.Value(question.Value());
                    toQuestion.Answer(question.Answer());
                }
            });
        };

        viewModel.MetaData.AdultAges = ko.observableArray();
        viewModel.MetaData.DependantAges = ko.observableArray();

        viewModel.MetaData.hasQuestionsForOptionPage = ko.computed(function () {
            var questions = _session.fullQuoteOptions || $$.fullQuoteOptions;
            if (questions == null)
                return false;
            return !ko.utils.arrayFirst($$.Client.QuestionDefaults || [], function (item) { return item.QuestionBriefCode === 'TRIP'; }) || !(ko.utils.arrayFilter(questions.Questions, function (item) { return item.BriefCode == 'TRIP'; }).length == 1 && questions.Questions.length == 1);
        });

        $$.baseUrl = PartnerConfiguration.SiteUrl;

        viewModel.StartDate.subscribe(function (newValue) {
            //If we are in multi-trip, recalculate the end date using the api.
            if ($("#multiTripTab").parent().hasClass('active') || viewModel.MetaData.multiTripChecked()) {
                $$.fn.calculateMultiTripEndDate();
            }
            else {
                // reset date picker options
                var minDate = Date.create(newValue).getDateOnly();
                var maxDate = Date.create(minDate).advance({ year: 1, day: -1 }).getDateOnly();

                var element = $($$.Client.datepicker.getType("_endDate").selector + ":visible");
                element.datepicker('option', 'yearRange', "{0}:{1}".format(minDate.getFullYear(), maxDate.getFullYear()));
                element.datepicker('option', 'minDate', minDate);
                element.datepicker('option', 'maxDate', maxDate);

                // set end date to + 1 day                
                viewModel.EndDate(Date.create(minDate).advance({ days: 1 }).toISOString());
            }
        });

        //Set start / end date validation
        viewModel.StartDate.formattedDate.rules(ko.utils.arrayFilter(viewModel.StartDate.formattedDate.rules(), function (data) {
            return data.rule !== "required";
        }));
        viewModel.StartDate.formattedDate.extend({
            required: {
                params: true, message: PrismApi.Validation.messages.requiredStartDate
            }
        });
        viewModel.EndDate.formattedDate.rules(ko.utils.arrayFilter(viewModel.EndDate.formattedDate.rules(), function (data) {
            return data.rule !== "required";
        }));
        viewModel.EndDate.formattedDate.extend({
            required: {
                params: true, message: PrismApi.Validation.messages.requiredEndDate
            }
        });
        viewModel.EndDate.formattedDate.rules(ko.utils.arrayFilter(viewModel.EndDate.formattedDate.rules(), function (data) {
            return data.rule !== "moreThan";
        }));
        viewModel.EndDate.formattedDate.extend({
            moreThan: {
                params: function () {
                    return viewModel.StartDate() == null ? Date.create('today') : Date.create(viewModel.StartDate());
                }, message: PrismApi.Validation.messages.startDateIsAfterEndDate
            }
        });

        if (_session.quickQuote && _session.quickQuote.BulkPremiums) {
            PrismApi.bulkQuickQuote = _session.quickQuote;
            PrismApi.policy.fn.applyBulkPremiumsToViewModel();
        }

        viewModel.PartnerCode(PartnerConfiguration.PartnerCode);

        viewModel.MetaData.RecalculateTimer = ko.observable();

        viewModel.MetaData.RecalculateTimer.subscribe(function (newValue) {
            $$.policy.MetaData.isRecalculating(newValue != null);
        });

        // throttle getFullQuote to prevent multiple ajax calls
        ko.computed(function () {
            var options = viewModel.MetaData.RecalculateTimer();
            if (options !== undefined) {
                $$.policy.MetaData.isRecalculating(true);
                // needs to set timeout on ajax call to not block IE8 thread that shows 
                if (viewModel.MetaData.IsIE8()) {
                    setTimeout(function () {
                        $$.fn.getFullQuote(false, options.doPageValidation, options.performRescore)
                            .done(typeof (options.onComplete) == "function" ? options.onComplete : function () { })
                            .fail(typeof (options.displayError) == "function" ? options.displayError : $$.Client.displayError)
                            .always(function () {
                                $$.policy.MetaData.isRecalculating(false);
                                if (options == viewModel.MetaData.RecalculateTimer()) viewModel.MetaData.RecalculateTimer(undefined);
                            });
                    }, $$.Client.Util.ThrottleTime);
                } else {

                    if (!PrismApi.policy.Plan().PlanId) {
                        $$.Client.Util.sessionTimeoutHandler();
                        return;
                    }
                    $$.fn.getFullQuote(false, options.doPageValidation, options.performRescore)
                        .done(typeof (options.onComplete) == "function" ? options.onComplete : function () { })
                        .fail(typeof (options.displayError) == "function" ? options.displayError : $$.Client.displayError)
                        .always(function () {
                            $$.policy.MetaData.isRecalculating(false);
                            viewModel.MetaData.RecalculateTimer(undefined)
                        });
                }
            }
        }, this).extend({ throttle: $$.Client.Util.ThrottleTime });

        // Disabled navigation buttons when recalculating
        viewModel.MetaData.PreventNavigationOnRecalc = ko.observable(false);

        viewModel.MetaData.MaxProductBenefits = ko.observableArray();

        viewModel.MetaData.multiTripChecked = ko.observable(function () {
            var question = ko.utils.arrayFirst(viewModel.Questions(), function (question) {
                return question.BriefCode() == 'MULTI'
            });
            return (question && question.Answer && question.Answer().BriefCode() === "Y");
        }());

        viewModel.MetaData.multiTripChecked.subscribe(function (newValue) {
            HideQuickQuotePlans();

            //If we are in multi-trip, recalculate the end date using the api.
            if (newValue) {
                $$.fn.calculateMultiTripEndDate();
            } else {
                if (viewModel.StartDate()) {
                    // set end date to + 5 days
                    viewModel.EndDate(new Date(viewModel.StartDate()).advance({ days: 5 }).toISOString());
                }
            }

            var multitripQuestion = ko.utils.arrayFirst(viewModel.Questions(), function (question) {
                return question.BriefCode() == 'MULTI'
            });

            multitripQuestion.Answer().BriefCode(newValue ? 'Y' : 'N');

        });


        viewModel.MetaData.BulkPremiumsOptionBenefits = ko.observableArray();
        viewModel.MetaData.OptionBenefitsReady = ko.observable(false);
        viewModel.MetaData.BulkPremiumsReady = ko.observable(false);

        // validation rule for privacy on payment page
        viewModel.MetaData.privacyAgree = ko.observable();
        viewModel.MetaData.privacyAgree.extend({ equal: { params: true, message: PrismApi.Validation.messages.equalTruePrivacyAgree } });
        //viewModel.MetaData.privacyAgree.subscribe(function (val) {
        //    if (window.localStorage) {
        //        if (val === true) {
        //            window.localStorage.privacyAgree = 'true';
        //        } else if (window.localStorage.privacyAgree) {
        //            window.localStorage.privacyAgree = undefined;
        //        }
        //    }
        //});

        viewModel.MetaData.PaymentEligibilty = {
	        check1: ko.observable(),
	        check2: ko.observable(),
	        check3: ko.observable()
        };

        viewModel.MetaData.PaymentEligibilty.IsNotEligable =
	        ko.computed(function() {
		        var result = 
			        this.check1() === false ||
				        this.check2() === false ||
				        this.check3() === false;

		        return result;

	        }, viewModel.MetaData.PaymentEligibilty);

        //validation for have selected check option
        viewModel.MetaData.PaymentEligibilty.check1.extend({
	        required: {
		        params: true,
		        message: PrismApi.Validation.messages.payment.check1
	        }
        });

        viewModel.MetaData.PaymentEligibilty.check2.extend({
	        required: {
		        params: true,
		        message: PrismApi.Validation.messages.payment.check2
	        }
        });

        viewModel.MetaData.PaymentEligibilty.check3.extend({
	        required: {
		        params: true,
		        message: PrismApi.Validation.messages.payment.check3
	        }
        });

        viewModel.MetaData.displayPromoCode = ko.observable(_session.displayPromoCode);
        for (var adult = 0; adult < viewModel.PolicyHolders().length; adult++) {
            var adultAge = viewModel.PolicyHolders()[adult].MetaData.age();
            if ($.isNumeric(adultAge)) {
                var newAdult = new PrismApi.Data.Customer(null, 'adult');
                newAdult.MetaData.age(adultAge);
                viewModel.MetaData.AdultAges.push(newAdult);
            }

        }
        for (var dependant = 0; dependant < viewModel.PolicyDependants().length; dependant++) {
            var dependantAge = viewModel.PolicyDependants()[dependant].MetaData.age();
            if ($.isNumeric(dependantAge)) {
                var newDependant = new PrismApi.Data.Customer(null, 'dependant');
                newDependant.MetaData.age(dependantAge);
                viewModel.MetaData.DependantAges.push(newDependant);
            }
        }

        if ($$.quickQuoteOptions()) {
            for (var travellerIndex = 0; travellerIndex < $$.quickQuoteOptions().MinAdults; travellerIndex++) {
                viewModel.MetaData.AdultAges()[travellerIndex].MetaData.age.extend({ required: { params: true, message: PrismApi.Validation.messages.travellers.invalidMinAdults.format($$.quickQuoteOptions().MinAdults) } });
            }
            for (var travellerIndex = 0; travellerIndex < $$.quickQuoteOptions().MinDependants; travellerIndex++) {
                viewModel.MetaData.DependantAges()[travellerIndex].MetaData.age.extend({
                    required: {
                        params: true, message: PrismApi.Validation.messages.travellers.invalidMinDependants.format($$.quickQuoteOptions().MinDependants)
                    }
                });
            }
        }

        /* Set Date of birth validation min max rule to match quoted age */
        $.each(viewModel.PolicyHolders(), function (index, item) {
            item.Title.subscribe(function (title) {
                if ($.inArray(title, ["MR", "MSTR"]) != -1) {
                    item.Gender("M");
                } else if ($.inArray(title, ["MRS", "MS", "MISS"]) != -1) {
                    item.Gender("F");
                } else {
                    item.Gender(undefined);
                    item.Gender.isModified(false);
                }
            });

            var today = Date.create('today');
            var birthYear = today.getFullYear() - item.MetaData.age();
            item.DateOfBirth.formattedDate.extend({
                min: {

                    params: function () {
                        var today = new Date();
                        var minDate = new Date(birthYear - 1, today.getMonth(), today.getDate() + 1);
                        return minDate;
                    }, message: PrismApi.Validation.messages.travellers.invalidDobRange
                }, max: {

                    params: function () {
                        var today = new Date();
                        var maxDate = new Date(birthYear, today.getMonth(), today.getDate());
                        return maxDate
                    }, message: PrismApi.Validation.messages.travellers.invalidDobRange
                }
            });



            $("#travellersForm").each(function () {
                // Check for PE loading / HealixAssessment mismatch and remove  HealixAssessment
                if (item.HealixAssessment() && item.HealixAssessment().ScreeningResult && item.HealixAssessment().ScreeningResult.ScreeningStatus && item.HealixAssessment().ScreeningResult.ScreeningStatus()) {
                    // attempt to find localstorage flag accepting healix assessment
                    var hasClickedNext = false
                    if (window.localStorage && window.localStorage['Traveller' + (index + 1).toString() + 'PeAccepted'])
                        hasClickedNext = true;
                    // verify user has accepted their offer and clicked next or just clicked next for ones that dont require acceptance.
                    if ((item.HealixAssessment().ScreeningResult.ScreeningStatus() === 'APPPP' && (item.HealixAssessment().CalculationOption.AcceptOffer() !== true || !hasClickedNext)) || item.HealixAssessment().ScreeningResult.ScreeningStatus() === 'DECNP' && (item.HealixAssessment().CalculationOption.AcceptOffer() !== true || !hasClickedNext) || !hasClickedNext) {
                        resetHealixForTraveller(item);
                        window.localStorage.removeItem('Traveller' + (index + 1).toString() + 'PeAccepted');
                    }
                }
            });
            item.MetaData.FormattedName = getTravellerNameComputed(item, "Adult", index);
        });
        $.each(viewModel.PolicyDependants(), function (index, item) {
            item.Title.subscribe(function (title) {
                if ($.inArray(title, ["MR", "MSTR"]) != -1) {
                    item.Gender("M");
                } else if ($.inArray(title, ["MRS", "MS", "MISS"]) != -1) {
                    item.Gender("F");
                } else {
                    item.Gender(undefined);
                    item.Gender.isModified(false);
                }
            });

            var today = Date.create('today');
            var birthYear = today.getFullYear() - item.MetaData.age();
            item.DateOfBirth.formattedDate.extend({
                min: {

                    params: function () {
                        var today = new Date();
                        var minDate = new Date(birthYear - 1, today.getMonth(), today.getDate() + 1);
                        return minDate;
                    }, message: PrismApi.Validation.messages.travellers.invalidDobRange
                }, max: {

                    params: function () {
                        var today = new Date();
                        var maxDate = new Date(birthYear, today.getMonth(), today.getDate())
                        return maxDate
                    }, message: PrismApi.Validation.messages.travellers.invalidDobRange
                }
            });

            $("#travellersForm").each(function () {
                // Check for PE loading / HealixAssessment mismatch and remove  HealixAssessment
                if (item.HealixAssessment && item.HealixAssessment.ScreeningResult && item.HealixAssessment.ScreeningResult.ScreeningStatus) {
                    var hasClickedNext = false
                    if (window.localStorage && window.localStorage['Dependant' + (index + 1).toString() + 'PeAccepted'])
                        hasClickedNext = true;
                    // verify user has accepted their offer and clicked next or just clicked next for ones that dont require acceptance.
                    if (item.HealixAssessment.ScreeningResult.ScreeningStatus() === 'APPPP' && (item.HealixAssessment.CalculationOption.AcceptOffer() !== true || !hasClickedNext) || !hasClickedNext) {
                        resetHealixForTraveller(item);
                        window.localStorage.removeItem('Dependant' + (index + 1).toString() + 'PeAccepted');
                    }
                }
            });
            item.MetaData.FormattedName = getTravellerNameComputed(item, "Dependant", index);
        });

        ko.utils.arrayForEach(viewModel.MetaData.AllTravellers(), function (traveller) {

            traveller.DateOfBirth.hasEntered.subscribe(function (newValue) {
                window.sessionStorage['Travellers[' + traveller.MetaData.TravellerIndex + '].HasEnteredDOB'] = newValue;
            });

            // To handle an F5 refresh before date has been persisted to policy object
            if (window.sessionStorage['Travellers[' + traveller.MetaData.TravellerIndex + '].HasEnteredDOB'] == 'true' && traveller.FirstName() == null) {
                window.sessionStorage['Travellers[' + traveller.MetaData.TravellerIndex + '].HasEnteredDOB'] = 'false';
            }
        });


        while (viewModel.MetaData.AdultAges().length < 2) {
            viewModel.MetaData.AdultAges.push(new PrismApi.Data.Customer(null, 'adult'));
        }

        if (_session.quickQuoteOptions) {
            for (var travellerIndex = 0; travellerIndex < _session.quickQuoteOptions.MinAdults; travellerIndex++) {
                viewModel.MetaData.AdultAges()[travellerIndex].MetaData.age.extend({ required: { params: true, message: PrismApi.Validation.messages.travellers.invalidMinAdults.format(_session.quickQuoteOptions.MinAdults) } });
            }
            for (var travellerIndex = 0; travellerIndex < _session.quickQuoteOptions.MinDependants; travellerIndex++) {
                viewModel.MetaData.DependantAges()[travellerIndex].MetaData.age.extend({ required: { params: true, message: PrismApi.Validation.messages.travellers.invalidMinDependants.format(_session.quickQuoteOptions.MinDependants) } });
            }
        }

        while (viewModel.MetaData.DependantAges().length < 2) {
            viewModel.MetaData.DependantAges.push(new PrismApi.Data.Customer(null, 'dependant'));
        }

        //Trigger a re-quote when the benefits are enabled
        for (var i = 0; i < viewModel.Benefits().length; i++) {
            var benefit = viewModel.Benefits()[i];
            benefit.Option = ko.observable();
            benefit.MetaData.IsEnabled.subscribe(function (newValue) {
                var benefit = this;
                setTimeout(function () {
                    if (!benefit.MetaData.removePack()) {
                        // adjust detail visiblility based on checkbox
                        benefit.MetaData.showDetail(newValue);
                    }
                    benefit.MetaData.removePack(false);
                }, 0);
            }, benefit);

            // extend benefit to have a show/hide benefit detail
            benefit.MetaData.showDetail = ko.observable(false);
            benefit.MetaData.checkboxHasFocus = ko.observable(false);
            benefit.MetaData.removePack = ko.observable(false);
            benefit.MetaData.removePack.subscribe(function (newValue) {
                // unselects option but leaves details visible
                if (newValue) {
                    this.MetaData.IsEnabled(false);
                }
            }, benefit);
            benefit.MetaData.IsEnabled.subscribe(function (newValue) {
                if (benefit.BriefCode() == 'SNOW') {
                    if (ko.utils.arrayFirst((benefit.MetaData.IsPerAdultOnly ? viewModel.PolicyHolders() : viewModel.MetaData.AllTravellers()),
                        function (traveller) {
                            return ko.utils.arrayFirst(benefit.MetaData.Values || new Array(),
                                function (item) {
                                    return item.Value != 'Covered' && item.MetaData.MinAge !== undefined && item.MetaData.MaxAge !== undefined &&
                                        item.MetaData.MinAge <= traveller.MetaData.age() && item.MetaData.MaxAge >= traveller.MetaData.age();
                                });
                        })) {
                        var modal = $('#modal-snow');
                        openModal(modal.data('title'), modal.html(), false, false);
                    }
                }
                var isPlansPage = $("#quickQuotePlans").length > 0;
                if (!isPlansPage) {
                    RecalculateQuoteImmediate();
                    return true;
                }
            });
            // sort specific items benefit items
            benefit.MetaData.SortedSpecificItems = ko.computed(function () {
                var sortedItems = this.BenefitItems(); return sortedItems.sort(function (a, b) {
                    return a.CustomerIndex() > b.CustomerIndex();
                });
            }, benefit).extend({
                throttle: $$.Client.Util.ThrottleTime
            });

            // determine traveller options for benefit
            benefit.MetaData.TravellerOptions = ko.computed(function () {
                if (this.MetaData.IsPerPerson) {
                    return this.MetaData.IsPerAdultOnly ? viewModel.PolicyHolders() : viewModel.MetaData.AllTravellers();
                }
                return [];
            }, benefit).extend({
                throttle: $$.Client.Util.ThrottleTime
            });
        }



        // Indicated to template when options loaded via ajax
        viewModel.MetaData.TravellerOptionsReady = ko.observable(false);

        viewModel.MetaData.QuickQuoteOptionsReady = ko.observable(false);

        // Indicate to do a rescore on recalculate
        viewModel.MetaData.RecalculatePERescore = ko.observable(false);

        // Indicate the primary contact, which set to the traveller index
        viewModel.MetaData.PrimaryTravellerIndex = ko.observable(null);

        if (window.sessionStorage["PrimaryTravellerIndex"]) {
            viewModel.MetaData.PrimaryTravellerIndex(window.sessionStorage['PrimaryTravellerIndex']);
        }
        viewModel.MetaData.PrimaryTravellerIndex.subscribe(function (val) {
            window.sessionStorage["PrimaryTravellerIndex"] = val;
        });

        var travellersHavePE = false;
        ko.utils.arrayForEach(viewModel.MetaData.AllTravellers(),
            function (traveller) {

                // healix assessment started
                if (ko.unwrap(traveller.HasPeCondition()) === "true") {
                    travellersHavePE = true;
                }
            });

        if (ko.utils.arrayFirst(viewModel.MetaData.AllTravellers(), function (traveller) { return traveller.HasPeCondition() !== undefined; }) == null) {
            travellersHavePE = undefined;
        }
       
        //resetting Healix and premium price when user clicks on NO to hasPECondition
        viewModel.MetaData.travellersHavePE = ko.observable(travellersHavePE);
        viewModel.MetaData.travellersHavePE.extend({
            required: { params: true, message: PrismApi.Validation.messages.travellers.requiredtravellersHavePE },
            validation: {
                validator: function (val) {
                    if (val === true && viewModel.MetaData.AllTravellers().length > 1) {
                        return (ko.utils.arrayFilter(ko.unwrap(viewModel.MetaData.AllTravellers), function (traveller) {
                            if (traveller.MetaData.HasPeCondition.isModified() === true) {
                                return traveller.MetaData.HasPeCondition.isValid() && (traveller.MetaData.HasPeCondition() === true || traveller.MetaData.HasPeCondition() === 'true')
                            }
                            return traveller;
                        }).length > 0)
                    }
                    return true;
                },
                message: viewModel.MetaData.AllTravellers().length > 1 ? PrismApi.Validation.messages.travellers.requiredtravellersHavePEAssessmentCompleted: PrismApi.Validation.messages.travellers.requiredPEAssessmentCompletedForOneTraveller,
                params:true
            }
        });

        viewModel.MetaData.travellersHavePE.subscribe(function (newValue) {
            if (newValue === false) {
                var travellers = ko.utils.arrayFilter(viewModel.MetaData.AllTravellers(), function (traveller) {
                    return traveller.HealixAssessment().ScreeningId() !== 0;
                });
                ko.utils.arrayForEach(viewModel.MetaData.AllTravellers(), function (traveller) {
                    traveller.MetaData.HasPeCondition(undefined);
                    traveller.MetaData.hasCompletedPeAssessment(true);
                    traveller.MetaData.ReAssessment('true');
                    traveller.MetaData.HasPeCondition.isModified(false);
                    if (traveller.HasPeCondition)
                        traveller.HasPeCondition("false");
                    resetHealixForTraveller(traveller, true);
                });
                $$.policy.MetaData.RecalculatePERescore(true);
            }
        });

        var creditCard = viewModel.CreditCard;

        viewModel.CreditCard.CardExpiry = ko.computed({
            read: function () {
                if (creditCard.CardExpiryMonth() && creditCard.CardExpiryYear()) {
                    return creditCard.CardExpiryMonth() + "/" + creditCard.CardExpiryYear();
                }
                return null;
            },
            write: function (value) {
                var lastSlashPos = value.lastIndexOf("/");

                if (lastSlashPos > 0) {
                    creditCard.CardExpiryMonth(value.substring(0, lastSlashPos));
                    creditCard.CardExpiryYear(value.substring(lastSlashPos + 1));
                }
            },
            owner: this
        });

        viewModel.CreditCard.CardExpiry.extend({
            required: { params: true, message: PrismApi.Validation.messages.payment.requiredCardExpiry },
            allOrNone: { params: [viewModel.CreditCard.CardExpiryMonth, viewModel.CreditCard.CardExpiryYear], message: 'Please enter valid expiry date'
            }
        });

        viewModel.MetaData.SharePolicyEmails = ko.observableArray([
            createEmailForSharingPolicy()
        ]);
    };

    //HEALIX INTEGRATION
    $$.Client.showHealixAssessment = function (self, value) {

        var okFunction = function () {
            var modal = $('#myModal');
            $(this).removeAttr('data-dismiss');

            $("#okcancel", modal).hide();
            if (ko.unwrap($$.policy.PeOptions) != null && $$.policy.PeOptions.PESystem() == "HEALX") {

                $("#myModalLabel", modal).html("Pre-existing medical assessment");
                $("#myModalContent", modal).html("Please wait… We are preparing your pre-existing medical assessment.");

                $('#modal-loading', modal).show();

                if ($$.policy.PeOptions.FirstHolderFlag()) {
                    $$.fn.retrieveHealixAssessment()
                        .done(function () {
                            window.location.href = $$.baseUrl + 'PreExisting/Screening'
                        })
                        .always(function () {
                            $('#modal-ok', modal).attr('data-dismiss', 'modal').removeClass('pe-visible');
                        })
                        .fail($$.Client.displayError);
                } else {
                    $$.fn.retrieveHealixFatalCondition()
                        .done(function () {
                            window.location.href = $$.baseUrl + 'PreExisting'
                        })
                        .always(function () {
                            $('#modal-ok', modal).attr('data-dismiss', 'modal').removeClass('pe-visible');
                        })
                        .fail($$.Client.displayError);
                }

            }
        };

        var bootstrapViewSize = $$.Client.Util.detectBootstrapViewSize();
        var skipWarning = $$.policy.MetaData.AllTravellers().length == 1 && bootstrapViewSize !== "xs";
        // skip PE privacy warning if only one traveller
        if (skipWarning) {
            openMessageBoxModal('', '');
            okFunction();
        } else {
            $("#modal-ok").addClass('pe-visible');
            openMessageBoxModal(skipWarning ? '' : 'Warning', skipWarning ? '' : $('#modal-peRequired').html(),
                'Ok',
                okFunction
                ,
                'Cancel', function () {
                    $("#modal-ok").removeClass('pe-visible');
                    self.MetaData.HasPeCondition(value);
                }
            );
        }
    };

    //DATEPICKERS
    $$.Client.datepicker.fn = {
        restrictToSameYearOptions: function (input) {
            return {
                maxDate: new Date(),
                changeYear: true,
                changeMonth: true,
                yearRange: PrismApi.Utils.getDatepickerYearRange("adult")
            };
        },
        restrictToSameYearOptionsDependant: function (input) {
            return {
                maxDate: new Date(),
                changeYear: true,
                changeMonth: true,
                yearRange: PrismApi.Utils.getDatepickerYearRange("dependant")
            };
        },
        restrictTravelStartDateOptions: function (input) {
            var advance = { day: -1 };
            var leadtime = $$.policy.MetaData.MaxLeadtime();
            switch (ko.unwrap($$.policy.MetaData.LeadtimeDurationType)) {
                case "DAY":
                    advance.day = advance.day + leadtime;
                    break;
                case "WEEK":
                    advance.week = leadtime;
                    break;
                case "MONTH":
                    advance.month = leadtime;
                    break;
                default:
                    advance.year = 1;
                    break;
            }
            var minDate = Date.create(PrismApi.Client.todayDateString).getDateOnly();
            var maxDate = Date.create(PrismApi.Client.todayDateString).advance(advance).getDateOnly();

            var options = {
                changeMonth: true,
                changeYear: true,
                yearRange: "{0}:{1}".format(minDate.getFullYear(), maxDate.getFullYear()),
                minDate: 0,
                maxDate: maxDate,
                onSelect: function () {
                    $(this).change(); // Forces re-validation      

                    setTimeout(function () {
                        $($$.Client.datepicker.getType("_endDate").selector + ":visible").focus();
                    }, 500);
                }
            };

            return options;
        },
        restrictTravelEndDateOptions: function (input) {
            var minDate = PrismApi.Utils.formattedStringToDate($($$.Client.datepicker.getType("_startDate").selector + ":visible").val());
            var maxDate = Date.create(minDate).advance({ year: 1, day: -1 }).getDateOnly();

            var options = {
                changeMonth: true,
                changeYear: true,
                yearRange: "{0}:{1}".format(minDate.getFullYear(), maxDate.getFullYear()),
                minDate: minDate,
                maxDate: maxDate,
                onSelect: function () {
                    $(this).change(); // Forces re-validation
                }
            };

            return options;
        }
    };

    if (isMobile()) {

        var defaultDateFormat = PrismApi.Client.datepicker.getDateFormat();
        var defaultDateOrder = 'D ddmmyy';
        var defaultDisplay = 'bottom';
        var defaultshowLabel = false;
        var now = new Date;

        var beforeShowFunc = function(input, inst) {
            var formattedDate = PrismApi.Utils.formattedStringToDate(this.value);
            if (formattedDate) {
                input.setDate(formattedDate);
            }
        };

        var beforeShowFuncForStartDate = function(input, inst) {
            var element = $($$.Client.datepicker.getType("_startDate").selector + ":visible");

            var options = $$.Client.datepicker.fn.restrictTravelStartDateOptions(element[0]);
            element.mobiscroll('option', 'maxDate', options.maxDate);

            beforeShowFunc(input, inst);
        };

        var beforeShowFuncForEndDate = function (input, inst) {
            var element = $($$.Client.datepicker.getType("_endDate").selector + ":visible");

            var options = $$.Client.datepicker.fn.restrictTravelEndDateOptions(element[0]);
            element.mobiscroll('option', 'maxDate', options.maxDate);

            beforeShowFunc(input, inst);
        };

        var setEndDateFunc = function(input, inst) {
            var element = $($$.Client.datepicker.getType("_endDate").selector + ":visible");

            var options = $$.Client.datepicker.fn.restrictTravelEndDateOptions(element[0]);
            element.mobiscroll('option', 'minDate', options.minDate);
            element.mobiscroll('option', 'maxDate', options.maxDate);
        };

        if (window.innerWidth <= 480 || window.innerHeight < 400) {
            defaultDisplay = 'bottom';
        }

        $($$.Client.datepicker.getType("_startDate").selector).mobiscroll().date({
            theme: 'ios7',
            dateFormat: defaultDateFormat,
            dateOrder: defaultDateOrder,
            display: defaultDisplay,
            showLabel: defaultshowLabel,
            onBeforeShow: beforeShowFuncForStartDate,
            onSelect: setEndDateFunc,
            minDate: Date.create(PrismApi.Client.todayDateString).getDateOnly()
        });

        $($$.Client.datepicker.getType("_endDate").selector).mobiscroll().date({
            theme: 'ios7',
            dateFormat: defaultDateFormat,
            dateOrder: defaultDateOrder,
            display: defaultDisplay,
            showLabel: defaultshowLabel,
            onBeforeShow: beforeShowFuncForEndDate,
            minDate: Date.create(PrismApi.Client.todayDateString).getDateOnly()
        });

        $("input.dobAdults, input.dobDependants").prop('readonly', true);

        $(document).on("focus", "input.dobAdults", function () {
            if (!this.id) { //only add it once        
                var today = new Date();
                var birthYear = today.getFullYear() - $(this).data('age');
                var mindate = new Date(birthYear - 1, now.getMonth(), now.getDate() + 1);
                var maxdate = new Date(birthYear, now.getMonth(), now.getDate());
                $(this).mobiscroll().date({
                    theme: 'ios7',
                    dateFormat: defaultDateFormat,
                    dateOrder: defaultDateOrder,
                    display: defaultDisplay,
                    showLabel: defaultshowLabel,
                    onBeforeShow: beforeShowFunc,
                    minDate: mindate,
                    maxDate: maxdate
                });
            }
        });

        $(document).on("focus", "input.dobDependants", function () {
            if (!this.id) { //only add it once                
                var today = new Date();
                var birthYear = today.getFullYear() - $(this).data('age');
                var mindate = new Date(birthYear - 1, now.getMonth(), now.getDate() + 1);
                var maxdate = new Date(birthYear, now.getMonth(), now.getDate());
                $(this).mobiscroll().date({
                    theme: 'ios7',
                    dateFormat: defaultDateFormat,
                    dateOrder: defaultDateOrder,
                    display: defaultDisplay,
                    showLabel: defaultshowLabel,
                    onBeforeShow: beforeShowFunc,
                    minDate: mindate,
                    maxDate: maxdate
                });
            }
        });

        // fix calendar click with live event
        $(document).on('click', '#startDate, #endDate', function (e) {
            $(this).mobiscroll('show');
        });
        $(document).on('click', '.datepane span.input-group-addon', function (e) {
            var input = $(this).prev('input').mobiscroll('show');
            input.focus();
        });
        $(document).on('tap', '.datepane span.input-group-addon', function (e) {
            var input = $(this).prev('input').mobiscroll('show');
            input.focus();
        });
    } else {
        // fix calendar click with live event
        $(document).on('click', '.datepane span.input-group-addon', function (e) {
            var input = $(this).prev('input');
            if (input.length === 0) {
                input = $(this).prev().prev('input');
            }
            if (!input.hasClass('hasDatepicker')) {
                // match up type to input               
                var typeFound = "_startDate";
                if (input.hasClass('startDate')) {
                    typeFound = "_startDate";
                }
                if (input.hasClass("endDate")) {
                    typeFound = "_endDate";
                }
                if (input.hasClass("dobAdults") || input.hasClass("dobDependants")) {
                    if (input.attr('disabled') !== 'disabled') {
                        input.focus();
                        return true;
                    }
                }

                // find options, currently either start or end date
                var options = $$.Client.datepicker.getType(typeFound).options;
                input.datepicker(options instanceof Function ? options(input) : options);
            }
            if (input.attr('disabled') !== 'disabled')
                input.datepicker('show');
        });        

        // Override datepicker ui settings to show year/month dropdowns and only one year advance on dropdown
        $.each($$.Client.datepicker.types, function (index, item) {
            switch (item.key) {
                case '_dobAdults':
                    item.options = $$.Client.datepicker.fn.restrictToSameYearOptions;
                    break;
                case '_dobDependants':
                    item.options = $$.Client.datepicker.fn.restrictToSameYearOptionsDependant;
                    break;
                case '_startDate':
                    item.options = $$.Client.datepicker.fn.restrictTravelStartDateOptions;
                    break;
                case '_endDate':
                    item.options = $$.Client.datepicker.fn.restrictTravelEndDateOptions;
                    break;
                default:
                    break;
            }
        });

        $$.Client.datepicker.apply_jQueryUIDatepickers();
    }

    //COMMON SETUP
    var commonSetup = function () {
        //ToolTips
        $(document).on('click', '.tooltip-image:not(.popover-tooltip)', function () {
            var text = $(this).closest('label').text();
            if (!text) text = $(this).prev('label').first().text();
            if (!text) text = $(this).parent().find('label').first().text();
            if (!text) text = $(this).parent().parent().find('label').first().text();
            if (!text) text = $(this).data('header');

            var titleOverride = $(this).data('title');
            if (titleOverride) { text = titleOverride; }

            var content = $(this).data('content');
            if (!content) content = $('.tooltip-content', this).html();

            openModal(text, content, false, false);
        });

        $(document).on('click', '.toggleDiv', function () {
            $(this).parent().next('div').toggle();
            $(this).find('.show-hide-button-detail').toggle();
        });

        var fixDestinations = function (destinations, viewModel) {
            ko.utils.arrayForEach(destinations,
                function(destination) {
                    var region = ko.utils.arrayFirst(viewModel.MetaData.Regions(),
                        function(r) {
                            return ko.utils.unwrapObservable(r.BriefCode) ==
                                ko.utils.unwrapObservable(destination.BriefCode);
                        });
                    if (!region) {
                        viewModel.MetaData.Regions.push(destination);
                        region = destination;
                    } else {
                        if (region.Countries) region.Countries.length = 0;
                        region.Countries = ko.observableArray();
                        ko.utils.arrayPushAll(region.Countries, destination.Countries || []);
                    }
                    if (viewModel.Destinations()) {
                        ko.utils.arrayForEach(viewModel.Destinations(),
                            function(selectedDestination) {
                                if (ko.utils.unwrapObservable(selectedDestination.BriefCode) == destination.BriefCode) {
                                    if (!selectedDestination.Description) {
                                        selectedDestination.Description = ko.observable()
                                    }
                                    selectedDestination.Description(destination.Description);
                                    if (selectedDestination.Country) {
                                        var country = ko.utils.arrayFirst(destination.Countries,
                                            function(country) {
                                                return ko.utils.unwrapObservable(selectedDestination.Country
                                                    .BriefCode) ==
                                                    country.BriefCode
                                            });
                                        if (country) {
                                            if (!selectedDestination.Country.Description) {
                                                selectedDestination.Country.Description = ko.observable()
                                            }
                                            selectedDestination.Country.Description(country.Description)
                                        }
                                        if (country && country.Locations && selectedDestination.Country.Location) {
                                            var location = ko.utils.arrayFirst(country.Locations,
                                                function(location) {
                                                    return ko.utils.unwrapObservable(selectedDestination.Country
                                                        .Location
                                                        .BriefCode) ==
                                                        location.BriefCode;
                                                });
                                            if (location) {
                                                if (!selectedDestination.Country.Location.Description) {
                                                    selectedDestination.Country.Location.Description = ko.observable();
                                                }
                                                if (country) {
                                                    selectedDestination.Country.Location.Description(
                                                        location.Description);
                                                }
                                            }
                                        }
                                    }
                                }
                            });
                    }
                });
        };
        var RedirectToChosenaPlanPage = function () {

            $$.fn.getQuickQuoteOptions().done(function () {
                $$.fn.getBulkQuickQuoteWithQuote($$.newPolicy, true, false, false)
                    .done(function (bqq) {
                        var qs = (PrismApi.bulkQuickQuote.PricingLogId !== undefined && PrismApi.bulkQuickQuote.AccessCode !== undefined ?
                            'id=' + PrismApi.bulkQuickQuote.PricingLogId + '&accessCode=' + PrismApi.bulkQuickQuote.AccessCode + '&session=true' : 'session=true');

                        window.top.location.href = $$.baseUrl + "QuickQuote?" + qs;
                    })
                    .fail($$.Client.displayError)
                    .always();
            });

        };

        $(document).on("click", ".btn-trip-edit", function (e) {
            hideSpinner($("#topWidget-quickQuote-submit"));
            $$.fn.getDestinations().done(function (result) {
                fixDestinations(result.Regions, $$.newPolicy);
            });
        });

        $("#quickQuoteForm, .current-quote .top-widget-wrapper").first().each(function () {
            if ($$.newPolicy == null) {
                var newPolicy = new PrismApi.Data.Policy(_session.policy);
                PrismApi.Client.extendViewModel(newPolicy);

                newPolicy.errors = ko.validation.group(newPolicy, { deep: true });
                $$.newPolicy = newPolicy;

                //move the destinations
                function moveDestinations(viewModel) {
                    var destinations = [];
                    ko.utils.arrayForEach(viewModel.Destinations(), function (destination) {
                        if (ko.utils.unwrapObservable(destination.BriefCode)) {
                            destinations.push(EncodeRegion(destination, destination.Country, destination.Country.Location));
                        }
                    });
                    viewModel.MetaData.Countries(destinations.join(','));
                }
                if (newPolicy.Destinations()) {
                    moveDestinations($$.policy);
                    moveDestinations($$.newPolicy);
                }
                if ($('.top-widget-toggle-wrapper').length > 0) {
                    ko.cleanNode($('.top-widget-toggle-wrapper')[0]);
                    ko.applyBindings(newPolicy, $('.top-widget-toggle-wrapper')[0]);
                }
                if ($('.editTripMobile').length > 0) {
                    ko.cleanNode($('.editTripMobile #quote-body')[0]);
                    ko.applyBindings(newPolicy, $('.editTripMobile  #quote-body')[0]);
                }
            }
        });

        $(document).on("click", "#quickQuotePlans #plan-type", function (e) {
            e.preventDefault();
            if ($$.newPolicy.MetaData.multiTripChecked()) {
                $$.newPolicy.MetaData.multiTripChecked(false);

                openMessageBoxModal('Single Trip travel dates', $('#single-trip-dates').html(),
                    'Go', function () {
                        var pageErrorMessages = PrismApi.Validation.validatePolicyAgainstPage($$.newPolicy);
                        if (pageErrorMessages.length === 0) {
                            $(".spinner-bar").css('display', 'block');
                            RedirectToChosenaPlanPage();
                            $('#myModal').on('hidden.bs.modal', function () {
                                $('#myModal').off('hidden.bs.modal');
                                $$.newPolicy.MetaData.multiTripChecked(false)
                                $$.policy.MetaData.quoteIsInvalid(true);
                                return;
                            })
                            return true;
                        }
                        return false;
                    },
                    $('#myModal').on('hidden.bs.modal', function () {
                        $('#myModal').off('hidden.bs.modal');
                        $$.newPolicy.MetaData.multiTripChecked(true)
                        $$.policy.MetaData.quoteIsInvalid(false);
                    })
                );

                $('#modal-cancel').hide();
                $("#myModal").modal().on('shown.bs.modal', function (e) {
                    $("#modal-close", "#myModal").show();
                });


                ko.cleanNode($('#myModalContent .form-group')[0]);
                ko.applyBindingsWithValidation($$.newPolicy, $('#myModalContent .form-group')[0]);
                return;
            }
            else {
                $(".spinner-bar").css('display', 'block');
                $$.newPolicy.MetaData.multiTripChecked(true);
                RedirectToChosenaPlanPage();
            }
        });



        //submit quickQuote
        $(document).on("click", "#quickQuote-submit", function (e) {
            var self = this;
            var onQuickQuotePage = $("#quickQuote").length > 0;
            var onPlansPage = $("#quickQuotePlans").length > 0;
            if (typeof HideQuickQuotePlans === 'function') HideQuickQuotePlans();
            //Force the EndDate to validate when the StartDate changes even if it hasn't been set.
            $$.policy.EndDate.formattedDate.isModified(true);



            $(self).find('svg.icon-arrow-right').hide();
            $(self).find('.spinner').css('visibility', 'visible');
            if (onPlansPage) {
                $$.policy.MetaData.BulkPremiumsReady(false);

                $(".spinner-bar").css('display', 'block');
                if ($$.newPolicy) {
                    $$.fn.CopyQuoteDataToQuote($$.newPolicy, $$.policy);
                }
                quickQuoteClick(null, true);
            } else if (onQuickQuotePage) {
                quickQuotePost();
            }
            else {
                setUpBeforeRedirectToChosenaPlanPage(this);
            }

        });
        //submit quickQuote
        $(document).on("click", ".top-widget-wrapper #topWidget-quickQuote-submit", function (e) {
            setUpBeforeRedirectToChosenaPlanPage(this);
        });

        function setUpBeforeRedirectToChosenaPlanPage(element) {
            var self = element;
            // show spinner
            $(self).find('.icon-arrow-right').hide();
            $(self).find('.spinner').css({'visibility': 'visible', 'display':'block'});

            if (window.sessionStorage && window.sessionStorage['FullAddress'] !== undefined) {
                window.sessionStorage.removeItem('FullAddress');
            }

            moveDataFromTempArray($$.newPolicy);

            $$.newPolicy.errors.showAllMessages();

            $$.newPolicy.errors.visibleMessages = function () {
                var configuration = ko.validation.utils.getConfigOptions($$.newPolicy);
                var errors = [];
                $('.top-widget-wrapper').find('.' + configuration.errorElementClass + ':visible').each(function () {
                    errors.push(new PrismApi.Data.ErrorMessage($(this).attr('name'), $(this).attr('title')))
                });
                return errors;
            }

            if ($$.newPolicy.errors.visibleMessages().length > 0) {
                var apiError = new PrismApi.Data.ApiError(null, $$.newPolicy.errors.visibleMessages(), null);
                $$.Client.displayError(apiError);
                hideSpinner(this)
                return;
            } else {

                // show spinner
                $(self).find('.icon-arrow-right').hide();
                $(self).find('.spinner').css('visibility','visible');
                // show a warning to user if the first adult age is less than 13             
                if ($$.newPolicy.MetaData.MinAdultLegalAge() == null && $$.newPolicy.MetaData.Adults() > 0 && $$.newPolicy.PolicyHolders()[0].MetaData.age() < $$.newPolicy.MetaData.DefaultUnaccompaniedAge() && ($$.newPolicy.MetaData.Adults() == 1 || ($$.newPolicy.MetaData.Adults() == 2 && $$.newPolicy.PolicyHolders()[1].MetaData.age() < $$.newPolicy.MetaData.DefaultUnaccompaniedAge()))) {
                    window.openMessageBoxModal('WARNING', $('#modal-unaccompanied-child').html(),
                        'Ok', RedirectToChosenaPlanPage,
                        'Cancel', function () { });
                    return;
                }
                else {
                    RedirectToChosenaPlanPage();
                }
            }
        }

        $(window).resize(function () {
            //force the scroll to re-evaluate to push the page down if required.
            setTimeout(function () { $(window).scroll() }, 100);
        });
    }



    // Reset healix assessment for traveller/dependant, used when changing plans or aborting pe assessment forcefully
    var resetHealixForTraveller = function (item) {
        if (item.HealixAssessment()) {
            item.HealixAssessment().ScreeningId(0);
            item.HealixAssessment().ScreeningRev(0);
            item.HealixAssessment().PeId(0);
            item.HealixAssessment().ScreeningResult = null;
            item.HealixAssessment().CalculationOption = [];

        }
        if (item.MetaData && item.MetaData.HasPeCondition() !== undefined) {
            item.MetaData.HasPeCondition(undefined);
            if (item.HasPeCondition)
                item.HasPeCondition(undefined);
        }
    }

    //This method will extract querystring values form URL
    function getParameterByName(name) {
        name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
        var regex = new RegExp("[\\?&]" + name + "=([^&#]*)", "i")
        results = regex.exec(location.search);
        return results === null ? null : decodeURIComponent(results[1].replace(/\+/g, " "));
    }

    function createEmailForSharingPolicy() {
        var email = new PrismApi.Data.Email();

        $.extend(email,
            {
                isSending: ko.observable(false),
                hasSent: ko.observable(false)
            });

        email.DisplayName.extend(
            {
                required: {
                    params: true,
                    message: PrismApi.Validation.messages.requiredEmailName
                },
                pattern: {
                    params: PrismApi.Validation.patterns.personName,
                    message: PrismApi.Validation.messages.fieldInvalidCharactersInEmailName
                }
            });

        return email;
    }

    //QUICK QUOTE SETUP
    var quickQuoteSetup = function () {

        var oldWidth = 0;

        $("#quickQuoteForm").each(function () {

            var hasPlansDisplayed = $("#quickQuotePlans").length > 0;
            if (hasPlansDisplayed && (!_session.policy)) {
                $$.Client.Util.sessionTimeoutHandler();
                return;
            }


            $(document).on('click', 'span.show-detailed-plan', function () {


                $('#full-list').collapse('show');
                var fullListOffset = ($('#full-list').offset().top) - (isMobile() ? 70 : 140);
                $('html,body').animate({
                    'scrollTop': fullListOffset
                }, 1200);

            });

            $(document).on('click', '.back-to-top', function () {
                $('body,html').animate({ scrollTop: 0 }, 800);
            });


            $$.policy.CoverStartDate(undefined);
            $$.policy.CoverEndDate(undefined);

            $$.fn.getQuickQuoteOptions()
                .fail($$.Client.displayError)
                .done(function () {
                    afterQuickQuoteOptionsLoaded($$.quickQuoteOptions());

                    $$.fn.getOptionBenefits().done(function () {
                        applyOptionBenefitsToBulkPremium();
                    });

                    // Set any default answers to questions
                    $$.Client.Util.setDefaultQuestions();

                    if (PrismApi.policy.MetaData.Adults() < 2) {
                        PrismApi.policy.MetaData.Adults(2);
                    }
                    if (PrismApi.policy.MetaData.Dependants() < 2) {
                        PrismApi.policy.MetaData.Dependants(2);
                    }
                    if (!PrismApi.policy.PolicyHolders()[0].DateOfBirth()) {
                        //Set default values
                        (function () {
                            if (Modernizr.inputtypes.date && Modernizr.touch) {
                                PrismApi.policy.PolicyHolders()[0].DateOfBirth.formattedDate('' + (new Date().getFullYear() - 35) + '-01-01');
                            } else {
                                PrismApi.policy.PolicyHolders()[0].DateOfBirth.formattedDate('1/1/' + (new Date().getFullYear() - 35));
                            }
                        })();
                    }
                    $(".quick-quote-overlay").show();

                    // set promo code value (uppercase) if value passed by edm querystring
                    var promoCodeAdjustment = ko.utils.arrayFirst($$.policy.Adjustments(), function (adjustments) { return adjustments.BriefCode() == 'DUMMY'; });
                    if (promoCodeAdjustment) {
                        var promoCode = getParameterByName('edm');
                        if (promoCode !== null) {
                            promoCodeAdjustment.Value(promoCode.toUpperCase());
                        }
                    }

                    //set affiliate code if value passed by affcd querystring
                    var affcd = getParameterByName('affcd');
                    if (affcd !== null && affcd.length > 0) {
                        $$.policy.AffiliateCode(affcd.toUpperCase());
                    }

                    //set source code SRCCD if value passed by source querystring
                    var source = getParameterByName('source');
                    if (source !== null && source.length > 0) {
                        var ppei = $$.Utils.arrayFirstBriefCode($$.policy.PremiumExtraInfo(), 'SRCCD');
                        if (!ppei) {
                            ppei = new PrismApi.Data.Question({ 'BriefCode': 'SRCCD' });
                            $$.policy.PremiumExtraInfo.push(ppei);
                        }
                        ppei.Answer({
                            'BriefCode': source.toUpperCase()
                        });
                    }
                    if ($$.ApiVersion != '2.1') {
                        $$.fn.getDestinations()
                            .fail($$.Client.displayError)
                            .done(function () {
                                //move the destinations
                                if ($$.policy.Destinations()) {
                                    var destinations = [];
                                    ko.utils.arrayForEach($$.policy.Destinations(), function (destination) {
                                        if (ko.utils.unwrapObservable(destination.BriefCode)) {
                                            destinations.push(EncodeRegion(destination, destination.Country, destination.Country.Location));
                                        }
                                    });
                                    $$.policy.MetaData.Countries(destinations.join(','));
                                    $$.policy.fn.updateQuickQuoteAssessment();
                                }
                                if ($$.policy.errors.visibleNotValidMessages().length == 0) {
                                    var useSession = $$.policy.MaxTripDuration() ? false : true;
                                    quickQuoteClick(null, true, useSession);
                                }

                                hideSpinner();

                            });
                    } else {

                        $('#quickQuoteForm').show();
                        if ($$.policy.errors.visibleNotValidMessages().length == 0) {
                            var useSession = $$.policy.MaxTripDuration() ? false : true;
                            quickQuoteClick(null, true, useSession);
                        }

                        hideSpinner();
                    }

                })
                .always(function () {
                    $$.fn.getProductDescriptions();

                    // show pe not availble block at bottom
                    if (isMobile()) {
                        $(".peNotAvailable").addClass("visible-xs");
                    }
                    $('.product-review .container').fadeIn();
                    $("#quickQuoteForm").fadeIn();
                    $(".quick-quote-overlay").hide();
                });

            //buy now
            $(document).on("click", ".quickQuote-buyNow", function () {
                var self = this;
                // prevent buying until privacy agreed and multi trip accepted if selected
                //var promPrivacy = $$.Client.Util.Modal.PrivacyModal($$.policy);
                var promPrivacy = $.Deferred().resolve();
                var promMultiTripAgree = $.Deferred();

                promPrivacy.promise().done(function () {
                    if ($(self).data("planbriefcode") === "MULTI") {
                        openMessageBoxModal('Multi Trip Confirmation', $("#modal-multitripplan-agree").html(),
                            'Confirm', function () {
                                var modal = $('#myModal');
                                $("#okcancel", modal).hide();
                                $('#myModal').on('hidden.bs.modal', function () {
                                    $(".modal-footer > div").attr('style', '');
                                    $('#myModal').off('hidden.bs.modal');
                                    promMultiTripAgree.resolve();
                                });
                            },
                            'Cancel', function () {
                                $('#myModal').on('hidden.bs.modal', function () {
                                    $(".modal-footer > div").attr('style', '');
                                    $('#myModal').off('hidden.bs.modal');
                                    promMultiTripAgree.reject();
                                });
                            }
                        );
                    } else {
                        promMultiTripAgree.resolve();
                    }
                });

                $.when(promMultiTripAgree.promise()).done(function () {
                    $(self).find('.icon-arrow-right').hide();

                    $(self).find('.spinner').css({'display': 'block', 'visibility': 'visible'});

                    $$.fn.setPlan($(self).data("planid"))
                        .done(function () {
                            var plan = ko.utils.arrayFirst($$.policy.MetaData.BulkPremiums(), function (bulkPremium) { return bulkPremium.Plan.PlanId() == $$.policy.Plan().PlanId(); }).Plan;



                            var dummyAdjustment = ko.utils.arrayFirst($$.policy.Adjustments(), function (adj) { return adj.BriefCode() == "DUMMY" && ko.unwrap(adj.Value) != null });
                            if (dummyAdjustment) {
                                // remove 'DUMMY' adjustment in policy if not in bulk premium result
                                var adjustment = ko.utils.arrayFirst(ko.unwrap(plan.Adjustments) || [], function (adj) { return adj.MetaData != null && ko.unwrap(adj.MetaData.InputBriefCode) == "DUMMY" && ko.unwrap(adj.Value) == dummyAdjustment.Value() });
                                if (!adjustment) {
                                    ko.utils.arrayRemoveItem($$.policy.Adjustments(), dummyAdjustment);
                                }
                            }

                            // clear pe data
                            $$.policy.PeOptions.PESystem(null);
                            if ($$.policy.PolicyHolders) {
                                $.each($$.policy.PolicyHolders(), function (index, item) {
                                    if (item.PECover && item.PECover.PESystem)
                                        item.PECover.PESystem(null);
                                    resetHealixForTraveller(item);
                                });
                            }
                            if ($$.policy.PolicyDependants) {
                                $.each($$.policy.PolicyDependants(), function (index, item) {
                                    if (item.PECover && item.PECover.PESystem)
                                        item.PECover.PESystem(null);
                                    resetHealixForTraveller(item);
                                });
                            }

                            $$.policy.CoverStartDate($$.policy.StartDate());
                            $$.policy.CoverEndDate($$.policy.EndDate());

                            if ($$.policy.MaxTripDuration()) {
                                var region = ko.utils.arrayFirst($$.policy.MetaData.Regions(), function (region) { return region.BriefCode() == "WORLD" })
                                $$.policy.Region().BriefCode(region.BriefCode());
                                $$.policy.Region().Description(region.Description());

                                var startDate = $$.policy.StartDate().fromISOString();
                                var endDate = new Date(startDate.getFullYear() + 1, startDate.getMonth(), startDate.getDate() - 1);
                                $$.policy.EndDate(endDate.toISOString());
                            }

                            $$.fn.getFullQuoteOptions()
                                .done(function () {
                                    ko.utils.arrayForEach(ko.unwrap($$.policy.MetaData.BulkPremiums()), function (bulkPremium) {
                                        if (bulkPremium.Plan.PlanId() == $$.policy.Plan().PlanId() && ko.unwrap(bulkPremium.Benefit) != undefined && ko.unwrap(bulkPremium.Benefit).length > 0) {
                                            ko.utils.arrayForEach(ko.unwrap(bulkPremium.Benefits), function (benefit) {
                                                if (benefit.MetaData.IsEnabled()) {
                                                    $$.policy.Benefits().push(benefit);
                                                }
                                            });
                                        }
                                    });

                                    window.location.href = $$.baseUrl + "Details"
                                })
                                .fail($$.Client.displayError)
                                .always(function () {
                                    hideSpinner();
                                });
                        })
                        .fail($$.Client.displayError);
                });
            });
            // restore session for privacy agreement if set            
            if (window.localStorage && window.localStorage.privacyAgree === "true") {
                $$.policy.MetaData.privacyAgree(true);
            }

            $(".btn-previous").click(function (e) {
                // navigate allow
                backClickOn();
                window.location.href = $$.baseUrl + "?session=true";
            });

        });

    };

    var applyOptionBenefitsToBulkPremium = function () {
        var ob = PrismApi.optionBenefits;
        if (ob) {
            ko.utils.arrayForEach(ko.unwrap($$.policy.MetaData.BulkPremiums) || [], function (bulkPremium) {

                ko.utils.arrayForEach(ko.unwrap(bulkPremium.Benefits) || [], function (benefit) {
                    var benefitOption = ko.utils.arrayFirst(ob, function (benefitOption) {
                        return benefitOption.Option.BriefCode == benefit.BriefCode()
                    });
                    if (benefitOption) {
                        if (ko.isObservable(benefit.Option)) {
                            benefit.Option(benefitOption.Option)
                        }
                        else {
                            benefit.Option = ko.observable();
                            benefit.Option(benefitOption.Option);
                        }
                        benefit.Benefits = benefitOption.Benefits
                    }
                })
            })

            var BulkpremiumOptions = [];

            ko.utils.arrayForEach(ko.unwrap($$.policy.MetaData.BulkPremiums) || [], function (bulkPremium) {
                ko.utils.arrayForEach(ko.unwrap(bulkPremium.Benefits) || [], function (benefit) {
                    BulkpremiumOptions.push({
                        'BriefCode': benefit.BriefCode(),
                        'Title': benefit.Option().Title
                    });
                })
            })

            $$.policy.MetaData.BulkPremiumsOptionBenefits(BulkpremiumOptions.filter(function (item, pos, array) {
                return array.map(function (mapItem) { return mapItem['BriefCode']; }).indexOf(item['BriefCode']) === pos;
            }))



            $$.policy.MetaData.OptionBenefitsReady(true);
        }
    };
    var moveDataFromTempArray = function (policy) {
        if (!policy) policy = $$.policy;

        //move adult ages from temp array to the policy
        var adults = ko.utils.arrayFilter(policy.MetaData.AdultAges(), function (item) {
            return $.isNumeric(item.MetaData.age());
        });
        policy.MetaData.Adults(adults.length);
        for (var i = 0; i < adults.length; i++) {
            if (!ko.unwrap(policy.PolicyHolders()[i].DateOfBirth) || policy.PolicyHolders()[i].MetaData.age() != adults[i].MetaData.age()) {
                policy.PolicyHolders()[i].MetaData.age(adults[i].MetaData.age());
                window.sessionStorage['Travellers[' + policy.PolicyHolders()[i].MetaData.TravellerIndex + '].HasEnteredDOB'] = 'false';

            }
        }

        //move dependant ages from temp array to the policy
        var dependants = ko.utils.arrayFilter(policy.MetaData.DependantAges(), function (item) {
            return $.isNumeric(item.MetaData.age());
        });
        policy.MetaData.Dependants(dependants.length);
        for (var i = 0; i < dependants.length; i++) {
            if (!ko.unwrap(policy.PolicyDependants()[i].DateOfBirth) || policy.PolicyDependants()[i].MetaData.age() != dependants[i].MetaData.age()) {
                policy.PolicyDependants()[i].MetaData.age(dependants[i].MetaData.age());
                window.sessionStorage['Travellers[' + policy.PolicyDependants()[i].MetaData.TravellerIndex + '].HasEnteredDOB'] = 'false';

            }
        }

        fixDestinations(policy);
    }

    var quickQuotePost = function () {

        moveDataFromTempArray();

        // to do: Post data to Session via API
        $$.policy.errors.showAllMessages();

        var pageErrorMessages = PrismApi.Validation.validatePolicyAgainstPage(PrismApi.policy);

        if ($$.policy.errors.visibleMessages().length > 0) {
            var apiError = new PrismApi.Data.ApiError(null, $$.policy.errors.visibleMessages(), null);
            $$.Client.displayError(apiError);
            hideSpinner(this)
            return;
        } else {
            if (window.location.href.indexOf("accessCode=") < 0) {
                // show a warning to user if the first adult age is less than 13
                if ($$.policy.MetaData.MinAdultLegalAge() == null && $$.policy.MetaData.Adults() > 0 && $$.policy.PolicyHolders()[0].MetaData.age() < $$.policy.MetaData.DefaultUnaccompaniedAge() && ($$.policy.MetaData.Adults() == 1 || ($$.policy.MetaData.Adults() == 2 && $$.policy.PolicyHolders()[1].MetaData.age() < $$.policy.MetaData.DefaultUnaccompaniedAge()))) {
                    window.openMessageBoxModal('WARNING', $('#modal-unaccompanied-child').html(),
                        'Ok', bulkQuotePost,
                        'Cancel', function () { });
                    return;
                }
            }

            bulkQuotePost();
        }
    };

    var bulkQuotePost = function () {

        $$.fn.getBulkQuickQuote(true, true, false, null)
            .done(function () {
                var qs = (PrismApi.bulkQuickQuote.PricingLogId !== undefined && PrismApi.bulkQuickQuote.AccessCode !== undefined ?
                    'id=' + PrismApi.bulkQuickQuote.PricingLogId + '&accessCode=' + PrismApi.bulkQuickQuote.AccessCode + '&session=true' : 'session=true');

                if (promoApplied() == true) {
                    window.top.location.href = $$.baseUrl + "QuickQuote?" + qs;
                }
            })
            .fail($$.Client.displayError)
            .always(function () {
                hideSpinner(this)
            });
    };

    var quickQuoteClick = function (control, suppressScroll, useSessionIfPossible) {

        var useSession = useSessionIfPossible && _session.policy;

        moveDataFromTempArray();

        var fatalFlag;
        if (ko.unwrap($$.policy.PeOptions) != null) {
            var totalHolders = $$.policy.MetaData.Adults() + $$.policy.MetaData.Dependants();
            if (totalHolders === 1 && $$.policy.PeOptions.FatalFlag() === true && PrismApi.nonMedical !== true) {
                fatalFlag = true;
            }
        }

        // reset max trip duration
        $$.policy.MaxTripDuration("");

        var doneFunction = function () {
            // show Privacy confirmation before showing plans
            // when land from aggregators, do not display agreement Declaration light box
            //var promPriv = $.Deferred();
            //if (window.localStorage.privacyAgree == "undefined" || window.localStorage.privacyAgree == '' || window.localStorage.privacyAgree == undefined) {
            //    $$.policy.MetaData.privacyAgree(false);
            //    promPriv = promPriv.resolve();
            //}
            //else {
            //    //promPriv = $$.Client.Util.Modal.PrivacyModal($$.policy);
            //    promPriv = promPriv;
            //}
            //promPriv.promise().done(function () {

            // sort bulk premium
            $$.policy.MetaData.BulkPremiums($$.policy.MetaData.BulkPremiums().sort(function (a, b) { return parseFloat(a.Premium.SellingGross()) - parseFloat(b.Premium.SellingGross()); }));

            ko.utils.arrayForEach($$.policy.MetaData.BulkPremiums(), function (BulkPremium) {

                BulkPremium.MetaData.MarketingText = ko.observable();

                ko.utils.arrayForEach(PartnerConfiguration.MarketingFlags || {}, function (MarketingFlag) {

                    if (MarketingFlag.CoverLevelBrief === BulkPremium.Plan.CoverLevel.BriefCode()) {
                        BulkPremium.MetaData.MarketingText(MarketingFlag.Text);
                    }

                });
            });


            // load data to show

            $$.fn.getProductDescriptions().always(function () {
                $$.fn.getPlanDescriptions().always(function () {
                    $$.fn.getProductBenefits().always(function () {
                        $$.fn.getPaymentOptions().always(function () {
                        });
                    });
                });
            });

            // assign row index for product benefit			    
            $$.policy.MetaData.MaxProductBenefits.removeAll();
            $$.policy.MetaData.MaxProductBenefits.push(0);
            var maxProdBenefits = $$.policy.MetaData.MaxProductBenefits();
            var _accProductBenefit = 0;
            if (ko.isObservable($$.policy.MetaData.ProductBenefits)) {
                for (var i = 0; i < $$.policy.MetaData.ProductBenefits().length ; i++) {
                    _accProductBenefit = _accProductBenefit + $$.policy.MetaData.ProductBenefits()[i].Benefits().length;
                    maxProdBenefits.push(_accProductBenefit);
                }
            }
            $$.policy.MetaData.MaxProductBenefits.valueHasMutated();
            hideSpinner(this);

            if (fatalFlag) {
                openModal($('#modal-peFatal .modal-header').html(), $('#modal-peFatal .modal-body').html(), true, false);
                return;
            }

            if ($$.newPolicy != undefined) {
                $$.policy.MetaData.AdultTravellers($$.newPolicy.MetaData.AdultTravellers());
                $$.policy.MetaData.DependantTravellers($$.newPolicy.MetaData.DependantTravellers());
                $$.policy.MetaData.DisplayMobileSummary(false);
            }
            $$.policy.MetaData.IsEditingTrip(false);
            $('.product-review .container').fadeIn();
            $("#quickQuotePlans").fadeIn();
            //resizePlanSummaryWidth();
            $('#plan-summary').fadeIn();

            $(document.body).animate({
                'scrollTop': $('#main-container').offset().top
            }, 1200);



            $$.policy.MetaData.quoteIsInvalid(false);
            $$.policy.MetaData.BulkPremiumsReady(true);
            //}  );
        };

        if (useSession) {
            doneFunction();
        }
        else {
            if (window.location.href.indexOf("accessCode=") < 0) {
                // show a warning to user if the first adult age is less than 13
                if ($$.policy.MetaData.MinAdultLegalAge() == null && $$.policy.MetaData.Adults() > 0 && $$.policy.PolicyHolders()[0].MetaData.age() < $$.policy.MetaData.DefaultUnaccompaniedAge() && ($$.policy.MetaData.Adults() == 1 || ($$.policy.MetaData.Adults() == 2 && $$.policy.PolicyHolders()[1].MetaData.age() < $$.policy.MetaData.DefaultUnaccompaniedAge()))) {
                    window.openMessageBoxModal('WARNING', $('#modal-unaccompanied-child').html(),
                        'Ok', function () {
                            $$.fn.getBulkQuickQuote(true, true, fatalFlag)
                                .done(function () {
                                    doneFunction();
                                })
                                .fail($$.Client.displayError)
                                .always(function () {
                                    hideSpinner(this)
                                });
                        },
                        'Cancel', function () {
                        });
                    return;
                }
            }

            var multiTripOptions = null;

            if ($$.newPolicy != undefined && $$.newPolicy.MetaData.multiTripChecked()) {
                $$.policy.MetaData.multiTripChecked(true);
                multiTripOptions = { CoverLevelBriefCode: 'MULTI', CoverTypeBriefCode: 'POLLM' };
            }
            else {
                $$.policy.MetaData.multiTripChecked(false);
                multiTripOptions = null;
            }

            $$.fn.getBulkQuickQuote(true, true, fatalFlag, multiTripOptions)
                .done(function () {
                    doneFunction();
                    applyOptionBenefitsToBulkPremium();
                })
                .fail($$.Client.displayError)
                .always(function () {
                    hideSpinner(this);
                });
        }
    };

    var promoApplied = function () {
        // if promo code has entered, check that bulk premium has promo code applied or not
        var dummyAdjustment = ko.utils.arrayFirst($$.policy.Adjustments(), function (adj) { return adj.BriefCode() == "DUMMY" && ko.unwrap(adj.Value) != null });
        var promApplied = false;
        if (dummyAdjustment && dummyAdjustment.Value() != '') {
            for (var i = 0; i < PrismApi.bulkQuickQuote.BulkPremiums.length; i++) {
                var bulkPremium = PrismApi.bulkQuickQuote.BulkPremiums[i];
                if (bulkPremium.Plan.Adjustments != null) {
                    var adjustments = bulkPremium.Plan.Adjustments;
                    for (var j = 0; j < adjustments.length; j++) {
                        if (adjustments[j] != null &&
                            adjustments[j].MetaData.InputBriefCode == dummyAdjustment.BriefCode() &&
                            adjustments[j].Value == dummyAdjustment.Value()) {
                            promApplied = true;
                            if (promApplied)
                                break;
                        }
                    }
                }
            }
        }
        else {
            promApplied = true;
        }
        if (!promApplied) {
            ko.utils.arrayFirst($$.policy.MetaData.PromoAdjustments(), function (adjustments) {
                adjustments.BriefCode() === 'DUMMY' ? adjustments.MetaData.IsPromoValid(false) : '';
            })
            if ($$.policy.MetaData.IsEditingTrip()) {
                ko.utils.arrayFirst($$.newPolicy.MetaData.PromoAdjustments(), function (adjustments) {
                    adjustments.BriefCode() === 'DUMMY' ? adjustments.MetaData.IsPromoValid(false) : '';
                    hideSpinner();
                })
            }
            return false;
        }
        return promApplied;
    }

    var detailsSetUp = function () {
        $("#detailsForm").each(function () {
            if (!PrismApi.policy.Plan().PlanId) {
                $$.Client.Util.sessionTimeoutHandler();
                return;
            }
            //OPTIONS SETUP
            var optionsSetup = function () {
                $("#optionsForm").each(function () {
                    // backspace prevent
                    //backClickOff();

                    //specified items
                    var benefit = $$.policy.fn.getBenefit("SPITM");
                    if (benefit) {
                        var e = benefit.fn.hasBenefitItems() ? "#specifiedYes" : "#specifiedNo";
                        $(e).attr("checked", "checked");
                    }

                    // Set any default answers to questions
                    $$.Client.Util.setDefaultQuestions();

                    //reset Increased Item Value data on closing
                    $('#IncreasedItemLimits').on('hidden.bs.modal', function () {
                        ko.utils.arrayForEach($$.policy.Benefits(), function (benefitItem) {
                            if (benefitItem.BriefCode() == "ITEM") {
                                benefitItem.MetaData.currentlySelectedTraveller(undefined);
                                benefitItem.MetaData.currentlySelectedItem(undefined);
                                benefitItem.MetaData.currentlySelectedValue(undefined);
                                benefitItem.MetaData.checkNewEntryIsValid(true);
                                $('#iilValue')[0].options.length = 0;
                            }
                        });
                    });

                    // handle scroller for special page changes
                    $(document).on("click", ".recalculate, .benefit-showhide", function () {
                        //$('#divScroller').css({ top: 0 + 'px' });
                        setTimeout(function () {
                            if ($$.Client.Util.PostionQuoteSummary) {
                                $$.Client.Util.PostionQuoteSummary(false);
                            }
                        }, 0);
                        return true;
                    });
                });
            };

            //TRAVELLERS SETUP
            var travellersSetup = function () {
                $("#travellersForm").each(function () {
                    if (!$$.fullQuoteOptions) {
                        $$.Client.Util.sessionTimeoutHandler();
                        return;
                    }
                    if (ko.unwrap($$.policy.PeOptions) != null && $$.policy.PeOptions.FatalFlag != null) {
                        $$.policy.PeOptions.FatalFlag(false);
                    }

                    if (window.sessionStorage && window.sessionStorage['showManual'] !== undefined) {
                        $('.address-manual').removeClass('hidden');
                        $('.address-auto').addClass('hidden');
                    }

                    $(document).on('click', '.tt-footer > u', function () {
                        $('.address-manual').removeClass('hidden');
                        $('.address-auto').addClass('hidden');
                    });

                    // set datepicker min max date restrictions
                    var adultType = $$.Client.datepicker.getType("_dobAdults");
                    var dependantType = $$.Client.datepicker.getType("_dobDependants");

                    var restrictSameYearRangeForTraveller = function (input) {
                        var today = new Date();
                        var birthYear = today.getFullYear() - $(input).data('age');
                        return {
                            changeYear: true,
                            changeMonth: true,
                            minDate: new Date(birthYear - 1, today.getMonth(), today.getDate() + 1),
                            maxDate: new Date(birthYear, today.getMonth(), today.getDate())
                        };
                    };
                    adultType.options = restrictSameYearRangeForTraveller;
                    dependantType.options = restrictSameYearRangeForTraveller;
                });
            };

            var self = this;
            var promQQOptions = $.Deferred();
            var promTravellerOptions = $.Deferred();

            $$.fn.getQuickQuoteOptions()
                .fail($$.Client.displayError)
                .done(function () {
                    afterQuickQuoteOptionsLoaded($$.quickQuoteOptions());
                    $$.Client.Util.setDefaultQuestions();

                }).always(function () {
                    promQQOptions.resolve();
                });

            $$.fn.getProductDescriptions()
                .done(function () {
                    $$.fn.getProductBenefits()
                        .done(function () {
                            $$.fn.getOptionBenefits()
                                .done(function () {
                                    ko.utils.arrayForEach($$.policy.Benefits(), function (benefitItem) {
                                        if (benefitItem.MetaData.IsEnabled() == true) {
                                            benefitItem.MetaData.showDetail(true);
                                        }
                                    });
                                    $$.fn.getTravellerOptions()
                                        .fail($$.Client.displayError)
                                        .done(function () {
                                            //  translate titlegroups 
                                            $.each($$.policy.MetaData.AllTravellers(), function (index, item) {
                                                fixTravellerTitle(item);
                                            });
                                            $$.policy.fn.FixTravellers();
                                            $$.policy.MetaData.TravellerOptionsReady(true);

                                        }).always(function () {
                                            promTravellerOptions.resolve();
                                            hideSpinner();
                                        });;

                                }).fail($$.Client.displayError)
                        }).fail($$.Client.displayError)
                }).fail($$.Client.displayError)

            $.when.apply($, [promQQOptions, promTravellerOptions]).done(function () {
                optionsSetup();
                travellersSetup();
                $('.product-review .container').fadeIn();

                $('.quote-summary').fadeIn();
                $(".spinner-bar").remove();
                $('#plan-summary').fadeIn();
                $(self).fadeIn();

                var referrer = document.referrer;

                if (referrer.indexOf("Assessment") > -1 && $$.policy.MetaData.travellersHavePE() === true) {
                    $('html, body').animate({
                        'scrollTop' : $("#PeArea").position().top
                    }, 1200);
                }
            });


            $(".btn-previous").click(function (e) {
                window.location.href = $$.baseUrl + "QuickQuote?session=true";
            });

            $(".btn-next").click(function (e) {
                e.preventDefault();
                var self = this;

                //Set isModified on enteredDOB fields as the validation traversal won't 
                // traverse and observable in an observable unless it's in an array
                ko.utils.arrayForEach($$.policy.MetaData.AllTravellers(), function (traveller) {
                    traveller.DateOfBirth.enteredDOB.isModified(true);
                    if (window.sessionStorage) {
                        window.sessionStorage['Travellers[' + traveller.MetaData.TravellerIndex + '].HasEnteredDOB'] = traveller.DateOfBirth.hasEntered();
                    }

                    if (ko.unwrap(traveller.MetaData.HasPeCondition) === true || ko.unwrap(traveller.MetaData.HasPeCondition) === 'true') {
                        traveller.MetaData.hasCompletedPeAssessment(ko.unwrap(traveller.HealixAssessment().ScreeningId) != 0 && ko.unwrap(traveller.HealixAssessment().ScreeningResult) != null);
                    }
                });

                // set timeouts to prevent script blocks
                var defValidate = $.Deferred();
                setTimeout(function () {
                    var pageErrorMessages = PrismApi.Validation.validatePolicyAgainstPage(PrismApi.policy);
                    defValidate.resolve();
                }, 0);

                defValidate.promise().done(function () {
                    setTimeout(function () {

                        if ($$.policy.errors.visibleMessages().length > 0) {
                            var apiError = new PrismApi.Data.ApiError(null, $$.policy.errors.visibleMessages(), null);
                            $$.Client.displayError(apiError);
                            return;

                        } else {
                            var hasError = false;
                            var PEYesTravellersNo = true;
                            var numberTravellersPENo = 0;


                            // navigate allow
                            backClickOn();
                            var spitm = PrismApi.Utils.arrayFirstBriefCode($$.policy.Benefits(), 'SPITM');
                            if (spitm) {
                                for (var i = 0; i < spitm.BenefitItems().length; i++) {
                                    var item = spitm.BenefitItems()[i];
                                    if ((!item.Name()) && (!item.Value())) {
                                        spitm.fn.removeBenefitItem(i);
                                    }
                                }
                            }

                            // Set isModified on enteredDOB fields as the validation traversal won't 
                            // traverse and observable in an observable unless it's in an array
                            ko.utils.arrayForEach($$.policy.MetaData.AllTravellers(), function (traveller) {
                                traveller.DateOfBirth.enteredDOB.isModified(true);
                                //if (window.sessionStorage) {
                                //    window.sessionStorage['Travellers[' + traveller.MetaData.TravellerIndex + '].HasEnteredDOB'] = traveller.DateOfBirth.hasEntered();
                                //}
                            });

                            $(self).find('.spinner').css('visibility','visible');
                            $$.fn.getFullQuote(false, true)
                                .done(function () {
                                    window.location.href = $$.baseUrl + "Payment";
                                })
                                .always(function () {
                                    hideSpinner($(this));
                                })
                                .fail($$.Client.displayError);
                        }
                    }, 0);
                });

                return true;
            });

        });
    };

    var backClickOff = function () {
        // prevent navigating away from page
        window.onbeforeunload = function (e) {
            if (e && e.preventDefault)
                e.preventDefault();
            return 'Are you sure you want to cancel your travel insurance purchase? By continuing all current information will be lost.';
        }
        // bind buttons to ignoe this rule
        $(document).on('click', '.ignoreNavigationPrevention', function (e) {
            backClickOn();
        });
    };

    var backClickOn = function () {
        // clear back/reload prevention
        window.onbeforeunload = null
    };


    //pe-Fatal SETUP
    var peFatalSetup = function () {
        $("#peFatalForm").each(function () {
            var self = this;
            backClickOn();
            if (!$$.fullQuoteOptions) {
                $$.Client.Util.sessionTimeoutHandler();
                return;
            }

            $$.fn.getQuickQuoteOptions()
                .fail($$.Client.displayError)
                .done(function () {
                    afterQuickQuoteOptionsLoaded($$.quickQuoteOptions());
                    $$.Client.Util.setDefaultQuestions();
                });

            $$.fn.getProductBenefits()
                .done(function () {
                    $$.fn.getOptionBenefits()
                        .done(function () {
                            ko.utils.arrayForEach($$.policy.Benefits(), function (benefitItem) {
                                if (benefitItem.MetaData.IsEnabled() == true) {
                                    benefitItem.MetaData.showDetail(true);
                                }
                            });

                        }).fail($$.Client.displayError)
                }).fail($$.Client.displayError);



            $$.fn.getTravellerOptions()
                .fail($$.Client.displayError)
                .done(function () {
                    //  translate titlegroups 
                    $.each($$.policy.MetaData.AllTravellers(), function (index, item) {
                        fixTravellerTitle(item);
                    });
                    $$.policy.MetaData.TravellerOptionsReady(true);
                    $('.product-review .container').fadeIn();
                    $(".spinner-bar").remove();
                    $(self).fadeIn();
                    $('.quote-summary').fadeIn();
                    $$.policy.MetaData.showHealixAssessmentSummary(true);
                    //resizePlanSummaryWidth();
                    $('#plan-summary').fadeIn();
                });

            $(".btn-no").click(function (e) {
                $(".btn-next").prop('disabled', true);
                $('.spinner').show();
                $$.policy.PeOptions.FatalFlag(false);
                $$.fn.retrieveHealixAssessment()
                    .done(function () {
                        window.location.href = $$.baseUrl + "PreExisting/Screening";
                    })
                    .always(function () {
                        hideSpinner($(this));
                    })
                    .fail(function (status) {
                        if (status && status.StatusCode && status.StatusCode === 200) {
                            window.location.href = $$.baseUrl + "PreExisting/Screening";
                        } else {
                            $$.Client.displayError
                            $(".btn-next").prop('disabled', false);
                        }
                    });
            });

            $(".btn-yes").click(function (e) {
                $(".btn-next").prop('disabled', true);
                $('.spinner').show();
                $$.policy.PeOptions.FatalFlag(true);
                $$.fn.persistAssessment()
                    .done(function () {
                        window.location.href = $$.baseUrl + "PreExisting/Assessment";
                    })
                    .always(function () {
                        hideSpinner($(this));
                    })
                    .fail(function (status) {
                        if (status && status.StatusCode && status.StatusCode === 200) {
                            window.location.href = $$.baseUrl + "PreExisting/Assessment";
                        } else {
                            $$.Client.displayError
                            $(".btn-next").prop('disabled', false);
                        }
                    });
            });

            $(".btn-previous").click(function (e) {
                window.location.href = $$.baseUrl + "Details";
            });
        });
        $("#myModal").on("shown.bs.modal", function () {
            $("#modal-peFatal").each(function () {

                if ($$.policy != null && ko.unwrap($$.policy.PeOptions) != null && $$.policy.PeOptions.FatalFlag() == true && $$.policy.PeOptions.PeFatalQuestion() == null) {
                    $$.fn.retrieveHealixFatalCondition();
                }
                $(".btn-no").click(function (e) {
                    $$.policy.PeOptions.FatalFlag(false);

                    $$.fn.persistAssessment()
                        .done(function () {
                            quickQuoteClick();
                        })
                        .always(function () {
                            hideSpinner($(this));
                        })
                        .fail(function (status) {
                            if (status && status.StatusCode && status.StatusCode === 200) {
                                quickQuoteClick();
                            } else {
                                $$.Client.displayError
                            }
                        });
                });

                $(".btn-yes").click(function (e) {
                    $$.policy.PeOptions.FatalFlag(true);
                    PrismApi.nonMedical = true;
                    $$.policy.MetaData.OptionBenefitsReady(false);
                    $$.fn.persistAssessment()
                        .done(function () {
                            quickQuoteClick();
                        })
                        .always(function () {
                            hideSpinner($(this));
                        })
                        .fail(function (status) {
                            if (status && status.StatusCode && status.StatusCode === 200) {
                                quickQuoteClick();
                            } else {
                                $$.Client.displayError
                            }
                        });
                });
            });
        });
    };

    var backspaceOverride = function (event) {
        var doPrevent = false;
        if (event.keyCode === 8) {
            var d = event.srcElement || event.target;
            if ((d.tagName.toUpperCase() === 'INPUT' && (d.type.toUpperCase() === 'TEXT' || d.type.toUpperCase() === 'PASSWORD'))
                || d.tagName.toUpperCase() === 'TEXTAREA') {
                doPrevent = d.readOnly || d.disabled;
            }
            else {
                doPrevent = true;
            }
        }

        if (doPrevent) {
            event.preventDefault();
        }
    };
    //Healix SETUP
    var healixSetup = function () {
        $("#healixForm").each(function () {
            var self = this;
            // backspace prevent
            backClickOff();
            $(".progress-item").removeClass("ignoreNavigationPrevention");
            $$.policy.MetaData.showHealixAssessmentSummary(true);

            $(document).off('keydown').on('keydown', backspaceOverride);
            if (!$$.fullQuoteOptions) {
                $$.Client.Util.sessionTimeoutHandler();
                return;
            }

            $$.fn.getQuickQuoteOptions()
                .fail($$.Client.displayError)
                .done(function () {
                    afterQuickQuoteOptionsLoaded($$.quickQuoteOptions());
                    $$.Client.Util.setDefaultQuestions();
                });

            $$.fn.getProductBenefits()
                .done(function () {
                    $$.fn.getOptionBenefits()
                        .done(function () {
                            ko.utils.arrayForEach($$.policy.Benefits(), function (benefitItem) {
                                if (benefitItem.MetaData.IsEnabled() == true) {
                                    benefitItem.MetaData.showDetail(true);
                                }
                            });

                        }).fail($$.Client.displayError)
                }).fail($$.Client.displayError);

            $$.fn.getTravellerOptions()
                .fail($$.Client.displayError)
                .done(function () {
                    //  translate titlegroups 
                    $.each($$.policy.MetaData.AllTravellers(), function (index, item) {
                        fixTravellerTitle(item);
                    });
                    $$.policy.MetaData.TravellerOptionsReady(true);

                    $(".spinner-bar").remove();
                    //resizePlanSummaryWidth();
                    $('#plan-summary').fadeIn();
                    $(self).fadeIn();
                });

            /* healix Tabs ***********/
            $(".tab_contents").hide();
            var tabLinks = $('#tabHealix li');
            // Add active class, could possibly go in markup
            // Show all active tabs
            $('ul.nav-tabsh li a').each(function () {
                var target = $(this).attr('href');
                $(target).hide();
            });
            tabLinks.eq(0).addClass('active');

            $('ul.nav-tabsh li.active a').each(function () {
                var target = $(this).attr('href');
                $(target).addClass('active').addClass('in');
                $(target).show();
            });
            // Hide all .tab-content divs
            $("#mainDivHealix").fadeIn();
            //resizePlanSummaryWidth();
            $('.product-review .container').fadeIn();
            $('#plan-summary').fadeIn();
            $('.quote-summary').fadeIn();
            $('iframe', this).each(function () {
                keepAlive();
                window.healixAlive = setInterval(keepAlive, keepAliveInterval * 1000 * 60);
            });

            $.each($(".freeCondTable input[type='radio']"), function (index, element) {
                $(element).after($("label[for='" + element.id + "']"));
            });

            $.each($(".divPreConditionQuestion .divRadio input[type='radio']"), function (index, element) {
                $(element).after($("label[for='" + element.id + "']"));
            });

            $(".back-button").click(function (e) {
                window.location.href = $$.baseUrl + "Details";
            });

            $('.btn-change').on('click', function () {
                // healix frames prevent opendialog being overriden for openmodalmessage
                if (openModalFunction)
                    window.openModal = openModalFunction;
            });
        });
    };

    //Pre-result SETUP
    var healixResultSetup = function () {
        $("#healixResultForm").each(function () {
            // backspace prevent
            backClickOff();

            // Stop navigation on recalc
            $$.policy.MetaData.PreventNavigationOnRecalc(true)
            $$.policy.MetaData.showHealixAssessmentSummary(true);

            $(document).off('keydown').on('keydown', backspaceOverride);
            $(".progress-item").removeClass("ignoreNavigationPrevention");

            if (!$$.fullQuoteOptions) {
                $$.Client.Util.sessionTimeoutHandler();
                return;
            }

            $$.fn.getProductBenefits()
                .done(function () {
                    $$.fn.getOptionBenefits()
                        .done(function () {
                            ko.utils.arrayForEach($$.policy.Benefits(), function (benefitItem) {
                                if (benefitItem.MetaData.IsEnabled() == true) {
                                    benefitItem.MetaData.showDetail(true);
                                }
                            });

                        }).fail($$.Client.displayError)
                        .always(function () {
                            hideSpinner();
                        });
                }).fail($$.Client.displayError);

            // now Get titles for lookup to display Persons name details
            $$.policy.MetaData.showHealixAssessmentSummary(true);
            $('.product-review .container').fadeIn();
            $('.quote-summary').fadeIn();
            $('#plan-summary').fadeIn();
            $$.fn.getTravellerOptions()
                .fail($$.Client.displayError)
                .done(function () {
                    //  translate titlegroups 
                    $.each($$.policy.MetaData.AllTravellers(), function (index, item) {
                        item.MetaData.FormattedName = getTravellerNameComputed(item);
                        fixTravellerTitle(item);
                    });
                    $$.policy.MetaData.TravellerOptionsReady(true);
                    $(".spinner-bar").remove();
                    $("#healixResultForm").fadeIn();
                }).always(function () {
                    hideSpinner();
                });


            var traveller = -1;
            var dependant = -1;
            $.each($$.policy.PolicyHolders(), function (index, item) {
                if (item.HealixAssessment() && item.HealixAssessment().PeId() == 1) {
                    traveller = index;
                    window.localStorage.removeItem('Traveller' + (index + 1).toString() + 'PeAccepted');
                    item.HealixAssessment().MetaData.ResetSelectPremium = function () {
                        item.HealixAssessment().MetaData.SelectPremium.isModified(false);
                    };
                }
            });
            $.each($$.policy.PolicyDependants(), function (index, item) {
                if (item.HealixAssessment() && item.HealixAssessment().PeId() == 1) {
                    dependant = index;
                    window.localStorage.removeItem('Dependant' + (index + 1).toString() + 'PeAccepted');
                }
            });


            $("#healixResultForm").on('click', '.peResultPeOptOut', function (e) {
                processDeclined(this, '#modal-peOptOut');
            });
            $("#healixResultForm").on('click', '.peResultDeclineOption', function (e) {
                processDeclined(this, '#modal-peDeclineOption');
            });
            var processDeclined = function (el, modelId) {
                var element = $(el);
                var data = ko.dataFor(el);
                var value = element.val();
                // display PE declined warning 
                openMessageBoxModal('Warning', $(modelId).html(),
                    'Ok', function () {
                        var modal = $('#myModal');
                        $("#okcancel", modal).hide();
                        window.UpdateTotalAfterPE();
                    },
                    'Cancel', function () {
                        data.MetaData.IsEnabled(undefined);
                        data.MetaData.IsEnabled.isModified(false);//reset the value
                        $("input[type=radio]").removeAttr('checked').removeClass('checked');
                    }
                );
            };


            $(".btn-next").click(function (e) {
                // set timeouts as to not block scripts when validating or 
                var defValidate = $.Deferred();
                setTimeout(function () {
                    // dirty Date of Births for validation incase a new traveller added, done here instead of add so input not marked invalid immediately
                    $.each($$.policy.MetaData.AllTravellers(), function (index, item) {
                        //dirty PE questions
                        if (item.HealixAssessment()) {
                            item.HealixAssessment().MetaData.IsEnabled.isModified(true);
                        }
                    });
                    $$.policy.errors.showAllMessages();
                    var pageErrorMessages = PrismApi.Validation.validatePolicyAgainstPage(PrismApi.policy);
                    defValidate.resolve();
                }, 0);
                defValidate.promise().done(function () {
                    setTimeout(function () {
                        if ($$.policy.errors.visibleMessages().length > 0) {
                            var apiError = new PrismApi.Data.ApiError(null, $$.policy.errors.visibleMessages(), null);
                            $$.Client.displayError(apiError);
                            return;
                        } else {

                            backClickOn();
                            if (window.localStorage) {
                                // search through travellers and dependants for healix accepted
                                if (traveller > -1) {
                                    window.localStorage['Traveller' + (traveller + 1).toString() + 'PeAccepted'] = true;
                                }
                                else if (dependant > -1) {
                                    window.localStorage['Dependant' + (dependant + 1).toString() + 'PeAccepted'] = true;
                                }
                            }
                            $('.btn-next').find('.spinner').css('visibility','visible');
                            // indicate in meta data for traveller PE data finalised
                            $.each(PrismApi.policy.PolicyHolders(), function (index, value) {
                                $$.policy.fn.updateScreeningSessionResult(value, '.spinner', "b2c", "Details");
                            });

                            $.each(PrismApi.policy.PolicyDependants(), function (index, value) {
                                $$.policy.fn.updateScreeningSessionResult(value, '.spinner', "b2c", "Details");
                            });
                        }
                    }, 0);
                });
                e.preventDefault();
                return true;
            });

            $(".btn-previous").click(function (e) {
                window.location.href = $$.baseUrl + "PreExisting/Screening";
            });

            // lock down links/buttons
            $('.progress-new .button').off('click').attr('onclick', '').attr('target', '').attr('href', '#');
            $('.logo a').off('click').attr('onclick', '').attr('target', '').attr('href', '#');

            $('.btn-change').on('click', function () {
                // healix frames prevent opendialog being overriden for openmodalmessage
                if (openModalFunction)
                    window.openModal = openModalFunction;
            });
        });

    };

    //PAYMENT SETUP
    var paymentSetup = function () {
        $("#paymentForm").each(function () {
            if (!$$.fullQuoteOptions) {
                $$.Client.Util.sessionTimeoutHandler();
                return;
            }

            $.when.apply($, [
                $$.fn.getQuickQuoteOptions(),
                $$.fn.getTravellerOptions(),
                $$.fn.getOptionBenefits(),
                $$.fn.getPaymentOptions()
            ]).done(function () {
                var selectedPaymentOption = $$.policy.fn.getPaymentOption();
                if (selectedPaymentOption.takesCreditCard) {
                    if (selectedPaymentOption.PCIStrategy === "OnePayHostedFields") {

                        $$.Client.Util.HostedFields = {
                            validateOnEvents: ["blur", "stateChanged"],
                            getFieldMappedValidators: function () {
                                var fieldMappedValidators = {};
                                fieldMappedValidators[PaymentService.config.cardNumber.id] = "isCardNumberValid";
                                fieldMappedValidators[PaymentService.config.securityCode.id] = "isSecurityCodeValid";
                                return fieldMappedValidators;
                            },
                            handleFieldEvent: function (event) {
                                if ($.inArray(event.eventType, $$.Client.Util.HostedFields.validateOnEvents) > -1) {
                                    var validatorName = $$.Client.Util.HostedFields.getFieldMappedValidators()[event.field.id];
                                    $$.policy.CreditCard.MetaData.HostedFields[validatorName](event.field.state === "valid");
                                }

                                if (event.field.id === PaymentService.config.securityCode.id) {
                                    $$.policy.CreditCard.CardSecurityCode(event.field.state === "empty" ? "" : "***");
                                }
                            },
                            handleCardTypeChanged: function (event) {
                                $$.policy.CreditCard.CardNumber(event.panMask);
                                $$.policy.CreditCard.CardType($$.payment.cardType(event.panMask));
                            }
                        };

                        var merchantId = $$.policy.MetaData.MerchantId;
                        $$.fn.createPaymentSession(merchantId).done(function (session) {

                            var defaultStyle = { fontFamily: 'Arial', color: '#555555', fontSize: '12px', padding: '0' };

                            PaymentService.configure({
                                url: session.BaseUrl,
                                styles: {
                                    default: defaultStyle,
                                    success: defaultStyle,
                                    error: defaultStyle
                                },
                                cardNumber: { placeholder: '' },
                                securityCode: { placeholder: '' },
                                onFieldEvent: $$.Client.Util.HostedFields.handleFieldEvent,
                                onCardTypeChangeEvent: $$.Client.Util.HostedFields.handleCardTypeChanged
                            }).then(function () {

                                $$.policy.CreditCard.MetaData.HostedFields.isEnabled(true);
                                $$.policy.CreditCard.PaymentSessionId(session.SessionId);
                                console.log("hosted payment fields initialized successfully");
                                $('#plan-summary').fadeIn();
                                $("#paymentForm").fadeIn();
                                $(".spinner-bar").remove();

                            }).catch($$.Client.displayError);

                        }).fail($$.Client.displayError);

                    } else {
                        $$.payment.fn.updateCardTypes();

                        $('#cc_number').payment('formatCardNumber');
                        $('#cc_number').on('payment.cardType', function (a, b) {
                            var cardType = b === 'unknown' ? undefined : b;
                            $$.policy.CreditCard.CardType(cardType);
                        });
                        $('#plan-summary').fadeIn();
                        $("#paymentForm").fadeIn();
                        $(".spinner-bar").remove();
                    }

                    $$.policy.CreditCard.CardType.subscribe(function (a, b, c) {
                        applyCreditCardPromo($$.policy);
                        $$.policy.MetaData.isRecalculating(true);
                        $$.fn.getFullQuote(false, false, false)
                            .always(function () {
                                $$.policy.MetaData.isRecalculating(false);
                            });
                    });
                }

                afterQuickQuoteOptionsLoaded($$.quickQuoteOptions());
                $$.Client.Util.setDefaultQuestions();

                $.each($$.policy.MetaData.AllTravellers(), function (index, item) {
                    fixTravellerTitle(item);
                });
                $$.policy.MetaData.TravellerOptionsReady(true);

                ko.utils.arrayForEach($$.policy.Benefits(), function (benefitItem) {
                    if (benefitItem.MetaData.IsEnabled() == true) {
                        benefitItem.MetaData.showDetail(true);
                    }
                });
            })
                .fail($$.Client.displayError);

            $(".btn-previous").click(function (e) {
                window.location.href = $$.baseUrl + "details";
            });

            $(".btn-purchase").click(function () {
                setTimeout(function () {
                    var errorMessages = PrismApi.fn._validatePolicy();
                    if (errorMessages.length > 0) {
                        var apiError = new PrismApi.Data.ApiError(null, errorMessages, null);
                        $$.Client.displayError(apiError);
                        return;
                    }

                    // default timeout to 5 minutes
                    var ajaxTimeout = 300000;
                    if (apiAjaxTimeout)
                        ajaxTimeout = apiAjaxTimeout;
                    $.ajaxSetup({ timeout: ajaxTimeout });

                    applyCreditCardPromo($$.policy);

                    var purchaseFn = function () {
                        openPurchaseModal();
                        $$.fn.purchase()
                            .done(function () {
                                window.location.href = $$.baseUrl + "receipt";
                            })
                            .fail(function (error, reason) {
                                $('#myModal').on('hidden.bs.modal', function () {
                                    $('#myModal').off('hidden.bs.modal');
                                    if (reason === "timeout") {
                                        // clear session data as the user should not be allowed to resubmit
                                        $$.Client.Util.resetSessionData();
                                        // any click should send user back to quick quote  (apart from contact page link)
                                        $(document).on('click', function () {
                                            window.location.href = $$.baseUrl;
                                        });
                                    }
                                    $$.Client.displayError(error);
                                });
                                hideModal();
                            });
                    };

                    var selectedPaymentOption = $$.policy.fn.getPaymentOption();
                    if (selectedPaymentOption.takesCreditCard) {
                        var cardInformation = {
                            expiryMonth: $$.policy.CreditCard.CardExpiryMonth(),
                            expiryYear: $$.policy.CreditCard.CardExpiryYear(),
                            cardHolderName: $$.policy.CreditCard.CardHolder()
                        };

                        if (selectedPaymentOption.PCIStrategy === "OnePayHostedFields") {
                            PaymentService.submit(cardInformation)
                                .then(function () {
                                    window.console.log("credit card information submit successfully via hosted payment fields");
                                    purchaseFn();
                                })
                                .catch($$.Client.displayError);
                        } else {
                            purchaseFn();
                        }
                    }

                }, 0);
                return true;
            });
        });
    };

    var applyPrimaryTraveller = function (viewModel, restore) {
        if (ko.unwrap(viewModel.MetaData.PrimaryTravellerIndex)) {
            var primaryTravellerIndex = parseInt(viewModel.MetaData.PrimaryTravellerIndex());
            if (viewModel.PolicyHolders().length > 1 && primaryTravellerIndex > 1) {
                if (restore) {
                    var primaryTraveller = viewModel.PolicyHolders.splice(0, 1)[0];
                    viewModel.PolicyHolders.splice(primaryTravellerIndex - 1, 0, primaryTraveller);
                } else {
                    var primaryTraveller = viewModel.PolicyHolders.splice(primaryTravellerIndex - 1, 1)[0];
                    viewModel.PolicyHolders.unshift(primaryTraveller);
                }

                // set Index as TravellerIndex
                ko.utils.arrayForEach(ko.unwrap(viewModel.PolicyHolders), function (policyHolder) {
                    policyHolder.MetaData.Index = policyHolder.MetaData.TravellerIndex;
                });

                // swap benefit items
                ko.utils.arrayForEach(ko.unwrap(viewModel.Benefits) || [], function (benefit) {
                    if (benefit.MetaData.IsPerPerson) {
                        ko.utils.arrayForEach(ko.unwrap(benefit.BenefitItems) || [], function (benefitItem) {
                            if (ko.unwrap(benefitItem.CustomerIndex) === 1) {
                                benefitItem.CustomerIndex(primaryTravellerIndex);
                            }
                            else if (ko.unwrap(benefitItem.CustomerIndex) === primaryTravellerIndex) {
                                benefitItem.CustomerIndex(1);
                            }
                        });
                    }
                });
            }
        }
    };

    var applyCreditCardPromo = function (viewModel) {

        //First, clear out any credit card promos
        ko.utils.arrayForEach($$.paymentOptions()[0].CreditCardTypes, function (card) {
            var adjustment = ko.utils.arrayFirst(viewModel.Adjustments(), function (item) {
                return ko.unwrap(item.BriefCode) == card.AdjustmentType;
            });

            if (adjustment) {
                adjustment.Value(null);
            }
        });
        //Put the first part of the credit card into the adjustment specified in the card type
        var card = ko.utils.arrayFirst($$.paymentOptions()[0].CreditCardTypes, function (card) {
            return card.BriefCode == viewModel.CreditCard.CardType();
        });
        if (card && card.AdjustmentType) {
            var adjustment = ko.utils.arrayFirst(viewModel.Adjustments(), function (item) {
                return ko.unwrap(item.BriefCode) == card.AdjustmentType;
            });

            if (adjustment) {
                if (viewModel.CreditCard.CardNumber()) {
                    adjustment.Value(viewModel.CreditCard.CardNumber().substr(0, 6));
                } else {
                    adjustment.Value('123456');
                }
            }
        }
    }

    var prepareShowFeature = function () {
        if ($(this).width() >= 480) {
            fixBenefitTable();
            $('.features-div').hide();
            $('.icon-plus').show();
            $('.icon-minus').hide();
        }
    };

    //CONFIRMATION SETUP
    var confirmationSetup = function () {
        $("#confirmationForm").each(function () {
            // backspace prevent
            backClickOff();

            if (!$$.fullQuoteOptions) {
                $$.Client.Util.sessionTimeoutHandler();
                return;
            }
            $(".spinner-bar").remove();
            $(".banner .container").remove();
            $("#plan-summary-mobile").remove();

            $(this).fadeIn();

            $(".purchase-path > div.button").not('.home')
                .removeClass("is-clickable")
                .click(function () {
                    return false;
                });

            $("#btn-print").click(function () {
                $$.fn.getDocument($$.policy.ClientReference());
            });

            $$.Client.sendPolicyEmail = function (item) {

                var errors = ko.validation.group(item, { deep: true });

                errors.showAllMessages();

                if (item.errors().length > 0) {
                    return;
                }

                item.isSending(true);

                var recipients = [
                    {
                        "DisplayName": item.DisplayName(),
                        "EmailAddress": item.EmailAddress()
                    }
                ];

                $$.fn.sendPolicyDocumentationEmail($$.policy.ClientReference(), recipients)
                    .done(function () {
                        item.isSending(false);
                        item.hasSent(true);
                    });
            };

            $$.Client.addOneToSharePolicyEmails = function () {

                $$.policy.MetaData.SharePolicyEmails.push(createEmailForSharingPolicy());
            };

            $(".purchase-path .home").attr('onclick', 'window.location.href=$$.baseUrl');
            if (window.localStorage)
                window.localStorage.clear();
        });
    };
    var faqSetup = function () {
        $("#faqs-init").each(function () {
            $('.faq-question').click(function () {          // Attach behavior
                $(this).children(":first").toggleClass('fa-minus');   // Swap the icon
                $(this).next().toggle();                    // Hide/show the text
            });
        });
    };

    var quoteSummarySetup = function () {
        $$.Client.Util.initialiseQuoteSummaryScroller();
        // check for travellers that have pe show warning before allowing quickquote navigation
        $(document).on('click', '.quote-summary .btn-change', function () {
            var foundPE = false;
            $.each($$.policy.PolicyHolders(), function (index, item) {
                if (item.MetaData.HasPeCondition() === 'true')
                    foundPE = true;
            });
            $.each($$.policy.PolicyDependants(), function (index, item) {
                if (item.MetaData.HasPeCondition() === 'true')
                    foundPE = true;
            });
            if (foundPE) {
                window.openMessageBoxModal('WARNING', PrismApi.Validation.messages.warningPEChange,
                    'Ok', function () {
                        window.location.href = $$.baseUrl + "QuickQuote?session=true";
                    },
                    'Cancel', function () {
                    });
                return;
            } else {
                window.location.href = $$.baseUrl + "QuickQuote?session=true";
                return;
            }
        });


    };

    //INITIALIZE PRISM API
    (function () {
        //SESSION HANDLING
        $("#quickQuoteForm").each(function () {
            //Clear policy in session if the server hasn't supplied it.
            if (!_session.policy) {
                $$.Client.Util.resetSessionData();
            }

            _session.fullQuoteOptions = undefined;

        });

        $$.fn.init()
            .done(function () {
                $$.Client.Util.setupSessionExpiryHandler();
                quickQuoteSetup();
                detailsSetUp();
                fixQuestionItems();
                peFatalSetup();
                healixSetup();
                healixResultSetup();
                paymentSetup();
                confirmationSetup();
                commonSetup();
                faqSetup();
                quoteSummarySetup();
                bootstrapSetup();
            })
            .fail($$.Client.displayError);
    })();


});;
/* 
 * Name: B2C-validation-messages.js
 * Description: Override PrismApi.Validation.Messages and shared-validation-messages extend with new messages for B2C
 *
 */
var PrismApi = PrismApi || {};
PrismApi.Validation = PrismApi.Validation || {};
PrismApi.Validation.messages = $.extend({}, PrismApi.Validation.messages, {
    // overwrite the API error messages
    requiredEndDate: 'Please enter your return date.',
    requiredStartDate: 'Please enter your departure date.',
    dateShouldBeAfterToday: '{1} cannot be earlier than today.', /* fieldname */
    startDateIsAfterEndDate: 'Return date cannot be earlier than the Departure date.',
    requiredEmailDocuments: "You must agree to receive the PDS and Certificate of Insurance by email before continuing.If you would like to update your email then please return to the Your Details screen.",
    equalTruePrivacyAgree: "You must agree to having your personal information collected.",
    warningPEChange: 'By choosing to change your quote you will be required to conduct the Pre-Existing Medical assessment again for each traveller that has a Pre-Existing medical condition.'
});
PrismApi.Validation.messages.payment = $.extend({}, PrismApi.Validation.messages.payment, {
    // overwrite the API error messages
    requiredCardType: "Please enter your payment card type.",
    requiredCardNumber: "Please enter your credit card number.",
    requiredCardHolderName: "Please enter the name on your credit card.",
    requiredCardMonth: "Please select the credit card expiry month.",
    requiredCardYear: "Please select the credit card expiry year.",
    requiredCVV: "Please enter the credit card CVV value.",
    creditCardNotValid: "Please enter a valid credit card.",
    CVVLength: "Please enter a valid credit card CVV value.",
    CVVNumber: "Please enter a valid credit card CVV value.",
    check1:"Please answer Eligibility Check 1",
    check2:"Please answer Eligibility Check 2",
    check3:"Please answer Eligibility Check 3"
});

;
