/* Minification failed. Returning unminified contents.
(3931,17-18): run-time error JS1005: Expected '(': {
(3932,5-6): run-time error JS1006: Expected ')': }
(3932,5-6): run-time error JS1008: Expected '{': }
(3933,2-3): run-time error JS1195: Expected expression: )
(10523,1): run-time error JS1009: Expected '}'
(10523,1): run-time error JS1107: Expecting more source characters
(3915,19-30): run-time error JS1301: End of file encountered before function is properly closed: function ()
(10523,1): run-time error JS1107: Expecting more source characters
(10523,1): run-time error JS1006: Expected ')'
 */
/* Minification failed. Returning unminified contents.
(3920,17-18): run-time error JS1005: Expected '(': {
(3921,5-6): run-time error JS1006: Expected ')': }
(3921,5-6): run-time error JS1008: Expected '{': }
(3922,2-3): run-time error JS1195: Expected expression: )
(10512,1): run-time error JS1009: Expected '}'
(10512,1): run-time error JS1107: Expecting more source characters
(3904,19-30): run-time error JS1301: End of file encountered before function is properly closed: function ()
(10512,1): run-time error JS1107: Expecting more source characters
(10512,1): run-time error JS1006: Expected ')'
 */
(function () {
    "use strict";

    angular
        .module('AF.directives')
        .directive('tripBookingAndPayment', ['$timeout', '$filter', 'locationService', 'priceService', 'finalizeBookingService', 'configurationConstant', 'dataLayerService', tripBookingAndPayment]);

    function tripBookingAndPayment($timeout, $filter, locationService, priceService, finalizeBookingService, configurationConstant, dataLayerService) {
        var directive = {
            restrict: 'A',
            scope: true,
            controller: tripBookingAndPaymentController,
            controllerAs: 'tbapc',
            bindToController: true,
            link: link
        };
        function link(scope, element, attr, ctrl) {
            var HELPERS = {};
            var CAROUSEL = {};
            var FORM = {};

            HELPERS.scrollTo = function (position) {
                angular.element('html, body').animate({
                    scrollTop: position
                }, 100);
            }

            FORM.$details = angular.element('#booking-steps--passenger-details form');
            FORM.$detailsDependentFields = $('[data-parent-sitecore-id]', FORM.$details);
            FORM.unbindedInputs = [];
            FORM.$payment = angular.element('.booking-form__payment__card form');
            FORM.$paypalPayment = angular.element('.booking-form__paypal__card form');
            FORM.$paymentSubmitButton = angular.element('#booking-steps--payment-details .booking-form__payment__process');
            FORM.$paymentHostedFields = FORM.$payment.find('.braintree__hosted-field');
            FORM.$cardNumberField = angular.element('#payment-gateway--card-number');
            FORM.$cardIcon = $('<div/>', { id: 'payment-gateway--card-icon' });
            FORM.$termsAndConditionsControl = angular.element('.booking-form__payment__tnc');
            FORM.$paypalTermsAndConditionsControl = angular.element('.booking-form__paypal__tnc');
            FORM.isHostedFieldsValid = false;
            FORM.hostedFieldInstance = {}
            FORM.hostedFields = {
                number: {
                    selector: '#payment-gateway--card-number'
                },
                cvv: {
                    selector: '#payment-gateway--card-security',
                    placeholder: 'CVV'
                },
                expirationDate: {
                    selector: '#payment-gateway--card-expiry',
                    placeholder: 'MM/YY'
                }
            }
            FORM.hostedFieldsStyles = {
                'input': {
                    'font-size': '16px',
                    'font-family': 'helvetica, tahoma, calibri, sans-serif',
                    'color': '#04183b',
                    'font-weight': 'bold'
                },
                ':focus': {
                    'color': 'black'
                },
                '::-ms-clear': {
                    'display': 'none',
                    'width': '0',
                    'height': '0',
                    'opacity': '0'
                },
                '.invalid': {
                    'color': '#db301a'
                },
            }

            FORM.resetSurcharges = function () {
                FORM.$cardIcon.removeClass();
                ctrl.payment.selectedCardBrand = '';
                ctrl.payment.selectedCardBrandKey = '';
                ctrl.payment.selectedCardType = '';
                ctrl.booking.selectedSurchargePct = '';
                ctrl.booking.totalAmountInclusive = ctrl.booking.totalAmount;
            }

            FORM.getSurchargesDetails = function () {
                var surchargeDetail;
                var surchargeDetails = ctrl.booking.surchargeDetails;
                var surchargeKey = ctrl.payment.selectedMethod === 'paypal' ? ctrl.payment.selectedMethod : ctrl.payment.selectedCardType;
                var surchargeType = ctrl.payment.selectedMethod === 'paypal' ? 'creditSurcharge' : ctrl.payment.selectedMethod + 'Surcharge';

                var surchargeDetailSearchResult = $filter('filter')(surchargeDetails, { cardKey: surchargeKey }, true);

                if (!surchargeDetailSearchResult.length) {
                    return false;
                }

                surchargeDetail = surchargeDetailSearchResult[0];

                return {
                    surchargeAmount: priceService.calculateSurcharge(ctrl.booking.totalAmount, surchargeDetail[surchargeType]),
                    selectedSurchargePct: surchargeDetail[surchargeType],
                    cardBrand: surchargeDetail.cardBrand,
                    cardKey: surchargeDetail.cardKey
                }
            }

            FORM.setSurcharges = function () {
                $timeout(function () {
                    var details = FORM.getSurchargesDetails();

                    if (!details) {
                        return FORM.resetSurcharges();
                    }

                    FORM.$cardIcon[0].className = ctrl.payment.selectedCardType;
                    ctrl.payment.selectedCardBrand = details.cardBrand;
                    ctrl.payment.selectedCardBrandKey = details.cardKey;
                    ctrl.booking.surchargeAmount = details.surchargeAmount;
                    ctrl.booking.totalAmountInclusive = ctrl.booking.totalAmount + details.surchargeAmount;
                    ctrl.booking.selectedSurchargePct = details.selectedSurchargePct;
                    scope.$apply();
                });
            }

            FORM.validateHostedFields = function (event, forceValid) {
                if (!event.fields) return;

                for (var property in event.fields) {
                    var hostedField = FORM.hostedFields[property];
                    if (!hostedField) return;

                    var $field = $(hostedField.selector);
                    if (!$field.length) continue;
                    // If a field is dirty (has blurred or attempted submission) and it is empty or invalid, show an error message
                    // If it is focussed and has invalid input that may potenitally be valid, show no message
                    // if it is valid, show a success box.
                    if (event.fields[property].isEmpty) {
                        $field.setValidity($field.data('empty-message'));
                    }
                    // Disallow a valid / potenitally valid number for a non-supported card
                    else if (property === "number" &&
                        !ctrl.payment.selectedCardBrand &&
                        event.cards.length === 1 &&
                        (event.fields[property].isValid || event.fields[property].isPotentiallyValid)) {
                        $field.attr('dirty', 'true');
                        $field.setValidity($field.data('error-message'));
                    }
                    else if (!event.fields[property].isValid &&
                        event.fields[property].isPotentiallyValid &&
                        property === event.emittedBy &&
                        !forceValid) {
                        $field.resetValidity();
                    }
                    else if (!event.fields[property].isValid) {
                        $field.attr('dirty', 'true');
                        $field.setValidity($field.data('error-message'));
                    }
                    else {
                        $field.attr('dirty', 'true');
                        $field.setValidity('');
                    }
                }
            }

            FORM.tokenizeHostedFields = function (callback) {
                if (!FORM.hostedFieldsInstance) return;

                FORM.hostedFieldsInstance.tokenize(function (err, payload) {
                    // Resets field validity
                    FORM.$paymentHostedFields.each(function () {
                        $(this).setValidity('');
                    });

                    var isValidCardType = ctrl.payment.selectedCardType.length > 0;

                    if (err || !isValidCardType) {
                        if (err) {
                            switch (err.code) {
                                case 'HOSTED_FIELDS_FIELDS_EMPTY':
                                    FORM.$paymentHostedFields.attr('dirty', 'true');
                                    FORM.$paymentHostedFields.each(function () {
                                        $(this).setValidity($(this).data('empty-message'));
                                    });
                                    break;
                                case 'HOSTED_FIELDS_FIELDS_INVALID':
                                    if (err.details && err.details.invalidFieldKeys && err.details.invalidFieldKeys.length) {
                                        for (var i = 0; i < err.details.invalidFieldKeys.length; i++) {
                                            var hostedField = FORM.hostedFields[err.details.invalidFieldKeys[i]];
                                            if (hostedField) {
                                                var $field = $(hostedField.selector);
                                                $field.attr('dirty', 'true');
                                                $field.setValidity($field.data('error-message'));
                                            }
                                        }
                                    }
                                    break;
                                default:
                                    console.error('Unknown payment error', err);
                            }

                        }
                        if (!isValidCardType) {
                            var hostedField = FORM.hostedFields['number'];
                            if (hostedField) {
                                var $field = $(hostedField.selector);
                                $field.attr('dirty', 'true');
                                $field.setValidity($field.data('error-message'));
                            }
                        }

                        FORM.$paymentSubmitButton.removeClass(FORM.btnLoadingClass);
                        FORM.isHostedFieldsValid = false;
                    }
                    else {
                        ctrl.payment.nonce = payload.nonce;
                        FORM.isHostedFieldsValid = true;
                    }

                    if (typeof callback === 'function') {
                        callback();
                    }
                });
            }

            FORM.setupPaymentGateway = function () {
                // Braintree hosted fields: https://developers.braintreepayments.com/guides/hosted-fields/examples/javascript/v3
                var token = ctrl.booking.token;

                if (token) {
                    FORM.$cardNumberField.append(FORM.$cardIcon);

                    braintree.client.create({
                        authorization: token
                    }, function (err, clientInstance) {
                        if (err) {
                            console.error(err);
                            return;
                        }
                        braintree.hostedFields.create({
                            client: clientInstance,
                            styles: FORM.hostedFieldsStyles,
                            fields: FORM.hostedFields
                        }, function (err, hostedFieldsInstance) {
                            FORM.hostedFieldsInstance = hostedFieldsInstance;

                            if (err) {
                                console.error(err);
                                return;
                            }

                            FORM.hostedFieldsInstance.on('validityChange', function (event) {
                                FORM.validateHostedFields(event);
                            });

                            FORM.hostedFieldsInstance.on('empty', function (event) {
                                FORM.validateHostedFields(event);
                            });

                            FORM.hostedFieldsInstance.on('notEmpty', function (event) {
                                FORM.validateHostedFields(event);
                            });

                            FORM.hostedFieldsInstance.on('blur', function (event) {
                                FORM.validateHostedFields(event, true);
                            });

                            FORM.hostedFieldsInstance.on('cardTypeChange', function (event) {
                                ctrl.payment.selectedCardType = event.cards.length === 1 ? event.cards[0].type : '';
                                FORM.setSurcharges();
                                FORM.validateHostedFields(event);
                            });
                        });

                        // Create a PayPal Checkout component.
                        // http://braintree.github.io/braintree-web/current/PayPalCheckout.html
                        // https://developers.braintreepayments.com/guides/paypal/checkout-with-paypal/javascript/v3
                        braintree.paypalCheckout.create({
                            client: clientInstance
                        }, function (paypalCheckoutErr, paypalCheckoutInstance) {
                            // Stop if there was a problem creating PayPal Checkout.
                            // This could happen if there was a network error or if it's incorrectly
                            // configured.
                            if (paypalCheckoutErr) {
                                console.error('Error creating PayPal Checkout:', paypalCheckoutErr);
                                return;
                            }

                            var environment = configurationConstant.environment === 'live' ? 'production' : 'sandbox';

                            paypal.Button.render({
                                env: environment,
                                commit: true,

                                style: {
                                    label: 'pay',       // checkout | credit | pay
                                    size: 'responsive', // small | medium | responsive
                                    shape: 'rect',      // pill | rect
                                    color: 'gold'       // gold | blue | silver
                                },

                                payment: function () {
                                    var amount = ctrl.booking.totalAmount;

                                    return paypalCheckoutInstance.createPayment({
                                        flow: 'checkout',   // Required
                                        amount: amount,     // Required
                                        currency: ctrl.booking.currencyCode // Required
                                        // For available options, see
                                        // http://braintree.github.io/braintree-web/current/PayPalCheckout.html#createPayment
                                    });
                                },

                                onAuthorize: function (data, actions) {
                                    ctrl.payment.isProcessing = true;
                                    scope.$apply();

                                    return paypalCheckoutInstance.tokenizePayment(data)
                                        .then(function (payload) {
                                            ctrl.payment.nonce = payload.nonce;
                                            ctrl.payment.selectedCardBrand = 'Paypal';
                                            ctrl.payment.selectedCardBrandKey = 'paypal';
                                            ctrl.payment.cardName = payload.details.firstName + ' ' + payload.details.lastName;

                                            FORM.makePayment();
                                        });
                                },

                                onCancel: function (data) {
                                    ctrl.payment.isProcessing = false;
                                    scope.$apply();
                                },

                                onError: function (err) {
                                    ctrl.payment.isError = true;
                                    ctrl.payment.isProcessing = false;
                                    scope.$apply();
                                }
                            }, '#paypal-button').then(function () {
                                // The PayPal button will be rendered in an html element with the id
                                // `paypal-button`. This function will be called when the PayPal button
                                // is set up and ready to be used.
                            });
                        });
                    });
                }
            }

            FORM.getDefaultCountry = function (callback) {
                locationService.GetLocation().then(function (data) {
                    ctrl.forms.passengerOne.country = data.data[0] || '';

                    $timeout(function () {
                        callback();
                    });
                });
            }

            FORM.updateScope = function (scopeTarget, value) {
                var target = scopeTarget.split('.');
                ctrl[target[1]][target[2]][target[3]] = value;
            }

            FORM.initUnbindedInputs = function () {
                FORM.unbindedInputs.map(function (obj) {
                    FORM.$details.trigger('form.masterfield.change', obj.parentSelector);
                });
            }

            FORM.doBookingModelMapping = function () {
                if (ctrl.booking.noOfPassengers >= 1) {
                    ctrl.booking.passengers[0].title = ctrl.forms.passengerOne.title;
                    ctrl.booking.passengers[0].firstName = ctrl.forms.passengerOne.firstName;
                    ctrl.booking.passengers[0].lastName = ctrl.forms.passengerOne.lastName;
                    ctrl.booking.passengers[0].dateOfBirth = ctrl.forms.passengerOne.dateOfBirth;
                    ctrl.booking.passengers[0].email = ctrl.forms.passengerOne.email;
                    ctrl.booking.passengers[0].phoneNumber = ctrl.forms.passengerOne.phoneNumber;
                    ctrl.booking.passengers[0].country = ctrl.forms.passengerOne.country;
                    ctrl.booking.passengers[0].address = ctrl.forms.passengerOne.address;
                    ctrl.booking.passengers[0].suburb = ctrl.forms.passengerOne.suburb;
                    ctrl.booking.passengers[0].state = ctrl.forms.passengerOne.state;
                    ctrl.booking.passengers[0].postCode = ctrl.forms.passengerOne.postCode;
                    ctrl.booking.passengers[0].howDidYouKnow = ctrl.forms.passengerOne.howDidYouKnow;
                    ctrl.booking.passengers[0].howDidYouKnowDetail = ctrl.forms.passengerOne.howDidYouKnowDetail;
                    if (ctrl.forms.passengerOne.optional != null) {
                        ctrl.booking.passengers[0].specialRequests = ctrl.forms.passengerOne.optional.specialRequests;
                    }
                }
                if (ctrl.booking.noOfPassengers >= 2) {
                    ctrl.booking.passengers[1].title = ctrl.forms.passengerTwo.title;
                    ctrl.booking.passengers[1].firstName = ctrl.forms.passengerTwo.firstName;
                    ctrl.booking.passengers[1].lastName = ctrl.forms.passengerTwo.lastName;
                    ctrl.booking.passengers[1].dateOfBirth = ctrl.forms.passengerTwo.dateOfBirth;
                    ctrl.booking.passengers[1].email = ctrl.forms.passengerTwo.email;
                    if (ctrl.forms.passengerTwo.optional != null) {
                        ctrl.booking.passengers[1].phoneNumber = ctrl.forms.passengerTwo.optional.phoneNumber;
                        ctrl.booking.passengers[1].specialRequests = ctrl.forms.passengerTwo.optional.specialRequests;
                    }
                }
                if (ctrl.booking.noOfPassengers >= 3) {
                    ctrl.booking.passengers[2].title = ctrl.forms.passengerThree.title;
                    ctrl.booking.passengers[2].firstName = ctrl.forms.passengerThree.firstName;
                    ctrl.booking.passengers[2].lastName = ctrl.forms.passengerThree.lastName;
                    ctrl.booking.passengers[2].dateOfBirth = ctrl.forms.passengerThree.dateOfBirth;
                    ctrl.booking.passengers[2].email = ctrl.forms.passengerThree.email;
                    if (ctrl.forms.passengerThree.optional != null) {
                        ctrl.booking.passengers[2].phoneNumber = ctrl.forms.passengerThree.optional.phoneNumber;
                        ctrl.booking.passengers[2].specialRequests = ctrl.forms.passengerThree.optional.specialRequests;
                    }
                }
                if (ctrl.booking.noOfPassengers >= 4) {
                    ctrl.booking.passengers[3].title = ctrl.forms.passengerFour.title;
                    ctrl.booking.passengers[3].firstName = ctrl.forms.passengerFour.firstName;
                    ctrl.booking.passengers[3].lastName = ctrl.forms.passengerFour.lastName;
                    ctrl.booking.passengers[3].dateOfBirth = ctrl.forms.passengerFour.dateOfBirth;
                    ctrl.booking.passengers[3].email = ctrl.forms.passengerFour.email;
                    if (ctrl.forms.passengerFour.optional != null) {
                        ctrl.booking.passengers[3].phoneNumber = ctrl.forms.passengerFour.optional.phoneNumber;
                        ctrl.booking.passengers[3].specialRequests = ctrl.forms.passengerFour.optional.specialRequests;
                    }
                }
                if (ctrl.booking.noOfPassengers >= 5) {
                    ctrl.booking.passengers[4].title = ctrl.forms.passengerFive.title;
                    ctrl.booking.passengers[4].firstName = ctrl.forms.passengerFive.firstName;
                    ctrl.booking.passengers[4].lastName = ctrl.forms.passengerFive.lastName;
                    ctrl.booking.passengers[4].dateOfBirth = ctrl.forms.passengerFive.dateOfBirth;
                    ctrl.booking.passengers[4].email = ctrl.forms.passengerFive.email;
                    if (ctrl.forms.passengerFive.optional != null) {
                        ctrl.booking.passengers[4].phoneNumber = ctrl.forms.passengerFive.optional.phoneNumber;
                        ctrl.booking.passengers[4].specialRequests = ctrl.forms.passengerFive.optional.specialRequests;
                    }
                }
                if (ctrl.booking.noOfPassengers >= 6) {
                    ctrl.booking.passengers[5].title = ctrl.forms.passengerSix.title;
                    ctrl.booking.passengers[5].firstName = ctrl.forms.passengerSix.firstName;
                    ctrl.booking.passengers[5].lastName = ctrl.forms.passengerSix.lastName;
                    ctrl.booking.passengers[5].dateOfBirth = ctrl.forms.passengerSix.dateOfBirth;
                    ctrl.booking.passengers[5].email = ctrl.forms.passengerSix.email;
                    if (ctrl.forms.passengerSix.optional != null) {
                        ctrl.booking.passengers[5].phoneNumber = ctrl.forms.passengerSix.optional.phoneNumber;
                        ctrl.booking.passengers[5].specialRequests = ctrl.forms.passengerSix.optional.specialRequests;
                    }
                }
                if (ctrl.booking.noOfPassengers >= 7) {
                    ctrl.booking.passengers[6].title = ctrl.forms.passengerSeven.title;
                    ctrl.booking.passengers[6].firstName = ctrl.forms.passengerSeven.firstName;
                    ctrl.booking.passengers[6].lastName = ctrl.forms.passengerSeven.lastName;
                    ctrl.booking.passengers[6].dateOfBirth = ctrl.forms.passengerSeven.dateOfBirth;
                    ctrl.booking.passengers[6].email = ctrl.forms.passengerSeven.email;
                    if (ctrl.forms.passengerSeven.optional != null) {
                        ctrl.booking.passengers[6].phoneNumber = ctrl.forms.passengerSeven.optional.phoneNumber;
                        ctrl.booking.passengers[6].specialRequests = ctrl.forms.passengerSeven.optional.specialRequests;
                    }
                }
                if (ctrl.booking.noOfPassengers >= 8) {
                    ctrl.booking.passengers[7].title = ctrl.forms.passengerEight.title;
                    ctrl.booking.passengers[7].firstName = ctrl.forms.passengerEight.firstName;
                    ctrl.booking.passengers[7].lastName = ctrl.forms.passengerEight.lastName;
                    ctrl.booking.passengers[7].dateOfBirth = ctrl.forms.passengerEight.dateOfBirth;
                    ctrl.booking.passengers[7].email = ctrl.forms.passengerEight.email;
                    if (ctrl.forms.passengerEight.optional != null) {
                        ctrl.booking.passengers[7].phoneNumber = ctrl.forms.passengerEight.optional.phoneNumber;
                        ctrl.booking.passengers[7].specialRequests = ctrl.forms.passengerEight.optional.specialRequests;
                    }
                }
            }

            FORM.registerUnbindedInputs = function () {
                FORM.$detailsDependentFields.each(function (i, group) {
                    var input = $(group).find('input, select')[0];
                    var parentGroup = $('[data-field-configuration-sitecore-id=' + group.dataset.parentSitecoreId + ']')[0];

                    FORM.unbindedInputs.push({
                        id: group.dataset.fieldSitecoreId,
                        model: input.dataset.ngModel,
                        parentSelector: '.' + parentGroup.className.replace(/ /g, '.')
                    });
                });
            }

            FORM.collectUnbindedInputs = function () {
                FORM.unbindedInputs.map(function (obj) {
                    var $input = $('[name^=' + obj.id.replace(/-/g, '') + ']');
                    var value = $input.length ? $input[0].value : undefined;
                    if (obj && obj.model) {
                        FORM.updateScope(obj.model, value);
                    }
                });
            }

            FORM.makePayment = function () {
                FORM.$payment.find('input:focus').blur();
                ctrl.payment.isProcessing = true;
                FORM.doBookingModelMapping();

                var requestObj = new Object();
                requestObj.noOfPassengers = ctrl.booking.noOfPassengers;
                requestObj.selectedTourPrice = ctrl.booking.selectedTourPrice;
                requestObj.selectedMethod = ctrl.payment.selectedMethod;
                requestObj.selectedAmount = ctrl.booking.totalAmount;
                requestObj.surchargeAmount = ctrl.booking.surchargeAmount;
                requestObj.totalAmountInclusive = ctrl.booking.totalAmountInclusive;
                requestObj.selectedCardBrandKey = ctrl.payment.selectedCardBrandKey;
                requestObj.selectedSurchargePct = ctrl.booking.selectedSurchargePct;
                requestObj.passengers = ctrl.booking.passengers;
                requestObj.nonce = ctrl.payment.nonce;
                requestObj.currencyCode = ctrl.booking.currencyCode;
                requestObj.tripCode = ctrl.booking.tripCode;
                requestObj.tourStartDate = ctrl.booking.tourStartDate;
                requestObj.tourEndDate = ctrl.booking.tourEndDate;

                finalizeBookingService.FinalizeBooking(requestObj)
                    .then(function (data) {
                        if (data && data.length > 0) {
                            ctrl.payment.success = true;
                            ctrl.payment.bookingReference = data[0].bookingConfirmationId;

                            var dataLayerModel = dataLayerService.buildBookingModel(
                                ctrl.booking.selectedTourPrice.price,
                                ctrl.booking.tripCode,
                                angular.element('h5.trip-priceandbooking__book__summary__trip-name')[0].innerText + " " +
                                    angular.element('h4.trip-priceandbooking__book__summary__package-title')[0].innerText,
                                data[0].bookingConfirmationId,
                                ctrl.booking.totalAmountInclusive - ctrl.booking.surchargeAmount,
                                ctrl.payment.selectedMethod,
                                ctrl.booking.noOfPassengers
                            );

                            dataLayerService.pushTransaction(dataLayerModel);

                            ctrl.carousel.next();
                            ctrl.payment.isProcessing = false;
                        }
                        else {
                            ctrl.payment.isError = true;
                            ctrl.payment.isProcessing = false;
                        }
                    }, function error(error) {
                        console.log("There was an error in retrieving booking. Error: " + error.statusText);
                        return false;
                    });
            }

            FORM.assignHasOptional = function (passenger) {
                var hasOptional = false;

                if (typeof passenger.optional === 'object') {
                    Object.keys(passenger.optional).forEach(function (key) {
                        if (passenger.optional[key] !== '') {
                            hasOptional = true;
                        }
                    });
                }

                passenger.hasOptional = hasOptional;
            }

            FORM.checkOptionalData = function () {
                Object.keys(ctrl.forms).forEach(function (key) {
                    FORM.assignHasOptional(ctrl.forms[key])
                });
            }

            FORM.init = function () {
                FORM.registerUnbindedInputs();
                FORM.getDefaultCountry(FORM.initUnbindedInputs);
                FORM.setupPaymentGateway();

                FORM.$details.on('form.validation.fail', function () {
                    var position = FORM.$details.find('.has-error').first().offset().top - 50
                    HELPERS.scrollTo(position);
                });

                FORM.$details.on('form.submit.success', function () {
                    FORM.collectUnbindedInputs();
                    FORM.checkOptionalData();
                    ctrl.carousel.next();
                });

                FORM.$payment.on('form.submit.success', function () {
                    if (FORM.isHostedFieldsValid) {
                        FORM.makePayment();
                    }
                });

                FORM.$payment.on('form.validation.fail', function () {
                    FORM.$paymentSubmitButton.removeClass(FORM.btnLoadingClass);
                    var position = FORM.$payment.find('.has-error').first().offset().top - 50
                    HELPERS.scrollTo(position);
                });

                if (!ctrl.payment.hasTermsAndConditions) {
                    FORM.$termsAndConditionsControl.remove();
                }

                scope.$on('broadcast.tripBookingAndPaymentController.submitPaymentForm', function () {
                    var submitButton = FORM.$payment.find('input[type=submit], button[type=submit]');
                    FORM.$paymentSubmitButton.addClass(FORM.btnLoadingClass);

                    FORM.tokenizeHostedFields(function () {
                        if (submitButton.length) {
                            submitButton.click();
                        }
                    });
                });

                scope.$watch("tbapc.payment.selectedMethod", function () {
                    FORM.setSurcharges();
                    scope.tbapc.payment.isError = false;
                });
            }

            CAROUSEL.$carousel = angular.element('.booking-carousel__inner');

            CAROUSEL.prev = function () {
                $timeout(function () {
                    CAROUSEL.$carousel.find('input:focus').blur();
                    CAROUSEL.$carousel.trigger('prev.owl.carousel');
                });
            }

            CAROUSEL.next = function () {
                $timeout(function () {
                    CAROUSEL.$carousel.find('input:focus').blur();
                    CAROUSEL.$carousel.trigger('next.owl.carousel');
                });
            }

            CAROUSEL.init = function (onInitialized) {
                if (typeof (onInitialized === "function")) {
                    CAROUSEL.$carousel.on('initialized.owl.carousel', function () {
                        onInitialized();
                    });
                }

                CAROUSEL.$carousel.owlCarousel({
                    loop: false,
                    items: 1,
                    mouseDrag: false,
                    touchDrag: false,
                    pullDrag: false,
                    freeDrag: false,
                    margin: 100,
                    smartSpeed: 500,
                    customAutoHeight: true
                });

                CAROUSEL.$carousel.on('translate.owl.carousel', function () {
                    HELPERS.scrollTo(CAROUSEL.$carousel.offset().top);
                });

                CAROUSEL.$carousel.on('translated.owl.carousel', function () {
                    CAROUSEL.$carousel.trigger('refresh.owl.carousel');
                });

                scope.$on('broadcast.tripBookingAndPaymentController.prev', CAROUSEL.prev);

                scope.$on('broadcast.tripBookingAndPaymentController.next', CAROUSEL.next);
            }
            $timeout(function () {
                CAROUSEL.init(FORM.init);
            });
        }
        return directive;
    }

    tripBookingAndPaymentController.$inject = ['$scope'];

    function tripBookingAndPaymentController($scope) {
        var tbapc = this;
        tbapc.forms = {
            passengerOne: {}
        },
            tbapc.carousel = {
                currentIndex: 1,
                prev: prev,
                next: next
            },
            tbapc.booking = {
                noOfPassengers: 1,
                selectedTourPrice: {},
                surchargeDetails: {},
                token: '',
                totalAmount: 0,
                currencyCode: 'AUD',
                surchargeAmount: 0,
                totalAmountInclusive: 0,
                selectedSurchargePct: 0,
                passengers: {},
                tripCode: '',
                tourStartDate: '',
                tourEndDate: '',
                extendWith: extendWith
            },
            tbapc.payment = {
                success: false,
                cardName: '',
                nonce: '',
                selectedMethod: 'Credit',
                hasTermsAndConditions: false,
                selectedAmount: undefined,
                selectedCardType: '',
                selectedCardBrand: '',
                selectedCardBrandKey: '',
                selectedSurchargePct: '',
                submit: submitPaymentForm,
                isError: false,
                isProcessing: false,
                bookingReference: ''
            }

        function prev() {
            tbapc.carousel.currentIndex--;
            $scope.$broadcast('broadcast.tripBookingAndPaymentController.prev');
        }

        function next() {
            tbapc.carousel.currentIndex++;
            $scope.$broadcast('broadcast.tripBookingAndPaymentController.next');
        }

        function extendWith(obj) {
            tbapc.booking.noOfPassengers = obj.noOfPassengers;
            tbapc.booking.selectedTourPrice = obj.selectedTourPrice;
            tbapc.booking.surchargeDetails = obj.surchargeDetails;
            tbapc.booking.token = obj.token;
            tbapc.booking.totalAmount = obj.totalAmount;
            tbapc.booking.totalAmountInclusive = obj.totalAmount;
            tbapc.booking.currencyCode = obj.currencyCode;
            tbapc.booking.tripCode = obj.tripCode;
            tbapc.booking.tourStartDate = obj.tourStartDate;
            tbapc.booking.tourEndDate = obj.tourEndDate;
            tbapc.booking.passengers = obj.passengers;
            tbapc.payment.hasTermsAndConditions = obj.hasTermsAndConditions;
        }

        function submitPaymentForm() {
            $scope.$broadcast('broadcast.tripBookingAndPaymentController.submitPaymentForm');
        }
    }
})();;
(function () {
    "use strict";

    angular
        .module('AF.directives')
        .directive('tripPriceAndAvailability', ['$timeout','tripPriceAndAvailabilityService', tripPriceAndAvailability]);

    function tripPriceAndAvailability($timeout, tripPriceAndAvailabilityService) {
        var directive = {
            restrict: 'A',
            scope: true,
            controller: tripPriceAndAvailabilityController,
            controllerAs: 'tpac',
            bindToController: true,
            link: link
        };
        function link(scope, element, attr, ctrl) {

            scope.$on('broadcast.tripPriceAndAvailabilityController.selectTourPrice', function () {
                setPrice();
            });

            scope.$on('broadcast.tripPriceAndAvailabilityController.setBooking', function () {
                setBooking();
            });

            var setPrice = function () {
                ctrl.previousPrice = ctrl.price;

                if (ctrl.tourPrice != null) {
                    ctrl.price = ctrl.tourPrice.price;
                }
            }

            var setBooking = function () {
                var requestObj = new Object();
                requestObj.noOfPassengers = ctrl.selectedNoOfPassenger;
                requestObj.selectedTourPrice = ctrl.tourPrice;
                requestObj.trip = ctrl.trip;
                ctrl.isLoading = true;

                tripPriceAndAvailabilityService.SetBooking(requestObj)
                    .then(function (data) {
                        if (data && data.length > 0) {
                            window.location = ctrl.bookingPageUrl;
                        }
                    });
            }

        }
        return directive;
    }

    tripPriceAndAvailabilityController.$inject = ['$scope','utilityService'];

    function tripPriceAndAvailabilityController($scope, utilityService) {
        var tpac = this;
        tpac.setTrip = setTrip;
        tpac.tourPrice = {};
        tpac.price = 0;
        tpac.previousPrice = 0;
        tpac.selectTourPrice = selectTourPrice;
        tpac.calculatePrice = calculatePrice;
        tpac.passengers = [1, 2, 3, 4, 5, 6, 7, 8];
        tpac.selectedNoOfPassenger = tpac.passengers[0];
        tpac.changePassenger = changePassenger;
        tpac.bookingPageUrl = '#';
        tpac.setBooking = setBooking;

        tpac.trip = {
            tripCode: '',
            tourDate: '',
            departingFrom: '',
            departing: '',
            checkin: '',
            returning: '',
            tripUrl:'',
            tourPrices: []
        }

        function setTrip(trip) {
            var tripObject = JSON.parse(trip);
            tpac.trip.tripCode = tripObject.tripCode;
            tpac.trip.tourPrices = tripObject.tourPrices;
            tpac.trip.tourDate = tripObject.tourDate;
            tpac.trip.departingFrom = tripObject.departingFrom;
            tpac.trip.departing = tripObject.departing;
            tpac.trip.checkin = tripObject.checkin;
            tpac.trip.returning = tripObject.returning;
            tpac.trip.tripUrl = tripObject.tripUrl;
            tpac.trip.tourStartDate = tripObject.tourStartDate;
            tpac.trip.tourEndDate = tripObject.tourEndDate;
            if (tripObject.tourPrices != null && tripObject.tourPrices.length > 0) {
                initializeTourPrice(tripObject.tourPrices);
            }

        }

        function initializeTourPrice(tourPrices) {
            var np = utilityService.GetQueryStringParameters('np');
            var tp = utilityService.GetQueryStringParameters('tp');
            if (np && tp) {
                tpac.selectedNoOfPassenger = tpac.passengers[np - 1];
                for (var i = 0, len = tourPrices.length; i < len; i++) {
                    if (tourPrices[i].priceType.title == tp) {
                        tpac.tourPrice = tourPrices[i];
                        tpac.price = tourPrices[i].price;
                        break;
                    }
                }
            }
            else {
                for (var i = 0, len = tourPrices.length; i < len; i++) {
                    if (tourPrices[i].price > 0 && tourPrices[i].availableSeats >= 0 && tourPrices[i].availableSeats >= tpac.selectedNoOfPassenger) {
                        tpac.tourPrice = tourPrices[i];
                        tpac.price = tourPrices[i].price;
                        break;
                    }
                }
            }

        }

        function selectTourPrice(tourPrice) {
            tpac.tourPrice = tourPrice;
            if (tourPrice.price > 0)
                $scope.$broadcast('broadcast.tripPriceAndAvailabilityController.selectTourPrice');
        }

        function calculatePrice(price) {
            var difference = tpac.price - price;
            if (difference < 0)
                difference = difference * -1;
            return difference;
        }

        function changePassenger() {
            if (tpac.tourPrice.availableSeats < tpac.selectedNoOfPassenger) {
                initializeTourPrice(tpac.trip.tourPrices);
            }
        }

        function setBooking(bookingPageUrl) {
            if (bookingPageUrl != '#') {
                tpac.bookingPageUrl = bookingPageUrl;
                $scope.$broadcast('broadcast.tripPriceAndAvailabilityController.setBooking');
            }
        }
    }

})();;
(function(){

    "use strict";

    angular.module('Phoenix.Shared.directives')
        .directive('accordionPanel', ['$timeout', '$window', function ($timeout, $window) {
            return {
                restrict: 'A',
                scope: true,
                link: function (scope, element, attrs) {

                    var $el = angular.element(element);
                    var $collapseLinks = $el.find('[data-toggle="collapse"]');
                    var isNavMenu = $el.closest('.nav-menu.nav-mobile').length > 0;

                    $collapseLinks.on('click', function (e) {
                        // Disable href
                        e.preventDefault();
                        // Disable scroll
                        if (attrs.accordionPanelScroll === 'disabled' || attrs.accordionPanelScroll === 'false') return;

                        var link = this;
                        var timeout = 350;

                        $timeout(function () {    
                            // Default
                            var scrollContainer = $('html,body');
                            var scrollTop = $(link).offset().top;
                            var scrollSpeed = 300;

                            // Nav menu
                            if (isNavMenu) {
                                scrollContainer = $('.nav-menu.nav-mobile');
                                scrollTop = $(link).offset().top - scrollContainer.offset().top + scrollContainer.scrollTop();
                            }
                            // Avoid conflicts with Nav Menu
                            else if (attrs.accordionPanelScroll) {
                                // Parse lists of classes or ID's into data-accordion-panel-scroll
                                // eg. <div data-accordion-panel-scroll=".my-parent-container"></div>
                                // eg. <div data-accordion-panel-scroll="disabled"></div>
                                scrollContainer = $(attrs.accordionPanelScroll);
                            }

                            // Perform scroll
                            scrollContainer.animate({
                                scrollTop: scrollTop
                            }, scrollSpeed);
                        
                        }, timeout);
                    });
                }
            };
        }]);

})();
;
(function () {

    'use strict';

    angular.module('Phoenix.Shared.directives')
        .directive('affix', ['$window', function ($window) {
            return function (scope, element, attrs) {
                // Helper functions
                function offset(el) {
                    var rect = el.getBoundingClientRect(),
                        scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
                        scrollTop = window.pageYOffset || document.documentElement.scrollTop;
                    return { top: rect.top + scrollTop, left: rect.left + scrollLeft }
                }

                /*
                 * Data
                 */
                var _window = angular.element($window);                
                var el = angular.element(element);
                var $el = $(el);
                var $body = $('body');
                var $header = $('.site-hero');
                var $offsetContainer = $(attrs.affixOffsetContainer);
                var bottom = calcOffsetBottom();
                var top = calcOffsetTop();
                
                /*
                 * Methods
                 */
                function addTopHeight() {
                    $el.css('top', $header.innerHeight() - (el.innerWidth() / 2));
                }
                function calcOffsetBottom() {
                    return $body.innerHeight() - $offsetContainer.innerHeight() - offset($offsetContainer[0]).top + $el.innerWidth() * 1.5;
                }
                function calcOffsetTop() {
                    return parseInt(attrs.affixOffsetTop) || 0;
                }

                // On Load
                addTopHeight();

                _window.on('resize', function () {
                    addTopHeight();
                    affixOffsetBottom();
                    // console.log('resize')
                });

                $el.affix({
                    offset: {
                        top: top,
                        bottom: bottom
                    }
                });

                // Event listener for BTS Affixed emitter
                $el.on('affixed.bs.affix', function () {
                    addTopHeight();
                });

                /*
                 * Detect bottom offset
                 * Mutation observer
                 */
                // Detect height change of the data-affix-offset-container being watched
                var config = { attributes: true, childList: true };
                var affixOffsetBottom = function () {
                    // When observer is called, recalculate top and bottom offsets
                    top = calcOffsetTop();
                    bottom = calcOffsetBottom();
                    // console.log('DEBOUNCE affixContainer change detected', top, bottom);

                    // Affix element
                    $el.data('bs.affix').options.offset.top = top;
                    $el.data('bs.affix').options.offset.bottom = bottom;
                    $el.affix('checkPosition');
                }
                // Set up observable on dom element
                var observer = new MutationObserver(affixOffsetBottom);
                observer.observe($offsetContainer[0], config);
                // observer.disconnect(); // Destroy observer method

   
            };
        }])
})();;
"use strict";

angular.module('Phoenix.Shared.directives')
    .directive('backToTop', ['$window', function ($window) {
        return function (scope, element, attrs) {

            var _window = angular.element($window);

            _window.on("scroll", function () {
                if (this.pageYOffset >= 100) {
                    scope.isVisible = true;
                } else {
                    scope.isVisible = false;
                }
                scope.$apply();
            });
        };
    }])
    .directive('scrollToTop', function () {
        return function (scope, element, attrs) {
            scope.gotoTop = function() {
                $("html, body").animate({ scrollTop: 0 }, "slow");
            };
        };
    });;
"use strict";

(function () {
    "use strict";

    angular
        .module('Phoenix.Shared.directives')
        .directive('brochurePage', ['$location', '$filter', '$rootScope', brochurePage])
        .directive('brochureFilters', ['$timeout', '$document', 'utilityService', brochureFilters])
        .directive('brochureListing', ['$timeout', brochureListing])
        .directive('brochureRequest', ['$timeout', '$document', '$rootScope', brochureRequest])
        .directive('brochureStickyTopBar', ['$timeout', '$window', brochureStickyTopBar])

    function brochurePage($location, $filter, $rootScope) {
        var directive = {
            restrict: 'A',
            scope: true,
            link: link,
            controller: brochureController,
            controllerAs: 'bc',
            bindToController: true
        };

        function link(scope, element, attr, ctrl) {
            if ($location.search().brochureId) {
                var brochureId = $location.search().brochureId;
                var brochure = $filter('filter')(scope.bc.brochures.model, { Id: brochureId });

                scope.$on('broadcast.multistepCarousel.initialized', function () {
                    scope.bc.brochures.model.forEach(function (b) {
                        if (b.Id === brochureId) {
                            b.selected = true;
                            $rootScope.$broadcast('broadcast.multistepCarouselControllers.goToIndex', { index: 1 });
                        }
                    });
                });
            }
        }
        return directive;
    }

    function brochureFilters($timeout, $document, utilityService) {
        var directive = {
            restrict: 'A',
            scope: true,
            link: link,
            require: '^brochurePage'
        };

        function link(scope, element, attr, ctrl) {
            // adapted from clickOutside common directive
            var onClick = function (event) {
                // is the element the search box or one of its children?
                var isChild = $(element).has(event.target).length > 0;
                var isSelf = element[0] === event.target;
                var isInside = isChild || isSelf;
                if (!isInside) {
                    // have to do this in scope.$apply() so that angular knows that we are changing things
                    // otherwise the view won't be updated (search filters hidden) until the next user interaction
                    scope.$apply(function () {
                        scope.bc.search.hideSearch();
                    });
                }
            };

            var setSelections = function () {
                scope.bc.search.filters.destinations = cleanSelectedOptions(utilityService.GetArrayFromCommaString(utilityService.GetQueryStringParameters('destination')), '.js-section-destination');
            };

            var cleanSelectedOptions = function (arr, key) {
                var cleanedArray = [];

                for (var i = 0; i < arr.length; i++) {
                    var $selectedKey = $(key + '  [data-key="' + arr[i] + '"]');

                    if ($selectedKey.length) { // we add the matching key to the array if it has been found
                        cleanedArray.push(arr[i]);
                    }
                }
                return cleanedArray;
            };

            // only turn on the event listener when the search box is actually open
            scope.$watch('bc.search.open', function (newValue, oldValue) {
                if (newValue !== oldValue && newValue === true) {
                    $document.bind('tap click', onClick);
                } else if (newValue !== oldValue && newValue === false) {
                    $document.unbind('tap click', onClick);
                }
            });

            scope.$on('broadcast.multistepCarouselControllers.indexChanged', function (e, args) {
                ctrl.search.hideFilters = args.index > 0;
            });

            scope.$on('broadcast.brochureController.tripFinderOverlay', function (e, isOpen) {
                var $htmlBody = angular.element('html body');
                var $siteOverlay = angular.element('.site-overlay-secondary');
                var $siteSearchHero = angular.element('.site-hero');

                if (isOpen) {
                    $siteOverlay.addClass('is-visible');
                    $siteSearchHero.addClass('z-stack-order-50');
                }
                else {
                    $siteOverlay.removeClass('is-visible');
                    $siteSearchHero.removeClass('z-stack-order-50');
                }
                $htmlBody.animate({
                    scrollTop: $('#brochure-filters').offset().top - 60
                }, 500);
            });

            $timeout(function () {
                setSelections();
            });
        }
        return directive;
    }

    function brochureListing($timeout) {
        var directive = {
            restrict: 'A',
            scope: true,
            link: link,
            require: '^brochurePage'
        };

        function link(scope, element, attr, ctrl) {
        }
        return directive;
    }

    brochureController.$inject = ['$scope', '$filter', '$analytics', '$timeout'];
    function brochureController($scope, $filter, $analytics, $timeout) {
        var timer;
        var bc = this;
        bc.brochures = {
            model: []
        };

        // Functions to determine whether the brochure is to be downloaded or mailed
        bc.downloadBrochure = downloadBrochure;
        bc.postBrochure = postBrochure;
        bc.setAllowBrochureMail = setAllowBrochureMail;
        bc.selectAllBrochures = selectAllBrochures;

        bc.displayWhichForm = "download";
        bc.displayPostBrochureForm = false;

        bc.search = {
            open: false,
            filters: {
                destinations: [],
                travelStyles: [],
                years: []
            },
            hideFilters: false,
            filterCount: 0,
            toggleOpen: toggleSearchOpen,
            hideSearch: hideSearch,
            toggleSelection: toggleSearchSelection,
            isOptionSelected: isSearchOptionSelected,
            isVisible: isVisible,
            clearSectionSelections: clearSectionSelections,
            clearSelections: clearSelections,
            getCheckboxAnalyticsLabel: getCheckboxAnalyticsLabel
        };

        bc.selection = {
            showSticky: showSticky,
            isSticky: false,
            maxSelectCount: 1,
            setMaxSelectCount: setMaxSelectCount,
            isSelectionMaxed: isSelectionMaxed,
            count: selectedBrochureCount,
            brochures: selectedBrochures,
            brochureIds: selectedBrochureIds,
            brochureTitles: selectedBrochureTitles,
            brochureUrls: selectedBrochureUrls,
            recentlyUpdated: false
        };

        bc.results = {
            count: 0
        };

        bc.setModel = setModel;

        $scope.$watch('bc.brochures.model', function () {
            if (timer) {
                $timeout.cancel(timer);
                bc.selection.recentlyUpdated = false;
            }

            $timeout(function () {
                bc.selection.recentlyUpdated = true;
            })
                .then(function () {
                    timer = $timeout(function () {
                        bc.selection.recentlyUpdated = false;
                    }, 1500);
                    return timer;
                });
        }, true);

        $scope.$watch('bc.search.filters.destinations', function () {
            setFilterCount();
        }, true);

        $scope.$watch('bc.search.filters.travelStyles', function () {
            setFilterCount();
        }, true);

        $scope.$watch('bc.search.filters.years', function () {
            setFilterCount();
        }, true);

        $scope.$on('broadcast.brochureController.searchFiltersUpdated', function () {
            filterBrochures();
        }, true);

        $scope.$on('broadcast.brochureRequestController.formSubmitSuccess', function () {
            formSubmitSuccess();
        }, true);

        function setFilterCount() {
            bc.search.filterCount =
                (bc.search.filters.destinations.length ||
                    bc.search.filters.travelStyles.length ||
                    bc.search.filters.years.length ? 1 : 0);
        }

        function toggleSearchOpen() {
            bc.search.open = !bc.search.open;
            $scope.$broadcast('broadcast.brochureController.tripFinderOverlay', bc.search.open);
        }

        function hideSearch() {
            bc.search.open = false;
            $scope.$broadcast('broadcast.brochureController.tripFinderOverlay', bc.search.open);
        }

        function setAllowBrochureMail(allowBrochureMail) {
            bc.displayPostBrochureForm = allowBrochureMail;
        }

        function toggleSearchSelection(id, arr, disableRedirect) {
            var exists = false;
            for (var i = 0; i < arr.length; i++) {
                if (arr[i] === id) {
                    exists = true;
                    arr.splice(i, 1);
                    break;
                }
            }
            if (!exists) {
                arr.push(id);
            }
            $scope.$broadcast('broadcast.brochureController.searchFiltersUpdated', { disableRedirect: disableRedirect });

            filterBrochures();
        }

        function filterBrochures() {
            bc.brochures.model.forEach(function (brochure) {
                brochure.isHidden = !isVisible(brochure.TagKey);
            });

            setResultCount();
        }

        function formSubmitSuccess() {
            bc.brochures.model.forEach(function (brochure) {
                // If posting, only allow downloading of brochures for selected brochures
                // If downloading, allow the user to download all brochures
                if ((brochure.selected && bc.displayWhichForm == "post") || bc.displayWhichForm == "download") {
                    brochure.canDownload = true;
                }
            });

            bc.submittedForm = true;
        }

        function downloadBrochure() {
            bc.displayWhichForm = "download";
            $scope.$emit('broadcast.multistepCarouselControllers.goToIndex', { index: 0 });

            selectAllBrochures(true);
        }

        function postBrochure() {
            bc.displayWhichForm = "post";
            $scope.$emit('broadcast.multistepCarouselControllers.goToIndex', { index: 1 });

            selectAllBrochures(false);
        }

        function selectAllBrochures(selectAll) {
            bc.brochures.model.forEach(function (brochure) {
                brochure.selected = selectAll;
            });
        }

        function isVisible(ids) {
            if (!bc.search.filters.destinations.length &&
                !bc.search.filters.travelStyles.length &&
                !bc.search.filters.years.length) {
                return true;
            }

            var idArray = String(ids).split('|');

            var destinationsResult,
                travelStylesResult,
                yearsResult = false;

            idArray.forEach(function (id) {
                if (!bc.search.filters.destinations.length || (bc.search.filters.destinations.indexOf(id) >= 0)) {
                    destinationsResult = true;
                }
                if (!bc.search.filters.travelStyles.length || (bc.search.filters.travelStyles.indexOf(id) >= 0)) {
                    travelStylesResult = true;
                }
                if (!bc.search.filters.years.length || (bc.search.filters.years.indexOf(id) >= 0)) {
                    yearsResult = true;
                }
            });

            return destinationsResult && travelStylesResult && yearsResult;
        }

        function setResultCount() {
            bc.results.count = $filter('filter')(bc.brochures.model, { isHidden: false }).length;
        }

        function selectedBrochureCount() {
            return bc.selection.brochures().length;
        }

        function showSticky() {
            return bc.selection.count() > 0;
        }

        function isSearchOptionSelected(id) {
            return bc.search.filters.destinations.indexOf(id) >= 0 ||
                bc.search.filters.travelStyles.indexOf(id) >= 0 ||
                bc.search.filters.years.indexOf(id) >= 0;
        }

        function clearSectionSelections(arr) {
            if (arr.length) {
                arr.splice(0, arr.length);
                $scope.$broadcast('broadcast.brochureController.searchFiltersUpdated');
            }
        }

        function clearSelections() {
            bc.search.filters.destinations = [];
            bc.search.filters.travelStyles = [];
            bc.search.filters.years = [];
            $scope.$broadcast('broadcast.brochureController.searchFiltersUpdated');
        }

        function setMaxSelectCount(count) {
            bc.selection.maxSelectCount = count;
        }

        function isSelectionMaxed() {
            return bc.selection.count() >= bc.selection.maxSelectCount;
        }

        function setModel(model) {
            bc.brochures.model = model;
            bc.brochures.filteredBrochures = model;
            filterBrochures();
        }

        function selectedBrochures() {
            return $filter('filter')(bc.brochures.model, { selected: true });
        }

        function selectedBrochureIds() {
            return selectedBrochures().map(function (brochure) { return brochure.Id; }).join('|');
        }

        function selectedBrochureTitles() {
            return selectedBrochures().map(function (brochure) { return brochure.Title; }).join('|');
        }

        function selectedBrochureUrls() {
            return selectedBrochures().map(function (brochure) { return brochure.EBrochure.Url; }).join('|');
        }

        function getCheckboxAnalyticsLabel(fieldKey, arr) {
            return (arr.indexOf(fieldKey) === -1 ? 'Deselect' : 'Select');
        }
    }

    function brochureRequest($timeout, $document, $rootScope) {
        var directive = {
            restrict: 'A',
            scope: true,
            link: link,
            controller: brochureRequestController,
            controllerAs: 'brc',
            bindToController: true
        };

        function link(scope, element, attr, ctrl) {
            var $el = angular.element(element);
            var form = $el.find('form');

            var brochureWrapper = document.getElementsByClassName('brochure-listing');
            var $brochureWrapperElement = angular.element(brochureWrapper);

            if (form.length) {
                form.on('form.submit.initialised', function () {
                    $timeout(function () {
                        ctrl.form.isSubmitButtonDisabled = true;
                    });
                });
                form.on('form.submit.success', function () {
                    scrollToBrochureWrapper();
                    ctrl.form.isSubmitButtonDisabled = false;
                    ctrl.form.isSubmitted = true;
                    scope.$apply();
                    $rootScope.$broadcast('broadcast.multistepCarouselControllers.goToIndex', { index: 2 });
                    $rootScope.$broadcast('broadcast.brochureRequestController.formSubmitSuccess');
                });
                form.on('form.submit.error', function () {
                    ctrl.form.isSubmitButtonDisabled = false;
                    scope.$apply();
                });
                form.on('form.submit.invalid', function () {
                    ctrl.form.isSubmitButtonDisabled = false;
                    scope.$apply();
                });

                scope.$on('broadcast.brochureRequestController.submitBrochureForm', function () {
                    var submitButton = form.find('input[type=submit], button[type=submit]');
                    if (submitButton.length) {
                        submitButton.click();
                    }
                });
            }

            var scrollToBrochureWrapper = function () {
                var $scrollToElement = $brochureWrapperElement.length !== 0 ? $brochureWrapperElement : $el;
                angular.element('html, body').stop().animate({
                    scrollTop: $scrollToElement.offset().top
                }, 0);
            }
        }
        return directive;
    }

    brochureRequestController.$inject = ['$scope'];
    function brochureRequestController($scope) {
        var brc = this;
        brc.form = {
            brochureId: '',
            brochureTitle: '',
            includeDvd: false,
            country: '',
            isSubmitButtonDisabled: false,
            isSubscribeNewsletter: false,
            isSubmitted: false,
        }

        brc.submitBrochureForm = submitBrochureForm;
        brc.init = init;

        function init(brochureId, brochureTitle) {
            brc.form.brochureId = brochureId;
            brc.form.brochureTitle = brochureTitle;
        }

        function submitBrochureForm() {
            $scope.$broadcast('broadcast.brochureRequestController.submitBrochureForm');
        }
    }

    function brochureStickyTopBar($timeout, $window) {
        var directive = {
            scope: true,
            restrict: 'AE',
            link: link,
            require: '^brochurePage'
        };

        return directive;

        function link(scope, element, attrs, ctrl) {
            var $el = angular.element(element).find('[data-brochure-sticky-top-bar-panel]');
            var isAnimating = false;
            var window = angular.element($window);
            var offsetTop;
            var offsetHeight;

            var setOffsets = function () {
                var offset = $el.offset();
                offsetTop = offset.top;
                offsetHeight = offset.height;
            }

            var setupMenu = function () {
                if (window.scrollTop() >= offsetTop) {
                    $el.addClass('sticky');
                }
                else {
                    $el.removeClass('sticky');
                }
            }

            $timeout(function () {
                setOffsets();
            });

            window.on('resize', function () {
                // iOS fires window.resize events randomly, which causes the offset to be different
                // As the interface isn't user scalable, we'll just ignore those events
                if (Modernizr.touchevents) {
                    return;
                }

                setOffsets();
                setupMenu();
            });

            window.on('scroll touchmove', setupMenu);
        }
    }
})();
;
(function () {
    'use strict';

    angular.module('Phoenix.Shared.directives')
        .directive('siteHeroCarousel', siteHeroCarousel)
        .directive('carousel', carousel)
        .directive('tripCardCarousel', tripCardCarousel)
        .directive('hereToHelpCarousel', hereToHelpCarousel)
        .directive('featurePanelCarousel', featurePanelCarousel)
        .directive('lifestyleCarousel', lifestyleCarousel)
        .directive('tourManagerCarousel', tourManagerCarousel)
        .directive('upliftTripCardCarousel', upliftTripCardCarousel);

    siteHeroCarousel.$inject = ['$window'];

    function siteHeroCarousel($window) {
        var directive = {
            restrict: 'A',
            scope: true,
            controller: siteHeroCarouselController,
            controllerAs: 'shcc',
            bindToController: true,
            link: link
        };

        return directive;

        function link(scope, element, attrs, ctrl) {
            var $el = angular.element(element);
            var $siteHeroCarousel = $el.find('.owl-carousel');
            var owlSlides = $siteHeroCarousel.children('div');
            var loop = owlSlides.length > 1;
            var autoplay = ctrl.enableAutoplay && owlSlides.length > 1;

            var options = {
                baseClass: 'owl-carousel',
                navContainerClass: 'owl-nav',
                items: 1,
                nav: true,
                navText: '',
                dots: true,
                animateIn: 'fadeIn',
                animateOut: 'fadeOut',
                autoplay: autoplay,
                autoplayTimeout: ctrl.transitionTime,
                loop: loop,
                lazyLoad: true,
                mouseDrag: false,
                onDragged: stopHeroAutoPlay,
            };

            $siteHeroCarousel.owlCarousel(options);
            
            function stopHeroAutoPlay(duration) {
                duration = duration || 500;

                setTimeout(function () {
                    $siteHeroCarousel.trigger('play.owl.autoplay', [1000]);
                    $siteHeroCarousel.trigger('stop.owl.autoplay');
                }, duration);
            }
            
            $('.owl-next, .owl-prev, .owl-dot').on('click', function () {
                stopHeroAutoPlay();
            });

            var $cameraTooltip = $el.find('.camera-tooltip');

            if (Modernizr.touchevents) {
                $cameraTooltip.bind('click', function () {
                    $cameraTooltip.toggleClass('is-active');
                });
            } else {
                $cameraTooltip.bind('mouseenter', function () {
                    $cameraTooltip.addClass('is-active');
                });
                $cameraTooltip.bind('mouseleave', function () {
                    $cameraTooltip.removeClass('is-active');
                });
            }

            $siteHeroCarousel.on('change.owl.carousel', function (e) {
                $cameraTooltip.removeClass('is-active');
            });
        }
    }

    siteHeroCarouselController.$inject = ['$scope'];

    function siteHeroCarouselController($scope) {
        var shcc = this;
        shcc.transitionTime = 5000;
        shcc.enableAutoplay = true;

        shcc.init = function (transitionTime, enableAutoplay) {
            shcc.transitionTime = transitionTime;

            if (!transitionTime) {
                shcc.transitionTime = 5000;
            }

            if (enableAutoplay === false) {
                shcc.enableAutoplay = false;
            }
        };
    }

    carousel.$inject = ['$window'];

    function carousel($window) {
        var directive = {
            restrict: 'A',
            link: link
        };

        return directive;

        function link(scope, element, attrs) {
            var $carousel = $(element);
            var carouselClasses = 'owl-carousel owl-carousel--has-nav grid-component__carousel';
            var media = window.matchMedia('(max-width: 800px)');
            var options = {
                items: 1,
                loop: true,
                nav: true,
                navText: false,
                dots: true,
                lazyLoad: true,
                lazyContent: true,
                autoHeight: true
            };

            function toggleCarousel(mediaQuery) {
                if (mediaQuery.matches) {
                    $carousel
                        .addClass(carouselClasses)
                        .owlCarousel(options);
                } else {
                    $carousel
                        .owlCarousel('destroy')
                        .removeClass(carouselClasses);
                }
            }

            function init() {
                toggleCarousel(media);
                media.addListener(toggleCarousel);
            }

            init();
        }
    }

    tripCardCarousel.$inject = ['$rootScope'];

    function tripCardCarousel($rootScope) {
        var directive = {
            restrict: 'A',
            scope: {
                stagePaddingXs: '=',
                itemsXs: '=',
                itemsSm: '=',
                itemsMd: '=',
                disableXs: '=',
                disableSm: '='
            },
            link: link
        };

        return directive;

        function link(scope, element, attrs, ctrl) {
            var media = window.matchMedia('(max-width: 800px)');
            var $tripCardCarousel = $(element);
            var stagePaddingXs = scope.stagePaddingXs ? scope.stagePaddingXs : 15;
            var itemsXs = scope.itemsXs ? scope.itemsXs : 1;
            var itemsSm = scope.itemsSm ? scope.itemsSm : 1;
            var itemsMd = scope.itemsMd ? scope.itemsXs : 3;
            var disableXs = scope.disableXs === true ? scope.disableXs : false;
            var disableSm = scope.disableSm === true ? scope.disableSm : false;
            var carouselClasses = 'owl-carousel owl-carousel--has-nav grid-component__carousel grid-component__carousel--no-margins trip-cards__carousel';

            var options = {
                baseClass: 'trip-card-carousel',
                navContainerClass: 'owl-nav',
                items: 3,
                dots: true,
                nav: true,
                navText: '',
                margin: 30,
                freeDrag: false,
                mouseDrag: false,
                loop: true,
                dotsEach: true,
                responsive: {
                    0: {
                        items: itemsXs,
                        slideBy: 1,
                        stagePadding: stagePaddingXs
                    },
                    800: {
                        items: itemsSm,
                        slideBy: 1,
                        stagePadding: stagePaddingXs
                    },
                    992: {
                        items: itemsMd,
                        slideBy: 1
                    }
                }
            };

            function doToggleCarousel(isDisabled) {
                if (isDisabled) {
                    $tripCardCarousel
                        .owlCarousel('destroy')
                        .removeClass(carouselClasses);
                } else {
                    $tripCardCarousel
                        .addClass(carouselClasses)
                        .owlCarousel(options);
                }
            }

            function toggleCarousel(mediaQuery) {
                if (mediaQuery.matches) {
                    doToggleCarousel(scope.disableXs);
                } else {
                    doToggleCarousel(scope.disableSm);
                }
            }

            $tripCardCarousel.on('initialized.owl.carousel', function () {
                //translatePolyfill();
                $rootScope.$broadcast('tripCardCarousel.carousel.afterInit');
            });

            function init() {
                toggleCarousel(media);
                media.addListener(toggleCarousel);
            }

            init();

            // POLYFILL to fix a flicker in IE11. This has a performance impact on other browsers so commenting out
            // as it is a minor bug that only impacts a very minor set of users. Remove at a later date if no bug is raised 11/10/17
            //$tripCardCarousel.on('translated.owl.carousel', translatePolyfill);

            //// fix for IE11 translate3d flicker
            //function translatePolyfill() {
            //    $timeout(function () {
            //        var $stage = angular.element(element).find('.hidden-xs .owl-stage');
            //        if ($stage.length) {
            //            // converts the css transform xyz values to an array
            //            var transforms = $stage.css('transform').match(/matrix(?:(3d)\(-{0,1}\d+(?:, -{0,1}\d+)*(?:, (-{0,1}\d+))(?:, (-{0,1}\d+))(?:, (-{0,1}\d+)), -{0,1}\d+\)|\(-{0,1}\d+(?:, -{0,1}\d+)*(?:, (-{0,1}\d+))(?:, (-{0,1}\d+))\))/);
            //            if (!transforms) return;
            //            if (transforms[1] == '3d') {
            //                transforms = transforms.slice(2, 5);
            //            }
            //            else {
            //                transforms.push(0);
            //                transforms = transforms.slice(5, 8);
            //            }

            //            if (transforms && transforms[0]) {
            //                $stage.css('transform', 'translateX(' + transforms[0] + 'px)');
            //            }
            //        }
            //    }, 100);
            //}
        }
    }

    //uplift trip carousel
    upliftTripCardCarousel.$inject = ['$rootScope'];

    function upliftTripCardCarousel($rootScope) {
        var directive = {
            restrict: 'A',
            scope: {
                stagePaddingXs: '=',
                itemsXs: '=',
                itemsSm: '=',
                itemsMd: '=',
                disableXs: '=',
                disableSm: '='
            },
            link: link
        };

        return directive;

        function link(scope, element, attrs, ctrl) {
            var media = window.matchMedia('(max-width: 800px)');
            var $upliftTripCardCarousel = $(element);
            var stagePaddingXs = scope.stagePaddingXs ? scope.stagePaddingXs : 15;
            var itemsXs = scope.itemsXs ? scope.itemsXs : 1;
            var itemsSm = scope.itemsSm ? scope.itemsSm : 1;
            var itemsMd = scope.itemsMd ? scope.itemsXs : 3;
            var disableXs = scope.disableXs === true ? scope.disableXs : false;
            var disableSm = scope.disableSm === true ? scope.disableSm : false;
            var carouselClasses = 'owl-carousel owl-carousel--has-nav grid-component__carousel grid-component__carousel--no-margins trip-cards__carousel';

            var options = {
                baseClass: 'uplift-trip-card-carousel',
                navContainerClass: 'owl-nav',
                dots: true,
                nav: true,
                navText: '',
                loop: false,
                rewind: true,
                dotsEach: true,
                responsiveClass: true,
                autoheight: true,
                responsive: {
                    0: {
                        items: 1,
                        margin: 30,
                        loop: true,
                        stagePadding: stagePaddingXs
                    },
                    801: {
                        items: 2,
                        margin: 30
                    },
                    992: {
                        items: 3,
                        margin: 30.5
                    },
                    1281: {
                        items: 4,
                        margin: 30
                    }
                }
            };

            function doToggleCarousel(isDisabled) {
                if (isDisabled) {
                    $upliftTripCardCarousel
                        .owlCarousel('destroy')
                        .removeClass(carouselClasses);
                } else {
                    $upliftTripCardCarousel
                        .addClass(carouselClasses)
                        .owlCarousel(options);
                }
            }

            function toggleCarousel(mediaQuery) {
                if (mediaQuery.matches) {
                    doToggleCarousel(scope.disableXs);
                } else {
                    doToggleCarousel(scope.disableSm);
                }
            }

            $upliftTripCardCarousel.on('initialized.owl.carousel', function () {
                //translatePolyfill();
                $rootScope.$broadcast('upliftTripCardCarousel.carousel.afterInit');
            });

            function init() {
                toggleCarousel(media);
                media.addListener(toggleCarousel);
            }

            init();
        }
    }

    featurePanelCarousel.$inject = ['$rootScope'];

    function featurePanelCarousel($rootScope) {
        var directive = {
            restrict: 'A',
            scope: {
                stagePaddingXs: '=',
                itemsXs: '=',
                itemsSm: '=',
                itemsMd: '=',
                disableXs: '=',
                disableSm: '='
            },
            link: link
        };

        return directive;

        function link(scope, element, attrs, ctrl) {
            var media = window.matchMedia('(max-width: 800px)');
            var $featurePanelCarousel = $(element);
            var stagePaddingXs = scope.stagePaddingXs ? scope.stagePaddingXs : 15;
            var itemsXs = scope.itemsXs ? scope.itemsXs : 1;
            var itemsSm = scope.itemsSm ? scope.itemsSm : 1;
            var itemsMd = scope.itemsMd ? scope.itemsXs : 3;
            var disableXs = scope.disableXs === true ? scope.disableXs : false;
            var disableSm = scope.disableSm === true ? scope.disableSm : false;
            var carouselClasses = 'owl-carousel owl-carousel--has-nav grid-component__carousel grid-component__carousel--no-margins feature-panel-uplift__carousel';

            var options = {
                baseClass: 'feature-panel-carousel',
                navContainerClass: 'owl-nav',
                items: 3,
                dots: true,
                nav: true,
                navText: '',
                margin: 30,
                freeDrag: false,
                mouseDrag: false,
                loop: true,
                dotsEach: true,
                responsive: {
                    0: {
                        items: itemsXs,
                        slideBy: 1,
                        stagePadding: stagePaddingXs
                    },
                    800: {
                        items: itemsSm,
                        slideBy: 1,
                        stagePadding: stagePaddingXs
                    },
                    992: {
                        items: itemsMd,
                        slideBy: 1
                    }
                }
            };

            function doToggleCarousel(isDisabled) {
                if (isDisabled) {
                    $featurePanelCarousel
                        .owlCarousel('destroy')
                        .removeClass(carouselClasses);
                } else {
                    $featurePanelCarousel
                        .addClass(carouselClasses)
                        .owlCarousel(options);
                }
            }

            function toggleCarousel(mediaQuery) {
                if (mediaQuery.matches) {
                    doToggleCarousel(scope.disableXs);
                } else {
                    doToggleCarousel(scope.disableSm);
                }
            }

            $featurePanelCarousel.on('initialized.owl.carousel', function () {
                $rootScope.$broadcast('featurePanelCarousel.carousel.afterInit');
            });

            function init() {
                toggleCarousel(media);
                media.addListener(toggleCarousel);
            }

            init();
        }
    }

    hereToHelpCarousel.$inject = ['$rootScope'];

    function hereToHelpCarousel($rootScope) {
        var directive = {
            restrict: 'A',
            scope: {
                stagePaddingXs: '=',
                itemsXs: '=',
                itemsSm: '=',
                itemsMd: '=',
                disableXs: '=',
                disableSm: '='
            },
            link: link
        };

        return directive;

        function link(scope, element, attrs, ctrl) {
            var media = window.matchMedia('(max-width: 800px)');
            var $hereToHelpCarousel = $(element);
            var stagePaddingXs = scope.stagePaddingXs ? scope.stagePaddingXs : 15;
            var itemsXs = scope.itemsXs ? scope.itemsXs : 1;
            var itemsSm = scope.itemsSm ? scope.itemsSm : 1;
            var itemsMd = scope.itemsMd ? scope.itemsXs : 3;
            var disableXs = scope.disableXs === true ? scope.disableXs : false;
            var disableSm = scope.disableSm === true ? scope.disableSm : false;
            var carouselClasses = 'owl-carousel owl-carousel--has-nav grid-component__carousel grid-component__carousel--no-margins here-to-help__carousel';

            var options = {
                baseClass: 'here-to-help-carousel',
                navContainerClass: 'owl-nav',
                items: 3,
                dots: true,
                nav: true,
                navText: '',
                margin: 30,
                freeDrag: false,
                mouseDrag: false,
                loop: true,
                dotsEach: true,
                responsive: {
                    0: {
                        items: itemsXs,
                        slideBy: 1,
                        stagePadding: stagePaddingXs
                    },
                    800: {
                        items: itemsSm,
                        slideBy: 1,
                        stagePadding: stagePaddingXs
                    },
                    992: {
                        items: itemsMd,
                        slideBy: 1
                    }
                }
            };

            function doToggleCarousel(isDisabled) {
                if (isDisabled) {
                    $hereToHelpCarousel
                        .owlCarousel('destroy')
                        .removeClass(carouselClasses);
                } else {
                    $hereToHelpCarousel
                        .addClass(carouselClasses)
                        .owlCarousel(options);
                }
            }

            function toggleCarousel(mediaQuery) {
                if (mediaQuery.matches) {
                    doToggleCarousel(scope.disableXs);
                } else {
                    doToggleCarousel(scope.disableSm);
                }
            }

            $hereToHelpCarousel.on('initialized.owl.carousel', function () {
                $rootScope.$broadcast('hereToHelpCarousel.carousel.afterInit');
            });

            function init() {
                toggleCarousel(media);
                media.addListener(toggleCarousel);
            }

            init();
        }
    }

    function lifestyleCarousel() {
        var directive = {
            restrict: 'A',
            link: link
        };

        return directive;

        function link(scope, element, attrs) {
            var $carousel = $(element);
            var options = {
                items: 1,
                loop: true,
                nav: true,
                navText: false,
                dots: true,
                lazyLoad: true,
                lazyContent: true,
                autoHeight: true,
                navSpeed: 1100
            };

            $carousel.owlCarousel(options);
        }
    }

    function tourManagerCarousel() {
        var directive = {
            restrict: 'A',
            link: link
        };

        return directive;

        function link(scope, element, attrs) {
            var $carousel = $(element);
            var options = {
                items: 1,
                loop: true,
                nav: true,
                navText: false,
                dots: true,
                lazyLoad: true,
                lazyContent: true,
                autoHeight: true,
                navSpeed: 1100
            };

            $carousel.owlCarousel(options);
        }
    }
})();



;
(function () {

    "use strict";


    angular.module('Phoenix.Shared.directives')
        // add ontouchstart if this is a touch device
        .directive('ontouchstart', function () {
            return {
                link: function () {
                    if (Modernizr.touchevents) {
                        $('html').attr('ontouchstart', '');
                    }
                }
            }
        })

        // resizes a child image to fit this parent by assigning css class
        .directive('fitImage', ['$timeout', '$window', function ($timeout, $window) {
            return {
                restrict: 'A',
                link: function (scope, element, attrs) {
                    var tallClass = 'tall';
                    var wideClass = 'wide';
                    angular.element($window).bind('resize', function () {
                        doFitImage();
                    });
                    $timeout(function () {
                        doFitImage();
                    }, 500);

                    function doFitImage() {
                        var img = element.find('img');
                        if (img.length) {
                            var parentAspectRatio = element.width() / element.height();
                            var imageAspectRatio = img.width() / img.height();
                            var imgClass = (parentAspectRatio > imageAspectRatio) ? tallClass : wideClass;
                            var removeClass = imgClass == tallClass ? wideClass : tallClass;
                            img.addClass(imgClass);
                            img.removeClass(removeClass);

                            var $img = angular.element(img);
                            if (imgClass == tallClass) {
                                var top = (img[0].clientHeight - element.height()) / 2;
                                $img.css('top', '-' + top + 'px');
                                $img.css('left', 'auto');
                            } else if (imgClass == wideClass) {
                                var left = (img[0].clientWidth - element.width()) / 2;
                                $img.css('left', '-' + left + 'px');
                                $img.css('top', 'auto');
                            }
                        }
                    }
                }
            };
        }])
        
        // sets all elements marked with this directive in a container to the same height -
        // the height of the tallest element
        .directive('autoheight', ['$timeout', '$window', function ($timeout, $window) {
            return {
                restrict: 'A',
                link: function (scope, element, attrs) {

                    $timeout(function () {
                        var $el = angular.element(element);
                        var parentContainer = $el.closest('.container');
                        var els = parentContainer.find('*[data-autoheight]');

                        if (parentContainer.length) {

                            var doAutosize = function () {
                                els.css('height', 'auto');
                                var height = 0;
                                for (var i = 0; i < els.length; i++) {
                                    if ($(els[i]).height() > height) {
                                        height = $(els[i]).height();
                                    }
                                }
                                els.height(height);
                            };

                            angular.element($window).bind('resize', doAutosize);


                            doAutosize();
                        }
                    }, 700);
                }
            };
        }])

    .directive('clickOutside', ['$document', function ($document) {
        return {
            restrict: 'A',
            link: function postLink(scope, element, attrs) {
                var onClick = function (event) {
                    var isChild = $(element).has(event.target).length > 0;
                    var isSelf = element[0] == event.target;
                    var isInside = isChild || isSelf;
                    if (!isInside) {
                        scope.$apply(attrs.clickOutside)
                    }
                }
                scope.$watch(attrs.isActive, function (newValue, oldValue) {
                    if (newValue !== oldValue && newValue == true) {
                        $document.bind('tap click', onClick);
                    } else if (newValue !== oldValue && newValue == false) {
                        $document.unbind('tap click', onClick);
                    }
                });
            }
        };
    }])

    .directive('objectFitPolyfill', ['$timeout', '$rootScope', function ($timeout, $rootScope) {
        return {
            restrict: 'A',
            link: function (scope, element, attrs) {

                $rootScope.$on('broadcast.dom-manipulation.image', function () {
                    doPolyfill();
                });

                $timeout(function () {
                    doPolyfill();
                });

                var browserHasObjectFit = function () {

                    // Modernizr.objectfit returns true for samsung, despite the fact object-fit isn't supported.
                    if (navigator.userAgent.match(/SAMSUNG|SGH-[I|N|T]|GT-[I|P|N]|SM-[N|P|T|Z|G]|SHV-E|SCH-[I|J|R|S]|SPH-L/i)) {
                        return false;
                    }
                    return Modernizr.objectfit;
                }

                var doPolyfill = function () {
                    if (!browserHasObjectFit()) {
                        $('img').each(function () {
                            var $container = $(this),
                                imgUrl = $container.data('src') ? $container.data('src') : $container.prop('src');
                            var imgClass = $container.attr('class');
                            var imgRatio = parseFloat($container.attr('data-ratio'));
                            var setHeight = true;
                            var imgHeightStyle = '';

                            if (isNaN(imgRatio) || imgRatio == 'undefined')
                                setHeight = false;
                            
                            if ($container.css('font-family').indexOf('object-fit') > -1 && imgUrl) {
                                var backgroundPosition = $container.attr('data-object-position');
                                var backgroundPositionStyle = backgroundPosition ? 'background-position: ' + backgroundPosition + ';' : '';

                                var svgSpecificStyles = '';
                                if ($container.hasClass('svg')) {
                                    svgSpecificStyles = '; width:' + $container.width() + 'px; margin: auto; ';
                                }

                                if (setHeight) {
                                    var imgHeight = ($container.width() / parseFloat(imgRatio));
                                    var imgHeightStyle = '; height:' + imgHeight + 'px; ';
                                }

                                $container
                                    .replaceWith('<div class="compat-object-fit ' + imgClass + '" style="background-image: url(' + imgUrl + ');' + imgHeightStyle + svgSpecificStyles + backgroundPositionStyle + '" />');
                            }
                        });
                    }
                }

            }
        };
    }])

    .directive('countTo', countTo)

    .directive('scrollToAnchor', scrollToAnchor)

    .directive('scrollToId', scrollToId)

    .directive('removeNestedContainer', removeNestedContainer)

    .directive('dropdownCloseOnNav', dropdownCloseOnNav)

    .directive('dynamicCollapse', dynamicCollapse)

    .directive('autocomplete', autocomplete)

    .directive('reloadPage', reloadPage)

    .directive('tooltip', tooltip);

    scrollToAnchor.$inject = ['$window', '$timeout'];

    function scrollToAnchor($window, $timeout) {
        var directive = {
            scope: true,
            restrict: 'AE',
            link: link
        };

        return directive;

        function link(scope, element, attrs) {

            var hash = $window.location.hash;
            var scrollEl = angular.element(hash)[0];

            if (hash && typeof scrollEl !== 'undefined') {
                $timeout(function () {
                    angular.element('html, body').stop().animate({
                        scrollTop: scrollEl.offsetTop - 20
                    }, 600);
                }, 1000);
            }
        }
    }

    scrollToId.$inject = ['$window'];

    function scrollToId($window) {
        var directive = {
            scope: {
                scrollToId: '@',
                scrollIntoView: '=',
                scrollToIdSecondary: '@',
                scrollIntoViewSecondary: '=',
                scrollDisabled: '=',
                scrollToIdExcludeBuffer: '@',
                addHashToUrl: '=',
                scrollToIdBufferSize: '@'
        },
            restrict: 'A',
            link: link
        };

        return directive;

        function link(scope, element, attrs) {

            var $el = angular.element(element);
            var $scrollEl = angular.element('#' + scope.scrollToId);
            var $scrollElSecondary = angular.element('#' + scope.scrollToIdSecondary);
            var buffer = scope.scrollToIdExcludeBuffer ? 10 : 80;
            buffer = scope.scrollToIdBufferSize ? scope.scrollToIdBufferSize : buffer;


            $el.on('click', function () {
                if ($scrollEl.length && $scrollEl.is(":visible")) {
                    doScroll($scrollEl, scope.scrollIntoView);
                }
                else if ($scrollElSecondary.length && $scrollElSecondary.is(":visible")) {
                    doScroll($scrollElSecondary, scope.scrollIntoViewSecondary);
                }
            });
            var doScroll = function (el, intoView) {
                if (!scope.scrollDisabled) {
                    var $htmlBody = angular.element('html, body');

                    if (scope.addHashToUrl == true) {
                        var scrollTopCurrent = $(document).scrollTop();
                        window.location.hash = scope.scrollToId;
                        $(document).scrollTop(scrollTopCurrent);
                    }

                    if (intoView != true) {
                        $htmlBody.stop().animate({
                            scrollTop: el.offset().top - buffer
                        }, 600);

                    }
                    else {
                        var scrollTopCurrent = $(document).scrollTop() + 30;
                        var scrollTop = el.offset().top - ($(window).height() - el.outerHeight() + 10) + 30;

                        if (scrollTopCurrent < scrollTop) {
                            $htmlBody.stop().animate({
                                scrollTop: scrollTop
                            }, 600);
                        }
                    }
                }
            }
        }
    }

    countTo.$inject = ['$timeout', '$filter'];

    function countTo($timeout, $filter) {
        var directive = {
            replace: true,
            scope: true,
            restrict: 'AE',
            link: link
        };

        return directive;

        function link(scope, element, attrs) {
            var e = element[0];
            var num, refreshInterval, duration, steps, step, countTo, value, increment;

            var calculate = function () {
                refreshInterval = 30;
                step = 0;
                scope.timoutId = null;
                countTo = parseInt(attrs.countTo) || 0;
                scope.value = parseInt(attrs.value, 10) || 0;
                duration = (parseFloat(attrs.duration) * 1000) || 0;

                steps = Math.ceil(duration / refreshInterval);
                increment = ((countTo - scope.value) / steps);
                num = scope.value;
            };

            var tick = function () {
                scope.timoutId = $timeout(function () {
                    num += increment;
                    step++;
                    if (step >= steps) {
                        $timeout.cancel(scope.timoutId);
                        num = countTo;
                        e.textContent = $filter('number')(countTo);
                    } else {
                        e.textContent = $filter('number')(Math.round(num));
                        tick();
                    }
                }, refreshInterval);

            };

            var start = function () {
                if (scope.timoutId) {
                    $timeout.cancel(scope.timoutId);
                }
                calculate();
                tick();
            };

            attrs.$observe('countTo', function (val) {
                if (val) {
                    start();
                }
            });

            attrs.$observe('value', function (val) {
                start();
            });

            return true;
        }
    }

    removeNestedContainer.$inject = ['$timeout'];

    function removeNestedContainer($timeout) {
        var directive = {
            replace: true,
            scope: true,
            restrict: 'AE',
            link: link
        };

        return directive;

        function link(scope, element) {
            $timeout(function () {
                var $el = angular.element(element);
                if ($el.parents('.container').length) {
                    $el.removeClass('container');
                }
            });
        }
    }

    dropdownCloseOnNav.$inject = ['$timeout', '$window'];

    function dropdownCloseOnNav($timeout, $window) {
        var directive = {
            replace: true,
            scope: true,
            restrict: 'AE',
            link: link
        };

        return directive;

        function link(scope, element) {
            var $dropdown = angular.element(element).find('.dropdown-hover-target');
            var openClass = 'dropdown-open';

            $dropdown.on('mouseover mouseenter click', function () {
                $dropdown.addClass(openClass);
            });

            $dropdown.on('mouseleave', function () {
                $dropdown.removeClass(openClass);
            });

            var $a = $dropdown.find('a').not('.iframe-link');

            $a.on('touchstart click tap', function (e) {
               // e.preventDefault();
                $dropdown.removeClass(openClass);
                //$window.open(e.target.href);
            });
        }
    } 

    dynamicCollapse.$inject = ['$timeout', '$window'];

    function dynamicCollapse($timeout, $window) {
        var directive = {
            scope: false,
            restrict: 'A',
            link: link,
            controller: dynamicCollapseController,
            controllerAs: 'dcc',
            bindToController: true
        };

        return directive;

        function link(scope, element, attr, ctrl) {

            var panelHeightTimer;
            var $htmlBody = angular.element('html body');
            var $element = angular.element(element);
            var panel = $element.find('[data-dynamic-collapse-panel]');
            var $container = $element.find('[data-dynamic-collapse-container]');

            ctrl.dynamicCollapseAnalyticsCategory = attr.dynamicCollapseAnalyticsCategory;
            ctrl.dynamicCollapseAnalyticsAction = attr.dynamicCollapseAnalyticsAction;
            ctrl.dynamicCollapseAnalyticsLabel = attr.dynamicCollapseAnalyticsLabel;

            scope.$watch('dcc.isCollapsed', function (collapse) {

                if (panelHeightTimer) {
                    $timeout.cancel(panelHeightTimer);
                }

                if (collapse) {
                    $htmlBody.animate({
                        scrollTop: 0
                    }, 500);
                }

                if (collapse) {
                    var currentHeight = getElementCurrentHeight();
                    panel.height(currentHeight);
                }

                var newHeight = collapse ? 0 : getElementAutoHeight();
                panel.height(newHeight);

                if (newHeight) {
                    panelHeightTimer = $timeout(function () {
                        panel.height('auto');
                    }, 500);
                }
            });

            function getElementAutoHeight() {
                var currentHeight = getElementCurrentHeight();

                panel.height('auto');
                var autoHeight = getElementCurrentHeight();

                panel.height(currentHeight);
                getElementCurrentHeight(); // Force the browser to recalc height after moving it back to normal

                return autoHeight;
            }

            function getElementCurrentHeight() {
                return panel.height();
            }
        }
    }

    dynamicCollapseController.$inject = ['$analytics'];

    function dynamicCollapseController($analytics) {
        var dcc = this;
        dcc.isCollapsed = true;
        dcc.toggleCollapse = toggleCollapse;
        dcc.collapse = collapse;
        dcc.toggleCollapseIfCollapsed = toggleCollapseIfCollapsed;

        function toggleCollapse() {
            dcc.isCollapsed = !dcc.isCollapsed;

            if (dcc.dynamicCollapseAnalyticsCategory) {
                $analytics.eventTrack(null, {
                    category: dcc.dynamicCollapseAnalyticsCategory,
                    action: dcc.dynamicCollapseAnalyticsAction,
                    label: dcc.dynamicCollapseAnalyticsLabel + " - " + (dcc.isCollapsed ? 'Hide' : 'Show')
                });
            }
        }

        function toggleCollapseIfCollapsed() {
            if(dcc.isCollapsed) {
                toggleCollapse();
            }
        }

        function collapse() {
            dcc.isCollapsed = true;
        }
    }

    autocomplete.$inject = ['$timeout', '$window'];

    function autocomplete($timeout, $window) {
        var directive = {
            replace: true,
            scope: {
                autocompleteSelected: '=',
                autocompleteSelectedPrevious: '=',
                autocompleteList: '=',
                autocompleteSearch: '=',
                autocompletePlaceholder: '@',
                autocompleteInputClass: '@'
            },
            restrict: 'E',
            link: link,
            templateUrl: '/assets/js/phoenix/shared/ng/templates/autocomplete.html',
        };

        return directive;

        function link(scope, element) {

            scope.autocompleteTyped = scope.autocompleteSelected;
            scope.autocompleteOpen = false;
            scope.activeIndex = 0;
            var $el = angular.element(element);

            scope.autocompleteClear = function () {
                scope.autocompleteSelected = '';
                scope.autocompleteTyped = '';
            }

            // Autocomplete up/down/enter implementation
            scope.showAutocomplete = function (e) {
                scope.autocompleteOpen = true;
                switch (e.keyCode) {
                    case 38: // up
                        if (scope.activeIndex > 1) scope.activeIndex--;
                        if (scope.activeIndex) scope.autocompleteTyped = scope.autocompleteData[scope.activeIndex - 1];

                        break;

                    case 40: // down
                        if (scope.activeIndex < scope.autocompleteData.length) scope.activeIndex++;
                        if (scope.activeIndex) scope.autocompleteTyped = scope.autocompleteData[scope.activeIndex - 1];

                        break;

                    case 13: // enter
                        if (scope.activeIndex) scope.doAutocompleteSearch(scope.autocompleteData[scope.activeIndex - 1], true);
                        scope.autocompleteOpen = false;

                        break;

                    default:
                        scope.autocompleteSelected = scope.autocompleteTyped;
                        scope.activeIndex = 0;
                        scope.autocompleteOpen = true;

                        return; // exit this handler for other keys
                }
                e.preventDefault(); // prevent the default action (scroll / move caret)
            }

            scope.hideAutocomplete = function () {
                scope.autocompleteOpen = false;
                scope.activeIndex = 0;
            }

            scope.setActiveIndex = function (index) {
                scope.activeIndex = index;
            }

            scope.doAutocompleteSearch = function (item) {
                scope.autocompleteSelected = item;
                scope.autocompleteTyped = item;
                scope.autocompleteOpen = false;
                scope.autocompleteSearch();
            }
        }
    }

    reloadPage.$inject = ['$window'];

    function reloadPage($window) {
        var directive = {
            scope: true,
            restrict: 'A',
            link: link,
            controller: reloadPageController,
            controllerAs: 'rpc',
            bindToController: true
        };

        return directive;

        function link(scope, element) {
            scope.$on('reloadPageController.reloadPage', function (e, args) {
                if (args.anchor) {
                    $window.location.href += '#' + args.anchor;
                }

                $window.location.reload();
            });
        }
    }

    reloadPageController.$inject = ['$scope'];

    function reloadPageController($scope) {
        var rpc = this;
        rpc.reloadPage = reloadPage;

        function reloadPage(anchor) {
            $scope.$broadcast('reloadPageController.reloadPage', { anchor: anchor });
        }
    }

    tooltip.$inject = ['$window'];

    function tooltip($window) {
        var directive = {
            restrict: 'A',
            scope: true,
            link: link
        };

        return directive;

        function link(scope, element, attrs, ctrl) {
            var $el = angular.element(element);
            var toolTipContainer = angular.element('.tooltip-container');

            angular.element(document).ready(function () {
                if (toolTipContainer) {
                    toolTipContainer.append("<span class='tooltip-container__arrow'></span>");
                }
            });

            if (Modernizr.touchevents) {
                element.bind('click', function () {
                    SetTooltipArrowPosition($el);
                    $el.toggleClass('is-active');
                });
            } else {
                element.bind('mouseenter', function () {
                    SetTooltipArrowPosition($el);
                    $el.addClass('is-active');
                });
                element.bind('mouseleave', function () {
                    $el.removeClass('is-active');
                });
            }
        }

        function SetTooltipArrowPosition(element) {
            if (!element) return;

            var pos = element.position();
            var containerPos = angular.element('.tooltip-container').position();
            $('.tooltip-container__arrow').css('left', pos.left - containerPos.left);
        }
    }

    if (!window.Sitecore) {
        angular.module('Phoenix.Shared.directives')
            // allows contenteditable-attributed elements to bind to a model
            .directive('contenteditable', ['$timeout', '$window', function ($timeout, $window) {
                return {
                    require: 'ngModel',
                    scope: {
                        placeholder: '@',
                        ngModel: "=",
                        maxlength: "="
                    },
                    link: function (scope, element, attrs, ctrl) {

                        var maxlength = scope.maxlength ? scope.maxlength : 0;
                        var $el = angular.element(element)
                        var width;
                        $timeout(function () {
                            setWidth();
                        });

                        angular.element($window).bind('resize', function () {
                            setWidth();
                        });

                        element.bind('keyup', function () {

                            var htmlValue = getHtmlValue();

                            if (htmlValue) {
                                scope.$apply(function () {
                                    ctrl.$setViewValue(htmlValue);
                                });
                            } else {
                                ctrl.$setViewValue('');
                            }
                            if (!htmlValue) {
                                element.html('&nbsp;');
                            }
                        });

                        element.bind('keydown', function (e) {
                            var allowKey = allowKeyDown(e);
                            if (!allowKey) return false;
                            if (element.html() == '&nbsp;') {
                                element.html('');
                            }
                            resetWidth();
                        });

                        element.bind('click', function (e) {
                            e.stopPropagation();
                            $el.addClass('active');
                            var htmlValue = getHtmlValue();
                            if (!htmlValue) {
                                element.html('&nbsp;')
                            }
                        });

                        $(document).click(function () {
                            var htmlValue = getHtmlValue();
                            if (!htmlValue) {
                                $el.removeClass('active');
                                element.html('');
                                setWidth();
                            }
                            else {
                                $timeout(function () {
                                    resetWidth();
                                }, 100); // prevent misclick on drop-down menu which populates this element
                            }
                        });

                        ctrl.$render = function () {
                            element.html(ctrl.$viewValue);
                        };
                        ctrl.$render();

                        var setWidth = function () {
                            width = angular.element(element).width();
                            $el.css('min-width', width);
                        }

                        var resetWidth = function () {
                            $el.css('min-width', '20px');
                        }

                        var getHtmlValue = function () {
                            var htmlValue = element.html().replace(/<(?:.|\n)*?>/gm, '').replace('&nbsp;', ''); // fix for IE11 contenteditiable - removes html from input
                            return htmlValue;
                        }

                        var allowKeyDown = function (e) {
                            if (e.which == 13) return false;
                            // allow the user to move cursor left/right, backspace, delete
                            if (e.which != 8 && e.which != 46 && e.which != 37 && e.which != 39 && maxlength > 0 && element.html().length >= maxlength) return false;
                            // disallow the user to enter cursor left/right, backspace, delete, space when no content exists
                            if ((e.which == 32 || e.which == 8 || e.which == 46 || e.which == 37 || e.which == 39) && (!element.html().length || element.html() === '&nbsp;')) return false;
                            return true;
                        }
                    }
                };
            }])
    }
})();
;
"use strict";

angular.module('Phoenix.Shared.directives')
    .directive('dynamicForm', function () {
        return {
            restrict: 'A',
            scope: {
                displayCaptchaOnValidForm: '@',
                displaySubmitOnValidForm: '@'
            },
            link: function (scope, element, attr, ctrl) {
                if (scope.displayCaptchaOnValidForm !== "true" && scope.displaySubmitOnValidForm !== "true") {
                    return;
                }

                var FORM = {};
                var CAPTCHA = {};
                var SUBMIT = {};

                FORM.showDuration = 200;
                FORM.selector = 'form';
                FORM.$element = $(element).find(FORM.selector).addBack(FORM.selector);
                CAPTCHA.$element = FORM.$element.find('.form-captcha');
                SUBMIT.$element = FORM.$element.find('.submit');

                FORM.init = function () {
                    var displayCaptchaOnValidForm = scope.displayCaptchaOnValidForm === "true";
                    var displaySubmitOnValidForm = scope.displaySubmitOnValidForm === "true";

                    if (displayCaptchaOnValidForm) {
                        CAPTCHA.$element.hide();
                    }

                    if (displaySubmitOnValidForm) {
                        SUBMIT.$element.hide();
                    }

                    FORM.$element.on('form.validation.valid', function () {
                        if (displayCaptchaOnValidForm) {
                            CAPTCHA.$element.show(FORM.showDuration);
                        }

                        if (displaySubmitOnValidForm) {
                            SUBMIT.$element.show(FORM.showDuration);
                        }
                    });

                    FORM.$element.on('form.validation.invalid', function () {
                        if (displayCaptchaOnValidForm) {
                            CAPTCHA.$element.hide(FORM.showDuration);
                        }

                        if (displaySubmitOnValidForm) {
                            SUBMIT.$element.hide(FORM.showDuration);
                        }
                    });
                }

                FORM.init();
            }
        }
    })
    .directive('tripRequestQuoteForm', [function () {
        return {
            scope: true,
            controller: tripRequestQuoteForm,
            controllerAs: 'rqfc',
            bindToController: true,
            restrict: 'A'
        }
    }])

    .directive('tripRequestQuoteFormInitialiseModel', [function () {
        return {
            scope: true,
            controller: tripRequestQuoteFormInitialiseModel,
            controllerAs: 'rqfimc',
            bindToController: true,
            restrict: 'A'
        }
    }])

    .directive('eventSignupForm', ['$timeout', function ($timeout) {
        return {
            restrict: 'A',
            scope: true,
            controller: eventSignupController,
            controllerAs: 'esc',
            bindToController: true,
            link: function (scope, element, attr, ctrl) {
                var $el = angular.element(element);
                var form = angular.element(element).find('form');

                var validateForm = function () {
                    ctrl.form.isSubmitted = true;
                    if (form.length) {
                        if (ctrl.form.eventSessionIdsString() === '') {
                            ctrl.form.isValid = false;
                        }
                    }
                }

                var scrollToTop = function () {
                    angular.element('html, body').stop().animate({
                        scrollTop: $el.offset().top
                    }, 500);
                }

                scope.$on('broadcast.eventSignupController.doSubmit', function () {
                    scrollToTop();
                    validateForm();

                    if (ctrl.form.isValid && form.length) {
                        var submitButton = form.find('input[type=submit], button[type=submit]');
                        if (submitButton.length) {
                            submitButton.click();
                        }
                    }
                });
            }
        }
    }]);

newsletterSubscriptionFormController.$inject = ['$scope'];
function newsletterSubscriptionFormController($scope) {
    var nsfc = this;
    nsfc.newsletterSubscriptionTitle;
}

tripRequestQuoteForm.$inject = ['$scope'];
function tripRequestQuoteForm($scope) {
    var rqfc = this;
    rqfc.tripCode = '';
    rqfc.tripName = '';

    rqfc.init = function (tripCode, tripName) {
        setTripData({ 'TripCode': tripCode, 'Name': tripName });
    };

    function setTripData(trip) {
        rqfc.tripCode = trip.TripCode;
        rqfc.tripName = trip.Name;
    }

    $scope.$on('broadcast.tripFinderController.updateTripData', function (event, trip) {
        if (!(trip && trip.TripCode && trip.Name)) {
            console.error('Error updating trip data in tripRequestQuoteForm controller');
            return;
        }
        setTripData(trip);
    });
}

tripRequestQuoteFormInitialiseModel.$inject = ['$scope', '$rootScope'];
function tripRequestQuoteFormInitialiseModel($scope, $rootScope) {
    var rqfimc = this;
    rqfimc.requestQuote = function (trip) {
        var formSection = $('[data-trip-request-quote-form] .js-form-section');
        formSection.show().next().hide();
        $rootScope.$broadcast('broadcast.tripFinderController.updateTripData', trip);
    };
}

eventSignupController.$inject = ['$scope'];
function eventSignupController($scope) {
    var esc = this;
    esc.form = {
        eventId: '',
        eventSessionIds: {},
        eventSessionIdsInvalid: eventSessionIdsInvalid,
        eventSessionIdsString: eventSessionIdsString,
        isSubscribeNewsletter: false,
        isValid: false,
        isSubmitted: false,
        doSubmit: doSubmit,
        setEventId: setEventId
    }

    function doSubmit() {
        $scope.$broadcast('broadcast.eventSignupController.doSubmit');
    }

    function setEventId(eventId) {
        esc.form.eventId = eventId;
    }

    function eventSessionIdsInvalid() {
        var isInvalid =
            !esc.form.isValid && esc.form.isSubmitted
        return isInvalid;
    }

    function eventSessionIdsString() {
        var eventSessionIdsString = '';

        if (!esc.form.eventSessionIds) return eventSessionIdsString;

        var sessionIds = Object.keys(esc.form.eventSessionIds).map(function (key) { return esc.form.eventSessionIds[key]; });

        var prefix = '';

        for (var i = 0; i < sessionIds.length; i++) {
            if (sessionIds[i]) {
                eventSessionIdsString += prefix + sessionIds[i];
                if (prefix === '') prefix = ',';
            }
        }

        if (eventSessionIdsString !== '') esc.form.isValid = true;

        return eventSessionIdsString;
    }
}

angular.module('Phoenix.Shared.directives')
    .directive('phoenixFormTwoColumn', [function () {
        return {
            restrict: 'A',
            link: function (scope, element) {
                var fieldSet = angular.element(element).find('.field-set');
                var formFieldsLeft = angular.element(element).find('.phoenix-form__field-set--left');
                var formFieldsRight = angular.element(element).find('.phoenix-form__field-set--right');
                var formFieldSubmit = angular.element(element).find('.form-field.submit');
                var formFields = angular.element(element).find('.form-field');
                var columnRowLeft = angular.element('<div class="row"></div>');
                var columnRowRight = angular.element('<div class="row"></div>');
                var columnLeft = angular.element('<div class="col-xs-12 col-sm-6"></div>');
                var columnRight = angular.element('<div class="col-xs-12 col-sm-6"></div>');

                columnLeft.appendTo(fieldSet);
                columnRight.appendTo(fieldSet);
                columnRowLeft.appendTo(columnLeft);
                columnRowRight.appendTo(columnRight);

                formFields.appendTo(columnRowRight);
                formFieldsLeft.appendTo(columnRowLeft);
                formFieldsRight.appendTo(columnRowRight);
                formFieldSubmit.appendTo(fieldSet);
            }
        }
    }]);

angular.module('Phoenix.Shared.directives')
    .directive('maxCharacters', ['$compile', '$timeout', function ($compile, $timeout) {
        return {
            scope: {
                maxCharacters: '=',
                ngModel: '=',
                charCountRemaining: '&'
            },
            restrict: 'A',
            link: function (scope, element) {
                var $el = angular.element(element);
                var label = angular.element('<span class="phoenix-form__char-count">{{charCountRemaining}} characters remaining</span>');

                label.insertAfter(element);
                $compile(label)(scope);

                scope.$watch('ngModel', function (newVal, oldVal) {
                    var valLength = newVal ? newVal.length : 0

                    var charCountRemaining = scope.maxCharacters - valLength;
                    scope.charCountRemaining = charCountRemaining >= 0 ? charCountRemaining : 0;

                    if (valLength > scope.maxCharacters) {
                        scope.ngModel = scope.ngModel.substring(0, scope.maxCharacters);
                    }
                });

                element.on('keypress', function () {
                    if (scope.charCountRemaining <= 0) {
                        return false;
                    }
                });

                element.on('paste', function (e) {
                    if (scope.charCountRemaining <= 0) {
                        return false;
                    }
                });
            }
        }
    }]);

angular.module('Phoenix.Shared.directives')
    .directive('phoenixForm', ['$timeout', 'utilityService', function ($timeout, utilityService) {
        return {
            controller: phoenixFormController,
            controllerAs: 'pfc',
            bindToController: true,
            restrict: 'A',
            link: function (scope, element, attr, ctrl) {
                var $el = angular.element(element);
                var form = $el.find('form');
                var title = $el.find('.phoenix-form__title');
                var titleWrapper = $el.find('.title-wrapper');
                var subtitle = $el.find('.phoenix-form__subtitle');
                var subtitleWrapper = $el.find('.subtitle-wrapper');
                var $nonceEl = $el.find('[name=nonce]');
                var $reCaptchaEl = $el.find('.g-recaptcha');

                form.on('form.submit.initialised', function () {
                    $timeout(function () {
                        scrollToTop();
                        ctrl.form.isSubmitted = true;
                    });
                });

                scope.$on('broadcast.phoenixFormController.doSubmit', function () {
                    scrollToTop();
                    if (form.length) {
                        var submitButton = form.find('input[type=submit], button[type=submit]');
                        if (submitButton.length) {
                            submitButton.click();
                        }
                    }
                });

                scope.$on('broadcast.tripFinderController.updateTripData', function (e, trip) {
                    if (!($nonceEl.length > 0 && trip && trip.CryptographicNonce && trip.CryptographicNonce.length > 0)) {
                        return;
                    }
                    $nonceEl.val(trip.CryptographicNonce);
                });

                scope.$on('broadcast.phoenixFormController.init', function (e, args) {
                    if (args.hideTitle === true) {
                        titleWrapper.remove();
                    }
                    else {
                        if (title.length) title.replaceWith($('<h2 class="phoenix-form__title text-center col-xs-12">' + title[0].innerHTML + '</h2>'));
                    }

                    if (args.hideSubtitle === true) {
                        subtitleWrapper.remove();
                    }
                    else {
                        if (subtitle.length) subtitle.replaceWith($('<p class="phoenix-form__subtitle col-xs-12">' + subtitle[0].innerHTML + '</p>'));
                    }

                    if (args.cryptographicNonce && args.cryptographicNonce.length && $nonceEl.length) {
                        $nonceEl.val(args.cryptographicNonce);
                    }
                });

                function scrollToTop() {
                    angular.element('html, body').stop().animate({
                        scrollTop: $el.offset().top
                    }, 500);
                }
            }
        }
    }]);

angular.module('Phoenix.Shared.directives')
    .directive('countrySelect', ['$timeout', 'locationService', function ($timeout, locationService) {
        return {
            scope: true,
            restrict: 'A',
            link: function (scope, element) {
                var select = angular.element(element);
                var form = angular.element(element).closest('form');
                var formGroup = angular.element(element).closest('.form-group');
                var formGroupClass = 'form-group--country';

                formGroup.addClass(formGroupClass);

                if (!select.length ||
                    !form.length ||
                    !formGroup.length) return;

                locationService.GetLocation()
                    .then(function (data) {
                        if (data) {
                            var location = data.data[0];
                            select.val(location);

                            $timeout(function () {
                                form.trigger('form.masterfield.change', '.' + formGroupClass);
                            });
                        }
                    });
            }
        }
    }]);

phoenixFormController.$inject = ['$scope', '$timeout'];
function phoenixFormController($scope, $timeout) {
    var pfc = this;
    pfc.form = {
        isSubmitted: false,
        doSubmit: doSubmit,
    }
    pfc.init = init;

    function doSubmit() {
        $scope.$broadcast('broadcast.phoenixFormController.doSubmit');
    }

    function init(hideTitle, hideSubtitle, reCaptchaId, cryptographicNonce) {
        $timeout(function () {
            $scope.$broadcast('broadcast.phoenixFormController.init', {
                hideTitle: hideTitle,
                hideSubtitle: hideSubtitle,
                reCaptchaId: reCaptchaId,
                cryptographicNonce: cryptographicNonce
            });
        });
    }
}

angular.module('Phoenix.Shared.directives')
    .directive('formTracking', ['$analytics', function ($analytics) {
        return {
            scope: false,
            restrict: 'A',
            link: function (scope, element, attrs) {
                var form = element.find('form');

                form.on('form.validation.success', function () {
                    $analytics.eventTrack(null, {
                        category: attrs.formTrackingCategory,
                        action: "Form Submitted",
                        label: attrs.formTrackingLabel + " - Validation Success"
                    });
                });

                form.on('form.validation.fail', function () {
                    $analytics.eventTrack(null, {
                        category: attrs.formTrackingCategory,
                        action: "Form Submitted",
                        label: attrs.formTrackingLabel + " - Validation Failure"
                    });
                });

                form.on('form.submit.success', function () {
                    $analytics.eventTrack(null, {
                        category: attrs.formTrackingCategory,
                        action: "Form Submitted",
                        label: attrs.formTrackingLabel + " - Submission Success"
                    });
                });

                form.on('form.submit.error', function () {
                    $analytics.eventTrack(null, {
                        category: attrs.formTrackingCategory,
                        action: "Form Submitted",
                        label: attrs.formTrackingLabel + " - Submission Failure"
                    });
                });

                form.on('change', 'input, textarea', function () {
                    var label = form.find("label[for=" + this.id + "]");
                    $analytics.eventTrack(null, {
                        category: attrs.formTrackingCategory,
                        action: "Form Interaction",
                        label: label.text()
                    });
                });

                form.on('change', 'select', function () {
                    $analytics.eventTrack(null, {
                        category: attrs.formTrackingCategory,
                        action: "Form Interaction",
                        label: angular.element(this).attr("placeholder")
                    });
                });
            }
        }
    }])

// feature view online brochure

angular.module('Phoenix.Shared.directives')
    .directive('feautureViewOnlineInitialiseModal', [function () {
        return {
            scope: true,
            controller: feautureViewOnlineInitialiseModal,
            controllerAs: 'fvoim',
            bindToController: true,
            restrict: 'A'
        }
    }])
    .directive('viewOnlineRequestModalForm', ['$timeout', '$document', '$rootScope', function ($timeout, $document, $rootScope) {
        return {
            scope: true,
            controller: viewOnlineRequestModalForm,
            controllerAs: 'vormf',
            bindToController: true,
            restrict: 'A',
            link: function (scope, element, attr, ctrl) {
                var $el = angular.element(element);
                var form = $el.find('form');
                var brochureWrapper = document.getElementsByClassName('view-online-brochure-modal');
                var $brochureWrapperElement = angular.element(brochureWrapper);

                if (form.length) {
                    form.on('form.submit.initialised', function () {
                     //   $timeout(function () {
                            ctrl.form.isSubmitButtonDisabled = true;
                      //  });
                    });
                    form.on('form.submit.success', function () {
                        scrollToBrochureWrapper();
                        ctrl.form.isSubmitButtonDisabled = false;
                        ctrl.form.isSubmitted = true;
                        var newWindow = window.open();
                        newWindow.location = scope.ebrochureUrl;
                        form[0].reset();
                        $("#view-online-brochure-loader-overlay").attr("style", "display:none");
                        $('#viewOnlineBrochureModal').modal('hide');
                        //storing flag of opened pop up into session
                        sessionStorage.setItem('isModalOpened', 'true');
                    });
                    form.on('form.submit.error', function () {
                        ctrl.form.isSubmitButtonDisabled = false;
                        //scope.$apply();
                    });
                    form.on('form.submit.invalid', function () {
                        ctrl.form.isSubmitButtonDisabled = false;
                       // scope.$apply();
                    });

                    scope.$on('broadcast.viewOnlineBrochureFormSubmitController.submitBrochureForm', function () {
                        var submitButton = form.find('input[type=submit], button[type=submit]');
                        if (submitButton.length) {
                            $("#view-online-brochure-loader-overlay").attr("style", "display:block");
                            submitButton.click();
                        }
                    });
                }

                var scrollToBrochureWrapper = function () {
                    var $scrollToElement = $brochureWrapperElement.length !== 0 ? $brochureWrapperElement : $el;
                    angular.element('html, body').stop().animate({
                        scrollTop: $scrollToElement.offset().top
                    }, 0);
                }
            }
        }
    }])
    .directive('eSubscribeDataHandling', [function () {
        return {
            restrict: 'A',
            link: function (scope, element, attr, ctrl) {
                const campaignCode = document.getElementById("e-subscription").getAttribute('data-campaign-code');
                element.on('click', function (event) {
                    if (!campaignCode) {
                        document.getElementsByClassName("campaign-code-sf")[0].children[0].value = 'NULL';
                    }
                    else {
                        document.getElementsByClassName("campaign-code-sf")[0].children[0].value = campaignCode;
                    }
                })

            }
        }
    }])
//feature view online modal code
feautureViewOnlineInitialiseModal.$inject = ['$scope','$rootScope'];
function feautureViewOnlineInitialiseModal($scope, $rootScope) {
    var fvoim = this;
    fvoim.dataTargetValue = '#viewOnlineBrochureModal';
    fvoim.requestModal = function (brochure) {
        console.log(brochure);
       var formSection = $('[data-view-online-request-modal-form]');
        formSection.show().next().hide();
        const modalopenedFlag = sessionStorage.getItem('isModalOpened');
        if (modalopenedFlag !== 'true') {
        $rootScope.$broadcast('broadcast.viewOnlineBrochureController.updateBrochureData', brochure);
        } else {
            fvoim.dataTargetValue = '';
            var newWindow = window.open();
            newWindow.location = brochure.ebrochureUrl;
        }
       // $rootScope.$broadcast('broadcast.viewOnlineBrochureController.updateBrochureData', brochure);
    }

}
viewOnlineRequestModalForm.$inject = ['$scope','$timeout'];
function viewOnlineRequestModalForm($scope, $timeout) {
    //style modified for the privacy policy and security policy for modal from sitecore
    var formSection = $('body');
    var checkPolicyDiv = formSection.find(".form-footer-note");
    if (!checkPolicyDiv) {
        console.log("No policy is set from sitecore");
    } else {
        $(".form-footer-note").children("text").eq(1).html("|");
        var str = document.getElementsByClassName("form-footer-note")[0].innerHTML.replace('#', '');
        $(".form-footer-note").html(str);
        $(".form-footer-note").addClass("view-online-brochure-modal-policies-margin");
        $(".form-footer-note").children("a").addClass("view-online-brochure-modal-policies-anchor");
    }
    var vormf = this;
    vormf.form = {
        brochureId: '',
        brochureTitle: '',
        includeDvd: false,
        country: '',
        isSubmitButtonDisabled: false,
        isSubscribeNewsletter: false,
        isSubmitted: false,
    }

    vormf.init = init; 
    vormf.viewOnlineSubmitBrochureForm = viewOnlineSubmitBrochureForm;
    function init(brochureId, brochureTitle) {
        vormf.form.brochureId = brochureId;
        vormf.form.brochureTitle = brochureTitle; 
    }
    $scope.$on('broadcast.viewOnlineBrochureController.updateBrochureData', function (event, brochure) {
        
        if (!(brochure && brochure.brochureId && brochure.brochureTitle && brochure.brochureImage && brochure.brochureImageAlt && brochure.ebrochureUrl)) {
            console.error('Error updating Brochure data controller');
            return;
        }
        $scope.brochureImage = brochure.brochureImage;
        $scope.brochureImageAlt = brochure.brochureImageAlt;
        $scope.ebrochureUrl = brochure.ebrochureUrl;
        $scope.$broadcast('broadcast.viewOnlineBrochureUrl.updateBrochureData', brochure);
        init(brochure.brochureId, brochure.brochureTitle, brochure.brochureImage, brochure.brochureImageAlt, brochure.ebrochureUrl);
    });
    function viewOnlineSubmitBrochureForm() {
        $scope.$broadcast('broadcast.viewOnlineBrochureFormSubmitController.submitBrochureForm');
    }
}
;
(function () {

    "use strict";

    angular.module('Phoenix.Shared.directives')
        .directive('browserWarning', [function () {
            return {
                scope: true,
                restrict: 'A',
                link: function (scope, element) {

                    scope.browserVersion = '';
                    var $el = angular.element(element);

                    var ie = getIEVersion();
                    if (ie.major != -1 && ie.major <= 10) {
                        $el.removeClass('hide');
                    }
                    else {
                        $el.remove();
                    }

                    function getIEVersion() {
                        var agent = navigator.userAgent;
                        var reg = /MSIE\s?(\d+)(?:\.(\d+))?/i;
                        var matches = agent.match(reg);
                        if (matches != null) {
                            scope.browserVersion = matches[1];
                            return { major: matches[1], minor: matches[2] };
                        }
                        return { major: "-1", minor: "-1" };
                    }
                }
            }
        }])
        .directive('globalNotification', ['$cookies', function ($cookies) {
        return {
            scope: true,
            restrict: 'A',
            link: function (scope, element) {

                var ACCEPTED_NOTIFICATION_KEY = 'ATG-Has-Accepted-Notification';
                var acceptCookie = $cookies.get(ACCEPTED_NOTIFICATION_KEY);
                var $el = angular.element(element);
                var $msgDesktop = $el.find('.notification-message-desktop').text();
                var $msgMobile = $el.find('.notification-message-mobile').text();

                if (acceptCookie === $msgDesktop + $msgMobile) {
                    $el.remove();
                }
                else {
                    $el.removeClass('is-hidden');
                }

                scope.closeNotification = function () {
                    $cookies.put(ACCEPTED_NOTIFICATION_KEY, $msgDesktop + $msgMobile);
                    $el.addClass('is-hidden');
                }  
            }
        }
    }])
    .directive('cookieDisclaimer', ['$timeout', '$cookies', function ($timeout, $cookies) {
        return {
            scope: true,
            restrict: 'A',
            link: function (scope, element) {

                var ACCEPTED_COOKIE_KEY = 'APT-Has-Accepted-Cookies';

                var acceptCookie = $cookies.get(ACCEPTED_COOKIE_KEY);

                var $el = angular.element(element);
                if (acceptCookie === 'true') {
                    $el.remove();
                }
                else {
                    $timeout(function () {
                        $el.removeClass('hide');
                    }, 1000);
                }

                scope.acceptDisclaimer = function () {
                    $cookies.put(ACCEPTED_COOKIE_KEY, 'true');

                    $el.addClass('hide');
                    $timeout(function () {
                        $el.remove();
                    }, 1000);
                }
            }
        }
    }]);
})();;
(function () {
    "use strict";

    function appendModalToBodyTag($el) {
        if (!$el || !$el.length) return;
        removeElementsWithSameId($el);
        $el.appendTo(document.body);
    }

    function removeElementsWithSameId($el) {
        // remove this element if it already exists in the dom
        var id = $el.attr('id');
        if (id) {
            var existingEl = angular.element('[id=' + id + ']');
            if (existingEl.length > 1) {
                existingEl.remove();
            }
        }
    }

    angular.module('Phoenix.Shared.directives')
        .directive('videoModal', ['$timeout', function ($timeout) {
            return {
                restrict: 'A',
                link: function (scope, element, attrs) {
                    var $el = angular.element(element);

                    var $video = $el.find('.video-embed');

                    var mobileDevice = false;
                    if (typeof window.orientation !== 'undefined') {
                        var mobileDevice = true;
                    }
                    $timeout(function () {
                        appendModalToBodyTag(angular.element(element));
                    })

                    // stop video when this modal closes
                    $(document).on('hidden.bs.modal', function (e) {
                        // Remove and set the video src on modal close. This resets the video.
                        if (e.target === $video.context) {
                            var src = $video.attr("src");
                            $video.attr("src", "");
                            $video.attr("src", src);
                        }
                    });
                    $(document).on('shown.bs.modal', function (e) {
                        if (!mobileDevice && e.target === $video.context) {
                            $timeout(function () {
                                $video.each(function () {
                                    this.contentWindow.postMessage('{"event":"command","func":"' + 'playVideo' + '","args":""}', '*')
                                });
                            }, 500);
                        }
                    });
                }
            }
        }])

        .directive('tripRequestQuoteModal', ['$timeout', '$window', function ($timeout, $window) {
            return {
                restrict: 'A',
                templateUrl: 'requestQuoteModal.html',
                link: function (scope, element, attrs) {
                    var $el = angular.element(element);
                    setupFormId($el);
                    setupRadioButtons($el);
                    setupCheckboxes($el);

                    function setupRadioButtons($modal) {
                        $modal.find('input[type=radio]').map(function (index) {
                            $(this).next().andSelf().wrapAll("<div class='radio'>");
                        });
                        $modal.find('.radio').wrap("<div class='radio-inline'>");
                        $modal.find('.radio').on('click', function (e) {
                            $(this).find('input[type=radio]').prop("checked", true);
                        });
                    }

                    function setupCheckboxes($modal) {
                        var checkBox = $modal.find('input[type=checkbox]');
                        checkBox.attr('id', checkBox.attr('id') + '_' + Math.floor((Math.random() * 10000) + 1));
                        $modal.find('.checkbox').on('click', function (e) {
                            checkBox.prop("checked", !checkBox.prop('checked'));
                        });
                    }

                    function setupFormId($modal) {
                        var form = $modal.find('form');
                        if (form.length) {
                            form.attr('id', form.attr('id') + '_' + Math.floor((Math.random() * 10000) + 1));
                        }
                    }
                }
            }
        }])
        //feature online view brochure
        .directive('viewOnlineBrochureModal', ['$timeout', '$window', function ($timeout, $window) {
            return {
                restrict: 'A',
                templateUrl: 'requestViewOnlineModal.html',
                link: function (scope, element, attrs) {
                    var $el = angular.element(element);
                    setupFormId($el);
                    setupRadioButtons($el);
                    setupCheckboxes($el);

                    function setupRadioButtons($modal) {
                        $modal.find('input[type=radio]').map(function (index) {
                            $(this).next().andSelf().wrapAll("<div class='radio'>");
                        });
                        $modal.find('.radio').wrap("<div class='radio-inline'>");
                        $modal.find('.radio').on('click', function (e) {
                            $(this).find('input[type=radio]').prop("checked", true);
                        });
                    }

                    function setupCheckboxes($modal) {
                        var checkBox = $modal.find('input[type=checkbox]');
                        checkBox.attr('id', checkBox.attr('id') + '_' + Math.floor((Math.random() * 10000) + 1));
                        $modal.find('.checkbox').on('click', function (e) {
                            checkBox.prop("checked", !checkBox.prop('checked'));
                        });
                    }

                    function setupFormId($modal) {
                        var form = $modal.find('form');
                        if (form.length) {
                            form.attr('id', form.attr('id') + '_' + Math.floor((Math.random() * 10000) + 1));
                        }
                    }
                }
            }
        }])
        .directive('modalScrollFix', ['$window', '$document', '$timeout', '$rootScope', function ($window, $document, $timeout, $rootScope) {
            return {
                restrict: 'A',
                link: function (scope, element) {
                    var $el = angular.element(element);
                    var $window = $(window);
                    var currentScroll = 0;
                    var $body = $document.find('body');
                    var hasCarouselParent = $el.closest('.owl-carousel').length > 0;

                    // process this directive only once its parent carousel has initialised,
                    // or no parent exists, process on page load
                    if (hasCarouselParent) {
                        scope.$on('tripCardCarousel.carousel.afterInit', function () {
                            $timeout(function () {
                                doModalScrollFix();
                            });
                        });
                        scope.$on('upliftTripCardCarousel.carousel.afterInit', function () {
                            $timeout(function () {
                                doModalScrollFix();
                            });
                        });
                    }
                    else {
                        $timeout(function () {
                            doModalScrollFix();
                        });
                    }

                    function doModalScrollFix() {
                        if (!$el.hasClass('modal')) {
                            $el = $el.find('.modal');
                        }

                        $el.each(function () {
                            appendModalToBodyTag($(this));

                            if (Modernizr.touchevents) {
                                $(this).on('show.bs.modal', function () {
                                    currentScroll = document.body.scrollTop;
                                    $rootScope.$broadcast('broadcast.dynamicScrollApplied');

                                    setTimeout(function () {
                                        $body.addClass('modal-open-scroll-fix');
                                        $body.css({ 'top': '-' + currentScroll + 'px' });
                                    });
                                });

                                $(this).on('hidden.bs.modal', function () {
                                    $body.removeClass('modal-open-scroll-fix');
                                    $body.css({ 'top': '' });
                                    window.scroll(0, currentScroll); // scroll back to the last position of user
                                    $rootScope.$broadcast('broadcast.dynamicScrollApplied');
                                });
                            }
                        });
                    }
                }
            }
        }])
})();

//hiding policies for footer e-newsletter form
$(document).ready(function () {
    $(".site-content").children("#e-subscription").find(".form-footer-note").show();
    //hiding button from the home page e-newsletter form
    $(".site-content").children("#e-subscription").find(".success.success-redirect").show();
    //style modified for the privacy policy and security policy for modal from sitecore
    var formSection = $('body');
    var checkPolicyDiv = formSection.find(".form-footer-note");
    if (!checkPolicyDiv) {
        console.log("No policy is set from sitecore");
    } else {
        try {
            $(".form-footer-note").children("text").eq(1).html("|");
            var str = document.getElementsByClassName("form-footer-note")[0].innerHTML.replace('#', '');
            $(".form-footer-note").html(str);
            $(".form-footer-note").addClass("enhancement-popup-modal-policies-margin");
            $(".form-footer-note").children("a").addClass("enhancement-popup-modal-policies-anchor");
        } catch {}
    }
});

;
(function () {
    'use strict';

    angular
        .module('Phoenix.Shared.directives')
        .directive('multistepCarousel', ['$timeout', multistepCarousel])

    function multistepCarousel($timeout) {
        return {
            restrict: 'A',
            scope: true,
            link: link,
            controller: 'multistepCarouselControllers',
            controllerAs: 'mcc',
            bindToController: true
        };

        function link(scope, element, attr, ctrl) {

            var CAROUSEL = {};

            CAROUSEL.element = angular.element(element).find('.owl-carousel').addBack('.owl-carousel');
            CAROUSEL.init = function () {

                CAROUSEL.element.on('initialized.owl.carousel', function () {
                    scope.$broadcast('broadcast.multistepCarousel.initialized');
                });

                CAROUSEL.element.owlCarousel({
                    items: 1,
                    loop: false,
                    nav: false,
                    navText: false,
                    dots: false,
                    mouseDrag: false,
                    touchDrag: false,
                    customAutoHeight: true,
                    smartSpeed: 400
                });

                

                scope.$watch('mcc.steps.currentIndex', function (newValue, oldValue) {
                    // on initialization this watch will fire and newValue and oldValue. No need to do anything as we will already be on the first step.
                    CAROUSEL.element.trigger('to.owl.carousel', [newValue]);
                });

                scope.$on('broadcast.multistepCarousel.goToStep', function(e, args) {
                    ctrl.steps.goToStep(args.step);
                });

            }

            $timeout(function () {
                CAROUSEL.init();
            });

        }
    }

})();;
"use strict";

angular.module('Phoenix.Shared.directives')
    .directive('toggleNav', ['$timeout', function ($timeout) {
        return {
            restrict: 'A',
            scope: { 'toggleNav': '@' },
            link: function (scope, element, attrs) {

                var el = angular.element(scope.toggleNav);
                var gn = angular.element('.global-notification');

                element.bind('click', function () {
                    var hai = angular.element('.hamburger-animated-icon');
                    var sc = angular.element('.site-container');
                    var selScrollable = '.nav-menu';
                    if (el.hasClass('invisible')) {
                        hideUserMessages();
                        el.removeClass('invisible');
                        hai.addClass('open');
                        sc.addClass('noscroll-xs');
                        $('body').addClass('modal-open-xs');
                        $('body').addClass('hero-modal-open');
                    }
                    else {
                        showUserMessages();
                        el.addClass('invisible');
                        hai.removeClass('open');
                        sc.removeClass('noscroll-xs');
                        $('body').removeClass('modal-open-xs');
                        $('body').removeClass('hero-modal-open');
                    }
                });

                var hideUserMessages = function () {
                    $('.user-message').addClass('force-hide');
                    gn.addClass('force-hide');
                }

                var showUserMessages = function () {
                    $('.user-message').removeClass('force-hide');
                    gn.removeClass('force-hide');
                }
            }
        }
    }
    ])
    .directive('dropdownOpenOnTouchHover', ['$document', function ($document) {
        return {
            restrict: 'A',
            scope: true,
            link: function (scope, element, attrs) {

                var dropdownOpen = false;

                element.on('mouseenter', function () {
                    if (!isTouchDevice()) {
                        addOverlays();
                    }
                });

                element.on('mouseleave', function () {
                    if (!isTouchDevice()) {
                        removeOverlays();
                    }
                });

                $('html').on('tap click', function () {
                    if (dropdownOpen && isTouchDevice()) {
                        element.removeClass("open");
                        element.parent().removeClass("opened");
                        element.parent().parent().parent().removeClass("section-opened");
                        element.find('.navbar-dropdown-menu').removeClass('is-visible');
                        $('.site-overlay').removeClass('overlay-visible');

                        var bodyEl = $document.find('body');
                        $('.header.home-page').removeClass('scrollable');
                        bodyEl.removeClass("body-fixed");
                        dropdownOpen = false;
                    }
                });

                element.on('tap click', function (event) {
                    dropdownOpen = true;
                    event.stopPropagation();
                    if (isTouchDevice()) {
                        $('.navbar-dropdown').removeClass("open");
                        element.addClass("open");
                        element.parent().addClass("opened");
                        element.parent().parent().parent().addClass("section-opened");
                        element.find('.navbar-dropdown-menu').addClass('is-visible');
                        $('.site-overlay').addClass('overlay-visible');
                        var bodyEl = $document.find('body');
                        $('.header.home-page').addClass('scrollable');
                        bodyEl.addClass("body-fixed");
                    }
                });

                function addOverlays() {
                    element.addClass("open");
                    element.parent().addClass("opened");
                    element.parent().parent().parent().addClass("section-opened");
                    element.find('.navbar-dropdown-menu').addClass('is-visible');
                    $('.site-overlay').addClass('overlay-visible');
                    $('.site-container').addClass('offset-scrollbar');
                    var bodyEl = $document.find('body');
                    bodyEl.addClass("body-fixed");
                    $('.header.home-page').addClass('scrollable');
                    dropdownOpen = !dropdownOpen;
                }

                function removeOverlays() {
                    element.removeClass("open");
                    element.parent().removeClass("opened");
                    element.parent().parent().parent().removeClass("section-opened");
                    element.find('.navbar-dropdown-menu').removeClass('is-visible');
                    $('.site-overlay').removeClass('overlay-visible');
                    $('.header.home-page').removeClass('scrollable');
                    $('.site-container').removeClass('offset-scrollbar');
                    var bodyEl = $document.find('body');
                    bodyEl.removeClass("body-fixed");
                    $('.header.home-page').removeClass('scrollable');
                    dropdownOpen = !dropdownOpen;
                }
                function isTouchDevice() {
                    try {
                        document.createEvent("TouchEvent");
                        return true;
                    } catch (e) {
                        return false;
                    }
                }
            }
        }
    }
    ])
    .directive('stickyNav', ['$window', '$timeout', '$rootScope', function ($window, $timeout, $rootScope) {
        return {
            restrict: 'A',
            controller: stickyNavController,
            controllerAs: 'snc',
            bindToController: true,
            link: function (scope, element, attrs, ctrl) {

                var $el = angular.element(element);
                var isAnimating = false;
                var window = angular.element($window);
                var margin;
                var offsetTop;
                var offsetHeight;

                var setOffsets = function () {
                    margin = $el.outerHeight();
                    var navEl = angular.element(element).parent();
                    if (!ctrl.hasAnchorLinks) {
                        navEl.remove();
                        return;
                    }
                    var offset = $(navEl).offset();
                    offsetTop = offset.top;
                    offsetHeight = offset.height;
                }

                var setupMenu = function () {

                    if (window.scrollTop() > offsetTop) {
                        element.addClass('nav-sticky');
                    }
                    else {
                        element.removeClass('nav-sticky');
                    }
                    if (isAnimating) return;
                    var isActiveSet = false;

                    var ii = 0;
                    // loop through the nav items from last to first
                    for (var i = ctrl.navItems.length - 1; i >= 0; i--) {
                        if (!isActiveSet) {
                            var el = angular.element('#' + ctrl.navItems[i].id);
                            if (el.length) {
                                // if the current nav item has been scrolled to...
                                if (i == 0 || window.scrollTop() > el.offset().top - margin) {
                                    // if the current item has been scrolled past, and it is last in the list
                                    // set no item as selected
                                    if (ii == 0 && el.next().length && window.scrollTop() > el.next().offset().top - margin) {
                                        setActiveById(ctrl.navItems[i].id, false);
                                        isActiveSet = false;
                                        element.removeClass('is-active');
                                        break;
                                    }
                                    setActiveById(ctrl.navItems[i].id, true);
                                    isActiveSet = true;
                                }
                                else {
                                    setActiveById(ctrl.navItems[i].id, false)
                                }
                                ii++;
                            }
                        }
                        else {
                            setActiveById(ctrl.navItems[i].id, false);
                        }
                    }
                }

                var setActiveById = function (id, isActive) {
                    for (var i = 0; i < ctrl.navItems.length; i++) {
                        if (ctrl.navItems[i].id == id) {
                            ctrl.navItems[i].isActive = isActive;
                        }
                    }
                    if (isActive) {
                        element.addClass('is-active');
                    }
                    scope.$apply();
                }

                var scrollTo = function(elementId) {
                    var target = angular.element('#' + elementId)[0];

                    if (typeof target === 'undefined') {
                        return false;
                    }

                    angular.element('html, body').stop().animate({ 
                        scrollTop: target.offsetTop - (margin - 5) 
                    }, 'slow', function () { 
                        isAnimating = false; 
                    });
                }

                var deepLinking = function () {

                    var hash = $window.location.hash.substr(1);
                    var result = ctrl.navItems.filter(function(item){
                        return item.id === hash;
                    })

                    if(hash.length && result.length) {
                        scrollTo(hash);
                    }
                }

                $timeout(function () {
                    setOffsets();
                }, 700);

                window.on('resize', function () {
                    setOffsets();
                    setupMenu();
                });

                window.on('scroll touchmove', setupMenu);

                window.on('load', deepLinking);

                $rootScope.$on('broadcast.dynamicScrollApplied', function (event, args) {
                    setOffsets();
                });

                scope.$on('broadcast.stickyNavLinkClicked', function (event, args) {
                    isAnimating = true;
                    scrollTo(args.id);
                });
            }
        }
    }
    ]);

stickyNavController.$inject = ['$scope'];

function stickyNavController($scope) {

    var snc = this;
    snc.navItems = [];

    snc.hasAnchorLinks = false;

    snc.init = function () {
        for (var i = 0; i < arguments.length; i++) {
            snc.navItems.push({
                id: arguments[i],
                isActive: i == 0 ? true : false
            });
        }
    }

    snc.isActive = function (id) {
        for (var i = 0; i < snc.navItems.length; i++) {
            if (snc.navItems[i].id == id) {
                return snc.navItems[i].isActive;
            }
        }
        return false;
    }

    snc.scrollTo = function (id) {
        setActive(id);
        $scope.$broadcast('broadcast.stickyNavLinkClicked', { id: id });
    }

    snc.anchorExists = function (id) {
        var anchorExists = angular.element('#' + id).length > 0;
        if (anchorExists) {
            snc.hasAnchorLinks = true;
        }
        return anchorExists;
    }

    var setActive = function (id) {
        for (var i = 0; i < snc.navItems.length; i++) {
            if (snc.navItems[i].id == id) {
                snc.navItems[i].isActive = true;
            }
            else {
                snc.navItems[i].isActive = false;
            }
        }
    }

}
;
"use strict";

(function () {

    angular.module('Phoenix.Shared.directives')
        .directive('quickViewBrochure', ['$window', function ($window) {
            return {
                restrict: 'E',
                scope: true,
                controllerAs: 'qvbc',
                controller: quickViewBrochureController,
                bindToController: true,
                link: function (scope, element, attrs, ctrl) {

                    var window = angular.element($window);
                    var navTabs = angular.element('.trip-tabs');

                    var $el = angular.element(element);
                    var elementDistance = 0;

                    // reset the button element offset distance from the top of the window
                    // when it is resized
                    window.on('resize', function () {
                        elementDistance = 0;
                    });

                    window.on('scroll', function () {

                        if (ctrl.site === 'cc') {
                            if (this.pageYOffset >= 100) {
                                ctrl.isBrochureBtnVisible = true;
                            } else {
                                ctrl.isBrochureBtnVisible = false;
                            }                            
                        }
                        else {
                            var triggerOutPriceAndBooking = angular.element('#trip-priceandbooking');
                            var triggerOutPackageSelection = angular.element('#trip-package-selection');
                            var hasScrolledIn = navTabs.hasClass("nav-sticky");
                            var hasScrolledOut = false;

                            // Hide button when price and booking scrolls into view,
                            // but re-display when the following container scrolls into view.
                            if (triggerOutPriceAndBooking.length || triggerOutPackageSelection.length) {

                                var scrollTop = $(window).scrollTop();
                                var windowHeight = window.height();
                                var triggeredElement = triggerOutPriceAndBooking.length ? triggerOutPriceAndBooking : triggerOutPackageSelection;

                                if ((scrollTop + windowHeight) > triggeredElement.offset().top) {
                                    hasScrolledOut = true;
                                }

                                if ((scrollTop + windowHeight) > triggeredElement.offset().top + $(triggeredElement).outerHeight()) {
                                    hasScrolledOut = false;
                                }
                            }

                            if (hasScrolledIn && !hasScrolledOut)
                                ctrl.isBrochureBtnVisible = true;
                            else
                                ctrl.isBrochureBtnVisible = false;
                        }                        
                    });
                }
            };
        }]);

    quickViewBrochureController.$inject = ['$scope'];

    function quickViewBrochureController($scope) {

        var qvbc = this;

        qvbc.isBrochureBtnVisible = false;
        qvbc.modalVisible = false;
        qvbc.brochureUrl = '';
        qvbc.site = '';
        var brochureIcon = angular.element('.btn-quick-view-brochure');
        var backToTopIcon = angular.element('.btn-back-to-top');
        var body = angular.element('body');
        qvbc.showModal = function () {
            if (!qvbc.modalVisible) {
                brochureIcon.hide();
                backToTopIcon.hide();
                qvbc.modalVisible = true;
                body.addClass('has-modal-open');
                body.bind('touchmove', false);
            }
        };
        qvbc.hideModal = function () {
            qvbc.modalVisible = false;
            brochureIcon.show();
            backToTopIcon.show();
            body.removeClass('has-modal-open');
            body.unbind('touchmove');
        };

        qvbc.init = function (brochureUrl, site) {
            qvbc.brochureUrl = brochureUrl;
            qvbc.site = site;
        };
    }

})();;
(function () {

    "use strict";

    angular.module('Phoenix.Shared.directives')
        .directive('searchPage', ['$timeout', '$rootScope', '$window', 'searchService', 'utilityService', searchPage])
        .directive('searchHero', ['$timeout', searchHero])
        .directive('searchResults', ['$timeout', searchResults])
        .directive('searchFilters', ['$timeout', '$document', searchFilters])
        .directive('searchInput', ['$analytics', function ($analytics) {
            return {
                scope: {
                    searchKeyword: '=ngModel',
                    placeholder: '@',
                    inputId: '@',
                    inputClass: '@',
                    buttonClass: '@',
                    iconClass: '@',
                    inputMaxlength: '=',
                    onClear: '&',
                    analyticsEventAction: '@'
                },
                restrict: 'E',
                templateUrl: '/assets/js/phoenix/shared/ng/templates/searchReset.html',
                link: function (scope, element, attrs, ctrl) {
                    scope.resetSearch = function () {
                        scope.searchKeyword = '';
                    };

                    if (scope.analyticsEventAction) {
                        element.find('input').on('focus', function () {
                            $analytics.eventTrack(null, {
                                category: "Global Navigation",
                                action: scope.analyticsEventAction,
                                label: "Search Opened"
                            });
                        });
                    }
                }
            }
        }])
        .directive('searchForm', ['$analytics', function ($analytics) {
            return {
                scope: true,
                restrict: 'A',
                link: function (scope, element, attrs, ctrl) {
                    scope.searchFormSubmit = function (form, $event) {
                        if (form.$invalid) {
                            $event.preventDefault();
                        } else if (attrs.analyticsEventAction) {
                            $analytics.eventTrack(null, {
                                category: "Global Navigation",
                                action: attrs.analyticsEventAction,
                                label: "Query - " + element.find('input').val()
                            });
                        }
                    };
                }
            }
        }]);

    function searchPage($timeout, $rootScope, $window, searchService, utilityService) {
        var directive = {
            restrict: 'A',
            scope: true,
            controller: searchController,
            controllerAs: 'sc',
            bindToController: true,
            link: link
        };
        function link(scope, element, attr, ctrl) {

            var isRedirect = false;

            var loadResults = function (pageSize, pageNumber, disableRedirect) {

                return searchService.GetResults(
                    ctrl.search.filters.keywords, ctrl.search.filters.categories, pageSize, pageNumber)
                    .then(function (data) {
                        isRedirect = false;
                        if (data) {

                            ctrl.search.loadingMoreResults = false;

                            ctrl.results.count = data.Total;
                            if (data.Data && data.Data.length) {

                                if (!disableRedirect && data.Total === 1 && data.Data[0].TripData) {
                                    doRedirectOnSingleTripResult(data.Data);
                                    return;
                                }

                                ctrl.results.nextPage = data.Data;
                            }

                            // intialise any new Request Quote forms, notify event listeners that new images are present
                            $timeout(function () {
                                AptForm.Initialise();
                                CaptchaCallback();
                                $rootScope.$broadcast('broadcast.dom-manipulation.image');
                            });
                        }
                    });
            };

            var loadAutocomplete = function () {

                return searchService.GetAutocomplete()
                    .then(function (data) {
                        if (data) {
                            ctrl.search.autocomplete.data = data.Data;
                        }
                    });
            };

            var getResults = function () {
                ctrl.search.loadingMoreResults = true;
                ctrl.results.data = ctrl.results.data.concat(ctrl.results.nextPage);

                // only preload the next set of results if there are more to load
                if (ctrl.results.count > ctrl.results.data.length) {
                    loadResults(ctrl.search.pageSize, ctrl.search.pageIndex + 1);
                }
            };

            var initResults = function (disableRedirect) {
                ctrl.search.loadingResults = true;
                ctrl.search.loadingMoreResults = false;
                // load 2 pages worth of results in one go
                return loadResults(ctrl.search.pageSize * 2, 0, disableRedirect).then(function () {
                    // split the results - returned array from the start becomes the current page, remainder of the array remains in the nextPage variable
                    ctrl.results.data = ctrl.results.nextPage.splice(0, ctrl.search.pageSize);
                });
            };

            var setSelections = function () {
                ctrl.search.filters.categories = cleanSelectedOptions(utilityService.GetArrayFromCommaString(utilityService.GetQueryStringParameters('category')), '.js-section-category');
                ctrl.search.filters.keywords = utilityService.GetQueryStringParameters('search');
                ctrl.search.previous.keywords = ctrl.search.filters.keywords;

            };

            var doRedirectOnSingleTripResult = function (results) {
                isRedirect = true;
                $window.location.href = results[0].Url;
            }

            /*
            filtering the array and returning the selected options based on valid filter options
            @param arr Array trip values received in GET request
            @param key String DOM selector that checks for matching key
            @return Array the matched value in the key
            */
            var cleanSelectedOptions = function (arr, key) {
                var cleanedArray = [];

                for (var i = 0; i < arr.length; i++) {
                    var $selectedKey = $(key + '  [data-key="' + arr[i] + '"]');

                    if ($selectedKey.length) { // we add the matching key to the array if it has been found
                        cleanedArray.push(arr[i]);
                    }
                }
                return cleanedArray;
            };

            var filterUpdateCount = 0;
            var filterUpdateCompleteCount = 0;

            scope.$on('broadcast.searchController.searchFiltersUpdated', function (e, args) {
                filterUpdateCount++;
                ctrl.results.data = [];
                ctrl.results.nextPage = [];
                ctrl.search.pageIndex = 0;
                var disableRedirect = args && args.disableRedirect ? true : false;
                initResults(disableRedirect).then(function () {
                    filterUpdateCompleteCount++;
                    if (!isRedirect) {
                        if (filterUpdateCompleteCount >= filterUpdateCount) {
                            ctrl.search.loadingResults = false;
                            filterUpdateCount = 0;
                            filterUpdateCompleteCount = 0;
                        }
                    }
                });
            });

            scope.$on('broadcast.searchController.selectSortOption', function () {
                ctrl.results.data = [];
                ctrl.results.nextPage = [];
                ctrl.search.pageIndex = 0;
                initResults().then(function () {
                    if (!isRedirect) {
                        ctrl.search.loadingResults = false;
                    }
                });
            });

            scope.$on('broadcast.searchController.showMoreResults', function () {
                // only load more if there are more to load
                if (ctrl.results.count > ctrl.results.data.length) {
                    ctrl.search.pageIndex++;
                    getResults();
                }
            });

            scope.$on('broadcast.searchController.tripFinderOverlay', function () {

                var $htmlBody = angular.element('html body');
                var $siteOverlay = angular.element('.site-overlay-secondary');
                var $siteSearchHero = angular.element('.site-search__hero');

                if (ctrl.search.open === true) {
                    $siteOverlay.addClass('is-visible');
                }
                else if (ctrl.search.open === false) {
                    $siteOverlay.removeClass('is-visible');
                    $htmlBody.animate({
                        scrollTop: $('#search-page-hero-carousel').offset().top
                    }, 500);
                }

            });

            (function () {
                loadAutocomplete();
                setSelections();
                initResults().then(function () {
                    if (!isRedirect) {
                        ctrl.search.loadingResults = false;
                    }
                });
            })();
        }

        return directive;
    }

    function searchHero($timeout) {
        var directive = {
            restrict: 'A',
            scope: true,
            require: '^searchPage',
            link: link
        };
        function link(scope, element, attr, ctrl) {

            scope.$on('broadcast.searchController.setKeyword', function (e, args) {
                $timeout(function () {
                    var form = angular.element(element).find('form');
                    if (form.length) {
                        form.submit();
                    }
                });
            });
        }
        return directive;
    }

    function searchResults($timeout) {
        var directive = {
            restrict: 'A',
            scope: true,
            require: '^searchPage',
            link: link
        };

        function link(scope, element, attr, ctrl) {

        }

        return directive;
    }

    searchController.$inject = ['$scope'];
    function searchController($scope) {

        var sc = this;
        sc.search = {
            open: false,
            filters: {
                keywords: '',
                categories: []
            },
            autocomplete: {
                data: [],
                open: false
            },
            previous: {
                keywords: ''
            },
            filterCount: 0,
            pageIndex: 0,
            pageSize: 10,

            toggleOpen: toggleSearchOpen,
            hideSearch: hideSearch,
            hideAutocomplete: hideAutocomplete,
            showAutocomplete: showAutocomplete,
            toggleSelection: toggleSearchSelection,
            isOptionSelected: isSearchOptionSelected,
            clearSectionSelections: clearSectionSelections,
            clearSelections: clearSelections,
            clearKeywords: clearKeywords,
            setKeyword: setKeyword,
            doSearch: doSearch,
            showMoreResults: showMoreResults,
            loadingResults: false,
            loadingMoreResults: false
        };
        sc.results = {
            count: 0,
            data: [],
            nextPage: [],
            remainingCount: remainingResultsCount
        };

        sc.requestQuote = requestQuote;

        $scope.$watch('sc.search.filters.categories', function () {
            setFilterCount();
        }, true);

        function setFilterCount() {
            sc.search.filterCount =
                (sc.search.filters.categories.length ? 1 : 0);
        }

        function toggleSearchOpen() {
            sc.search.open = !sc.search.open;
            $scope.$broadcast('broadcast.searchController.tripFinderOverlay');
        }

        function showAutocomplete() {
            if (sc.search.filters.keywords && sc.search.filters.keywords.length >= 1) {
                sc.search.autocomplete.open = true;
            }
            else {
                sc.search.autocomplete.open = false;
            }
        }

        function hideAutocomplete() {
            sc.search.autocomplete.open = false;
        }

        function hideSearch() {
            sc.search.open = false;
            $scope.$broadcast('broadcast.searchController.tripFinderOverlay');
        }

        function toggleSearchSelection(id, arr, disableRedirect) {
            var exists = false;
            for (var i = 0; i < arr.length; i++) {
                if (arr[i] == id) {
                    exists = true;
                    arr.splice(i, 1);
                    break;
                }
            }
            if (!exists) {
                arr.push(id);
            }
            $scope.$broadcast('broadcast.searchController.searchFiltersUpdated', { disableRedirect: disableRedirect });
        }

        function isSearchOptionSelected(id, arr) {
            for (var i = 0; i < arr.length; i++) {
                if (arr[i] == id) {
                    return true;
                }
            }
            return false;
        }

        function clearSectionSelections(arr) {
            if (arr.length) {
                arr.splice(0, arr.length);
                $scope.$broadcast('broadcast.searchController.searchFiltersUpdated');
            }

        }

        function clearSelections() {
            sc.search.filters.categories = [];
            $scope.$broadcast('broadcast.searchController.searchFiltersUpdated');
        }

        function clearKeywords() {
            sc.search.filters.keywords = '';
        }

        function doSearch() {
            $scope.$broadcast('broadcast.searchController.setKeyword');
        }

        function setKeyword(item) {
            sc.search.filters.keywords = item;
            sc.search.hideAutocomplete();
            $scope.$broadcast('broadcast.searchController.setKeyword');
        }

        function showMoreResults() {
            $scope.$broadcast('broadcast.searchController.showMoreResults');
        }

        function remainingResultsCount() {
            var shownCount = sc.search.pageIndex == 0 ? sc.search.pageSize : (sc.search.pageIndex + 1) * sc.search.pageSize;
            var remaining = sc.results.count > shownCount ? sc.results.count - shownCount : 0;
            return remaining;
        }

        function requestQuote(trip, tripName) {
            var formSection = $('[data-trip-request-quote-form] .js-form-section');
            formSection.show().next().hide();

            var tripObject = Object.assign({}, trip, {
                Name: tripName
            });

            $scope.$broadcast('broadcast.tripFinderController.updateTripData', tripObject);
        }
    }

    function searchFilters($timeout, $document) {
        var directive = {
            restrict: 'A',
            scope: true,
            require: '^searchPage',
            link: link
        };

        function link(scope, element, attr, ctrl) {
            // adapted from clickOutside common directive
            var onClick = function (event) {

                // is the element the search box or one of its children?
                var isChild = $(element).has(event.target).length > 0;
                var isSelf = element[0] == event.target;
                var isInside = isChild || isSelf;
                if (!isInside) {
                    // have to do this in scope.$apply() so that angular knows that we are changing things
                    // otherwise the view won't be updated (search filters hidden) until the next user interaction
                    scope.$apply(function () {
                        ctrl.search.hideSearch();
                    });
                }
            };

            // only turn on the event listener when the search box is actually open
            scope.$watch(function () { return ctrl.search.open; }, function (newValue, oldValue) {
                if (newValue !== oldValue && newValue === true) {
                    $document.bind('tap click', onClick);
                } else if (newValue !== oldValue && newValue === false) {
                    $document.unbind('tap click', onClick);
                }
            });
        }
        return directive;
    }
})();
;
(function(){

"use strict";

    angular
        .module('Phoenix.Shared.directives')
        .directive('tripItinerary', tripItinerary)
        .directive('tripOverviewZoomableImg', tripOverviewZoomableImg)
        .directive('tripPdfDownload', tripPdfDownload);

        tripItinerary.$inject = ['$window', '$document'];

        function tripItinerary($window, $document) {
            var directive = {
                restrict: 'AE',
                scope: true,
                replace: 'true',
                link: link,
                controller: tripItineraryController,
                controllerAs: 'tic'
            };
            return directive;
        }

        function link(scope, element, attrs, ctrl) {

            var $el = angular.element(element);
            checkRemainingItems();

            scope.$on('broadcast.tripItineraryController.LoadMoreDays', function() {
                loadMoreDays();
            });

            scope.$on('broadcast.tripItineraryController.ToggleExpandAllDays', function () {
                loadAllDays();
                toggleExpandAllDays();
            });

            function checkRemainingItems(){
                if(!$el.find('.force-hide').length) {
                    ctrl.AllItemsVisible = true;
                }
            }

            function loadMoreDays() {
                var $hiddenItineraryDays = $el.find('.force-hide');
                var limit = ctrl.takeCount;

                $hiddenItineraryDays.each(function (index) {
                    var $currentItem = $hiddenItineraryDays.eq(index); // get the item by index
                    $currentItem.removeClass('force-hide');
                    if (index === (limit - 1)) { // subtract 1 as index starts from 0
                        return false;
                    }
                });
                checkRemainingItems();
            }

            function loadAllDays() {
                var $hiddenItineraryDays = $el.find('.force-hide');
                $hiddenItineraryDays.removeClass('force-hide');
                ctrl.AllItemsVisible = true;
            }

            function toggleExpandAllDays() {
                var action = ctrl.AllDaysExpanded ? 'hide' : 'show';
                $el.find('.panel-collapse').collapse(action);
                ctrl.AllDaysExpanded = !ctrl.AllDaysExpanded;
            }
        }

        // Controller
        tripItineraryController.$inject = ['$filter', '$scope'];

        function tripItineraryController($filter, $scope) {

            var tic = this;
            tic.AllItemsVisible = false;
            tic.takeCount = 1;
            tic.AllDaysExpanded = false;

            // bind functions
            tic.loadMoreDays = loadMoreDays;
            tic.toggleExpandAllDays = toggleExpandAllDays;
            tic.init = init;
            tic.formatPrice = formatPrice;

            function init(takeCount) {
                tic.takeCount = takeCount;
            }

            function loadMoreDays() {
                $scope.$broadcast('broadcast.tripItineraryController.LoadMoreDays');
            }

            function toggleExpandAllDays() {
                $scope.$broadcast('broadcast.tripItineraryController.ToggleExpandAllDays');
            }

            function formatPrice(value, symbol) {
                return $filter('currency')(value, symbol, 0);
            }
        }

    tripOverviewZoomableImg.$inject = ['$window', '$document', '$timeout', '$interval'];

    function tripOverviewZoomableImg($window, $document, $timeout, $interval) {
        var directive = {
            restrict: 'A',
            scope: true,
            replace: 'true',
            link: function (scope, element, attrs) {

                var $element = angular.element(element);
                var src = attrs['src'];
                var alt = attrs['alt'] || '';

                // --- Zoom animation parameters ---
                // Zoom animation duration (0 to disable - betwen 50 to disable and 5000ms)
                var animationTime = parseInt(attrs['zoomingAnimationTime']) || 1000;
                // Zoom animation interval delay (betwen 1 and 5000ms) - Lower => CPU intensive
                var animationDelay = parseInt(attrs['zoomingAnimationIntervalDelay']) || 20;

                var maxZoomMultiplier = 1.6;
                var dynamicSizeRegex = new RegExp(/useCustomFunctions=1&rw=(\d*)&w=(\d*)&h=(\d*)&cropX=(\d*)&cropY=(\d*)/i);

                // --- Animation internal setup ---
                var _shouldAnimate = (animationTime > 0);
                var _animationInterval;
                var _animationStep = 0;

                // - Bound values to prevents incorrect calculations
                var _animationTime = Math.min(5000, Math.max(50, animationTime));
                var _animationDelay = Math.min(5000, Math.max(1, animationDelay));
                var _animationStepSize = Math.min(1, Math.max(0.0002, 1 / (_animationTime / _animationDelay)));

                // --- Initialize variables ---
                var mouse = { x: 0, y: 0 };
                var _originalWidth, _originalHeight;
                var _naturalWidth, _naturalHeight;
                var _imageXDiff, _imageYDiff;
                var containerOffset;
                var magnifiedContainer;
                var modalContainer;

                var createZoomContainer = function () {
                    // Wrap original image into relative position div
                    $element.wrap('<div style="position: relative;"></div>');

                    magnifiedContainer = angular.element('<div></div>');
                    magnifiedContainer.addClass('zoomable-img-magnifier');

                    magnifiedContainer.css({
                        'background-image': 'url(' + src + ')',
                        'background-position': '0 0',
                        'background-size': _originalWidth + 'px ' + _originalHeight + 'px'
                    });

                    // --- Attach mouse listeners
                    var mouseMoveCounter;
                    var hasAnimate = false;
                    magnifiedContainer.on('mouseenter', function (e) {
                        // Reset mouseMoveCounter
                        mouseMoveCounter = 0;
                        hasAnimate = false;
                    });

                    magnifiedContainer.on('mousemove', function (e) {
                        mouseMoveCounter++;

                        // Only trigger the zoom if the mouse has moved long enough over the image 
                        // to prevent touch / tap event from triggering the zoom animation
                        if (mouseMoveCounter > 3 && !hasAnimate) {
                            hasAnimate = true;

                            if (_shouldAnimate) {
                                animate(1);
                            } else {
                                _animationStep = 1;
                            }
                        }
                        // If mouse moves over container, and is not animating:
                        // - Update magnification position
                        updateMousePosition(e);
                        magnify();
                    });

                    magnifiedContainer.on('mouseout', function (e) {
                        // If mouse leaves container area:
                        // - Trigger zoom-out animation
                        updateMousePosition(e);
                        if (_shouldAnimate) {
                            animate(-1);
                        } else {
                            _animationStep = 0;
                            magnify();
                        }
                    });

                    magnifiedContainer.on('click', function (e) {
                        openModal();
                    });

                    // --- Append zoomed image container after original element
                    $element.after(magnifiedContainer);
                };

                // Hammer.js returns relative transformation information (scale, deltaX,...)
                // Create some holders to calculate successive transformations from previous state:
                // - original (values when first opening modal)
                // - start (base value for current calculation)
                // - current (temporary/intermediate values)
                var original, start, current;

                // Creates the modal container, attaches modal/zoom events and add element to the DOM
                var createModalContainer = function () {

                    var modalContainerDOM = [];
                    modalContainerDOM.push('<div class="modal fade zoomable-img-modal" role="dialog" data-modal-scroll-fix data-modal data-modal-xs>');
                    modalContainerDOM.push('    <div class="modal-dialog">');
                    modalContainerDOM.push('        <div class="modal-content">');
                    modalContainerDOM.push('            <div class="modal-header">');
                    modalContainerDOM.push('                <div class="modal-header__close">');
                    modalContainerDOM.push('                    <button class="close-notification" data-dismiss="modal">');
                    modalContainerDOM.push('                        <span class="close-notification__text">Close</span><i class="close-notification__icon icon-cancel"></i>');
                    modalContainerDOM.push('                    </button>');
                    modalContainerDOM.push('                </div>');
                    modalContainerDOM.push('            </div>');
                    modalContainerDOM.push('            <div class="modal-body">');
                    modalContainerDOM.push('                <img class="img-responsive" src="' + src + '" alt="' + alt + '" />');
                    modalContainerDOM.push('            </div>');
                    modalContainerDOM.push('        </div>');
                    modalContainerDOM.push('    </div>');
                    modalContainerDOM.push('</div>');

                    var modalContainerDOMStr = '';
                    for (var i = 0; i < modalContainerDOM.length; ++i) {
                        modalContainerDOMStr += modalContainerDOM[i].trim();
                    }

                    modalContainer = angular.element(modalContainerDOMStr);

                    modalContainer.on('shown.bs.modal', function (e) {
                        // Modal is visible
                        calculateModalSize();

                        // Initialize default value
                        resetOriginal();
                    });

                    modalContainer.on('hidden.bs.modal', function (e) {

                        // Reset values to original
                        start = Object.assign({}, original);
                        current = Object.assign({}, original);

                        // Revert css change
                        resetModalImgStyle();
                    });

                    $document.find('body').append(modalContainer);

                    var modalImg = modalContainer.find('img.img-responsive');
                    var modalBody = modalContainer.find('.modal-body');

                    // Configure Hammer.js to raise pinch and pan events
                    var hammer = new Hammer.Manager(modalImg[0]);
                    hammer.add(new Hammer.Pan({ pointers: 0 }));
                    hammer.add(new Hammer.Pinch());
                    hammer.add(new Hammer.Tap({ taps: 2, interval: 500 }));

                    // On pinch event
                    hammer.on('pinch', function (e) {
                        // Get the absolute scale from a relative event scale
                        // Limit the scale from 1 (original display size) to max (natural image size)
                        current.scale = Math.min(_naturalWidth / original.w, Math.max(1, e.scale * start.scale));

                        // Calculate and register current size
                        current.w = original.w * current.scale;
                        current.h = original.h * current.scale;

                        // Calculate zoom position
                        if (current.pinchCenter === null) {
                            // We want the center of the pinch to remain the same during the whole action
                            // Only calculate it the first time
                            current.pinchCenter = getCenterFromEvent(e);

                            current.pinchCenterOffset = {
                                x: current.pinchCenter.x * start.scale - (-start.x * start.scale + Math.min(original.w, start.w) / 2),
                                y: current.pinchCenter.y * start.scale - (-start.y * start.scale + Math.min(original.h, start.h) / 2)
                            };
                        }

                        var zoomCenter = {
                            x: (current.pinchCenter.x * current.scale - current.pinchCenterOffset.x) / current.scale,
                            y: (current.pinchCenter.y * current.scale - current.pinchCenterOffset.y) / current.scale
                        };

                        var imageCenter = {
                            x: -current.x + original.w / 2 / current.scale,
                            y: -current.y + original.h / 2 / current.scale
                        };

                        registerCurrentPosition({
                            x: current.x + (imageCenter.x - zoomCenter.x),
                            y: current.y + (imageCenter.y - zoomCenter.y)
                        });

                        zoomToCurrent();
                    });

                    hammer.on('pinchend', function (e) {
                        // Keep values as new start values for future transform
                        start.w = current.w;
                        start.h = current.h;
                        start.x = current.x;
                        start.y = current.y;
                        start.scale = current.scale;

                        // Reset pinchCenter to recalculate during next pinch event
                        current.pinchCenter = null;
                    });

                    hammer.on('pan', function (e) {
                        // Calculate and register position
                        registerCurrentPosition({
                            x: start.x + (e.deltaX / current.scale),
                            y: start.y + (e.deltaY / current.scale)
                        });

                        zoomToCurrent();
                    });

                    hammer.on('panend', function (e) {
                        // Keep values as new start values for future transform
                        start.x = current.x;
                        start.y = current.y;
                    });

                    hammer.on('tap', function (e) {
                        // Zoom to max scale
                        current.scale = Math.min(maxZoomMultiplier, _naturalWidth / original.w);

                        // Calculate and register current size
                        current.w = original.w * current.scale;
                        current.h = original.h * current.scale;

                        var center = getCenterFromEvent(e);

                        var imageCenter = {
                            x: -current.x + original.w / 2 / current.scale,
                            y: -current.y + original.h / 2 / current.scale
                        };

                        registerCurrentPosition({
                            x: current.x + (imageCenter.x - center.x),
                            y: current.y + (imageCenter.y - center.y)
                        });

                        zoomToCurrent();

                        // Save values as new start values for future transformations
                        start.w = current.w;
                        start.h = current.h;
                        start.x = current.x;
                        start.y = current.y;
                        start.scale = current.scale;
                    });

                    var getCenterFromEvent = function (e) {
                        var imgRect = modalImg[0].getBoundingClientRect();

                        var center = {
                            x: -start.x + (e.center.x - imgRect.left) / start.scale,
                            y: -start.y + (e.center.y - imgRect.top) / start.scale
                        };

                        return center;
                    };

                    var registerCurrentPosition = function (newPosition) {
                        // Bound values and save to current
                        var viewportW = Math.max(modalBody.width(), original.w);

                        current.x = Math.min(0, Math.max(newPosition.x, (viewportW - current.w) / current.scale));
                        current.y = Math.min(0, Math.max(newPosition.y, (original.h - current.h) / current.scale));
                    };
                };

                var openModal = function () {
                    modalContainer.modal();
                };

                var closeModal = function () {
                    modalContainer.modal('hide');
                };

                var zoomToCurrent = function () {
                    var modalImg = modalContainer.find('img.img-responsive');

                    // Apply transformation
                    modalImg.css({
                        'width': Math.ceil(current.w) + 'px',
                        'height': Math.ceil(current.h) + 'px',
                        'max-width': 'none',
                        'transform': 'translate( ' + Math.ceil(current.x * current.scale) + 'px, ' + Math.ceil(current.y * current.scale) + 'px)'
                    });
                };

                var calculateModalSize = function () {
                    // Modal shouldn't be bigger than the natural size of the image
                    var modalContent = modalContainer.find('.modal-content');
                    var modalDialog = modalContainer.find('.modal-dialog');
                    var modalHeader = modalContainer.find('.modal-header');

                    // Get modal padding/margin (keep only digits)
                    var modalMargin = parseInt(modalDialog.css('margin-top').replace(/[^-\d\.]/g, ''));
                    var modalContentPadding = parseInt(modalContent.css('padding-left').replace(/[^-\d\.]/g, ''));
                    var modalHeaderHeight = modalHeader[0].getBoundingClientRect().height;

                    var isMobile = (modalContentPadding === 0);

                    var modalWidth;
                    var imageWidth;
                    var imageHeight;
                    var modalHeight;

                    if ($window.innerHeight < $window.innerWidth) {
                        //Landscape
                        var maxImageWidth = $window.innerHeight - modalContentPadding * 2;

                        modalHeight = Math.min(_naturalHeight + (modalContentPadding + modalHeaderHeight), $window.innerHeight - modalMargin * 2);
                        imageHeight = modalHeight - (modalContentPadding + modalHeaderHeight);
                        imageWidth = _naturalWidth * (imageHeight / _naturalHeight);

                        if (imageWidth > maxImageWidth) {
                            imageWidth = maxImageWidth;
                            imageHeight = _naturalHeight * (maxImageWidth / _naturalWidth);
                            modalHeight = imageHeight + (modalContentPadding + modalHeaderHeight);
                        }

                        modalWidth = imageWidth + (modalContentPadding * 2);
                    } else {
                        // Portrait
                        modalWidth = Math.min(_naturalWidth + modalContentPadding * 2, $window.innerWidth);
                        imageWidth = modalWidth - (modalContentPadding * 2);
                        imageHeight = _naturalHeight * (imageWidth / _naturalWidth);
                        modalHeight = imageHeight + (modalContentPadding + modalHeaderHeight);
                    }

                    if (isMobile) {
                        // If we are on a mobile:
                        // the image should be displayed at the calculated size
                        // but we want the modal to fill the whole viewport.
                        var modalImg = modalContainer.find('img.img-responsive');
                        modalImg.css({
                            'width': imageWidth + 'px',
                            'height': imageHeight + 'px',
                            'margin': '0 auto'
                        });

                        modalWidth = $window.innerWidth;
                    }

                    // Apply max width to modal dialog
                    modalDialog.css('width', Math.ceil(modalWidth) + 'px');
                    modalDialog.css('height', Math.ceil(modalHeight) + 'px');
                };

                // Triggers zoom-in/zoom-out animation
                // @params direction: 1 to zoom-in or -1 to zoom-out
                var animate = function (direction) {
                    if (angular.isDefined(_animationInterval)) {
                        stopAnimate();
                    }

                    // The animation should never run more than:
                    //  - The whole step (1) divided by the animationStepSize
                    var _maxNbRun = (1 / _animationStepSize);

                    var destValue = (direction === 1 ? 1 : 0);
                    var count = 0;
                    _animationInterval = $interval(function () {
                        _animationStep = getAnimationEasingValue('easeInOutQuad', count, _animationStep, destValue - _animationStep, _maxNbRun);
                        magnify();

                        count++;
                        if (count === _maxNbRun) {
                            // Set _animationStep to expected value, prevents value from slowly 
                            // drifiting away from expected value due to JS floating point calculation.
                            _animationStep = destValue;
                        }
                    }, _animationDelay, _maxNbRun);
                };

                // Stop animation interval
                var stopAnimate = function () {
                    if (angular.isDefined(_animationInterval)) {
                        $interval.cancel(_animationInterval);
                        _animationInterval = undefined;
                    }
                };

                // Calculate zooming level and position
                var mouseRatio = { x: 0, y: 0 };
                var cur_imageXDiff, cur_imageYDiff;
                var zoomedBackground = {
                    x: 0,
                    y: 0,
                    w: 0,
                    h: 0
                };

                var magnify = function () {
                    // Mouse position relative to container
                    mouseRatio.x = mouse.x / _originalWidth;
                    mouseRatio.y = mouse.y / _originalHeight;

                    // Calculate background size relative to animation progression
                    zoomedBackground.w = _originalWidth + (_imageXDiff * _animationStep);
                    zoomedBackground.h = _originalHeight + (_imageYDiff * _animationStep);

                    var maxHoverZoom = maxZoomMultiplier;
                    var maxW = Math.min(_naturalWidth, _originalWidth * maxHoverZoom);
                    var maxH = Math.min(_naturalHeight, _originalHeight * maxHoverZoom);

                    zoomedBackground.w = Math.min(maxW, Math.round(zoomedBackground.w));
                    zoomedBackground.h = Math.min(maxH, Math.round(zoomedBackground.h));

                    cur_imageXDiff = zoomedBackground.w - _originalWidth;
                    cur_imageYDiff = zoomedBackground.h - _originalHeight;

                    // Calculate background position
                    zoomedBackground.x = Math.round(mouseRatio.x * cur_imageXDiff * -1);
                    zoomedBackground.y = Math.round(mouseRatio.y * cur_imageYDiff * -1);

                    // Update style
                    magnifiedContainer.css('background-size', zoomedBackground.w + 'px ' + zoomedBackground.h + 'px');
                    magnifiedContainer.css('background-position', zoomedBackground.x + "px " + zoomedBackground.y + "px");
                };

                // Update mouse position relative to container based on mouse event
                var updateMousePosition = function (e) {
                    containerOffset = magnifiedContainer.offset();
                    mouse.x = Math.min(_originalWidth, Math.max(0, e.pageX - containerOffset.left));
                    mouse.y = Math.min(_originalHeight, Math.max(0, e.pageY - containerOffset.top));
                };

                // Easing function for animation
                var getAnimationEasingValue = function (type, time, startValue, step, duration) {
                    var result;

                    switch (type) {
                        case "easeInOutQuad":
                            time /= duration / 2;
                            if (time < 1) return step / 2 * time * time + startValue;
                            time--;
                            result = -step / 2 * (time * (time - 2) - 1) + startValue;
                            break;
                        case "linear":
                            result = step * time / duration + startValue;
                    }

                    return result;
                };

                // We need to ensure the image is loaded in order to get its displayed and natural size
                //  - Create a temporary image object to prevent issue when is image is retrieved 
                //    from cache or if the server takes time to serve the image 
                //  - In case the image is dynamically resized, this image contains the natural sized version.
                var _img = new Image();
                var isDynamicSize = false;

                var calculateSizes = function () {
                    if (isDynamicSize) {
                        ///-/media/cc-responsive-website-for-prod/trip-page-images-load/a-discovery-of-south-america-by-private-jet/
                        //2-c-sca-francis-mallman-artichokes-and-fingerling-potatoes-1920-x-1080.jpg?
                        //useCustomFunctions=1&rw=390&w=390&h=219&cropX=0&cropY=0
                        var match = $element.data('src').match(dynamicSizeRegex);
                        _originalWidth = parseInt(match[2]);
                        _originalHeight = parseInt(match[3]);
                    } else {
                        _originalWidth = $element.width();
                        _originalHeight = $element.height();
                    }

                    _naturalWidth = _img.naturalWidth;
                    _naturalHeight = _img.naturalHeight;

                    _imageXDiff = _naturalWidth - _originalWidth;
                    _imageYDiff = _naturalHeight - _originalHeight;
                };

                var init = function () {
                    calculateSizes();

                    // Only zoomable if the native size of image is bigger than display size
                    if (_imageXDiff > 0 && _imageYDiff > 0) {
                        if (magnifiedContainer === undefined) {
                            createZoomContainer();
                        }

                        if (modalContainer === undefined) {
                            createModalContainer();
                        }
                    } else {
                        if (magnifiedContainer !== undefined) {
                            stopAnimate();
                            magnifiedContainer.remove();
                            magnifiedContainer = undefined;
                        } 
                        
                        if (modalContainer !== undefined) {
                            modalContainer.remove();
                            modalContainer = undefined;
                        }
                    }
                };

                /**
                 * Reset the modal style and transform
                 */
                var resetModalImgStyle = function () {
                    var modalImg = modalContainer.find('img.img-responsive');

                    // Reset current styling
                    modalImg.css({
                        'width': 'auto',
                        'height': 'auto',
                        'max-width': '100%',
                        'margin': '0',
                        'transform': 'translate(0, 0)'
                    });
                };

                // Reset current transform
                var resetOriginal = function () {
                    var modalImg = modalContainer.find('img.img-responsive');

                    original = {
                        x: 0,
                        y: 0,
                        w: modalImg.width(),
                        h: modalImg.height(),
                        scale: 1,
                        pinchCenter: null,
                        pinchCenterOffset: null
                    };

                    start = Object.assign({}, original);
                    current = Object.assign({}, start);
                };

                // If the directive is set on a image with a src attribute
                // and the containers have not been created yet
                if ($element[0].tagName === "IMG" && src !== undefined) {

                    _img.onload = init;

                    if ($element.hasClass('lazyload') || $element.hasClass('lazyloaded')) {
                        // If the image is lazy-loaded we use the src info from the data-attribute.

                        // If the image is dynamically resize, we create a new src to the dimension of the max zoom.
                        var newSource = $element.data('src').replace(dynamicSizeRegex, function (match, rw, w, h, cropX, cropY, offset, string) {
                            isDynamicSize = true;
                            rw = Math.ceil(parseInt(rw) * maxZoomMultiplier);
                            w = Math.ceil(parseInt(w) * maxZoomMultiplier);
                            h = Math.ceil(parseInt(h) * maxZoomMultiplier);
                            cropX = Math.ceil(parseInt(cropX) * maxZoomMultiplier);
                            cropY = Math.ceil(parseInt(cropY) * maxZoomMultiplier);
                            return 'useCustomFunctions=1&rw=' + rw + '&w=' + w + '&h=' + h + '&cropX=' + cropX + '&cropY=' + cropY;
                        });

                        src = newSource;
                    }

                    _img.src = src;
                }

                // Attach resize event 
                // Ensure the background size remains correct even if breakpoint changes
                var debounceResize;
                function onResizeActions() {
                    $timeout.cancel(debounceResize);
                    debounceResize = $timeout(function () {
                        init();

                        // Display size might have changed: reset zoom 
                        if (magnifiedContainer !== undefined) {
                            magnifiedContainer.css({
                                'background-position': '0 0',
                                'background-size': _originalWidth + 'px ' + _originalHeight + 'px'
                            });
                        }

                        if (modalContainer !== undefined) {
                            // Reset styles, recalculate modal size and reset transform
                            resetModalImgStyle();
                            calculateModalSize();
                            resetOriginal();
                        }
                    }, 10);
                }
                angular.element($window).bind('resize', function () {
                    onResizeActions();
                });
                angular.element($window).bind('orientationchange', function () {
                    $timeout(function() {
                        onResizeActions();
                    }, 250);
                });
            }
        };

        return directive;
    }

    tripPdfDownload.$inject = ['tripService', '$q'];

    function tripPdfDownload($tripService, $q) {
        var directive = {
            restrict: 'AE',
            scope: true,
            replace: 'true',
            link: function (scope, element, attrs, ctrl) {
                element.click(function () {

                    var def = $q.defer();

                    var element = $(this);
                    var loadingClass = 'btn--loading dark-font'; //dark-font class used for APT

                    element.attr('disabled', 'disabled');
                    if (!element.hasClass(loadingClass)) {
                        element.addClass(loadingClass);
                    }

                    $tripService.downloadTripItinerary(attrs.pdfName)
                        .then(function (success) {
                            element.removeClass(loadingClass);
                            element.removeAttr('disabled');
                            if (success) {
                                def.resolve();
                            }
                            else {
                                def.reject();
                            }
                        });
                });
            }
        };
        return directive;
    }
})();
;
(function () {
    "use strict";

    angular
        .module('Phoenix.Shared.directives')
        .directive('tripFinder', ['$timeout', '$rootScope', 'tripFinderService', 'tripService', 'utilityService', tripFinder])
        .directive('tripFinderHero', ['$timeout', tripFinderHero])
        .directive('tripFinderSearch', ['$timeout', '$document', tripFinderSearch])
        .directive('tripFinderResults', ['$timeout', tripFinderResults])
        .directive('bookingFunnelBackButton', ['$window', 'tripService', bookingFunnelBackButton]);

    function bookingFunnelBackButton($window, tripService) {
        var directive = {
            restrict: 'A',
            link: link
        };

        function link(scope, element, attr, ctrl) {
            function backToTripPage() {
                $window.location = tripService.getTripUrl();

                if (element.data('forceReload')) {
                    $window.location.reload();
                }
            }

            element.bind('click', backToTripPage);
        }

        return directive;
    }

    function tripFinder($timeout, $rootScope, tripFinderService, tripService, utilityService) {
        var directive = {
            restrict: 'A',
            scope: true,
            controller: tripFinderController,
            controllerAs: 'tfc',
            bindToController: true,
            link: link
        };
        function link(scope, element, attr, ctrl) {
            var loadTrips = function (pageSize, pageNumber) {
                var sort = ctrl.search.sort.current.Field !== undefined ? ctrl.search.sort.current.Field : '';
                var sortOrder = ctrl.search.sort.current.Direction !== undefined ? ctrl.search.sort.current.Direction : '';

                ctrl.search.filters.dateselection = '';
                var dateQueryParam = utilityService.GetQueryStringParameters('dateselection');
                if (!!dateQueryParam) {
                    ctrl.search.filters.dateselection = dateQueryParam;
                }
                return tripFinderService.GetTrips(
                    ctrl.search.filters.destinations, ctrl.search.filters.travelStyles, ctrl.search.filters.dateselection,
                    ctrl.search.filters.duration, ctrl.search.filters.city, ctrl.search.filters.years, ctrl.search.filters.experiences,
                    pageSize, pageNumber, sort, sortOrder)
                    .then(function (data) {
                        if (data) {
                            ctrl.tripResults.count = data.Total;
                            ctrl.search.sort.options = data.SortOptions;

                            if (!sort && data.SortOptions && data.SortOptions.length) {
                                ctrl.search.sort.current = ctrl.search.sort.options.length ? ctrl.search.sort.options[0] : {};
                            }
                            if (data.Data && data.Data.length) {
                                ctrl.tripResults.nextPage = data.Data;
                            }

                            ctrl.search.loadingMoreResults = false;
                            // intialise any new Request Quote forms, notify event listeners that new images are present
                            $timeout(function () {
                                AptForm.Initialise();
                                $rootScope.$broadcast('broadcast.dom-manipulation.image');
                            });
                        }
                    });
            };

            var getTrips = function () {
                ctrl.search.loadingMoreResults = true;
                ctrl.tripResults.trips = ctrl.tripResults.trips.concat(ctrl.tripResults.nextPage);
                getTripTags();

                // only preload the next set of results if there are more to load
                if (ctrl.tripResults.count > ctrl.tripResults.trips.length) {
                    loadTrips(ctrl.search.pageSize, ctrl.search.pageIndex + 1);
                }
            };

            var initTrips = function () {
                ctrl.search.loadingResults = true;
                ctrl.search.loadingMoreResults = false;
                // load 2 pages worth of results in one go
                return loadTrips(ctrl.search.pageSize * 2, 1).then(function () {
                    // split the results - returned array from the start becomes the current page, remainder of the array remains in the nextPage variable
                    ctrl.tripResults.trips = ctrl.tripResults.nextPage.splice(0, ctrl.search.pageSize);

                    getTripTags();
                });
            };
            var dateQueryString = utilityService.GetQueryStringParameters('dateselection');
            var dateQueryParam = "";
            if (!!dateQueryString) {
                dateQueryParam = dateQueryString;
            }
            var getTripTags = function () {
                tripService.GetTripTags(ctrl.search.filters.destinations.join(','), ctrl.search.filters.travelStyles.join(','), dateQueryParam, ctrl.search.filters.duration.join('_'))
                    .then(function (data) {
                        ctrl.search.filters.cities = data;
                    });
            };

            var destinationQueryParam = utilityService.GetQueryStringParameters('destination');
            var travelStyleQueryParam = utilityService.GetQueryStringParameters('travelstyle');
            var durationQueryParam = utilityService.GetQueryStringParameters('duration');
            var yearQueryParam = utilityService.GetQueryStringParameters('year');
            var keywordsQueryParam = utilityService.GetQueryStringParameters('keywords');

            var setSelections = function () {
                ctrl.search.filters.destinations = cleanSelectedOptions(utilityService.GetArrayFromCommaString(destinationQueryParam), '.js-section-destination');
                ctrl.search.filters.travelStyles = cleanSelectedOptions(utilityService.GetArrayFromCommaString(travelStyleQueryParam), '.js-section-travelstyle');
                ctrl.search.filters.experiences = cleanSelectedOptions(utilityService.GetArrayFromCommaString(travelStyleQueryParam), '.js-section-experience');
                ctrl.search.filters.duration = cleanSelectedOptions(utilityService.GetArrayFromCommaString(durationQueryParam, '_'), '.js-section-duration');
                ctrl.search.filters.years = cleanSelectedOptions(utilityService.GetArrayFromCommaString(yearQueryParam), '.js-section-year');
                ctrl.search.filters.city = ctrl.search.cityInput = keywordsQueryParam;

                scope.$apply();
            };

            var doesQueryStringContainSearchParameters = function () {
                return destinationQueryParam !== null || travelStyleQueryParam !== null || durationQueryParam !== null ||
                    yearQueryParam !== null || keywordsQueryParam !== null;
            };

            var doesQueryStringHaveFilters = function () {
                var filterCount = 0;

                if (destinationQueryParam !== null) {
                    if (ctrl.search.filters.destinations.length > 0) ++filterCount;
                }
                if (travelStyleQueryParam !== null) {
                    if (ctrl.search.filters.travelStyles.length > 0) ++filterCount;
                    if (ctrl.search.filters.experiences.length > 0) ++filterCount;
                }
                if (durationQueryParam !== null) {
                    if (ctrl.search.filters.duration.length > 0) ++filterCount;
                }
                if (yearQueryParam !== null) {
                    if (ctrl.search.filters.years.length > 0) ++filterCount;
                }
                if (keywordsQueryParam !== null) {
                    if (ctrl.search.filters.city.length > 0) ++filterCount;
                }

                return filterCount > 0 ? true : false;
            };

            var isQueryStringFiltersEmpty = function () {
                // Checks whether no filters have been selected when first visiting the trip finder page
                var emptyQueryString = true;

                if ((destinationQueryParam !== null && destinationQueryParam != '')
                    || (travelStyleQueryParam !== null && travelStyleQueryParam != '')
                    || (durationQueryParam !== null && durationQueryParam != '')
                    || (yearQueryParam !== null && yearQueryParam != '')
                    || (keywordsQueryParam !== null && keywordsQueryParam != '')) {
                    emptyQueryString = false;
                }

                return emptyQueryString;
            };

            /*
            filtering the array and returning the selected options based on valid filter options
            @param arr Array trip values received in GET request
            @param key String DOM selector that checks for matching key
            @return Array the matched value in the key
            */
            var searchPageFilters = angular.element('.search-page__filters, .search-page-filters, .trip-finder__filters__options');
            var cleanSelectedOptions = function (arr, key) {
                var cleanedArray = [];

                for (var i = 0; i < arr.length; i++) {
                    // only need to filter results if the search results filter component is present
                    if (searchPageFilters.length) {
                        var $selectedKey = $(key + '  [data-key="' + arr[i] + '"]');

                        if ($selectedKey.length) { // we add the matching key to the array if it has been found
                            cleanedArray.push(arr[i]);
                        }
                    }
                    else {
                        cleanedArray.push(arr[i]);
                    }
                }
                return cleanedArray;
            };

            $timeout(function () {
                setSelections();
                initTrips().then(function () {
                    if (ctrl.tripResults.count === 0) {
                        ctrl.search.clearSelections();
                    } else {
                        ctrl.search.loadingResults = false;
                    }

                    if (doesQueryStringContainSearchParameters()) {
                        ctrl.showNoTripsFoundMsg = !(doesQueryStringHaveFilters() || isQueryStringFiltersEmpty());
                    }
                });
            });

            scope.$on('broadcast.tripFinderController.searchFiltersUpdated', function () {
                ctrl.tripResults.trips = [];
                ctrl.tripResults.nextPage = [];
                ctrl.search.pageIndex = 1;
                initTrips().then(function () {
                    ctrl.search.loadingResults = false;
                });

                angular.element('.trip-card-listing__no-results-msg')[0].classList.remove('display');
            });

            scope.$on('broadcast.tripFinderController.searchFiltersUpdatedTravelStyle', function () {
                ctrl.search.filters.travelStyles.length = 0;
                ctrl.search.filters.experiences.length = 0;
                ctrl.tripResults.trips = [];
                ctrl.tripResults.nextPage = [];
                ctrl.search.pageIndex = 1;
                initTrips().then(function () {
                    ctrl.search.loadingResults = false;
                });

                angular.element('.trip-card-listing__no-results-msg')[0].classList.remove('display');
            });

            scope.$on('broadcast.tripFinderController.selectSortOption', function () {
                ctrl.tripResults.trips = [];
                ctrl.tripResults.nextPage = [];
                ctrl.search.pageIndex = 1;
                initTrips().then(function () {
                    ctrl.search.loadingResults = false;
                });
            });

            scope.$on('broadcast.tripFinderController.hideSortOptions', function () {
                var $modal = angular.element('#tripFinderSortOptionsModal');
                $modal.modal('hide');
            });

            scope.$on('broadcast.tripFinderController.hideCityOptions', function () {
                var $modal = angular.element('#tripFinderCitiesModal');
                $modal.modal('hide');
            });

            scope.$on('broadcast.tripFinderController.showMoreResults', function () {
                // only load more if there are more to load
                if (ctrl.tripResults.count > ctrl.tripResults.trips.length) {
                    ctrl.search.pageIndex++;
                    getTrips();
                }
            });

            scope.$on('broadcast.tripFinderController.tripFinderOverlay', function () {
                var $htmlBody = angular.element('html body');
                var $siteOverlay = angular.element('.site-overlay-secondary');
                var $siteHeader = angular.element('.header.home-page');
                var $tripFinderHero = angular.element('.trip-finder-hero');
                var $tripSearchResult = angular.element('.trip-finder__search');

                if (ctrl.search.open === true) {
                    $siteOverlay.addClass('is-visible');
                    $tripFinderHero.addClass('z-stack-order-50');
                    $tripSearchResult.addClass('z-stack-order-50');
                }
                else if (ctrl.search.open === false) {
                    $siteOverlay.removeClass('is-visible');
                    $tripFinderHero.removeClass('z-stack-order-50');
                    $tripSearchResult.removeClass('z-stack-order-50');
                    var scrollToEl = $('#search-page-hero-carousel');

                    if (scrollToEl.length) {
                        $htmlBody.animate({
                            scrollTop: $('#search-page-hero-carousel').offset().top
                        }, 500);
                    }
                }
            });
        }
        return directive;
    }

    function tripFinderHero($timeout) {
        var directive = {
            restrict: 'A',
            scope: true,
            require: '^tripFinder',
            link: link
        };
        function link(scope, element, attr, ctrl) {
        }
        return directive;
    }

    function tripFinderSearch($timeout, $document) {
        var directive = {
            restrict: 'A',
            scope: true,
            require: '^tripFinder',
            link: link
        };

        function link(scope, element, attr, ctrl) {

            // Lock screen when trip finder overlay is active
            $timeout(function () {
                var $check = angular.element(element).find('#trip-filter-overlay');
                var $body = $document.find('body')[0];
                var $siteContainer = $document.find('.site-container')[0];
                $check.on('click', function () {
                    if ($body.hasAttribute('data-no-scroll')) {
                        $body.removeAttribute('data-no-scroll');
                        $('.site-container').removeClass('noscroll-xs');
                        $('body').removeClass('modal-open-xs');
                    } else {
                        $body.setAttribute('data-no-scroll', true)
                        $('.site-container').addClass('noscroll-xs');
                        $('body').removeClass('modal-open').addClass('modal-open-xs');
                    }

                    angular.element('.trip-card-listing__no-results-msg')[0].classList.remove('display');
                });
            });

            $timeout(function () {
                var $modal = angular.element(element).find('.modal');
                $modal.on('hidden.bs.modal', function () {
                    ctrl.search.modalOpen = false;
                });
                $modal.on('show.bs.modal', function () {
                    ctrl.search.modalOpen = true;
                });
            });

            // adapted from clickOutside common directive
            var onClick = function (event) {
                // don't close the search panel if the modal is open
                if (ctrl.search.modalOpen) { ctrl.search.open = true; return; }

                // don't close the search panel if we clicked on a city autocomplete results
                // this sometimes could happen as these results get removed from the DOM
                if ($(event.target).is('.trip-finder__search__popup-menu__listitem a')) { return; }

                // is the element the search box or one of its children?
                var isChild = $(element).has(event.target).length > 0;
                var isSelf = element[0] == event.target;
                var isInside = isChild || isSelf;
                if (!isInside) {
                    // have to do this in scope.$apply() so that angular knows that we are changing things
                    // otherwise the view won't be updated (search filters hidden) until the next user interaction
                    scope.$apply(function () {
                        ctrl.search.hideSearch();
                    });
                }
            };

            // only turn on the event listener when the search box is actually open
            scope.$watch(function () { return ctrl.search.open; }, function (newValue, oldValue) {
                if (newValue !== oldValue && newValue === true) {
                    $document.bind('tap click', onClick);
                } else if (newValue !== oldValue && newValue === false) {
                    $document.unbind('tap click', onClick);
                }
            });
        }
        return directive;
    }

    function tripFinderResults($timeout) {
        var directive = {
            restrict: 'A',
            scope: true,
            require: '^tripFinder',
            link: link
        };

        function link(scope, element, attr, ctrl) {
        }

        return directive;
    }

    tripFinderController.$inject = ['$scope'];
    function tripFinderController($scope) {
        var tfc = this;
        tfc.search = {
            open: false,
            filters: {
                destinations: [],
                travelStyles: [],
                duration: [],
                city: '',
                cities: [],
                years: [],
                secondaryDestinations: [],

                experiences: [],
                canShowViewResultsCta: canShowFiltersViewResultsCta,
                canShowNoResultsCta: canShowFiltersNoResultsCta
            },
            sort: {
                optionsOpen: false,
                options: [],
                current: {
                    Title: 'Popularity',
                    Field: 'Rank',
                    Direction: 'Asc'
                },
                hideOptions: hideSortOptions,
                showOptions: showSortOptions,
                selectOption: selectSortOption
            },
            filterCount: 0,
            pageIndex: 1,
            pageSize: 12,
            citiesVisible: false,
            cityInput: '',
            modalOpen: false,
            toggleOpen: toggleSearchOpen,
            hideSearch: hideSearch,
            toggleSelection: toggleSearchSelection,
            isOptionSelected: isSearchOptionSelected,
            clearSectionSelectionsTripStyles: clearSectionSelectionsTripStyles,
            clearSectionSelections: clearSectionSelections,
            clearSelections: clearSelections,
            toggleNestedSelection: toggleNestedSelection,
            isAnyNestedOptionsSelected: isAnyNestedOptionsSelected,
            firstLevelNumberOfFiltersDescription: firstLevelNumberOfFiltersDescription,
            firstLevelNumberOfFiltersDescriptionDestination: firstLevelNumberOfFiltersDescriptionDestination,
            nestedNumberOfFiltersDescription: nestedNumberOfFiltersDescription,
            toggleSecondarySearchSelection: toggleSecondarySearchSelection,
            isSelfOrParentSelected: isSelfOrParentSelected,
            showMoreResults: showMoreResults,
            showCities: showCities,
            hideCities: hideCities,
            setCity: setCity,
            clearCity: clearCity,
            loadingResults: true,
            loadingMoreResults: false,
            hideCityOptions: hideCityOptions,
            canShowResults: canShowResults,
            canShowNoResults: canShowNoResults,
            canShowLoading: canShowLoading,
            ccTripFilterDescription: ccTripFilterDescription,
            ccOverlayClick: ccOverlayClick,
            showNoTripsFoundMsg: false
        };

        tfc.tripResults = {
            count: 0,
            trips: [],
            nextPage: []
        };
        tfc.setResults = setResults;
        tfc.requestQuote = requestQuote;

        $scope.$watch('tfc.search.filters', function () {
            setFilterCount();
        }, true);

        ccFiltersBodyAction(function($filter) {
            $filter.on('show.bs.collapse', ccOpenOverlay);
            $filter.on('hidden.bs.collapse', ccUpdateOverlay);
        });

        tfc.init = function (secondaryDestinations) {
            tfc.search.filters.secondaryDestinations = secondaryDestinations;
        }

        function setFilterCount() {
            tfc.search.filterCount =
                (tfc.search.filters.destinations.length ? 1 : 0) +
                (tfc.search.filters.travelStyles.length ? 1 : 0) +
                (tfc.search.filters.duration.length ? 1 : 0) +
                (tfc.search.filters.city ? 1 : 0) +
                (tfc.search.filters.years.length ? 1 : 0) +
                (tfc.search.filters.experiences.length ? 1 : 0);
        }

        function setResults(count) {
            tfc.tripResults.count = count;
        }

        function toggleSearchOpen() {
            tfc.search.open = !tfc.search.open;
            $scope.$broadcast('broadcast.tripFinderController.tripFinderOverlay');
            if (tfc.search.cityInput != tfc.search.filters.city) {
                tfc.search.cityInput = tfc.search.filters.city;
            }
        }

        function hideSearch() {
            tfc.search.open = false;
            tfc.search.cityInput = tfc.search.filters.city;
            $scope.$broadcast('broadcast.tripFinderController.tripFinderOverlay');
        }

        function toggleSearchSelection(id, arr) {
            if (!arr) return;

            var exists = false;
            for (var i = 0; i < arr.length; i++) {
                if (arr[i] == id) {
                    exists = true;
                    arr.splice(i, 1);
                    break;
                }
            }
            if (!exists) {
                arr.push(id);
            }
            $scope.$broadcast('broadcast.tripFinderController.searchFiltersUpdated');
        }

        function arrayContainsId(id, arr) {
            return arr.filter(function(x){
                return x == id;
            }).length >= 1;
        }

        function removeIdIfExists(id, arr) {
            for (var i = 0; i < arr.length; i++) {
                if (arr[i] == id) {
                    arr.splice(i, 1);
                    break;
                }
            }
        }

        function removeIdsIfExists(ids, arr) {
            for(var i = arr.length-1; i >= 0; --i) {
                for(var j = 0; j < ids.length; ++j) {
                    if(arr[i] == ids[j]) {
                        arr.splice(i, 1);
                        break;
                    }
                }
            }
        }

        function toggleId(id, arr) {
            var removed = false;
            for (var i = 0; i < arr.length; i++) {
                if (arr[i] == id) {
                    arr.splice(i, 1);
                    removed = true;
                    break;
                }
            }
            if(!removed) {
                arr.push(id);
            }
        }

        function toggleSecondarySearchSelection(parentId, id, secondaryDestinationGroups, sectionArr) {
            var nestedIds = secondaryDestinationGroups.filter(function(x){
                return x.Parent == parentId;
            })[0].Children;
            var parentSelected = arrayContainsId(parentId, sectionArr);

            if(parentSelected) {
                // unselect parent
                removeIdIfExists(parentId, sectionArr);
                // select all children except self
                for(var i = 0; i < nestedIds.length; ++i) {
                    if(nestedIds[i] != id) {
                        sectionArr.push(nestedIds[i]);
                    }
                }
            } else {
                // toggle self
                toggleId(id, sectionArr);
                // if all children are selected, unselect them all and select parent
                var allChildrenSelected = isAllNestedOptionsSelected(parentId, secondaryDestinationGroups, sectionArr);
                if(allChildrenSelected) {
                    removeIdsIfExists(nestedIds, sectionArr);
                    sectionArr.push(parentId);
                }
            }
            $scope.$broadcast('broadcast.tripFinderController.searchFiltersUpdated');
        }

        function isSelfOrParentSelected(parentId, id, sectionArr) {
            return arrayContainsId(parentId, sectionArr) || arrayContainsId(id, sectionArr);
        }

        function isSearchOptionSelected(id, arr) {
            if (!arr) return false;

            for (var i = 0; i < arr.length; i++) {
                if (arr[i] == id) {
                    return true;
                }
            }
            return false;
        }

        function clearSectionSelectionsTripStyles(arr) {
            if (arr.length) {
                arr.splice(0, arr.length);
                $scope.$broadcast('broadcast.tripFinderController.searchFiltersUpdatedTravelStyle');
            }
        }
        function clearSectionSelections(arr) {
            if (arr.length) {
                arr.splice(0, arr.length);
                $scope.$broadcast('broadcast.tripFinderController.searchFiltersUpdated');
            }
        }

        function toggleNestedSelection(id, secondaryDestinationGroups, sectionArr) {
            var nestedIds = secondaryDestinationGroups.filter(function(x){
                return x.Parent == id;
            })[0].Children;
            var anyChildrenSelected = isAnyNestedOptionsSelected(id, secondaryDestinationGroups, sectionArr);
            var parentSelected = arrayContainsId(id, sectionArr);

            if(parentSelected) {
                // unselect parent
                removeIdIfExists(id, sectionArr);
            } else if(anyChildrenSelected) {
                // unselect children
                removeIdsIfExists(nestedIds, sectionArr);
            } else {
                // select parent
                sectionArr.push(id);
            }

            $scope.$broadcast('broadcast.tripFinderController.searchFiltersUpdated');
        }

        function isAnyNestedOptionsSelected(parentId, secondaryDestinationGroups, sectionArr) {
            var nestedIds = secondaryDestinationGroups.filter(function(x){
                return x.Parent == parentId;
            })[0].Children;
            for(var i = 0; i < sectionArr.length; ++i) {
                for(var j = 0; j < nestedIds.length; ++j) {
                    if(sectionArr[i] == nestedIds[j]) {
                        return true;
                    }
                }
            }
            return false;
        }

        function isAllNestedOptionsSelected(parentId, secondaryDestinationGroups, sectionArr) {
            var nestedIds = secondaryDestinationGroups.filter(function(x){
                return x.Parent == parentId;
            })[0].Children;
            var found;
            for(var i = 0; i < nestedIds.length; ++i) {
                found = false;
                for(var j = 0; j < sectionArr.length; ++j) {
                    if(nestedIds[i] == sectionArr[j]) {
                        found = true;
                    }
                }
                if(!found) {
                    return false;
                }
            }
            return true;
        }

        function firstLevelNumberOfFiltersDescription(sectionArr, maxNumFilters) {
            var num = sectionArr.length;
            if(num === 0 || num === maxNumFilters) {
                return "(All)";
            } else {
                return '('+num+')';
            }
        }

        function firstLevelNumberOfFiltersDescriptionDestination(sectionArr, secondaryDestinationGroups, destinations) {
            var allDestinationsAreSelected = true;
            for(var i = 0; i < destinations.length; ++i) {
                var found = false;
                for(var j = 0; j < sectionArr.length; ++j) {
                    if(destinations[i] == sectionArr[j]) {
                        found = true;
                        break;
                    }
                }
                if(!found) {
                    allDestinationsAreSelected = false;
                    break;
                }
            }

            var allSecondaryDestinationsSelected = true;
            var num = sectionArr.length;
            for(var i = 0; i < secondaryDestinationGroups.length; ++i) {
                if(arrayContainsId(secondaryDestinationGroups[i].Parent, sectionArr)) {
                    num += secondaryDestinationGroups[i].Children.length;
                } else if(isAllNestedOptionsSelected(secondaryDestinationGroups[i].Parent, secondaryDestinationGroups, sectionArr)) {
                    // Exception
                } else {
                    allSecondaryDestinationsSelected = false;
                }
            }

            if ((num === 0)||(allDestinationsAreSelected && allSecondaryDestinationsSelected)) {
                return "(All)";
            } else {
                return '('+num+')';
            }
        }

        function nestedNumberOfFiltersDescription(sectionArr, secondaryDestinationGroups, prefix) {
            var nestedIds = secondaryDestinationGroups.filter(function(x){
                return x.Parent == prefix;
            })[0].Children;
            var maxNumFilters = nestedIds.length;
            var parentSelected = arrayContainsId(prefix, sectionArr);

            var numFilters = sectionArr.filter(function(x){
                for(var i = 0; i < nestedIds.length; ++i){
                    if(x == nestedIds[i]) {
                        return true;
                    }
                }
                return false;
            }).length;

            if(sectionArr.length === 0) {
                return "";
            } else if(numFilters === maxNumFilters || parentSelected) {
                return "(All)";
            } else if(numFilters === 0) {
                return "";
            } else {
                return '('+numFilters+')';
            }
        }

        function ccTripFilterDescription(sectionArr, totalPossibleFilters, allText) {
            if(!(sectionArr && totalPossibleFilters && allText)) {
                return "";
            }

            if(sectionArr.length === 0 || sectionArr.length >= totalPossibleFilters) {
                return allText;
            } else {
                return '('+sectionArr.length+')';
            }
        }

        function ccFiltersBodyAction(fn) {
            var $filters = $('.tf-search__filters__filter__body__wrapper');
            if(!$filters) {
                return;
            }

            $filters.each(function() {
                var $filter = $(this);
                fn($filter);
            });
        }

        function ccCloseFilters(ids) {
            ccFiltersBodyAction(function($filter) {
                $filter.collapse('hide');
            });
        }

        function ccOverlayClick() {
            ccCloseFilters();
            ccUpdateOverlay();
        }

        function ccCloseOverlay() {
            var $overlay = $("#tf-search__overlay");
            if($overlay && $overlay.hasClass("visible")) {
                $overlay.removeClass("visible");
            }
        }

        function ccOpenOverlay() {
            var $overlay = $("#tf-search__overlay");
            if($overlay && !$overlay.hasClass("visible")) {
                $overlay.addClass("visible");
            }
        }

        function ccUpdateOverlay() {
            var someOpen = false;
            ccFiltersBodyAction(function($filter) {
                if($filter.hasClass('in') || $filter.hasClass('collapsing')) {
                    someOpen = true;
                }
            });

            if(someOpen) {
                ccOpenOverlay();
            } else {
                ccCloseOverlay();
            }
        }

        function clearSelections() {
            tfc.search.filters.destinations = [];
            tfc.search.filters.travelStyles = [];
            tfc.search.filters.duration = [];
            tfc.search.filters.city = '';
            tfc.search.cityInput = '';
            tfc.search.filters.years = [];
            tfc.search.filters.experiences = [];
            $scope.$broadcast('broadcast.tripFinderController.searchFiltersUpdated');
        }

        function showMoreResults() {
            $scope.$broadcast('broadcast.tripFinderController.showMoreResults');
        }

        function showCities() {
            tfc.search.citiesVisible = true;
        }

        function hideCities() {
            tfc.search.citiesVisible = false;
        }

        function setCity(city) {
            tfc.search.filters.city = city.Title;
            tfc.search.cityInput = city.Title;
            hideCities();
            $scope.$broadcast('broadcast.tripFinderController.searchFiltersUpdated');
        }

        function clearCity() {
            tfc.search.filters.city = '';
            tfc.search.cityInput = '';
            $scope.$broadcast('broadcast.tripFinderController.searchFiltersUpdated');
        }

        function showSortOptions() {
            tfc.search.sort.optionsOpen = true;
        }

        function hideSortOptions() {
            tfc.search.sort.optionsOpen = false;
            $scope.$broadcast('broadcast.tripFinderController.hideSortOptions');
        }

        function selectSortOption(option) {
            tfc.search.sort.current = option;
            $scope.$broadcast('broadcast.tripFinderController.selectSortOption');
        }

        function requestQuote(trip) {
            tfc.currentTrip = trip;
            var formSection = $('[data-trip-request-quote-form] .js-form-section');
            formSection.show().next().hide();
            $scope.$broadcast('broadcast.tripFinderController.updateTripData', trip);
        }

        function hideCityOptions() {
            $scope.$broadcast('broadcast.tripFinderController.hideCityOptions');
        }

        function canShowResults() {
            return (tfc.tripResults.count > tfc.tripResults.trips.length) && (!tfc.search.loadingMoreResults) && (!tfc.search.loadingResults);
        }

        function canShowNoResults() {
            return tfc.tripResults.count == 0 && !tfc.search.loadingResults;
        }

        function canShowLoading() {
            return (tfc.tripResults.count > tfc.tripResults.trips.length) && (tfc.search.loadingMoreResults);
        }

        function canShowFiltersViewResultsCta() {
            return (tfc.tripResults.count > 0 || tfc.tripResults.trips.length) && !tfc.search.loadingResults;
        }

        function canShowFiltersNoResultsCta() {
            return tfc.tripResults.count == 0 && !tfc.tripResults.trips.length && !tfc.search.loadingResults;
        }
    }
})();;
(function () {
    'use strict';

    angular
        .module('Phoenix.Shared.directives')
        .directive('tripPackageSelectionForm', ['$timeout', '$rootScope', '$analytics', tripPackageSelectionForm])
        .directive('tripPackageSelectionInfo', ['tripPackageSelectionService', tripPackageSelectionInfo])
        .directive('tripPackageSelection', ['utilityService', 'tripPackageSelectionService', tripPackageSelection]);

    function tripPackageSelectionInfo(tripPackageSelectionService) {
        return {
            restrict: 'A',
            scope: true,
            require: '^tripPackageSelection',
            link: link
        };

        function link(scope, element, attr, ctrl) {

            var $infoModal = $('#tpsc-info');

            function getInfo(id) {
                // display the modal in loading state
                ctrl.modal = {};
                ctrl.modal.isLoading = true;
                scope.$apply();
                $infoModal.modal();

                // retrieve package informations
                tripPackageSelectionService
                    .GetPackageInformation(id)
                    .then(displayInfo);
            }

            function displayInfo(data) {
                if (!data) {
                    ctrl.modal.title = ctrl.modalError.title;
                    ctrl.modal.description = ctrl.modalError.description;
                } else {
                    ctrl.modal = angular.extend(ctrl.modal, data);
                }
                
                ctrl.modal.isLoading = false;
            }

            element.bind('click', function() {
                var id = this.dataset.infoId;
                getInfo(id);
            });
        }
    }

    function tripPackageSelectionForm($timeout, $rootScope, $analytics) {
        return {
            restrict: 'A',
            scope: true,
            require: '^tripPackageSelection',
            link: link
        };

        function link(scope, element, attr, ctrl) {

            var FORM = {};

            FORM.$element = $(element).find('form');
            FORM.init = function () {

                FORM.$element.on('form.submit.initialised', function () {
                    ctrl.form.isSubmitting = true;
                    scope.$apply();
                });

                FORM.$element.on('form.submit.success', function () {
                    ctrl.form.isSubmitting = false;
                    $rootScope.$broadcast('broadcast.multistepCarousel.goToStep', { step: 2 });

                    $analytics.eventTrack(null, {
                        'Packagesku': ctrl.trip.tripCode,
                        'Packagename': ctrl.trip.tripName,
                        'Packageprice': ctrl.price,
                        'Packagetype': ctrl.package.journeyPackageType,
                        'Travelmode': ctrl.roomType.roomConfigurationType,
                        'Upgradeoptions': ctrl.buildPackageSelectionArray(),
                        'event': 'enquiryComplete'
                    });
                });

                FORM.$element.on('form.submit.error', function () {
                    ctrl.form.isSubmitting = false;
                    scope.$apply();
                });

                FORM.$element.on('form.submit.invalid', function () {
                    ctrl.form.isSubmitting = false;
                    scope.$apply();
                });
            }

            FORM.init();
        }
    }

    function tripPackageSelection(utilityService, tripPackageSelectionService) {
        return {
            restrict: 'A',
            scope: true,
            controller: 'tripPackageSelectionController',
            controllerAs: 'tpsc',
            bindToController: true,
            link: link
        };

        function link(scope, element, attr, ctrl) {
            var $el = $(element);

            function setupModel() {
                tripPackageSelectionService.GetDeparture(ctrl.trip.tripId, ctrl.date)
                    .then(function (data) {
                        ctrl.setupModel(data);
                    });
            }

            scope.$watch('tpsc.date', function (newValue, oldValue) {
                if (newValue !== oldValue) {
                    setupModel();
                    scope.tpsc.setTripBadge(newValue);
                }
            });

            scope.$on('broadcast.multistepCarouselControllers.indexChanged', function() {
                utilityService.ScrollTo($el, 300);
            });


            scope.$watch('tpsc.package', function (newValue, oldValue) {
                scope.tpsc.calculateTotalPrice();
            });

            scope.$watch('tpsc.roomType', function (newValue, oldValue) {
                scope.tpsc.isUpdatingRoomType = true;
                scope.tpsc.setDefaultUpgradeCategories();
                scope.tpsc.calculateTotalPrice();
            });

            scope.$watch('tpsc.roomType.upgradeCategories', function (newValue, oldValue) {
                if (!scope.tpsc.isUpdatingRoomType) {
                    scope.tpsc.calculateTotalPrice();
                }
                scope.tpsc.isUpdatingRoomType = false;
            }, true);

            scope.$on('broadcast.multistepCarouselControllers.goToNext', function() {
                ctrl.buildPackageDetailsString();
                ctrl.buildRoomConfigurationString();
            });

            setupModel();
        }
    }
})();;
(function () {
    "use strict";

    angular
        .module('Phoenix.Shared.directives')
        .directive('tripPriceAndBooking', ['$timeout', '$cookies', '$window', '$filter', 'tripPriceAndBookingService', 'tripService', 'locationService', 'dataLayerService', 'priceService', 'bookingService', 'configurationConstant', tripPriceAndBooking])
        .directive('closeSnackbar', [closeSnackbar])
        .directive('frequentFlyerValidation', ['$q', '$timeout', 'bookingService', frequentFlyerValidation]);

    function tripPriceAndBooking($timeout, $cookies, $window, $filter, tripPriceAndBookingService, tripService, locationService, dataLayerService, priceService, bookingService, configurationConstant) {
        var directive = {
            restrict: 'A',
            scope: true,
            controller: tripPriceAndBookingController,
            controllerAs: 'tpbc',
            bindToController: true,
            link: link
        };
        function link(scope, element, attr, ctrl) {
            var BOOKING_STEP_MAX_INDEX;
            var $bookingSteps;
            var $el = angular.element(element);
            var $stepsListContainer = angular.element('.trip-priceandbooking__booking-steps-container');
            var $stepsList = angular.element('.trip-priceandbooking__booking-steps');
            var $steps;
            var pageWidth = angular.element('body').prop('clientWidth');
            var $collapses;
            var FORM = {};
            var HELPERS = {};

            HELPERS.scrollTo = function (position) {
                angular.element('html, body').animate({
                    scrollTop: position
                }, 100);
            }

            FORM.isHostedFieldsValid = false;
            FORM.hostedFieldInstance = {}
            FORM.hostedFields = {
                number: {
                    selector: '#payment-gateway--card-number'
                },
                cvv: {
                    selector: '#payment-gateway--card-security',
                    placeholder: 'CVV'
                },
                expirationDate: {
                    selector: '#payment-gateway--card-expiry',
                    placeholder: 'MM/YY'
                }
            }
            FORM.hostedFieldsStyles = {
                'input': {
                    'font-size': '16px',
                    'font-family': 'helvetica, tahoma, calibri, sans-serif',
                    'color': '#04183b',
                    'font-weight': 'bold'
                },
                ':focus': {
                    'color': 'black'
                },
                '::-ms-clear': {
                    'display': 'none',
                    'width': '0',
                    'height': '0',
                    'opacity': '0'
                },
                '.invalid': {
                    'color': '#db301a'
                },
            }

            FORM.updateScope = function (scopeTarget, value) {
                var target = scopeTarget.split('.');
                ctrl[target[1]][target[2]][target[3]] = value;
            }

            FORM.initUnbindedInputs = function () {
                FORM.unbindedInputs.map(function (obj) {
                    FORM.$details.trigger('form.masterfield.change', obj.parentSelector);
                });
            }

            FORM.doBookingModelMapping = function () {
                ctrl.paymentPrice.cartMappingModel.primaryPassenger.firstName = ctrl.forms.passengerOne.firstname;
                ctrl.paymentPrice.cartMappingModel.primaryPassenger.lastName = ctrl.forms.passengerOne.lastname;
                ctrl.paymentPrice.cartMappingModel.primaryPassenger.passengerTitleName = ctrl.forms.passengerOne.title;
                ctrl.paymentPrice.cartMappingModel.primaryPassenger.address = "Online";
                ctrl.paymentPrice.cartMappingModel.primaryPassenger.suburb = "Online";
                ctrl.paymentPrice.cartMappingModel.primaryPassenger.country = "Australia";
                ctrl.paymentPrice.cartMappingModel.primaryPassenger.state = "VIC";
                ctrl.paymentPrice.cartMappingModel.primaryPassenger.postCode = "3192";
                ctrl.paymentPrice.cartMappingModel.primaryPassenger.howDidYouHearAboutUsOptionId = 8; // hardcoded to other
                ctrl.paymentPrice.cartMappingModel.primaryPassenger.howDidYouHearAboutUsOptionDetailId = 40; // hardcoded to other
                ctrl.paymentPrice.cartMappingModel.primaryPassenger.email = ctrl.forms.passengerOne.email;
                ctrl.paymentPrice.cartMappingModel.primaryPassenger.phoneNumber = ctrl.forms.passengerOne.phonenumber;
                ctrl.paymentPrice.cartMappingModel.primaryPassenger.phoneNumberType = "Mobile";
                ctrl.paymentPrice.cartMappingModel.primaryPassenger.contactMethod = "Phone";
                ctrl.paymentPrice.cartMappingModel.primaryPassenger.frequentFlyerNumber = ctrl.forms.passengerOne.frequentflyernumber;
                ctrl.paymentPrice.cartMappingModel.paymentDetail.amount = ctrl.payment.isTotalAmountSelected ?
                    ctrl.paymentPrice.priceBreakDown.totalAmount : ctrl.paymentPrice.priceBreakDown.minDeposit;
                ctrl.paymentPrice.cartMappingModel.paymentDetail.surcharge = ctrl.payment.isTotalAmountSelected ?
                    ctrl.paymentPrice.priceBreakDown.surchargeAmount : ctrl.paymentPrice.priceBreakDown.minDepositSurchargeAmount;
                ctrl.paymentPrice.cartMappingModel.paymentDetail.totalAmount = ctrl.paymentPrice.cartMappingModel.paymentDetail.amount + ctrl.paymentPrice.cartMappingModel.paymentDetail.surcharge;
                // Due to Braintree 3DS, ctrl.payment.nonce will be consumed when verifying the customers card
                // Method threeDSecure.verifyCard will return a new nonce which can be used when making the booking
                // at the back-end. I am keeping this here in case something happens
                ctrl.paymentPrice.cartMappingModel.paymentDetail.paymentMethodNonce = ctrl.payment.nonce;
                ctrl.paymentPrice.cartMappingModel.paymentDetail.nameOnCard = ctrl.payment.cardName;
                ctrl.paymentPrice.cartMappingModel.paymentDetail.cardType = ctrl.payment.selectedMethod;
                ctrl.paymentPrice.cartMappingModel.paymentDetail.cardBrand = ctrl.payment.selectedCardBrandKey;
                if (!$.isEmptyObject(ctrl.qantas.authObject)) {
                    ctrl.paymentPrice.cartMappingModel.paymentDetail.qantasPointsBurnRequest.memberNumber = ctrl.qantas.authObject.memberNumber;
                    ctrl.paymentPrice.cartMappingModel.paymentDetail.qantasPointsBurnRequest.quoteReference = ctrl.qantas.authObject.quoteNumber;
                    ctrl.paymentPrice.cartMappingModel.paymentDetail.qantasPointsBurnRequest.pointsToBurn = ctrl.qantas.authObject.pointsBurned;
                    ctrl.paymentPrice.cartMappingModel.paymentDetail.qantasPointsBurnRequest.pointsValueInDollars = ctrl.qantas.authObject.currencyAmount;
                }

                if (ctrl.paymentPrice.cartMappingModel.additionalPassenger == null) return;

                ctrl.paymentPrice.cartMappingModel.additionalPassenger.firstName = ctrl.forms.passengerTwo.firstname;
                ctrl.paymentPrice.cartMappingModel.additionalPassenger.lastName = ctrl.forms.passengerTwo.lastname;
                ctrl.paymentPrice.cartMappingModel.additionalPassenger.passengerTitleName = ctrl.forms.passengerTwo.title;
                ctrl.paymentPrice.cartMappingModel.additionalPassenger.frequentFlyerNumber = ctrl.forms.passengerTwo.frequentflyernumber;
            }

            FORM.setupPassengerForms = function () {
                FORM.$onePassengerForm = angular.element('#trip_One_Passenger_Form');
                FORM.$twoPassengerForm = angular.element('#trip_Two_Passenger_Form');
                var activeForm;
                if (ctrl.roomType !== null && ctrl.roomType.allowedAdultNumber === 2) {
                    FORM.$onePassengerForm.hide();
                    FORM.$twoPassengerForm.show();
                    activeForm = FORM.$twoPassengerForm;
                }
                else {
                    FORM.$onePassengerForm.show();
                    FORM.$twoPassengerForm.hide();
                    activeForm = FORM.$onePassengerForm;
                }
                FORM.$passengerFormsSubmitButtons = activeForm.find('.booking-form__details__submit');
                if (FORM.$passengerFormsSubmitButtons) {
                    FORM.$passengerFormsSubmitButtons.hide();
                }

                FORM.$details = activeForm.find('form');
                FORM.$detailsDependentFields = $('[data-parent-sitecore-id]', FORM.$details);
            };

            FORM.registerUnbindedInputs = function () {
                FORM.$detailsDependentFields.each(function (i, group) {
                    var input = $(group).find('input, select')[0];
                    var parentGroup = $('[data-field-configuration-sitecore-id=' + group.dataset.parentSitecoreId + ']')[0];

                    FORM.unbindedInputs.push({
                        id: group.dataset.fieldSitecoreId,
                        model: input.dataset.ngModel,
                        parentSelector: '.' + parentGroup.className.replace(/ /g, '.')
                    });
                });
            }

            FORM.collectUnbindedInputs = function () {
                FORM.unbindedInputs.map(function (obj) {
                    var $input = $('[name^=' + obj.id.replace(/-/g, '') + ']');
                    var value = $input.length ? $input[0].value : undefined;
                    if (obj && obj.model) {
                        FORM.updateScope(obj.model, value);
                    }
                });
            }

            FORM.resetSurcharges = function () {
                FORM.$cardIcon.removeClass();
                ctrl.payment.selectedCardBrand = '';
                ctrl.payment.selectedCardBrandKey = '';
                ctrl.payment.selectedCardType = '';
                ctrl.paymentPrice.surchargeDetails.selectedSurchargePct = '';
                ctrl.paymentPrice.priceBreakDown.totalAmountInclusive = ctrl.paymentPrice.priceBreakDown.totalAmount;
                ctrl.paymentPrice.priceBreakDown.minDepositInclusive = ctrl.paymentPrice.priceBreakDown.minDeposit;
                ctrl.paymentPrice.priceBreakDown.minDepositSurchargeAmount = 0;
                ctrl.paymentPrice.priceBreakDown.surchargeAmount = 0;
            }


            FORM.getSurchargesDetails = function () {
                var surchargeDetail;
                var surchargeDetails = ctrl.paymentPrice.surchargeDetails.surchargeDetails;
                var surchargeKey = ctrl.payment.selectedMethod === 'paypal' ? ctrl.payment.selectedMethod : ctrl.payment.selectedCardType;
                var surchargeType = ctrl.payment.selectedMethod === 'paypal' ? 'creditSurcharge' : ctrl.payment.selectedMethod + 'Surcharge';

                var surchargeDetailSearchResult = $filter('filter')(surchargeDetails, { cardKey: surchargeKey }, true);

                if (!surchargeDetailSearchResult.length) {
                    return false;
                }

                surchargeDetail = surchargeDetailSearchResult[0];

                return {
                    surchargeAmount: priceService.calculateSurcharge(ctrl.paymentPrice.priceBreakDown.totalAmount, surchargeDetail[surchargeType]),
                    minDepositSurchargeAmount: priceService.calculateSurcharge(ctrl.paymentPrice.priceBreakDown.minDeposit, surchargeDetail[surchargeType]),
                    selectedSurchargePct: surchargeDetail[surchargeType],
                    cardBrand: surchargeDetail.cardBrand,
                    cardKey: surchargeDetail.cardKey
                }
            }

            FORM.setSurcharges = function () {
                $timeout(function () {
                    var details = FORM.getSurchargesDetails();

                    if (!details) {
                        return FORM.resetSurcharges();
                    }

                    FORM.$cardIcon[0].className = ctrl.payment.selectedCardType;
                    ctrl.payment.selectedCardBrand = details.cardBrand;
                    ctrl.payment.selectedCardBrandKey = details.cardKey;
                    ctrl.paymentPrice.priceBreakDown.surchargeAmount = details.surchargeAmount;
                    ctrl.paymentPrice.priceBreakDown.totalAmountInclusive = ctrl.paymentPrice.priceBreakDown.totalAmount + details.surchargeAmount;
                    ctrl.paymentPrice.priceBreakDown.minDepositSurchargeAmount = details.minDepositSurchargeAmount;
                    ctrl.paymentPrice.priceBreakDown.minDepositInclusive = ctrl.paymentPrice.priceBreakDown.minDeposit + details.minDepositSurchargeAmount;
                    ctrl.paymentPrice.surchargeDetails.selectedSurchargePct = details.selectedSurchargePct;

                    scope.$apply();
                });
                setStepsContainerHeight();
            }

            FORM.validateHostedFields = function (event, forceValid) {
                if (!event.fields) return;

                for (var property in event.fields) {
                    var hostedField = FORM.hostedFields[property];
                    if (!hostedField) return;

                    var $field = $(hostedField.selector);
                    if (!$field.length) continue;
                    // If a field is dirty (has blurred or attempted submission) and it is empty or invalid, show an error message
                    // If it is focussed and has invalid input that may potenitally be valid, show no message
                    // if it is valid, show a success box.
                    if (event.fields[property].isEmpty) {
                        $field.setValidity($field.data('empty-message'));
                    }
                    // Disallow a valid / potenitally valid number for a non-supported card
                    else if (property === "number" &&
                        !ctrl.payment.selectedCardBrand &&
                        event.cards.length === 1 &&
                        (event.fields[property].isValid || event.fields[property].isPotentiallyValid)) {
                        $field.attr('dirty', 'true');
                        $field.setValidity($field.data('error-message'));
                    }
                    else if (!event.fields[property].isValid &&
                        event.fields[property].isPotentiallyValid &&
                        property === event.emittedBy &&
                        !forceValid) {
                        $field.resetValidity();
                    }
                    else if (!event.fields[property].isValid) {
                        $field.attr('dirty', 'true');
                        $field.setValidity($field.data('error-message'));
                    }
                    else {
                        $field.attr('dirty', 'true');
                        $field.setValidity('');
                    }
                }
            }

            FORM.tokenizeHostedFields = function (callback) {
                if (!FORM.hostedFieldsInstance) return;

                FORM.hostedFieldsInstance.tokenize(function (err, payload) {
                    // Resets field validity
                    FORM.$paymentHostedFields.each(function () {
                        $(this).setValidity('');
                    });

                    var isValidCardType = ctrl.payment.selectedCardType.length > 0;

                    if (err || !isValidCardType) {
                        if (err) {
                            switch (err.code) {
                                case 'HOSTED_FIELDS_FIELDS_EMPTY':
                                    FORM.$paymentHostedFields.attr('dirty', 'true');
                                    FORM.$paymentHostedFields.each(function () {
                                        $(this).setValidity($(this).data('empty-message'));
                                    });
                                    break;
                                case 'HOSTED_FIELDS_FIELDS_INVALID':
                                    if (err.details && err.details.invalidFieldKeys && err.details.invalidFieldKeys.length) {
                                        for (var i = 0; i < err.details.invalidFieldKeys.length; i++) {
                                            var hostedField = FORM.hostedFields[err.details.invalidFieldKeys[i]];
                                            if (hostedField) {
                                                var $field = $(hostedField.selector);
                                                $field.attr('dirty', 'true');
                                                $field.setValidity($field.data('error-message'));
                                            }
                                        }
                                    }
                                    break;
                                default:
                                    console.error('Unknown payment error', err);
                            }

                        }
                        if (!isValidCardType) {
                            var hostedField = FORM.hostedFields['number'];
                            if (hostedField) {
                                var $field = $(hostedField.selector);
                                $field.attr('dirty', 'true');
                                $field.setValidity($field.data('error-message'));
                            }
                        }

                        FORM.$paymentSubmitButton.removeClass(FORM.btnLoadingClass);
                        FORM.isHostedFieldsValid = false;
                    }
                    else {
                        ctrl.payment.nonce = payload.nonce;
                        FORM.isHostedFieldsValid = true;
                    }

                    if (typeof callback === 'function') {
                        callback();
                    }
                });
            };

            FORM.setupPaymentGateway = function () {
                // Braintree hosted fields: https://developers.braintreepayments.com/guides/hosted-fields/examples/javascript/v3
                var token = ctrl.payment.token;

                if (token) {
                    FORM.$cardNumberField.append(FORM.$cardIcon);


                    braintree.client.create({
                        authorization: token
                    }, function (err, clientInstance) {
                        if (err) {
                            console.error(err);
                            return;
                        }
                        braintree.hostedFields.create({
                            client: clientInstance,
                            styles: FORM.hostedFieldsStyles,
                            fields: FORM.hostedFields
                        }, function (err, hostedFieldsInstance) {
                            FORM.hostedFieldsInstance = hostedFieldsInstance;

                            if (err) {
                                console.error(err);
                                return;
                            }

                            FORM.hostedFieldsInstance.on('validityChange', function (event) {
                                FORM.validateHostedFields(event);
                            });

                            FORM.hostedFieldsInstance.on('empty', function (event) {
                                FORM.validateHostedFields(event);
                            });

                            FORM.hostedFieldsInstance.on('notEmpty', function (event) {
                                FORM.validateHostedFields(event);
                            });

                            FORM.hostedFieldsInstance.on('blur', function (event) {
                                FORM.validateHostedFields(event, true);
                            });

                            FORM.hostedFieldsInstance.on('cardTypeChange', function (event) {
                                ctrl.payment.selectedCardType = event.cards.length === 1 ? event.cards[0].type : '';
                                FORM.setSurcharges();
                                FORM.validateHostedFields(event);
                            });
                        });

                        // Create a PayPal Checkout component.
                        // http://braintree.github.io/braintree-web/current/PayPalCheckout.html
                        // https://developers.braintreepayments.com/guides/paypal/checkout-with-paypal/javascript/v3
                        braintree.paypalCheckout.create({
                            client: clientInstance
                        }, function (paypalCheckoutErr, paypalCheckoutInstance) {
                            // Stop if there was a problem creating PayPal Checkout.
                            // This could happen if there was a network error or if it's incorrectly
                            // configured.
                            if (paypalCheckoutErr) {
                                console.error('Error creating PayPal Checkout:', paypalCheckoutErr);
                                return;
                            }

                            var environment = configurationConstant.environment === 'live' ? 'production' : 'sandbox';

                            paypal.Button.render({
                                env: environment,
                                commit: true,

                                style: {
                                    label: 'pay',       // checkout | credit | pay
                                    size: 'responsive', // small | medium | responsive
                                    shape: 'rect',      // pill | rect
                                    color: 'gold'       // gold | blue | silver
                                },

                                payment: function () {
                                    var amount = ctrl.payment.isTotalAmountSelected ?
                                        ctrl.paymentPrice.priceBreakDown.totalAmountInclusive : ctrl.paymentPrice.priceBreakDown.minDepositInclusive;

                                    return paypalCheckoutInstance.createPayment({
                                        flow: 'checkout',   // Required
                                        amount: amount,     // Required
                                        currency: ctrl.paymentPrice.priceBreakDown.currencyCode // Required
                                        // For available options, see
                                        // http://braintree.github.io/braintree-web/current/PayPalCheckout.html#createPayment
                                    });
                                },

                                onAuthorize: function (data, actions) {
                                    ctrl.payment.isProcessing = true;
                                    scope.$apply();

                                    return paypalCheckoutInstance.tokenizePayment(data)
                                        .then(function (payload) {
                                            ctrl.payment.nonce = payload.nonce;
                                            ctrl.payment.selectedCardBrand = 'Paypal';
                                            ctrl.payment.selectedCardBrandKey = 'paypal';
                                            ctrl.payment.cardName = payload.details.firstName + ' ' + payload.details.lastName;

                                            FORM.makePayment();
                                        });
                                },

                                onCancel: function (data) {
                                    ctrl.payment.isProcessing = false;
                                    scope.$apply();
                                },

                                onError: function (err) {
                                    ctrl.payment.isError = true;
                                    ctrl.payment.isProcessing = false;
                                    scope.$apply();
                                }
                            }, '#paypal-button').then(function () {
                                // The PayPal button will be rendered in an html element with the id
                                // `paypal-button`. This function will be called when the PayPal button
                                // is set up and ready to be used.
                            });
                        });
                    });
                }
            }

            FORM.makePayment = function () {
                ctrl.payment.isQantasFullPointsBurnBooking ? FORM.$qantas.find('input:focus').blur() : FORM.$payment.find('input:focus').blur();

                if (FORM.$paymentHasError || FORM.$detailsHasError) {
                    FORM.$paymentSubmitButton.removeClass(FORM.btnLoadingClass);
                } else {
                    FORM.doBookingModelMapping();
                    bookingService.MakePayment(ctrl.paymentPrice.cartMappingModel)
                        .then(function (data) {
                            FORM.$paymentSubmitButton.removeClass(FORM.btnLoadingClass);
                            ctrl.payment.isProcessing = false;

                            if (data && data.data && data.data.length > 0) {
                                var reservationResult = data.data[0];

                                        if (data.success) {
                                            scrollToTop();
                                            ctrl.payment.success = true;
                                            ctrl.payment.bookingReference = reservationResult.bookingReference;
                                            ctrl.payment.balanceDueDate = new Date(reservationResult.balanceDueDate).toDateString();
                                            ctrl.payment.ErrorType = reservationResult.errorType;
                                            ctrl.payment.ErrorMessage = reservationResult.errorMessage;

                                    var dataLayerModel = dataLayerService.buildBookingModel(
                                        ctrl.paymentPrice.priceBreakDown.totalAmount,
                                        ctrl.trip.code,
                                        ctrl.trip.name,
                                        reservationResult.bookingReference,
                                        reservationResult.amountPaid, //TODO QFFBurn how do we show the amount paid?
                                        ctrl.payment.selectedMethod
                                        //TODO QFFBurn should we add qantas burn to the data layer?
                                    );

                                    dataLayerService.pushTransaction(dataLayerModel);

                                            ctrl.payment.isPaymentSuccess = true;
                                        } else {
                                            ctrl.payment.isError = true;
                                            ctrl.payment.ErrorType = reservationResult.errorType;
                                            ctrl.payment.ErrorMessage = reservationResult.errorMessage;

                                    if (!$.isEmptyObject(ctrl.qantas.authObject)) {
                                        if (reservationResult.qantasPointsBurnQuoteRef.length > 0) {
                                            ctrl.qantas.authObject.quoteNumber = reservationResult.qantasPointsBurnQuoteRef;
                                        } else {
                                            FORM.resetQantasPointsBurn();
                                        }
                                    }
                                }
                            } else {
                                ctrl.payment.isError = true;
                            }

                            setStepsContainerHeight();
                        });
                }
            };

            FORM.assignHasOptional = function (passenger) {
                var hasOptional = false;

                if (typeof passenger.optional === 'object') {
                    Object.keys(passenger.optional).forEach(function (key) {
                        if (passenger.optional[key] !== '') {
                            hasOptional = true;
                        }
                    });
                }

                passenger.hasOptional = hasOptional;
            }

            FORM.checkOptionalData = function () {
                Object.keys(ctrl.forms).forEach(function (key) {
                    FORM.assignHasOptional(ctrl.forms[key])
                });
            }

            FORM.initQantasPointsBurnWidget = function () {
                if (ctrl.qantas.clientId.length > 0 && ctrl.qantas.clientName.length > 0) {
                    try {
                        // Qantas script must be added to page to enable qantas object
                        // Staging: https://cdn.stg.qantasloyalty.com/appcache/wid-redemptions-button/master/0.0.0/qantas.min.js
                        // Producton: https://cdn.qantasloyalty.com/appcache/wid-redemptions-button/master/0.0.0/qantas.min.js
                        qantas.Button.render({
                            Client: {
                                id: ctrl.qantas.clientId,
                                name: ctrl.qantas.clientName
                            },
                            payment: function (actions) {
                                return actions.createQuote(ctrl.payment.isTotalAmountSelected
                                    ? ctrl.paymentPrice.priceBreakDown.originalTotalAmount
                                    : ctrl.paymentPrice.priceBreakDown.originalMinDeposit);
                            },
                            onAuthorize: function (data) {
                                if (data) {
                                    if (data.errorCode) {
                                        this.onError(data);
                                        return;
                                    }
                                    ctrl.qantas.authObject = data;

                                    var amountSelection = ctrl.payment.isTotalAmountSelected
                                        ? ctrl.paymentPrice.priceBreakDown.originalTotalAmount
                                        : ctrl.paymentPrice.priceBreakDown.originalMinDeposit;
                                    var remainingBalance = parseFloat((amountSelection - data.currencyAmount).toFixed(2));
                                    ctrl.payment.isQantasFullPointsBurnBooking = amountSelection === data.currencyAmount && remainingBalance === 0;

                                    ctrl.payment.isTotalAmountSelected
                                        ? ctrl.paymentPrice.priceBreakDown.totalAmount = remainingBalance
                                        : ctrl.paymentPrice.priceBreakDown.minDeposit = remainingBalance;
                                    FORM.setSurcharges();

                                    this.modalToggle(false);

                                    FORM.showSnackbar();

                                    dataLayer.push({ 'event': 'qffBurnModalPointsApplied' });
                                } else {
                                    this.onError("There was an error returning the auth object from Qantas");

                                    this.modalToggle(false);

                                    return;
                                }
                            },
                            onError: function (data) {
                                console.log(data.toString());
                                this.modalToggle(false);
                            },
                            onClicked: function (data) {
                                var mobileDevice = false;

                                if (typeof window.orientation !== 'undefined') {
                                    mobileDevice = true;
                                }

                                // Prevent modal on mobile due to onClosed event not being called when closing qantas tab
                                if (!mobileDevice)
                                    this.modalToggle(true);

                                dataLayer.push({ 'event': 'qffBurnModalOpened' });
                            },
                            onClosed: function (data) {
                                this.modalToggle(false);

                                dataLayer.push({ 'event': 'qffBurnModalClosed' });
                            },
                            modalToggle: function (showModal) {
                                if (showModal)
                                    $('#booking-steps--qantas-overlay--modal').modal('show');
                                else
                                    $('#booking-steps--qantas-overlay--modal').modal('hide');
                            }
                            // Below are functions available which may be used in the future
                            //onLoad: function (data) { }
                        }, '#qantasBurnWidget');
                    } catch (e) {
                        if (e instanceof ReferenceError) {
                            // Qantas burn is not valid for this site/region;
                        } else {
                            console.log('There was a problem loading the Qantas burn widget');
                        }
                    }
                }
            };

            FORM.resetQantasPointsBurn = function () {
                // Close the snackbar before clearing variables
                var snackbar = angular.element('.trip-priceandbooking__snackbar');
                $(snackbar).fadeOut(500);

                ctrl.qantas.authObject = null;
                ctrl.payment.isQantasFullPointsBurnBooking = false;
                ctrl.paymentPrice.priceBreakDown.totalAmount = ctrl.paymentPrice.priceBreakDown.originalTotalAmount;
                ctrl.paymentPrice.priceBreakDown.minDeposit = ctrl.paymentPrice.priceBreakDown.originalMinDeposit;
                FORM.setSurcharges();
            };

            FORM.showSnackbar = function () {
                var snackbar = angular.element('.trip-priceandbooking__snackbar');
                $(snackbar).fadeIn(500);
                $timeout(function () {
                    $(snackbar).fadeOut(500);
                }, 8000);
            };


            FORM.init = function () {

                FORM.setupPassengerForms();
                FORM.btnLoadingClass = 'btn--loading';
                FORM.$detailsHasError = false;
                FORM.unbindedInputs = [];
                FORM.$payment = angular.element('.booking-form__payment__card form');
                FORM.$paymentHasError = false;
                FORM.$qantas = angular.element('.booking-form__qantas__card form');
                FORM.$paypalPayment = angular.element('.booking-form__paypal__card form');
                FORM.$paymentSubmitButton = angular.element('#booking-steps--payment-details .booking-form__payment__process');
                FORM.$paymentHostedFields = FORM.$payment.find('.braintree__hosted-field');
                FORM.$cardNumberField = angular.element('#payment-gateway--card-number');
                FORM.$cardIcon = $('<div/>', { id: 'payment-gateway--card-icon' });
                FORM.$termsAndConditionsControl = angular.element('.booking-form__payment__tnc');
                FORM.$paypalTermsAndConditionsControl = angular.element('.booking-form__paypal__tnc');
                FORM.$qantasTermsAndConditionsControl = angular.element('.booking-form__qantas__tnc');
                FORM.$formIsInitialized;

                FORM.registerUnbindedInputs();
                
                FORM.$details.on('form.validation.fail', function () {
                    FORM.scrollToFormError(FORM.$details);
                    FORM.$detailsHasError = true;
                });
                FORM.$details.on('form.submit.success', function () {
                    FORM.collectUnbindedInputs();
                    FORM.checkOptionalData();
                    FORM.$detailsHasError = false;
                });

                if (FORM.$formIsInitialized === true) {
                    return;
                } else {
                    FORM.$formIsInitialized = true;
                }

                FORM.setupPaymentGateway();
                FORM.initQantasPointsBurnWidget();

                FORM.$payment.on('form.submit.success', function () {
                    if (FORM.isHostedFieldsValid) {
                        FORM.$paymentHasError = false;
                        FORM.makePayment();
                    }
                });
                FORM.$payment.on('form.validation.fail', function () {
                    FORM.$paymentSubmitButton.removeClass(FORM.btnLoadingClass);
                    setStepsContainerHeight();
                    if (!FORM.$detailsHasError) FORM.scrollToFormError(FORM.$payment);
                    FORM.$paymentHasError = true;

                });

                FORM.$qantas.on('form.submit.success', function () {
                    FORM.$paymentHasError = false;
                    FORM.makePayment();
                });
                FORM.$qantas.on('form.validation.fail', function () {
                    FORM.$paymentSubmitButton.removeClass(FORM.btnLoadingClass);
                    setStepsContainerHeight();
                    if (!FORM.$detailsHasError) FORM.scrollToFormError(FORM.$payment);
                    FORM.$paymentHasError = true;
                });

                if (!ctrl.payment.hasTermsAndConditions) {
                    FORM.$termsAndConditionsControl.remove();
                    FORM.$paypalTermsAndConditionsControl.remove();
                    FORM.$qantasTermsAndConditionsControl.remove();
                }

                scope.$on('broadcast.tripPriceAndBookingController.submitPaymentForm', function () {
                    var form = ctrl.payment.isQantasFullPointsBurnBooking ? FORM.$qantas : FORM.$payment;
                    var submitButton = form.find('input[type=submit], button[type=submit]');
                    FORM.$paymentSubmitButton.addClass(FORM.btnLoadingClass);

                    if (FORM.$passengerFormsSubmitButtons) {
                        FORM.$passengerFormsSubmitButtons[0].click();
                    }

                    if (ctrl.payment.isQantasFullPointsBurnBooking) {
                        if (submitButton.length) {
                            submitButton.click();
                        }
                    }
                    else {
                        FORM.tokenizeHostedFields(function () {
                            if (submitButton.length) {
                                submitButton.click();
                            }
                        });
                    }

                    setStepsContainerHeight();
                });

                scope.$watch('tpbc.payment.selectedMethod', function () {
                    FORM.setSurcharges();
                    scope.tpbc.payment.isError = false;
                });

                scope.$watch('tpbc.payment.selectedAmount', function () {
                    ctrl.payment.isTotalAmountSelected = ctrl.payment.selectedAmount === 'total' ? true : false;

                    FORM.resetQantasPointsBurn();
                    FORM.setSurcharges();
                });

                $(angular.element('.form-control')).on('change', function () {
                    setStepsContainerHeight();
                });
            };

            FORM.scrollToFormError = function (form) {
                var position = form.find('.has-error').first().offset().top - 50;
                HELPERS.scrollTo(position);
            }

            var setupLoadMoreButton = function () {
                if (!ctrl.allDatesLoaded) {
                    if ($el.find('.trip-priceandbooking__departures__dates.active').find('.force-hide').length) {
                        ctrl.showLoadMoreDates = true;
                    }
                    else {
                        ctrl.showLoadMoreDates = false;
                    }
                }
                else {
                    ctrl.showLoadMoreDates = false;
                }
            }

            var setupBookingSteps = function () {
                pageWidth = angular.element('body').prop('clientWidth');
                var stepsWidth = $steps.length * pageWidth;
                $steps.css('width', pageWidth + 'px');
                $stepsList.css('width', stepsWidth + 'px');
                var bookingStepTranslation = pageWidth * ctrl.bookingStepIndex * -1;
                $stepsList.css('transform', 'translateX(' + bookingStepTranslation + 'px)');
                setStepsContainerHeight();
            }

            var setStepsContainerHeight = function (modifier) {
                $timeout(function () {
                    var currStep = $bookingSteps[ctrl.bookingStepIndex];
                    var heightModifier = typeof modifier === 'number' ? modifier : 0;
                    var expectedHeight = $(currStep).height() + heightModifier;
                    if (ctrl.bookingStepIndex === 4) {
                        expectedHeight = expectedHeight + 5;
                    }
                    $stepsListContainer.css('height', expectedHeight);
                });
            }

            var updateShowPrice = function () {
                ctrl.showPrice = (ctrl.bookingStepIndex !== 2 || !ctrl.isBookingEnabled);
            }

            var goToBookingStep = function () {
                var bookingStepTranslation = pageWidth * ctrl.bookingStepIndex * -1;
                $stepsList.css('transform', 'translateX(' + bookingStepTranslation + 'px)');
                ctrl.bookingStep.isBackButtonHidden = ctrl.bookingStepIndex == 0 || ctrl.bookingStepIndex == BOOKING_STEP_MAX_INDEX;
                scrollToTop();
                setStepsContainerHeight();
                updateShowPrice();
            }
            var resetFormValidation = function (divId) {
                var thisForm = angular.element('#' + divId);
                if (thisForm.length > 0) {
                    var invalidElements = thisForm[0].querySelectorAll('.has-error,.has-success');
                    if (invalidElements.length > 0) {
                        for (let i = 0; i < invalidElements.length; i++) {
                            var formGroup = $(invalidElements[i]);
                            formGroup.removeClass('has-error');
                            formGroup.removeClass('has-success');
                            formGroup.find('.error').remove();
                        }
                    }
                }
            }
            var goNextBookingStep = function () {
                if (ctrl.bookingStepIndex < BOOKING_STEP_MAX_INDEX) ctrl.bookingStepIndex++;
                goToBookingStep();
            }

            var goPreviousBookingStep = function () {
                if (ctrl.bookingStepIndex > 0) ctrl.bookingStepIndex--;
                goToBookingStep();
            }

            var goToBookingStep0 = function () {
                if (ctrl.bookingStepIndex >= 2) {
                    ctrl.bookingStepIndex = 0;
                    ctrl.showProgressBar = true;
                    ctrl.showBackButton = false;
                    goToBookingStep(0);
                }
                resetFormValidation('booking-steps--payment-details');
            }

            var goToBookingStep1 = function () {
                if (ctrl.bookingStepIndex === 1) {
                    ctrl.bookingStepIndex--;
                    goToBookingStep(1);
                }
                resetFormValidation('booking-steps--payment-details');
            }

            var goToBookingStep2 = function () {
                if (ctrl.bookingStepIndex === 2) {
                    ctrl.bookingStepIndex--;
                    goToBookingStep(2);
                }
                resetFormValidation('booking-steps--payment-details');
            }

            var goToBookingStep3 = function () {
                if (ctrl.bookingStepIndex > 2) {
                    ctrl.bookingStepIndex = 2;
                    ctrl.showProgressBar = true;
                    ctrl.showBackButton = false;
                    goToBookingStep(3);
                }
            }

            var getRoomTypes = function (onSuccess) {
                ctrl.isLoading = true;
                tripPriceAndBookingService.GetRoomTypes(ctrl.package.packageId, ctrl.date, ctrl.tripCode, ctrl.promoCode, ctrl.hasLastMinuteSpecials)
                    .then(function (data) {
                        ctrl.roomTypes = data;
                        if (data && data.length > 0) {
                            ctrl.hasRoomTypes = true;
                            ctrl.selectRoomType(data[0]);
                        }
                        else {
                            ctrl.hasRoomTypes = false;
                        }
                        if (typeof onSuccess === "function") {
                            onSuccess();
                        }
                        ctrl.isLoading = false;
                    });
            }

            var getMinimumDeposit = function (onSuccess) {
                ctrl.isLoading = true;

                var requestObj = new Object();
                requestObj.categoryId = ctrl.cabin.categoryId;
                requestObj.departureDate = ctrl.date;
                requestObj.duration = ctrl.trip.tripDuration;
                requestObj.itineraryId = ctrl.trip.itineraryShortId;
                requestObj.hasLastMinuteSpecials = ctrl.hasLastMinuteSpecials;
                requestObj.packageId = ctrl.package.packageId;
                requestObj.packageName = ctrl.package.packageTitle;
                requestObj.packageDescription = ctrl.package.packageDescription;
                requestObj.useCruiseService = ctrl.package.useCruiseService;
                requestObj.packageType = "Extended"; // What is this?
                requestObj.tripId = ctrl.trip.tripShortId;
                requestObj.roomCost = ctrl.roomCost;
                requestObj.promoCode = ctrl.promoCode;

                requestObj.rooms = new Array();
                var room = new Object();
                room.roomTypeId = ctrl.roomType.roomTypeId;
                room.numberOfPassengers = ctrl.roomType.allowedAdultNumber;
                room.passengerType = ctrl.cabin.passengerUpgrades[0].passengerType;
                room.totalPrice = 0;
                room.promotionNumber = ctrl.roomType.promotionNumber;
                room.promotionCode = ctrl.roomType.promotionCode;
                room.categoryCode = ctrl.roomType.categoryCode;
                room.fullFarePersonPrice = ctrl.cabin.passengerUpgrades[0].fullFareCabinPrice;
                room.personPrice = ctrl.cabin.passengerUpgrades[0].cabinPrice;
                room.upgradePrice = ctrl.currentCabinUpgradePrice(ctrl.cabin);
                requestObj.rooms.push(room);

                requestObj.cabinOriginalPrice = ctrl.cabinOriginalPrice;
                requestObj.cabins = new Array();
                var cabin = new Object();
                cabin.categoryId = ctrl.cabin.categoryId;
                cabin.categoryDescription = ctrl.cabin.categoryDescription;
                cabin.categoryName = ctrl.cabin.categoryName;
                cabin.categoryType = ctrl.cabin.categoryType;
                cabin.isPromotionAvailable = ctrl.cabin.isPromotionAvailable;
                cabin.doesContainChild = ctrl.cabin.doesContainChild;
                cabin.deckPlan = ctrl.cabin.deckPlan;
                cabin.maximumAvailable = ctrl.cabin.maximumAvailable;
                cabin.maximumAvailableCollection = ctrl.cabin.maximumAvailableCollection;
                cabin.isCabin = ctrl.cabin.isCabin;
                cabin.passengerUpgrades = ctrl.cabin.passengerUpgrades;
                requestObj.cabins.push(cabin);

                tripPriceAndBookingService.GetMinimumDeposit(requestObj)
                    .then(function (data) {
                        if (data && data.length > 0 && data[0].minimumDepositData && data[0].bookingData) {
                            ctrl.totalPrice = data[0].minimumDepositData.totalPrice;
                            ctrl.minimumDeposit = data[0].minimumDepositData.minimumDeposit;
                            ctrl.paymentDueDate = data[0].minimumDepositData.paymentDueDate;
                            ctrl.hasDepositOption = ctrl.minimumDeposit > 0 && (ctrl.minimumDeposit !== (ctrl.price * ctrl.roomType.allowedAdultNumber));

                            ctrl.bookingInfo = data[0].bookingData;
                            ctrl.payment.token = ctrl.bookingInfo.paymentSection.paymentGatewayToken;
                            ctrl.payment.hasTermsAndConditions = ctrl.bookingInfo.paymentSection.hasValidTermsAndConditions;
                            ctrl.extendWith(ctrl.bookingInfo.stepsJson.priceJsonString);
                            FORM.init();
                        }
                        else {
                            console.log("Minimum deposit or Booking Data are null");
                            goNextBookingStep(); // Move to Enquiry Form
                        }

                        if (typeof onSuccess === "function") {
                            onSuccess();
                        }
                        ctrl.isLoading = false;
                    });
            }

            var getLocation = function (onSuccess) {
                locationService.GetLocation()
                    .then(function (data) {
                        if (data) {
                            ctrl.userLocation.country = data.data[0];
                        }
                        if (typeof onSuccess === "function") {
                            onSuccess();
                        }
                    });
            }

            var scrollToTop = function () {
                angular.element('html, body').stop().animate({
                    scrollTop: $el.offset().top - 80
                }, 0);
            }

            var setPrice = function () {
                ctrl.previousPrice = ctrl.price;

                var price;

                if (ctrl.cabin && ctrl.cabin.isCabin) {
                    var cabinPrice = ctrl.cabin.passengerUpgrades && ctrl.cabin.passengerUpgrades.length ?
                        ctrl.cabin.passengerUpgrades[0].cabinPrice : 0;
                    var upgradePrice = ctrl.cabin.passengerUpgrades && ctrl.cabin.passengerUpgrades.length ?
                        ctrl.cabin.passengerUpgrades[0].upgradePrice : 0;

                    price = cabinPrice + upgradePrice;
                }
                else if (ctrl.roomType) {
                    price = ctrl.roomType.passengers && ctrl.roomType.passengers.length
                        ? ctrl.roomType.passengers[0].promoPricePerPerson > 0
                            ? ctrl.roomType.passengers[0].promoPricePerPerson
                            : ctrl.roomType.passengers[0].tripPricePerPerson
                        : 0;
                }

                ctrl.price = price;
            }

            var setupCarouselForCurrentPackage = function () {
                var activePackageClass = '.trip-priceandbooking__departures__dates.active';

                var $packageEl = angular.element(activePackageClass);

                if ($packageEl.length) {
                    var $carouselQuarterlyView = $packageEl.find('.quarterly-view-carousel');
                    var $carouselQuarterlyViewOffset = $packageEl.find('.quarterly-view-carousel-offset');
                    var $carouselSeasonView = $packageEl.find('.season-view-carousel');
                    var $carouselSeasonViewOffset = $packageEl.find('.season-view-carousel-offset');

                    $timeout(function () {
                        $carouselQuarterlyView.owlCarousel({
                            baseClass: 'quarterly-view-carousel',
                            loop: false,
                            nav: true,
                            navText: ['', ''],
                            margin: 30,
                            stagePadding: 5,
                            freeDrag: false,
                            startPosition: ctrl.package.startMonthIndex,
                            responsive: {
                                0: {
                                    items: 1,
                                    slideBy: 1
                                },
                                800: {
                                    items: 3,
                                    slideBy: 1
                                }
                            }
                        });
                        setupBookingSteps();
                        setupLoadMoreButton();
                        getLocation();

                        $carouselQuarterlyViewOffset.owlCarousel({
                            baseClass: 'quarterly-view-carousel-offset',
                            loop: false,
                            nav: true,
                            navText: ['', ''],
                            margin: 30,
                            stagePadding: 5,
                            freeDrag: false,
                            startPosition: ctrl.package.startMonthIndex + 1,
                            responsive: {
                                0: {
                                    items: 1,
                                    slideBy: 1
                                },
                                800: {
                                    items: 3,
                                    slideBy: 1
                                }
                            }
                        });
                        setupBookingSteps();
                        setupLoadMoreButton();
                        getLocation();

                        $carouselSeasonView.owlCarousel({
                            baseClass: 'season-view-carousel',
                            loop: false,
                            nav: true,
                            navText: ['', ''],
                            margin: 30,
                            stagePadding: 5,
                            freeDrag: false,
                            items: 1
                        });

                        $carouselSeasonViewOffset.owlCarousel({
                            baseClass: 'season-view-carousel-offset',
                            loop: false,
                            nav: true,
                            navText: ['', ''],
                            margin: 30,
                            stagePadding: 5,
                            freeDrag: false,
                            items: 1,
                            startPosition: 1
                        });
                    });
                }
            }

            var saveUrlIntoCookie = function () {
                var currentUrl = $window.location.origin + $window.location.pathname + $window.location.search;
                tripService.setTripUrl(currentUrl);
            }

            var watchCollapse = function (event) {
                var modifier;
                modifier = $(this)['height']('').height();
                modifier = event.type === 'show' ? modifier : -1 * modifier;
                setStepsContainerHeight(modifier);
            }

            $(window).on('resize', function () {
                setupBookingSteps();
            });

            scope.$on('broadcast.tripPriceAndBookingController.selectPackage', function () {
                setupLoadMoreButton();
                setupCarouselForCurrentPackage();
            });

            scope.$on('broadcast.tripPriceAndBookingController.selectDate', function () {
                ctrl.roomType = {};
                saveUrlIntoCookie();

                getRoomTypes(function () {
                    ctrl.bookingStepIndex = 1;
                    goToBookingStep();
                });
            });

            scope.$on('broadcast.tripPriceAndBookingController.selectRoomType', function () {
                ctrl.cabin = {};
                ctrl.hideCabins = false;
                setPrice();

                // If there is only one cabin and upgrade price is zero, select it
                if (!ctrl.roomType.cabinCategories ||
                    !ctrl.roomType.cabinCategories.length) {
                    ctrl.hideCabins = true;
                    ctrl.roomCost = 0;
                    setStepsContainerHeight();
                    return;
                }

                ctrl.roomCost = ctrl.roomType.passengers[0].tripPricePerPerson - ctrl.roomTypes[0].passengers[0].tripPricePerPerson;

                // If there is only one cabin and upgrade price is zero, select it
                if (ctrl.roomType.cabinCategories.length == 1 &&
                    ctrl.roomType.cabinCategories[0].passengerUpgrades &&
                    ctrl.roomType.cabinCategories[0].passengerUpgrades.length &&
                    ctrl.roomType.cabinCategories[0].passengerUpgrades[0].upgradePrice == 0) {
                    ctrl.selectCabin(ctrl.roomType.cabinCategories[0]);

                    if (!ctrl.roomType.cabinCategories[0].categoryId) {
                        ctrl.hideCabins = true;
                    }

                    setStepsContainerHeight();
                    return;
                }

                ctrl.roomType.cabinCategories.sort(function (a, b) {
                    if (a && a.passengerUpgrades.length && b && b.passengerUpgrades.length) {
                        return a.passengerUpgrades[0].upgradePrice - b.passengerUpgrades[0].upgradePrice;
                    }
                    return 0;
                });

                // select the default cabin
                if (ctrl.roomType.defaultCategoryId) {
                    var categoryId = ctrl.roomType.defaultCategoryId;
                    var hasSelectedCabin = false;
                    for (var i = 0; i < ctrl.roomType.cabinCategories.length; i++) {
                        if (ctrl.roomType.cabinCategories[i].categoryId == categoryId) {
                            ctrl.selectCabin(ctrl.roomType.cabinCategories[i]);
                            hasSelectedCabin = true;
                            break;
                        }
                    }

                    if (!hasSelectedCabin) {
                        var cabinCategories = ctrl.sortCabinCategoriesByUpgradePrice(ctrl.roomType);
                        ctrl.selectCabin(cabinCategories[0]);
                    }
                }

                setStepsContainerHeight();
            });

            scope.$on('broadcast.tripPriceAndBookingController.selectCabin', function () {
                setPrice();
            });

            scope.$on('broadcast.tripPriceAndBookingController.getMinimumDeposit', function () {
                ctrl.minimumDeposit = 0;
                ctrl.paymentDueDate = 0;
                ctrl.showMinimumDepositLoadingMessage = true;
                getMinimumDeposit(function () {
                    ctrl.bookingStepIndex = 2;
                    goToBookingStep();
                    ctrl.showMinimumDepositLoadingMessage = false;
                });
            });

            scope.$on('broadcast.tripPriceAndBookingController.goPreviousBookingStep', function () {
                goPreviousBookingStep();
            });

            scope.$on('broadcast.tripPriceAndBookingController.goToBookingStep2', function () {
                goToBookingStep2();
            });

            scope.$on('broadcast.tripPriceAndBookingController.goToBookingStep3', function () {
                goToBookingStep3();
            });

            scope.$on('broadcast.tripPriceAndBookingController.goToBookingStep1', function () {
                goToBookingStep1();
            });

            scope.$on('broadcast.tripPriceAndBookingController.goToBookingStep0', function () {
                goToBookingStep0();
            });

            scope.$on('broadcast.tripPriceAndBookingController.invokeWebChat', function () {
                $('.cx-webchat-chat-button').click();
            });

            scope.$on('broadcast.tripPriceAndBookingController.goToBookingStep', function () {
                goToBookingStep();
            });

            scope.$on('broadcast.tripPriceAndBookingController.loadMoreDates', function () {
                setStepsContainerHeight();
            });

            scope.$on('broadcast.tripPriceAndBookingController.submitBookingForm', function () {
                var form = angular.element('.trip-priceandbooking__book__form form');
                if (form.length) {
                    form.on('form.submit.initialised', function () {
                        ctrl.form.isSubmitButtonDisabled = true;
                    });
                    form.on('form.submit.success', function () {
                        ctrl.bookingStepIndex = BOOKING_STEP_MAX_INDEX;

                        var dataLayerModel = dataLayerService.buildBookingModel(
                            ctrl.totalPrice,
                            ctrl.trip.tripCode,
                            ctrl.trip.tripName
                        );

                        dataLayerService.pushEnquiry(dataLayerModel);

                        goToBookingStep();
                        ctrl.form.isSubmitButtonDisabled = false;
                        ctrl.showProgressBar = ctrl.showBackButton = false;

                    });
                    form.on('form.submit.error', function () {
                        ctrl.form.isSubmitButtonDisabled = false;
                    });
                    form.on('form.submit.invalid', function () {
                        ctrl.form.isSubmitButtonDisabled = false;
                        scrollToTop();
                    });

                    var submitButton = form.find('input[type=submit], button[type=submit]');
                    if (submitButton.length) {
                        submitButton.click();
                        form.on('submit', setStepsContainerHeight);
                    }
                }
            });

            scope.$on('broadcast.bookingFunnelFormController.resetPaymentMethod', function () {
                FORM.resetQantasPointsBurn();
            });

            $timeout(function () {
                // initialise booking steps after angular initialization is finished
                $steps = $stepsList.find('.trip-priceandbooking__booking-step');
                $bookingSteps = angular.element('.trip-priceandbooking__booking-step');
                BOOKING_STEP_MAX_INDEX = $steps.length - 1;

                $collapses = $stepsListContainer.find('.collapse');
                $collapses.on('show.bs.collapse hide.bs.collapse', watchCollapse);

            });
        }
        return directive;
    }

    function closeSnackbar() {
        var directive = {
            restrict: 'A',
            link: link
        };

        function link(scope, element, attr, ctrl) {
            function closeSnackbar() {
                var snackbar = angular.element('.trip-priceandbooking__snackbar');
                $(snackbar).fadeOut(500);
            }

            element.bind('click', closeSnackbar);
        }

        return directive;
    }

    function frequentFlyerValidation($q, $timeout, bookingService) {
        return {
            require: 'ngModel',
            link: function (scope, element, attr, ctrl) {
                ctrl.$asyncValidators.validateffn = function (modelValue, viewValue) {
                    var inputElement = angular.element(window.document.activeElement);
                    var input = inputElement[0];
                    var isInput = input.tagName === 'INPUT';

                    if ((modelValue !== undefined && ctrl.$isEmpty(modelValue)) || !isInput) {
                        if (isInput) {
                            input.setCustomValidity('');
                            inputElement.resetValidity();
                        }
                        return $q.resolve();
                    }

                    var def = $q.defer();

                    if (!$(input.parentElement).hasClass('field--loading')) {
                        $(input.parentElement).addClass('field--loading');
                    }

                    var formArray = Array.from(input.form.elements);
                    var currInputPos = formArray.map(function (e) { return e.name }).indexOf(input.name);
                    var modifiedFormArray = formArray.slice(0, currInputPos).reverse();
                    var lastName = modifiedFormArray.filter(function (e) { return new RegExp('lastname*').test(e.name); })[0].value;

                    bookingService.ValidateFrequentFlyer(lastName, modelValue)
                        .then(function (data) {
                            $(input.parentElement).removeClass('field--loading');

                            if (input.value.length > 0) {
                                if (data && data.length > 0) {
                                    var validationResponse = data[0];
                                    if (validationResponse.isValid) {
                                        input.dataset.errorMessage = '';
                                        input.setCustomValidity('');
                                        inputElement.setValidity('');
                                        def.resolve();
                                    }
                                    else {
                                        input.dataset.errorMessage = validationResponse.errorMsg;
                                        input.setCustomValidity(validationResponse.errorMsg);
                                        inputElement.setValidity(validationResponse.errorMsg);
                                        def.reject();
                                    }
                                }
                                else {
                                    var fallbackErrorMsg = "There was an error validating your frequent flyer number. Please try again later.";
                                    input.dataset.errorMessage = fallbackErrorMsg;
                                    input.setCustomValidity(fallbackErrorMsg);
                                    inputElement.setValidity(fallbackErrorMsg);
                                    def.reject();
                                }
                            } else {
                                def.resolve();
                            }
                        }, function (error) {
                            def.reject();
                        });

                    return def.promise;
                };
            }
        };
    };

    tripPriceAndBookingController.$inject = ['$scope', '$timeout'];

    function tripPriceAndBookingController($scope, $timeout) {
        var tpbc = this;
        tpbc.allDatesLoaded = false;
        tpbc.bookingStepIndex = 0;

        tpbc.userLocation = {
            country: ''
        }

        tpbc.trip = {
            tripCode: '',
            tripName: '',
            tripShortId: '',
            tripDuration: 0,
            itineraryShortId: ''
        }

        tpbc.forms = {
            passengerOne: {}
        }

        tpbc.package = {
            packageId: '',
            packageTitle: '',
            packageDescription: '',
            startMonthIndex: 0,
            useCruiseService: false
        };
        tpbc.dateStr = '';
        tpbc.date = {};
        tpbc.returnDate = {};
        tpbc.returnDateStr = {};
        tpbc.promoCode = '';
        tpbc.hasLastMinuteSpecials = false;

        tpbc.roomType = {};

        tpbc.roomCost = 0;
        tpbc.cabin = {};

        tpbc.cabinOriginalPrice = 0;
        tpbc.currentCabinImage = '';
        tpbc.hideCabins = false;
        tpbc.price = 0;
        tpbc.totalPrice = 0;
        tpbc.previousPrice = 0;
        tpbc.minimumDeposit = 0;
        tpbc.hasDepositOption = false;
        tpbc.paymentDueDate = {};
        tpbc.bookingInfo = {};
        tpbc.showMinimumDepositLoadingMessage = false;

        tpbc.isLoading = false;

        tpbc.form = {
            isSubscribeNewsletter: false,
            isSubmitButtonDisabled: false
        }

        tpbc.bookingStep = {
            isBackButtonHidden: true
        }

        tpbc.roomTypes = [];
        tpbc.bookingStepTitles = [];
        tpbc.bookingMainTitles = [];

        tpbc.hasRoomTypes = false;

        tpbc.setBookingStepClass = function () {
            var cssClass = 'trip-priceandbooking';
            if (tpbc.bookingInfo && !tpbc.payment.isPaymentSuccess && tpbc.showProgressBar) {
                cssClass = 'trip-priceandbooking newtrip-priceandbooking';
            }
            if (tpbc.bookingStepIndex === 3) {
                cssClass = 'trip-priceandbooking newtrip-priceandbooking';
            }

            return cssClass;
        }

        tpbc.setProgressBarClass = function (stepnumber) {
            var cssClass = '';
            if (stepnumber === 0) {
                if (tpbc.showStep1()) {
                    cssClass = 'active';
                }
                if (tpbc.showStep2()) {
                    cssClass = 'complete';
                }
                if (tpbc.showStep3()) {
                    cssClass = 'complete';
                }
            }

            if (stepnumber === 1) {
                if (tpbc.showStep1()) {
                    cssClass = 'incomplete';
                }
                if (tpbc.showStep2()) {
                    cssClass = 'active';
                }
                if (tpbc.showStep3()) {
                    cssClass = 'complete';
                }
            }

            if (stepnumber === 2) {
                if (tpbc.showStep1()) {
                    cssClass = 'incomplete';
                }
                if (tpbc.showStep2()) {
                    cssClass = 'incomplete';
                }
                if (tpbc.showStep3()) {
                    cssClass = 'active';
                }
            }

            return cssClass;
        }

        tpbc.showStep1 = function () {
            return true;
        };

        tpbc.showStep2 = function () {
            if (tpbc.bookingStepIndex === 0) {
                return false;
            }
            return true;
        };

        tpbc.showStep3 = function () {
            if (tpbc.bookingStepIndex === 0 || tpbc.bookingStepIndex === 1) {
                return false;
            }
            return true;
        };
        tpbc.showPrice = true;
        tpbc.isBookingEnabled = true;

        tpbc.setTrip = setTrip;
        tpbc.loadMoreDates = loadMoreDates;
        tpbc.selectPackage = selectPackage;
        tpbc.selectDate = selectDate;
        tpbc.selectRoomType = selectRoomType;
        tpbc.selectCabin = selectCabin;
        tpbc.setCabinImage = setCabinImage;
        tpbc.goPreviousBookingStep = goPreviousBookingStep;
        tpbc.goToBookingStep0 = goToBookingStep0;
        tpbc.goToBookingStep1 = goToBookingStep1;
        tpbc.goToBookingStep2 = goToBookingStep2;
        tpbc.goToBookingStep3 = goToBookingStep3;
        tpbc.goToBookingStep = goToBookingStep;
        tpbc.invokeWebChat = invokeWebChat;
        tpbc.setBookingStepTitles = setBookingStepTitles;
        tpbc.setBookingMainTitles = setBookingMainTitles;
        tpbc.submitBookingForm = submitBookingForm;
        tpbc.resetBooking = resetBooking;
        tpbc.getRoomTypeBasePrice = getRoomTypeBasePrice;
        tpbc.currentCabinUpgradePrice = currentCabinUpgradePrice;
        tpbc.cabinUpgradePrice = cabinUpgradePrice;
        tpbc.setCabinOriginalPrice = setCabinOriginalPrice;
        tpbc.lowestUpgradePrice = lowestUpgradePrice;
        tpbc.sortCabinCategoriesByUpgradePrice = sortCabinCategoriesByUpgradePrice;
        tpbc.setFinalState = setFinalState;
        tpbc.initBookingSettings = initBookingSettings;
        tpbc.extendWith = extendWith;
        tpbc.resetPaymentMethod = resetPaymentMethod;
        tpbc.showBackButton = false;
        tpbc.showProgressBar = true;
        tpbc.paymentPrice = {
            priceBreakDown: {},
            surchargeDetails: {},
            cartMappingModel: {}
        };
        tpbc.payment = {
            success: false,
            cardName: '',
            token: '',
            nonce: '',
            selectedMethod: 'credit',
            hasTermsAndConditions: false,
            termsAndConditions: false,
            selectedAmount: 'total',
            selectedCardType: '',
            selectedCardBrand: '',
            selectedCardBrandKey: '',
            selectedSurchargePct: '',
            isError: false,
            isProcessing: false,
            bookingReference: '',
            balanceDueDate: '',
            paypalTermsAccepted: false,
            isQantasFullPointsBurnBooking: false,
            isTotalAmountSelected: true,
            isPaymentSuccess: false,
            submit: submitPaymentForm
        };

        tpbc.qantas = {
            clientId: '',
            clientName: '',
            authObject: null
        };

        function extendWith(jsonString) {
            var obj = JSON.parse(jsonString);
            obj.priceBreakDown.hasDeposit = obj.priceBreakDown.minDeposit > 0 && obj.priceBreakDown.minDeposit !== obj.priceBreakDown.totalAmount;
            tpbc.payment.selectedAmount = obj.priceBreakDown.hasDeposit ? 'deposit' : 'total';
            tpbc.payment.isTotalAmountSelected = tpbc.payment.selectedAmount === 'total' ? true : false;
            tpbc.paymentPrice.priceBreakDown = obj.priceBreakDown;
            tpbc.paymentPrice.priceBreakDown.originalTotalAmount = tpbc.paymentPrice.priceBreakDown.totalAmount;
            tpbc.paymentPrice.priceBreakDown.totalAmountInclusive = tpbc.paymentPrice.priceBreakDown.totalAmount;
            tpbc.paymentPrice.priceBreakDown.surchargeAmount = 0;
            tpbc.paymentPrice.priceBreakDown.originalMinDeposit = tpbc.paymentPrice.priceBreakDown.minDeposit;
            tpbc.paymentPrice.priceBreakDown.minDepositInclusive = tpbc.paymentPrice.priceBreakDown.minDeposit;
            tpbc.paymentPrice.priceBreakDown.minDepositSurchargeAmount = 0;
            tpbc.paymentPrice.surchargeDetails = obj.surchargeDetails;
            tpbc.paymentPrice.cartMappingModel = obj.cartMappingModel;
            tpbc.paymentPrice.surchargeDetails.selectedSurchargePct = '';
        }
        function setFinalState(options) {
            options.date = new Date(options.dateStr);
            options.returnDate = new Date(options.returnDateStr);
            tpbc = angular.extend(tpbc, options);
        }

        function setTrip(tripCode, tripName, tripShortId, tripDuration, itineraryShortId) {
            tpbc.trip.tripCode = tripCode;
            tpbc.trip.tripName = tripName;
            tpbc.trip.tripShortId = tripShortId;
            tpbc.trip.tripDuration = tripDuration;
            tpbc.trip.itineraryShortId = itineraryShortId;
        }

        function loadMoreDates() {
            tpbc.allDatesLoaded = true;
            tpbc.showLoadMoreDates = false;
            $scope.$broadcast('broadcast.tripPriceAndBookingController.loadMoreDates');
        }

        function selectPackage(packageId, packageTitle, packageDescription, startMonthIndex, useCruiseService) {
            tpbc.package.packageId = packageId;
            tpbc.package.packageTitle = packageTitle;
            tpbc.package.packageDescription = packageDescription;
            tpbc.package.startMonthIndex = parseInt(startMonthIndex, 10) || 0;
            tpbc.package.useCruiseService = useCruiseService;

            $timeout(function () {
                $scope.$broadcast('broadcast.tripPriceAndBookingController.selectPackage');
            }, 700);
        }

        function selectDate(date, returnDate, tripCode, promoCode, hasLastMinuteSpecials) {
            tpbc.dateStr = date;
            tpbc.returnDateStr = returnDate;
            tpbc.date = new Date(date);
            tpbc.returnDate = new Date(returnDate);
            tpbc.tripCode = tripCode;
            tpbc.promoCode = promoCode;
            tpbc.hasLastMinuteSpecials = hasLastMinuteSpecials;
            $scope.$broadcast('broadcast.tripPriceAndBookingController.selectDate');
        }

        function selectRoomType(roomType) {
            tpbc.roomType = roomType;
            $scope.$broadcast('broadcast.tripPriceAndBookingController.selectRoomType');
        }

        function selectCabin(cabin) {
            tpbc.cabin = cabin;
            if (cabin.categoryId > 0)
                $scope.$broadcast('broadcast.tripPriceAndBookingController.selectCabin');
        }

        function goPreviousBookingStep() {
            tpbc.showBackButton = false;
            tpbc.showProgressBar = true;
            $scope.$broadcast('broadcast.tripPriceAndBookingController.goPreviousBookingStep');
        }

        function goToBookingStep0() {
            $scope.$broadcast('broadcast.tripPriceAndBookingController.goToBookingStep0');
        }

        function goToBookingStep1() {
            $scope.$broadcast('broadcast.tripPriceAndBookingController.goToBookingStep1');
        }

        function goToBookingStep2() {
            $scope.$broadcast('broadcast.tripPriceAndBookingController.goToBookingStep2');
        }

        function goToBookingStep3() {
            $scope.$broadcast('broadcast.tripPriceAndBookingController.goToBookingStep3');
        }

        function invokeWebChat() {
            $scope.$broadcast('broadcast.tripPriceAndBookingController.invokeWebChat');
        }

        function goToBookingStep(index) {
            if (index === 2 && tpbc.isBookingEnabled) {
                // booking is enabled so get minimum deposit and proceed to booking step
                $scope.$broadcast('broadcast.tripPriceAndBookingController.getMinimumDeposit');
            }
            else {
                tpbc.bookingStepIndex = index;
                $scope.$broadcast('broadcast.tripPriceAndBookingController.goToBookingStep');
                tpbc.showBackButton = true;
                tpbc.showProgressBar = false;
            }
        }

        function submitBookingForm() {
            $scope.$broadcast('broadcast.tripPriceAndBookingController.submitBookingForm');
        }

        function setBookingStepTitles(titles) {
            // remove booking summary step title if booking is disabled
            if (!tpbc.isBookingEnabled) {
                titles.splice(2, 1);
            }

            tpbc.bookingStepTitles = titles;
        }

        function setBookingMainTitles(titles) {
            tpbc.bookingMainTitles = titles;
        }

        function initBookingSettings(isEnabled, qantasClientId, qantasClientName) {
            tpbc.isBookingEnabled = isEnabled;
            tpbc.qantas.clientId = qantasClientId;
            tpbc.qantas.clientName = qantasClientName;
        }

        function setCabinImage(cabinImage) {
            tpbc.currentCabinImage = cabinImage;
        }

        function resetBooking() {
            tpbc.bookingStepIndex = 0;
            tpbc.dateStr = '';
            tpbc.date = {};
            tpbc.promoCode = '';
            tpbc.hasLastMinuteSpecials = false;
            tpbc.roomType = {};
            tpbc.cabin = {};
            tpbc.price = 0;
            tpbc.previousPrice = 0;
            $scope.$broadcast('broadcast.tripPriceAndBookingController.goToBookingStep');
        }

        function getRoomTypeBasePrice(roomType) {
            var roomBasePrice = roomType.passengers[0].tripPricePerPerson;
            return roomBasePrice;
        }

        function currentCabinUpgradePrice(cabin) {
            var cheapestPrice = tpbc.getRoomTypeBasePrice(tpbc.roomType);
            var cabinPrice = cabin.passengerUpgrades[0].fullFareCabinPrice;
            var cabinUpgradePrice = cabin.passengerUpgrades[0].upgradePrice;

            return cabinPrice - cheapestPrice + cabinUpgradePrice;
        }

        function cabinUpgradePrice(cabin) {
            var cabinPrice = cabin.passengerUpgrades[0].cabinPrice;
            var cabinUpgradePrice = cabin.passengerUpgrades[0].upgradePrice;

            return cabinPrice - tpbc.price + cabinUpgradePrice;
        }

        function setCabinOriginalPrice() {
            if (!tpbc.roomType || !tpbc.roomType.passengers || !tpbc.roomType.passengers.length || !tpbc.cabin || !tpbc.cabin.passengerUpgrades || !tpbc.cabin.passengerUpgrades.length) return 0;
            var roomTypeOriginalPrice = tpbc.roomType.passengers[0].tripPricePerPerson;
            var cabinUpgradePrice = tpbc.cabin.passengerUpgrades[0].upgradePrice;

            return roomTypeOriginalPrice + cabinUpgradePrice;
        }

        function lowestUpgradePrice(roomType) {
            var cabinCategories = tpbc.sortCabinCategoriesB.upgradePrice(roomType);
            return cabinCategories[0].passengerUpgrades[0].upgradePrice;
        }

        function sortCabinCategoriesByUpgradePrice(roomType) {
            var cabinCategories = roomType.cabinCategories.sort(function (a, b) {
                var aPrice = a.passengerUpgrades[0].upgradePrice;
                var bPrice = b.passengerUpgrades[0].upgradePrice;
                return aPrice - bPrice;
            });

            return cabinCategories;
        }

        function submitPaymentForm() {
            $scope.$broadcast('broadcast.tripPriceAndBookingController.submitPaymentForm');
        }

        function resetPaymentMethod() {
            $scope.$broadcast('broadcast.bookingFunnelFormController.resetPaymentMethod');
        }
    }
})();
;
(function(){
    'use strict';

    angular
        .module('Phoenix.Shared.directives')
        .directive('pageHeroCarousel', ['$timeout', pageHeroCarousel])
        .directive('pageHero', pageHero)
        .directive('videoHero', ['$window', '$timeout', videoHero]);

    function pageHeroCarousel($timeout) {
        return {
            restrict: 'A',
            scope: true,
            require: '^pageHero',
            link: link
        };

        function link(scope, element, attr, ctrl) {

            var CAROUSEL = {};

            CAROUSEL.element = $(element);
            CAROUSEL.init = function () {

                // Only initialise a carousel if there are more than 1 slides
                var enableCarousel = (CAROUSEL.element.children().length > 1);

                if (!enableCarousel) {
                    CAROUSEL.element.addClass('owl-carousel--single-slide');
                    return;
                }

                CAROUSEL.element.owlCarousel({
                    items: 1,
                    loop: true,
                    nav: true,
                    navText: false,
                    dots: false,
                    lazyLoad: true,
                    lazyContent: true,
                    mouseDrag: enableCarousel,
                    touchDrag: enableCarousel,
                });


                CAROUSEL.leftArrow = CAROUSEL.element.find('.owl-prev');
                CAROUSEL.rightArrow = CAROUSEL.element.find('.owl-next');

                // Due to an owl carousel bug that returns the current slide index differently for dragging and clicking between slides,
                // need to hook into the dom button clicks instead of listening for carousel events
                CAROUSEL.leftArrow.on('click', function () {
                    ctrl.title.showPrevious();
                    scope.$apply();
                });

                CAROUSEL.rightArrow.on('click', function () {
                    ctrl.title.showNext();
                    scope.$apply();
                });

                CAROUSEL.element.on('dragged.owl.carousel', function (e) {
                    if (e.relatedTarget['_drag']['direction'] === 'left') {
                        ctrl.title.showNext();
                    } else {
                        ctrl.title.showPrevious();
                    }
                    scope.$apply();
                });
            }

            $timeout(function () {
                CAROUSEL.init();
            });

        }
    }

    function pageHero() {
        return {
            restrict: 'A',
            scope: true,
            controller: 'pageHeroController',
            controllerAs: 'phc',
            bindToController: true
        };
    }

    function videoHero($window, $timeout) {
        return {
            restrict: 'A',
            scope: true,
            controller: 'videoPageHeroController',
            controllerAs: 'vphc',
            bindToController: true,
            link: link
        };

        function link(scope, element, attr, ctrl) {

            // Adapted from https://codepen.io/ccrch/pen/GgPLVW
            var VIDEO = {};
            VIDEO.isSupported = true;
            VIDEO.PLAY_COUNT = 3
            VIDEO.player = {};
            VIDEO.$element = $(element);


            VIDEO.addApiTag = function () {
                var tag = document.createElement('script');
                tag.src = 'https://www.youtube.com/player_api';
                var firstScriptTag = document.getElementsByTagName('script')[0];
                firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
            }

            VIDEO.setupPlayer = function () {

                var playCount = 0;
                var playerDefaults = { autoplay: 1, autohide: 1, modestbranding: 0, rel: 0, showinfo: 0, controls: 0, disablekb: 1, enablejsapi: 0, iv_load_policy: 3, loop: 1, playsinline: 1 };

                $window.onYouTubePlayerAPIReady = function () {
                    VIDEO.player = new YT.Player('video-hero-player',
                        {
                            events: {
                                'onReady': onPlayerReady,
                                'onStateChange': onPlayerStateChange,
                                'onError': onPlayerError
                            },
                            playerVars: playerDefaults
                        });
                }

                function onPlayerReady(e) {
                    VIDEO.player.loadVideoById(ctrl.videoId);
                    VIDEO.player.mute();
                    VIDEO.resize();
                    scope.$apply();
                }

                function onPlayerStateChange(e) {
                    if (e.data === YT.PlayerState.ENDED) {
                        playCount++;
                        VIDEO.player.seekTo(0);
                        if (playCount === VIDEO.PLAY_COUNT) {
                            VIDEO.player.pauseVideo();
                            ctrl.isVideoPlaying = false;
                            scope.$apply();
                        }
                    } else if (e.data === YT.PlayerState.PLAYING) {
                        ctrl.isVideoLoaded = true;
                        ctrl.isVideoPlaying = true;
                        scope.$apply();
                    }
                }

                function onPlayerError() {
                    ctrl.displayVideo = false;
                    ctrl.isVideoLoaded = false;
                    scope.$apply();
                }
            }

            VIDEO.init = function () {

                VIDEO.checkBrowserSupport();
                if (!VIDEO.isSupported) return;

                VIDEO.setDisplayFlag();

                if (!ctrl.displayVideo) return;

                VIDEO.addApiTag();
                VIDEO.setupPlayer();
                VIDEO.setupClickOutside();

                $(window).on('resize', function () {
                    if (!ctrl.isVideoLoaded) return;
                    VIDEO.resize();
                });
            }

            // Pauses the video at the first frame on clicking outside the video
            VIDEO.setupClickOutside = function () {

                var windowW = $(window).width(),
                    windowH = $(window).height();
                var pos = VIDEO.$element.offset(),
                    elX = pos.left,
                    elY = pos.top,
                    elXEnd = elX + VIDEO.$element.width(),
                    elYEnd = elY + VIDEO.$element.height();

                var onDocumentClick = function (e) {

                    if (ctrl.isVideoPlaying) {
                        var clickedX = e.pageX,
                            clickedY = e.pageY;

                        // need to get different X and Y event values for touch
                        if (clickedX === undefined || clickedY === undefined) {
                            if (e.originalEvent.touches.length) {
                                clickedX = e.originalEvent.touches[0].pageX;
                                clickedY = e.originalEvent.touches[0].pageY;
                            }
                        }

                        if (clickedX < elX ||
                            clickedY < elY ||
                            clickedX > elXEnd ||
                            clickedY > elYEnd) {

                            VIDEO.player.seekTo(0);
                            VIDEO.player.pauseVideo();
                            ctrl.isVideoPlaying = false;
                            $(document).off('click touchstart', onDocumentClick);
                        }
                    }
                }

                $(document).on('click touchstart', onDocumentClick);
            }

            VIDEO.resize = function () {

                VIDEO.$playerEl = $('#video-hero-player');

                var w = $(window).width() + 200,
                    h = $(window).height() + 200;

                if (w / h > 16 / 9) {
                    VIDEO.player.setSize(w, w / 16 * 9);
                    VIDEO.$playerEl.css({ 'left': '0' });
                } else {
                    VIDEO.player.setSize(h / 9 * 16, h);
                    VIDEO.$playerEl.css({ 'left': -(VIDEO.$playerEl.outerWidth() - w) / 2 });
                }
            }

            VIDEO.checkBrowserSupport = function () {
                var v = document.createElement('video');
                if (!v.canPlayType || !v.canPlayType('video/mp4').replace(/no/, '')) {
                    ctrl.displayVideo = false;
                    VIDEO.isSupported = false;
                }
            }

            VIDEO.setDisplayFlag = function () {
                var media = window.matchMedia('(max-width: 767px)');
                function toggleVideo(mediaQuery) {
                    if (mediaQuery.matches) {
                        ctrl.displayVideo = false;
                    } else {
                        ctrl.displayVideo = true;
                    }
                }
                toggleVideo(media);
            }

            VIDEO.init();
        }
    }

})();;
angular.module('Phoenix.Shared.services')
    .factory('bookingService', ['$http', '$q', 'utilityService', function ($http, $q, utilityService) {

        var BOOKING_MAKEPAYMENT_URL = '/api/booking/makepayment';
        var FREQUENT_FLYER_VALIDATION_URL = '/api/booking/validatefrequentflyer';
        var canceller;
        return {
            MakePayment: function (makePaymentRequest) {
                // cancel any outstanding ajax request
                if (canceller) {
                    canceller.resolve();
                }

                var url = BOOKING_MAKEPAYMENT_URL;
                var ip = utilityService.GetQueryStringParameters('ip');
                if (ip) {
                    url += '?ip=' + ip
                }

                canceller = $q.defer();

                return $http({
                    method: 'POST',
                    cache: false,
                    url: url,
                    timeout: canceller.promise,
                    data: {
                        'primaryPassenger': makePaymentRequest.primaryPassenger,
                        'additionalPassenger': makePaymentRequest.additionalPassenger,
                        'paymentDetail': makePaymentRequest.paymentDetail
                    }
                })
                    .then(function success(response) {
                        if (response.status >= 200 && response.status < 300) {
                            return response.data;
                        }
                    });
            },
            ValidateFrequentFlyer: function (surname, frequentFlyerNumber) {
                // cancel any outstanding ajax request
                if (canceller) {
                    canceller.resolve();
                }

                var url = FREQUENT_FLYER_VALIDATION_URL;
                var ip = utilityService.GetQueryStringParameters('ip');
                if (ip) {
                    url += '?ip=' + ip
                }

                canceller = $q.defer();

                return $http({
                    method: 'POST',
                    cache: false,
                    url: url,
                    timeout: canceller.promise,
                    data: {
                        'surname': surname,
                        'frequentFlyerNumber': frequentFlyerNumber
                    }
                })
                    .then(function success(response) {
                        if (response.status >= 200 && response.status < 300) {
                            return response.data.data;
                        }
                    });
            }
        }
    }
    ]);;
angular.module('Phoenix.Shared.services')
    .factory('dataLayerService', [function () {

        return {
            buildBookingModel: function(
                tripPrice,
                tripCode,
                tripName,
                transactionId,
                transactionTotal,
                transactionPaymentType,
                quantity
            ) {
                if (quantity === null || quantity === 'undefined') { quantity = 1; }
                return {
                    tripCode: tripCode,
                    tripName: tripName,
                    tripPrice: tripPrice,
                    transactionId: transactionId,
                    transactionTotal: transactionTotal,
                    transactionPaymentType: transactionPaymentType,
                    quantity: quantity
                };
            },

            pushTransaction: function (bookingModel) {

                dataLayer.push({
                    'transactionId': bookingModel.transactionId, // Transaction ID - Type:String - Required
                    'transactionTotal': bookingModel.transactionTotal, //total revenue - Type:Numeric - Required : NOTE - DO NOT INCLUDE SURGARGE
                    'transactionProducts': [{
                        'sku': bookingModel.tripCode, // Product SKU - Type:String - Required : Example - EULC13
                        'name': bookingModel.tripName, // Product Name - Type:String - Required  : Example - Croatia And Balkan Peninsula
                        'price': bookingModel.tripPrice, // Product Price - Type:Numeric - Required
                        'quantity': bookingModel.quantity // Product Quantity - Type:Numeric - Required
                    }],
		            'event': 'transactionComplete',
                    'transactionPaymentType': bookingModel.transactionPaymentType, // Add transaction type - Example - Credit, Debit or PayPal
                    'transactionProductsSku': bookingModel.tripCode,
                    'transactionProductsName': bookingModel.tripName,
                    'transactionProductsPrice': bookingModel.tripPrice
                });
            },

            pushEnquiry: function (bookingModel) {

                dataLayer.push({
                    'Bookingsku': bookingModel.tripCode, // Product SKU - Type:String - Required : Example - EULC13
                    'Bookingname': bookingModel.tripName, // Product Name - Type:String - Required  : Example - Croatia And Balkan Peninsula
                    'Bookingprice': bookingModel.tripPrice, // Product Price - Type:Numeric - Required
                    'Bookingquantity': bookingModel.quantity, // Product Quantity - Type:Numeric - Required
		            'event': 'enquiryComplete'
                });
            }
        }
    }
]);;
angular.module('Phoenix.Shared.services')
    .factory('finalizeBookingService', ['$http', '$timeout', '$q', 'utilityService', function ($http, $timeout, $q, utilityService) {
        var FINALIZE_BOOKING_URL = '/api/booking/finalizebooking/';

        var canceller;

        return {
            FinalizeBooking: function (finalizeBookingRequest) {
                // cancel any outstanding ajax request
                if (canceller) {
                    canceller.resolve();
                }

                var url = FINALIZE_BOOKING_URL;
                var ip = utilityService.GetQueryStringParameters('ip');
                if (ip) {
                    url += '&ip=' + ip
                }
                canceller = $q.defer();

                return $http({
                    method: 'POST',
                    cache: true,
                    url: url,
                    timeout: canceller.promise,
                    data: {
                        "noOfPassengers": finalizeBookingRequest.noOfPassengers,
                        "selectedTourPrice": finalizeBookingRequest.selectedTourPrice,
                        "selectedMethod": finalizeBookingRequest.selectedMethod,
                        "selectedAmount": finalizeBookingRequest.selectedAmount,
                        "selectedCardBrand": finalizeBookingRequest.selectedCardBrandKey,
                        "selectedSurchargePct": finalizeBookingRequest.selectedSurchargePct,
                        "passengers": finalizeBookingRequest.passengers,
                        "surchargeAmount": finalizeBookingRequest.surchargeAmount,
                        "nonce": finalizeBookingRequest.nonce,
                        "totalAmountInclusive": finalizeBookingRequest.totalAmountInclusive,
                        "tripCode": finalizeBookingRequest.tripCode,
                        "tourStartDate": finalizeBookingRequest.tourStartDate,
                        "tourEndDate": finalizeBookingRequest.tourEndDate,
                        "currencyCode": finalizeBookingRequest.currencyCode
                    }
                })
                    .then(function success(response) {
                        if (response.status >= 200 && response.status < 300) {
                            return response.data.data;
                        }
                    });
            }
        }
    }
    ]);;
angular.module('Phoenix.Shared.services')
    .factory('locationService', ['$http', '$timeout', function ($http) {
        var IPINFO_BASE_URL = '/api/trip/getUserLocation';

        return {
            GetLocation: function () {
                return $http({
                    method: 'GET',
                    cache: true,
                    url: IPINFO_BASE_URL
                })
                    .then(function success(response) {
                        if (response.status >= 200 && response.status < 300) {
                            return response.data;
                        }
                        else {
                            return "Australia";
                        }
                    }, function error(error) {
                        return "Australia";
                    });
            }
        };
    }
    ]);;
angular.module('Phoenix.Shared.services')
    .factory('priceService', [function () {
        return {
            // Calculates the surcharge for a given amount from a percentage string. ie '2.2%'
            calculateSurcharge: function (fltAmount, strSurchargePct) {

                if (isNaN(fltAmount) || fltAmount <= 0) return 0;

                var pctParsed = parseFloat(strSurchargePct);
                var pct = isNaN(pctParsed) ? 0 : pctParsed / 100.0;

                if (!pct) return 0;

                var surchargeAmount = fltAmount * pct;

                return surchargeAmount;
            },

            convertPriceToNumber: function(strPrice) {
                return Number(strPrice.replace(/[^0-9\.-]+/g, ""));
            }
        }
    }
]);;
angular.module('Phoenix.Shared.services')
    .factory('searchService', ['$http', '$q', 'utilityService', function ($http, $q, utilityService) {

        var SEARCH_SERVICE_BASE_URL = '/api/search';
        var SEARCH_AUTOCOMPLETE_BASE_URL = '/api/search/autocomplete';

        var formatArray = function (arr) {
            if (arr) {
                return arr.join('|');
            }
            return '';
        }
        var canceller;

        return {
            GetResults: function (keywords, filters, pageSize, pageIndex) {

                // cancel any outstanding ajax request
                if (canceller) {
                    canceller.resolve();
                }

                var qs = '?keywords=' + (keywords || '') +
                    '&filters=' + formatArray(filters) +
                    '&pageSize=' + pageSize +
                    '&pageIndex=' + pageIndex;

                var ip = utilityService.GetQueryStringParameters('ip');
                if (ip) {
                    qs += '&ip=' + ip
                }

                canceller = $q.defer();

                return $http({
                    method: 'GET',
                    cache: true,
                    url: SEARCH_SERVICE_BASE_URL + qs,
                    timeout: canceller.promise
                })
                .then(
                    function success(response) {

                        if (response.status >= 200 && response.status < 300) {
                            return response.data;
                        }
                        return null;
                    },
                    function error(response) {
                        return null;
                    }
                );
            },
            GetAutocomplete: function () {

                var qs = '';

                var ip = utilityService.GetQueryStringParameters('ip');
                if (ip) {
                    qs = '?ip=' + ip
                }

                return $http({
                    method: 'GET',
                    cache: true,
                    url: SEARCH_AUTOCOMPLETE_BASE_URL + qs
                })
                .then(
                    function success(response) {

                        if (response.status >= 200 && response.status < 300) {
                            return response.data;
                        }
                        return null;
                    },
                    function error(response) {
                        return null;
                    }
                );
            },
        }
    }
]);;
angular.module('Phoenix.Shared.services')
    .factory('tripFinderService', ['$http', '$q', 'utilityService', function ($http, $q, utilityService) {

        var TRIP_SEARCH_SERVICE_BASE_URL = '/api/trip/search';

        var formatArray = function (arr) {
            if (arr) {
                return arr.join(',');
            }
            return '';
        }

        /*
        * Given an array of durations we need to return them as an underscore separated string
        * ex: ['2,7', '15'] => '2,7_15'
        */
        function getDurations(arr) {
            arr = arr || [];
            return arr.join('_');
        }

        var canceller;

        return {
            GetTrips: function (destinations, travelStyles, date, durations, keywords, years, experiences, pageSize, pageIndex, sort, sortOrder) {

                // cancel any outstanding ajax request
                if (canceller) {
                    canceller.resolve();
                }

                var qs = '?destination=' + formatArray(destinations) +
                    '&travelstyle=' + formatArray(travelStyles) +
                    '&dateselection=' + date +
                    '&experience=' + formatArray(experiences) +
                    '&duration=' + getDurations(durations) +
                    '&year=' + formatArray(years) +
                    '&keywords=' + (keywords || '') +
                    '&pageSize=' + pageSize +
                    '&pageIndex=' + pageIndex +
                    '&sort=' + sort +
                    '&sortOrder=' + sortOrder;

                var ip = utilityService.GetQueryStringParameters('ip');
                if (ip) {
                    qs += '&ip=' + ip
                }

                canceller = $q.defer();

                return $http({
                    method: 'GET',
                    cache: true,
                    url: TRIP_SEARCH_SERVICE_BASE_URL + qs,
                    timeout: canceller.promise
                })
                    .then(function success(response) {
                        if (response.status >= 200 && response.status < 300) {
                            return response.data;
                        }
                    });
            },
        }
    }
    ]);;
angular.module('Phoenix.Shared.services')
    .factory('tripPackageSelectionService', ['$http', '$q', 'utilityService', function ($http, $q, utilityService) {
        var TRIP_PACKAGE_SELECTION_URL = '/api/trip/departures/';
        var GET_PACKAGE_INFORMATION = 'api/trip/packageinformation/';
        var canceller;

        return {
            GetDeparture: function (tripId, departureDate) {
                // cancel any outstanding ajax request
                if (canceller) {
                    canceller.resolve();
                }

                var departureDateIso = utilityService.GetFormattedDate(new Date(departureDate));

                var url = TRIP_PACKAGE_SELECTION_URL
                    + tripId + '/' + departureDateIso;

                var ip = utilityService.GetQueryStringParameters('ip');
                if (ip) {
                    url += '?ip=' + ip
                }

                canceller = $q.defer();

                return $http({
                    method: 'GET',
                    cache: true,
                    url: url,
                    timeout: canceller.promise
                })
                .then(function success(response) {
                    if (response.status >= 200 && response.status < 300) {
                        return response.data.data;
                    }
                });
            },
            GetPackageInformation: function(id) {
                if (canceller) {
                    canceller.resolve();
                }

                var url = GET_PACKAGE_INFORMATION + id;

                canceller = $q.defer();

                return $http({
                    method: 'GET',
                    cache: false,
                    url: url,
                    timeout: canceller.promise
                })
                    .then(function success(response) {
                        if (response.status >= 200 && response.status < 300) {
                            return response.data.data[0];
                        } else {
                            return false;
                        }
                    });
            }            
        }
    }
    ]);;
angular.module('Phoenix.Shared.services')
    .factory('tripPriceAndBookingService', ['$http', '$timeout', '$q', 'utilityService', function ($http, $timeout, $q, utilityService) {
        var TRIP_PRICE_AND_BOOKING_SERVICE_ROOMTYPES_URL = '/api/trip/roomtypes/';
        var TRIP_PRICE_AND_BOOKING_SERVICE_MINIMUMDEPOSIT_URL = '/api/trip/minimumdeposit/';

        var canceller;

        function getShortDate(d) {
            var dtStr = d.getFullYear() + "/"
                + ("0" + (d.getMonth() + 1)).slice(-2) + "/"
                + ("0" + d.getDate()).slice(-2);

            return dtStr;
        }

        // Sorts the RoomTypes into the order Double, Twin, Single
        var sortRoomTypes = function (a, b) {
            var aName = a.roomTypeName.toLowerCase();
            var bName = b.roomTypeName.toLowerCase();
            if (aName == "double") return -1;
            if (aName == "single") return 1;
            if (aName == "twin" && bName == "single") return 0;
            return 1;
        }

        return {
            GetRoomTypes: function (packageId, departureDate, tripCode, promoCode, lastMinuteSpecial) {
                // cancel any outstanding ajax request
                if (canceller) {
                    canceller.resolve();
                }

                var departureDateIso = utilityService.GetFormattedDate(departureDate);

                var url = TRIP_PRICE_AND_BOOKING_SERVICE_ROOMTYPES_URL
                    + tripCode + '/' + packageId + '/' + departureDateIso;

                var lastMinuteSpecialPrefix = '?';
                if (promoCode) {
                    url = url + '?promoCode=' + encodeURIComponent(promoCode);
                    lastMinuteSpecialPrefix = '&';
                }
                url = url + lastMinuteSpecialPrefix + 'lastMinuteSpecial=' + lastMinuteSpecial;

                var ip = utilityService.GetQueryStringParameters('ip');
                if (ip) {
                    url += '&ip=' + ip
                }

                canceller = $q.defer();

                return $http({
                    method: 'GET',
                    cache: true,
                    url: url,
                    timeout: canceller.promise
                })
                    .then(function success(response) {
                        if (response.status >= 200 && response.status < 300) {
                            if (response.data.data) {
                                response.data.data.sort(sortRoomTypes);
                            }
                            return response.data.data;
                        }
                    });
            },
            GetMinimumDeposit: function (minimumDepositRequest) {
                // cancel any outstanding ajax request
                if (canceller) {
                    canceller.resolve();
                }

                var url = TRIP_PRICE_AND_BOOKING_SERVICE_MINIMUMDEPOSIT_URL;
                var ip = utilityService.GetQueryStringParameters('ip');
                if (ip) {
                    url += '?ip=' + ip
                }

                canceller = $q.defer();

                return $http({
                    method: 'POST',
                    cache: true,
                    url: url,
                    timeout: canceller.promise,
                    data: {
                        "categoryId": minimumDepositRequest.categoryId,
                        "departureDate": getShortDate(minimumDepositRequest.departureDate),
                        "duration": minimumDepositRequest.duration,
                        "itineraryId": minimumDepositRequest.itineraryId,
                        "lastMinuteSpecial": minimumDepositRequest.LastMinuteSpecial,
                        "packageId": minimumDepositRequest.packageId,
                        "packageName": minimumDepositRequest.packageName,
                        "packageDescription": minimumDepositRequest.packageDescription,
                        "packageType": minimumDepositRequest.packageType,
                        "pickupLocation": "",
                        "promotionCode": minimumDepositRequest.promoCode,
                        "rooms": minimumDepositRequest.rooms,
                        "tripId": minimumDepositRequest.tripId,
                        "cabinOriginalPrice": minimumDepositRequest.cabinOriginalPrice,
                        "cabins": minimumDepositRequest.cabins,
                        "roomCost": minimumDepositRequest.roomCost,
                        "useCruiseService": minimumDepositRequest.useCruiseService
                    }
                })
                    .then(function success(response) {
                        if (response.status >= 200 && response.status < 300) {
                            return response.data.data;
                        }
                    });
            },
        }
    }
    ]);;
angular.module('Phoenix.Shared.services')
    .factory('tripService', ['$http', '$timeout', '$cookies', 'utilityService', '$q', '$location',
        function ($http, $timeout, $cookies, utilityService, $q, $location) {

            var TRIP_CHARACTERISTICS_SERVICE_BASE_URL = '/services/tripcharacteristicsservice.svc/ajax/';
            var TRIP_TAGS_SERVICE_BASE_URL = '/api/trip/tags';
            var TRIP_COOKIE_KEY = 'APTBookingUrl';
            var TRIP_PDF_DOWNLOAD_URL = '/api/trip/downloadpdf';
            var canceller;

            return {
                GetTripCharacteristics: function(destinationsFilter, travelStylesFilter) {
                    return $http({
                        method: 'POST',
                        cache: true,
                        url: TRIP_CHARACTERISTICS_SERVICE_BASE_URL + 'GetTripCharacteristics',
                        data: {
                            "DestinationTopicTags": destinationsFilter,
                            "TravelStyleTopicTags": travelStylesFilter,
                            "DepartureMonths": [],
                            "Durations": [],
                            "IsRefine": true
                        }
                    })
                        .then(function success(response) {
                            if (response.status >= 200 && response.status < 300) {
                                return response.data;
                            }
                        });
                },
                GetTripTags: function (destinationsFilter, travelStylesFilter, dateFilter, durationsFilter) {

                    var qs = '?destination=' + destinationsFilter +
                        '&travelstyle=' + travelStylesFilter +
                        '&dateselection=' + dateFilter +
                        '&duration=' + durationsFilter;

                    var ip = utilityService.GetQueryStringParameters('ip');
                    if (ip) {
                        qs += '&ip=' + ip
                    }

                    return $http({
                        method: 'GET',
                        cache: true,
                        url: TRIP_TAGS_SERVICE_BASE_URL + qs,
                    })
                        .then(function success(response) {
                            if (response.status >= 200 && response.status < 300) {
                                if (response.data.Data) {
                                    return response.data.Data;
                                }
                                return [];
                            }
                        });
                },
                setTripUrl: function(url) {
                    return $cookies.put(TRIP_COOKIE_KEY, url);
                },
                getTripUrl: function() {
                    return ($cookies.get(TRIP_COOKIE_KEY) || document.referrer) + '#trip-priceandbooking';
                },
                downloadTripItinerary: function (tripCode) {
                    // cancel any outstanding ajax request
                    if (canceller) {
                        canceller.resolve();
                    }

                    var url = TRIP_PDF_DOWNLOAD_URL;
                    var ip = utilityService.GetQueryStringParameters('ip');
                    if (ip) {
                        url += '?ip=' + ip
                    }

                    canceller = $q.defer();

                    return $http({
                        method: 'GET',
                        cache: false,
                        url: url,
                        timeout: canceller.promise,
                        responseType: 'arraybuffer',
                        data: {
                            'requestorUrl': $location.absUrl()
                        }
                    })
                        .then(function success(response) {
                            if (response.status >= 200 && response.status < 300) {
                                if (response.data) {
                                    var file = new Blob([response.data], { type: 'application/pdf' });
                                    var fileURL = URL.createObjectURL(file);
                                    var fileName = tripCode + ".pdf";

                                    var a = document.createElement("a");
                                    a.style = "display: none";
                                    a.href = fileURL;
                                    a.download = fileName;
                                    document.body.appendChild(a);

                                    if (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.userAgent.indexOf('Edge') !== -1 || navigator.appVersion.indexOf('Trident/') > 0) {
                                        navigator.msSaveBlob(file, fileName);
                                    }
                                    else {
                                        a.click();
                                    }

                                    window.URL.revokeObjectURL(fileURL);
                                }
                                return true;
                            }
                        }, function error(response) {
                            return false;
                        });
                }
            }
        }
    ]);;
angular.module('Phoenix.Shared.services')
    .factory('utilityService', ['$timeout', function ($timeout) {
        return {
            GetFormattedDate: function(d) {
                var m_names = new Array("Jan", "Feb", "Mar",
                    "Apr", "May", "Jun", "Jul", "Aug", "Sep",
                    "Oct", "Nov", "Dec");

                var curr_date = d.getDate();
                var curr_month = d.getMonth();
                var curr_year = d.getFullYear();
                var dtStr = curr_date + "-" + m_names[curr_month]
                    + "-" + curr_year;

                return dtStr;
            },
            GetQueryStringParameters: function (name, url) {
                if (!url) url = window.location.href;
                name = name.replace(/[\[\]]/g, "\\$&");
                var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
                    results = regex.exec(url);
                if (!results) return null;
                if (!results[2]) return '';
                return decodeURIComponent(results[2].replace(/\+/g, " "));
            },
            GetArrayFromCommaString: function (str, splitter) {
                if (str) {
                    if (!splitter) splitter = ',';
                    var array = str.split(splitter);
                    return array;
                }
                return [];
            },
            NewGuid: function () {
                return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
                    var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
                    return v.toString(16);
                });
            },
            ScrollTo: function ($element, duration, delay, callback) {

                if (!$element.length) return;

                duration = duration || 500;
                delay = delay || 1;
                callback = callback || false;

                // test if there is any known elements with position:fixed
                // then impact the buffer's value
                var buffer;
                buffer = $('.trip-tabs').length ? $('.trip-tabs').innerHeight() : 0;

                $timeout(function () {
                    $('html, body').stop().animate({
                        scrollTop: $element.offset().top - buffer
                    }, duration, function(){
                        if (typeof(callback) === 'function') return callback();
                        return true;
                    }); 
                }, delay);
            }
        }
    }
]);;
angular.module('Phoenix.Shared.services')
    .factory('tripPriceAndAvailabilityService', ['$http', '$timeout', '$q', 'utilityService', function ($http, $timeout, $q, utilityService) {
        
        var TRIP_PRICE_AND_AVAILABILITY_SERVICE_SETBOOKING_URL = '/api/trip/selectedbooking/';

        var canceller;

        return {

            SetBooking: function (selectedBookingRequest) {
                // cancel any outstanding ajax request
                if (canceller) {
                    canceller.resolve();
                }

                var url = TRIP_PRICE_AND_AVAILABILITY_SERVICE_SETBOOKING_URL;
                var ip = utilityService.GetQueryStringParameters('ip');
                if (ip) {
                    url += '&ip=' + ip
                }
                canceller = $q.defer();

                return $http({
                    method: 'POST',
                    cache: true,
                    url: url,
                    timeout: canceller.promise,
                    data: {
                        "noOfPassengers": selectedBookingRequest.noOfPassengers,
                        "selectedTourPrice": selectedBookingRequest.selectedTourPrice,
                        "trip": selectedBookingRequest.trip
                    }
                })
                    .then(function success(response) {
                        if (response.status >= 200 && response.status < 300) {
                            return response.data.data;
                        }
                    });
            }
        }
    }
    ]);;
(function() {

    "use strict";

    // filters using AND or OR between search words
    angular.module('Phoenix.Shared.filters')
        .filter("logicalSearch", [function () {
            return function (input, searchText, AND_OR) {
                var returnArray = [];
                if (searchText) {
                    searchText = searchText.replace('&nbsp;', '');
                    // Split on single or multi space
                    var splitext = searchText.toLowerCase().split(/\s+/),
                    // Build Regexp with Logical AND using "look ahead assertions"
                    regexp_and = "(?=.*" + splitext.join(")(?=.*") + ")",
                    // Build Regexp with logicial OR
                    regexp_or = searchText.toLowerCase().replace(/\s+/g, "|"),
                    // Compile the regular expression
                    re = new RegExp((AND_OR == "AND") ? regexp_and : regexp_or, "i");

                    for (var x = 0; x < input.length; x++) {
                        if (re.test(input[x].Title)) {
                            returnArray.push(input[x]);
                        }
                    }
                }
                return returnArray;
            }
        }])

    angular.module('Phoenix.Shared.filters')
        .filter("exactSearch", [function () {
            return function (input, searchText) {
                var returnArray = [];
                if (searchText && input.length) {
                    // replace mutiple spaces with one space
                    searchText = searchText.replace(/&nbsp;/g, ' ');
                    searchText = searchText.replace(/\s\s+/g, ' ');

                    // normalise character case
                    searchText = searchText.toLowerCase();

                    for (var x = 0; x < input.length; x++) {
                        if (input[x].Title && input[x].Title.toLowerCase().indexOf(searchText) !== -1) {
                            returnArray.push(input[x]);
                        }
                    }
                }
                return returnArray;
            }
        }]);

    // filters array by relevance.
    // first outputs results where result starts with the search term
    // then outputs results where search term exists in any other part of the result
    angular.module('Phoenix.Shared.filters')
        .filter("relevantSearch", [function () {
            return function (input, searchText) {
                var returnArray = [];

                if (searchText && input.length) {
                    var matchesClose = [];
                    var matchesDistant = [];

                    // replace mutiple spaces with one space
                    searchText = searchText.replace(/&nbsp;/g, ' ');
                    searchText = searchText.replace(/\s\s+/g, ' ');

                    // normalise character case
                    searchText = searchText.toLowerCase();

                    for (var x = 0; x < input.length; x++) {
                        if (input[x].toLowerCase().indexOf(searchText) === 0) {
                            matchesClose.push(input[x]);
                        }
                        else if (input[x].toLowerCase().indexOf(searchText) > 0) {
                            matchesDistant.push(input[x]);
                        }
                    }
                    returnArray = matchesClose
                                .sort()
                                .concat(matchesDistant.sort());
                }
                return returnArray;
            }
        }]);
}());;
(function() {
    'use strict';

    // filters using AND or OR between search words
    angular.module('Phoenix.Shared.filters')
        .filter('ellipsis', [function () {
            return function (input, stringLength) {
                var returnString = input;
                if (stringLength && input.length >= stringLength) {
                    returnString = input.substring(0, stringLength) + '...';
                }
                return returnString;
            }
        }]);

    // convert string to a valid html id
    angular.module('Phoenix.Shared.filters')
        .filter("textToId", [function () {
            return function (input) {
                return input.replace(/[^a-z0-9\-_:\.]|^[^a-z]+/gi, '').toLowerCase();
            }
        }]);


}());;
(function () {

    "use strict";

    angular.module('Phoenix.Shared.controllers')
        .controller('multistepCarouselControllers', ['$rootScope', function ($rootScope) {

            var MAX_SLIDES = 3;

            var mcc = this;

            mcc.steps = {
                currentIndex: 0,
                goToNext: goToNext,
                goToPrevious: goToPrevious,
                goToStep: goToStep
            };

            function goToStep(index) {
                if (index >= 0 && index < MAX_SLIDES) {
                    mcc.steps.currentIndex = index;

                    $rootScope.$broadcast('broadcast.multistepCarouselControllers.indexChanged', { index: mcc.steps.currentIndex });
                }
            }

            function goToNext() {
                if (mcc.steps.currentIndex + 1 < MAX_SLIDES) {
                    mcc.steps.currentIndex++;

                    $rootScope.$broadcast('broadcast.multistepCarouselControllers.indexChanged', { index: mcc.steps.currentIndex });
                    $rootScope.$broadcast('broadcast.multistepCarouselControllers.goToNext');
                }
            }

            function goToPrevious() {
                if (mcc.steps.currentIndex > 0) {
                    mcc.steps.currentIndex--;

                    $rootScope.$broadcast('broadcast.multistepCarouselControllers.indexChanged', { index: mcc.steps.currentIndex });
                }
            }

            $rootScope.$on('broadcast.multistepCarouselControllers.goToIndex', function (e, args) {
                goToStep(args.index);
            });

        }]);
})();
;
(function () {

    "use strict";

    angular.module('Phoenix.Shared.controllers')
        .controller('pageHeroController', [function () {
            var phc = this;
            phc.title = {
                currentIndex: 0,
                class: '',
                classes: [],
                showNext: showNext,
                showPrevious: showPrevious
            };
            phc.init = init;

            function init(titleClasses) {
                phc.title.class = titleClasses.length ? titleClasses[0] : '';
                phc.title.classes = titleClasses;
            }

            function showNext() {
                phc.title.currentIndex = (phc.title.currentIndex + 1) >= phc.title.classes.length ? 0 : phc.title.currentIndex + 1;
                phc.title.class = phc.title.classes[phc.title.currentIndex];
            }

            function showPrevious() {
                phc.title.currentIndex = (phc.title.currentIndex <= 0) ? phc.title.classes.length - 1 : phc.title.currentIndex - 1;
                phc.title.class = phc.title.classes[phc.title.currentIndex];
            }
        }])
        .controller('videoPageHeroController', ['$scope', function ($scope) {

            var vphc = this;
            vphc.videoId = '';
            vphc.isVideoLoaded = false;
            vphc.displayVideo = true;
            vphc.isVideoPlaying = false;
            vphc.pauseVideo = pauseVideo;

            vphc.init = init;

            function init(videoId) {
                vphc.videoId = videoId;
            }

            function pauseVideo() {
                $scope.$broadcast('broadcast.videoPageHeroController.pauseVideo');
            }

        }]);
})();
;
(function () {

    "use strict";

    angular.module('Phoenix.Shared.controllers')
        .controller('styleGuideElementController', [function () {
            var sgc = this;
            sgc.styles = {
                color: '',
                backgroundColor: '',
                letterSpacing: '',
                fontFamily: '',
                rem: {
                    fontSize: '',
                    lineHeight: ''
                },
                desktop: {
                    fontSize: '',
                    lineHeight: ''
                },
                mobile: {
                    fontSize: '',
                    lineHeight: ''
                }
            }
        }]);
})();
;
(function () {

    "use strict";

    angular.module('Phoenix.Shared.controllers')
        .controller('tripPackageSelectionController', ['$filter', '$scope', function ($filter, $scope) {

            var MAX_SLIDES = 3;

            var tpsc = this;

            tpsc.init = init;
            tpsc.setupModel = setupModel;

            tpsc.date = '';
            tpsc.package = {};
            tpsc.roomType = {};
            tpsc.price = 0;
            tpsc.previousPrice = 0;
            tpsc.modalError = {};
            tpsc.modal = {};
            tpsc.upgradeOptionsString = '';
            tpsc.isUpdatingRoomType = false;
            tpsc.roomConfigurationString = '';
            tpsc.tripBadgeDict = {};
            tpsc.tripBadgeText = '';
            tpsc.tripBadgeColor = '';

            tpsc.packages = [];
            tpsc.roomTypes = [];

            tpsc.trip = {
                tripName: '',
                tripId: '',
                tripCode: ''
            }

            tpsc.form = {
                isSubmitting: false
            }

            tpsc.calculateTotalPrice = calculateTotalPrice;
            tpsc.formatPriceDifference = formatPriceDifference;
            tpsc.setDefaultUpgradeCategories = setDefaultUpgradeCategories;
            tpsc.calculateBasePriceForRoomType = calculateBasePriceForRoomType;
            tpsc.setTripBadge = setTripBadge;

            function isArray(arr) {
                return Array.isArray(arr);
            }

            function init(tripId, tripCode, tripName, departureDate, tripBadgeJson) {
                tpsc.trip.tripId = tripId;
                tpsc.trip.tripCode = tripCode;
                tpsc.trip.tripName = tripName;
                tpsc.date = departureDate;

                try { tpsc.tripBadgeDict = JSON.parse(tripBadgeJson); }
                catch (e) { tpsc.tripBadgeDict = {}; }
                
                setTripBadge(tpsc.date);
            }

            function setupModel(model) {
                if (!model
                    || !isArray(model)
                    || !isArray(model[0].journeyPackages)
                    || !isArray(model[0].roomConfigurations)
                ) {
                    tpsc.packages = [];
                    tpsc.roomTypes = [];
                    tpsc.package = {};
                    tpsc.roomType = {};
                }

                var tripDeparture = model[0];

                tpsc.packages = tripDeparture.journeyPackages.filter(function (journeyPackage) { return journeyPackage.journeyPackageType !== null; });
                tpsc.roomTypes = tripDeparture.roomConfigurations;
                tpsc.package = tripDeparture.journeyPackages[0];
                tpsc.roomType = tripDeparture.roomConfigurations[0];
                tpsc.modalError.title = model.infoApiErrorTitle;
                tpsc.modalError.description = model.infoApiErrorMsg;
                tpsc.buildPackageDetailsString = buildPackageDetailsString;
                tpsc.buildRoomConfigurationString = buildRoomConfigurationString;
                tpsc.buildPackageSelectionArray = buildPackageSelectionArray;
            }

            function setTripBadge(newDate) {
                var tripBadge = tpsc.tripBadgeDict[newDate];
                
                if (typeof tripBadge !== "undefined") {
                    tpsc.tripBadgeText = tripBadge.text;
                    tpsc.tripBadgeColor = tripBadge.colorClass;
                }
            }

            function setDefaultUpgradeCategories() {
                if (!tpsc.roomType || !tpsc.roomType.upgradeCategories) return;

                tpsc.roomType.upgradeCategories.forEach(function (category) {
                    category.selectedCategory = category.upgradeOptions[0];
                    category.isUpgraded = false;
                });
            }

            function calculateTotalPrice() {
                if (!tpsc.roomType || !tpsc.roomType.upgradeCategories) {
                    tpsc.price = 0;
                    return;
                };

                tpsc.previousPrice = tpsc.price;
                var price = tpsc.package.amount + tpsc.roomType.amount;

                tpsc.roomType.upgradeCategories.forEach(function (category) {
                    if (category.isUpgraded && category.selectedCategory !== null) {
                        price += category.selectedCategory.amount;
                    }
                });

                tpsc.price = price;
            }

            function formatPriceDifference(value, symbol) {
                var formatted = $filter('currency')(value, symbol, 0);

                return value < 0 ? formatted : '+' + formatted;
            }

            function calculateBasePriceForRoomType(roomType) {
                if (!roomType.basePrice) {
                    roomType.basePrice = roomType.amount;
                }

                return tpsc.package.amount + roomType.basePrice;
            }

            function buildPackageDetailsString() {
                var packageDetails = '';
                tpsc.roomType.upgradeCategories.forEach(function (category) {
                    if (category.isUpgraded && category.selectedCategory != null) {
                        packageDetails = packageDetails + category.upgradeCategoryTitle
                            + ' - ' + category.selectedCategory.upgradeOptionTitle
                            + '|';
                    }
                });

                tpsc.upgradeOptionsString = packageDetails;
            }

            function buildPackageSelectionArray() {
                var packageDetails = [];

                tpsc.roomType.upgradeCategories.forEach(function (category) {
                    if (category.isUpgraded && category.selectedCategory != null) {
                        packageDetails.push(category.upgradeCategoryTitle + ' - '
                            + category.selectedCategory.upgradeOptionTitle);
                    }
                });

                return packageDetails;
            }

            function buildRoomConfigurationString() {
                tpsc.roomConfigurationString = tpsc.roomType.roomConfigurationType;
            }
        }]);
})();
;
(function(){

    "use strict";

    angular.module('Phoenix.Shared.directives')
        .directive('styleGuideElement', ['$timeout', '$window', function ($timeout, $window) {
            return {
                restrict: 'A',
                scope: true,
                controller: 'styleGuideElementController',
                controllerAs: 'sgc',
                bindToController: true,
                link: function (scope, element, attrs, ctrl) {

                    var REM_DESKTOP = 16;
                    var DESKTOP_MIN_WIDTH = 801;
                    var REM_MOBILE = 14;
                    var windowWidth = $window.innerWidth;
                    var $el = angular.element(element);
                    var $elInstance = $el.find('[data-style-guide-element-instance]');

                    if ($elInstance.length) {
                        ctrl.styles.className = $elInstance[0].className;
                        ctrl.styles.fontFamily = getFirstFont($elInstance.css('font-family'));
                        ctrl.styles.color = rgb2hex($elInstance.css('color'));
                        ctrl.styles.backgroundColor = rgb2hex($elInstance.css('background-color'));
                        ctrl.styles.letterSpacing = $elInstance.css('letter-spacing');
                        ctrl.styles.rem.fontSize = toRem($elInstance.css('font-size'));
                        ctrl.styles.rem.lineHeight = toRem($elInstance.css('line-height'));
                        ctrl.styles.mobile.fontSize = toMobilePx($elInstance.css('font-size'));
                        ctrl.styles.mobile.lineHeight = $elInstance.css('line-height');
                        ctrl.styles.desktop.fontSize = toDesktopPx($elInstance.css('font-size'));
                        ctrl.styles.desktop.lineHeight = $elInstance.css('line-height');
                    }

                    function getFirstFont(fonts) {
                        var font;
                        if (fonts) {
                            var fontArray = fonts.split(',')
                            if (fontArray.length) {
                                font = fontArray[0].replace(/['"]+/g, '');
                            }
                        }
                        return font;
                    }

                    function toRem(px) {

                        var flt = parseFloat(px);
                        if (isNaN(flt)) return px;

                        return windowWidth >= DESKTOP_MIN_WIDTH ?
                            flt / REM_DESKTOP + 'rem':
                            flt / REM_MOBILE + 'rem';
                    }

                    function toMobilePx(px) {

                        var flt = parseFloat(px);
                        if (isNaN(flt)) return px;

                        return windowWidth >= DESKTOP_MIN_WIDTH ?
                            flt / REM_DESKTOP * REM_MOBILE + 'px' :
                            px;
                    }

                    function toDesktopPx(px) {

                        var flt = parseFloat(px);
                        if (isNaN(flt)) return px;

                        return windowWidth >= DESKTOP_MIN_WIDTH ?
                            px :
                            flt / REM_MOBILE * REM_DESKTOP + 'px';
                    }

                    function rgb2hex(rgb) {
                        if (!rgb) return '';

                        rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
                        function hex(x) {
                            return ("0" + parseInt(x).toString(16)).slice(-2);
                        }
                        return rgb ? "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]) : '';
                    }
                }
            };
        }]);

})();
;

$(document).ready(function () {
    function ValidateEmail(mail) 
    {
        if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(mail))
            {
                return (true)
            }else{
                return (false)
            }
    }

    var webChatEnabled = false;
    var chatElement = angular.element('#webchatsnippet');
    if (chatElement) {
        if (chatElement.attr('data-brand')) {
            webChatEnabled = true;
        }
    }
    if (webChatEnabled) {
        const isUserDataSubmitted = sessionStorage.getItem('userDataAdded');
        if (isUserDataSubmitted !== 'true') {
            Genesys("subscribe", "Messenger.ready", function () {

                //Variable declaration
                const wrapperDiv = document.createElement('div');
                const mainDiv = document.createElement('div');
                const formDiv = document.createElement('div');
                wrapperDiv.setAttribute('class', 'container');
                mainDiv.setAttribute("class", "main_container");
                const chatToggleButton = document.createElement('button');
                chatToggleButton.setAttribute('type', 'button');
                chatToggleButton.setAttribute('id', 'chatToggleButton');
                chatToggleButton.setAttribute('data-ga4-click', 'data-ga4-click');
                chatToggleButton.setAttribute("style", "position: fixed;right: 40px;bottom: 116px;cursor: pointer;width: 56px;height: 56px;font-size: 0.9rem;min-width: 0;box-shadow: 0px 3px 5px -1px rgb(0 0 0 / 20%), 0px 6px 10px 0px rgb(0 0 0 / 14%), 0px 1px 18px 0px rgb(0 0 0 / 12%);box-sizing: border-box;transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,border 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;font-weight: 500;text-transform: uppercase;border-radius: 50%;line-height: 1.75;color: rgb(255, 255, 255) !important;background-color: rgb(0, 33, 105) !important;margin: 0; display: inline-flex;outline: 0;border: 0;align-items: center;user-select: none;vertical-align: middle;    justify-content: center;text-decoration: none;    -webkit-appearance: none;-webkit-tap-highlight-color: transparent;")
                const chatIconWrapper = document.createElement('span');
                chatIconWrapper.setAttribute('class', 'chat_icon_wrapper');
                chatIconWrapper.innerHTML = '<svg class="chat_icon_wrapper_svg"  focusable="false" viewBox="0 0 24 24" aria-hidden="true"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM6 9h12v2H6V9zm8 5H6v-2h8v2zm4-6H6V6h12v2z"></path></svg>';
                chatToggleButton.append(chatIconWrapper);
                //creating a form
                var form = document.createElement("form");
                form.setAttribute("method", "post");
                form.setAttribute("action", "/");
                form.setAttribute('class', 'dynamic-form has-form-action is-form-step ng-valid ng-isolate-scope form-bound form-section-style');
                var formSection = document.createElement('section');
                formSection.setAttribute('class', 'form-section');
                var formSectionDiv = document.createElement('div');
                formSectionDiv.setAttribute('class', 'field-set row');
                // Create an input element for First Name
                var divFN = document.createElement("div");
                divFN.setAttribute('class', 'form-field col-xs-12  form-group');
                divFN.setAttribute('id', 'firstNameDiv');
                var FN = document.createElement("input");
                var errorName = document.createElement("span");
                errorName.setAttribute('class', 'error-name');
                FN.setAttribute("type", "text");
                FN.setAttribute("name", "FirstName");
                FN.setAttribute("placeholder", "First Name");
                FN.setAttribute('class', 'form-control');
                divFN.appendChild(FN);
                divFN.appendChild(errorName);
                // Create an input element for Last Name
                var divLN = document.createElement("div");
                var errorLastName = document.createElement("span");
                errorLastName.setAttribute('class', 'last-name');
                divLN.setAttribute('class', 'form-field col-xs-12  form-group');
                divLN.setAttribute('id', 'lastNameDiv');
                var LN = document.createElement("input");
                LN.setAttribute("type", "text");
                LN.setAttribute("name", "LastName");
                LN.setAttribute("placeholder", "Last Name");
                LN.setAttribute('class', 'form-control');
                divLN.appendChild(LN);
                divLN.appendChild(errorLastName);
                // Create an input element for emailID
                var divEID = document.createElement("div");
                divEID.setAttribute('class', 'form-field col-xs-12  form-group')
                divEID.setAttribute('id', 'emailDiv');
                var errorEID = document.createElement("span");
                errorEID.setAttribute('class', 'error-eid');
                var EID = document.createElement("input");
                EID.setAttribute("type", "text");
                EID.setAttribute("name", "emailID");
                EID.setAttribute("placeholder", "Email");
                EID.setAttribute('class', 'form-control');
                divEID.appendChild(EID);
                divEID.appendChild(errorEID);
                // Create an input element for Last Name
                var divMSG = document.createElement("div");
                divMSG.setAttribute('class', 'form-field col-xs-12  form-group')
                divMSG.setAttribute('id', 'messageDiv');
                var errorMessage = document.createElement("span");
                errorMessage.setAttribute('class', 'error-message');
                var MSG = document.createElement("input");
                MSG.setAttribute("type", "text");
                MSG.setAttribute("name", "Message");
                MSG.setAttribute("placeholder", "Message");
                MSG.setAttribute('class', 'form-control');
                divMSG.appendChild(MSG);
                divMSG.appendChild(errorMessage);
                //Checkbox
                var divCHECKBOX = document.createElement("div");
                divCHECKBOX.setAttribute('class', 'form-field col-xs-12 form-checkbox-style ')
                divCHECKBOX.setAttribute('style', 'display: none !important')
                var CHECKBOX = document.createElement("input");
                var labelCheckbox = document.createElement("label");
                labelCheckbox.setAttribute('for', 'transcript');
                labelCheckbox.innerHTML = "Would you like to receive Chat Transcript:"
                labelCheckbox.setAttribute('style', 'color: #fff;');
                CHECKBOX.checked = false;
                CHECKBOX.setAttribute("type", "checkbox");
                CHECKBOX.setAttribute("id", "transcript");
                CHECKBOX.setAttribute("name", "transcript");
                CHECKBOX.setAttribute('class', 'chat_checkbox');
                divCHECKBOX.appendChild(labelCheckbox);
                divCHECKBOX.appendChild(CHECKBOX);
                // create a submit button
                var submitButtonDiv = document.createElement('div');
                submitButtonDiv.setAttribute('class', 'form-field col-xs-12 submit-form-button');
                var submitForm = document.createElement("input");
                submitForm.setAttribute("type", "submit");
                submitForm.setAttribute("value", "Submit");
                submitForm.setAttribute("id", "submitFormButton");
                submitButtonDiv.appendChild(submitForm);
                //input fields rendering
                formSectionDiv.appendChild(divFN);

                formSectionDiv.appendChild(divLN);

                formSectionDiv.appendChild(divEID);

                formSectionDiv.appendChild(divMSG);

                formSectionDiv.appendChild(divCHECKBOX);

                formSectionDiv.appendChild(submitButtonDiv);
                // Append the submit button to the form
                formSection.appendChild(formSectionDiv);
                form.appendChild(formSection);
                formDiv.appendChild(form);
                formDiv.setAttribute('class', 'col-full');
                formDiv.classList.add("form-container-wrapper");
                formDiv.style.display = "none";
                wrapperDiv.appendChild(mainDiv);
                mainDiv.appendChild(formDiv);
                mainDiv.appendChild(chatToggleButton);
                //Appending form to the body
                document.body.appendChild(wrapperDiv);

                //Events
                const showForm = document.getElementById("chatToggleButton");
                showForm.addEventListener('click', function (e) {
                    if (formDiv.style.display === "block") {
                        formDiv.style.display = "none";
                        chatToggleButton.style.display = "block";

                    } else {
                        formDiv.style.display = "block";

                    }
                });
                //Click event for form submission
                const submitFormEvent = document.getElementById("submitFormButton");
                submitFormEvent.addEventListener('click', function (e) {
                    e.preventDefault();
                    if (!FN.value) {
                        // Changing content and color of content
                        errorName.textContent = "Please enter a valid first name";
                        errorName.style.color = "red";
                        return;
                    } else {
                        errorName.textContent = "";
                    }
                    if (!LN.value) {
                        // Changing content and color of content
                        errorLastName.textContent = "Please enter a valid last name";
                        errorLastName.style.color = "red";
                        return;
                    } else {
                        errorLastName.textContent = "";
                    }
                    if (!EID.value) {
                        // Changing content and color of content
                        errorEID.textContent = "Please enter email address";
                        errorEID.style.color = "red";
                        return;
                    } else {
                        errorEID.textContent = "";
                    }
                    if (!ValidateEmail(EID.value)) {
                        // Changing content and color of content
                        errorEID.textContent = "You have entered an invalid email address, please try again";
                        errorEID.style.color = "red";
                        return;
                    } else {
                        errorEID.textContent = "";
                    }
                    // if (!MSG.value) {
                    //     // Changing content and color of content
                    //     errorMessage.textContent = "Please enter a valid Message";
                    //     errorMessage.style.color = "red";
                    //     return;
                    //     } else {
                    //         errorMessage.textContent = "";
                    // }

                    let isCheckBoxChecked = document.querySelectorAll('input[name="transcript"]')[0];
                    if (isCheckBoxChecked.checked) {
                        isCheckBoxChecked = 'true';
                    } else {
                        isCheckBoxChecked = 'false';
                    }
                    //toggle div 
                    formDiv.style.display = 'none';

                    try {
                        var webchatSnippetValue = document.getElementById("webchatsnippet");;
                        if (!webchatSnippetValue) throw "Please Check Data Url, Country Code and Brand is not assigned from Sitecore";
                        var webchatBrand = webchatSnippetValue.getAttribute("data-brand");
                        //var webchatUrl  = webchatSnippetValue.getAttribute("data-url");
                        var webchatCountryCode = webchatSnippetValue.getAttribute("data-countrycode").split("-")[1];
                        if (!webchatBrand) throw "Please Check Brand Value is not assigned from Sitecore";
                        //if(!webchatUrl) throw "Please Check Url Value is not assigned from Sitecore";
                        if (!webchatCountryCode) throw "Please Check Country Code is not assigned from Sitecore";
                    }
                    catch (err) {
                        console.log(err);
                    }
                    Genesys("command", "Database.set", {
                        messaging: {
                            customAttributes: {
                                //userData: JSON.stringify(getUserSessionData)
                                'firstName': FN.value,
                                'lastName': LN.value,
                                'email': EID.value,
                                'istranscriptChecked': isCheckBoxChecked,
                                'brand': webchatBrand,
                                'countryCode': webchatCountryCode,
                                'url': window.location.href
                            }
                        }
                    },
                        function (o) {
                            console.log("Passed" + JSON.stringify(o));
                            chatToggleButton.style.display = "none";
                            sessionStorage.setItem('userDataAdded', 'true');
                        },
                        function (o) {
                            console.log("Fail" + JSON.stringify(o));
                        })
                    //open chat window
                    Genesys("command", "Messenger.open", {},
                        function (o) {
                            console.log(JSON.stringify(o));
                        },  // if resolved
                        function (o) {    // if rejected
                            Genesys("command", "Messenger.close");
                        }
                    );
                    //Getting user session and conversation id after chat box closed
                    // Genesys("subscribe", "Conversations.closed", function (userChat) {
                    //     if (!userChat['data']) {
                    //         console.log("No data found!");
                    //     } else {
                    //         const userConversationId = userChat.data['journeyContext']['customer']['id'];
                    //         const userConcersationSessionId = userChat.data['journeyContext']['customerSession']['id'];
                    //         console.log("customerID" + userConversationId);
                    //         console.log("customerSessionId" + userConcersationSessionId);
                    //     }

                    // });
                })
            })
        } else {
            Genesys("subscribe", "Messenger.ready", function () {
                //open chat window
                Genesys("command", "Messenger.open", {},
                    function (o) {
                        console.log(JSON.stringify(o));
                    },  // if resolved
                    function (o) {    // if rejected
                        Genesys("command", "Messenger.close");
                    }
                );
            })
        }
    }
});

;
$(document).ready(function() {
    GA4_GenericClickEvent();
    GA4_SocialClick();
    GA4_GlobalNav();
    GA4_FooterNav();
})

// Generic Click events can be triggerd just by adding this attribute: data-ga4-click="xxx"
function GA4_GenericClickEvent() {
    $('[data-ga4-click]').click(function () {

        dataLayer.push({
            event: $(this).attr('data-ga4-click')
        });

    });
}

function GA4_SocialClick() {
    $('.footer-social-icon').click(function () {

        // expecting: footer-social-icon icon-facebook
        var classes = $(this).attr("class").split(" ");

        classes.forEach(function (value) {
            if (value.startsWith("icon-")) {

                // convert: icon-facebook > facebook
                var clickText = value.replace("icon-", "");

                dataLayer.push({
                    event: "social_link_click",
                    clickText: clickText
                });

            }
        });
    });
}

function GA4_GlobalNav() {
    $(".navbar-listitem-link").click(function () {
        dataLayer.push({
            event: "global_nav_click",
            clickText: $(this).text()
        });
    });

    $(".mappoint").click(function () {
        dataLayer.push({
            event: "global_nav_click",
            clickText: $(this).text()
        });
    });
}

function GA4_FooterNav() {
    $(".footer-nav-list-text a").click(function () {
        dataLayer.push({
            event: "footer_click",
            clickText: $(this).text()
        });
    });
    
    $(".footer-cta a").click(function () {
        dataLayer.push({
            event: "footer_click",
            clickText: $(this).text()
        });
    });
};
$(document).ready(function () {
    var dataLayer = window.dataLayer || [];

    if (typeof dataLayer !== 'undefined') {

        // Call for booking
        $(document).on("click", '#booking-step-call-for-booking', function () {
            dataLayer.push({              
                event: "call_for_booking",
                tripName: $('#trip-intro-trip-name').text(),
                tripCode: $('#ga4-trip-code').val(),
                promotionText: $('#trip-intro-promotion-text').text().trim(),
                promotionCode: $('#ga4-trip-promotion-code').val()
            })    
        });

        // Call for booking - under card details
        $(document).on("click", '#booking-step-call-for-booking-card-details', function () {
            dataLayer.push({
                event: "call_for_booking",
                tripName: $('#trip-intro-trip-name').text(),
                tripCode: $('#ga4-trip-code').val(),
                promotionText: $('#trip-intro-promotion-text').text().trim(),
                promotionCode: $('#ga4-trip-promotion-code').val()
            })
        });

        // Call back request click - Enquire Now
        $(document).on("click", '#booking-step-call-back-request', function () {
            dataLayer.push({
                event: "booking_call_back_request_click",
                tripName: $('#trip-intro-trip-name').text(),
                tripCode: $('#ga4-trip-code').val(),
                promotionText: $('#trip-intro-promotion-text').text().trim(),
                promotionCode: $('#ga4-trip-promotion-code').val()
            })
        });

        // Call back request click - under card details
        $(document).on("click", '#booking-step-call-back-request-card-details', function () {
            dataLayer.push({
                event: "booking_call_back_request_click",
                tripName: $('#trip-intro-trip-name').text(),
                tripCode: $('#ga4-trip-code').val(),
                promotionText: $('#trip-intro-promotion-text').text().trim(),
                promotionCode: $('#ga4-trip-promotion-code').val()
            })
        });

        // Call back request submit
        $(document).on("click", '#booking-step-call-back-submit', function () {
            dataLayer.push({
                event: "booking_call_back",
                tripName: $('#trip-intro-trip-name').text(),
                tripCode: $('#ga4-trip-code').val(),
                promotionText: $('#trip-intro-promotion-text').text().trim(),
                promotionCode: $('#ga4-trip-promotion-code').val()
            })
        });

        // PDF download - desktop
        // Implemented it differently because it was not working with document on click
        $('#trip-map-save-pdf-desktop').click(function () {
            dataLayer.push({
                event: "save_trip_information_pdf",
                tripName: $('#trip-intro-trip-name').text(),
                tripCode: $('#ga4-trip-code').val(),
                promotionText: $('#trip-intro-promotion-text').text().trim(),
                promotionCode: $('#ga4-trip-promotion-code').val()
            })
        });

        // PDF download - mobile
        // Implemented it differently because it was not working with document on click
        $('#trip-map-save-pdf-mobile').click(function () {
            dataLayer.push({
                event: "save_trip_information_pdf",
                tripName: $('#trip-intro-trip-name').text(),
                tripCode: $('#ga4-trip-code').val(),
                promotionText: $('#trip-intro-promotion-text').text().trim(),
                promotionCode: $('#ga4-trip-promotion-code').val()
            })
        });

        // Check Availability And Book Now Click - APT and TM
        $(document).on("click", '#trip-tab-button-trip-priceandbooking', function () {
            dataLayer.push({
                event: "check_availability_and_book_click",
                tripName: $('#trip-intro-trip-name').text(),
                tripCode: $('#ga4-trip-code').val(),
                promotionText: $('#trip-intro-promotion-text').text().trim(),
                promotionCode: $('#ga4-trip-promotion-code').val()
            })
        });

        // Map And Itinerary Click - APT
        $(document).on("click", '#trip-tab-button-trip-itinerary', function () {
            dataLayer.push({
                event: "click_map_and_itinerary",
                tripName: $('#trip-intro-trip-name').text(),
                tripCode: $('#ga4-trip-code').val(),
                promotionText: $('#trip-intro-promotion-text').text().trim(),
                promotionCode: $('#ga4-trip-promotion-code').val()
            })
        });

        // Map And Itinerary Click - TM
        $(document).on("click", '#trip-tab-button-trip-itinerary', function () {
            dataLayer.push({
                event: "click_map_and_itinerary",
                tripName: $('#trip-intro-trip-name').text(),
                tripCode: $('#ga4-trip-code').val(),
                promotionText: $('#trip-intro-promotion-text').text().trim(),
                promotionCode: $('#ga4-trip-promotion-code').val()
            })
        });
        // Price Click
        $(document).on("click", '#trip-intro-price-button', function () {
            dataLayer.push({
                event: "click_price",
                tripName: $('#trip-intro-trip-name').text(),
                tripCode: $('#ga4-trip-code').val(),
                promotionText: $('#trip-intro-promotion-text').text().trim(),
                promotionCode: $('#ga4-trip-promotion-code').val()
            })
        });

        //Request Quote - Form Submit
        // Implemented it differently because it was not working with document on click
        $('#modalRequestQuote-Trip .form-field.center.submit').click(function () {
            dataLayer.push({
                event: "request_quote_form_submit",
                tripName: $('#modalRequestQuote-Trip .trip-name'),
                tripCode: $('#modalRequestQuote-Trip input[name*="_tripcode"]'),
            })
        });

        // Expand Full Itinerary
        $(document).on("click", '.trip-itinerary__button-group .trip-itinerary__expand-itinerary', function () {
            dataLayer.push({
                event: "expand_full_itinerary",
                tripName: $('.trip-intro .trip-intro__title').text().trim(),
                tripCode: $('.trip-intro .trip-code__value').text().trim(),
                promotionText: $('.trip-intro .trip-intro__badge').text().trim(),
                promotionCode: $('.trip-intro .trip-intro__badge').attr('data-ga4-trip-intro-promo-code')
            })
        });
    }
});;
