/* Minification failed. Returning unminified contents.
(6058,9-10): run-time error JS1010: Expected identifier: .
(6058,9-10): run-time error JS1195: Expected expression: .
 */
/*!
 * money.js / fx() v0.2
 * Copyright 2014 Open Exchange Rates
 *
 * JavaScript library for realtime currency conversion and exchange rate calculation.
 *
 * Freely distributable under the MIT license.
 * Portions of money.js are inspired by or borrowed from underscore.js
 *
 * For details, examples and documentation:
 * http://openexchangerates.github.io/money.js/
 */
(function (root, undefined) {

    // Create a safe reference to the money.js object for use below.
    var fx = function (obj) {
        return new fxWrapper(obj);
    };

    // Current version.
    fx.version = '0.2';


    /* --- Setup --- */

    // fxSetup can be defined before loading money.js, to set the exchange rates and the base
    // (and default from/to) currencies - or the rates can be loaded in later if needed.
    var fxSetup = root.fxSetup || {
        rates: {},
        base: ""
    };

    // Object containing exchange rates relative to the fx.base currency, eg { "GBP" : "0.64" }
    fx.rates = fxSetup.rates;

    // Default exchange rate base currency (eg "USD"), which all the exchange rates are relative to
    fx.base = fxSetup.base;

    // Default from / to currencies for conversion via fx.convert():
    fx.settings = {
        from: fxSetup.from || fx.base,
        to: fxSetup.to || fx.base
    };


    /* --- Conversion --- */

    // The base function of the library: converts a value from one currency to another
    var convert = fx.convert = function (val, opts) {
        // Convert arrays recursively
        if (typeof val === 'object' && val.length) {
            for (var i = 0; i < val.length; i++) {
                val[i] = convert(val[i], opts);
            }
            return val;
        }

        // Make sure we gots some opts
        opts = opts || {};

        // We need to know the `from` and `to` currencies
        if (!opts.from) opts.from = fx.settings.from;
        if (!opts.to) opts.to = fx.settings.to;

        // Multiple the value by the exchange rate
        return val * getRate(opts.to, opts.from);
    };

    // Returns the exchange rate to `target` currency from `base` currency
    var getRate = function (to, from) {
        // Save bytes in minified version
        var rates = fx.rates;

        // Make sure the base rate is in the rates object:
        rates[fx.base] = 1;

        // Throw an error if either rate isn't in the rates array
        if (!rates[to] || !rates[from]) throw "fx error";

        // If `from` currency === fx.base, return the basic exchange rate for the `to` currency
        if (from === fx.base) {
            return rates[to];
        }

        // If `to` currency === fx.base, return the basic inverse rate of the `from` currency
        if (to === fx.base) {
            return 1 / rates[from];
        }

        // Otherwise, return the `to` rate multipled by the inverse of the `from` rate to get the
        // relative exchange rate between the two currencies
        return rates[to] * (1 / rates[from]);
    };


    /* --- OOP wrapper and chaining --- */

    // If fx(val) is called as a function, it returns a wrapped object that can be used OO-style
    var fxWrapper = function (val) {
        // Experimental: parse strings to pull out currency code and value:
        if (typeof val === "string") {
            this._v = parseFloat(val.replace(/[^0-9-.]/g, ""));
            this._fx = val.replace(/([^A-Za-z])/g, "");
        } else {
            this._v = val;
        }
    };

    // Expose `wrapper.prototype` as `fx.prototype`
    var fxProto = fx.prototype = fxWrapper.prototype;

    // fx(val).convert(opts) does the same thing as fx.convert(val, opts)
    fxProto.convert = function () {
        var args = Array.prototype.slice.call(arguments);
        args.unshift(this._v);
        return convert.apply(fx, args);
    };

    // fx(val).from(currency) returns a wrapped `fx` where the value has been converted from
    // `currency` to the `fx.base` currency. Should be followed by `.to(otherCurrency)`
    fxProto.from = function (currency) {
        var wrapped = fx(convert(this._v, { from: currency, to: fx.base }));
        wrapped._fx = fx.base;
        return wrapped;
    };

    // fx(val).to(currency) returns the value, converted from `fx.base` to `currency`
    fxProto.to = function (currency) {
        return convert(this._v, { from: this._fx ? this._fx : fx.settings.from, to: currency });
    };


    /* --- Module Definition --- */

    // Export the fx object for CommonJS. If being loaded as an AMD module, define it as such.
    // Otherwise, just add `fx` to the global object
    if (typeof exports !== 'undefined') {
        if (typeof module !== 'undefined' && module.exports) {
            exports = module.exports = fx;
        }
        exports.fx = fx;
    } else if (typeof define === 'function' && define.amd) {
        // Return the library as an AMD module:
        define([], function () {
            return fx;
        });
    } else {
        // Use fx.noConflict to restore `fx` back to its original value before money.js loaded.
        // Returns a reference to the library's `fx` object; e.g. `var money = fx.noConflict();`
        fx.noConflict = (function (previousFx) {
            return function () {
                // Reset the value of the root's `fx` variable:
                root.fx = previousFx;
                // Delete the noConflict function:
                fx.noConflict = undefined;
                // Return reference to the library to re-assign it:
                return fx;
            };
        })(root.fx);

        // Declare `fx` on the root (global/window) object:
        root['fx'] = fx;
    }

    // Root will be `window` in browser or `global` on the server:
}(this));;
/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */
(function (window, document, Math) {
    var rAF = window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.oRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function (callback) { window.setTimeout(callback, 1000 / 60); };

    var utils = (function () {
        var me = {};

        var _elementStyle = document.createElement('div').style;
        var _vendor = (function () {
            var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
                transform,
                i = 0,
                l = vendors.length;

            for (; i < l; i++) {
                transform = vendors[i] + 'ransform';
                if (transform in _elementStyle) return vendors[i].substr(0, vendors[i].length - 1);
            }

            return false;
        })();

        function _prefixStyle(style) {
            if (_vendor === false) return false;
            if (_vendor === '') return style;
            return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
        }

        me.getTime = Date.now || function getTime() { return new Date().getTime(); };

        me.extend = function (target, obj) {
            for (var i in obj) {
                target[i] = obj[i];
            }
        };

        me.addEvent = function (el, type, fn, capture) {
            el.addEventListener(type, fn, !!capture);
        };

        me.removeEvent = function (el, type, fn, capture) {
            el.removeEventListener(type, fn, !!capture);
        };

        me.prefixPointerEvent = function (pointerEvent) {
            return window.MSPointerEvent ?
                'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8) :
                pointerEvent;
        };

        me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) {
            var distance = current - start,
                speed = Math.abs(distance) / time,
                destination,
                duration;

            deceleration = deceleration === undefined ? 0.0006 : deceleration;

            destination = current + (speed * speed) / (2 * deceleration) * (distance < 0 ? -1 : 1);
            duration = speed / deceleration;

            if (destination < lowerMargin) {
                destination = wrapperSize ? lowerMargin - (wrapperSize / 2.5 * (speed / 8)) : lowerMargin;
                distance = Math.abs(destination - current);
                duration = distance / speed;
            } else if (destination > 0) {
                destination = wrapperSize ? wrapperSize / 2.5 * (speed / 8) : 0;
                distance = Math.abs(current) + destination;
                duration = distance / speed;
            }

            return {
                destination: Math.round(destination),
                duration: duration
            };
        };

        var _transform = _prefixStyle('transform');

        me.extend(me, {
            hasTransform: _transform !== false,
            hasPerspective: _prefixStyle('perspective') in _elementStyle,
            hasTouch: 'ontouchstart' in window,
            hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed
            hasTransition: _prefixStyle('transition') in _elementStyle
        });

        /*
        This should find all Android browsers lower than build 535.19 (both stock browser and webview)
        - galaxy S2 is ok
        - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1`
        - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
       - galaxy S3 is badAndroid (stock brower, webview)
         `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
       - galaxy S4 is badAndroid (stock brower, webview)
         `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
       - galaxy S5 is OK
         `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
       - galaxy S6 is OK
         `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
      */
        me.isBadAndroid = (function () {
            var appVersion = window.navigator.appVersion;
            // Android browser is not a chrome browser.
            if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) {
                var safariVersion = appVersion.match(/Safari\/(\d+.\d)/);
                if (safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) {
                    return parseFloat(safariVersion[1]) < 535.19;
                } else {
                    return true;
                }
            } else {
                return false;
            }
        })();

        me.extend(me.style = {}, {
            transform: _transform,
            transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
            transitionDuration: _prefixStyle('transitionDuration'),
            transitionDelay: _prefixStyle('transitionDelay'),
            transformOrigin: _prefixStyle('transformOrigin')
        });

        me.hasClass = function (e, c) {
            var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
            return re.test(e.className);
        };

        me.addClass = function (e, c) {
            if (me.hasClass(e, c)) {
                return;
            }

            var newclass = e.className.split(' ');
            newclass.push(c);
            e.className = newclass.join(' ');
        };

        me.removeClass = function (e, c) {
            if (!me.hasClass(e, c)) {
                return;
            }

            var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
            e.className = e.className.replace(re, ' ');
        };

        me.offset = function (el) {
            var left = -el.offsetLeft,
                top = -el.offsetTop;

            // jshint -W084
            while (el = el.offsetParent) {
                left -= el.offsetLeft;
                top -= el.offsetTop;
            }
            // jshint +W084

            return {
                left: left,
                top: top
            };
        };

        me.preventDefaultException = function (el, exceptions) {
           var elAux = el;
            //if (!el["className"] && (el["tagName"] || "").toLowerCase() === "span") {
            //    elAux = el.firstfirstChild;
            //}
            //if (!elAux) return false;
            for (var i in exceptions) {
                if (i.toLowerCase() === "containerclasses") {
                    if (!exceptions[i]) continue;

                    for (var index = 0; index < exceptions[i].length; ++index) {
                        var container = exceptions[i][index];
                        var parent = document.querySelectorAll(container);
                        if (parent) {
                            for (var ind = 0; ind < parent.length; ind++) {
                                if (parent[ind]&&(parent[ind] === elAux || parent[ind].contains(elAux))) {
                                    return true;
                                }
                            }
                        }
                    };
                    continue;
                }

                if (exceptions[i].test(elAux[i])) {
                    return true;
                }
            }

            return false;
        };

        me.extend(me.eventType = {}, {
            touchstart: 1,
            touchmove: 1,
            touchend: 1,

            mousedown: 2,
            mousemove: 2,
            mouseup: 2,

            pointerdown: 3,
            pointermove: 3,
            pointerup: 3,

            MSPointerDown: 3,
            MSPointerMove: 3,
            MSPointerUp: 3
        });

        me.extend(me.ease = {}, {
            quadratic: {
                style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
                fn: function (k) {
                    return k * (2 - k);
                }
            },
            circular: {
                style: 'cubic-bezier(0.1, 0.57, 0.1, 1)',	// Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1)
                fn: function (k) {
                    return Math.sqrt(1 - (--k * k));
                }
            },
            back: {
                style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
                fn: function (k) {
                    var b = 4;
                    return (k = k - 1) * k * ((b + 1) * k + b) + 1;
                }
            },
            bounce: {
                style: '',
                fn: function (k) {
                    if ((k /= 1) < (1 / 2.75)) {
                        return 7.5625 * k * k;
                    } else if (k < (2 / 2.75)) {
                        return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75;
                    } else if (k < (2.5 / 2.75)) {
                        return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375;
                    } else {
                        return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375;
                    }
                }
            },
            elastic: {
                style: '',
                fn: function (k) {
                    var f = 0.22,
                        e = 0.4;

                    if (k === 0) { return 0; }
                    if (k == 1) { return 1; }

                    return (e * Math.pow(2, -10 * k) * Math.sin((k - f / 4) * (2 * Math.PI) / f) + 1);
                }
            }
        });

        me.tap = function (e, eventName) {
            var ev = document.createEvent('Event');
            ev.initEvent(eventName, true, true);
            ev.pageX = e.pageX;
            ev.pageY = e.pageY;
            e.target.dispatchEvent(ev);
        };

        me.click = function (e) {
            var target = e.target,
                ev;

            if (!(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName)) {
                ev = document.createEvent('MouseEvents');
                ev.initMouseEvent('click', true, true, e.view, 1,
                    target.screenX, target.screenY, target.clientX, target.clientY,
                    e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
                    0, null);

                ev._constructed = true;
                target.dispatchEvent(ev);
            }
        };

        return me;
    })();
    function IScroll(el, options) {
        this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;
        this.scroller = this.wrapper.children[0];
        this.scrollerStyle = this.scroller.style;		// cache style for better performance

        this.options = {

            resizeScrollbars: true,

            mouseWheelSpeed: 20,

            snapThreshold: 0.334,

            // INSERT POINT: OPTIONS
            disablePointer: !utils.hasPointer,
            disableTouch: utils.hasPointer || !utils.hasTouch,
            disableMouse: utils.hasPointer || utils.hasTouch,
            startX: 0,
            startY: 0,
            scrollY: true,
            directionLockThreshold: 5,
            momentum: true,

            bounce: true,
            bounceTime: 600,
            bounceEasing: '',

            preventDefault: true,
            preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/ },

            HWCompositing: true,
            useTransition: true,
            useTransform: true,
            bindToWrapper: typeof window.onmousedown === "undefined"
        };

        for (var i in options) {
            this.options[i] = options[i];
        }

        // Normalize options
        this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : '';

        this.options.useTransition = utils.hasTransition && this.options.useTransition;
        this.options.useTransform = utils.hasTransform && this.options.useTransform;

        this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;
        this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;

        // If you want eventPassthrough I have to lock one of the axes
        this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;
        this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;

        // With eventPassthrough we also need lockDirection mechanism
        this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;
        this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;

        this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;

        this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;

        if (this.options.tap === true) {
            this.options.tap = 'tap';
        }

        if (this.options.shrinkScrollbars == 'scale') {
            this.options.useTransition = false;
        }

        this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1;

        // INSERT POINT: NORMALIZATION

        // Some defaults
        this.x = 0;
        this.y = 0;
        this.directionX = 0;
        this.directionY = 0;
        this._events = {};

        // INSERT POINT: DEFAULTS

        this._init();
        this.refresh();

        this.scrollTo(this.options.startX, this.options.startY);
        this.enable();
    }

    IScroll.prototype = {
        version: '5.2.0',

        _init: function () {
            this._initEvents();

            if (this.options.scrollbars || this.options.indicators) {
                this._initIndicators();
            }

            if (this.options.mouseWheel) {
                this._initWheel();
            }

            if (this.options.snap) {
                this._initSnap();
            }

            if (this.options.keyBindings) {
                this._initKeys();
            }

            // INSERT POINT: _init

        },

        destroy: function () {
            this._initEvents(true);
            clearTimeout(this.resizeTimeout);
            this.resizeTimeout = null;
            this._execEvent('destroy');
        },

        _transitionEnd: function (e) {
            if (e.target != this.scroller || !this.isInTransition) {
                return;
            }

            this._transitionTime();
            if (!this.resetPosition(this.options.bounceTime)) {
                this.isInTransition = false;
                this._execEvent('scrollEnd');
            }
        },

        _start: function (e) {
            // React to left mouse button only
            if (utils.eventType[e.type] != 1) {
                // for button property
                // http://unixpapa.com/js/mouse.html
                var button;
                if (!e.which) {
                    /* IE case */
                    button = (e.button < 2) ? 0 :
                             ((e.button == 4) ? 1 : 2);
                } else {
                    /* All others */
                    button = e.button;
                }
                if (button !== 0) {
                    return;
                }
            }

            if (!this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated)) {
                return;
            }

            if (this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException)) {
                e.preventDefault();
            }

            var point = e.touches ? e.touches[0] : e,
                pos;

            this.initiated = utils.eventType[e.type];
            this.moved = false;
            this.distX = 0;
            this.distY = 0;
            this.directionX = 0;
            this.directionY = 0;
            this.directionLocked = 0;

            this.startTime = utils.getTime();

            if (this.options.useTransition && this.isInTransition) {
                this._transitionTime();
                this.isInTransition = false;
                pos = this.getComputedPosition();
                this._translate(Math.round(pos.x), Math.round(pos.y));
                this._execEvent('scrollEnd');
            } else if (!this.options.useTransition && this.isAnimating) {
                this.isAnimating = false;
                this._execEvent('scrollEnd');
            }

            this.startX = this.x;
            this.startY = this.y;
            this.absStartX = this.x;
            this.absStartY = this.y;
            this.pointX = point.pageX;
            this.pointY = point.pageY;

            this._execEvent('beforeScrollStart');
        },

        _move: function (e) {
            if (!this.enabled || utils.eventType[e.type] !== this.initiated) {
                return;
            }

            if (this.options.preventDefault) {	// increases performance on Android? TODO: check!
                e.preventDefault();
            }

            var point = e.touches ? e.touches[0] : e,
                deltaX = point.pageX - this.pointX,
                deltaY = point.pageY - this.pointY,
                timestamp = utils.getTime(),
                newX, newY,
                absDistX, absDistY;

            this.pointX = point.pageX;
            this.pointY = point.pageY;

            this.distX += deltaX;
            this.distY += deltaY;
            absDistX = Math.abs(this.distX);
            absDistY = Math.abs(this.distY);

            // We need to move at least 10 pixels for the scrolling to initiate
            if (timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10)) {
                return;
            }

            // If you are scrolling in one direction lock the other
            if (!this.directionLocked && !this.options.freeScroll) {
                if (absDistX > absDistY + this.options.directionLockThreshold) {
                    this.directionLocked = 'h';		// lock horizontally
                } else if (absDistY >= absDistX + this.options.directionLockThreshold) {
                    this.directionLocked = 'v';		// lock vertically
                } else {
                    this.directionLocked = 'n';		// no lock
                }
            }

            if (this.directionLocked == 'h') {
                if (this.options.eventPassthrough == 'vertical') {
                    e.preventDefault();
                } else if (this.options.eventPassthrough == 'horizontal') {
                    this.initiated = false;
                    return;
                }

                deltaY = 0;
            } else if (this.directionLocked == 'v') {
                if (this.options.eventPassthrough == 'horizontal') {
                    e.preventDefault();
                } else if (this.options.eventPassthrough == 'vertical') {
                    this.initiated = false;
                    return;
                }

                deltaX = 0;
            }

            deltaX = this.hasHorizontalScroll ? deltaX : 0;
            deltaY = this.hasVerticalScroll ? deltaY : 0;

            newX = this.x + deltaX;
            newY = this.y + deltaY;

            // Slow down if outside of the boundaries
            if (newX > 0 || newX < this.maxScrollX) {
                newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
            }
            if (newY > 0 || newY < this.maxScrollY) {
                newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
            }

            this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
            this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;

            if (!this.moved) {
                this._execEvent('scrollStart');
            }

            this.moved = true;

            this._translate(newX, newY);

            /* REPLACE START: _move */

            if (timestamp - this.startTime > 300) {
                this.startTime = timestamp;
                this.startX = this.x;
                this.startY = this.y;
            }

            /* REPLACE END: _move */

        },

        _end: function (e) {
            if (!this.enabled || utils.eventType[e.type] !== this.initiated) {
                return;
            }

            if (this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException)) {
                e.preventDefault();
            }

            var point = e.changedTouches ? e.changedTouches[0] : e,
                momentumX,
                momentumY,
                duration = utils.getTime() - this.startTime,
                newX = Math.round(this.x),
                newY = Math.round(this.y),
                distanceX = Math.abs(newX - this.startX),
                distanceY = Math.abs(newY - this.startY),
                time = 0,
                easing = '';

            this.isInTransition = 0;
            this.initiated = 0;
            this.endTime = utils.getTime();

            // reset if we are outside of the boundaries
            if (this.resetPosition(this.options.bounceTime)) {
                return;
            }

            this.scrollTo(newX, newY);	// ensures that the last position is rounded

            // we scrolled less than 10 pixels
            if (!this.moved) {
                if (this.options.tap) {
                    utils.tap(e, this.options.tap);
                }

                if (this.options.click) {
                    utils.click(e);
                }

                this._execEvent('scrollCancel');
                return;
            }

            if (this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100) {
                this._execEvent('flick');
                return;
            }

            // start momentum animation if needed
            if (this.options.momentum && duration < 300) {
                momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0, this.options.deceleration) : { destination: newX, duration: 0 };
                momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration) : { destination: newY, duration: 0 };
                newX = momentumX.destination;
                newY = momentumY.destination;
                time = Math.max(momentumX.duration, momentumY.duration);
                this.isInTransition = 1;
            }


            if (this.options.snap) {
                var snap = this._nearestSnap(newX, newY);
                this.currentPage = snap;
                time = this.options.snapSpeed || Math.max(
                        Math.max(
                            Math.min(Math.abs(newX - snap.x), 1000),
                            Math.min(Math.abs(newY - snap.y), 1000)
                        ), 300);
                newX = snap.x;
                newY = snap.y;

                this.directionX = 0;
                this.directionY = 0;
                easing = this.options.bounceEasing;
            }

            // INSERT POINT: _end

            if (newX != this.x || newY != this.y) {
                // change easing function when scroller goes out of the boundaries
                if (newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY) {
                    easing = utils.ease.quadratic;
                }

                this.scrollTo(newX, newY, time, easing);
                return;
            }

            this._execEvent('scrollEnd');
        },

        _resize: function () {
            var that = this;

            clearTimeout(this.resizeTimeout);

            this.resizeTimeout = setTimeout(function () {
                that.refresh();
            }, this.options.resizePolling);
        },

        resetPosition: function (time) {
            var x = this.x,
                y = this.y;

            time = time || 0;

            if (!this.hasHorizontalScroll || this.x > 0) {
                x = 0;
            } else if (this.x < this.maxScrollX) {
                x = this.maxScrollX;
            }

            if (!this.hasVerticalScroll || this.y > 0) {
                y = 0;
            } else if (this.y < this.maxScrollY) {
                y = this.maxScrollY;
            }

            if (x == this.x && y == this.y) {
                return false;
            }

            this.scrollTo(x, y, time, this.options.bounceEasing);

            return true;
        },

        disable: function () {
            this.enabled = false;
        },

        enable: function () {
            this.enabled = true;
        },

        refresh: function () {
            var rf = this.wrapper.offsetHeight;		// Force reflow

            this.wrapperWidth = this.wrapper.clientWidth;
            this.wrapperHeight = this.wrapper.clientHeight;

            /* REPLACE START: refresh */

            this.scrollerWidth = this.scroller.offsetWidth;
            this.scrollerHeight = this.scroller.offsetHeight;

            this.maxScrollX = this.wrapperWidth - this.scrollerWidth;
            this.maxScrollY = this.wrapperHeight - this.scrollerHeight;

            /* REPLACE END: refresh */

            this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0;
            this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0;

            if (!this.hasHorizontalScroll) {
                this.maxScrollX = 0;
                this.scrollerWidth = this.wrapperWidth;
            }

            if (!this.hasVerticalScroll) {
                this.maxScrollY = 0;
                this.scrollerHeight = this.wrapperHeight;
            }

            this.endTime = 0;
            this.directionX = 0;
            this.directionY = 0;

            this.wrapperOffset = utils.offset(this.wrapper);

            this._execEvent('refresh');

            this.resetPosition();

            // INSERT POINT: _refresh

        },

        on: function (type, fn) {
            if (!this._events[type]) {
                this._events[type] = [];
            }

            this._events[type].push(fn);
        },

        off: function (type, fn) {
            if (!this._events[type]) {
                return;
            }

            var index = this._events[type].indexOf(fn);

            if (index > -1) {
                this._events[type].splice(index, 1);
            }
        },

        _execEvent: function (type) {
            if (!this._events[type]) {
                return;
            }

            var i = 0,
                l = this._events[type].length;

            if (!l) {
                return;
            }

            for (; i < l; i++) {
                this._events[type][i].apply(this, [].slice.call(arguments, 1));
            }
        },

        scrollBy: function (x, y, time, easing) {
            x = this.x + x;
            y = this.y + y;
            time = time || 0;

            this.scrollTo(x, y, time, easing);
        },

        scrollTo: function (x, y, time, easing) {
            easing = easing || utils.ease.circular;

            this.isInTransition = this.options.useTransition && time > 0;
            var transitionType = this.options.useTransition && easing.style;
            if (!time || transitionType) {
                if (transitionType) {
                    this._transitionTimingFunction(easing.style);
                    this._transitionTime(time);
                }
                this._translate(x, y);
            } else {
                this._animate(x, y, time, easing.fn);
            }
        },

        scrollToElement: function (el, time, offsetX, offsetY, easing) {
            el = el.nodeType ? el : this.scroller.querySelector(el);

            if (!el) {
                return;
            }

            var pos = utils.offset(el);

            pos.left -= this.wrapperOffset.left;
            pos.top -= this.wrapperOffset.top;

            // if offsetX/Y are true we center the element to the screen
            if (offsetX === true) {
                offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2);
            }
            if (offsetY === true) {
                offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2);
            }

            pos.left -= offsetX || 0;
            pos.top -= offsetY || 0;

            pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left;
            pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY : pos.top;

            time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x - pos.left), Math.abs(this.y - pos.top)) : time;

            this.scrollTo(pos.left, pos.top, time, easing);
        },

        _transitionTime: function (time) {
            time = time || 0;

            var durationProp = utils.style.transitionDuration;
            this.scrollerStyle[durationProp] = time + 'ms';

            if (!time && utils.isBadAndroid) {
                this.scrollerStyle[durationProp] = '0.0001ms';
                // remove 0.0001ms
                var self = this;
                rAF(function () {
                    if (self.scrollerStyle[durationProp] === '0.0001ms') {
                        self.scrollerStyle[durationProp] = '0s';
                    }
                });
            }


            if (this.indicators) {
                for (var i = this.indicators.length; i--;) {
                    this.indicators[i].transitionTime(time);
                }
            }


            // INSERT POINT: _transitionTime

        },

        _transitionTimingFunction: function (easing) {
            this.scrollerStyle[utils.style.transitionTimingFunction] = easing;


            if (this.indicators) {
                for (var i = this.indicators.length; i--;) {
                    this.indicators[i].transitionTimingFunction(easing);
                }
            }


            // INSERT POINT: _transitionTimingFunction

        },

        _translate: function (x, y) {
            if (this.options.useTransform) {

                /* REPLACE START: _translate */

                this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;

                /* REPLACE END: _translate */

            } else {
                x = Math.round(x);
                y = Math.round(y);
                this.scrollerStyle.left = x + 'px';
                this.scrollerStyle.top = y + 'px';
            }

            this.x = x;
            this.y = y;


            if (this.indicators) {
                for (var i = this.indicators.length; i--;) {
                    this.indicators[i].updatePosition();
                }
            }


            // INSERT POINT: _translate

        },

        _initEvents: function (remove) {
            var eventType = remove ? utils.removeEvent : utils.addEvent,
                target = this.options.bindToWrapper ? this.wrapper : window;

            eventType(window, 'orientationchange', this);
            eventType(window, 'resize', this);

            if (this.options.click) {
                eventType(this.wrapper, 'click', this, true);
            }

            if (!this.options.disableMouse) {
                eventType(this.wrapper, 'mousedown', this);
                eventType(target, 'mousemove', this);
                eventType(target, 'mousecancel', this);
                eventType(target, 'mouseup', this);
            }

            if (utils.hasPointer && !this.options.disablePointer) {
                eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this);
                eventType(target, utils.prefixPointerEvent('pointermove'), this);
                eventType(target, utils.prefixPointerEvent('pointercancel'), this);
                eventType(target, utils.prefixPointerEvent('pointerup'), this);
            }

            if (utils.hasTouch && !this.options.disableTouch) {
                eventType(this.wrapper, 'touchstart', this);
                eventType(target, 'touchmove', this);
                eventType(target, 'touchcancel', this);
                eventType(target, 'touchend', this);
            }

            eventType(this.scroller, 'transitionend', this);
            eventType(this.scroller, 'webkitTransitionEnd', this);
            eventType(this.scroller, 'oTransitionEnd', this);
            eventType(this.scroller, 'MSTransitionEnd', this);
        },

        getComputedPosition: function () {
            var matrix = window.getComputedStyle(this.scroller, null),
                x, y;

            if (this.options.useTransform) {
                matrix = matrix[utils.style.transform].split(')')[0].split(', ');
                x = +(matrix[12] || matrix[4]);
                y = +(matrix[13] || matrix[5]);
            } else {
                x = +matrix.left.replace(/[^-\d.]/g, '');
                y = +matrix.top.replace(/[^-\d.]/g, '');
            }

            return { x: x, y: y };
        },
        _initIndicators: function () {
            var interactive = this.options.interactiveScrollbars,
                customStyle = typeof this.options.scrollbars != 'string',
                indicators = [],
                indicator;

            var that = this;

            this.indicators = [];

            if (this.options.scrollbars) {
                // Vertical scrollbar
                if (this.options.scrollY) {
                    indicator = {
                        el: createDefaultScrollbar('v', interactive, this.options.scrollbars),
                        interactive: interactive,
                        defaultScrollbars: true,
                        customStyle: customStyle,
                        resize: this.options.resizeScrollbars,
                        shrink: this.options.shrinkScrollbars,
                        fade: this.options.fadeScrollbars,
                        listenX: false
                    };

                    this.wrapper.appendChild(indicator.el);
                    indicators.push(indicator);
                }

                // Horizontal scrollbar
                if (this.options.scrollX) {
                    indicator = {
                        el: createDefaultScrollbar('h', interactive, this.options.scrollbars),
                        interactive: interactive,
                        defaultScrollbars: true,
                        customStyle: customStyle,
                        resize: this.options.resizeScrollbars,
                        shrink: this.options.shrinkScrollbars,
                        fade: this.options.fadeScrollbars,
                        listenY: false
                    };

                    this.wrapper.appendChild(indicator.el);
                    indicators.push(indicator);
                }
            }

            if (this.options.indicators) {
                // TODO: check concat compatibility
                indicators = indicators.concat(this.options.indicators);
            }

            for (var i = indicators.length; i--;) {
                this.indicators.push(new Indicator(this, indicators[i]));
            }

            // TODO: check if we can use array.map (wide compatibility and performance issues)
            function _indicatorsMap(fn) {
                if (that.indicators) {
                    for (var i = that.indicators.length; i--;) {
                        fn.call(that.indicators[i]);
                    }
                }
            }

            if (this.options.fadeScrollbars) {
                this.on('scrollEnd', function () {
                    _indicatorsMap(function () {
                        this.fade();
                    });
                });

                this.on('scrollCancel', function () {
                    _indicatorsMap(function () {
                        this.fade();
                    });
                });

                this.on('scrollStart', function () {
                    _indicatorsMap(function () {
                        this.fade(1);
                    });
                });

                this.on('beforeScrollStart', function () {
                    _indicatorsMap(function () {
                        this.fade(1, true);
                    });
                });
            }


            this.on('refresh', function () {
                _indicatorsMap(function () {
                    this.refresh();
                });
            });

            this.on('destroy', function () {
                _indicatorsMap(function () {
                    this.destroy();
                });

                delete this.indicators;
            });
        },

        _initWheel: function () {
            utils.addEvent(this.wrapper, 'wheel', this);
            utils.addEvent(this.wrapper, 'mousewheel', this);
            utils.addEvent(this.wrapper, 'DOMMouseScroll', this);

            this.on('destroy', function () {
                clearTimeout(this.wheelTimeout);
                this.wheelTimeout = null;
                utils.removeEvent(this.wrapper, 'wheel', this);
                utils.removeEvent(this.wrapper, 'mousewheel', this);
                utils.removeEvent(this.wrapper, 'DOMMouseScroll', this);
            });
        },

        _wheel: function (e) {
            if (!this.enabled || $(e.target).parents(".dropdownjs").length) {
                return;
            }

            e.preventDefault();

            var wheelDeltaX, wheelDeltaY,
                newX, newY,
                that = this;

            if (this.wheelTimeout === undefined) {
                that._execEvent('scrollStart');
            }

            // Execute the scrollEnd event after 400ms the wheel stopped scrolling
            clearTimeout(this.wheelTimeout);
            this.wheelTimeout = setTimeout(function () {
                if (!that.options.snap) {
                    that._execEvent('scrollEnd');
                }
                that.wheelTimeout = undefined;
            }, 400);

            if ('deltaX' in e) {
                if (e.deltaMode === 1) {
                    wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed;
                    wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed;
                } else {
                    wheelDeltaX = -e.deltaX;
                    wheelDeltaY = -e.deltaY;
                }
            } else if ('wheelDeltaX' in e) {
                wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed;
                wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed;
            } else if ('wheelDelta' in e) {
                wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed;
            } else if ('detail' in e) {
                wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed;
            } else {
                return;
            }

            wheelDeltaX *= this.options.invertWheelDirection;
            wheelDeltaY *= this.options.invertWheelDirection;

            if (!this.hasVerticalScroll) {
                wheelDeltaX = wheelDeltaY;
                wheelDeltaY = 0;
            }

            if (this.options.snap) {
                newX = this.currentPage.pageX;
                newY = this.currentPage.pageY;

                if (wheelDeltaX > 0) {
                    newX--;
                } else if (wheelDeltaX < 0) {
                    newX++;
                }

                if (wheelDeltaY > 0) {
                    newY--;
                } else if (wheelDeltaY < 0) {
                    newY++;
                }

                this.goToPage(newX, newY);

                return;
            }

            newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0);
            newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0);

            this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0;
            this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0;

            if (newX > 0) {
                newX = 0;
            } else if (newX < this.maxScrollX) {
                newX = this.maxScrollX;
            }

            if (newY > 0) {
                newY = 0;
            } else if (newY < this.maxScrollY) {
                newY = this.maxScrollY;
            }

            this.scrollTo(newX, newY, 0);

            // INSERT POINT: _wheel
        },

        _initSnap: function () {
            this.currentPage = {};

            if (typeof this.options.snap == 'string') {
                this.options.snap = this.scroller.querySelectorAll(this.options.snap);
            }

            this.on('refresh', function () {
                var i = 0, l,
                    m = 0, n,
                    cx, cy,
                    x = 0, y,
                    stepX = this.options.snapStepX || this.wrapperWidth,
                    stepY = this.options.snapStepY || this.wrapperHeight,
                    el;

                this.pages = [];

                if (!this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight) {
                    return;
                }

                if (this.options.snap === true) {
                    cx = Math.round(stepX / 2);
                    cy = Math.round(stepY / 2);

                    while (x > -this.scrollerWidth) {
                        this.pages[i] = [];
                        l = 0;
                        y = 0;

                        while (y > -this.scrollerHeight) {
                            this.pages[i][l] = {
                                x: Math.max(x, this.maxScrollX),
                                y: Math.max(y, this.maxScrollY),
                                width: stepX,
                                height: stepY,
                                cx: x - cx,
                                cy: y - cy
                            };

                            y -= stepY;
                            l++;
                        }

                        x -= stepX;
                        i++;
                    }
                } else {
                    el = this.options.snap;
                    l = el.length;
                    n = -1;

                    for (; i < l; i++) {
                        if (i === 0 || el[i].offsetLeft <= el[i - 1].offsetLeft) {
                            m = 0;
                            n++;
                        }

                        if (!this.pages[m]) {
                            this.pages[m] = [];
                        }

                        x = Math.max(-el[i].offsetLeft, this.maxScrollX);
                        y = Math.max(-el[i].offsetTop, this.maxScrollY);
                        cx = x - Math.round(el[i].offsetWidth / 2);
                        cy = y - Math.round(el[i].offsetHeight / 2);

                        this.pages[m][n] = {
                            x: x,
                            y: y,
                            width: el[i].offsetWidth,
                            height: el[i].offsetHeight,
                            cx: cx,
                            cy: cy
                        };

                        if (x > this.maxScrollX) {
                            m++;
                        }
                    }
                }

                this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0);

                // Update snap threshold if needed
                if (this.options.snapThreshold % 1 === 0) {
                    this.snapThresholdX = this.options.snapThreshold;
                    this.snapThresholdY = this.options.snapThreshold;
                } else {
                    this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold);
                    this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold);
                }
            });

            this.on('flick', function () {
                var time = this.options.snapSpeed || Math.max(
                        Math.max(
                            Math.min(Math.abs(this.x - this.startX), 1000),
                            Math.min(Math.abs(this.y - this.startY), 1000)
                        ), 300);

                this.goToPage(
                    this.currentPage.pageX + this.directionX,
                    this.currentPage.pageY + this.directionY,
                    time
                );
            });
        },

        _nearestSnap: function (x, y) {
            if (!this.pages.length) {
                return { x: 0, y: 0, pageX: 0, pageY: 0 };
            }

            var i = 0,
                l = this.pages.length,
                m = 0;

            // Check if we exceeded the snap threshold
            if (Math.abs(x - this.absStartX) < this.snapThresholdX &&
                Math.abs(y - this.absStartY) < this.snapThresholdY) {
                return this.currentPage;
            }

            if (x > 0) {
                x = 0;
            } else if (x < this.maxScrollX) {
                x = this.maxScrollX;
            }

            if (y > 0) {
                y = 0;
            } else if (y < this.maxScrollY) {
                y = this.maxScrollY;
            }

            for (; i < l; i++) {
                if (x >= this.pages[i][0].cx) {
                    x = this.pages[i][0].x;
                    break;
                }
            }

            l = this.pages[i].length;

            for (; m < l; m++) {
                if (y >= this.pages[0][m].cy) {
                    y = this.pages[0][m].y;
                    break;
                }
            }

            if (i == this.currentPage.pageX) {
                i += this.directionX;

                if (i < 0) {
                    i = 0;
                } else if (i >= this.pages.length) {
                    i = this.pages.length - 1;
                }

                x = this.pages[i][0].x;
            }

            if (m == this.currentPage.pageY) {
                m += this.directionY;

                if (m < 0) {
                    m = 0;
                } else if (m >= this.pages[0].length) {
                    m = this.pages[0].length - 1;
                }

                y = this.pages[0][m].y;
            }

            return {
                x: x,
                y: y,
                pageX: i,
                pageY: m
            };
        },

        goToPage: function (x, y, time, easing) {
            easing = easing || this.options.bounceEasing;

            if (x >= this.pages.length) {
                x = this.pages.length - 1;
            } else if (x < 0) {
                x = 0;
            }

            if (y >= this.pages[x].length) {
                y = this.pages[x].length - 1;
            } else if (y < 0) {
                y = 0;
            }

            var posX = this.pages[x][y].x,
                posY = this.pages[x][y].y;

            time = time === undefined ? this.options.snapSpeed || Math.max(
                Math.max(
                    Math.min(Math.abs(posX - this.x), 1000),
                    Math.min(Math.abs(posY - this.y), 1000)
                ), 300) : time;

            this.currentPage = {
                x: posX,
                y: posY,
                pageX: x,
                pageY: y
            };

            this.scrollTo(posX, posY, time, easing);
        },

        next: function (time, easing) {
            var x = this.currentPage.pageX,
                y = this.currentPage.pageY;

            x++;

            if (x >= this.pages.length && this.hasVerticalScroll) {
                x = 0;
                y++;
            }

            this.goToPage(x, y, time, easing);
        },

        prev: function (time, easing) {
            var x = this.currentPage.pageX,
                y = this.currentPage.pageY;

            x--;

            if (x < 0 && this.hasVerticalScroll) {
                x = 0;
                y--;
            }

            this.goToPage(x, y, time, easing);
        },

        _initKeys: function (e) {
            // default key bindings
            var keys = {
                pageUp: 33,
                pageDown: 34,
                end: 35,
                home: 36,
                left: 37,
                up: 38,
                right: 39,
                down: 40
            };
            var i;

            // if you give me characters I give you keycode
            if (typeof this.options.keyBindings == 'object') {
                for (i in this.options.keyBindings) {
                    if (typeof this.options.keyBindings[i] == 'string') {
                        this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCodeAt(0);
                    }
                }
            } else {
                this.options.keyBindings = {};
            }

            for (i in keys) {
                this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i];
            }

            utils.addEvent(window, 'keydown', this);

            this.on('destroy', function () {
                utils.removeEvent(window, 'keydown', this);
            });
        },

        _key: function (e) {
            if (!this.enabled) {
                return;
            }

            var snap = this.options.snap,	// we are using this alot, better to cache it
                newX = snap ? this.currentPage.pageX : this.x,
                newY = snap ? this.currentPage.pageY : this.y,
                now = utils.getTime(),
                prevTime = this.keyTime || 0,
                acceleration = 0.250,
                pos;

            if (this.options.useTransition && this.isInTransition) {
                pos = this.getComputedPosition();

                this._translate(Math.round(pos.x), Math.round(pos.y));
                this.isInTransition = false;
            }

            this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0;

            switch (e.keyCode) {
                case this.options.keyBindings.pageUp:
                    if (this.hasHorizontalScroll && !this.hasVerticalScroll) {
                        newX += snap ? 1 : this.wrapperWidth;
                    } else {
                        newY += snap ? 1 : this.wrapperHeight;
                    }
                    break;
                case this.options.keyBindings.pageDown:
                    if (this.hasHorizontalScroll && !this.hasVerticalScroll) {
                        newX -= snap ? 1 : this.wrapperWidth;
                    } else {
                        newY -= snap ? 1 : this.wrapperHeight;
                    }
                    break;
                case this.options.keyBindings.end:
                    newX = snap ? this.pages.length - 1 : this.maxScrollX;
                    newY = snap ? this.pages[0].length - 1 : this.maxScrollY;
                    break;
                case this.options.keyBindings.home:
                    newX = 0;
                    newY = 0;
                    break;
                case this.options.keyBindings.left:
                    newX += snap ? -1 : 5 + this.keyAcceleration >> 0;
                    break;
                case this.options.keyBindings.up:
                    newY += snap ? 1 : 5 + this.keyAcceleration >> 0;
                    break;
                case this.options.keyBindings.right:
                    newX -= snap ? -1 : 5 + this.keyAcceleration >> 0;
                    break;
                case this.options.keyBindings.down:
                    newY -= snap ? 1 : 5 + this.keyAcceleration >> 0;
                    break;
                default:
                    return;
            }

            if (snap) {
                this.goToPage(newX, newY);
                return;
            }

            if (newX > 0) {
                newX = 0;
                this.keyAcceleration = 0;
            } else if (newX < this.maxScrollX) {
                newX = this.maxScrollX;
                this.keyAcceleration = 0;
            }

            if (newY > 0) {
                newY = 0;
                this.keyAcceleration = 0;
            } else if (newY < this.maxScrollY) {
                newY = this.maxScrollY;
                this.keyAcceleration = 0;
            }

            this.scrollTo(newX, newY, 0);

            this.keyTime = now;
        },

        _animate: function (destX, destY, duration, easingFn) {
            var that = this,
                startX = this.x,
                startY = this.y,
                startTime = utils.getTime(),
                destTime = startTime + duration;

            function step() {
                var now = utils.getTime(),
                    newX, newY,
                    easing;

                if (now >= destTime) {
                    that.isAnimating = false;
                    that._translate(destX, destY);

                    if (!that.resetPosition(that.options.bounceTime)) {
                        that._execEvent('scrollEnd');
                    }

                    return;
                }

                now = (now - startTime) / duration;
                easing = easingFn(now);
                newX = (destX - startX) * easing + startX;
                newY = (destY - startY) * easing + startY;
                that._translate(newX, newY);

                if (that.isAnimating) {
                    rAF(step);
                }
            }

            this.isAnimating = true;
            step();
        },
        handleEvent: function (e) {
            switch (e.type) {
                case 'touchstart':
                case 'pointerdown':
                case 'MSPointerDown':
                case 'mousedown':
                    this._start(e);
                    break;
                case 'touchmove':
                case 'pointermove':
                case 'MSPointerMove':
                case 'mousemove':
                    this._move(e);
                    break;
                case 'touchend':
                case 'pointerup':
                case 'MSPointerUp':
                case 'mouseup':
                case 'touchcancel':
                case 'pointercancel':
                case 'MSPointerCancel':
                case 'mousecancel':
                    this._end(e);
                    break;
                case 'orientationchange':
                case 'resize':
                    this._resize();
                    break;
                case 'transitionend':
                case 'webkitTransitionEnd':
                case 'oTransitionEnd':
                case 'MSTransitionEnd':
                    this._transitionEnd(e);
                    break;
                case 'wheel':
                case 'DOMMouseScroll':
                case 'mousewheel':
                    this._wheel(e);
                    break;
                case 'keydown':
                    this._key(e);
                    break;
                case 'click':
                    if (this.enabled && !e._constructed) {
                        e.preventDefault();
                        e.stopPropagation();
                    }
                    break;
            }
        }
    };
    function createDefaultScrollbar(direction, interactive, type) {
        var scrollbar = document.createElement('div'),
            indicator = document.createElement('div');

        if (type === true) {
            scrollbar.style.cssText = 'position:absolute;z-index:9999';
            indicator.style.cssText = '-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px';
        }

        indicator.className = 'iScrollIndicator';

        if (direction == 'h') {
            if (type === true) {
                scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';
                indicator.style.height = '100%';
            }
            scrollbar.className = 'iScrollHorizontalScrollbar';
        } else {
            if (type === true) {
                scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';
                indicator.style.width = '100%';
            }
            scrollbar.className = 'iScrollVerticalScrollbar';
        }

        scrollbar.style.cssText += ';overflow:hidden';

        if (!interactive) {
            scrollbar.style.pointerEvents = 'none';
        }

        scrollbar.appendChild(indicator);

        return scrollbar;
    }

    function Indicator(scroller, options) {
        this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el;
        this.wrapperStyle = this.wrapper.style;
        this.indicator = this.wrapper.children[0];
        this.indicatorStyle = this.indicator.style;
        this.scroller = scroller;

        this.options = {
            listenX: true,
            listenY: true,
            interactive: false,
            resize: true,
            defaultScrollbars: false,
            shrink: false,
            fade: false,
            speedRatioX: 0,
            speedRatioY: 0
        };

        for (var i in options) {
            this.options[i] = options[i];
        }

        this.sizeRatioX = 1;
        this.sizeRatioY = 1;
        this.maxPosX = 0;
        this.maxPosY = 0;

        if (this.options.interactive) {
            if (!this.options.disableTouch) {
                utils.addEvent(this.indicator, 'touchstart', this);
                utils.addEvent(window, 'touchend', this);
            }
            if (!this.options.disablePointer) {
                utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
                utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this);
            }
            if (!this.options.disableMouse) {
                utils.addEvent(this.indicator, 'mousedown', this);
                utils.addEvent(window, 'mouseup', this);
            }
        }

        if (this.options.fade) {
            this.wrapperStyle[utils.style.transform] = this.scroller.translateZ;
            var durationProp = utils.style.transitionDuration;
            this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms';
            // remove 0.0001ms
            var self = this;
            if (utils.isBadAndroid) {
                rAF(function () {
                    if (self.wrapperStyle[durationProp] === '0.0001ms') {
                        self.wrapperStyle[durationProp] = '0s';
                    }
                });
            }
            this.wrapperStyle.opacity = '0';
        }
    }

    Indicator.prototype = {
        handleEvent: function (e) {
            switch (e.type) {
                case 'touchstart':
                case 'pointerdown':
                case 'MSPointerDown':
                case 'mousedown':
                    this._start(e);
                    break;
                case 'touchmove':
                case 'pointermove':
                case 'MSPointerMove':
                case 'mousemove':
                    this._move(e);
                    break;
                case 'touchend':
                case 'pointerup':
                case 'MSPointerUp':
                case 'mouseup':
                case 'touchcancel':
                case 'pointercancel':
                case 'MSPointerCancel':
                case 'mousecancel':
                    this._end(e);
                    break;
            }
        },

        destroy: function () {
            if (this.options.fadeScrollbars) {
                clearTimeout(this.fadeTimeout);
                this.fadeTimeout = null;
            }
            if (this.options.interactive) {
                utils.removeEvent(this.indicator, 'touchstart', this);
                utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
                utils.removeEvent(this.indicator, 'mousedown', this);

                utils.removeEvent(window, 'touchmove', this);
                utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
                utils.removeEvent(window, 'mousemove', this);

                utils.removeEvent(window, 'touchend', this);
                utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this);
                utils.removeEvent(window, 'mouseup', this);
            }

            if (this.options.defaultScrollbars) {
                this.wrapper.parentNode.removeChild(this.wrapper);
            }
        },

        _start: function (e) {
            var point = e.touches ? e.touches[0] : e;

            e.preventDefault();
            e.stopPropagation();

            this.transitionTime();

            this.initiated = true;
            this.moved = false;
            this.lastPointX = point.pageX;
            this.lastPointY = point.pageY;

            this.startTime = utils.getTime();

            if (!this.options.disableTouch) {
                utils.addEvent(window, 'touchmove', this);
            }
            if (!this.options.disablePointer) {
                utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this);
            }
            if (!this.options.disableMouse) {
                utils.addEvent(window, 'mousemove', this);
            }

            this.scroller._execEvent('beforeScrollStart');
        },

        _move: function (e) {
            var point = e.touches ? e.touches[0] : e,
                deltaX, deltaY,
                newX, newY,
                timestamp = utils.getTime();

            if (!this.moved) {
                this.scroller._execEvent('scrollStart');
            }

            this.moved = true;

            deltaX = point.pageX - this.lastPointX;
            this.lastPointX = point.pageX;

            deltaY = point.pageY - this.lastPointY;
            this.lastPointY = point.pageY;

            newX = this.x + deltaX;
            newY = this.y + deltaY;

            this._pos(newX, newY);

            // INSERT POINT: indicator._move

            e.preventDefault();
            e.stopPropagation();
        },

        _end: function (e) {
            if (!this.initiated) {
                return;
            }

            this.initiated = false;

            e.preventDefault();
            e.stopPropagation();

            utils.removeEvent(window, 'touchmove', this);
            utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
            utils.removeEvent(window, 'mousemove', this);

            if (this.scroller.options.snap) {
                var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y);

                var time = this.options.snapSpeed || Math.max(
                        Math.max(
                            Math.min(Math.abs(this.scroller.x - snap.x), 1000),
                            Math.min(Math.abs(this.scroller.y - snap.y), 1000)
                        ), 300);

                if (this.scroller.x != snap.x || this.scroller.y != snap.y) {
                    this.scroller.directionX = 0;
                    this.scroller.directionY = 0;
                    this.scroller.currentPage = snap;
                    this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing);
                }
            }

            if (this.moved) {
                this.scroller._execEvent('scrollEnd');
            }
        },

        transitionTime: function (time) {
            time = time || 0;
            var durationProp = utils.style.transitionDuration;
            this.indicatorStyle[durationProp] = time + 'ms';

            if (!time && utils.isBadAndroid) {
                this.indicatorStyle[durationProp] = '0.0001ms';
                // remove 0.0001ms
                var self = this;
                rAF(function () {
                    if (self.indicatorStyle[durationProp] === '0.0001ms') {
                        self.indicatorStyle[durationProp] = '0s';
                    }
                });
            }
        },

        transitionTimingFunction: function (easing) {
            this.indicatorStyle[utils.style.transitionTimingFunction] = easing;
        },

        refresh: function () {
            this.transitionTime();

            if (this.options.listenX && !this.options.listenY) {
                this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none';
            } else if (this.options.listenY && !this.options.listenX) {
                this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none';
            } else {
                this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none';
            }

            if (this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll) {
                utils.addClass(this.wrapper, 'iScrollBothScrollbars');
                utils.removeClass(this.wrapper, 'iScrollLoneScrollbar');

                if (this.options.defaultScrollbars && this.options.customStyle) {
                    if (this.options.listenX) {
                        this.wrapper.style.right = '8px';
                    } else {
                        this.wrapper.style.bottom = '8px';
                    }
                }
            } else {
                utils.removeClass(this.wrapper, 'iScrollBothScrollbars');
                utils.addClass(this.wrapper, 'iScrollLoneScrollbar');

                if (this.options.defaultScrollbars && this.options.customStyle) {
                    if (this.options.listenX) {
                        this.wrapper.style.right = '2px';
                    } else {
                        this.wrapper.style.bottom = '2px';
                    }
                }
            }

            var r = this.wrapper.offsetHeight;	// force refresh

            if (this.options.listenX) {
                this.wrapperWidth = this.wrapper.clientWidth;
                if (this.options.resize) {
                    this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8);
                    this.indicatorStyle.width = this.indicatorWidth + 'px';
                } else {
                    this.indicatorWidth = this.indicator.clientWidth;
                }

                this.maxPosX = this.wrapperWidth - this.indicatorWidth;

                if (this.options.shrink == 'clip') {
                    this.minBoundaryX = -this.indicatorWidth + 8;
                    this.maxBoundaryX = this.wrapperWidth - 8;
                } else {
                    this.minBoundaryX = 0;
                    this.maxBoundaryX = this.maxPosX;
                }

                this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX));
            }

            if (this.options.listenY) {
                this.wrapperHeight = this.wrapper.clientHeight;
                if (this.options.resize) {
                    this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8);
                    this.indicatorStyle.height = this.indicatorHeight + 'px';
                } else {
                    this.indicatorHeight = this.indicator.clientHeight;
                }

                this.maxPosY = this.wrapperHeight - this.indicatorHeight;

                if (this.options.shrink == 'clip') {
                    this.minBoundaryY = -this.indicatorHeight + 8;
                    this.maxBoundaryY = this.wrapperHeight - 8;
                } else {
                    this.minBoundaryY = 0;
                    this.maxBoundaryY = this.maxPosY;
                }

                this.maxPosY = this.wrapperHeight - this.indicatorHeight;
                this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY));
            }

            this.updatePosition();
        },

        updatePosition: function () {
            var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0,
                y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0;

            if (!this.options.ignoreBoundaries) {
                if (x < this.minBoundaryX) {
                    if (this.options.shrink == 'scale') {
                        this.width = Math.max(this.indicatorWidth + x, 8);
                        this.indicatorStyle.width = this.width + 'px';
                    }
                    x = this.minBoundaryX;
                } else if (x > this.maxBoundaryX) {
                    if (this.options.shrink == 'scale') {
                        this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8);
                        this.indicatorStyle.width = this.width + 'px';
                        x = this.maxPosX + this.indicatorWidth - this.width;
                    } else {
                        x = this.maxBoundaryX;
                    }
                } else if (this.options.shrink == 'scale' && this.width != this.indicatorWidth) {
                    this.width = this.indicatorWidth;
                    this.indicatorStyle.width = this.width + 'px';
                }

                if (y < this.minBoundaryY) {
                    if (this.options.shrink == 'scale') {
                        this.height = Math.max(this.indicatorHeight + y * 3, 8);
                        this.indicatorStyle.height = this.height + 'px';
                    }
                    y = this.minBoundaryY;
                } else if (y > this.maxBoundaryY) {
                    if (this.options.shrink == 'scale') {
                        this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8);
                        this.indicatorStyle.height = this.height + 'px';
                        y = this.maxPosY + this.indicatorHeight - this.height;
                    } else {
                        y = this.maxBoundaryY;
                    }
                } else if (this.options.shrink == 'scale' && this.height != this.indicatorHeight) {
                    this.height = this.indicatorHeight;
                    this.indicatorStyle.height = this.height + 'px';
                }
            }

            this.x = x;
            this.y = y;

            if (this.scroller.options.useTransform) {
                this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ;
            } else {
                this.indicatorStyle.left = x + 'px';
                this.indicatorStyle.top = y + 'px';
            }
        },

        _pos: function (x, y) {
            if (x < 0) {
                x = 0;
            } else if (x > this.maxPosX) {
                x = this.maxPosX;
            }

            if (y < 0) {
                y = 0;
            } else if (y > this.maxPosY) {
                y = this.maxPosY;
            }

            x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x;
            y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y;

            this.scroller.scrollTo(x, y);
        },

        fade: function (val, hold) {
            if (hold && !this.visible) {
                return;
            }

            clearTimeout(this.fadeTimeout);
            this.fadeTimeout = null;

            var time = val ? 250 : 500,
                delay = val ? 0 : 300;

            val = val ? '1' : '0';

            this.wrapperStyle[utils.style.transitionDuration] = time + 'ms';

            this.fadeTimeout = setTimeout((function (val) {
                this.wrapperStyle.opacity = val;
                this.visible = +val;
            }).bind(this, val), delay);
        }
    };

    IScroll.utils = utils;

    if (typeof module != 'undefined' && module.exports) {
        module.exports = IScroll;
    } else if (typeof define == 'function' && define.amd) {
        define(function () { return IScroll; });
    } else {
        window.IScroll = IScroll;
    }

})(window, document, Math);
;
/* globals jQuery */

(function ($) {
  // Selector to select only not already processed elements
  $.expr[":"].notmdproc = function (obj) {
    if ($(obj).data("mdproc")) {
      return false;
    } else {
      return true;
    }
  };

  function _isChar(evt) {
    if (typeof evt.which == "undefined") {
      return true;
    } else if (typeof evt.which == "number" && evt.which > 0) {
      return (
        !evt.ctrlKey
        && !evt.metaKey
        && !evt.altKey
        && evt.which != 8  // backspace
        && evt.which != 9  // tab
        && evt.which != 13 // enter
        && evt.which != 16 // shift
        && evt.which != 17 // ctrl
        && evt.which != 20 // caps lock
        && evt.which != 27 // escape
      );
    }
    return false;
  }

  function _addFormGroupFocus(element) {
    var $element = $(element);
    if (!$element.prop('disabled')) {  // this is showing as undefined on chrome but works fine on firefox??
      $element.closest(".form-group").addClass("is-focused");
    }
  }

  function _toggleDisabledState($element, state) {
    var $target;
    if ($element.hasClass('checkbox-inline') || $element.hasClass('radio-inline')) {
      $target = $element;
    } else {
      $target = $element.closest('.checkbox').length ? $element.closest('.checkbox') : $element.closest('.radio');
    }
    return $target.toggleClass('disabled', state);
  }

  function _toggleTypeFocus($input) {
    var disabledToggleType = false;
    if ($input.is($.material.options.checkboxElements) || $input.is($.material.options.radioElements)) {
      disabledToggleType = true;
    }
    $input.closest('label').hover(function () {
        var $i = $(this).find('input');
        var isDisabled = $i.prop('disabled'); // hack because the _addFormGroupFocus() wasn't identifying the property on chrome
        if (disabledToggleType) {
          _toggleDisabledState($(this), isDisabled);
        }
        if (!isDisabled) {
          _addFormGroupFocus($i);     // need to find the input so we can check disablement
        }
      },
      function () {
        _removeFormGroupFocus($(this).find('input'));
      });
  }

  function _removeFormGroupFocus(element) {
    $(element).closest(".form-group").removeClass("is-focused"); // remove class from form-group
  }

  $.material = {
    "options": {
      // These options set what will be started by $.material.init()
      "validate": true,
      "input": true,
      "ripples": true,
      "checkbox": true,
      "togglebutton": true,
      "radio": true,
      "arrive": true,
      "autofill": false,

      "withRipples": [
        ".btn:not(.btn-link)",
        ".card-image",
        ".navbar a:not(.withoutripple)",
        ".dropdown-menu a",
        ".nav-tabs a:not(.withoutripple)",
        ".withripple",
        ".pagination li:not(.active):not(.disabled) a:not(.withoutripple)"
      ].join(","),
      "inputElements": "input.form-control, textarea.form-control, select.form-control",
      "checkboxElements": ".checkbox > label > input[type=checkbox], label.checkbox-inline > input[type=checkbox]",
      "togglebuttonElements": ".togglebutton > label > input[type=checkbox]",
      "radioElements": ".radio > label > input[type=radio], label.radio-inline > input[type=radio]"
    },
    "checkbox": function (selector) {
      // Add fake-checkbox to material checkboxes
      var $input = $((selector) ? selector : this.options.checkboxElements)
        .filter(":notmdproc")
        .data("mdproc", true)
        .after("<span class='checkbox-material'><span class='check'></span></span>");

      _toggleTypeFocus($input);
    },
    "togglebutton": function (selector) {
      // Add fake-checkbox to material checkboxes
      var $input = $((selector) ? selector : this.options.togglebuttonElements)
        .filter(":notmdproc")
        .data("mdproc", true)
        .after("<span class='toggle'></span>");

      _toggleTypeFocus($input);
    },
    "radio": function (selector) {
      // Add fake-radio to material radios
      var $input = $((selector) ? selector : this.options.radioElements)
        .filter(":notmdproc")
        .data("mdproc", true)
        .after("<span class='circle'></span><span class='check'></span>");

      _toggleTypeFocus($input);
    },
    "input": function (selector) {
      $((selector) ? selector : this.options.inputElements)
        .filter(":notmdproc")
        .data("mdproc", true)
        .each(function () {
          var $input = $(this);

          // Requires form-group standard markup (will add it if necessary)
          var $formGroup = $input.closest(".form-group"); // note that form-group may be grandparent in the case of an input-group
          if ($formGroup.length === 0 && $input.attr('type') !== "hidden" && !$input.attr('hidden')) {
            $input.wrap("<div class='form-group'></div>");
            $formGroup = $input.closest(".form-group"); // find node after attached (otherwise additional attachments don't work)
          }

          // Legacy - Add hint label if using the old shorthand data-hint attribute on the input
          if ($input.attr("data-hint")) {
            $input.after("<p class='help-block'>" + $input.attr("data-hint") + "</p>");
            $input.removeAttr("data-hint");
          }

          // Legacy - Change input-sm/lg to form-group-sm/lg instead (preferred standard and simpler css/less variants)
          var legacySizes = {
            "input-lg": "form-group-lg",
            "input-sm": "form-group-sm"
          };
          $.each(legacySizes, function (legacySize, standardSize) {
            if ($input.hasClass(legacySize)) {
              $input.removeClass(legacySize);
              $formGroup.addClass(standardSize);
            }
          });

          // Legacy - Add label-floating if using old shorthand <input class="floating-label" placeholder="foo">
          if ($input.hasClass("floating-label")) {
            var placeholder = $input.attr("placeholder");
            $input.attr("placeholder", null).removeClass("floating-label");
            var id = $input.attr("id");
            var forAttribute = "";
            if (id) {
              forAttribute = "for='" + id + "'";
            }
            $formGroup.addClass("label-floating");
            $input.after("<label " + forAttribute + "class='control-label'>" + placeholder + "</label>");
          }

          // Set as empty if is empty (damn I must improve this...)
          if ($input.val() === null || $input.val() == "undefined" || $input.val() === "") {
            $formGroup.addClass("is-empty");
          }

          // Support for file input
          if ($formGroup.find("input[type=file]").length > 0) {
            $formGroup.addClass("is-fileinput");
          }
        });
    },
    "attachInputEventHandlers": function () {
      var validate = this.options.validate;

      $(document)
        .on("keydown paste", ".form-control", function (e) {
          if (_isChar(e)) {
            $(this).closest(".form-group").removeClass("is-empty");
          }
        })
        .on("keyup change", ".form-control", function () {
          var $input = $(this);
          var $formGroup = $input.closest(".form-group");
          var isValid = (typeof $input[0].checkValidity === "undefined" || $input[0].checkValidity());

          if ($input.val() === "") {
            $formGroup.addClass("is-empty");
          }
          else {
            $formGroup.removeClass("is-empty");
          }

          // Validation events do not bubble, so they must be attached directly to the input: http://jsfiddle.net/PEpRM/1/
          //  Further, even the bind method is being caught, but since we are already calling #checkValidity here, just alter
          //  the form-group on change.
          //
          // NOTE: I'm not sure we should be intervening regarding validation, this seems better as a README and snippet of code.
          //        BUT, I've left it here for backwards compatibility.
          if (validate) {
            if (isValid) {
              $formGroup.removeClass("has-error");
            }
            else {
              $formGroup.addClass("has-error");
            }
          }
        })
        .on("focus", ".form-control, .form-group.is-fileinput", function () {
          _addFormGroupFocus(this);
        })
        .on("blur", ".form-control, .form-group.is-fileinput", function () {
          _removeFormGroupFocus(this);
        })
        // make sure empty is added back when there is a programmatic value change.
        //  NOTE: programmatic changing of value using $.val() must trigger the change event i.e. $.val('x').trigger('change')
        .on("change", ".form-group input", function () {
          var $input = $(this);
          if ($input.attr("type") == "file") {
            return;
          }

          var $formGroup = $input.closest(".form-group");
          var value = $input.val();
          if (value) {
            $formGroup.removeClass("is-empty");
          } else {
            $formGroup.addClass("is-empty");
          }
        })
        // set the fileinput readonly field with the name of the file
        .on("change", ".form-group.is-fileinput input[type='file']", function () {
          var $input = $(this);
          var $formGroup = $input.closest(".form-group");
          var value = "";
          $.each(this.files, function (i, file) {
            value += file.name + ", ";
          });
          value = value.substring(0, value.length - 2);
          if (value) {
            $formGroup.removeClass("is-empty");
          } else {
            $formGroup.addClass("is-empty");
          }
          $formGroup.find("input.form-control[readonly]").val(value);
        });
    },
    "ripples": function (selector) {
      $((selector) ? selector : this.options.withRipples).ripples();
    },
    "autofill": function () {
      // This part of code will detect autofill when the page is loading (username and password inputs for example)
      var loading = setInterval(function () {
        $("input[type!=checkbox]").each(function () {
          var $this = $(this);
          if ($this.val() && $this.val() !== $this.attr("value")) {
            $this.trigger("change");
          }
        });
      }, 100);

      // After 10 seconds we are quite sure all the needed inputs are autofilled then we can stop checking them
      setTimeout(function () {
        clearInterval(loading);
      }, 10000);
    },
    "attachAutofillEventHandlers": function () {
      // Listen on inputs of the focused form (because user can select from the autofill dropdown only when the input has focus)
      var focused;
      $(document)
        .on("focus", "input", function () {
          var $inputs = $(this).parents("form").find("input").not("[type=file]");
          focused = setInterval(function () {
            $inputs.each(function () {
              var $this = $(this);
              if ($this.val() !== $this.attr("value")) {
                $this.trigger("change");
              }
            });
          }, 100);
        })
        .on("blur", ".form-group input", function () {
          clearInterval(focused);
        });
    },
    "init": function (options) {
      this.options = $.extend({}, this.options, options);
      var $document = $(document);

      if ($.fn.ripples && this.options.ripples) {
        this.ripples();
      }
      if (this.options.input) {
        this.input();
        this.attachInputEventHandlers();
      }
      if (this.options.checkbox) {
        this.checkbox();
      }
      if (this.options.togglebutton) {
        this.togglebutton();
      }
      if (this.options.radio) {
        this.radio();
      }
      if (this.options.autofill) {
        this.autofill();
        this.attachAutofillEventHandlers();
      }

      if (document.arrive && this.options.arrive) {
        if ($.fn.ripples && this.options.ripples) {
          $document.arrive(this.options.withRipples, function () {
            $.material.ripples($(this));
          });
        }
        if (this.options.input) {
          $document.arrive(this.options.inputElements, function () {
            $.material.input($(this));
          });
        }
        if (this.options.checkbox) {
          $document.arrive(this.options.checkboxElements, function () {
            $.material.checkbox($(this));
          });
        }
        if (this.options.radio) {
          $document.arrive(this.options.radioElements, function () {
            $.material.radio($(this));
          });
        }
        if (this.options.togglebutton) {
          $document.arrive(this.options.togglebuttonElements, function () {
            $.material.togglebutton($(this));
          });
        }

      }
    }
  };

})(jQuery);
;
/* Copyright 2014+, Federico Zivolo, LICENSE at https://github.com/FezVrasta/bootstrap-material-design/blob/master/LICENSE.md */
/* globals jQuery, navigator */

(function($, window, document, undefined) {

  "use strict";

  /**
   * Define the name of the plugin
   */
  var ripples = "ripples";


  /**
   * Get an instance of the plugin
   */
  var self = null;


  /**
   * Define the defaults of the plugin
   */
  var defaults = {};


  /**
   * Create the main plugin function
   */
  function Ripples(element, options) {
    self = this;

    this.element = $(element);

    this.options = $.extend({}, defaults, options);

    this._defaults = defaults;
    this._name = ripples;

    this.init();
  }


  /**
   * Initialize the plugin
   */
  Ripples.prototype.init = function() {
    var $element  = this.element;

    $element.on("mousedown touchstart", function(event) {
      /**
       * Verify if the user is just touching on a device and return if so
       */
      if(self.isTouch() && event.type === "mousedown") {
        return;
      }


      /**
       * Verify if the current element already has a ripple wrapper element and
       * creates if it doesn't
       */
      if(!($element.find(".ripple-container").length)) {
        $element.append("<div class=\"ripple-container\"></div>");
      }


      /**
       * Find the ripple wrapper
       */
      var $wrapper = $element.children(".ripple-container");


      /**
       * Get relY and relX positions
       */
      var relY = self.getRelY($wrapper, event);
      var relX = self.getRelX($wrapper, event);


      /**
       * If relY and/or relX are false, return the event
       */
      if(!relY && !relX) {
        return;
      }


      /**
       * Get the ripple color
       */
      var rippleColor = self.getRipplesColor($element);


      /**
       * Create the ripple element
       */
      var $ripple = $("<div></div>");

      $ripple
      .addClass("ripple")
      .css({
        "left": relX,
        "top": relY,
        "background-color": rippleColor
      });


      /**
       * Append the ripple to the wrapper
       */
      $wrapper.append($ripple);


      /**
       * Make sure the ripple has the styles applied (ugly hack but it works)
       */
      (function() { return window.getComputedStyle($ripple[0]).opacity; })();


      /**
       * Turn on the ripple animation
       */
      self.rippleOn($element, $ripple);


      /**
       * Call the rippleEnd function when the transition "on" ends
       */
      setTimeout(function() {
        self.rippleEnd($ripple);
      }, 500);


      /**
       * Detect when the user leaves the element
       */
      $element.on("mouseup mouseleave touchend", function() {
        $ripple.data("mousedown", "off");

        if($ripple.data("animating") === "off") {
          self.rippleOut($ripple);
        }
      });

    });
  };


  /**
   * Get the new size based on the element height/width and the ripple width
   */
  Ripples.prototype.getNewSize = function($element, $ripple) {

    return (Math.max($element.outerWidth(), $element.outerHeight()) / $ripple.outerWidth()) * 2.5;
  };


  /**
   * Get the relX
   */
  Ripples.prototype.getRelX = function($wrapper,  event) {
    var wrapperOffset = $wrapper.offset();

    if(!self.isTouch()) {
      /**
       * Get the mouse position relative to the ripple wrapper
       */
      return event.pageX - wrapperOffset.left;
    } else {
      /**
       * Make sure the user is using only one finger and then get the touch
       * position relative to the ripple wrapper
       */
      event = event.originalEvent;

      if(event.touches.length === 1) {
        return event.touches[0].pageX - wrapperOffset.left;
      }

      return false;
    }
  };


  /**
   * Get the relY
   */
  Ripples.prototype.getRelY = function($wrapper, event) {
    var wrapperOffset = $wrapper.offset();

    if(!self.isTouch()) {
      /**
       * Get the mouse position relative to the ripple wrapper
       */
      return event.pageY - wrapperOffset.top;
    } else {
      /**
       * Make sure the user is using only one finger and then get the touch
       * position relative to the ripple wrapper
       */
      event = event.originalEvent;

      if(event.touches.length === 1) {
        return event.touches[0].pageY - wrapperOffset.top;
      }

      return false;
    }
  };


  /**
   * Get the ripple color
   */
  Ripples.prototype.getRipplesColor = function($element) {

    var color = $element.data("ripple-color") ? $element.data("ripple-color") : window.getComputedStyle($element[0]).color;

    return color;
  };


  /**
   * Verify if the client browser has transistion support
   */
  Ripples.prototype.hasTransitionSupport = function() {
    var thisBody  = document.body || document.documentElement;
    var thisStyle = thisBody.style;

    var support = (
      thisStyle.transition !== undefined ||
      thisStyle.WebkitTransition !== undefined ||
      thisStyle.MozTransition !== undefined ||
      thisStyle.MsTransition !== undefined ||
      thisStyle.OTransition !== undefined
    );

    return support;
  };


  /**
   * Verify if the client is using a mobile device
   */
  Ripples.prototype.isTouch = function() {
    return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
  };


  /**
   * End the animation of the ripple
   */
  Ripples.prototype.rippleEnd = function($ripple) {
    $ripple.data("animating", "off");

    if($ripple.data("mousedown") === "off") {
      self.rippleOut($ripple);
    }
  };


  /**
   * Turn off the ripple effect
   */
  Ripples.prototype.rippleOut = function($ripple) {
    $ripple.off();

    if(self.hasTransitionSupport()) {
      $ripple.addClass("ripple-out");
    } else {
      $ripple.animate({"opacity": 0}, 100, function() {
        $ripple.trigger("transitionend");
      });
    }

    $ripple.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function() {
      $ripple.remove();
    });
  };


  /**
   * Turn on the ripple effect
   */
  Ripples.prototype.rippleOn = function($element, $ripple) {
    var size = self.getNewSize($element, $ripple);

    if(self.hasTransitionSupport()) {
      $ripple
      .css({
        "-ms-transform": "scale(" + size + ")",
        "-moz-transform": "scale(" + size + ")",
        "-webkit-transform": "scale(" + size + ")",
        "transform": "scale(" + size + ")"
      })
      .addClass("ripple-on")
      .data("animating", "on")
      .data("mousedown", "on");
    } else {
      $ripple.animate({
        "width": Math.max($element.outerWidth(), $element.outerHeight()) * 2,
        "height": Math.max($element.outerWidth(), $element.outerHeight()) * 2,
        "margin-left": Math.max($element.outerWidth(), $element.outerHeight()) * (-1),
        "margin-top": Math.max($element.outerWidth(), $element.outerHeight()) * (-1),
        "opacity": 0.2
      }, 500, function() {
        $ripple.trigger("transitionend");
      });
    }
  };


  /**
   * Create the jquery plugin function
   */
  $.fn.ripples = function(options) {
    return this.each(function() {
      if(!$.data(this, "plugin_" + ripples)) {
        $.data(this, "plugin_" + ripples, new Ripples(this, options));
      }
    });
  };

})(jQuery, window, document);
;
/* globals jQuery, window, document */

(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node/CommonJS
        module.exports = factory(require('jquery'));
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function($) {

  var methods = {
    options : {
      "optionClass": "",
      "dropdownClass": "",
      "autoinit": false,
      "callback": false,
      "onSelected": false,
      "dynamicOptLabel": "Add a new option..."
    },
    init: function(options) {
      // Apply user options if user has defined some
      if (options) {
        options = $.extend(methods.options, options);
      } else {
        options = methods.options;
      }

      function initElement($select) {
        // Don't do anything if this is not a select or if this select was already initialized
          if ($select.data("dropdownjs") || !$select.is("select")) {
              var _ul = $select.parent().find("ul:first");
              var _input = $select.parent().find("input.fakeinput:first");
              if (_ul.length) {
                  _ul.html('');
                  // Loop trough options and transfer them to the dropdown menu
                  $select.find("option").each(function () {
                      if ($(this).is(":selected")) {
                          _input.val($(this).text().trim());
                      }
                      // Cache $(this)
                      var $this = $(this);
                      methods._addOption(_ul, $this);

                  });
              }
              return;
        }

        // Is it a multi select?
        var multi = $select.attr("multiple");

        // Does it allow to create new options dynamically?
        var dynamicOptions = $select.attr("data-dynamic-opts"),
            $dynamicInput = $();

        // Create the dropdown wrapper
        var $dropdown = $("<div></div>");
        $dropdown.addClass("dropdownjs").addClass(options.dropdownClass);
        $dropdown.data("select", $select);

        // Create the fake input used as "select" element and cache it as $input
        var $input = $("<input type=text readonly class=fakeinput>");
        if ($.material) { $input.data("mdproc", true); }
        // Append it to the dropdown wrapper
        $dropdown.append($input);

        // Create the UL that will be used as dropdown and cache it AS $ul
        var $ul = $("<ul></ul>");
        $ul.data("select", $select);

        // Append it to the dropdown
        $dropdown.append($ul);

        // Transfer the placeholder attribute
        $input.attr("placeholder", $select.attr("placeholder"));

        // Loop trough options and transfer them to the dropdown menu
        $select.find("option").each(function() {
          // Cache $(this)
          var $this = $(this);
          methods._addOption($ul, $this);

        });

        // If this select allows dynamic options add the widget
        if (dynamicOptions) {
          $dynamicInput = $("<li class=dropdownjs-add></li>");
          $dynamicInput.append("<input>");
          $dynamicInput.find("input").attr("placeholder", options.dynamicOptLabel);
          $ul.append($dynamicInput);
        }
        // Cache the dropdown options
        var selectOptions = $dropdown.find("li");

        // If is a single select, selected the first one or the last with selected attribute
        if (!multi) {
            var $selected;
            if ($select.find(":selected").length) {
                $selected = $select.find(":selected").last();
            } else {
                $selected = $select.find("option, li").first();
            }

            methods._select($dropdown, $selected);
        } else {
            var selectors = [], val = $select.val()
            for (var i in val) {
              selectors.push('li[value=' + val[i] + ']')
            }
            if (selectors.length > 0) {
              methods._select($dropdown, $dropdown.find(selectors.join(',')));
            }
        }

        // Transfer the classes of the select to the input dropdown
        $input.addClass($select[0].className);

        // Hide the old and ugly select
        $select.hide().attr("data-dropdownjs", true);

        // Bring to life our awesome dropdownjs
        $select.after($dropdown);

        // Call the callback
        if (options.callback) {
          options.callback($dropdown);
        }

        //---------------------------------------//
        // DROPDOWN EVENTS                       //
        //---------------------------------------//

        // On click, set the clicked one as selected
        $ul.on("click", "li:not(.dropdownjs-add)", function(e) {
          methods._select($dropdown, $(this));
        });
        $ul.on("keydown", "li:not(.dropdownjs-add)", function(e) {
          if (e.which === 27) {
            $(".dropdownjs > ul > li").attr("tabindex", -1);
            return $input.removeClass("focus").blur();
          }
          if (e.which === 32 && !$(e.target).is("input")) {
            methods._select($dropdown, $(this));
            return false;
          }
        });
        $ul.on("focus", "li:not(.dropdownjs-add)", function() {
          if ($select.is(":disabled")) {
            return;
          }
          $input.addClass("focus");
        });

        // Add new options when the widget is used
        if (dynamicOptions && dynamicOptions.length) {
          $dynamicInput.on("keydown", function(e) {
            if(e.which !== 13) return;
            var $option = $("<option>"),
                val = $dynamicInput.find("input").val();
            $dynamicInput.find("input").val("");

            $option.attr("value", val);
            $option.text(val);
            $select.append($option);

          });
        }

        // Listen for new added options and update dropdown if needed
        $select.on("DOMNodeInserted", function(e) {
          var $this = $(e.target);
          if (!$this.val().length) return;

          methods._addOption($ul, $this);
          $ul.find("li").not(".dropdownjs-add").attr("tabindex", 0);

        });

        // Update dropdown when using val, need to use .val("value").trigger("change");
        $select.on("change", function(e) {
          var $this = $(e.target);
          if (!$this.val().length) return;

          if (!multi) {
            var $selected;
            if ($select.find(":selected").length) {
              $selected = $select.find(":selected").last();
            } else {
              $selected = $select.find("option, li").first();
            }
            methods._select($dropdown, $selected);
          } else {
            methods._select($dropdown, $select.find(":selected"));
          }
        });

        // Used to make the dropdown menu more dropdown-ish
        $input.on("click focus", function(e) {
          e.stopPropagation();
          if ($select.is(":disabled")) {
            return;
          }
          $(".dropdownjs > ul > li").attr("tabindex", -1);
          $(".dropdownjs > input").not($(this)).removeClass("focus").blur();

          $(".dropdownjs > ul > li").not(".dropdownjs-add").attr("tabindex", 0);

          // Set height of the dropdown
          var coords = {
            top: $(this).offset().top - $(document).scrollTop(),
            left: $(this).offset().left - $(document).scrollLeft(),
            bottom: $(window).height() - ($(this).offset().top - $(document).scrollTop()),
            right: $(window).width() - ($(this).offset().left - $(document).scrollLeft())
          };

          var height = coords.bottom;

          // Decide if place the dropdown below or above the input
          if (height < 200 && coords.top > coords.bottom) {
            height = coords.top;
            $ul.attr("placement", "top-left");
          } else {
            $ul.attr("placement", "bottom-left");
          }

          $(this).next("ul").css("max-height", height - 20);
          $(this).addClass("focus");
        });
        // Close every dropdown on click outside
        $(document).on("click", function(e) {

          // Don't close the multi dropdown if user is clicking inside it
          if (multi && $(e.target).parents(".dropdownjs").length) return;

          // Don't close the dropdown if user is clicking inside the dynamic-opts widget
          if ($(e.target).parents(".dropdownjs-add").length || $(e.target).is(".dropdownjs-add")) return;

          // Close opened dropdowns
          $(".dropdownjs > ul > li").attr("tabindex", -1);
          $input.removeClass("focus");
        });
      }

      if (options.autoinit) {
        $(document).on("DOMNodeInserted", function(e) {
          var $this = $(e.target);
          if (!$this.is("select")) {
            $this = $this.find('select');
          }
          if ($this.is(options.autoinit)) {
            $this.each(function() {
              initElement($(this));
            });
          }
        });
      }

      // Loop trough elements
      $(this).each(function() {
        initElement($(this));
      });
    },
    select: function(target) {
      var $target = $(this).find("[value=\"" + target + "\"]");
      methods._select($(this), $target);
    },
    _select: function($dropdown, $target) {
      if ($target.is(".dropdownjs-add")) return;

      // Get dropdown's elements
      var $select = $dropdown.data("select"),
          $input  = $dropdown.find("input.fakeinput");
      // Is it a multi select?
      var multi = $select.attr("multiple");

      // Cache the dropdown options
      var selectOptions = $dropdown.find("li");

      // Behavior for multiple select
      if (multi) {
        // Toggle option state
        $target.toggleClass("selected");
        // Toggle selection of the clicked option in native select
        $target.each(function() {
          var $selected = $select.find("[value=\"" + $(this).attr("value") + "\"]");
          $selected.prop("selected", $(this).hasClass("selected"));
        });
        // Add or remove the value from the input
        var text = [];
        selectOptions.each(function() {
          if ($(this).hasClass("selected")) {
            text.push($(this).text());
          }
        });
        $input.val(text.join(", "));
      }

      // Behavior for single select
      if (!multi) {
        // Unselect options except the one that will be selected
        if ($target.is("li")) {
          selectOptions.not($target).removeClass("selected");
        }
        // Select the selected option
        $target.addClass("selected");
        // Set the value to the native select
        $select.val($target.attr("value"));
        // Set the value to the input
        $input.val($target.text().trim());
      }

      // This is used only if Material Design for Bootstrap is selected
      if ($.material) {
        if ($input.val().trim()) {
          $select.removeClass("empty");
        } else {
          $select.addClass("empty");
        }
      }

      // Call the callback
      if (this.options.onSelected) {
          this.options.onSelected($dropdown,$target.attr("value"));
      }
    },
    _addOption: function($ul, $this) {
      // Create the option
      var $option = $("<li></li>");

      // Style the option
      $option.addClass(this.options.optionClass);

      // If the option has some text then transfer it
      if ($this.text()) {
        $option.text($this.text());
      }
      // Otherwise set the empty label and set it as an empty option
      else {
        $option.html("&nbsp;");
      }
      // Set the value of the option
      $option.attr("value", $this.val());

      // Will user be able to remove this option?
      if ($ul.data("select").attr("data-dynamic-opts")) {
        $option.append("<span class=close></span>");
        $option.find(".close").on("click", function() {
          $option.remove();
          $this.remove();
        });
      }

      // Ss it selected?
      if ($this.prop("selected")) {
        $option.attr("selected", true);
        $option.addClass("selected");
      }

      // Append option to our dropdown
      if ($ul.find(".dropdownjs-add").length) {
        $ul.find(".dropdownjs-add").before($option);
      } else {
        $ul.append($option);
      }
    }
  };

  $.fn.dropdown = function (params) {
    if (methods[params]) {
      return methods[params].apply(this, Array.prototype.slice.call(arguments,1));
    } 
    else if (typeof params === "object" | !params) {
      return methods.init.apply(this, arguments);
    } else {
      $.error("Method " + params + " does not exists on jQuery.dropdown");
    }
  };

}));
;
/*!
 * VERSION: 1.19.0
 * DATE: 2016-07-14
 * UPDATES AND DOCS AT: http://greensock.com
 * 
 * Includes all of the following: TweenLite, TweenMax, TimelineLite, TimelineMax, EasePack, CSSPlugin, RoundPropsPlugin, BezierPlugin, AttrPlugin, DirectionalRotationPlugin
 *
 * @license Copyright (c) 2008-2016, GreenSock. All rights reserved.
 * This work is subject to the terms at http://greensock.com/standard-license or for
 * Club GreenSock members, the software agreement that was issued with your membership.
 * 
 * @author: Jack Doyle, jack@greensock.com
 **/
var _gsScope="undefined"!=typeof module&&module.exports&&"undefined"!=typeof global?global:this||window;(_gsScope._gsQueue||(_gsScope._gsQueue=[])).push(function(){"use strict";_gsScope._gsDefine("TweenMax",["core.Animation","core.SimpleTimeline","TweenLite"],function(a,b,c){var d=function(a){var b,c=[],d=a.length;for(b=0;b!==d;c.push(a[b++]));return c},e=function(a,b,c){var d,e,f=a.cycle;for(d in f)e=f[d],a[d]="function"==typeof e?e(c,b[c]):e[c%e.length];delete a.cycle},f=function(a,b,d){c.call(this,a,b,d),this._cycle=0,this._yoyo=this.vars.yoyo===!0,this._repeat=this.vars.repeat||0,this._repeatDelay=this.vars.repeatDelay||0,this._dirty=!0,this.render=f.prototype.render},g=1e-10,h=c._internals,i=h.isSelector,j=h.isArray,k=f.prototype=c.to({},.1,{}),l=[];f.version="1.19.0",k.constructor=f,k.kill()._gc=!1,f.killTweensOf=f.killDelayedCallsTo=c.killTweensOf,f.getTweensOf=c.getTweensOf,f.lagSmoothing=c.lagSmoothing,f.ticker=c.ticker,f.render=c.render,k.invalidate=function(){return this._yoyo=this.vars.yoyo===!0,this._repeat=this.vars.repeat||0,this._repeatDelay=this.vars.repeatDelay||0,this._uncache(!0),c.prototype.invalidate.call(this)},k.updateTo=function(a,b){var d,e=this.ratio,f=this.vars.immediateRender||a.immediateRender;b&&this._startTime<this._timeline._time&&(this._startTime=this._timeline._time,this._uncache(!1),this._gc?this._enabled(!0,!1):this._timeline.insert(this,this._startTime-this._delay));for(d in a)this.vars[d]=a[d];if(this._initted||f)if(b)this._initted=!1,f&&this.render(0,!0,!0);else if(this._gc&&this._enabled(!0,!1),this._notifyPluginsOfEnabled&&this._firstPT&&c._onPluginEvent("_onDisable",this),this._time/this._duration>.998){var g=this._totalTime;this.render(0,!0,!1),this._initted=!1,this.render(g,!0,!1)}else if(this._initted=!1,this._init(),this._time>0||f)for(var h,i=1/(1-e),j=this._firstPT;j;)h=j.s+j.c,j.c*=i,j.s=h-j.c,j=j._next;return this},k.render=function(a,b,c){this._initted||0===this._duration&&this.vars.repeat&&this.invalidate();var d,e,f,i,j,k,l,m,n=this._dirty?this.totalDuration():this._totalDuration,o=this._time,p=this._totalTime,q=this._cycle,r=this._duration,s=this._rawPrevTime;if(a>=n-1e-7?(this._totalTime=n,this._cycle=this._repeat,this._yoyo&&0!==(1&this._cycle)?(this._time=0,this.ratio=this._ease._calcEnd?this._ease.getRatio(0):0):(this._time=r,this.ratio=this._ease._calcEnd?this._ease.getRatio(1):1),this._reversed||(d=!0,e="onComplete",c=c||this._timeline.autoRemoveChildren),0===r&&(this._initted||!this.vars.lazy||c)&&(this._startTime===this._timeline._duration&&(a=0),(0>s||0>=a&&a>=-1e-7||s===g&&"isPause"!==this.data)&&s!==a&&(c=!0,s>g&&(e="onReverseComplete")),this._rawPrevTime=m=!b||a||s===a?a:g)):1e-7>a?(this._totalTime=this._time=this._cycle=0,this.ratio=this._ease._calcEnd?this._ease.getRatio(0):0,(0!==p||0===r&&s>0)&&(e="onReverseComplete",d=this._reversed),0>a&&(this._active=!1,0===r&&(this._initted||!this.vars.lazy||c)&&(s>=0&&(c=!0),this._rawPrevTime=m=!b||a||s===a?a:g)),this._initted||(c=!0)):(this._totalTime=this._time=a,0!==this._repeat&&(i=r+this._repeatDelay,this._cycle=this._totalTime/i>>0,0!==this._cycle&&this._cycle===this._totalTime/i&&a>=p&&this._cycle--,this._time=this._totalTime-this._cycle*i,this._yoyo&&0!==(1&this._cycle)&&(this._time=r-this._time),this._time>r?this._time=r:this._time<0&&(this._time=0)),this._easeType?(j=this._time/r,k=this._easeType,l=this._easePower,(1===k||3===k&&j>=.5)&&(j=1-j),3===k&&(j*=2),1===l?j*=j:2===l?j*=j*j:3===l?j*=j*j*j:4===l&&(j*=j*j*j*j),1===k?this.ratio=1-j:2===k?this.ratio=j:this._time/r<.5?this.ratio=j/2:this.ratio=1-j/2):this.ratio=this._ease.getRatio(this._time/r)),o===this._time&&!c&&q===this._cycle)return void(p!==this._totalTime&&this._onUpdate&&(b||this._callback("onUpdate")));if(!this._initted){if(this._init(),!this._initted||this._gc)return;if(!c&&this._firstPT&&(this.vars.lazy!==!1&&this._duration||this.vars.lazy&&!this._duration))return this._time=o,this._totalTime=p,this._rawPrevTime=s,this._cycle=q,h.lazyTweens.push(this),void(this._lazy=[a,b]);this._time&&!d?this.ratio=this._ease.getRatio(this._time/r):d&&this._ease._calcEnd&&(this.ratio=this._ease.getRatio(0===this._time?0:1))}for(this._lazy!==!1&&(this._lazy=!1),this._active||!this._paused&&this._time!==o&&a>=0&&(this._active=!0),0===p&&(2===this._initted&&a>0&&this._init(),this._startAt&&(a>=0?this._startAt.render(a,b,c):e||(e="_dummyGS")),this.vars.onStart&&(0!==this._totalTime||0===r)&&(b||this._callback("onStart"))),f=this._firstPT;f;)f.f?f.t[f.p](f.c*this.ratio+f.s):f.t[f.p]=f.c*this.ratio+f.s,f=f._next;this._onUpdate&&(0>a&&this._startAt&&this._startTime&&this._startAt.render(a,b,c),b||(this._totalTime!==p||e)&&this._callback("onUpdate")),this._cycle!==q&&(b||this._gc||this.vars.onRepeat&&this._callback("onRepeat")),e&&(!this._gc||c)&&(0>a&&this._startAt&&!this._onUpdate&&this._startTime&&this._startAt.render(a,b,c),d&&(this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),!b&&this.vars[e]&&this._callback(e),0===r&&this._rawPrevTime===g&&m!==g&&(this._rawPrevTime=0))},f.to=function(a,b,c){return new f(a,b,c)},f.from=function(a,b,c){return c.runBackwards=!0,c.immediateRender=0!=c.immediateRender,new f(a,b,c)},f.fromTo=function(a,b,c,d){return d.startAt=c,d.immediateRender=0!=d.immediateRender&&0!=c.immediateRender,new f(a,b,d)},f.staggerTo=f.allTo=function(a,b,g,h,k,m,n){h=h||0;var o,p,q,r,s=0,t=[],u=function(){g.onComplete&&g.onComplete.apply(g.onCompleteScope||this,arguments),k.apply(n||g.callbackScope||this,m||l)},v=g.cycle,w=g.startAt&&g.startAt.cycle;for(j(a)||("string"==typeof a&&(a=c.selector(a)||a),i(a)&&(a=d(a))),a=a||[],0>h&&(a=d(a),a.reverse(),h*=-1),o=a.length-1,q=0;o>=q;q++){p={};for(r in g)p[r]=g[r];if(v&&(e(p,a,q),null!=p.duration&&(b=p.duration,delete p.duration)),w){w=p.startAt={};for(r in g.startAt)w[r]=g.startAt[r];e(p.startAt,a,q)}p.delay=s+(p.delay||0),q===o&&k&&(p.onComplete=u),t[q]=new f(a[q],b,p),s+=h}return t},f.staggerFrom=f.allFrom=function(a,b,c,d,e,g,h){return c.runBackwards=!0,c.immediateRender=0!=c.immediateRender,f.staggerTo(a,b,c,d,e,g,h)},f.staggerFromTo=f.allFromTo=function(a,b,c,d,e,g,h,i){return d.startAt=c,d.immediateRender=0!=d.immediateRender&&0!=c.immediateRender,f.staggerTo(a,b,d,e,g,h,i)},f.delayedCall=function(a,b,c,d,e){return new f(b,0,{delay:a,onComplete:b,onCompleteParams:c,callbackScope:d,onReverseComplete:b,onReverseCompleteParams:c,immediateRender:!1,useFrames:e,overwrite:0})},f.set=function(a,b){return new f(a,0,b)},f.isTweening=function(a){return c.getTweensOf(a,!0).length>0};var m=function(a,b){for(var d=[],e=0,f=a._first;f;)f instanceof c?d[e++]=f:(b&&(d[e++]=f),d=d.concat(m(f,b)),e=d.length),f=f._next;return d},n=f.getAllTweens=function(b){return m(a._rootTimeline,b).concat(m(a._rootFramesTimeline,b))};f.killAll=function(a,c,d,e){null==c&&(c=!0),null==d&&(d=!0);var f,g,h,i=n(0!=e),j=i.length,k=c&&d&&e;for(h=0;j>h;h++)g=i[h],(k||g instanceof b||(f=g.target===g.vars.onComplete)&&d||c&&!f)&&(a?g.totalTime(g._reversed?0:g.totalDuration()):g._enabled(!1,!1))},f.killChildTweensOf=function(a,b){if(null!=a){var e,g,k,l,m,n=h.tweenLookup;if("string"==typeof a&&(a=c.selector(a)||a),i(a)&&(a=d(a)),j(a))for(l=a.length;--l>-1;)f.killChildTweensOf(a[l],b);else{e=[];for(k in n)for(g=n[k].target.parentNode;g;)g===a&&(e=e.concat(n[k].tweens)),g=g.parentNode;for(m=e.length,l=0;m>l;l++)b&&e[l].totalTime(e[l].totalDuration()),e[l]._enabled(!1,!1)}}};var o=function(a,c,d,e){c=c!==!1,d=d!==!1,e=e!==!1;for(var f,g,h=n(e),i=c&&d&&e,j=h.length;--j>-1;)g=h[j],(i||g instanceof b||(f=g.target===g.vars.onComplete)&&d||c&&!f)&&g.paused(a)};return f.pauseAll=function(a,b,c){o(!0,a,b,c)},f.resumeAll=function(a,b,c){o(!1,a,b,c)},f.globalTimeScale=function(b){var d=a._rootTimeline,e=c.ticker.time;return arguments.length?(b=b||g,d._startTime=e-(e-d._startTime)*d._timeScale/b,d=a._rootFramesTimeline,e=c.ticker.frame,d._startTime=e-(e-d._startTime)*d._timeScale/b,d._timeScale=a._rootTimeline._timeScale=b,b):d._timeScale},k.progress=function(a,b){return arguments.length?this.totalTime(this.duration()*(this._yoyo&&0!==(1&this._cycle)?1-a:a)+this._cycle*(this._duration+this._repeatDelay),b):this._time/this.duration()},k.totalProgress=function(a,b){return arguments.length?this.totalTime(this.totalDuration()*a,b):this._totalTime/this.totalDuration()},k.time=function(a,b){return arguments.length?(this._dirty&&this.totalDuration(),a>this._duration&&(a=this._duration),this._yoyo&&0!==(1&this._cycle)?a=this._duration-a+this._cycle*(this._duration+this._repeatDelay):0!==this._repeat&&(a+=this._cycle*(this._duration+this._repeatDelay)),this.totalTime(a,b)):this._time},k.duration=function(b){return arguments.length?a.prototype.duration.call(this,b):this._duration},k.totalDuration=function(a){return arguments.length?-1===this._repeat?this:this.duration((a-this._repeat*this._repeatDelay)/(this._repeat+1)):(this._dirty&&(this._totalDuration=-1===this._repeat?999999999999:this._duration*(this._repeat+1)+this._repeatDelay*this._repeat,this._dirty=!1),this._totalDuration)},k.repeat=function(a){return arguments.length?(this._repeat=a,this._uncache(!0)):this._repeat},k.repeatDelay=function(a){return arguments.length?(this._repeatDelay=a,this._uncache(!0)):this._repeatDelay},k.yoyo=function(a){return arguments.length?(this._yoyo=a,this):this._yoyo},f},!0),_gsScope._gsDefine("TimelineLite",["core.Animation","core.SimpleTimeline","TweenLite"],function(a,b,c){var d=function(a){b.call(this,a),this._labels={},this.autoRemoveChildren=this.vars.autoRemoveChildren===!0,this.smoothChildTiming=this.vars.smoothChildTiming===!0,this._sortChildren=!0,this._onUpdate=this.vars.onUpdate;var c,d,e=this.vars;for(d in e)c=e[d],i(c)&&-1!==c.join("").indexOf("{self}")&&(e[d]=this._swapSelfInParams(c));i(e.tweens)&&this.add(e.tweens,0,e.align,e.stagger)},e=1e-10,f=c._internals,g=d._internals={},h=f.isSelector,i=f.isArray,j=f.lazyTweens,k=f.lazyRender,l=_gsScope._gsDefine.globals,m=function(a){var b,c={};for(b in a)c[b]=a[b];return c},n=function(a,b,c){var d,e,f=a.cycle;for(d in f)e=f[d],a[d]="function"==typeof e?e.call(b[c],c):e[c%e.length];delete a.cycle},o=g.pauseCallback=function(){},p=function(a){var b,c=[],d=a.length;for(b=0;b!==d;c.push(a[b++]));return c},q=d.prototype=new b;return d.version="1.19.0",q.constructor=d,q.kill()._gc=q._forcingPlayhead=q._hasPause=!1,q.to=function(a,b,d,e){var f=d.repeat&&l.TweenMax||c;return b?this.add(new f(a,b,d),e):this.set(a,d,e)},q.from=function(a,b,d,e){return this.add((d.repeat&&l.TweenMax||c).from(a,b,d),e)},q.fromTo=function(a,b,d,e,f){var g=e.repeat&&l.TweenMax||c;return b?this.add(g.fromTo(a,b,d,e),f):this.set(a,e,f)},q.staggerTo=function(a,b,e,f,g,i,j,k){var l,o,q=new d({onComplete:i,onCompleteParams:j,callbackScope:k,smoothChildTiming:this.smoothChildTiming}),r=e.cycle;for("string"==typeof a&&(a=c.selector(a)||a),a=a||[],h(a)&&(a=p(a)),f=f||0,0>f&&(a=p(a),a.reverse(),f*=-1),o=0;o<a.length;o++)l=m(e),l.startAt&&(l.startAt=m(l.startAt),l.startAt.cycle&&n(l.startAt,a,o)),r&&(n(l,a,o),null!=l.duration&&(b=l.duration,delete l.duration)),q.to(a[o],b,l,o*f);return this.add(q,g)},q.staggerFrom=function(a,b,c,d,e,f,g,h){return c.immediateRender=0!=c.immediateRender,c.runBackwards=!0,this.staggerTo(a,b,c,d,e,f,g,h)},q.staggerFromTo=function(a,b,c,d,e,f,g,h,i){return d.startAt=c,d.immediateRender=0!=d.immediateRender&&0!=c.immediateRender,this.staggerTo(a,b,d,e,f,g,h,i)},q.call=function(a,b,d,e){return this.add(c.delayedCall(0,a,b,d),e)},q.set=function(a,b,d){return d=this._parseTimeOrLabel(d,0,!0),null==b.immediateRender&&(b.immediateRender=d===this._time&&!this._paused),this.add(new c(a,0,b),d)},d.exportRoot=function(a,b){a=a||{},null==a.smoothChildTiming&&(a.smoothChildTiming=!0);var e,f,g=new d(a),h=g._timeline;for(null==b&&(b=!0),h._remove(g,!0),g._startTime=0,g._rawPrevTime=g._time=g._totalTime=h._time,e=h._first;e;)f=e._next,b&&e instanceof c&&e.target===e.vars.onComplete||g.add(e,e._startTime-e._delay),e=f;return h.add(g,0),g},q.add=function(e,f,g,h){var j,k,l,m,n,o;if("number"!=typeof f&&(f=this._parseTimeOrLabel(f,0,!0,e)),!(e instanceof a)){if(e instanceof Array||e&&e.push&&i(e)){for(g=g||"normal",h=h||0,j=f,k=e.length,l=0;k>l;l++)i(m=e[l])&&(m=new d({tweens:m})),this.add(m,j),"string"!=typeof m&&"function"!=typeof m&&("sequence"===g?j=m._startTime+m.totalDuration()/m._timeScale:"start"===g&&(m._startTime-=m.delay())),j+=h;return this._uncache(!0)}if("string"==typeof e)return this.addLabel(e,f);if("function"!=typeof e)throw"Cannot add "+e+" into the timeline; it is not a tween, timeline, function, or string.";e=c.delayedCall(0,e)}if(b.prototype.add.call(this,e,f),(this._gc||this._time===this._duration)&&!this._paused&&this._duration<this.duration())for(n=this,o=n.rawTime()>e._startTime;n._timeline;)o&&n._timeline.smoothChildTiming?n.totalTime(n._totalTime,!0):n._gc&&n._enabled(!0,!1),n=n._timeline;return this},q.remove=function(b){if(b instanceof a){this._remove(b,!1);var c=b._timeline=b.vars.useFrames?a._rootFramesTimeline:a._rootTimeline;return b._startTime=(b._paused?b._pauseTime:c._time)-(b._reversed?b.totalDuration()-b._totalTime:b._totalTime)/b._timeScale,this}if(b instanceof Array||b&&b.push&&i(b)){for(var d=b.length;--d>-1;)this.remove(b[d]);return this}return"string"==typeof b?this.removeLabel(b):this.kill(null,b)},q._remove=function(a,c){b.prototype._remove.call(this,a,c);var d=this._last;return d?this._time>d._startTime+d._totalDuration/d._timeScale&&(this._time=this.duration(),this._totalTime=this._totalDuration):this._time=this._totalTime=this._duration=this._totalDuration=0,this},q.append=function(a,b){return this.add(a,this._parseTimeOrLabel(null,b,!0,a))},q.insert=q.insertMultiple=function(a,b,c,d){return this.add(a,b||0,c,d)},q.appendMultiple=function(a,b,c,d){return this.add(a,this._parseTimeOrLabel(null,b,!0,a),c,d)},q.addLabel=function(a,b){return this._labels[a]=this._parseTimeOrLabel(b),this},q.addPause=function(a,b,d,e){var f=c.delayedCall(0,o,d,e||this);return f.vars.onComplete=f.vars.onReverseComplete=b,f.data="isPause",this._hasPause=!0,this.add(f,a)},q.removeLabel=function(a){return delete this._labels[a],this},q.getLabelTime=function(a){return null!=this._labels[a]?this._labels[a]:-1},q._parseTimeOrLabel=function(b,c,d,e){var f;if(e instanceof a&&e.timeline===this)this.remove(e);else if(e&&(e instanceof Array||e.push&&i(e)))for(f=e.length;--f>-1;)e[f]instanceof a&&e[f].timeline===this&&this.remove(e[f]);if("string"==typeof c)return this._parseTimeOrLabel(c,d&&"number"==typeof b&&null==this._labels[c]?b-this.duration():0,d);if(c=c||0,"string"!=typeof b||!isNaN(b)&&null==this._labels[b])null==b&&(b=this.duration());else{if(f=b.indexOf("="),-1===f)return null==this._labels[b]?d?this._labels[b]=this.duration()+c:c:this._labels[b]+c;c=parseInt(b.charAt(f-1)+"1",10)*Number(b.substr(f+1)),b=f>1?this._parseTimeOrLabel(b.substr(0,f-1),0,d):this.duration()}return Number(b)+c},q.seek=function(a,b){return this.totalTime("number"==typeof a?a:this._parseTimeOrLabel(a),b!==!1)},q.stop=function(){return this.paused(!0)},q.gotoAndPlay=function(a,b){return this.play(a,b)},q.gotoAndStop=function(a,b){return this.pause(a,b)},q.render=function(a,b,c){this._gc&&this._enabled(!0,!1);var d,f,g,h,i,l,m,n=this._dirty?this.totalDuration():this._totalDuration,o=this._time,p=this._startTime,q=this._timeScale,r=this._paused;if(a>=n-1e-7)this._totalTime=this._time=n,this._reversed||this._hasPausedChild()||(f=!0,h="onComplete",i=!!this._timeline.autoRemoveChildren,0===this._duration&&(0>=a&&a>=-1e-7||this._rawPrevTime<0||this._rawPrevTime===e)&&this._rawPrevTime!==a&&this._first&&(i=!0,this._rawPrevTime>e&&(h="onReverseComplete"))),this._rawPrevTime=this._duration||!b||a||this._rawPrevTime===a?a:e,a=n+1e-4;else if(1e-7>a)if(this._totalTime=this._time=0,(0!==o||0===this._duration&&this._rawPrevTime!==e&&(this._rawPrevTime>0||0>a&&this._rawPrevTime>=0))&&(h="onReverseComplete",f=this._reversed),0>a)this._active=!1,this._timeline.autoRemoveChildren&&this._reversed?(i=f=!0,h="onReverseComplete"):this._rawPrevTime>=0&&this._first&&(i=!0),this._rawPrevTime=a;else{if(this._rawPrevTime=this._duration||!b||a||this._rawPrevTime===a?a:e,0===a&&f)for(d=this._first;d&&0===d._startTime;)d._duration||(f=!1),d=d._next;a=0,this._initted||(i=!0)}else{if(this._hasPause&&!this._forcingPlayhead&&!b){if(a>=o)for(d=this._first;d&&d._startTime<=a&&!l;)d._duration||"isPause"!==d.data||d.ratio||0===d._startTime&&0===this._rawPrevTime||(l=d),d=d._next;else for(d=this._last;d&&d._startTime>=a&&!l;)d._duration||"isPause"===d.data&&d._rawPrevTime>0&&(l=d),d=d._prev;l&&(this._time=a=l._startTime,this._totalTime=a+this._cycle*(this._totalDuration+this._repeatDelay))}this._totalTime=this._time=this._rawPrevTime=a}if(this._time!==o&&this._first||c||i||l){if(this._initted||(this._initted=!0),this._active||!this._paused&&this._time!==o&&a>0&&(this._active=!0),0===o&&this.vars.onStart&&(0===this._time&&this._duration||b||this._callback("onStart")),m=this._time,m>=o)for(d=this._first;d&&(g=d._next,m===this._time&&(!this._paused||r));)(d._active||d._startTime<=m&&!d._paused&&!d._gc)&&(l===d&&this.pause(),d._reversed?d.render((d._dirty?d.totalDuration():d._totalDuration)-(a-d._startTime)*d._timeScale,b,c):d.render((a-d._startTime)*d._timeScale,b,c)),d=g;else for(d=this._last;d&&(g=d._prev,m===this._time&&(!this._paused||r));){if(d._active||d._startTime<=o&&!d._paused&&!d._gc){if(l===d){for(l=d._prev;l&&l.endTime()>this._time;)l.render(l._reversed?l.totalDuration()-(a-l._startTime)*l._timeScale:(a-l._startTime)*l._timeScale,b,c),l=l._prev;l=null,this.pause()}d._reversed?d.render((d._dirty?d.totalDuration():d._totalDuration)-(a-d._startTime)*d._timeScale,b,c):d.render((a-d._startTime)*d._timeScale,b,c)}d=g}this._onUpdate&&(b||(j.length&&k(),this._callback("onUpdate"))),h&&(this._gc||(p===this._startTime||q!==this._timeScale)&&(0===this._time||n>=this.totalDuration())&&(f&&(j.length&&k(),this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),!b&&this.vars[h]&&this._callback(h)))}},q._hasPausedChild=function(){for(var a=this._first;a;){if(a._paused||a instanceof d&&a._hasPausedChild())return!0;a=a._next}return!1},q.getChildren=function(a,b,d,e){e=e||-9999999999;for(var f=[],g=this._first,h=0;g;)g._startTime<e||(g instanceof c?b!==!1&&(f[h++]=g):(d!==!1&&(f[h++]=g),a!==!1&&(f=f.concat(g.getChildren(!0,b,d)),h=f.length))),g=g._next;return f},q.getTweensOf=function(a,b){var d,e,f=this._gc,g=[],h=0;for(f&&this._enabled(!0,!0),d=c.getTweensOf(a),e=d.length;--e>-1;)(d[e].timeline===this||b&&this._contains(d[e]))&&(g[h++]=d[e]);return f&&this._enabled(!1,!0),g},q.recent=function(){return this._recent},q._contains=function(a){for(var b=a.timeline;b;){if(b===this)return!0;b=b.timeline}return!1},q.shiftChildren=function(a,b,c){c=c||0;for(var d,e=this._first,f=this._labels;e;)e._startTime>=c&&(e._startTime+=a),e=e._next;if(b)for(d in f)f[d]>=c&&(f[d]+=a);return this._uncache(!0)},q._kill=function(a,b){if(!a&&!b)return this._enabled(!1,!1);for(var c=b?this.getTweensOf(b):this.getChildren(!0,!0,!1),d=c.length,e=!1;--d>-1;)c[d]._kill(a,b)&&(e=!0);return e},q.clear=function(a){var b=this.getChildren(!1,!0,!0),c=b.length;for(this._time=this._totalTime=0;--c>-1;)b[c]._enabled(!1,!1);return a!==!1&&(this._labels={}),this._uncache(!0)},q.invalidate=function(){for(var b=this._first;b;)b.invalidate(),b=b._next;return a.prototype.invalidate.call(this)},q._enabled=function(a,c){if(a===this._gc)for(var d=this._first;d;)d._enabled(a,!0),d=d._next;return b.prototype._enabled.call(this,a,c)},q.totalTime=function(b,c,d){this._forcingPlayhead=!0;var e=a.prototype.totalTime.apply(this,arguments);return this._forcingPlayhead=!1,e},q.duration=function(a){return arguments.length?(0!==this.duration()&&0!==a&&this.timeScale(this._duration/a),this):(this._dirty&&this.totalDuration(),this._duration)},q.totalDuration=function(a){if(!arguments.length){if(this._dirty){for(var b,c,d=0,e=this._last,f=999999999999;e;)b=e._prev,e._dirty&&e.totalDuration(),e._startTime>f&&this._sortChildren&&!e._paused?this.add(e,e._startTime-e._delay):f=e._startTime,e._startTime<0&&!e._paused&&(d-=e._startTime,this._timeline.smoothChildTiming&&(this._startTime+=e._startTime/this._timeScale),this.shiftChildren(-e._startTime,!1,-9999999999),f=0),c=e._startTime+e._totalDuration/e._timeScale,c>d&&(d=c),e=b;this._duration=this._totalDuration=d,this._dirty=!1}return this._totalDuration}return a&&this.totalDuration()?this.timeScale(this._totalDuration/a):this},q.paused=function(b){if(!b)for(var c=this._first,d=this._time;c;)c._startTime===d&&"isPause"===c.data&&(c._rawPrevTime=0),c=c._next;return a.prototype.paused.apply(this,arguments)},q.usesFrames=function(){for(var b=this._timeline;b._timeline;)b=b._timeline;return b===a._rootFramesTimeline},q.rawTime=function(){return this._paused?this._totalTime:(this._timeline.rawTime()-this._startTime)*this._timeScale},d},!0),_gsScope._gsDefine("TimelineMax",["TimelineLite","TweenLite","easing.Ease"],function(a,b,c){var d=function(b){a.call(this,b),this._repeat=this.vars.repeat||0,this._repeatDelay=this.vars.repeatDelay||0,this._cycle=0,this._yoyo=this.vars.yoyo===!0,this._dirty=!0},e=1e-10,f=b._internals,g=f.lazyTweens,h=f.lazyRender,i=_gsScope._gsDefine.globals,j=new c(null,null,1,0),k=d.prototype=new a;return k.constructor=d,k.kill()._gc=!1,d.version="1.19.0",k.invalidate=function(){return this._yoyo=this.vars.yoyo===!0,this._repeat=this.vars.repeat||0,this._repeatDelay=this.vars.repeatDelay||0,this._uncache(!0),a.prototype.invalidate.call(this)},k.addCallback=function(a,c,d,e){return this.add(b.delayedCall(0,a,d,e),c)},k.removeCallback=function(a,b){if(a)if(null==b)this._kill(null,a);else for(var c=this.getTweensOf(a,!1),d=c.length,e=this._parseTimeOrLabel(b);--d>-1;)c[d]._startTime===e&&c[d]._enabled(!1,!1);return this},k.removePause=function(b){return this.removeCallback(a._internals.pauseCallback,b)},k.tweenTo=function(a,c){c=c||{};var d,e,f,g={ease:j,useFrames:this.usesFrames(),immediateRender:!1},h=c.repeat&&i.TweenMax||b;for(e in c)g[e]=c[e];return g.time=this._parseTimeOrLabel(a),d=Math.abs(Number(g.time)-this._time)/this._timeScale||.001,f=new h(this,d,g),g.onStart=function(){f.target.paused(!0),f.vars.time!==f.target.time()&&d===f.duration()&&f.duration(Math.abs(f.vars.time-f.target.time())/f.target._timeScale),c.onStart&&f._callback("onStart")},f},k.tweenFromTo=function(a,b,c){c=c||{},a=this._parseTimeOrLabel(a),c.startAt={onComplete:this.seek,onCompleteParams:[a],callbackScope:this},c.immediateRender=c.immediateRender!==!1;var d=this.tweenTo(b,c);return d.duration(Math.abs(d.vars.time-a)/this._timeScale||.001)},k.render=function(a,b,c){this._gc&&this._enabled(!0,!1);var d,f,i,j,k,l,m,n,o=this._dirty?this.totalDuration():this._totalDuration,p=this._duration,q=this._time,r=this._totalTime,s=this._startTime,t=this._timeScale,u=this._rawPrevTime,v=this._paused,w=this._cycle;if(a>=o-1e-7)this._locked||(this._totalTime=o,this._cycle=this._repeat),this._reversed||this._hasPausedChild()||(f=!0,j="onComplete",k=!!this._timeline.autoRemoveChildren,0===this._duration&&(0>=a&&a>=-1e-7||0>u||u===e)&&u!==a&&this._first&&(k=!0,u>e&&(j="onReverseComplete"))),this._rawPrevTime=this._duration||!b||a||this._rawPrevTime===a?a:e,this._yoyo&&0!==(1&this._cycle)?this._time=a=0:(this._time=p,a=p+1e-4);else if(1e-7>a)if(this._locked||(this._totalTime=this._cycle=0),this._time=0,(0!==q||0===p&&u!==e&&(u>0||0>a&&u>=0)&&!this._locked)&&(j="onReverseComplete",f=this._reversed),0>a)this._active=!1,this._timeline.autoRemoveChildren&&this._reversed?(k=f=!0,j="onReverseComplete"):u>=0&&this._first&&(k=!0),this._rawPrevTime=a;else{if(this._rawPrevTime=p||!b||a||this._rawPrevTime===a?a:e,0===a&&f)for(d=this._first;d&&0===d._startTime;)d._duration||(f=!1),d=d._next;a=0,this._initted||(k=!0)}else if(0===p&&0>u&&(k=!0),this._time=this._rawPrevTime=a,this._locked||(this._totalTime=a,0!==this._repeat&&(l=p+this._repeatDelay,this._cycle=this._totalTime/l>>0,0!==this._cycle&&this._cycle===this._totalTime/l&&a>=r&&this._cycle--,this._time=this._totalTime-this._cycle*l,this._yoyo&&0!==(1&this._cycle)&&(this._time=p-this._time),this._time>p?(this._time=p,a=p+1e-4):this._time<0?this._time=a=0:a=this._time)),this._hasPause&&!this._forcingPlayhead&&!b){if(a=this._time,a>=q)for(d=this._first;d&&d._startTime<=a&&!m;)d._duration||"isPause"!==d.data||d.ratio||0===d._startTime&&0===this._rawPrevTime||(m=d),d=d._next;else for(d=this._last;d&&d._startTime>=a&&!m;)d._duration||"isPause"===d.data&&d._rawPrevTime>0&&(m=d),d=d._prev;m&&(this._time=a=m._startTime,this._totalTime=a+this._cycle*(this._totalDuration+this._repeatDelay))}if(this._cycle!==w&&!this._locked){var x=this._yoyo&&0!==(1&w),y=x===(this._yoyo&&0!==(1&this._cycle)),z=this._totalTime,A=this._cycle,B=this._rawPrevTime,C=this._time;if(this._totalTime=w*p,this._cycle<w?x=!x:this._totalTime+=p,this._time=q,this._rawPrevTime=0===p?u-1e-4:u,this._cycle=w,this._locked=!0,q=x?0:p,this.render(q,b,0===p),b||this._gc||this.vars.onRepeat&&this._callback("onRepeat"),q!==this._time)return;if(y&&(q=x?p+1e-4:-1e-4,this.render(q,!0,!1)),this._locked=!1,this._paused&&!v)return;this._time=C,this._totalTime=z,this._cycle=A,this._rawPrevTime=B}if(!(this._time!==q&&this._first||c||k||m))return void(r!==this._totalTime&&this._onUpdate&&(b||this._callback("onUpdate")));if(this._initted||(this._initted=!0),this._active||!this._paused&&this._totalTime!==r&&a>0&&(this._active=!0),0===r&&this.vars.onStart&&(0===this._totalTime&&this._totalDuration||b||this._callback("onStart")),n=this._time,n>=q)for(d=this._first;d&&(i=d._next,n===this._time&&(!this._paused||v));)(d._active||d._startTime<=this._time&&!d._paused&&!d._gc)&&(m===d&&this.pause(),d._reversed?d.render((d._dirty?d.totalDuration():d._totalDuration)-(a-d._startTime)*d._timeScale,b,c):d.render((a-d._startTime)*d._timeScale,b,c)),d=i;else for(d=this._last;d&&(i=d._prev,n===this._time&&(!this._paused||v));){if(d._active||d._startTime<=q&&!d._paused&&!d._gc){if(m===d){for(m=d._prev;m&&m.endTime()>this._time;)m.render(m._reversed?m.totalDuration()-(a-m._startTime)*m._timeScale:(a-m._startTime)*m._timeScale,b,c),m=m._prev;m=null,this.pause()}d._reversed?d.render((d._dirty?d.totalDuration():d._totalDuration)-(a-d._startTime)*d._timeScale,b,c):d.render((a-d._startTime)*d._timeScale,b,c)}d=i}this._onUpdate&&(b||(g.length&&h(),this._callback("onUpdate"))),j&&(this._locked||this._gc||(s===this._startTime||t!==this._timeScale)&&(0===this._time||o>=this.totalDuration())&&(f&&(g.length&&h(),this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),!b&&this.vars[j]&&this._callback(j)))},k.getActive=function(a,b,c){null==a&&(a=!0),null==b&&(b=!0),null==c&&(c=!1);var d,e,f=[],g=this.getChildren(a,b,c),h=0,i=g.length;for(d=0;i>d;d++)e=g[d],e.isActive()&&(f[h++]=e);return f},k.getLabelAfter=function(a){a||0!==a&&(a=this._time);var b,c=this.getLabelsArray(),d=c.length;for(b=0;d>b;b++)if(c[b].time>a)return c[b].name;return null},k.getLabelBefore=function(a){null==a&&(a=this._time);for(var b=this.getLabelsArray(),c=b.length;--c>-1;)if(b[c].time<a)return b[c].name;return null},k.getLabelsArray=function(){var a,b=[],c=0;for(a in this._labels)b[c++]={time:this._labels[a],name:a};return b.sort(function(a,b){return a.time-b.time}),b},k.progress=function(a,b){return arguments.length?this.totalTime(this.duration()*(this._yoyo&&0!==(1&this._cycle)?1-a:a)+this._cycle*(this._duration+this._repeatDelay),b):this._time/this.duration()},k.totalProgress=function(a,b){return arguments.length?this.totalTime(this.totalDuration()*a,b):this._totalTime/this.totalDuration()},k.totalDuration=function(b){return arguments.length?-1!==this._repeat&&b?this.timeScale(this.totalDuration()/b):this:(this._dirty&&(a.prototype.totalDuration.call(this),this._totalDuration=-1===this._repeat?999999999999:this._duration*(this._repeat+1)+this._repeatDelay*this._repeat),this._totalDuration)},k.time=function(a,b){return arguments.length?(this._dirty&&this.totalDuration(),a>this._duration&&(a=this._duration),this._yoyo&&0!==(1&this._cycle)?a=this._duration-a+this._cycle*(this._duration+this._repeatDelay):0!==this._repeat&&(a+=this._cycle*(this._duration+this._repeatDelay)),this.totalTime(a,b)):this._time},k.repeat=function(a){return arguments.length?(this._repeat=a,this._uncache(!0)):this._repeat},k.repeatDelay=function(a){return arguments.length?(this._repeatDelay=a,this._uncache(!0)):this._repeatDelay},k.yoyo=function(a){return arguments.length?(this._yoyo=a,this):this._yoyo},k.currentLabel=function(a){return arguments.length?this.seek(a,!0):this.getLabelBefore(this._time+1e-8)},d},!0),function(){var a=180/Math.PI,b=[],c=[],d=[],e={},f=_gsScope._gsDefine.globals,g=function(a,b,c,d){c===d&&(c=d-(d-b)/1e6),a===b&&(b=a+(c-a)/1e6),this.a=a,this.b=b,this.c=c,this.d=d,this.da=d-a,this.ca=c-a,this.ba=b-a},h=",x,y,z,left,top,right,bottom,marginTop,marginLeft,marginRight,marginBottom,paddingLeft,paddingTop,paddingRight,paddingBottom,backgroundPosition,backgroundPosition_y,",i=function(a,b,c,d){var e={a:a},f={},g={},h={c:d},i=(a+b)/2,j=(b+c)/2,k=(c+d)/2,l=(i+j)/2,m=(j+k)/2,n=(m-l)/8;return e.b=i+(a-i)/4,f.b=l+n,e.c=f.a=(e.b+f.b)/2,f.c=g.a=(l+m)/2,g.b=m-n,h.b=k+(d-k)/4,g.c=h.a=(g.b+h.b)/2,[e,f,g,h]},j=function(a,e,f,g,h){var j,k,l,m,n,o,p,q,r,s,t,u,v,w=a.length-1,x=0,y=a[0].a;for(j=0;w>j;j++)n=a[x],k=n.a,l=n.d,m=a[x+1].d,h?(t=b[j],u=c[j],v=(u+t)*e*.25/(g?.5:d[j]||.5),o=l-(l-k)*(g?.5*e:0!==t?v/t:0),p=l+(m-l)*(g?.5*e:0!==u?v/u:0),q=l-(o+((p-o)*(3*t/(t+u)+.5)/4||0))):(o=l-(l-k)*e*.5,p=l+(m-l)*e*.5,q=l-(o+p)/2),o+=q,p+=q,n.c=r=o,0!==j?n.b=y:n.b=y=n.a+.6*(n.c-n.a),n.da=l-k,n.ca=r-k,n.ba=y-k,f?(s=i(k,y,r,l),a.splice(x,1,s[0],s[1],s[2],s[3]),x+=4):x++,y=p;n=a[x],n.b=y,n.c=y+.4*(n.d-y),n.da=n.d-n.a,n.ca=n.c-n.a,n.ba=y-n.a,f&&(s=i(n.a,y,n.c,n.d),a.splice(x,1,s[0],s[1],s[2],s[3]))},k=function(a,d,e,f){var h,i,j,k,l,m,n=[];if(f)for(a=[f].concat(a),i=a.length;--i>-1;)"string"==typeof(m=a[i][d])&&"="===m.charAt(1)&&(a[i][d]=f[d]+Number(m.charAt(0)+m.substr(2)));if(h=a.length-2,0>h)return n[0]=new g(a[0][d],0,0,a[-1>h?0:1][d]),n;for(i=0;h>i;i++)j=a[i][d],k=a[i+1][d],n[i]=new g(j,0,0,k),e&&(l=a[i+2][d],b[i]=(b[i]||0)+(k-j)*(k-j),c[i]=(c[i]||0)+(l-k)*(l-k));return n[i]=new g(a[i][d],0,0,a[i+1][d]),n},l=function(a,f,g,i,l,m){var n,o,p,q,r,s,t,u,v={},w=[],x=m||a[0];l="string"==typeof l?","+l+",":h,null==f&&(f=1);for(o in a[0])w.push(o);if(a.length>1){for(u=a[a.length-1],t=!0,n=w.length;--n>-1;)if(o=w[n],Math.abs(x[o]-u[o])>.05){t=!1;break}t&&(a=a.concat(),m&&a.unshift(m),a.push(a[1]),m=a[a.length-3])}for(b.length=c.length=d.length=0,n=w.length;--n>-1;)o=w[n],e[o]=-1!==l.indexOf(","+o+","),v[o]=k(a,o,e[o],m);for(n=b.length;--n>-1;)b[n]=Math.sqrt(b[n]),c[n]=Math.sqrt(c[n]);if(!i){for(n=w.length;--n>-1;)if(e[o])for(p=v[w[n]],s=p.length-1,q=0;s>q;q++)r=p[q+1].da/c[q]+p[q].da/b[q]||0,d[q]=(d[q]||0)+r*r;for(n=d.length;--n>-1;)d[n]=Math.sqrt(d[n])}for(n=w.length,q=g?4:1;--n>-1;)o=w[n],p=v[o],j(p,f,g,i,e[o]),t&&(p.splice(0,q),p.splice(p.length-q,q));return v},m=function(a,b,c){b=b||"soft";var d,e,f,h,i,j,k,l,m,n,o,p={},q="cubic"===b?3:2,r="soft"===b,s=[];if(r&&c&&(a=[c].concat(a)),null==a||a.length<q+1)throw"invalid Bezier data";for(m in a[0])s.push(m);for(j=s.length;--j>-1;){for(m=s[j],p[m]=i=[],n=0,l=a.length,k=0;l>k;k++)d=null==c?a[k][m]:"string"==typeof(o=a[k][m])&&"="===o.charAt(1)?c[m]+Number(o.charAt(0)+o.substr(2)):Number(o),r&&k>1&&l-1>k&&(i[n++]=(d+i[n-2])/2),i[n++]=d;for(l=n-q+1,n=0,k=0;l>k;k+=q)d=i[k],e=i[k+1],f=i[k+2],h=2===q?0:i[k+3],i[n++]=o=3===q?new g(d,e,f,h):new g(d,(2*e+d)/3,(2*e+f)/3,f);i.length=n}return p},n=function(a,b,c){for(var d,e,f,g,h,i,j,k,l,m,n,o=1/c,p=a.length;--p>-1;)for(m=a[p],f=m.a,g=m.d-f,h=m.c-f,i=m.b-f,d=e=0,k=1;c>=k;k++)j=o*k,l=1-j,d=e-(e=(j*j*g+3*l*(j*h+l*i))*j),n=p*c+k-1,b[n]=(b[n]||0)+d*d},o=function(a,b){b=b>>0||6;var c,d,e,f,g=[],h=[],i=0,j=0,k=b-1,l=[],m=[];for(c in a)n(a[c],g,b);for(e=g.length,d=0;e>d;d++)i+=Math.sqrt(g[d]),f=d%b,m[f]=i,f===k&&(j+=i,f=d/b>>0,l[f]=m,h[f]=j,i=0,m=[]);return{length:j,lengths:h,
segments:l}},p=_gsScope._gsDefine.plugin({propName:"bezier",priority:-1,version:"1.3.7",API:2,global:!0,init:function(a,b,c){this._target=a,b instanceof Array&&(b={values:b}),this._func={},this._mod={},this._props=[],this._timeRes=null==b.timeResolution?6:parseInt(b.timeResolution,10);var d,e,f,g,h,i=b.values||[],j={},k=i[0],n=b.autoRotate||c.vars.orientToBezier;this._autoRotate=n?n instanceof Array?n:[["x","y","rotation",n===!0?0:Number(n)||0]]:null;for(d in k)this._props.push(d);for(f=this._props.length;--f>-1;)d=this._props[f],this._overwriteProps.push(d),e=this._func[d]="function"==typeof a[d],j[d]=e?a[d.indexOf("set")||"function"!=typeof a["get"+d.substr(3)]?d:"get"+d.substr(3)]():parseFloat(a[d]),h||j[d]!==i[0][d]&&(h=j);if(this._beziers="cubic"!==b.type&&"quadratic"!==b.type&&"soft"!==b.type?l(i,isNaN(b.curviness)?1:b.curviness,!1,"thruBasic"===b.type,b.correlate,h):m(i,b.type,j),this._segCount=this._beziers[d].length,this._timeRes){var p=o(this._beziers,this._timeRes);this._length=p.length,this._lengths=p.lengths,this._segments=p.segments,this._l1=this._li=this._s1=this._si=0,this._l2=this._lengths[0],this._curSeg=this._segments[0],this._s2=this._curSeg[0],this._prec=1/this._curSeg.length}if(n=this._autoRotate)for(this._initialRotations=[],n[0]instanceof Array||(this._autoRotate=n=[n]),f=n.length;--f>-1;){for(g=0;3>g;g++)d=n[f][g],this._func[d]="function"==typeof a[d]?a[d.indexOf("set")||"function"!=typeof a["get"+d.substr(3)]?d:"get"+d.substr(3)]:!1;d=n[f][2],this._initialRotations[f]=(this._func[d]?this._func[d].call(this._target):this._target[d])||0,this._overwriteProps.push(d)}return this._startRatio=c.vars.runBackwards?1:0,!0},set:function(b){var c,d,e,f,g,h,i,j,k,l,m=this._segCount,n=this._func,o=this._target,p=b!==this._startRatio;if(this._timeRes){if(k=this._lengths,l=this._curSeg,b*=this._length,e=this._li,b>this._l2&&m-1>e){for(j=m-1;j>e&&(this._l2=k[++e])<=b;);this._l1=k[e-1],this._li=e,this._curSeg=l=this._segments[e],this._s2=l[this._s1=this._si=0]}else if(b<this._l1&&e>0){for(;e>0&&(this._l1=k[--e])>=b;);0===e&&b<this._l1?this._l1=0:e++,this._l2=k[e],this._li=e,this._curSeg=l=this._segments[e],this._s1=l[(this._si=l.length-1)-1]||0,this._s2=l[this._si]}if(c=e,b-=this._l1,e=this._si,b>this._s2&&e<l.length-1){for(j=l.length-1;j>e&&(this._s2=l[++e])<=b;);this._s1=l[e-1],this._si=e}else if(b<this._s1&&e>0){for(;e>0&&(this._s1=l[--e])>=b;);0===e&&b<this._s1?this._s1=0:e++,this._s2=l[e],this._si=e}h=(e+(b-this._s1)/(this._s2-this._s1))*this._prec||0}else c=0>b?0:b>=1?m-1:m*b>>0,h=(b-c*(1/m))*m;for(d=1-h,e=this._props.length;--e>-1;)f=this._props[e],g=this._beziers[f][c],i=(h*h*g.da+3*d*(h*g.ca+d*g.ba))*h+g.a,this._mod[f]&&(i=this._mod[f](i,o)),n[f]?o[f](i):o[f]=i;if(this._autoRotate){var q,r,s,t,u,v,w,x=this._autoRotate;for(e=x.length;--e>-1;)f=x[e][2],v=x[e][3]||0,w=x[e][4]===!0?1:a,g=this._beziers[x[e][0]],q=this._beziers[x[e][1]],g&&q&&(g=g[c],q=q[c],r=g.a+(g.b-g.a)*h,t=g.b+(g.c-g.b)*h,r+=(t-r)*h,t+=(g.c+(g.d-g.c)*h-t)*h,s=q.a+(q.b-q.a)*h,u=q.b+(q.c-q.b)*h,s+=(u-s)*h,u+=(q.c+(q.d-q.c)*h-u)*h,i=p?Math.atan2(u-s,t-r)*w+v:this._initialRotations[e],this._mod[f]&&(i=this._mod[f](i,o)),n[f]?o[f](i):o[f]=i)}}}),q=p.prototype;p.bezierThrough=l,p.cubicToQuadratic=i,p._autoCSS=!0,p.quadraticToCubic=function(a,b,c){return new g(a,(2*b+a)/3,(2*b+c)/3,c)},p._cssRegister=function(){var a=f.CSSPlugin;if(a){var b=a._internals,c=b._parseToProxy,d=b._setPluginRatio,e=b.CSSPropTween;b._registerComplexSpecialProp("bezier",{parser:function(a,b,f,g,h,i){b instanceof Array&&(b={values:b}),i=new p;var j,k,l,m=b.values,n=m.length-1,o=[],q={};if(0>n)return h;for(j=0;n>=j;j++)l=c(a,m[j],g,h,i,n!==j),o[j]=l.end;for(k in b)q[k]=b[k];return q.values=o,h=new e(a,"bezier",0,0,l.pt,2),h.data=l,h.plugin=i,h.setRatio=d,0===q.autoRotate&&(q.autoRotate=!0),!q.autoRotate||q.autoRotate instanceof Array||(j=q.autoRotate===!0?0:Number(q.autoRotate),q.autoRotate=null!=l.end.left?[["left","top","rotation",j,!1]]:null!=l.end.x?[["x","y","rotation",j,!1]]:!1),q.autoRotate&&(g._transform||g._enableTransforms(!1),l.autoRotate=g._target._gsTransform,l.proxy.rotation=l.autoRotate.rotation||0,g._overwriteProps.push("rotation")),i._onInitTween(l.proxy,q,g._tween),h}})}},q._mod=function(a){for(var b,c=this._overwriteProps,d=c.length;--d>-1;)b=a[c[d]],b&&"function"==typeof b&&(this._mod[c[d]]=b)},q._kill=function(a){var b,c,d=this._props;for(b in this._beziers)if(b in a)for(delete this._beziers[b],delete this._func[b],c=d.length;--c>-1;)d[c]===b&&d.splice(c,1);if(d=this._autoRotate)for(c=d.length;--c>-1;)a[d[c][2]]&&d.splice(c,1);return this._super._kill.call(this,a)}}(),_gsScope._gsDefine("plugins.CSSPlugin",["plugins.TweenPlugin","TweenLite"],function(a,b){var c,d,e,f,g=function(){a.call(this,"css"),this._overwriteProps.length=0,this.setRatio=g.prototype.setRatio},h=_gsScope._gsDefine.globals,i={},j=g.prototype=new a("css");j.constructor=g,g.version="1.19.0",g.API=2,g.defaultTransformPerspective=0,g.defaultSkewType="compensated",g.defaultSmoothOrigin=!0,j="px",g.suffixMap={top:j,right:j,bottom:j,left:j,width:j,height:j,fontSize:j,padding:j,margin:j,perspective:j,lineHeight:""};var k,l,m,n,o,p,q,r,s=/(?:\-|\.|\b)(\d|\.|e\-)+/g,t=/(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,u=/(?:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b)/gi,v=/(?![+-]?\d*\.?\d+|[+-]|e[+-]\d+)[^0-9]/g,w=/(?:\d|\-|\+|=|#|\.)*/g,x=/opacity *= *([^)]*)/i,y=/opacity:([^;]*)/i,z=/alpha\(opacity *=.+?\)/i,A=/^(rgb|hsl)/,B=/([A-Z])/g,C=/-([a-z])/gi,D=/(^(?:url\(\"|url\())|(?:(\"\))$|\)$)/gi,E=function(a,b){return b.toUpperCase()},F=/(?:Left|Right|Width)/i,G=/(M11|M12|M21|M22)=[\d\-\.e]+/gi,H=/progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i,I=/,(?=[^\)]*(?:\(|$))/gi,J=/[\s,\(]/i,K=Math.PI/180,L=180/Math.PI,M={},N=document,O=function(a){return N.createElementNS?N.createElementNS("http://www.w3.org/1999/xhtml",a):N.createElement(a)},P=O("div"),Q=O("img"),R=g._internals={_specialProps:i},S=navigator.userAgent,T=function(){var a=S.indexOf("Android"),b=O("a");return m=-1!==S.indexOf("Safari")&&-1===S.indexOf("Chrome")&&(-1===a||Number(S.substr(a+8,1))>3),o=m&&Number(S.substr(S.indexOf("Version/")+8,1))<6,n=-1!==S.indexOf("Firefox"),(/MSIE ([0-9]{1,}[\.0-9]{0,})/.exec(S)||/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/.exec(S))&&(p=parseFloat(RegExp.$1)),b?(b.style.cssText="top:1px;opacity:.55;",/^0.55/.test(b.style.opacity)):!1}(),U=function(a){return x.test("string"==typeof a?a:(a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100:1},V=function(a){window.console&&console.log(a)},W="",X="",Y=function(a,b){b=b||P;var c,d,e=b.style;if(void 0!==e[a])return a;for(a=a.charAt(0).toUpperCase()+a.substr(1),c=["O","Moz","ms","Ms","Webkit"],d=5;--d>-1&&void 0===e[c[d]+a];);return d>=0?(X=3===d?"ms":c[d],W="-"+X.toLowerCase()+"-",X+a):null},Z=N.defaultView?N.defaultView.getComputedStyle:function(){},$=g.getStyle=function(a,b,c,d,e){var f;return T||"opacity"!==b?(!d&&a.style[b]?f=a.style[b]:(c=c||Z(a))?f=c[b]||c.getPropertyValue(b)||c.getPropertyValue(b.replace(B,"-$1").toLowerCase()):a.currentStyle&&(f=a.currentStyle[b]),null==e||f&&"none"!==f&&"auto"!==f&&"auto auto"!==f?f:e):U(a)},_=R.convertToPixels=function(a,c,d,e,f){if("px"===e||!e)return d;if("auto"===e||!d)return 0;var h,i,j,k=F.test(c),l=a,m=P.style,n=0>d,o=1===d;if(n&&(d=-d),o&&(d*=100),"%"===e&&-1!==c.indexOf("border"))h=d/100*(k?a.clientWidth:a.clientHeight);else{if(m.cssText="border:0 solid red;position:"+$(a,"position")+";line-height:0;","%"!==e&&l.appendChild&&"v"!==e.charAt(0)&&"rem"!==e)m[k?"borderLeftWidth":"borderTopWidth"]=d+e;else{if(l=a.parentNode||N.body,i=l._gsCache,j=b.ticker.frame,i&&k&&i.time===j)return i.width*d/100;m[k?"width":"height"]=d+e}l.appendChild(P),h=parseFloat(P[k?"offsetWidth":"offsetHeight"]),l.removeChild(P),k&&"%"===e&&g.cacheWidths!==!1&&(i=l._gsCache=l._gsCache||{},i.time=j,i.width=h/d*100),0!==h||f||(h=_(a,c,d,e,!0))}return o&&(h/=100),n?-h:h},aa=R.calculateOffset=function(a,b,c){if("absolute"!==$(a,"position",c))return 0;var d="left"===b?"Left":"Top",e=$(a,"margin"+d,c);return a["offset"+d]-(_(a,b,parseFloat(e),e.replace(w,""))||0)},ba=function(a,b){var c,d,e,f={};if(b=b||Z(a,null))if(c=b.length)for(;--c>-1;)e=b[c],(-1===e.indexOf("-transform")||Ca===e)&&(f[e.replace(C,E)]=b.getPropertyValue(e));else for(c in b)(-1===c.indexOf("Transform")||Ba===c)&&(f[c]=b[c]);else if(b=a.currentStyle||a.style)for(c in b)"string"==typeof c&&void 0===f[c]&&(f[c.replace(C,E)]=b[c]);return T||(f.opacity=U(a)),d=Pa(a,b,!1),f.rotation=d.rotation,f.skewX=d.skewX,f.scaleX=d.scaleX,f.scaleY=d.scaleY,f.x=d.x,f.y=d.y,Ea&&(f.z=d.z,f.rotationX=d.rotationX,f.rotationY=d.rotationY,f.scaleZ=d.scaleZ),f.filters&&delete f.filters,f},ca=function(a,b,c,d,e){var f,g,h,i={},j=a.style;for(g in c)"cssText"!==g&&"length"!==g&&isNaN(g)&&(b[g]!==(f=c[g])||e&&e[g])&&-1===g.indexOf("Origin")&&("number"==typeof f||"string"==typeof f)&&(i[g]="auto"!==f||"left"!==g&&"top"!==g?""!==f&&"auto"!==f&&"none"!==f||"string"!=typeof b[g]||""===b[g].replace(v,"")?f:0:aa(a,g),void 0!==j[g]&&(h=new ra(j,g,j[g],h)));if(d)for(g in d)"className"!==g&&(i[g]=d[g]);return{difs:i,firstMPT:h}},da={width:["Left","Right"],height:["Top","Bottom"]},ea=["marginLeft","marginRight","marginTop","marginBottom"],fa=function(a,b,c){if("svg"===(a.nodeName+"").toLowerCase())return(c||Z(a))[b]||0;if(a.getBBox&&Ma(a))return a.getBBox()[b]||0;var d=parseFloat("width"===b?a.offsetWidth:a.offsetHeight),e=da[b],f=e.length;for(c=c||Z(a,null);--f>-1;)d-=parseFloat($(a,"padding"+e[f],c,!0))||0,d-=parseFloat($(a,"border"+e[f]+"Width",c,!0))||0;return d},ga=function(a,b){if("contain"===a||"auto"===a||"auto auto"===a)return a+" ";(null==a||""===a)&&(a="0 0");var c,d=a.split(" "),e=-1!==a.indexOf("left")?"0%":-1!==a.indexOf("right")?"100%":d[0],f=-1!==a.indexOf("top")?"0%":-1!==a.indexOf("bottom")?"100%":d[1];if(d.length>3&&!b){for(d=a.split(", ").join(",").split(","),a=[],c=0;c<d.length;c++)a.push(ga(d[c]));return a.join(",")}return null==f?f="center"===e?"50%":"0":"center"===f&&(f="50%"),("center"===e||isNaN(parseFloat(e))&&-1===(e+"").indexOf("="))&&(e="50%"),a=e+" "+f+(d.length>2?" "+d[2]:""),b&&(b.oxp=-1!==e.indexOf("%"),b.oyp=-1!==f.indexOf("%"),b.oxr="="===e.charAt(1),b.oyr="="===f.charAt(1),b.ox=parseFloat(e.replace(v,"")),b.oy=parseFloat(f.replace(v,"")),b.v=a),b||a},ha=function(a,b){return"function"==typeof a&&(a=a(r,q)),"string"==typeof a&&"="===a.charAt(1)?parseInt(a.charAt(0)+"1",10)*parseFloat(a.substr(2)):parseFloat(a)-parseFloat(b)||0},ia=function(a,b){return"function"==typeof a&&(a=a(r,q)),null==a?b:"string"==typeof a&&"="===a.charAt(1)?parseInt(a.charAt(0)+"1",10)*parseFloat(a.substr(2))+b:parseFloat(a)||0},ja=function(a,b,c,d){var e,f,g,h,i,j=1e-6;return"function"==typeof a&&(a=a(r,q)),null==a?h=b:"number"==typeof a?h=a:(e=360,f=a.split("_"),i="="===a.charAt(1),g=(i?parseInt(a.charAt(0)+"1",10)*parseFloat(f[0].substr(2)):parseFloat(f[0]))*(-1===a.indexOf("rad")?1:L)-(i?0:b),f.length&&(d&&(d[c]=b+g),-1!==a.indexOf("short")&&(g%=e,g!==g%(e/2)&&(g=0>g?g+e:g-e)),-1!==a.indexOf("_cw")&&0>g?g=(g+9999999999*e)%e-(g/e|0)*e:-1!==a.indexOf("ccw")&&g>0&&(g=(g-9999999999*e)%e-(g/e|0)*e)),h=b+g),j>h&&h>-j&&(h=0),h},ka={aqua:[0,255,255],lime:[0,255,0],silver:[192,192,192],black:[0,0,0],maroon:[128,0,0],teal:[0,128,128],blue:[0,0,255],navy:[0,0,128],white:[255,255,255],fuchsia:[255,0,255],olive:[128,128,0],yellow:[255,255,0],orange:[255,165,0],gray:[128,128,128],purple:[128,0,128],green:[0,128,0],red:[255,0,0],pink:[255,192,203],cyan:[0,255,255],transparent:[255,255,255,0]},la=function(a,b,c){return a=0>a?a+1:a>1?a-1:a,255*(1>6*a?b+(c-b)*a*6:.5>a?c:2>3*a?b+(c-b)*(2/3-a)*6:b)+.5|0},ma=g.parseColor=function(a,b){var c,d,e,f,g,h,i,j,k,l,m;if(a)if("number"==typeof a)c=[a>>16,a>>8&255,255&a];else{if(","===a.charAt(a.length-1)&&(a=a.substr(0,a.length-1)),ka[a])c=ka[a];else if("#"===a.charAt(0))4===a.length&&(d=a.charAt(1),e=a.charAt(2),f=a.charAt(3),a="#"+d+d+e+e+f+f),a=parseInt(a.substr(1),16),c=[a>>16,a>>8&255,255&a];else if("hsl"===a.substr(0,3))if(c=m=a.match(s),b){if(-1!==a.indexOf("="))return a.match(t)}else g=Number(c[0])%360/360,h=Number(c[1])/100,i=Number(c[2])/100,e=.5>=i?i*(h+1):i+h-i*h,d=2*i-e,c.length>3&&(c[3]=Number(a[3])),c[0]=la(g+1/3,d,e),c[1]=la(g,d,e),c[2]=la(g-1/3,d,e);else c=a.match(s)||ka.transparent;c[0]=Number(c[0]),c[1]=Number(c[1]),c[2]=Number(c[2]),c.length>3&&(c[3]=Number(c[3]))}else c=ka.black;return b&&!m&&(d=c[0]/255,e=c[1]/255,f=c[2]/255,j=Math.max(d,e,f),k=Math.min(d,e,f),i=(j+k)/2,j===k?g=h=0:(l=j-k,h=i>.5?l/(2-j-k):l/(j+k),g=j===d?(e-f)/l+(f>e?6:0):j===e?(f-d)/l+2:(d-e)/l+4,g*=60),c[0]=g+.5|0,c[1]=100*h+.5|0,c[2]=100*i+.5|0),c},na=function(a,b){var c,d,e,f=a.match(oa)||[],g=0,h=f.length?"":a;for(c=0;c<f.length;c++)d=f[c],e=a.substr(g,a.indexOf(d,g)-g),g+=e.length+d.length,d=ma(d,b),3===d.length&&d.push(1),h+=e+(b?"hsla("+d[0]+","+d[1]+"%,"+d[2]+"%,"+d[3]:"rgba("+d.join(","))+")";return h+a.substr(g)},oa="(?:\\b(?:(?:rgb|rgba|hsl|hsla)\\(.+?\\))|\\B#(?:[0-9a-f]{3}){1,2}\\b";for(j in ka)oa+="|"+j+"\\b";oa=new RegExp(oa+")","gi"),g.colorStringFilter=function(a){var b,c=a[0]+a[1];oa.test(c)&&(b=-1!==c.indexOf("hsl(")||-1!==c.indexOf("hsla("),a[0]=na(a[0],b),a[1]=na(a[1],b)),oa.lastIndex=0},b.defaultStringFilter||(b.defaultStringFilter=g.colorStringFilter);var pa=function(a,b,c,d){if(null==a)return function(a){return a};var e,f=b?(a.match(oa)||[""])[0]:"",g=a.split(f).join("").match(u)||[],h=a.substr(0,a.indexOf(g[0])),i=")"===a.charAt(a.length-1)?")":"",j=-1!==a.indexOf(" ")?" ":",",k=g.length,l=k>0?g[0].replace(s,""):"";return k?e=b?function(a){var b,m,n,o;if("number"==typeof a)a+=l;else if(d&&I.test(a)){for(o=a.replace(I,"|").split("|"),n=0;n<o.length;n++)o[n]=e(o[n]);return o.join(",")}if(b=(a.match(oa)||[f])[0],m=a.split(b).join("").match(u)||[],n=m.length,k>n--)for(;++n<k;)m[n]=c?m[(n-1)/2|0]:g[n];return h+m.join(j)+j+b+i+(-1!==a.indexOf("inset")?" inset":"")}:function(a){var b,f,m;if("number"==typeof a)a+=l;else if(d&&I.test(a)){for(f=a.replace(I,"|").split("|"),m=0;m<f.length;m++)f[m]=e(f[m]);return f.join(",")}if(b=a.match(u)||[],m=b.length,k>m--)for(;++m<k;)b[m]=c?b[(m-1)/2|0]:g[m];return h+b.join(j)+i}:function(a){return a}},qa=function(a){return a=a.split(","),function(b,c,d,e,f,g,h){var i,j=(c+"").split(" ");for(h={},i=0;4>i;i++)h[a[i]]=j[i]=j[i]||j[(i-1)/2>>0];return e.parse(b,h,f,g)}},ra=(R._setPluginRatio=function(a){this.plugin.setRatio(a);for(var b,c,d,e,f,g=this.data,h=g.proxy,i=g.firstMPT,j=1e-6;i;)b=h[i.v],i.r?b=Math.round(b):j>b&&b>-j&&(b=0),i.t[i.p]=b,i=i._next;if(g.autoRotate&&(g.autoRotate.rotation=g.mod?g.mod(h.rotation,this.t):h.rotation),1===a||0===a)for(i=g.firstMPT,f=1===a?"e":"b";i;){if(c=i.t,c.type){if(1===c.type){for(e=c.xs0+c.s+c.xs1,d=1;d<c.l;d++)e+=c["xn"+d]+c["xs"+(d+1)];c[f]=e}}else c[f]=c.s+c.xs0;i=i._next}},function(a,b,c,d,e){this.t=a,this.p=b,this.v=c,this.r=e,d&&(d._prev=this,this._next=d)}),sa=(R._parseToProxy=function(a,b,c,d,e,f){var g,h,i,j,k,l=d,m={},n={},o=c._transform,p=M;for(c._transform=null,M=b,d=k=c.parse(a,b,d,e),M=p,f&&(c._transform=o,l&&(l._prev=null,l._prev&&(l._prev._next=null)));d&&d!==l;){if(d.type<=1&&(h=d.p,n[h]=d.s+d.c,m[h]=d.s,f||(j=new ra(d,"s",h,j,d.r),d.c=0),1===d.type))for(g=d.l;--g>0;)i="xn"+g,h=d.p+"_"+i,n[h]=d.data[i],m[h]=d[i],f||(j=new ra(d,i,h,j,d.rxp[i]));d=d._next}return{proxy:m,end:n,firstMPT:j,pt:k}},R.CSSPropTween=function(a,b,d,e,g,h,i,j,k,l,m){this.t=a,this.p=b,this.s=d,this.c=e,this.n=i||b,a instanceof sa||f.push(this.n),this.r=j,this.type=h||0,k&&(this.pr=k,c=!0),this.b=void 0===l?d:l,this.e=void 0===m?d+e:m,g&&(this._next=g,g._prev=this)}),ta=function(a,b,c,d,e,f){var g=new sa(a,b,c,d-c,e,-1,f);return g.b=c,g.e=g.xs0=d,g},ua=g.parseComplex=function(a,b,c,d,e,f,h,i,j,l){c=c||f||"","function"==typeof d&&(d=d(r,q)),h=new sa(a,b,0,0,h,l?2:1,null,!1,i,c,d),d+="",e&&oa.test(d+c)&&(d=[c,d],g.colorStringFilter(d),c=d[0],d=d[1]);var m,n,o,p,u,v,w,x,y,z,A,B,C,D=c.split(", ").join(",").split(" "),E=d.split(", ").join(",").split(" "),F=D.length,G=k!==!1;for((-1!==d.indexOf(",")||-1!==c.indexOf(","))&&(D=D.join(" ").replace(I,", ").split(" "),E=E.join(" ").replace(I,", ").split(" "),F=D.length),F!==E.length&&(D=(f||"").split(" "),F=D.length),h.plugin=j,h.setRatio=l,oa.lastIndex=0,m=0;F>m;m++)if(p=D[m],u=E[m],x=parseFloat(p),x||0===x)h.appendXtra("",x,ha(u,x),u.replace(t,""),G&&-1!==u.indexOf("px"),!0);else if(e&&oa.test(p))B=u.indexOf(")")+1,B=")"+(B?u.substr(B):""),C=-1!==u.indexOf("hsl")&&T,p=ma(p,C),u=ma(u,C),y=p.length+u.length>6,y&&!T&&0===u[3]?(h["xs"+h.l]+=h.l?" transparent":"transparent",h.e=h.e.split(E[m]).join("transparent")):(T||(y=!1),C?h.appendXtra(y?"hsla(":"hsl(",p[0],ha(u[0],p[0]),",",!1,!0).appendXtra("",p[1],ha(u[1],p[1]),"%,",!1).appendXtra("",p[2],ha(u[2],p[2]),y?"%,":"%"+B,!1):h.appendXtra(y?"rgba(":"rgb(",p[0],u[0]-p[0],",",!0,!0).appendXtra("",p[1],u[1]-p[1],",",!0).appendXtra("",p[2],u[2]-p[2],y?",":B,!0),y&&(p=p.length<4?1:p[3],h.appendXtra("",p,(u.length<4?1:u[3])-p,B,!1))),oa.lastIndex=0;else if(v=p.match(s)){if(w=u.match(t),!w||w.length!==v.length)return h;for(o=0,n=0;n<v.length;n++)A=v[n],z=p.indexOf(A,o),h.appendXtra(p.substr(o,z-o),Number(A),ha(w[n],A),"",G&&"px"===p.substr(z+A.length,2),0===n),o=z+A.length;h["xs"+h.l]+=p.substr(o)}else h["xs"+h.l]+=h.l||h["xs"+h.l]?" "+u:u;if(-1!==d.indexOf("=")&&h.data){for(B=h.xs0+h.data.s,m=1;m<h.l;m++)B+=h["xs"+m]+h.data["xn"+m];h.e=B+h["xs"+m]}return h.l||(h.type=-1,h.xs0=h.e),h.xfirst||h},va=9;for(j=sa.prototype,j.l=j.pr=0;--va>0;)j["xn"+va]=0,j["xs"+va]="";j.xs0="",j._next=j._prev=j.xfirst=j.data=j.plugin=j.setRatio=j.rxp=null,j.appendXtra=function(a,b,c,d,e,f){var g=this,h=g.l;return g["xs"+h]+=f&&(h||g["xs"+h])?" "+a:a||"",c||0===h||g.plugin?(g.l++,g.type=g.setRatio?2:1,g["xs"+g.l]=d||"",h>0?(g.data["xn"+h]=b+c,g.rxp["xn"+h]=e,g["xn"+h]=b,g.plugin||(g.xfirst=new sa(g,"xn"+h,b,c,g.xfirst||g,0,g.n,e,g.pr),g.xfirst.xs0=0),g):(g.data={s:b+c},g.rxp={},g.s=b,g.c=c,g.r=e,g)):(g["xs"+h]+=b+(d||""),g)};var wa=function(a,b){b=b||{},this.p=b.prefix?Y(a)||a:a,i[a]=i[this.p]=this,this.format=b.formatter||pa(b.defaultValue,b.color,b.collapsible,b.multi),b.parser&&(this.parse=b.parser),this.clrs=b.color,this.multi=b.multi,this.keyword=b.keyword,this.dflt=b.defaultValue,this.pr=b.priority||0},xa=R._registerComplexSpecialProp=function(a,b,c){"object"!=typeof b&&(b={parser:c});var d,e,f=a.split(","),g=b.defaultValue;for(c=c||[g],d=0;d<f.length;d++)b.prefix=0===d&&b.prefix,b.defaultValue=c[d]||g,e=new wa(f[d],b)},ya=R._registerPluginProp=function(a){if(!i[a]){var b=a.charAt(0).toUpperCase()+a.substr(1)+"Plugin";xa(a,{parser:function(a,c,d,e,f,g,j){var k=h.com.greensock.plugins[b];return k?(k._cssRegister(),i[d].parse(a,c,d,e,f,g,j)):(V("Error: "+b+" js file not loaded."),f)}})}};j=wa.prototype,j.parseComplex=function(a,b,c,d,e,f){var g,h,i,j,k,l,m=this.keyword;if(this.multi&&(I.test(c)||I.test(b)?(h=b.replace(I,"|").split("|"),i=c.replace(I,"|").split("|")):m&&(h=[b],i=[c])),i){for(j=i.length>h.length?i.length:h.length,g=0;j>g;g++)b=h[g]=h[g]||this.dflt,c=i[g]=i[g]||this.dflt,m&&(k=b.indexOf(m),l=c.indexOf(m),k!==l&&(-1===l?h[g]=h[g].split(m).join(""):-1===k&&(h[g]+=" "+m)));b=h.join(", "),c=i.join(", ")}return ua(a,this.p,b,c,this.clrs,this.dflt,d,this.pr,e,f)},j.parse=function(a,b,c,d,f,g,h){return this.parseComplex(a.style,this.format($(a,this.p,e,!1,this.dflt)),this.format(b),f,g)},g.registerSpecialProp=function(a,b,c){xa(a,{parser:function(a,d,e,f,g,h,i){var j=new sa(a,e,0,0,g,2,e,!1,c);return j.plugin=h,j.setRatio=b(a,d,f._tween,e),j},priority:c})},g.useSVGTransformAttr=m||n;var za,Aa="scaleX,scaleY,scaleZ,x,y,z,skewX,skewY,rotation,rotationX,rotationY,perspective,xPercent,yPercent".split(","),Ba=Y("transform"),Ca=W+"transform",Da=Y("transformOrigin"),Ea=null!==Y("perspective"),Fa=R.Transform=function(){this.perspective=parseFloat(g.defaultTransformPerspective)||0,this.force3D=g.defaultForce3D!==!1&&Ea?g.defaultForce3D||"auto":!1},Ga=window.SVGElement,Ha=function(a,b,c){var d,e=N.createElementNS("http://www.w3.org/2000/svg",a),f=/([a-z])([A-Z])/g;for(d in c)e.setAttributeNS(null,d.replace(f,"$1-$2").toLowerCase(),c[d]);return b.appendChild(e),e},Ia=N.documentElement,Ja=function(){var a,b,c,d=p||/Android/i.test(S)&&!window.chrome;return N.createElementNS&&!d&&(a=Ha("svg",Ia),b=Ha("rect",a,{width:100,height:50,x:100}),c=b.getBoundingClientRect().width,b.style[Da]="50% 50%",b.style[Ba]="scaleX(0.5)",d=c===b.getBoundingClientRect().width&&!(n&&Ea),Ia.removeChild(a)),d}(),Ka=function(a,b,c,d,e,f){var h,i,j,k,l,m,n,o,p,q,r,s,t,u,v=a._gsTransform,w=Oa(a,!0);v&&(t=v.xOrigin,u=v.yOrigin),(!d||(h=d.split(" ")).length<2)&&(n=a.getBBox(),b=ga(b).split(" "),h=[(-1!==b[0].indexOf("%")?parseFloat(b[0])/100*n.width:parseFloat(b[0]))+n.x,(-1!==b[1].indexOf("%")?parseFloat(b[1])/100*n.height:parseFloat(b[1]))+n.y]),c.xOrigin=k=parseFloat(h[0]),c.yOrigin=l=parseFloat(h[1]),d&&w!==Na&&(m=w[0],n=w[1],o=w[2],p=w[3],q=w[4],r=w[5],s=m*p-n*o,i=k*(p/s)+l*(-o/s)+(o*r-p*q)/s,j=k*(-n/s)+l*(m/s)-(m*r-n*q)/s,k=c.xOrigin=h[0]=i,l=c.yOrigin=h[1]=j),v&&(f&&(c.xOffset=v.xOffset,c.yOffset=v.yOffset,v=c),e||e!==!1&&g.defaultSmoothOrigin!==!1?(i=k-t,j=l-u,v.xOffset+=i*w[0]+j*w[2]-i,v.yOffset+=i*w[1]+j*w[3]-j):v.xOffset=v.yOffset=0),f||a.setAttribute("data-svg-origin",h.join(" "))},La=function(a){try{return a.getBBox()}catch(a){}},Ma=function(a){return!!(Ga&&a.getBBox&&a.getCTM&&La(a)&&(!a.parentNode||a.parentNode.getBBox&&a.parentNode.getCTM))},Na=[1,0,0,1,0,0],Oa=function(a,b){var c,d,e,f,g,h,i=a._gsTransform||new Fa,j=1e5,k=a.style;if(Ba?d=$(a,Ca,null,!0):a.currentStyle&&(d=a.currentStyle.filter.match(G),d=d&&4===d.length?[d[0].substr(4),Number(d[2].substr(4)),Number(d[1].substr(4)),d[3].substr(4),i.x||0,i.y||0].join(","):""),c=!d||"none"===d||"matrix(1, 0, 0, 1, 0, 0)"===d,c&&Ba&&((h="none"===Z(a).display)||!a.parentNode)&&(h&&(f=k.display,k.display="block"),a.parentNode||(g=1,Ia.appendChild(a)),d=$(a,Ca,null,!0),c=!d||"none"===d||"matrix(1, 0, 0, 1, 0, 0)"===d,f?k.display=f:h&&Ta(k,"display"),g&&Ia.removeChild(a)),(i.svg||a.getBBox&&Ma(a))&&(c&&-1!==(k[Ba]+"").indexOf("matrix")&&(d=k[Ba],c=0),e=a.getAttribute("transform"),c&&e&&(-1!==e.indexOf("matrix")?(d=e,c=0):-1!==e.indexOf("translate")&&(d="matrix(1,0,0,1,"+e.match(/(?:\-|\b)[\d\-\.e]+\b/gi).join(",")+")",c=0))),c)return Na;for(e=(d||"").match(s)||[],va=e.length;--va>-1;)f=Number(e[va]),e[va]=(g=f-(f|=0))?(g*j+(0>g?-.5:.5)|0)/j+f:f;return b&&e.length>6?[e[0],e[1],e[4],e[5],e[12],e[13]]:e},Pa=R.getTransform=function(a,c,d,e){if(a._gsTransform&&d&&!e)return a._gsTransform;var f,h,i,j,k,l,m=d?a._gsTransform||new Fa:new Fa,n=m.scaleX<0,o=2e-5,p=1e5,q=Ea?parseFloat($(a,Da,c,!1,"0 0 0").split(" ")[2])||m.zOrigin||0:0,r=parseFloat(g.defaultTransformPerspective)||0;if(m.svg=!(!a.getBBox||!Ma(a)),m.svg&&(Ka(a,$(a,Da,c,!1,"50% 50%")+"",m,a.getAttribute("data-svg-origin")),za=g.useSVGTransformAttr||Ja),f=Oa(a),f!==Na){if(16===f.length){var s,t,u,v,w,x=f[0],y=f[1],z=f[2],A=f[3],B=f[4],C=f[5],D=f[6],E=f[7],F=f[8],G=f[9],H=f[10],I=f[12],J=f[13],K=f[14],M=f[11],N=Math.atan2(D,H);m.zOrigin&&(K=-m.zOrigin,I=F*K-f[12],J=G*K-f[13],K=H*K+m.zOrigin-f[14]),m.rotationX=N*L,N&&(v=Math.cos(-N),w=Math.sin(-N),s=B*v+F*w,t=C*v+G*w,u=D*v+H*w,F=B*-w+F*v,G=C*-w+G*v,H=D*-w+H*v,M=E*-w+M*v,B=s,C=t,D=u),N=Math.atan2(-z,H),m.rotationY=N*L,N&&(v=Math.cos(-N),w=Math.sin(-N),s=x*v-F*w,t=y*v-G*w,u=z*v-H*w,G=y*w+G*v,H=z*w+H*v,M=A*w+M*v,x=s,y=t,z=u),N=Math.atan2(y,x),m.rotation=N*L,N&&(v=Math.cos(-N),w=Math.sin(-N),x=x*v+B*w,t=y*v+C*w,C=y*-w+C*v,D=z*-w+D*v,y=t),m.rotationX&&Math.abs(m.rotationX)+Math.abs(m.rotation)>359.9&&(m.rotationX=m.rotation=0,m.rotationY=180-m.rotationY),m.scaleX=(Math.sqrt(x*x+y*y)*p+.5|0)/p,m.scaleY=(Math.sqrt(C*C+G*G)*p+.5|0)/p,m.scaleZ=(Math.sqrt(D*D+H*H)*p+.5|0)/p,m.rotationX||m.rotationY?m.skewX=0:(m.skewX=B||C?Math.atan2(B,C)*L+m.rotation:m.skewX||0,Math.abs(m.skewX)>90&&Math.abs(m.skewX)<270&&(n?(m.scaleX*=-1,m.skewX+=m.rotation<=0?180:-180,m.rotation+=m.rotation<=0?180:-180):(m.scaleY*=-1,m.skewX+=m.skewX<=0?180:-180))),m.perspective=M?1/(0>M?-M:M):0,m.x=I,m.y=J,m.z=K,m.svg&&(m.x-=m.xOrigin-(m.xOrigin*x-m.yOrigin*B),m.y-=m.yOrigin-(m.yOrigin*y-m.xOrigin*C))}else if(!Ea||e||!f.length||m.x!==f[4]||m.y!==f[5]||!m.rotationX&&!m.rotationY){var O=f.length>=6,P=O?f[0]:1,Q=f[1]||0,R=f[2]||0,S=O?f[3]:1;m.x=f[4]||0,m.y=f[5]||0,i=Math.sqrt(P*P+Q*Q),j=Math.sqrt(S*S+R*R),k=P||Q?Math.atan2(Q,P)*L:m.rotation||0,l=R||S?Math.atan2(R,S)*L+k:m.skewX||0,Math.abs(l)>90&&Math.abs(l)<270&&(n?(i*=-1,l+=0>=k?180:-180,k+=0>=k?180:-180):(j*=-1,l+=0>=l?180:-180)),m.scaleX=i,m.scaleY=j,m.rotation=k,m.skewX=l,Ea&&(m.rotationX=m.rotationY=m.z=0,m.perspective=r,m.scaleZ=1),m.svg&&(m.x-=m.xOrigin-(m.xOrigin*P+m.yOrigin*R),m.y-=m.yOrigin-(m.xOrigin*Q+m.yOrigin*S))}m.zOrigin=q;for(h in m)m[h]<o&&m[h]>-o&&(m[h]=0)}return d&&(a._gsTransform=m,m.svg&&(za&&a.style[Ba]?b.delayedCall(.001,function(){Ta(a.style,Ba)}):!za&&a.getAttribute("transform")&&b.delayedCall(.001,function(){a.removeAttribute("transform")}))),m},Qa=function(a){var b,c,d=this.data,e=-d.rotation*K,f=e+d.skewX*K,g=1e5,h=(Math.cos(e)*d.scaleX*g|0)/g,i=(Math.sin(e)*d.scaleX*g|0)/g,j=(Math.sin(f)*-d.scaleY*g|0)/g,k=(Math.cos(f)*d.scaleY*g|0)/g,l=this.t.style,m=this.t.currentStyle;if(m){c=i,i=-j,j=-c,b=m.filter,l.filter="";var n,o,q=this.t.offsetWidth,r=this.t.offsetHeight,s="absolute"!==m.position,t="progid:DXImageTransform.Microsoft.Matrix(M11="+h+", M12="+i+", M21="+j+", M22="+k,u=d.x+q*d.xPercent/100,v=d.y+r*d.yPercent/100;if(null!=d.ox&&(n=(d.oxp?q*d.ox*.01:d.ox)-q/2,o=(d.oyp?r*d.oy*.01:d.oy)-r/2,u+=n-(n*h+o*i),v+=o-(n*j+o*k)),s?(n=q/2,o=r/2,t+=", Dx="+(n-(n*h+o*i)+u)+", Dy="+(o-(n*j+o*k)+v)+")"):t+=", sizingMethod='auto expand')",-1!==b.indexOf("DXImageTransform.Microsoft.Matrix(")?l.filter=b.replace(H,t):l.filter=t+" "+b,(0===a||1===a)&&1===h&&0===i&&0===j&&1===k&&(s&&-1===t.indexOf("Dx=0, Dy=0")||x.test(b)&&100!==parseFloat(RegExp.$1)||-1===b.indexOf(b.indexOf("Alpha"))&&l.removeAttribute("filter")),!s){var y,z,A,B=8>p?1:-1;for(n=d.ieOffsetX||0,o=d.ieOffsetY||0,d.ieOffsetX=Math.round((q-((0>h?-h:h)*q+(0>i?-i:i)*r))/2+u),d.ieOffsetY=Math.round((r-((0>k?-k:k)*r+(0>j?-j:j)*q))/2+v),va=0;4>va;va++)z=ea[va],y=m[z],c=-1!==y.indexOf("px")?parseFloat(y):_(this.t,z,parseFloat(y),y.replace(w,""))||0,A=c!==d[z]?2>va?-d.ieOffsetX:-d.ieOffsetY:2>va?n-d.ieOffsetX:o-d.ieOffsetY,l[z]=(d[z]=Math.round(c-A*(0===va||2===va?1:B)))+"px"}}},Ra=R.set3DTransformRatio=R.setTransformRatio=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,o,p,q,r,s,t,u,v,w,x,y,z=this.data,A=this.t.style,B=z.rotation,C=z.rotationX,D=z.rotationY,E=z.scaleX,F=z.scaleY,G=z.scaleZ,H=z.x,I=z.y,J=z.z,L=z.svg,M=z.perspective,N=z.force3D;if(((1===a||0===a)&&"auto"===N&&(this.tween._totalTime===this.tween._totalDuration||!this.tween._totalTime)||!N)&&!J&&!M&&!D&&!C&&1===G||za&&L||!Ea)return void(B||z.skewX||L?(B*=K,x=z.skewX*K,y=1e5,b=Math.cos(B)*E,e=Math.sin(B)*E,c=Math.sin(B-x)*-F,f=Math.cos(B-x)*F,x&&"simple"===z.skewType&&(s=Math.tan(x-z.skewY*K),s=Math.sqrt(1+s*s),c*=s,f*=s,z.skewY&&(s=Math.tan(z.skewY*K),s=Math.sqrt(1+s*s),b*=s,e*=s)),L&&(H+=z.xOrigin-(z.xOrigin*b+z.yOrigin*c)+z.xOffset,I+=z.yOrigin-(z.xOrigin*e+z.yOrigin*f)+z.yOffset,za&&(z.xPercent||z.yPercent)&&(p=this.t.getBBox(),H+=.01*z.xPercent*p.width,I+=.01*z.yPercent*p.height),p=1e-6,p>H&&H>-p&&(H=0),p>I&&I>-p&&(I=0)),u=(b*y|0)/y+","+(e*y|0)/y+","+(c*y|0)/y+","+(f*y|0)/y+","+H+","+I+")",L&&za?this.t.setAttribute("transform","matrix("+u):A[Ba]=(z.xPercent||z.yPercent?"translate("+z.xPercent+"%,"+z.yPercent+"%) matrix(":"matrix(")+u):A[Ba]=(z.xPercent||z.yPercent?"translate("+z.xPercent+"%,"+z.yPercent+"%) matrix(":"matrix(")+E+",0,0,"+F+","+H+","+I+")");if(n&&(p=1e-4,p>E&&E>-p&&(E=G=2e-5),p>F&&F>-p&&(F=G=2e-5),!M||z.z||z.rotationX||z.rotationY||(M=0)),B||z.skewX)B*=K,q=b=Math.cos(B),r=e=Math.sin(B),z.skewX&&(B-=z.skewX*K,q=Math.cos(B),r=Math.sin(B),"simple"===z.skewType&&(s=Math.tan((z.skewX-z.skewY)*K),s=Math.sqrt(1+s*s),q*=s,r*=s,z.skewY&&(s=Math.tan(z.skewY*K),s=Math.sqrt(1+s*s),b*=s,e*=s))),c=-r,f=q;else{if(!(D||C||1!==G||M||L))return void(A[Ba]=(z.xPercent||z.yPercent?"translate("+z.xPercent+"%,"+z.yPercent+"%) translate3d(":"translate3d(")+H+"px,"+I+"px,"+J+"px)"+(1!==E||1!==F?" scale("+E+","+F+")":""));b=f=1,c=e=0}j=1,d=g=h=i=k=l=0,m=M?-1/M:0,o=z.zOrigin,p=1e-6,v=",",w="0",B=D*K,B&&(q=Math.cos(B),r=Math.sin(B),h=-r,k=m*-r,d=b*r,g=e*r,j=q,m*=q,b*=q,e*=q),B=C*K,B&&(q=Math.cos(B),r=Math.sin(B),s=c*q+d*r,t=f*q+g*r,i=j*r,l=m*r,d=c*-r+d*q,g=f*-r+g*q,j*=q,m*=q,c=s,f=t),1!==G&&(d*=G,g*=G,j*=G,m*=G),1!==F&&(c*=F,f*=F,i*=F,l*=F),1!==E&&(b*=E,e*=E,h*=E,k*=E),(o||L)&&(o&&(H+=d*-o,I+=g*-o,J+=j*-o+o),L&&(H+=z.xOrigin-(z.xOrigin*b+z.yOrigin*c)+z.xOffset,I+=z.yOrigin-(z.xOrigin*e+z.yOrigin*f)+z.yOffset),p>H&&H>-p&&(H=w),p>I&&I>-p&&(I=w),p>J&&J>-p&&(J=0)),u=z.xPercent||z.yPercent?"translate("+z.xPercent+"%,"+z.yPercent+"%) matrix3d(":"matrix3d(",u+=(p>b&&b>-p?w:b)+v+(p>e&&e>-p?w:e)+v+(p>h&&h>-p?w:h),u+=v+(p>k&&k>-p?w:k)+v+(p>c&&c>-p?w:c)+v+(p>f&&f>-p?w:f),C||D||1!==G?(u+=v+(p>i&&i>-p?w:i)+v+(p>l&&l>-p?w:l)+v+(p>d&&d>-p?w:d),u+=v+(p>g&&g>-p?w:g)+v+(p>j&&j>-p?w:j)+v+(p>m&&m>-p?w:m)+v):u+=",0,0,0,0,1,0,",u+=H+v+I+v+J+v+(M?1+-J/M:1)+")",A[Ba]=u};j=Fa.prototype,j.x=j.y=j.z=j.skewX=j.skewY=j.rotation=j.rotationX=j.rotationY=j.zOrigin=j.xPercent=j.yPercent=j.xOffset=j.yOffset=0,j.scaleX=j.scaleY=j.scaleZ=1,xa("transform,scale,scaleX,scaleY,scaleZ,x,y,z,rotation,rotationX,rotationY,rotationZ,skewX,skewY,shortRotation,shortRotationX,shortRotationY,shortRotationZ,transformOrigin,svgOrigin,transformPerspective,directionalRotation,parseTransform,force3D,skewType,xPercent,yPercent,smoothOrigin",{parser:function(a,b,c,d,f,h,i){if(d._lastParsedTransform===i)return f;d._lastParsedTransform=i;var j;"function"==typeof i[c]&&(j=i[c],i[c]=b);var k,l,m,n,o,p,s,t,u,v=a._gsTransform,w=a.style,x=1e-6,y=Aa.length,z=i,A={},B="transformOrigin",C=Pa(a,e,!0,z.parseTransform),D=z.transform&&("function"==typeof z.transform?z.transform(r,q):z.transform);if(d._transform=C,D&&"string"==typeof D&&Ba)l=P.style,l[Ba]=D,l.display="block",l.position="absolute",N.body.appendChild(P),k=Pa(P,null,!1),C.svg&&(p=C.xOrigin,s=C.yOrigin,k.x-=C.xOffset,k.y-=C.yOffset,(z.transformOrigin||z.svgOrigin)&&(D={},Ka(a,ga(z.transformOrigin),D,z.svgOrigin,z.smoothOrigin,!0),p=D.xOrigin,s=D.yOrigin,k.x-=D.xOffset-C.xOffset,k.y-=D.yOffset-C.yOffset),(p||s)&&(t=Oa(P,!0),k.x-=p-(p*t[0]+s*t[2]),k.y-=s-(p*t[1]+s*t[3]))),N.body.removeChild(P),k.perspective||(k.perspective=C.perspective),null!=z.xPercent&&(k.xPercent=ia(z.xPercent,C.xPercent)),null!=z.yPercent&&(k.yPercent=ia(z.yPercent,C.yPercent));else if("object"==typeof z){if(k={scaleX:ia(null!=z.scaleX?z.scaleX:z.scale,C.scaleX),scaleY:ia(null!=z.scaleY?z.scaleY:z.scale,C.scaleY),scaleZ:ia(z.scaleZ,C.scaleZ),x:ia(z.x,C.x),y:ia(z.y,C.y),z:ia(z.z,C.z),xPercent:ia(z.xPercent,C.xPercent),yPercent:ia(z.yPercent,C.yPercent),perspective:ia(z.transformPerspective,C.perspective)},o=z.directionalRotation,null!=o)if("object"==typeof o)for(l in o)z[l]=o[l];else z.rotation=o;"string"==typeof z.x&&-1!==z.x.indexOf("%")&&(k.x=0,k.xPercent=ia(z.x,C.xPercent)),"string"==typeof z.y&&-1!==z.y.indexOf("%")&&(k.y=0,k.yPercent=ia(z.y,C.yPercent)),k.rotation=ja("rotation"in z?z.rotation:"shortRotation"in z?z.shortRotation+"_short":"rotationZ"in z?z.rotationZ:C.rotation-C.skewY,C.rotation-C.skewY,"rotation",A),Ea&&(k.rotationX=ja("rotationX"in z?z.rotationX:"shortRotationX"in z?z.shortRotationX+"_short":C.rotationX||0,C.rotationX,"rotationX",A),k.rotationY=ja("rotationY"in z?z.rotationY:"shortRotationY"in z?z.shortRotationY+"_short":C.rotationY||0,C.rotationY,"rotationY",A)),k.skewX=ja(z.skewX,C.skewX-C.skewY),(k.skewY=ja(z.skewY,C.skewY))&&(k.skewX+=k.skewY,k.rotation+=k.skewY)}for(Ea&&null!=z.force3D&&(C.force3D=z.force3D,n=!0),C.skewType=z.skewType||C.skewType||g.defaultSkewType,m=C.force3D||C.z||C.rotationX||C.rotationY||k.z||k.rotationX||k.rotationY||k.perspective,m||null==z.scale||(k.scaleZ=1);--y>-1;)u=Aa[y],D=k[u]-C[u],(D>x||-x>D||null!=z[u]||null!=M[u])&&(n=!0,
f=new sa(C,u,C[u],D,f),u in A&&(f.e=A[u]),f.xs0=0,f.plugin=h,d._overwriteProps.push(f.n));return D=z.transformOrigin,C.svg&&(D||z.svgOrigin)&&(p=C.xOffset,s=C.yOffset,Ka(a,ga(D),k,z.svgOrigin,z.smoothOrigin),f=ta(C,"xOrigin",(v?C:k).xOrigin,k.xOrigin,f,B),f=ta(C,"yOrigin",(v?C:k).yOrigin,k.yOrigin,f,B),(p!==C.xOffset||s!==C.yOffset)&&(f=ta(C,"xOffset",v?p:C.xOffset,C.xOffset,f,B),f=ta(C,"yOffset",v?s:C.yOffset,C.yOffset,f,B)),D=za?null:"0px 0px"),(D||Ea&&m&&C.zOrigin)&&(Ba?(n=!0,u=Da,D=(D||$(a,u,e,!1,"50% 50%"))+"",f=new sa(w,u,0,0,f,-1,B),f.b=w[u],f.plugin=h,Ea?(l=C.zOrigin,D=D.split(" "),C.zOrigin=(D.length>2&&(0===l||"0px"!==D[2])?parseFloat(D[2]):l)||0,f.xs0=f.e=D[0]+" "+(D[1]||"50%")+" 0px",f=new sa(C,"zOrigin",0,0,f,-1,f.n),f.b=l,f.xs0=f.e=C.zOrigin):f.xs0=f.e=D):ga(D+"",C)),n&&(d._transformType=C.svg&&za||!m&&3!==this._transformType?2:3),j&&(i[c]=j),f},prefix:!0}),xa("boxShadow",{defaultValue:"0px 0px 0px 0px #999",prefix:!0,color:!0,multi:!0,keyword:"inset"}),xa("borderRadius",{defaultValue:"0px",parser:function(a,b,c,f,g,h){b=this.format(b);var i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y=["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],z=a.style;for(q=parseFloat(a.offsetWidth),r=parseFloat(a.offsetHeight),i=b.split(" "),j=0;j<y.length;j++)this.p.indexOf("border")&&(y[j]=Y(y[j])),m=l=$(a,y[j],e,!1,"0px"),-1!==m.indexOf(" ")&&(l=m.split(" "),m=l[0],l=l[1]),n=k=i[j],o=parseFloat(m),t=m.substr((o+"").length),u="="===n.charAt(1),u?(p=parseInt(n.charAt(0)+"1",10),n=n.substr(2),p*=parseFloat(n),s=n.substr((p+"").length-(0>p?1:0))||""):(p=parseFloat(n),s=n.substr((p+"").length)),""===s&&(s=d[c]||t),s!==t&&(v=_(a,"borderLeft",o,t),w=_(a,"borderTop",o,t),"%"===s?(m=v/q*100+"%",l=w/r*100+"%"):"em"===s?(x=_(a,"borderLeft",1,"em"),m=v/x+"em",l=w/x+"em"):(m=v+"px",l=w+"px"),u&&(n=parseFloat(m)+p+s,k=parseFloat(l)+p+s)),g=ua(z,y[j],m+" "+l,n+" "+k,!1,"0px",g);return g},prefix:!0,formatter:pa("0px 0px 0px 0px",!1,!0)}),xa("borderBottomLeftRadius,borderBottomRightRadius,borderTopLeftRadius,borderTopRightRadius",{defaultValue:"0px",parser:function(a,b,c,d,f,g){return ua(a.style,c,this.format($(a,c,e,!1,"0px 0px")),this.format(b),!1,"0px",f)},prefix:!0,formatter:pa("0px 0px",!1,!0)}),xa("backgroundPosition",{defaultValue:"0 0",parser:function(a,b,c,d,f,g){var h,i,j,k,l,m,n="background-position",o=e||Z(a,null),q=this.format((o?p?o.getPropertyValue(n+"-x")+" "+o.getPropertyValue(n+"-y"):o.getPropertyValue(n):a.currentStyle.backgroundPositionX+" "+a.currentStyle.backgroundPositionY)||"0 0"),r=this.format(b);if(-1!==q.indexOf("%")!=(-1!==r.indexOf("%"))&&r.split(",").length<2&&(m=$(a,"backgroundImage").replace(D,""),m&&"none"!==m)){for(h=q.split(" "),i=r.split(" "),Q.setAttribute("src",m),j=2;--j>-1;)q=h[j],k=-1!==q.indexOf("%"),k!==(-1!==i[j].indexOf("%"))&&(l=0===j?a.offsetWidth-Q.width:a.offsetHeight-Q.height,h[j]=k?parseFloat(q)/100*l+"px":parseFloat(q)/l*100+"%");q=h.join(" ")}return this.parseComplex(a.style,q,r,f,g)},formatter:ga}),xa("backgroundSize",{defaultValue:"0 0",formatter:function(a){return a+="",ga(-1===a.indexOf(" ")?a+" "+a:a)}}),xa("perspective",{defaultValue:"0px",prefix:!0}),xa("perspectiveOrigin",{defaultValue:"50% 50%",prefix:!0}),xa("transformStyle",{prefix:!0}),xa("backfaceVisibility",{prefix:!0}),xa("userSelect",{prefix:!0}),xa("margin",{parser:qa("marginTop,marginRight,marginBottom,marginLeft")}),xa("padding",{parser:qa("paddingTop,paddingRight,paddingBottom,paddingLeft")}),xa("clip",{defaultValue:"rect(0px,0px,0px,0px)",parser:function(a,b,c,d,f,g){var h,i,j;return 9>p?(i=a.currentStyle,j=8>p?" ":",",h="rect("+i.clipTop+j+i.clipRight+j+i.clipBottom+j+i.clipLeft+")",b=this.format(b).split(",").join(j)):(h=this.format($(a,this.p,e,!1,this.dflt)),b=this.format(b)),this.parseComplex(a.style,h,b,f,g)}}),xa("textShadow",{defaultValue:"0px 0px 0px #999",color:!0,multi:!0}),xa("autoRound,strictUnits",{parser:function(a,b,c,d,e){return e}}),xa("border",{defaultValue:"0px solid #000",parser:function(a,b,c,d,f,g){var h=$(a,"borderTopWidth",e,!1,"0px"),i=this.format(b).split(" "),j=i[0].replace(w,"");return"px"!==j&&(h=parseFloat(h)/_(a,"borderTopWidth",1,j)+j),this.parseComplex(a.style,this.format(h+" "+$(a,"borderTopStyle",e,!1,"solid")+" "+$(a,"borderTopColor",e,!1,"#000")),i.join(" "),f,g)},color:!0,formatter:function(a){var b=a.split(" ");return b[0]+" "+(b[1]||"solid")+" "+(a.match(oa)||["#000"])[0]}}),xa("borderWidth",{parser:qa("borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth")}),xa("float,cssFloat,styleFloat",{parser:function(a,b,c,d,e,f){var g=a.style,h="cssFloat"in g?"cssFloat":"styleFloat";return new sa(g,h,0,0,e,-1,c,!1,0,g[h],b)}});var Sa=function(a){var b,c=this.t,d=c.filter||$(this.data,"filter")||"",e=this.s+this.c*a|0;100===e&&(-1===d.indexOf("atrix(")&&-1===d.indexOf("radient(")&&-1===d.indexOf("oader(")?(c.removeAttribute("filter"),b=!$(this.data,"filter")):(c.filter=d.replace(z,""),b=!0)),b||(this.xn1&&(c.filter=d=d||"alpha(opacity="+e+")"),-1===d.indexOf("pacity")?0===e&&this.xn1||(c.filter=d+" alpha(opacity="+e+")"):c.filter=d.replace(x,"opacity="+e))};xa("opacity,alpha,autoAlpha",{defaultValue:"1",parser:function(a,b,c,d,f,g){var h=parseFloat($(a,"opacity",e,!1,"1")),i=a.style,j="autoAlpha"===c;return"string"==typeof b&&"="===b.charAt(1)&&(b=("-"===b.charAt(0)?-1:1)*parseFloat(b.substr(2))+h),j&&1===h&&"hidden"===$(a,"visibility",e)&&0!==b&&(h=0),T?f=new sa(i,"opacity",h,b-h,f):(f=new sa(i,"opacity",100*h,100*(b-h),f),f.xn1=j?1:0,i.zoom=1,f.type=2,f.b="alpha(opacity="+f.s+")",f.e="alpha(opacity="+(f.s+f.c)+")",f.data=a,f.plugin=g,f.setRatio=Sa),j&&(f=new sa(i,"visibility",0,0,f,-1,null,!1,0,0!==h?"inherit":"hidden",0===b?"hidden":"inherit"),f.xs0="inherit",d._overwriteProps.push(f.n),d._overwriteProps.push(c)),f}});var Ta=function(a,b){b&&(a.removeProperty?(("ms"===b.substr(0,2)||"webkit"===b.substr(0,6))&&(b="-"+b),a.removeProperty(b.replace(B,"-$1").toLowerCase())):a.removeAttribute(b))},Ua=function(a){if(this.t._gsClassPT=this,1===a||0===a){this.t.setAttribute("class",0===a?this.b:this.e);for(var b=this.data,c=this.t.style;b;)b.v?c[b.p]=b.v:Ta(c,b.p),b=b._next;1===a&&this.t._gsClassPT===this&&(this.t._gsClassPT=null)}else this.t.getAttribute("class")!==this.e&&this.t.setAttribute("class",this.e)};xa("className",{parser:function(a,b,d,f,g,h,i){var j,k,l,m,n,o=a.getAttribute("class")||"",p=a.style.cssText;if(g=f._classNamePT=new sa(a,d,0,0,g,2),g.setRatio=Ua,g.pr=-11,c=!0,g.b=o,k=ba(a,e),l=a._gsClassPT){for(m={},n=l.data;n;)m[n.p]=1,n=n._next;l.setRatio(1)}return a._gsClassPT=g,g.e="="!==b.charAt(1)?b:o.replace(new RegExp("(?:\\s|^)"+b.substr(2)+"(?![\\w-])"),"")+("+"===b.charAt(0)?" "+b.substr(2):""),a.setAttribute("class",g.e),j=ca(a,k,ba(a),i,m),a.setAttribute("class",o),g.data=j.firstMPT,a.style.cssText=p,g=g.xfirst=f.parse(a,j.difs,g,h)}});var Va=function(a){if((1===a||0===a)&&this.data._totalTime===this.data._totalDuration&&"isFromStart"!==this.data.data){var b,c,d,e,f,g=this.t.style,h=i.transform.parse;if("all"===this.e)g.cssText="",e=!0;else for(b=this.e.split(" ").join("").split(","),d=b.length;--d>-1;)c=b[d],i[c]&&(i[c].parse===h?e=!0:c="transformOrigin"===c?Da:i[c].p),Ta(g,c);e&&(Ta(g,Ba),f=this.t._gsTransform,f&&(f.svg&&(this.t.removeAttribute("data-svg-origin"),this.t.removeAttribute("transform")),delete this.t._gsTransform))}};for(xa("clearProps",{parser:function(a,b,d,e,f){return f=new sa(a,d,0,0,f,2),f.setRatio=Va,f.e=b,f.pr=-10,f.data=e._tween,c=!0,f}}),j="bezier,throwProps,physicsProps,physics2D".split(","),va=j.length;va--;)ya(j[va]);j=g.prototype,j._firstPT=j._lastParsedTransform=j._transform=null,j._onInitTween=function(a,b,h,j){if(!a.nodeType)return!1;this._target=q=a,this._tween=h,this._vars=b,r=j,k=b.autoRound,c=!1,d=b.suffixMap||g.suffixMap,e=Z(a,""),f=this._overwriteProps;var n,p,s,t,u,v,w,x,z,A=a.style;if(l&&""===A.zIndex&&(n=$(a,"zIndex",e),("auto"===n||""===n)&&this._addLazySet(A,"zIndex",0)),"string"==typeof b&&(t=A.cssText,n=ba(a,e),A.cssText=t+";"+b,n=ca(a,n,ba(a)).difs,!T&&y.test(b)&&(n.opacity=parseFloat(RegExp.$1)),b=n,A.cssText=t),b.className?this._firstPT=p=i.className.parse(a,b.className,"className",this,null,null,b):this._firstPT=p=this.parse(a,b,null),this._transformType){for(z=3===this._transformType,Ba?m&&(l=!0,""===A.zIndex&&(w=$(a,"zIndex",e),("auto"===w||""===w)&&this._addLazySet(A,"zIndex",0)),o&&this._addLazySet(A,"WebkitBackfaceVisibility",this._vars.WebkitBackfaceVisibility||(z?"visible":"hidden"))):A.zoom=1,s=p;s&&s._next;)s=s._next;x=new sa(a,"transform",0,0,null,2),this._linkCSSP(x,null,s),x.setRatio=Ba?Ra:Qa,x.data=this._transform||Pa(a,e,!0),x.tween=h,x.pr=-1,f.pop()}if(c){for(;p;){for(v=p._next,s=t;s&&s.pr>p.pr;)s=s._next;(p._prev=s?s._prev:u)?p._prev._next=p:t=p,(p._next=s)?s._prev=p:u=p,p=v}this._firstPT=t}return!0},j.parse=function(a,b,c,f){var g,h,j,l,m,n,o,p,s,t,u=a.style;for(g in b)n=b[g],"function"==typeof n&&(n=n(r,q)),h=i[g],h?c=h.parse(a,n,g,this,c,f,b):(m=$(a,g,e)+"",s="string"==typeof n,"color"===g||"fill"===g||"stroke"===g||-1!==g.indexOf("Color")||s&&A.test(n)?(s||(n=ma(n),n=(n.length>3?"rgba(":"rgb(")+n.join(",")+")"),c=ua(u,g,m,n,!0,"transparent",c,0,f)):s&&J.test(n)?c=ua(u,g,m,n,!0,null,c,0,f):(j=parseFloat(m),o=j||0===j?m.substr((j+"").length):"",(""===m||"auto"===m)&&("width"===g||"height"===g?(j=fa(a,g,e),o="px"):"left"===g||"top"===g?(j=aa(a,g,e),o="px"):(j="opacity"!==g?0:1,o="")),t=s&&"="===n.charAt(1),t?(l=parseInt(n.charAt(0)+"1",10),n=n.substr(2),l*=parseFloat(n),p=n.replace(w,"")):(l=parseFloat(n),p=s?n.replace(w,""):""),""===p&&(p=g in d?d[g]:o),n=l||0===l?(t?l+j:l)+p:b[g],o!==p&&""!==p&&(l||0===l)&&j&&(j=_(a,g,j,o),"%"===p?(j/=_(a,g,100,"%")/100,b.strictUnits!==!0&&(m=j+"%")):"em"===p||"rem"===p||"vw"===p||"vh"===p?j/=_(a,g,1,p):"px"!==p&&(l=_(a,g,l,p),p="px"),t&&(l||0===l)&&(n=l+j+p)),t&&(l+=j),!j&&0!==j||!l&&0!==l?void 0!==u[g]&&(n||n+""!="NaN"&&null!=n)?(c=new sa(u,g,l||j||0,0,c,-1,g,!1,0,m,n),c.xs0="none"!==n||"display"!==g&&-1===g.indexOf("Style")?n:m):V("invalid "+g+" tween value: "+b[g]):(c=new sa(u,g,j,l-j,c,0,g,k!==!1&&("px"===p||"zIndex"===g),0,m,n),c.xs0=p))),f&&c&&!c.plugin&&(c.plugin=f);return c},j.setRatio=function(a){var b,c,d,e=this._firstPT,f=1e-6;if(1!==a||this._tween._time!==this._tween._duration&&0!==this._tween._time)if(a||this._tween._time!==this._tween._duration&&0!==this._tween._time||this._tween._rawPrevTime===-1e-6)for(;e;){if(b=e.c*a+e.s,e.r?b=Math.round(b):f>b&&b>-f&&(b=0),e.type)if(1===e.type)if(d=e.l,2===d)e.t[e.p]=e.xs0+b+e.xs1+e.xn1+e.xs2;else if(3===d)e.t[e.p]=e.xs0+b+e.xs1+e.xn1+e.xs2+e.xn2+e.xs3;else if(4===d)e.t[e.p]=e.xs0+b+e.xs1+e.xn1+e.xs2+e.xn2+e.xs3+e.xn3+e.xs4;else if(5===d)e.t[e.p]=e.xs0+b+e.xs1+e.xn1+e.xs2+e.xn2+e.xs3+e.xn3+e.xs4+e.xn4+e.xs5;else{for(c=e.xs0+b+e.xs1,d=1;d<e.l;d++)c+=e["xn"+d]+e["xs"+(d+1)];e.t[e.p]=c}else-1===e.type?e.t[e.p]=e.xs0:e.setRatio&&e.setRatio(a);else e.t[e.p]=b+e.xs0;e=e._next}else for(;e;)2!==e.type?e.t[e.p]=e.b:e.setRatio(a),e=e._next;else for(;e;){if(2!==e.type)if(e.r&&-1!==e.type)if(b=Math.round(e.s+e.c),e.type){if(1===e.type){for(d=e.l,c=e.xs0+b+e.xs1,d=1;d<e.l;d++)c+=e["xn"+d]+e["xs"+(d+1)];e.t[e.p]=c}}else e.t[e.p]=b+e.xs0;else e.t[e.p]=e.e;else e.setRatio(a);e=e._next}},j._enableTransforms=function(a){this._transform=this._transform||Pa(this._target,e,!0),this._transformType=this._transform.svg&&za||!a&&3!==this._transformType?2:3};var Wa=function(a){this.t[this.p]=this.e,this.data._linkCSSP(this,this._next,null,!0)};j._addLazySet=function(a,b,c){var d=this._firstPT=new sa(a,b,0,0,this._firstPT,2);d.e=c,d.setRatio=Wa,d.data=this},j._linkCSSP=function(a,b,c,d){return a&&(b&&(b._prev=a),a._next&&(a._next._prev=a._prev),a._prev?a._prev._next=a._next:this._firstPT===a&&(this._firstPT=a._next,d=!0),c?c._next=a:d||null!==this._firstPT||(this._firstPT=a),a._next=b,a._prev=c),a},j._mod=function(a){for(var b=this._firstPT;b;)"function"==typeof a[b.p]&&a[b.p]===Math.round&&(b.r=1),b=b._next},j._kill=function(b){var c,d,e,f=b;if(b.autoAlpha||b.alpha){f={};for(d in b)f[d]=b[d];f.opacity=1,f.autoAlpha&&(f.visibility=1)}for(b.className&&(c=this._classNamePT)&&(e=c.xfirst,e&&e._prev?this._linkCSSP(e._prev,c._next,e._prev._prev):e===this._firstPT&&(this._firstPT=c._next),c._next&&this._linkCSSP(c._next,c._next._next,e._prev),this._classNamePT=null),c=this._firstPT;c;)c.plugin&&c.plugin!==d&&c.plugin._kill&&(c.plugin._kill(b),d=c.plugin),c=c._next;return a.prototype._kill.call(this,f)};var Xa=function(a,b,c){var d,e,f,g;if(a.slice)for(e=a.length;--e>-1;)Xa(a[e],b,c);else for(d=a.childNodes,e=d.length;--e>-1;)f=d[e],g=f.type,f.style&&(b.push(ba(f)),c&&c.push(f)),1!==g&&9!==g&&11!==g||!f.childNodes.length||Xa(f,b,c)};return g.cascadeTo=function(a,c,d){var e,f,g,h,i=b.to(a,c,d),j=[i],k=[],l=[],m=[],n=b._internals.reservedProps;for(a=i._targets||i.target,Xa(a,k,m),i.render(c,!0,!0),Xa(a,l),i.render(0,!0,!0),i._enabled(!0),e=m.length;--e>-1;)if(f=ca(m[e],k[e],l[e]),f.firstMPT){f=f.difs;for(g in d)n[g]&&(f[g]=d[g]);h={};for(g in f)h[g]=k[e][g];j.push(b.fromTo(m[e],c,h,f))}return j},a.activate([g]),g},!0),function(){var a=_gsScope._gsDefine.plugin({propName:"roundProps",version:"1.6.0",priority:-1,API:2,init:function(a,b,c){return this._tween=c,!0}}),b=function(a){for(;a;)a.f||a.blob||(a.m=Math.round),a=a._next},c=a.prototype;c._onInitAllProps=function(){for(var a,c,d,e=this._tween,f=e.vars.roundProps.join?e.vars.roundProps:e.vars.roundProps.split(","),g=f.length,h={},i=e._propLookup.roundProps;--g>-1;)h[f[g]]=Math.round;for(g=f.length;--g>-1;)for(a=f[g],c=e._firstPT;c;)d=c._next,c.pg?c.t._mod(h):c.n===a&&(2===c.f&&c.t?b(c.t._firstPT):(this._add(c.t,a,c.s,c.c),d&&(d._prev=c._prev),c._prev?c._prev._next=d:e._firstPT===c&&(e._firstPT=d),c._next=c._prev=null,e._propLookup[a]=i)),c=d;return!1},c._add=function(a,b,c,d){this._addTween(a,b,c,c+d,b,Math.round),this._overwriteProps.push(b)}}(),function(){_gsScope._gsDefine.plugin({propName:"attr",API:2,version:"0.6.0",init:function(a,b,c,d){var e,f;if("function"!=typeof a.setAttribute)return!1;for(e in b)f=b[e],"function"==typeof f&&(f=f(d,a)),this._addTween(a,"setAttribute",a.getAttribute(e)+"",f+"",e,!1,e),this._overwriteProps.push(e);return!0}})}(),_gsScope._gsDefine.plugin({propName:"directionalRotation",version:"0.3.0",API:2,init:function(a,b,c,d){"object"!=typeof b&&(b={rotation:b}),this.finals={};var e,f,g,h,i,j,k=b.useRadians===!0?2*Math.PI:360,l=1e-6;for(e in b)"useRadians"!==e&&(h=b[e],"function"==typeof h&&(h=h(d,a)),j=(h+"").split("_"),f=j[0],g=parseFloat("function"!=typeof a[e]?a[e]:a[e.indexOf("set")||"function"!=typeof a["get"+e.substr(3)]?e:"get"+e.substr(3)]()),h=this.finals[e]="string"==typeof f&&"="===f.charAt(1)?g+parseInt(f.charAt(0)+"1",10)*Number(f.substr(2)):Number(f)||0,i=h-g,j.length&&(f=j.join("_"),-1!==f.indexOf("short")&&(i%=k,i!==i%(k/2)&&(i=0>i?i+k:i-k)),-1!==f.indexOf("_cw")&&0>i?i=(i+9999999999*k)%k-(i/k|0)*k:-1!==f.indexOf("ccw")&&i>0&&(i=(i-9999999999*k)%k-(i/k|0)*k)),(i>l||-l>i)&&(this._addTween(a,e,g,g+i,e),this._overwriteProps.push(e)));return!0},set:function(a){var b;if(1!==a)this._super.setRatio.call(this,a);else for(b=this._firstPT;b;)b.f?b.t[b.p](this.finals[b.p]):b.t[b.p]=this.finals[b.p],b=b._next}})._autoCSS=!0,_gsScope._gsDefine("easing.Back",["easing.Ease"],function(a){var b,c,d,e=_gsScope.GreenSockGlobals||_gsScope,f=e.com.greensock,g=2*Math.PI,h=Math.PI/2,i=f._class,j=function(b,c){var d=i("easing."+b,function(){},!0),e=d.prototype=new a;return e.constructor=d,e.getRatio=c,d},k=a.register||function(){},l=function(a,b,c,d,e){var f=i("easing."+a,{easeOut:new b,easeIn:new c,easeInOut:new d},!0);return k(f,a),f},m=function(a,b,c){this.t=a,this.v=b,c&&(this.next=c,c.prev=this,this.c=c.v-b,this.gap=c.t-a)},n=function(b,c){var d=i("easing."+b,function(a){this._p1=a||0===a?a:1.70158,this._p2=1.525*this._p1},!0),e=d.prototype=new a;return e.constructor=d,e.getRatio=c,e.config=function(a){return new d(a)},d},o=l("Back",n("BackOut",function(a){return(a-=1)*a*((this._p1+1)*a+this._p1)+1}),n("BackIn",function(a){return a*a*((this._p1+1)*a-this._p1)}),n("BackInOut",function(a){return(a*=2)<1?.5*a*a*((this._p2+1)*a-this._p2):.5*((a-=2)*a*((this._p2+1)*a+this._p2)+2)})),p=i("easing.SlowMo",function(a,b,c){b=b||0===b?b:.7,null==a?a=.7:a>1&&(a=1),this._p=1!==a?b:0,this._p1=(1-a)/2,this._p2=a,this._p3=this._p1+this._p2,this._calcEnd=c===!0},!0),q=p.prototype=new a;return q.constructor=p,q.getRatio=function(a){var b=a+(.5-a)*this._p;return a<this._p1?this._calcEnd?1-(a=1-a/this._p1)*a:b-(a=1-a/this._p1)*a*a*a*b:a>this._p3?this._calcEnd?1-(a=(a-this._p3)/this._p1)*a:b+(a-b)*(a=(a-this._p3)/this._p1)*a*a*a:this._calcEnd?1:b},p.ease=new p(.7,.7),q.config=p.config=function(a,b,c){return new p(a,b,c)},b=i("easing.SteppedEase",function(a){a=a||1,this._p1=1/a,this._p2=a+1},!0),q=b.prototype=new a,q.constructor=b,q.getRatio=function(a){return 0>a?a=0:a>=1&&(a=.999999999),(this._p2*a>>0)*this._p1},q.config=b.config=function(a){return new b(a)},c=i("easing.RoughEase",function(b){b=b||{};for(var c,d,e,f,g,h,i=b.taper||"none",j=[],k=0,l=0|(b.points||20),n=l,o=b.randomize!==!1,p=b.clamp===!0,q=b.template instanceof a?b.template:null,r="number"==typeof b.strength?.4*b.strength:.4;--n>-1;)c=o?Math.random():1/l*n,d=q?q.getRatio(c):c,"none"===i?e=r:"out"===i?(f=1-c,e=f*f*r):"in"===i?e=c*c*r:.5>c?(f=2*c,e=f*f*.5*r):(f=2*(1-c),e=f*f*.5*r),o?d+=Math.random()*e-.5*e:n%2?d+=.5*e:d-=.5*e,p&&(d>1?d=1:0>d&&(d=0)),j[k++]={x:c,y:d};for(j.sort(function(a,b){return a.x-b.x}),h=new m(1,1,null),n=l;--n>-1;)g=j[n],h=new m(g.x,g.y,h);this._prev=new m(0,0,0!==h.t?h:h.next)},!0),q=c.prototype=new a,q.constructor=c,q.getRatio=function(a){var b=this._prev;if(a>b.t){for(;b.next&&a>=b.t;)b=b.next;b=b.prev}else for(;b.prev&&a<=b.t;)b=b.prev;return this._prev=b,b.v+(a-b.t)/b.gap*b.c},q.config=function(a){return new c(a)},c.ease=new c,l("Bounce",j("BounceOut",function(a){return 1/2.75>a?7.5625*a*a:2/2.75>a?7.5625*(a-=1.5/2.75)*a+.75:2.5/2.75>a?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375}),j("BounceIn",function(a){return(a=1-a)<1/2.75?1-7.5625*a*a:2/2.75>a?1-(7.5625*(a-=1.5/2.75)*a+.75):2.5/2.75>a?1-(7.5625*(a-=2.25/2.75)*a+.9375):1-(7.5625*(a-=2.625/2.75)*a+.984375)}),j("BounceInOut",function(a){var b=.5>a;return a=b?1-2*a:2*a-1,a=1/2.75>a?7.5625*a*a:2/2.75>a?7.5625*(a-=1.5/2.75)*a+.75:2.5/2.75>a?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375,b?.5*(1-a):.5*a+.5})),l("Circ",j("CircOut",function(a){return Math.sqrt(1-(a-=1)*a)}),j("CircIn",function(a){return-(Math.sqrt(1-a*a)-1)}),j("CircInOut",function(a){return(a*=2)<1?-.5*(Math.sqrt(1-a*a)-1):.5*(Math.sqrt(1-(a-=2)*a)+1)})),d=function(b,c,d){var e=i("easing."+b,function(a,b){this._p1=a>=1?a:1,this._p2=(b||d)/(1>a?a:1),this._p3=this._p2/g*(Math.asin(1/this._p1)||0),this._p2=g/this._p2},!0),f=e.prototype=new a;return f.constructor=e,f.getRatio=c,f.config=function(a,b){return new e(a,b)},e},l("Elastic",d("ElasticOut",function(a){return this._p1*Math.pow(2,-10*a)*Math.sin((a-this._p3)*this._p2)+1},.3),d("ElasticIn",function(a){return-(this._p1*Math.pow(2,10*(a-=1))*Math.sin((a-this._p3)*this._p2))},.3),d("ElasticInOut",function(a){return(a*=2)<1?-.5*(this._p1*Math.pow(2,10*(a-=1))*Math.sin((a-this._p3)*this._p2)):this._p1*Math.pow(2,-10*(a-=1))*Math.sin((a-this._p3)*this._p2)*.5+1},.45)),l("Expo",j("ExpoOut",function(a){return 1-Math.pow(2,-10*a)}),j("ExpoIn",function(a){return Math.pow(2,10*(a-1))-.001}),j("ExpoInOut",function(a){return(a*=2)<1?.5*Math.pow(2,10*(a-1)):.5*(2-Math.pow(2,-10*(a-1)))})),l("Sine",j("SineOut",function(a){return Math.sin(a*h)}),j("SineIn",function(a){return-Math.cos(a*h)+1}),j("SineInOut",function(a){return-.5*(Math.cos(Math.PI*a)-1)})),i("easing.EaseLookup",{find:function(b){return a.map[b]}},!0),k(e.SlowMo,"SlowMo","ease,"),k(c,"RoughEase","ease,"),k(b,"SteppedEase","ease,"),o},!0)}),_gsScope._gsDefine&&_gsScope._gsQueue.pop()(),function(a,b){"use strict";var c={},d=a.GreenSockGlobals=a.GreenSockGlobals||a;if(!d.TweenLite){var e,f,g,h,i,j=function(a){var b,c=a.split("."),e=d;for(b=0;b<c.length;b++)e[c[b]]=e=e[c[b]]||{};return e},k=j("com.greensock"),l=1e-10,m=function(a){var b,c=[],d=a.length;for(b=0;b!==d;c.push(a[b++]));return c},n=function(){},o=function(){var a=Object.prototype.toString,b=a.call([]);return function(c){return null!=c&&(c instanceof Array||"object"==typeof c&&!!c.push&&a.call(c)===b)}}(),p={},q=function(e,f,g,h){this.sc=p[e]?p[e].sc:[],p[e]=this,this.gsClass=null,this.func=g;var i=[];this.check=function(k){for(var l,m,n,o,r,s=f.length,t=s;--s>-1;)(l=p[f[s]]||new q(f[s],[])).gsClass?(i[s]=l.gsClass,t--):k&&l.sc.push(this);if(0===t&&g){if(m=("com.greensock."+e).split("."),n=m.pop(),o=j(m.join("."))[n]=this.gsClass=g.apply(g,i),h)if(d[n]=c[n]=o,r="undefined"!=typeof module&&module.exports,!r&&"function"==typeof define&&define.amd)define((a.GreenSockAMDPath?a.GreenSockAMDPath+"/":"")+e.split(".").pop(),[],function(){return o});else if(r)if(e===b){module.exports=c[b]=o;for(s in c)o[s]=c[s]}else c[b]&&(c[b][n]=o);for(s=0;s<this.sc.length;s++)this.sc[s].check()}},this.check(!0)},r=a._gsDefine=function(a,b,c,d){return new q(a,b,c,d)},s=k._class=function(a,b,c){return b=b||function(){},r(a,[],function(){return b},c),b};r.globals=d;var t=[0,0,1,1],u=s("easing.Ease",function(a,b,c,d){this._func=a,this._type=c||0,this._power=d||0,this._params=b?t.concat(b):t},!0),v=u.map={},w=u.register=function(a,b,c,d){for(var e,f,g,h,i=b.split(","),j=i.length,l=(c||"easeIn,easeOut,easeInOut").split(",");--j>-1;)for(f=i[j],e=d?s("easing."+f,null,!0):k.easing[f]||{},g=l.length;--g>-1;)h=l[g],v[f+"."+h]=v[h+f]=e[h]=a.getRatio?a:a[h]||new a};for(g=u.prototype,g._calcEnd=!1,g.getRatio=function(a){if(this._func)return this._params[0]=a,this._func.apply(null,this._params);var b=this._type,c=this._power,d=1===b?1-a:2===b?a:.5>a?2*a:2*(1-a);return 1===c?d*=d:2===c?d*=d*d:3===c?d*=d*d*d:4===c&&(d*=d*d*d*d),1===b?1-d:2===b?d:.5>a?d/2:1-d/2},e=["Linear","Quad","Cubic","Quart","Quint,Strong"],f=e.length;--f>-1;)g=e[f]+",Power"+f,w(new u(null,null,1,f),g,"easeOut",!0),w(new u(null,null,2,f),g,"easeIn"+(0===f?",easeNone":"")),w(new u(null,null,3,f),g,"easeInOut");v.linear=k.easing.Linear.easeIn,v.swing=k.easing.Quad.easeInOut;var x=s("events.EventDispatcher",function(a){this._listeners={},this._eventTarget=a||this});g=x.prototype,g.addEventListener=function(a,b,c,d,e){e=e||0;var f,g,j=this._listeners[a],k=0;for(this!==h||i||h.wake(),null==j&&(this._listeners[a]=j=[]),g=j.length;--g>-1;)f=j[g],f.c===b&&f.s===c?j.splice(g,1):0===k&&f.pr<e&&(k=g+1);j.splice(k,0,{c:b,s:c,up:d,pr:e})},g.removeEventListener=function(a,b){var c,d=this._listeners[a];if(d)for(c=d.length;--c>-1;)if(d[c].c===b)return void d.splice(c,1)},g.dispatchEvent=function(a){var b,c,d,e=this._listeners[a];if(e)for(b=e.length,b>1&&(e=e.slice(0)),c=this._eventTarget;--b>-1;)d=e[b],d&&(d.up?d.c.call(d.s||c,{type:a,target:c}):d.c.call(d.s||c))};var y=a.requestAnimationFrame,z=a.cancelAnimationFrame,A=Date.now||function(){return(new Date).getTime()},B=A();for(e=["ms","moz","webkit","o"],f=e.length;--f>-1&&!y;)y=a[e[f]+"RequestAnimationFrame"],z=a[e[f]+"CancelAnimationFrame"]||a[e[f]+"CancelRequestAnimationFrame"];s("Ticker",function(a,b){var c,d,e,f,g,j=this,k=A(),m=b!==!1&&y?"auto":!1,o=500,p=33,q="tick",r=function(a){var b,h,i=A()-B;i>o&&(k+=i-p),B+=i,j.time=(B-k)/1e3,b=j.time-g,(!c||b>0||a===!0)&&(j.frame++,g+=b+(b>=f?.004:f-b),h=!0),a!==!0&&(e=d(r)),h&&j.dispatchEvent(q)};x.call(j),j.time=j.frame=0,j.tick=function(){r(!0)},j.lagSmoothing=function(a,b){o=a||1/l,p=Math.min(b,o,0)},j.sleep=function(){null!=e&&(m&&z?z(e):clearTimeout(e),d=n,e=null,j===h&&(i=!1))},j.wake=function(a){null!==e?j.sleep():a?k+=-B+(B=A()):j.frame>10&&(B=A()-o+5),d=0===c?n:m&&y?y:function(a){return setTimeout(a,1e3*(g-j.time)+1|0)},j===h&&(i=!0),r(2)},j.fps=function(a){return arguments.length?(c=a,f=1/(c||60),g=this.time+f,void j.wake()):c},j.useRAF=function(a){return arguments.length?(j.sleep(),m=a,void j.fps(c)):m},j.fps(a),setTimeout(function(){"auto"===m&&j.frame<5&&"hidden"!==document.visibilityState&&j.useRAF(!1)},1500)}),g=k.Ticker.prototype=new k.events.EventDispatcher,g.constructor=k.Ticker;var C=s("core.Animation",function(a,b){if(this.vars=b=b||{},this._duration=this._totalDuration=a||0,this._delay=Number(b.delay)||0,this._timeScale=1,this._active=b.immediateRender===!0,this.data=b.data,this._reversed=b.reversed===!0,V){i||h.wake();var c=this.vars.useFrames?U:V;c.add(this,c._time),this.vars.paused&&this.paused(!0)}});h=C.ticker=new k.Ticker,g=C.prototype,g._dirty=g._gc=g._initted=g._paused=!1,g._totalTime=g._time=0,g._rawPrevTime=-1,g._next=g._last=g._onUpdate=g._timeline=g.timeline=null,g._paused=!1;var D=function(){i&&A()-B>2e3&&h.wake(),setTimeout(D,2e3)};D(),g.play=function(a,b){return null!=a&&this.seek(a,b),this.reversed(!1).paused(!1)},g.pause=function(a,b){return null!=a&&this.seek(a,b),this.paused(!0)},g.resume=function(a,b){return null!=a&&this.seek(a,b),this.paused(!1)},g.seek=function(a,b){return this.totalTime(Number(a),b!==!1)},g.restart=function(a,b){return this.reversed(!1).paused(!1).totalTime(a?-this._delay:0,b!==!1,!0)},g.reverse=function(a,b){return null!=a&&this.seek(a||this.totalDuration(),b),this.reversed(!0).paused(!1)},g.render=function(a,b,c){},g.invalidate=function(){return this._time=this._totalTime=0,this._initted=this._gc=!1,this._rawPrevTime=-1,(this._gc||!this.timeline)&&this._enabled(!0),this},g.isActive=function(){var a,b=this._timeline,c=this._startTime;return!b||!this._gc&&!this._paused&&b.isActive()&&(a=b.rawTime())>=c&&a<c+this.totalDuration()/this._timeScale},g._enabled=function(a,b){return i||h.wake(),this._gc=!a,this._active=this.isActive(),b!==!0&&(a&&!this.timeline?this._timeline.add(this,this._startTime-this._delay):!a&&this.timeline&&this._timeline._remove(this,!0)),!1},g._kill=function(a,b){return this._enabled(!1,!1)},g.kill=function(a,b){return this._kill(a,b),this},g._uncache=function(a){for(var b=a?this:this.timeline;b;)b._dirty=!0,b=b.timeline;return this},g._swapSelfInParams=function(a){for(var b=a.length,c=a.concat();--b>-1;)"{self}"===a[b]&&(c[b]=this);return c},g._callback=function(a){var b=this.vars,c=b[a],d=b[a+"Params"],e=b[a+"Scope"]||b.callbackScope||this,f=d?d.length:0;switch(f){case 0:c.call(e);break;case 1:c.call(e,d[0]);break;case 2:c.call(e,d[0],d[1]);break;default:c.apply(e,d)}},g.eventCallback=function(a,b,c,d){if("on"===(a||"").substr(0,2)){var e=this.vars;if(1===arguments.length)return e[a];null==b?delete e[a]:(e[a]=b,e[a+"Params"]=o(c)&&-1!==c.join("").indexOf("{self}")?this._swapSelfInParams(c):c,e[a+"Scope"]=d),"onUpdate"===a&&(this._onUpdate=b)}return this},g.delay=function(a){return arguments.length?(this._timeline.smoothChildTiming&&this.startTime(this._startTime+a-this._delay),this._delay=a,this):this._delay},g.duration=function(a){return arguments.length?(this._duration=this._totalDuration=a,this._uncache(!0),this._timeline.smoothChildTiming&&this._time>0&&this._time<this._duration&&0!==a&&this.totalTime(this._totalTime*(a/this._duration),!0),this):(this._dirty=!1,this._duration)},g.totalDuration=function(a){return this._dirty=!1,arguments.length?this.duration(a):this._totalDuration},g.time=function(a,b){return arguments.length?(this._dirty&&this.totalDuration(),this.totalTime(a>this._duration?this._duration:a,b)):this._time},g.totalTime=function(a,b,c){if(i||h.wake(),!arguments.length)return this._totalTime;if(this._timeline){if(0>a&&!c&&(a+=this.totalDuration()),this._timeline.smoothChildTiming){this._dirty&&this.totalDuration();var d=this._totalDuration,e=this._timeline;if(a>d&&!c&&(a=d),this._startTime=(this._paused?this._pauseTime:e._time)-(this._reversed?d-a:a)/this._timeScale,e._dirty||this._uncache(!1),e._timeline)for(;e._timeline;)e._timeline._time!==(e._startTime+e._totalTime)/e._timeScale&&e.totalTime(e._totalTime,!0),e=e._timeline}this._gc&&this._enabled(!0,!1),(this._totalTime!==a||0===this._duration)&&(I.length&&X(),this.render(a,b,!1),I.length&&X())}return this},g.progress=g.totalProgress=function(a,b){var c=this.duration();return arguments.length?this.totalTime(c*a,b):c?this._time/c:this.ratio},g.startTime=function(a){return arguments.length?(a!==this._startTime&&(this._startTime=a,this.timeline&&this.timeline._sortChildren&&this.timeline.add(this,a-this._delay)),this):this._startTime},g.endTime=function(a){return this._startTime+(0!=a?this.totalDuration():this.duration())/this._timeScale},g.timeScale=function(a){if(!arguments.length)return this._timeScale;if(a=a||l,this._timeline&&this._timeline.smoothChildTiming){var b=this._pauseTime,c=b||0===b?b:this._timeline.totalTime();this._startTime=c-(c-this._startTime)*this._timeScale/a}return this._timeScale=a,this._uncache(!1)},g.reversed=function(a){return arguments.length?(a!=this._reversed&&(this._reversed=a,this.totalTime(this._timeline&&!this._timeline.smoothChildTiming?this.totalDuration()-this._totalTime:this._totalTime,!0)),this):this._reversed},g.paused=function(a){if(!arguments.length)return this._paused;var b,c,d=this._timeline;return a!=this._paused&&d&&(i||a||h.wake(),b=d.rawTime(),c=b-this._pauseTime,!a&&d.smoothChildTiming&&(this._startTime+=c,this._uncache(!1)),this._pauseTime=a?b:null,this._paused=a,this._active=this.isActive(),!a&&0!==c&&this._initted&&this.duration()&&(b=d.smoothChildTiming?this._totalTime:(b-this._startTime)/this._timeScale,this.render(b,b===this._totalTime,!0))),this._gc&&!a&&this._enabled(!0,!1),this};var E=s("core.SimpleTimeline",function(a){C.call(this,0,a),this.autoRemoveChildren=this.smoothChildTiming=!0});g=E.prototype=new C,g.constructor=E,g.kill()._gc=!1,g._first=g._last=g._recent=null,g._sortChildren=!1,g.add=g.insert=function(a,b,c,d){var e,f;if(a._startTime=Number(b||0)+a._delay,a._paused&&this!==a._timeline&&(a._pauseTime=a._startTime+(this.rawTime()-a._startTime)/a._timeScale),a.timeline&&a.timeline._remove(a,!0),a.timeline=a._timeline=this,a._gc&&a._enabled(!0,!0),e=this._last,this._sortChildren)for(f=a._startTime;e&&e._startTime>f;)e=e._prev;return e?(a._next=e._next,e._next=a):(a._next=this._first,this._first=a),a._next?a._next._prev=a:this._last=a,a._prev=e,this._recent=a,this._timeline&&this._uncache(!0),this},g._remove=function(a,b){return a.timeline===this&&(b||a._enabled(!1,!0),a._prev?a._prev._next=a._next:this._first===a&&(this._first=a._next),a._next?a._next._prev=a._prev:this._last===a&&(this._last=a._prev),a._next=a._prev=a.timeline=null,a===this._recent&&(this._recent=this._last),this._timeline&&this._uncache(!0)),this},g.render=function(a,b,c){var d,e=this._first;for(this._totalTime=this._time=this._rawPrevTime=a;e;)d=e._next,(e._active||a>=e._startTime&&!e._paused)&&(e._reversed?e.render((e._dirty?e.totalDuration():e._totalDuration)-(a-e._startTime)*e._timeScale,b,c):e.render((a-e._startTime)*e._timeScale,b,c)),e=d},g.rawTime=function(){return i||h.wake(),this._totalTime};var F=s("TweenLite",function(b,c,d){if(C.call(this,c,d),this.render=F.prototype.render,null==b)throw"Cannot tween a null target.";this.target=b="string"!=typeof b?b:F.selector(b)||b;var e,f,g,h=b.jquery||b.length&&b!==a&&b[0]&&(b[0]===a||b[0].nodeType&&b[0].style&&!b.nodeType),i=this.vars.overwrite;if(this._overwrite=i=null==i?T[F.defaultOverwrite]:"number"==typeof i?i>>0:T[i],(h||b instanceof Array||b.push&&o(b))&&"number"!=typeof b[0])for(this._targets=g=m(b),this._propLookup=[],this._siblings=[],e=0;e<g.length;e++)f=g[e],f?"string"!=typeof f?f.length&&f!==a&&f[0]&&(f[0]===a||f[0].nodeType&&f[0].style&&!f.nodeType)?(g.splice(e--,1),this._targets=g=g.concat(m(f))):(this._siblings[e]=Y(f,this,!1),1===i&&this._siblings[e].length>1&&$(f,this,null,1,this._siblings[e])):(f=g[e--]=F.selector(f),"string"==typeof f&&g.splice(e+1,1)):g.splice(e--,1);else this._propLookup={},this._siblings=Y(b,this,!1),1===i&&this._siblings.length>1&&$(b,this,null,1,this._siblings);(this.vars.immediateRender||0===c&&0===this._delay&&this.vars.immediateRender!==!1)&&(this._time=-l,this.render(Math.min(0,-this._delay)))},!0),G=function(b){return b&&b.length&&b!==a&&b[0]&&(b[0]===a||b[0].nodeType&&b[0].style&&!b.nodeType);
},H=function(a,b){var c,d={};for(c in a)S[c]||c in b&&"transform"!==c&&"x"!==c&&"y"!==c&&"width"!==c&&"height"!==c&&"className"!==c&&"border"!==c||!(!P[c]||P[c]&&P[c]._autoCSS)||(d[c]=a[c],delete a[c]);a.css=d};g=F.prototype=new C,g.constructor=F,g.kill()._gc=!1,g.ratio=0,g._firstPT=g._targets=g._overwrittenProps=g._startAt=null,g._notifyPluginsOfEnabled=g._lazy=!1,F.version="1.19.0",F.defaultEase=g._ease=new u(null,null,1,1),F.defaultOverwrite="auto",F.ticker=h,F.autoSleep=120,F.lagSmoothing=function(a,b){h.lagSmoothing(a,b)},F.selector=a.$||a.jQuery||function(b){var c=a.$||a.jQuery;return c?(F.selector=c,c(b)):"undefined"==typeof document?b:document.querySelectorAll?document.querySelectorAll(b):document.getElementById("#"===b.charAt(0)?b.substr(1):b)};var I=[],J={},K=/(?:(-|-=|\+=)?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/gi,L=function(a){for(var b,c=this._firstPT,d=1e-6;c;)b=c.blob?a?this.join(""):this.start:c.c*a+c.s,c.m?b=c.m(b,this._target||c.t):d>b&&b>-d&&(b=0),c.f?c.fp?c.t[c.p](c.fp,b):c.t[c.p](b):c.t[c.p]=b,c=c._next},M=function(a,b,c,d){var e,f,g,h,i,j,k,l=[a,b],m=0,n="",o=0;for(l.start=a,c&&(c(l),a=l[0],b=l[1]),l.length=0,e=a.match(K)||[],f=b.match(K)||[],d&&(d._next=null,d.blob=1,l._firstPT=l._applyPT=d),i=f.length,h=0;i>h;h++)k=f[h],j=b.substr(m,b.indexOf(k,m)-m),n+=j||!h?j:",",m+=j.length,o?o=(o+1)%5:"rgba("===j.substr(-5)&&(o=1),k===e[h]||e.length<=h?n+=k:(n&&(l.push(n),n=""),g=parseFloat(e[h]),l.push(g),l._firstPT={_next:l._firstPT,t:l,p:l.length-1,s:g,c:("="===k.charAt(1)?parseInt(k.charAt(0)+"1",10)*parseFloat(k.substr(2)):parseFloat(k)-g)||0,f:0,m:o&&4>o?Math.round:0}),m+=k.length;return n+=b.substr(m),n&&l.push(n),l.setRatio=L,l},N=function(a,b,c,d,e,f,g,h,i){"function"==typeof d&&(d=d(i||0,a));var j,k,l="get"===c?a[b]:c,m=typeof a[b],n="string"==typeof d&&"="===d.charAt(1),o={t:a,p:b,s:l,f:"function"===m,pg:0,n:e||b,m:f?"function"==typeof f?f:Math.round:0,pr:0,c:n?parseInt(d.charAt(0)+"1",10)*parseFloat(d.substr(2)):parseFloat(d)-l||0};return"number"!==m&&("function"===m&&"get"===c&&(k=b.indexOf("set")||"function"!=typeof a["get"+b.substr(3)]?b:"get"+b.substr(3),o.s=l=g?a[k](g):a[k]()),"string"==typeof l&&(g||isNaN(l))?(o.fp=g,j=M(l,d,h||F.defaultStringFilter,o),o={t:j,p:"setRatio",s:0,c:1,f:2,pg:0,n:e||b,pr:0,m:0}):n||(o.s=parseFloat(l),o.c=parseFloat(d)-o.s||0)),o.c?((o._next=this._firstPT)&&(o._next._prev=o),this._firstPT=o,o):void 0},O=F._internals={isArray:o,isSelector:G,lazyTweens:I,blobDif:M},P=F._plugins={},Q=O.tweenLookup={},R=0,S=O.reservedProps={ease:1,delay:1,overwrite:1,onComplete:1,onCompleteParams:1,onCompleteScope:1,useFrames:1,runBackwards:1,startAt:1,onUpdate:1,onUpdateParams:1,onUpdateScope:1,onStart:1,onStartParams:1,onStartScope:1,onReverseComplete:1,onReverseCompleteParams:1,onReverseCompleteScope:1,onRepeat:1,onRepeatParams:1,onRepeatScope:1,easeParams:1,yoyo:1,immediateRender:1,repeat:1,repeatDelay:1,data:1,paused:1,reversed:1,autoCSS:1,lazy:1,onOverwrite:1,callbackScope:1,stringFilter:1,id:1},T={none:0,all:1,auto:2,concurrent:3,allOnStart:4,preexisting:5,"true":1,"false":0},U=C._rootFramesTimeline=new E,V=C._rootTimeline=new E,W=30,X=O.lazyRender=function(){var a,b=I.length;for(J={};--b>-1;)a=I[b],a&&a._lazy!==!1&&(a.render(a._lazy[0],a._lazy[1],!0),a._lazy=!1);I.length=0};V._startTime=h.time,U._startTime=h.frame,V._active=U._active=!0,setTimeout(X,1),C._updateRoot=F.render=function(){var a,b,c;if(I.length&&X(),V.render((h.time-V._startTime)*V._timeScale,!1,!1),U.render((h.frame-U._startTime)*U._timeScale,!1,!1),I.length&&X(),h.frame>=W){W=h.frame+(parseInt(F.autoSleep,10)||120);for(c in Q){for(b=Q[c].tweens,a=b.length;--a>-1;)b[a]._gc&&b.splice(a,1);0===b.length&&delete Q[c]}if(c=V._first,(!c||c._paused)&&F.autoSleep&&!U._first&&1===h._listeners.tick.length){for(;c&&c._paused;)c=c._next;c||h.sleep()}}},h.addEventListener("tick",C._updateRoot);var Y=function(a,b,c){var d,e,f=a._gsTweenID;if(Q[f||(a._gsTweenID=f="t"+R++)]||(Q[f]={target:a,tweens:[]}),b&&(d=Q[f].tweens,d[e=d.length]=b,c))for(;--e>-1;)d[e]===b&&d.splice(e,1);return Q[f].tweens},Z=function(a,b,c,d){var e,f,g=a.vars.onOverwrite;return g&&(e=g(a,b,c,d)),g=F.onOverwrite,g&&(f=g(a,b,c,d)),e!==!1&&f!==!1},$=function(a,b,c,d,e){var f,g,h,i;if(1===d||d>=4){for(i=e.length,f=0;i>f;f++)if((h=e[f])!==b)h._gc||h._kill(null,a,b)&&(g=!0);else if(5===d)break;return g}var j,k=b._startTime+l,m=[],n=0,o=0===b._duration;for(f=e.length;--f>-1;)(h=e[f])===b||h._gc||h._paused||(h._timeline!==b._timeline?(j=j||_(b,0,o),0===_(h,j,o)&&(m[n++]=h)):h._startTime<=k&&h._startTime+h.totalDuration()/h._timeScale>k&&((o||!h._initted)&&k-h._startTime<=2e-10||(m[n++]=h)));for(f=n;--f>-1;)if(h=m[f],2===d&&h._kill(c,a,b)&&(g=!0),2!==d||!h._firstPT&&h._initted){if(2!==d&&!Z(h,b))continue;h._enabled(!1,!1)&&(g=!0)}return g},_=function(a,b,c){for(var d=a._timeline,e=d._timeScale,f=a._startTime;d._timeline;){if(f+=d._startTime,e*=d._timeScale,d._paused)return-100;d=d._timeline}return f/=e,f>b?f-b:c&&f===b||!a._initted&&2*l>f-b?l:(f+=a.totalDuration()/a._timeScale/e)>b+l?0:f-b-l};g._init=function(){var a,b,c,d,e,f,g=this.vars,h=this._overwrittenProps,i=this._duration,j=!!g.immediateRender,k=g.ease;if(g.startAt){this._startAt&&(this._startAt.render(-1,!0),this._startAt.kill()),e={};for(d in g.startAt)e[d]=g.startAt[d];if(e.overwrite=!1,e.immediateRender=!0,e.lazy=j&&g.lazy!==!1,e.startAt=e.delay=null,this._startAt=F.to(this.target,0,e),j)if(this._time>0)this._startAt=null;else if(0!==i)return}else if(g.runBackwards&&0!==i)if(this._startAt)this._startAt.render(-1,!0),this._startAt.kill(),this._startAt=null;else{0!==this._time&&(j=!1),c={};for(d in g)S[d]&&"autoCSS"!==d||(c[d]=g[d]);if(c.overwrite=0,c.data="isFromStart",c.lazy=j&&g.lazy!==!1,c.immediateRender=j,this._startAt=F.to(this.target,0,c),j){if(0===this._time)return}else this._startAt._init(),this._startAt._enabled(!1),this.vars.immediateRender&&(this._startAt=null)}if(this._ease=k=k?k instanceof u?k:"function"==typeof k?new u(k,g.easeParams):v[k]||F.defaultEase:F.defaultEase,g.easeParams instanceof Array&&k.config&&(this._ease=k.config.apply(k,g.easeParams)),this._easeType=this._ease._type,this._easePower=this._ease._power,this._firstPT=null,this._targets)for(f=this._targets.length,a=0;f>a;a++)this._initProps(this._targets[a],this._propLookup[a]={},this._siblings[a],h?h[a]:null,a)&&(b=!0);else b=this._initProps(this.target,this._propLookup,this._siblings,h,0);if(b&&F._onPluginEvent("_onInitAllProps",this),h&&(this._firstPT||"function"!=typeof this.target&&this._enabled(!1,!1)),g.runBackwards)for(c=this._firstPT;c;)c.s+=c.c,c.c=-c.c,c=c._next;this._onUpdate=g.onUpdate,this._initted=!0},g._initProps=function(b,c,d,e,f){var g,h,i,j,k,l;if(null==b)return!1;J[b._gsTweenID]&&X(),this.vars.css||b.style&&b!==a&&b.nodeType&&P.css&&this.vars.autoCSS!==!1&&H(this.vars,b);for(g in this.vars)if(l=this.vars[g],S[g])l&&(l instanceof Array||l.push&&o(l))&&-1!==l.join("").indexOf("{self}")&&(this.vars[g]=l=this._swapSelfInParams(l,this));else if(P[g]&&(j=new P[g])._onInitTween(b,this.vars[g],this,f)){for(this._firstPT=k={_next:this._firstPT,t:j,p:"setRatio",s:0,c:1,f:1,n:g,pg:1,pr:j._priority,m:0},h=j._overwriteProps.length;--h>-1;)c[j._overwriteProps[h]]=this._firstPT;(j._priority||j._onInitAllProps)&&(i=!0),(j._onDisable||j._onEnable)&&(this._notifyPluginsOfEnabled=!0),k._next&&(k._next._prev=k)}else c[g]=N.call(this,b,g,"get",l,g,0,null,this.vars.stringFilter,f);return e&&this._kill(e,b)?this._initProps(b,c,d,e,f):this._overwrite>1&&this._firstPT&&d.length>1&&$(b,this,c,this._overwrite,d)?(this._kill(c,b),this._initProps(b,c,d,e,f)):(this._firstPT&&(this.vars.lazy!==!1&&this._duration||this.vars.lazy&&!this._duration)&&(J[b._gsTweenID]=!0),i)},g.render=function(a,b,c){var d,e,f,g,h=this._time,i=this._duration,j=this._rawPrevTime;if(a>=i-1e-7)this._totalTime=this._time=i,this.ratio=this._ease._calcEnd?this._ease.getRatio(1):1,this._reversed||(d=!0,e="onComplete",c=c||this._timeline.autoRemoveChildren),0===i&&(this._initted||!this.vars.lazy||c)&&(this._startTime===this._timeline._duration&&(a=0),(0>j||0>=a&&a>=-1e-7||j===l&&"isPause"!==this.data)&&j!==a&&(c=!0,j>l&&(e="onReverseComplete")),this._rawPrevTime=g=!b||a||j===a?a:l);else if(1e-7>a)this._totalTime=this._time=0,this.ratio=this._ease._calcEnd?this._ease.getRatio(0):0,(0!==h||0===i&&j>0)&&(e="onReverseComplete",d=this._reversed),0>a&&(this._active=!1,0===i&&(this._initted||!this.vars.lazy||c)&&(j>=0&&(j!==l||"isPause"!==this.data)&&(c=!0),this._rawPrevTime=g=!b||a||j===a?a:l)),this._initted||(c=!0);else if(this._totalTime=this._time=a,this._easeType){var k=a/i,m=this._easeType,n=this._easePower;(1===m||3===m&&k>=.5)&&(k=1-k),3===m&&(k*=2),1===n?k*=k:2===n?k*=k*k:3===n?k*=k*k*k:4===n&&(k*=k*k*k*k),1===m?this.ratio=1-k:2===m?this.ratio=k:.5>a/i?this.ratio=k/2:this.ratio=1-k/2}else this.ratio=this._ease.getRatio(a/i);if(this._time!==h||c){if(!this._initted){if(this._init(),!this._initted||this._gc)return;if(!c&&this._firstPT&&(this.vars.lazy!==!1&&this._duration||this.vars.lazy&&!this._duration))return this._time=this._totalTime=h,this._rawPrevTime=j,I.push(this),void(this._lazy=[a,b]);this._time&&!d?this.ratio=this._ease.getRatio(this._time/i):d&&this._ease._calcEnd&&(this.ratio=this._ease.getRatio(0===this._time?0:1))}for(this._lazy!==!1&&(this._lazy=!1),this._active||!this._paused&&this._time!==h&&a>=0&&(this._active=!0),0===h&&(this._startAt&&(a>=0?this._startAt.render(a,b,c):e||(e="_dummyGS")),this.vars.onStart&&(0!==this._time||0===i)&&(b||this._callback("onStart"))),f=this._firstPT;f;)f.f?f.t[f.p](f.c*this.ratio+f.s):f.t[f.p]=f.c*this.ratio+f.s,f=f._next;this._onUpdate&&(0>a&&this._startAt&&a!==-1e-4&&this._startAt.render(a,b,c),b||(this._time!==h||d||c)&&this._callback("onUpdate")),e&&(!this._gc||c)&&(0>a&&this._startAt&&!this._onUpdate&&a!==-1e-4&&this._startAt.render(a,b,c),d&&(this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),!b&&this.vars[e]&&this._callback(e),0===i&&this._rawPrevTime===l&&g!==l&&(this._rawPrevTime=0))}},g._kill=function(a,b,c){if("all"===a&&(a=null),null==a&&(null==b||b===this.target))return this._lazy=!1,this._enabled(!1,!1);b="string"!=typeof b?b||this._targets||this.target:F.selector(b)||b;var d,e,f,g,h,i,j,k,l,m=c&&this._time&&c._startTime===this._startTime&&this._timeline===c._timeline;if((o(b)||G(b))&&"number"!=typeof b[0])for(d=b.length;--d>-1;)this._kill(a,b[d],c)&&(i=!0);else{if(this._targets){for(d=this._targets.length;--d>-1;)if(b===this._targets[d]){h=this._propLookup[d]||{},this._overwrittenProps=this._overwrittenProps||[],e=this._overwrittenProps[d]=a?this._overwrittenProps[d]||{}:"all";break}}else{if(b!==this.target)return!1;h=this._propLookup,e=this._overwrittenProps=a?this._overwrittenProps||{}:"all"}if(h){if(j=a||h,k=a!==e&&"all"!==e&&a!==h&&("object"!=typeof a||!a._tempKill),c&&(F.onOverwrite||this.vars.onOverwrite)){for(f in j)h[f]&&(l||(l=[]),l.push(f));if((l||!a)&&!Z(this,c,b,l))return!1}for(f in j)(g=h[f])&&(m&&(g.f?g.t[g.p](g.s):g.t[g.p]=g.s,i=!0),g.pg&&g.t._kill(j)&&(i=!0),g.pg&&0!==g.t._overwriteProps.length||(g._prev?g._prev._next=g._next:g===this._firstPT&&(this._firstPT=g._next),g._next&&(g._next._prev=g._prev),g._next=g._prev=null),delete h[f]),k&&(e[f]=1);!this._firstPT&&this._initted&&this._enabled(!1,!1)}}return i},g.invalidate=function(){return this._notifyPluginsOfEnabled&&F._onPluginEvent("_onDisable",this),this._firstPT=this._overwrittenProps=this._startAt=this._onUpdate=null,this._notifyPluginsOfEnabled=this._active=this._lazy=!1,this._propLookup=this._targets?{}:[],C.prototype.invalidate.call(this),this.vars.immediateRender&&(this._time=-l,this.render(Math.min(0,-this._delay))),this},g._enabled=function(a,b){if(i||h.wake(),a&&this._gc){var c,d=this._targets;if(d)for(c=d.length;--c>-1;)this._siblings[c]=Y(d[c],this,!0);else this._siblings=Y(this.target,this,!0)}return C.prototype._enabled.call(this,a,b),this._notifyPluginsOfEnabled&&this._firstPT?F._onPluginEvent(a?"_onEnable":"_onDisable",this):!1},F.to=function(a,b,c){return new F(a,b,c)},F.from=function(a,b,c){return c.runBackwards=!0,c.immediateRender=0!=c.immediateRender,new F(a,b,c)},F.fromTo=function(a,b,c,d){return d.startAt=c,d.immediateRender=0!=d.immediateRender&&0!=c.immediateRender,new F(a,b,d)},F.delayedCall=function(a,b,c,d,e){return new F(b,0,{delay:a,onComplete:b,onCompleteParams:c,callbackScope:d,onReverseComplete:b,onReverseCompleteParams:c,immediateRender:!1,lazy:!1,useFrames:e,overwrite:0})},F.set=function(a,b){return new F(a,0,b)},F.getTweensOf=function(a,b){if(null==a)return[];a="string"!=typeof a?a:F.selector(a)||a;var c,d,e,f;if((o(a)||G(a))&&"number"!=typeof a[0]){for(c=a.length,d=[];--c>-1;)d=d.concat(F.getTweensOf(a[c],b));for(c=d.length;--c>-1;)for(f=d[c],e=c;--e>-1;)f===d[e]&&d.splice(c,1)}else for(d=Y(a).concat(),c=d.length;--c>-1;)(d[c]._gc||b&&!d[c].isActive())&&d.splice(c,1);return d},F.killTweensOf=F.killDelayedCallsTo=function(a,b,c){"object"==typeof b&&(c=b,b=!1);for(var d=F.getTweensOf(a,b),e=d.length;--e>-1;)d[e]._kill(c,a)};var aa=s("plugins.TweenPlugin",function(a,b){this._overwriteProps=(a||"").split(","),this._propName=this._overwriteProps[0],this._priority=b||0,this._super=aa.prototype},!0);if(g=aa.prototype,aa.version="1.19.0",aa.API=2,g._firstPT=null,g._addTween=N,g.setRatio=L,g._kill=function(a){var b,c=this._overwriteProps,d=this._firstPT;if(null!=a[this._propName])this._overwriteProps=[];else for(b=c.length;--b>-1;)null!=a[c[b]]&&c.splice(b,1);for(;d;)null!=a[d.n]&&(d._next&&(d._next._prev=d._prev),d._prev?(d._prev._next=d._next,d._prev=null):this._firstPT===d&&(this._firstPT=d._next)),d=d._next;return!1},g._mod=g._roundProps=function(a){for(var b,c=this._firstPT;c;)b=a[this._propName]||null!=c.n&&a[c.n.split(this._propName+"_").join("")],b&&"function"==typeof b&&(2===c.f?c.t._applyPT.m=b:c.m=b),c=c._next},F._onPluginEvent=function(a,b){var c,d,e,f,g,h=b._firstPT;if("_onInitAllProps"===a){for(;h;){for(g=h._next,d=e;d&&d.pr>h.pr;)d=d._next;(h._prev=d?d._prev:f)?h._prev._next=h:e=h,(h._next=d)?d._prev=h:f=h,h=g}h=b._firstPT=e}for(;h;)h.pg&&"function"==typeof h.t[a]&&h.t[a]()&&(c=!0),h=h._next;return c},aa.activate=function(a){for(var b=a.length;--b>-1;)a[b].API===aa.API&&(P[(new a[b])._propName]=a[b]);return!0},r.plugin=function(a){if(!(a&&a.propName&&a.init&&a.API))throw"illegal plugin definition.";var b,c=a.propName,d=a.priority||0,e=a.overwriteProps,f={init:"_onInitTween",set:"setRatio",kill:"_kill",round:"_mod",mod:"_mod",initAll:"_onInitAllProps"},g=s("plugins."+c.charAt(0).toUpperCase()+c.substr(1)+"Plugin",function(){aa.call(this,c,d),this._overwriteProps=e||[]},a.global===!0),h=g.prototype=new aa(c);h.constructor=g,g.API=a.API;for(b in f)"function"==typeof a[b]&&(h[f[b]]=a[b]);return g.version=a.version,aa.activate([g]),g},e=a._gsQueue){for(f=0;f<e.length;f++)e[f]();for(g in p)p[g].func||a.console.log("GSAP encountered missing dependency: "+g)}i=!1}}("undefined"!=typeof module&&module.exports&&"undefined"!=typeof global?global:this||window,"TweenMax");;
/* @license 
 * jQuery.print, version 1.4.0
 *  (c) Sathvik Ponangi, Doers' Guild
 * Licence: CC-By (http://creativecommons.org/licenses/by/3.0/)
 *--------------------------------------------------------------------------*/
(function ($) {
    "use strict";
    // A nice closure for our definitions
    function getjQueryObject(string) {
        // Make string a vaild jQuery thing
        var jqObj = $("");
        try {
            jqObj = $(string)
                .clone();
        } catch (e) {
            jqObj = $("<span />")
                .html(string);
        }
        return jqObj;
    }

    function printFrame(frameWindow, content, options) {
        // Print the selected window/iframe
        var def = $.Deferred();
        try {
            frameWindow = frameWindow.contentWindow || frameWindow.contentDocument || frameWindow;
            var wdoc = frameWindow.document || frameWindow.contentDocument || frameWindow;
            if(options.doctype) {
                wdoc.write(options.doctype);
            }
            wdoc.write(content);
            wdoc.close();
            setTimeout(function () {
                // Fix for IE : Allow it to render the iframe
                frameWindow.focus();
                try {
                    // Fix for IE11 - printng the whole page instead of the iframe content
                    if (!frameWindow.document.execCommand('print', false, null)) {
                        // document.execCommand returns false if it failed -http://stackoverflow.com/a/21336448/937891
                        frameWindow.print();
                    }
                } catch (e) {
                    frameWindow.print();
                }
                frameWindow.close();
                def.resolve();
            }, options.timeout);
        } catch (err) {
            def.reject(err);
        }
        return def;
    }

    function printContentInIFrame(content, options) {
        var $iframe = $(options.iframe + "");
        var iframeCount = $iframe.length;
        if (iframeCount === 0) {
            // Create a new iFrame if none is given
            $iframe = $('<iframe height="0" width="0" border="0" wmode="Opaque"/>')
                .prependTo('body')
                .css({
                    "position": "absolute",
                    "top": -999,
                    "left": -999
                });
        }
        var frameWindow = $iframe.get(0);
        return printFrame(frameWindow, content, options)
            .done(function () {
                // Success
                setTimeout(function () {
                    // Wait for IE
                    if (iframeCount === 0) {
                        // Destroy the iframe if created here
                        $iframe.remove();
                    }
                }, 100);
            })
            .fail(function (err) {
                // Use the pop-up method if iframe fails for some reason
                console.error("Failed to print from iframe", err);
                printContentInNewWindow(content, options);
            })
            .always(function () {
                try {
                    options.deferred.resolve();
                } catch (err) {
                    console.warn('Error notifying deferred', err);
                }
            });
    }

    function printContentInNewWindow(content, options) {
        // Open a new window and print selected content
        var frameWindow = window.open();
        return printFrame(frameWindow, content, options)
            .always(function () {
                try {
                    options.deferred.resolve();
                } catch (err) {
                    console.warn('Error notifying deferred', err);
                }
            });
    }

    function isNode(o) {
        /* http://stackoverflow.com/a/384380/937891 */
        return !!(typeof Node === "object" ? o instanceof Node : o && typeof o === "object" && typeof o.nodeType === "number" && typeof o.nodeName === "string");
    }
    $.print = $.fn.print = function () {
        // Print a given set of elements
        var options, $this, self = this;
        // console.log("Printing", this, arguments);
        if (self instanceof $) {
            // Get the node if it is a jQuery object
            self = self.get(0);
        }
        if (isNode(self)) {
            // If `this` is a HTML element, i.e. for
            // $(selector).print()
            $this = $(self);
            if (arguments.length > 0) {
                options = arguments[0];
            }
        } else {
            if (arguments.length > 0) {
                // $.print(selector,options)
                $this = $(arguments[0]);
                if (isNode($this[0])) {
                    if (arguments.length > 1) {
                        options = arguments[1];
                    }
                } else {
                    // $.print(options)
                    options = arguments[0];
                    $this = $("html");
                }
            } else {
                // $.print()
                $this = $("html");
            }
        }
        // Default options
        var defaults = {
            globalStyles: true,
            mediaPrint: false,
            stylesheet: null,
            noPrintSelector: ".no-print",
            iframe: true,
            append: null,
            prepend: null,
            manuallyCopyFormValues: true,
            deferred: $.Deferred(),
            timeout: 250,
            title: null,
            doctype: '<!doctype html>'
        };
        // Merge with user-options
        options = $.extend({}, defaults, (options || {}));
        var $styles = $("");
        if (options.globalStyles) {
            // Apply the stlyes from the current sheet to the printed page
            $styles = $("style, link, meta, base, title");
        } else if (options.mediaPrint) {
            // Apply the media-print stylesheet
            $styles = $("link[media=print]");
        }
        if (options.stylesheet) {
            // Add a custom stylesheet if given
            $styles = $.merge($styles, $('<link rel="stylesheet" href="' + options.stylesheet + '">'));
        }
        // Create a copy of the element to print
        var copy = $this.clone();
        // Wrap it in a span to get the HTML markup string
        copy = $("<span/>")
            .append(copy);
        // Remove unwanted elements
        copy.find(options.noPrintSelector)
            .remove();
        // Add in the styles
        copy.append($styles.clone());
        // Update title
        if (options.title) {
            var title = $("title", copy);
            if (title.length === 0) {
                title = $("<title />");
                copy.append(title);                
            }
            title.text(options.title);            
        }
        // Appedned content
        copy.append(getjQueryObject(options.append));
        // Prepended content
        copy.prepend(getjQueryObject(options.prepend));
        if (options.manuallyCopyFormValues) {
            // Manually copy form values into the HTML for printing user-modified input fields
            // http://stackoverflow.com/a/26707753
            copy.find("input")
                .each(function () {
                    var $field = $(this);
                    if ($field.is("[type='radio']") || $field.is("[type='checkbox']")) {
                        if ($field.prop("checked")) {
                            $field.attr("checked", "checked");
                        }
                    } else {
                        $field.attr("value", $field.val());
                    }
                });
            copy.find("select").each(function () {
                var $field = $(this);
                $field.find(":selected").attr("selected", "selected");
            });
            copy.find("textarea").each(function () {
                // Fix for https://github.com/DoersGuild/jQuery.print/issues/18#issuecomment-96451589
                var $field = $(this);
                $field.text($field.val());
            });
        }
        // Get the HTML markup string
        var content = copy.html();
        // Notify with generated markup & cloned elements - useful for logging, etc
        try {
            options.deferred.notify('generated_markup', content, copy);
        } catch (err) {
            console.warn('Error notifying deferred', err);
        }
        // Destroy the copy
        copy.remove();
        if (options.iframe) {
            // Use an iframe for printing
            try {
                printContentInIFrame(content, options);
            } catch (e) {
                // Use the pop-up method if iframe fails for some reason
                console.error("Failed to print from iframe", e.stack, e.message);
                printContentInNewWindow(content, options);
            }
        } else {
            // Use a new window for printing
            printContentInNewWindow(content, options);
        }
        return this;
    };
})(jQuery);
;
/*
 *	jQuery dotdotdot 3.2.2
 *	@requires jQuery 1.7.0 or later
 *
 *	dotdotdot.frebsite.nl
 *
 *	Copyright (c) Fred Heusschen
 *	www.frebsite.nl
 *
 *	License: CC-BY-NC-4.0
 *	http://creativecommons.org/licenses/by-nc/4.0/
 */

(function( $ ) {
	'use strict';
	
	var _PLUGIN_    = 'dotdotdot';
	var _VERSION_   = '3.2.2';

	if ( $[ _PLUGIN_ ] && $[ _PLUGIN_ ].version > _VERSION_ )
	{
		return;
	}



	/*
		The class
	*/
	$[ _PLUGIN_ ] = function( $container, opts )
	{
		this.$dot 	= $container;
		this.api	= [ 'getInstance', 'truncate', 'restore', 'destroy', 'watch', 'unwatch' ];
		this.opts	= opts;

		var oldAPI = this.$dot.data( _PLUGIN_ );
		if ( oldAPI )
		{
			oldAPI.destroy();
		}

		this.init();
		this.truncate();

		if ( this.opts.watch )
		{
			this.watch();
		}

		return this;
	};

	$[ _PLUGIN_ ].version 	= _VERSION_;
	$[ _PLUGIN_ ].uniqueId 	= 0;

	$[ _PLUGIN_ ].defaults  = {
		ellipsis		: '\u2026 ',
		callback		: function( isTruncated ) {},
		truncate 		: 'word',
		tolerance		: 0,
		keep			: null,
		watch			: 'window',
		height 			: null
	};


	$[ _PLUGIN_ ].prototype = {

		init: function()
		{
			this.watchTimeout		= null;
			this.watchInterval		= null;
			this.uniqueId 			= $[ _PLUGIN_ ].uniqueId++;
			this.originalStyle		= this.$dot.attr( 'style' ) || '';
			this.originalContent 	= this._getOriginalContent();
			
			if ( this.$dot.css( 'word-wrap' ) !== 'break-word' )
			{
				this.$dot.css( 'word-wrap', 'break-word' );
			}
			if ( this.$dot.css( 'white-space' ) === 'nowrap' )
			{
				this.$dot.css( 'white-space', 'normal' );
			}

			if ( this.opts.height === null )
			{
				this.opts.height = this._getMaxHeight();
			}

			if ( typeof this.opts.ellipsis == 'string' )
			{
				this.opts.ellipsis = document.createTextNode( this.opts.ellipsis );
			}
		},

		getInstance: function()
		{
			return this;
		},

		truncate: function()
		{
			var that = this;


			//	Add inner node for measuring the height
			this.$inner = this.$dot
				.wrapInner( '<div />' )
				.children()
				.css({
					'display'	: 'block',
					'height'	: 'auto',
					'width'		: 'auto',
					'border'	: 'none',
					'padding'	: 0,
					'margin'	: 0
				});


			//	Set original content
			this.$inner
				.empty()
				.append( this.originalContent.clone( true ) );


			//	Get max height
			this.maxHeight = this._getMaxHeight();


			//	Truncate the text
			var isTruncated = false;
			if ( !this._fits() )
			{
				isTruncated = true;
				this._truncateToNode( this.$inner[ 0 ] );
			}

			this.$dot[ isTruncated ? 'addClass' : 'removeClass' ]( _c.truncated );


			//	Remove inner node
			this.$inner.replaceWith( this.$inner.contents() );
			this.$inner = null;


			//	 Callback
			this.opts.callback.call( this.$dot[ 0 ], isTruncated );

			return isTruncated;
		},

		restore: function()
		{
			this.unwatch();

			this.$dot
				.empty()
				.append( this.originalContent )
				.attr( 'style', this.originalStyle )
				.removeClass( _c.truncated );
		},

		destroy: function()
		{
			this.restore();
			this.$dot.data( _PLUGIN_, null );
		},

		watch: function()
		{
			var that = this;

			this.unwatch();

			var oldSizes = {};

			if ( this.opts.watch == 'window' )
			{
				$wndw.on(
					_e.resize + that.uniqueId,
					function( e )
					{
						if ( that.watchTimeout )
						{
							clearTimeout( that.watchTimeout );
						}
						that.watchTimeout = setTimeout(
							function() {

								oldSizes = that._watchSizes( oldSizes, $wndw, 'width', 'height' );

							}, 100
						);
					}
				);

			}
			else
			{
				this.watchInterval = setInterval(
					function()
					{
						oldSizes = that._watchSizes( oldSizes, that.$dot, 'innerWidth', 'innerHeight' );

					}, 500
				);
			}
		},

		unwatch: function()
		{
			$wndw.off( _e.resize + this.uniqueId );

			if ( this.watchInterval )
			{
				clearInterval( this.watchInterval );
			}

			if ( this.watchTimeout )
			{
				clearTimeout( this.watchTimeout );
			}
		},

		_api: function()
		{
			var that = this,
				api = {};

			$.each( this.api,
				function( i )
				{
					var fn = this;
					api[ fn ] = function()
					{
						var re = that[ fn ].apply( that, arguments );
						return ( typeof re == 'undefined' ) ? api : re;
					};
				}
			);
			return api;
		},

		_truncateToNode: function( _elem )
		{

			var that = this;

			var _coms = [],
				_elms = [];

			//	Empty the node 
			//		-> replace all contents with comments
			$(_elem)
				.contents()
				.each(
					function()
					{
						var $e = $(this);
						if ( !$e.hasClass( _c.keep ) )
						{
							var c = document.createComment( '' );
							$e.replaceWith( c );

							_elms.push( this );
							_coms.push( c );
						}
					}
				);

			if ( !_elms.length )
			{
				return;
			}

			//	Re-fill the node 
			//		-> replace comments with contents until it doesn't fit anymore
			for ( var e = 0; e < _elms.length; e++ )
			{

				$(_coms[ e ]).replaceWith( _elms[ e ] );

				$(_elms[ e ]).append( this.opts.ellipsis );
				var fits = this._fits();
				$(this.opts.ellipsis, _elms[ e ]).remove();

				if ( !fits )
				{
					if ( this.opts.truncate == 'node' && e > 1 )
					{
						$(_elms[ e - 2 ]).remove();
						return;
					}
					break;
				}
			}

			//	Remove left over comments
			for ( var c = e; c < _coms.length; c++ )
			{
				$(_coms[ c ]).remove();
			}

			//	Get last node 
			//		-> the node that overflows

			var _last = _elms[ Math.max( 0, Math.min( e, _elms.length - 1 ) ) ];

			//	Border case
			//		-> the last node with only an ellipsis in it...
			if ( _last.nodeType == 1 )
			{

				var $e = $('<' + _last.nodeName + ' />');
				$e.append( this.opts.ellipsis );

				$(_last).replaceWith( $e );

				//	... fits
				//		-> Restore the full last node
				if ( this._fits() )
				{
					$e.replaceWith( _last );
				}

				//	... doesn't fit
				//		-> remove it and go back one node
				else
				{
					$e.remove();
					_last = _elms[ Math.max( 0, e - 1 ) ];
				}
			}

			//	Proceed inside last node
			if ( _last.nodeType == 1 )
			{
				this._truncateToNode( _last );
			}
			else
			{
				this._truncateToWord( _last );
			}
		},

		_truncateToWord: function( _elem )
		{

			var e = _elem;

			var that = this;

			var txt = this.__getTextContent( e ),
				sep = ( txt.indexOf( ' ' ) !== -1 ) ? ' ' : '\u3000',
				arr = txt.split( sep ),
				str = '';

			for ( var a = arr.length; a >= 0; a-- )
			{
				str = arr.slice( 0, a ).join( sep );

				that.__setTextContent( e, that._addEllipsis( str ) );

				if ( that._fits() )
				{
					if ( that.opts.truncate == 'letter' )
					{
						that.__setTextContent( e, arr.slice( 0, a + 1 ).join( sep ) );
						that._truncateToLetter( e );
					}
					break;
				}
			}
		},

		_truncateToLetter: function( e )
		{
			var that = this;

			var txt = this.__getTextContent( e ),
				arr = txt.split( '' ),
				str = '';

			for ( var a = arr.length; a >= 0; a-- )
			{
				str = arr.slice( 0, a ).join( '' );

				if ( !str.length )
				{
					continue;
				}

				that.__setTextContent( e, that._addEllipsis( str ) );

				if ( that._fits() )
				{
					break;
				}
			}
		},

		_fits: function()
		{
			return ( this.$inner.innerHeight() <= this.maxHeight + this.opts.tolerance );
		},

		_addEllipsis: function( txt )
		{
			var remove = [' ', '\u3000', ',', ';', '.', '!', '?'];

			while ( $.inArray( txt.slice( -1 ), remove ) > -1 )
			{
				txt = txt.slice( 0, -1 );
			}
			txt += this.__getTextContent( this.opts.ellipsis );

			return txt;
		},

		_getOriginalContent: function()
		{
			var that = this;

			//	Add "keep" class to nodes to keep
			this.$dot
				.find( 'script, style' )
				.addClass( _c.keep );

			if ( this.opts.keep )
			{
				this.$dot
					.find( this.opts.keep )
					.addClass( _c.keep );
			}

			//	Filter out unneeded whitespace
			this.$dot
				.find( '*' )
				.not( '.' + _c.keep )
				.add( this.$dot )
				.contents()
				.each(
					function()
					{

						var e = this,
							$e = $(this);

						//	Text nodes
						if ( e.nodeType == 3 )
						{

							//	Remove whitespace where it does not take up space in the DOM
							if ( $.trim( that.__getTextContent( e ) ) == '' )
							{
								if ( $e.parent().is( 'table, thead, tbody, tfoot, tr, dl, ul, ol, video' ) )
								{
									$e.remove();
									return;
								}
								if ( $e.prev().is( 'div, p, table, td, td, dt, dd, li' ) )
								{
									$e.remove();
									return;
								}
								if ( $e.next().is( 'div, p, table, td, td, dt, dd, li' ) )
								{
									$e.remove();
									return;
								}
								if ( !$e.prev().length )
								{
									$e.remove();
									return;
								}
								if ( !$e.next().length )
								{
									$e.remove();
									return;
								}
							}
						}

						//	Comment nodes
						else if ( e.nodeType == 8 )
						{
							$e.remove();
						}

					}
				);

			return this.$dot.contents();
		},

		_getMaxHeight: function()
		{
			if ( typeof this.opts.height == 'number' )
			{
				return this.opts.height;
			}

			//	Find smallest CSS height
			var arr = [ 'maxHeight', 'height' ],
				hgh = 0;
 
			for ( var a = 0; a < arr.length; a++ )
			{
				hgh = window.getComputedStyle( this.$dot[ 0 ] )[ arr[ a ] ];
				if ( hgh.slice( -2 ) == 'px' )
				{
					hgh = parseFloat( hgh );
					break;
				}
			}

			//	Remove padding-top/bottom when needed.
			var arr = [];
			switch ( this.$dot.css( 'boxSizing' ) )
			{
				case 'border-box':
					arr.push( 'borderTopWidth' );
					arr.push( 'borderBottomWidth' );
					//	no break -> padding needs to be added too

				case 'padding-box':
					arr.push( 'paddingTop' );
					arr.push( 'paddingBottom' );
					break;
			}
			for ( var a = 0; a < arr.length; a++ )
			{
				var p = window.getComputedStyle( this.$dot[ 0 ] )[ arr[ a ] ];
				if ( p.slice( -2 ) == 'px' )
				{
					hgh -= parseFloat( p );
				}
			}

			//	Sanitize
			return Math.max( hgh, 0 );
		},

		_watchSizes: function( oldSizes, $elem, width, height )
		{
			if ( this.$dot.is( ':visible' ) )
			{
				var newSizes = {
					'width'		: $elem[ width  ](),
					'height'	: $elem[ height ]()
				};

				if ( oldSizes.width != newSizes.width || oldSizes.height != newSizes.height )
				{
					this.truncate();
				}

				return newSizes;
			}
			return oldSizes;
		},

		__getTextContent: function( elem )
		{
			var arr = [ 'nodeValue', 'textContent', 'innerText' ];
			for ( var a = 0; a < arr.length; a++ )
			{
				if ( typeof elem[ arr[ a ] ] == 'string' )
				{
					return elem[ arr[ a ] ];
				}
			}
			return '';
		},
		__setTextContent: function( elem, content )
		{
		    var arr = ['nodeValue', 'textContent', 'innerText'];
		    
			for ( var a = 0; a < arr.length; a++ )
			{
				elem[ arr[ a ] ] = content;
			}			 
			
		}
	};



	/*
		The jQuery plugin
	*/
	$.fn[ _PLUGIN_ ] = function( opts )
	{
		initPlugin();

		opts = $.extend( true, {}, $[ _PLUGIN_ ].defaults, opts );

		return this.each(
			function()
			{
				$(this).data( _PLUGIN_, new $[ _PLUGIN_ ]( $(this), opts )._api() );
			}
		);
	};



	/*
		Global variables
	*/
	var _c, _d, _e, $wndw;

	function initPlugin()
	{
		$wndw = $(window);

		//	Classnames, Datanames, Eventnames
		_c = {};
		_d = {};
		_e = {};

		$.each( [ _c, _d, _e ],
			function( i, o )
			{
				o.add = function( a )
				{
					a = a.split( ' ' );
					for ( var b = 0, l = a.length; b < l; b++ )
					{
						o[ a[ b ] ] = o.ddd( a[ b ] );
					}
				};
			}
		);

		//	Classnames
		_c.ddd = function( c ) { return 'ddd-' + c; };
		_c.add( 'truncated keep' );

		//	Datanames
		_d.ddd = function( d ) { return 'ddd-' + d; };

		//	Eventnames
		_e.ddd = function( e ) { return e + '.ddd'; };
		_e.add( 'resize' );


		//	Only once
		initPlugin = function() {};

	}


})( jQuery );
;
(function () {
    "use strict";
    $.material.init();

    //

    var app = angular.module("app", ["ui.bootstrap", "ui.router", "ngCookies", "ui.bootstrap.carousel",
        "ngAnimate", "ngTouch", "LocalStorageModule", "satellizer", "ngMaterial", "ngSanitize",
        'angular-bootstrap-select',
        'angular-bootstrap-select.extra']);

    app.run([
        "$animate", function ($animate) {
            $animate.enabled(true);
        }
    ]);

    app.run(['$rootScope', '$state', function ($rootScope, $state) {

        $rootScope.$on('$stateChangeStart', function (evt, to, params) {
            if (to.redirectTo) {
                evt.preventDefault();
                $state.go(to.redirectTo, params, { location: 'replace' });
            }
        });
    }]);

    app.config([
        "localStorageServiceProvider", function (localStorageServiceProvider) {
            localStorageServiceProvider.setPrefix("viad-ibe").setStorageType("sessionStorage");
        }
    ]);

    app.config([
        "$provide", "$httpProvider", function ($provide, $httpProvider) {
            $httpProvider.defaults.useXDomain = true;
            delete $httpProvider.defaults.headers.common["X-Requested-With"];

            function containsAny(source, values) {
                for (var i = 0, len = values.length; i < len; i++) {
                    if (source.indexOf(values[i]) >= 0) return true;
                }
                return false;
            }

            //set up global http interceptor
            $provide.factory("httpInterceptor", [
                "$q", "$rootScope", function ($q, $rootScope) {
                    return {
                        response: function (response) {
                            return response || $q.when(response);
                        },
                        responseError: function (rejection) {
                            var url = rejection.config.url.toLocaleLowerCase();
                            var skipForUrls = [
                                "/api/authentication/customerlogin",
                                "/api/user/",
                                "/api/payment/creditcard",
                                "/api/product/relatedservicesmulti",
                                "/api/product/enhanceyourexperience",
                                "/api/product/hotelcheckincalendar",
                                "/api/product/hotelcheckoutcalendar",
                                "/api/product/dynamicpackageprices"

                            ];
                            if (jQuery("#checkoutScreen").length > 0 || jQuery("#enhancebooking").length > 0) {
                                skipForUrls.push("/api/product/");
                                skipForUrls.push("/api/usercode/");
                            }
                            if (!containsAny(url, skipForUrls)) {

                                if (!rejection.data || rejection.data.ExceptionMessage || rejection.data.Message || !(rejection.data.errors || "").length) {
                                    var defaultError = "An error has occurred!";
                                    var msg = rejection.data ? (rejection.data.ExceptionMessage || rejection.data.Message || defaultError) : defaultError;
                                    $rootScope.$broadcast("mergeGlobalErros", [{ serverSide: true, "errorMessage": msg }]);
                                } else if (rejection.data.errors && rejection.data.errors.length > 0) {
                                    $rootScope.$broadcast("mergeGlobalErros", rejection.data.errors);
                                }
                            }

                            return $q.reject(rejection);
                        }
                    };
                }
            ]);
            $httpProvider.interceptors.push("httpInterceptor");
        }
    ]);

    //custom factories
    app.factory("validHelper", function () {
        return {
            checkMethod: {
                all: 1,
                pattern: 2,
                required: 3
            },
            getInvalidClassByCond: function (isValid, submitted) {
                return isValid && submitted ? "invalid" : "";
            },
            getInvalidClass: function (option, submitted) {
                return this.isInvalid(option, submitted) ? "invalid" : "";
            },
            getHasErrorClass: function (option, submitted, isRequired) {
                var isRequiredClass = isRequired ? "is-required" : "";
                return this.isInvalid(option, submitted) ? isRequiredClass + " custom-has-error" : isRequiredClass;
            },
            isInvalid: function (option, submitted, method) {
                if (option && option.$name == "travelerPhone") {
                    //console.log("test");
                }
                if (!option || !(submitted || option.activated)) return false;

                method = !method ? this.checkMethod.all : method;
                if (method == this.checkMethod.required) {
                    return option.$error && option.$error.required;
                }
                else if (method == this.checkMethod.pattern) {
                    return option.$error && option.$error.pattern;
                } else {
                    return (option.$invalid || (option.$error && option.$error.pattern));
                }
            },

            getInvalidClassExpr: function (invalidExpr, submitted, activated) {
                return this.isInvalidExpr(invalidExpr, submitted, activated) ? "invalid" : "";
            },
            getHasErrorClassExpr: function (invalidExpr, submitted, activated) {
                return this.isInvalidExpr(invalidExpr, submitted, activated) ? "custom-has-error" : "";
            },
            isInvalidExpr: function (invalidExpr, submitted, activated) {
                return invalidExpr && (submitted || activated);
            }
        };
    });

    app.factory("ExternalAuthProvider", [
        "$http", function ($http) {
            var factory =
            {
                getSettings: function () {
                    return jQuery.parseJSON($("#externalAuthProviderSettings").val());
                },
                getProfile: function (token) {
                    var settings = factory.getSettings();
                    var url = "";
                    $.each(settings, function (key, value) {
                        if (value.Name.toLowerCase().indexOf("facebook") >= 0) {
                            url = value.GetProfileUrl;
                        }
                    });

                    var fields = "id,email,first_name,last_name";
                    var q = "?access_token=" + token + "&fields=" + fields;

                    return $http.get(url + q);
                }
            };
            return factory;

        }
    ]);
    //custom directives
    app.directive('customTelInput', function () {
        return {
            restrict: 'E',
            require: '^form',
            scope: {
                ngModel: '=',
                ngRequired: '=',
                ngInitValue: '=',
                ngAvailablecountries: "=",
                ngSelectedcountryname: "=",
                ngDisabled: '=?', // Add this to bind the disabled attribute
                onBlur: '&',
                onPhoneValueChangedEvent: '&' // Add this to pass functions as properties
            },
            template: '<input type="text" ng-model="ngModel" ng-required="ngRequired" ng-disabled="ngDisabled"/>',
            link: function (scope, element, attrs, formCtrl) {
                // Access the input element
                var inputElement = element.find('input');
                var inputName = attrs.name;
                var initialCountry = attrs.initialcountrycode;
                //var initialValue = attrs.initvalue || "";

                console.log("Custom tel input init: ", inputElement, initialCountry, scope.ngInitValue);
                const iti = window.intlTelInput(inputElement[0], {
                    //loadUtilsOnInit: "path/to/utils.js"
                    customPlaceholder: function (selectedCountryPlaceholder, selectedCountryData) {
                        return "e.g. " + selectedCountryPlaceholder;
                    },
                    strictMode: false,
                    formatAsYouType: true,
                    separateDialCode: true,
                    initialCountry: initialCountry || "ca",
                    countryOrder: ["us", "ca", "uk", "is", "de"]
                });
                // listen to the telephone input for changes
                inputElement[0].addEventListener('countrychange', () => {
                    setTimeout(function () {
                        validateInput();
                        scope.$apply(function () {
                            scope.onBlur && scope.onBlur(); // Call the function and pass parameters if needed
                        });
                    });
                });

                if (scope.ngInitValue) {
                    iti.setNumber(scope.ngInitValue);
                }

                // Function to check validation
                function validateInput(value) {
                    // Custom validation logic (example: minimum 3 characters)
                    var hasContent = (iti.getNumber(intlTelInput.utils.numberFormat.E164) || "").length > 0;
                    const isValid = hasContent && iti.isValidNumber() || !hasContent;
                    scope.hasError = !isValid;
                    formCtrl[inputName].$setValidity('pattern', isValid);

                    //if (!value || value.length < 3) {
                    //    formCtrl[inputName].$setValidity('pattern', false);
                    //    scope.hasError = true;
                    //} else {
                    //    formCtrl[inputName].$setValidity('customError', true);
                    //    scope.hasError = false;
                    //}
                }

                inputElement.on('blur', function () {
                    //console.log("on tel input blur");
                    scope.$apply(function () {
                        scope.onBlur && scope.onBlur(); // Call the function and pass parameters if needed
                    });
                });

                //inputElement.on('change', function () {
                //    console.log("on tel input change");
                //    scope.$apply(function () {
                //        scope.onPhoneValueChangedEvent && scope.onPhoneValueChangedEvent({ value: iti.getNumber(intlTelInput.utils.numberFormat.E164) }); // Call the function and pass parameters if needed
                //    });
                //});

                // Initialize the plugin (replace `yourPlugin` with the actual plugin)
                //inputElement.yourPlugin({
                //    option1: 'value1', // Plugin options go here
                //    option2: 'value2'
                //});

                scope.$watch('ngSelectedcountryname', function (newValue) {
                    console.log("dataSelectedcountryname changed: ", newValue);

                    if ((scope.ngAvailablecountries || "").length && newValue) {
                        var foundCountry = scope.ngAvailablecountries.find(function (country) { return country && country.name == newValue; });
                        if (foundCountry && foundCountry.code) {
                            iti.setCountry(foundCountry.code.toLowerCase());
                            setTimeout(function () {
                                validateInput();
                            });
                        }
                    }                   
                });

                scope.$watch('ngInitValue', function (newValue) {
                    // TO DO: possible infinite loop issue here
                    if (newValue) {
                        //console.log("ngInitValue update: ", iti, newValue);
                        iti.setNumber(newValue);
                    }
                    // inputElement.yourPlugin('update', newValue); // Adjust if the plugin has an update method
                });

                // Watch for changes in the model and update the plugin if needed
                scope.$watch('ngModel', function (newValue) {
                    //console.log("Custom tel input update: ", iti, newValue);
                    validateInput();

                    setTimeout(function () {
                        scope.$apply(function () {
                            scope.onPhoneValueChangedEvent({ value: iti.isValidNumber() && iti.getNumber(intlTelInput.utils.numberFormat.E164) || "" }); // Call the function and pass parameters if needed
                        });
                    });
                    // inputElement.yourPlugin('update', newValue); // Adjust if the plugin has an update method
                });

                // Clean up on directive destroy
                scope.$on('$destroy', function () {
                    console.log("Custom tel input destroy: ");
                    // inputElement.yourPlugin('destroy'); // Adjust if the plugin has a destroy method
                });
            }
        };
    });

    app.directive("compareTo", function () {
        return {
            require: "ngModel",
            scope: {
                otherModelValue: "=compareTo"
            },
            link: function (scope, element, attributes, ngModel) {
                ngModel.$validators.compareTo = function (modelValue) {
                    return modelValue === scope.otherModelValue;
                };

                scope.$watch("otherModelValue", function () {
                    ngModel.$validate();
                });
            }
        };
    });
    app.directive("refreshOnShow", [
        "$window", "$timeout", function ($window, $timeout) {
            return {
                restrict: "A",
                link: function (scope, element) {
                    scope.$watch(
                        function () {
                            return element.height();
                        },
                        function (newHeight, oldHeight) {
                            setTimeout(function () {
                                $($window).resize();
                            }, 500);
                        });

                    //scope.$watch(
                    //    "submitted&&showSummaryErrors",
                    //    function (newVal, oldVal) {
                    //        console.log("resize panel error");
                    //        $timeout(function () {
                    //            $($window).resize();
                    //            console.log("done resize");
                    //        }, 0);
                    //        if (newVal === oldVal) return;

                    //    }
                    //);
                }
            };
        }
    ]);
    app.directive("ifMobileDevice", [
        "$window", "$timeout", function ($window, $timeout) {
            return {
                restrict: "A",
                link: function (scope, element, attr, ngModelCtrl) {

                    var isMobile = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
                        || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte|(iPad|iPhone|iPod)\-/i.test(navigator.userAgent.substr(0, 4));

                    if (isMobile) {
                        if (!$(element).hasClass("mobile-device") && (attr.type === "select" || attr.type === "input")) {
                            $(element).addClass("mobile-device");
                        }
                        $(element).show();
                    } else {
                        $(element).hide();
                    }
                }
            };
        }
    ]);
    app.directive("ifNotMobileDevice", [
        "$window", "$timeout", function ($window, $timeout) {
            return {
                restrict: "A",
                link: function (scope, element) {

                    var isMobile = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
                        || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte|(iPad|iPhone|iPod)\-/i.test(navigator.userAgent.substr(0, 4));

                    if (!isMobile) {
                        $(element).show();
                    } else {
                        $(element).hide();
                    }
                }
            };
        }
    ]);
    app.directive("ngModelOnblur", function () {
        return {
            restrict: 'A',
            require: 'ngModel',
            priority: 1, // needed for angular 1.2.x
            link: function (scope, elm, attr, ngModelCtrl) {
                if (attr.type === "radio" || attr.type === "checkbox") return;

                var isIos = navigator.userAgent.indexOf("iPad") > -1 || navigator.userAgent.indexOf("iPhone") > -1
                    || navigator.userAgent.indexOf("iPod") > -1;

                if (!isIos) return;

                elm.unbind("input").unbind("keydown").unbind("change");
                elm.bind("blur", function () {
                    scope.$apply(function () {
                        ngModelCtrl.$setViewValue(elm.val());
                    });
                });
            }
        };
    });
    app.directive("showonImgLoad",
        [
            "$animate", "$timeout", function ($animate, $timeout) {
                return {
                    restrict: "A",
                    link: function (scope, element, attr) {
                        attr.$observe("showonImgLoad", function (value) {
                            if (!value || value.length === 0 || value.trim().length === 0)
                                return;

                            var image = document.createElement("img");
                            image.src = value;
                            image.onload = function () {
                                $timeout(function () {
                                    $animate.removeClass(element, "ng-hide");
                                });
                            };
                        });
                    }
                };
            }
        ]);


    //Not used
    app.directive("updateSelect", [
        "$window", function ($window) {
            return {
                restrict: "A",
                link: function (scope, element, attrs) {
                    function activateOriginalSelect(el, val) {
                        var dropdown = el.parent().find("select:first");
                        dropdown.find("option[value='" + val + "']").triggerHandler("click");
                        dropdown.triggerHandler("blur");
                    }

                    try {
                        var observer = new MutationObserver(function (mutations) {
                            setTimeout(function () {
                                jQuery(element).dropdown({
                                    "onSelected": activateOriginalSelect
                                });
                            }, 0);
                        });
                        observer.observe(element[0], {
                            childList: true,
                            subtree: true
                        });
                    } catch (e) {
                        console.log("Mutation Observer not supported.");
                    }

                    scope.$evalAsync(function () {
                        setTimeout(function () {
                            jQuery(element).dropdown({
                                "onSelected": activateOriginalSelect
                            });
                        }, 0);
                    });
                }
            };
        }
    ]);


    app.directive("listOverlay", [
        "$cookies", function ($cookies) {
            return {
                restrict: "A",
                link: function (scope, element) {
                    var overlayCookieName = "hide.scroll-list-overlay";

                    var overlayCookie = $cookies.get(overlayCookieName);
                    scope.showOverlay = !overlayCookie || overlayCookie !== "1";

                    element.on("click", function () {
                        if (!scope.showOverlay) return false;

                        var now = new Date();
                        now.setDate(now.getDate() + 30); //expire in 30 days
                        $cookies.put(overlayCookieName, "1", {
                            expires: now
                        });

                        scope.$apply(function () {
                            scope.showOverlay = false;
                        });

                        return false;
                    });
                }
            };
        }
    ]);

    app.directive("modalWindow", ["$parse",
        function ($parse) {
            return {
                restrict: "A",
                link: function (scope, element, attrs) {

                    var modalShowHandler = attrs.onShow && $parse(attrs.onShow);
                    var modalHideHandler = attrs.onHide && $parse(attrs.onHide);

                    scope.$watch(attrs.visible, function (value) {
                        if (value === true)
                            $(element).modal("show");
                        else
                            $(element).modal("hide");
                    });

                    $(element).on("shown.bs.modal", function () {
                        scope.$apply(function () {
                            var indA = attrs.visible.indexOf("[");
                            var indB = attrs.visible.indexOf("]");
                            var at = attrs.visible.substring(0, indA);
                            var title = attrs.visible.substring((indA + 2), indB - 1);
                            scope[at][title] = true;
                            // $(element).find("input:not(.ng-empty)").change();
                            _.each($(element).find("input"), function (input) {
                                if (jQuery(input).val()) {
                                    jQuery(input).change();
                                }
                            });
                        });
                        modalShowHandler && modalShowHandler(scope);
                    });

                    $(element).on("hidden.bs.modal", function () {
                        scope.$apply(function () {
                            var indA = attrs.visible.indexOf("[");
                            var indB = attrs.visible.indexOf("]");
                            var at = attrs.visible.substring(0, indA);
                            var title = attrs.visible.substring((indA + 2), indB - 1);
                            if (title === "GlobalErrors") {
                                scope.cleanGlobalErrors();
                            }
                            scope[at][title] = false;
                        });
                        modalHideHandler && modalHideHandler(scope);
                    });
                }
            };
        }
    ]);

    app.directive("filterDropdown", [
        function () {
            return {
                restrict: "A",
                link: function (scope, element, $rootScope) {
                    var dropdown = element.find(".dropdown");

                    jQuery(document).click(function (e) {
                        element.removeClass("active");
                        dropdown.attr("aria-hidden", true);
                    });

                    element.on("click", function (e) {
                        e.stopPropagation();
                        element.toggleClass("active");
                        var dropdown = element.find(".dropdown");
                        dropdown.attr("aria-hidden", !element.hasClass("active"));
                    });
                }
            };
        }
    ]);

    app.directive("slideToggle", [
        function () {
            return {
                restrict: "A",
                link: function (scope, element, $rootScope) {
                    element.on("click", function () {
                        if (scope.activeSliding === true) return false;
                        scope.activeSliding = true;
                        if (!element.hasClass("slide-toggle-active") && angular.element(".slide-toggle-active").length > 0) {
                            angular.element(".slide-toggle-active").next().slideToggle(function () {

                                angular.element(".slide-toggle-active").toggleClass("slide-toggle-active");
                                element.next().slideToggle(function () {
                                    element.toggleClass("slide-toggle-active");
                                    if (angular.element(".slide-toggle-active").length > 0) {
                                        jQuery(".scroll-up, .scroll-down").hide();
                                    } else {
                                        jQuery(".scroll-up, .scroll-down").show();
                                    }
                                    scope.activeSliding = false;
                                });
                            });
                        } else {
                            element.next().slideToggle(function () {
                                element.toggleClass("slide-toggle-active");
                                if (angular.element(".slide-toggle-active").length > 0) {
                                    jQuery(".scroll-up, .scroll-down").hide();
                                } else {
                                    jQuery(".scroll-up, .scroll-down").show();
                                }
                                scope.activeSliding = false;
                            });
                        }
                        return false;
                    });
                }
            };
        }
    ]);

    app.directive("slideAddon", [
        "$timeout", function ($timeout) {
            return {
                restrict: "A",
                link: function (scope, element, attrs) {
                    scope.closeAddon = function () {
                        $(element).find(".enhance-button:first").click();
                    };
                    var btn = $(element).find(".enhance-button:first");
                    $(window).on("resize", function () {
                        if ($(element).data("toggled")) {
                            $(element).css({
                                bottom: 0 - $(element).height() + btn.height()
                            });
                        }
                    });

                    $(element).css("bottom", 0 - $(element).height() + btn.height());
                    $(element).data("toggled", true);
                    btn.removeClass("toggle-down").addClass("toggle-up");
                    btn.on("click", function () {
                        $(element).data("toggled", !$(element).data("toggled"));
                        $(this).removeClass($(element).data("toggled") ? "toggle-up" : "toggle-down").addClass($(element).data("toggled") ? "toggle-down" : "toggle-up");
                        $(element).stop().animate({
                            bottom: $(element).data("toggled") ? 0 - $(element).height() + btn.height() : 0
                        }, 300);
                        return false;
                    });
                    if (attrs.delayslide > 0) {
                        $timeout(function () {
                            btn.click();
                        }, attrs.delayslide);
                    }
                }
            };
        }
    ]);
    app.directive('ngEnter', function () {
        return function (scope, element, attrs) {
            element.bind("keydown keypress", function (event) {
                if (event.which === 13) {
                    scope.$apply(function () {
                        scope.$eval(attrs.ngEnter);
                    });

                    event.preventDefault();
                }
            });
        };
    });
    app.directive('customTooltip', function () {
        return function (scope, element, attrs) {
            element.tooltip({ container: 'body', html: true });
        };
    });
    app.directive("equalPanelsRowHeight", [
        "$window", "$timeout", function ($window, $timeout) {
            return {
                restrict: "A",
                scope: {
                    callId: '='
                },
                link: function (scope, element, attrs) {
                    scope.$watch("callId", function (newValue, oldValue) {
                        $timeout(function () {
                            var resizeElements = function () {
                                element.find(".deal-banner").each(function (index, el) {
                                    var el = jQuery(el);

                                    el.css("width", el.parent().height());
                                });
                                var leftCol = element.find(".results-column-left:first");
                                var rightCol = element.find(".results-column-right:first");
                                if (!leftCol.is(":visible") || !rightCol.is(":visible")) {
                                    element.find(".panel-image").css("min-height", "");
                                    return;
                                }
                                var leftColItems = leftCol.children();//find(".panel-ticket");
                                var rightColItems = rightCol.children();//find(".panel-ticket");

                                var index = 0;
                                _.each(leftColItems, function (el, indx) {
                                    var leftEl = jQuery(el);
                                    if (leftEl.hasClass("visible-sm")) return;
                                    var rightEl = jQuery(rightColItems[index++]);
                                    if (!rightEl) return;
                                    //var prevLeftElHeight = leftEl.find(".panel-image").css("min-height");
                                    //var prevRightElHeight = rightEl.find(".panel-image").css("min-height");

                                    if (leftEl.find(".read-less:first").length || rightEl.find(".read-less:first").length
                                        || leftEl.find(".expanded:first").length || rightEl.find(".expanded:first").length) {
                                        return;
                                    }

                                    //var prevLeftElHeight = leftEl.find(".panel-image").css("min-height");
                                    //var prevRightElHeight = rightEl.find(".panel-image").css("min-height");

                                    leftEl.find(".panel-image").css("min-height", "");
                                    rightEl.find(".panel-image").css("min-height", "");

                                    var firstHeight = leftEl.height();
                                    var secondHeight = rightEl.height();


                                    if (firstHeight == secondHeight) {
                                        return;
                                    }



                                    if (firstHeight < secondHeight) {
                                        leftEl.find(".panel-image").css("min-height", secondHeight);
                                        rightEl.find(".panel-image").css("min-height", secondHeight);
                                    } else {
                                        rightEl.find(".panel-image").css("min-height", firstHeight);
                                        leftEl.find(".panel-image").css("min-height", firstHeight);
                                    }
                                });
                                element.find(".deal-banner").each(function (index, el) {
                                    var el = jQuery(el);
                                    el.css("width", el.parent().height());
                                });
                            };
                            resizeElements();
                            var resizeTimeout;
                            jQuery(window).resize(function () {
                                clearTimeout(resizeTimeout);
                                resizeTimeout = setTimeout(resizeElements, 500);
                            });
                            // if (!element.is(".results-column-left")) return;

                        });
                    });



                    //console.log(element.find(".panel-ticket").length);
                    //var leftCol = element.parent().find(".results-column-left:first");
                    //var rightCol = element.parent().find(".results-column-right:first");
                    //console.log("leftCol=", leftCol.length, " rightCol=", rightCol.length);
                }
            };
        }
    ]);
    app.directive("readMoreLink", [
        "$window", "$timeout", function ($window, $timeout) {
            return {
                restrict: "A",
                scope: {
                    checkInit: '='
                },
                link: function (scope, element, attrs) {

                    if (!attrs.readmoretarget) {
                        return;
                    }
                    var API = undefined
                    var isInit = false;
                    //  if (scope.checkInit) {
                    var useDotdotdot = attrs.readMoreLink == "dot";
                    var initHeight = parseFloat(attrs.initHeight > 0 ? attrs.initHeight : 30);

                    scope.$watch("checkInit", function (newValue, oldValue) {
                        if (!useDotdotdot && isInit) return;
                        if (newValue && (!useDotdotdot || (newValue != oldValue) || !isInit)) { // && !isInit) {                                                     
                            init(isInit);
                            isInit = true;
                        }
                    });
                    //} else {
                    //    init();
                    //}
                    function init(reset) {

                        if (API && reset) {
                            API.destroy();
                        }

                        $timeout(function () {
                            var targetEl = jQuery(attrs.readmoretarget);
                            if (!targetEl.length) {
                                return;
                            }


                            if (useDotdotdot) {

                                targetEl.show();
                                targetEl.attr("aria-hidden", false);

                                API = targetEl.data("dotdotdot") ||
                                    targetEl.dotdotdot({
                                        callback: function (isTruncated) {
                                            // remove the read more link if text is too short
                                            if (!isTruncated) {
                                                element.hide();
                                                element.attr('style', 'display: none !important');
                                                element.attr("aria-hidden", true);
                                            } else {
                                                element.show();
                                                if (initHeight) {
                                                    targetEl.css("max-height", initHeight + "px");
                                                }
                                                element.attr("aria-hidden", false);
                                            }
                                        },
                                        truncate: "word",
                                        height: initHeight
                                    }).data("dotdotdot");
                                // jQuery(window).resize(); 
                                if (initHeight) {
                                    targetEl.css("max-height", initHeight + "px");
                                }

                            } else {
                                targetEl.hide();
                                targetEl.attr("aria-hidden", true);
                            }


                            element.on("click", function () {
                                /* Starts the truncate process. */
                                element.toggleClass("read-less");
                                if (element.hasClass("read-less")) {
                                    element.text(element.data("readlesstxt") || "Read less");
                                    if (useDotdotdot) {
                                        API.restore();
                                    }

                                } else {
                                    element.text(element.data("readmoretxt") || "Read more");
                                    if (useDotdotdot) {
                                        API.truncate();
                                    }
                                }
                                if (!useDotdotdot) {
                                    var panelImg = targetEl.parents(".panel-ticket").find(".panel-image:first");
                                    var dealsBanner = panelImg.find(".deal-banner");
                                    if (dealsBanner) {
                                        dealsBanner.hide(200);
                                    }
                                    targetEl.slideToggle(function () {
                                        if (dealsBanner.length) {
                                            dealsBanner.css("width", panelImg.height());
                                            dealsBanner.show(200);
                                        }
                                        if (element.hasClass("read-less")) {
                                            element.addClass("expanded");
                                            targetEl.attr("aria-hidden", false);
                                        } else {
                                            element.removeClass("expanded");
                                            targetEl.attr("aria-hidden", true);
                                        }
                                        //  setTimeout(function () { jQuery($window).resize(); });
                                    });
                                }
                            });
                            setTimeout(function () {
                                if (element.hasClass("default-open")) { element.trigger("click"); }
                            });
                        });
                    }

                }
            };
        }
    ]);
    //app.directive('activityitem', function () {
    //    return {
    //        replace: true,
    //        restrict: 'E',
    //        // template: '<div><div ng-bind="reply.content"></div></div>' //this works fine
    //        templateUrl: '/Scripts/app/views/partials/activity/templates/activityItem.html' // same content
    //    };
    //});
    app.directive("listScroll", ["$window", function ($window) {
        return {
            restrict: "A",
            link: function (scope, element, attrs) {

                var mobBreakpoint =
                    attrs.disablebreakpoint > 0 ? parseInt(attrs.disablebreakpoint) : 767;

                function initScroll() {
                    if (checkSmallWindow()) return false;
                    if (getScrollDataObj() != null) return true;

                    var wrapper = attrs.scrollwrapper ? $(attrs.scrollwrapper) : element.find(".list-scroll-wrapper:eq(0)");

                    if (!wrapper.length || wrapper.childElementCount <= 0) return false;
                    try {
                        // 
                        var myScroll = new IScroll(attrs.scrollwrapper ? attrs.scrollwrapper : element.find(".list-scroll-wrapper:eq(0)")[0],
                            {
                                mouseWheel: true,
                                click: attrs.allowclick,
                                freeScroll: false,
                                preventDefault: true,
                                tap: true,
                                preventDefaultException: {
                                    containerClasses: [".list-scroll-wrapper"],
                                    //  className: /(^|\s)(form-control|md-select-value|md-text|check|circle|radio|btn|finalize-button|back-button|link-text|checbox-label|checbox-control-label|panel-body|md-off|md-on|md-container)(\s|$)/i,
                                    // tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|MD-INPUT-CONTAINER|A|LABEL|SPAN|md-radio-button)$/i
                                }

                            });

                        $(element).find(".back-button.set-pos").css("position", "absolute");
                        setScrollDataObj(myScroll);
                        scope.disableScrollArrows = false;
                        return true;
                    } catch (e) {
                        console.log(e);
                    }
                    return false;
                }

                function clearScrollStyle() {
                    scope.disableScrollArrows = true;
                    //clear element height
                    $(element).css("height", "");
                    var elScr = attrs.scrollwrapper ? $(attrs.scrollwrapper + " div:eq(0)") : element.find(".list-scroll-wrapper div:eq(0)");
                    elScr.css("height", "");
                    elScr.attr("style", "");
                    $(element).find(".back-button.set-pos").css("position", "");
                }

                function destroyScroll() {
                    var el = getScrollDataObj();
                    if (el != null) {
                        getScrollDataObj().destroy();
                        setScrollDataObj(null);
                    }
                    //clear element height
                    clearScrollStyle();
                }

                function checkSmallWindow() {
                    if ($($window).width() <= mobBreakpoint) {
                        clearScrollStyle();
                        return true;
                    };
                    return false;
                }

                function destroySliderForSmallWindow() {
                    if (checkSmallWindow()) {
                        destroyScroll();
                    } else {
                        initScroll();
                    }
                }

                function getScrollDataObj() {
                    return $(element).data("myScroll");
                }

                function setScrollDataObj(obj) {
                    return $(element).data("myScroll", obj);
                }

                function setElementHeight() {
                    if (jQuery(element).data("is-loadingHeight") === "1") return;
                    if (checkSmallWindow()) return;
                    jQuery(element).data("is-loadingHeight", "1");
                    var navbarHeight = jQuery(".navbar:first").height();
                    var cookieConsent = jQuery(".CookieConsent");
                    var cookieConsentHeight = 0;
                    if (cookieConsent.is(":visible")) {
                        cookieConsentHeight = cookieConsent.height();
                    }
                    $(element).height($window.innerHeight - ((element.prev().hasClass("filter-table")) ? element.prev().height() : 0) - navbarHeight - cookieConsentHeight);
                    jQuery(element).data("is-loadingHeight", "0");
                }

                function resizeScrollWrapper() {
                    if (jQuery(element).data("is-loadingWrappper") === "1") return false;
                    if (checkSmallWindow() || ((parseInt(attrs.scrolloffsetheight) || 0) <= 0 && (!attrs.fixedbottom || !attrs.fixedbottom.length) && !attrs.resizescrollwrapper)) return false;
                    jQuery(element).data("is-loadingWrappper", "1");
                    var wrap = attrs.scrollwrapper ? $(attrs.scrollwrapper + " div:eq(0)") : element.find(".list-scroll-wrapper div:eq(0)");
                    wrap.css("height", "");

                    var priceRowEl = (attrs.pricerow || "").length ? $(attrs.pricerow) : null;
                    var priceRowHeight = priceRowEl ? priceRowEl.height() : 0;

                    //(attrs.offsetforfixedbottom && attrs.offsetforfixedbottom.length)

                    var offset =
                        attrs.scrolloffsetheight > 0 ? parseInt(attrs.scrolloffsetheight) : 0;

                    if (wrap.height() == null) {
                        jQuery(element).data("is-loadingWrappper", "0");
                        return false;
                    }
                    var fixedButton = undefined;
                    if (attrs.fixedbottom && attrs.fixedbottom.length) {
                        fixedButton = $(attrs.fixedbottom);
                    }

                    if (fixedButton) {
                        fixedButton.css({ 'position': "relative", 'top': "-120px", 'width': "" });
                    }

                    if (wrap.height() + priceRowHeight + offset < $(element).height()) {
                        wrap.height($(element).height());
                        if (fixedButton) {
                            fixedButton.css({ 'position': "absolute", 'top': "", 'bottom': 0, 'width': "100%" });
                        }
                    } else {
                        if (offset > 0) {
                            wrap.css("height", "");
                            wrap.height(wrap.height() + offset + priceRowHeight);
                            wrap.data("offset", offset);
                        }

                        if (fixedButton) {
                            fixedButton.css({ 'position': "relative", 'top': "-58px", 'width': "" });
                        }
                    }
                    jQuery(element).data("is-loadingWrappper", "0");
                    return true;
                }

                function resizeOnCarouselLoad() {
                    if (checkSmallWindow()) return false;
                    if (!attrs.hascarousel || $(element).data("loaded") || (attrs.disableupdatingheight || $(element).find(".carousel").length === 0)) {
                        return false;
                    }

                    if ($(element).find(".carousel").height() > 0) {
                        setTimeout(function () {
                            $(window).resize();
                            $(element).data("loaded", true);
                        }, 0);
                    } else {
                        window.setTimeout(resizeOnCarouselLoad, 100);
                    }
                    return true;
                }

                function initTooltips() {
                    jQuery('[data-toggle="tooltip"]').tooltip({ container: 'body' });

                    jQuery(".list-scroll-wrapper").off("click").on("click", function () {
                        jQuery('[data-toggle="tooltip"]').tooltip("hide");
                    });
                };

                destroySliderForSmallWindow();

                if (!attrs.disableupdatingheight) {
                    setElementHeight();
                    resizeScrollWrapper();
                    // setOffsetHeight();
                }

                if (attrs.updateonimgload) {
                    $(element).find("img").each(function () {
                        //check if the image is already on cache
                        if ($(this).prop("complete")) {
                            window.setTimeout(function () {
                                $(window).resize();
                            }, 0);
                        } else {
                            /* Call the codes/function after the image is loaded */
                            $(this).on("load", function () {
                                window.setTimeout(function () {
                                    $(window).resize();
                                }, 0);
                            });
                        }
                    });
                }

                resizeOnCarouselLoad();

                function updateSlider() {

                    initTooltips();
                    destroySliderForSmallWindow();
                    if (checkSmallWindow()) return;
                    resizeOnCarouselLoad();
                    if (!attrs.disableupdatingheight) {
                        setElementHeight();
                        resizeScrollWrapper();
                    }
                    // setOffsetHeight();
                    setTimeout(function () {
                        var el = getScrollDataObj();
                        if (el != null) {
                            getScrollDataObj().refresh();
                            updateArrows();
                        }
                    }, 0);
                }

                if (attrs.watchupdate) {
                    var containter = jQuery(element).find(".list-scroll-wrapper")[0];
                    try {
                        var observer = new MutationObserver(function (mutations) {
                            updateSlider();
                        });

                        observer.observe(containter, {
                            childList: true,
                            subtree: true
                        });
                    }
                    catch (e) {
                        console.log("Mutation Observer not supported.");
                    }

                    jQuery(window).resize(function () {
                        updateSlider();
                    });


                }
                element.find(".scroll-down").on("click", function () {
                    var moveOffset = jQuery(this).data("moveoffset") || 150;

                    if (getScrollDataObj() && getScrollDataObj().maxScrollY < getScrollDataObj().y) {
                        getScrollDataObj().scrollTo(getScrollDataObj().x, getScrollDataObj().y - moveOffset, 500, getScrollDataObj().easing);
                    }
                    return false;
                });
                element.find(".scroll-up").on("click", function () {
                    var moveOffset = jQuery(this).data("moveoffset") || 150;
                    if (getScrollDataObj() && getScrollDataObj().y < 0) {
                        getScrollDataObj().scrollTo(getScrollDataObj().x, getScrollDataObj().y + moveOffset, 500, getScrollDataObj().easing);
                    }
                    return false;
                });

                function updateArrows() {
                    if (getScrollDataObj()) {
                        if (getScrollDataObj() && getScrollDataObj().maxScrollY >= getScrollDataObj().y) {
                            element.find(".scroll-down").addClass("ng-hide");
                        } else {
                            element.find(".scroll-down").removeClass("ng-hide");
                        }

                        if (getScrollDataObj() && getScrollDataObj().y >= 0) {
                            element.find(".scroll-up").addClass("ng-hide");
                        } else {
                            element.find(".scroll-up").removeClass("ng-hide");
                        }
                    }
                }

                jQuery(element).on("checkArrows", function () {
                    updateArrows();
                });

                setTimeout(function () {
                    initScroll();

                    if (getScrollDataObj()) {
                        getScrollDataObj().refresh();
                        getScrollDataObj().on("scrollEnd", function () {
                            updateArrows();
                        });
                    }
                }, 0);
            }
        };
    }
    ]);

    //custom filters
    app.filter('modulo', function () {
        return function (arr, num, val) {
            if (!arr) return arr;
            return arr.filter(function (item, index) {
                return index % num === (val || 0);
            })
        }
    });
    app.filter("dateFormat", function () {
        return function (dateString, format) {
            return moment(dateString).format(format ? format : "DD MMMM YYYY");
        };
    });

    app.filter("formatPriceDescription", ["$filter", "currenciesService", function ($filter, currenciesService) {

        return function (input, culture, currency, targetCurrency) {
            if (!currency || !targetCurrency || !culture || !input) return input;

            var findTag = /<[^\/].*?>[^<]*<\/.*?>/g;
            var priceTag = findTag.exec(input);
            var element = priceTag && priceTag[0];

            if (!element) return input;


            var priceInput = (element.match(/data-price="(.*?)"/i) || [, ""])[1];
            if (!priceInput) return input;

            priceInput = currenciesService.getPriceInSelectedCurrency(priceInput, currency, targetCurrency);

            var priceFormatted = $filter('formatPrice')(priceInput, culture, targetCurrency);

            return input.replace(element, priceFormatted);
        };
    }]);

    app.filter("formatPrice", function ($filter) {
        return function (input, culture, currency, minFractDigits) {
            input = parseFloat(input || 0);
            input = Math.round(input * 100) / 100; // round up to 2 decimal places
            culture = culture || "en";
            currency = currency || "USD";

            var styleProps = { style: "currency", currency: currency };
            if (minFractDigits != null && minFractDigits != undefined) {
                styleProps.minimumFractionDigits = minFractDigits;
            }
            return input.toLocaleString(culture, styleProps);
        };
    });
    app.filter("formatPriceWithoutCurrency", function ($filter) {
        return function (input, culture) {
            input = parseFloat(input || 0);
            input = Math.round(input * 100) / 100; // round up to 2 decimal places
            culture = culture || "en";

            return input.toLocaleString(culture);
        };
    });

    app.filter("setDecimalIfAny", function ($filter) {
        return function (input, places, currencySymbol) {
            currencySymbol = currencySymbol ? currencySymbol : "";
            if (!input || isNaN(input)) input = 0;
            return currencySymbol + input.toFixed(places);
        };
    });

    app.filter("rawHtml", [
        "$sce", "$compile", function ($sce, $compile) {
            return function (val) {
                return $sce.trustAsHtml(val);
            };
        }
    ]);

    // Setup the filter
    app.filter("filterAttractions", function () {
        // Create the return function and set the required parameter as well as an optional paramater
        return function (input, filterObj) {

            if (filterObj) {
                var out = [];

                angular.forEach(input, function (value, key) {
                    var type = true;


                    if (filterObj.type) {
                        type = (filterObj.type == "package" && value.isPackage) || (filterObj.type == "ticket" && !value.isPackage);
                    }
                    if (!type) return;

                    if (!value.isPackage && filterObj.totalTickets > 0 && value.minimumTicketCount > 0) {
                        type = filterObj.totalTickets >= value.minimumTicketCount;
                    }

                    if (!type) return;

                    out.push(value);


                }, out);

                return out;

            } else {
                return input;
            }

        };
    });
    app.filter("filterActivities", function () {

        // Create the return function and set the required parameter as well as an optional paramater
        return function (input, filterObj) {

            if (filterObj) {
                var out = [];

                angular.forEach(input, function (value, key) {
                    var categ = true,
                        loc = true,
                        priceR = true;

                    if (filterObj.selectedLocation) {
                        loc = false;
                        if (value.isHeader && (value.alternateStartingLocations || "").length) {
                            loc = _.some(value.alternateStartingLocations, function (l) {
                                return l.code === filterObj.selectedLocation.code;
                            });
                        }
                        else {
                            if (value.destination != null && value.destination.code != null) {
                                loc = value.destination.code === filterObj.selectedLocation.code;
                            } else if (value.startingLocation != null && value.startingLocation.code != null) {
                                loc = value.startingLocation.code === filterObj.selectedLocation.code;
                            }
                        }
                    }

                    if (loc) {

                        if (filterObj.selectedCategory) {
                            if (!(value.tags || "").length) {
                                categ = false;
                            } else {
                                categ = new RegExp(filterObj.selectedCategory.code + "\\b").test(value.tags);
                            }
                        }
                    } else {
                        categ = false;
                    }

                    if (categ) {
                        if (filterObj.selectedPriceRange != null) {
                            var condLow = false, condHigh = false;
                            condLow = value.price >= filterObj.selectedPriceRange.minValue;
                            condHigh = filterObj.selectedPriceRange.maxValue === 0 || value.price <= filterObj.selectedPriceRange.maxValue;

                            if (filterObj.selectedPriceRange.minValue > filterObj.selectedPriceRange.maxValue) {
                                priceR = true;
                            } else if (!condLow || !condHigh) {
                                priceR = false;
                            }
                        }
                    } else {
                        priceR = false;
                    }

                    if (priceR) {
                        out.push(value);
                    }

                }, out);

                return out;

            } else {
                return input;
            }

        };
    });

    app.filter("filterHotels", function () {

        // Create the return function and set the required parameter as well as an optional paramater
        return function (input, filterObj) {

            if (filterObj) {
                var out = [];

                angular.forEach(input, function (value, key) {
                    var categ = true,
                        loc = true,
                        priceR = true;

                    if (filterObj.selectedLocation != null) {
                        loc = false;
                        if (value.isHeader && (value.alternateStartingLocations || "").length) {
                            loc = _.some(value.alternateStartingLocations, function (l) {
                                return l.code === filterObj.selectedLocation.code;
                            });
                        } else {
                            if (value.destination != null && value.destination.name != null) {
                                loc = value.destination.name === filterObj.selectedLocation.name;
                            } else if (value.startingLocation != null && value.startingLocation.name != null) {
                                loc = value.startingLocation.name === filterObj.selectedLocation.name;
                            }
                        }
                    }

                    if (loc) {
                        if (filterObj.selectedCategory) {
                            if (!(value.tags || "").length) {
                                categ = false;
                            } else {
                                categ = new RegExp(filterObj.selectedCategory.description + "\\b").test(value.tags);
                            }
                        }
                    } else {
                        categ = false;
                    }

                    if (categ) {
                        if (filterObj.selectedPriceRange != null) {
                            var condLow = false, condHigh = false;
                            condLow = value.price >= filterObj.selectedPriceRange.minValue;
                            condHigh = filterObj.selectedPriceRange.maxValue === 0 || value.price <= filterObj.selectedPriceRange.maxValue;

                            if (filterObj.selectedPriceRange.minValue > filterObj.selectedPriceRange.maxValue) {
                                priceR = true;
                            } else if (!condLow || !condHigh) {
                                priceR = false;
                            }
                        }
                    } else {
                        priceR = false;
                    }

                    if (priceR) {
                        out.push(value);
                    }

                }, out);

                return out;

            } else {
                return input;
            }

        };
    });

    app.filter("filterTransportations", function () {

        // Create the return function and set the required parameter as well as an optional paramater
        return function (input, filterObj) {

            if (filterObj) {
                var out = [];

                angular.forEach(input, function (value, key) {
                    var categ = true,
                        loc = true,
                        priceR = true;

                    if (filterObj.selectedLocation != null) {
                        loc = false;
                        if (value.isHeader && (value.alternateStartingLocations || "").length) {
                            loc = _.some(value.alternateStartingLocations, function (l) {
                                return l.code === filterObj.selectedLocation.code;
                            });
                        } else {
                            if (value.destination != null && value.destination.name != null) {
                                loc = value.destination.name === filterObj.selectedLocation.name;
                            } else if (value.startingLocation != null && value.startingLocation.name != null) {
                                loc = value.startingLocation.name === filterObj.selectedLocation.name;
                            }
                        }
                    }
                    if (loc) {
                        if (filterObj.selectedCategory) {
                            if (!(value.tags || "").length) {
                                categ = false;
                            } else {
                                categ = new RegExp(filterObj.selectedCategory.description + "\\b").test(value.tags);
                            }
                        }
                    } else {
                        categ = false;
                    }

                    if (categ) {
                        if (filterObj.selectedPriceRange != null) {
                            var condLow = false, condHigh = false;
                            condLow = value.price >= filterObj.selectedPriceRange.minValue;
                            condHigh = filterObj.selectedPriceRange.maxValue === 0 || value.price <= filterObj.selectedPriceRange.maxValue;

                            if (filterObj.selectedPriceRange.minValue > filterObj.selectedPriceRange.maxValue) {
                                priceR = true;
                            } else if (!condLow || !condHigh) {
                                priceR = false;
                            }
                        }
                    } else {
                        priceR = false;
                    }

                    if (priceR) {
                        out.push(value);
                    }

                }, out);

                return out;

            } else {
                return input;
            }

        };
    });

    app.filter("stringFormat", function () {

        function toFormattedString(useLocale, format, values) {
            var result = "";

            for (var i = 0; ;) {
                // Find the next opening or closing brace
                var open = format.indexOf("{", i);
                var close = format.indexOf("}", i);
                if ((open < 0) && (close < 0)) {
                    // Not found: copy the end of the string and break
                    result += format.slice(i);
                    break;
                }
                if ((close > 0) && ((close < open) || (open < 0))) {

                    if (format.charAt(close + 1) !== "}") {
                        throw new Error("format stringFormatBraceMismatch");
                    }

                    result += format.slice(i, close + 1);
                    i = close + 2;
                    continue;
                }

                // Copy the string before the brace
                result += format.slice(i, open);
                i = open + 1;

                // Check for double braces (which display as one and are not arguments)
                if (format.charAt(i) === "{") {
                    result += "{";
                    i++;
                    continue;
                }

                if (close < 0) throw new Error("format stringFormatBraceMismatch");

                // Find the closing brace

                // Get the string between the braces, and split it around the ':' (if any)
                var brace = format.substring(i, close);
                var colonIndex = brace.indexOf(":");
                var argNumber = parseInt((colonIndex < 0) ? brace : brace.substring(0, colonIndex), 10);

                if (isNaN(argNumber)) throw new Error("format stringFormatInvalid");

                var argFormat = (colonIndex < 0) ? "" : brace.substring(colonIndex + 1);

                var arg = values[argNumber];
                if (typeof (arg) === "undefined" || arg === null) {
                    arg = "";
                }

                // If it has a toFormattedString method, call it.  Otherwise, call toString()
                if (arg.toFormattedString) {
                    result += arg.toFormattedString(argFormat);
                } else if (useLocale && arg.localeFormat) {
                    result += arg.localeFormat(argFormat);
                } else if (arg.format) {
                    result += arg.format(argFormat);
                } else
                    result += arg.toString();

                i = close + 1;
            }

            return result;
        };

        return function (/*string*/template, /*array*/values) {
            if (!values || !values.length || !template) {
                return template;
            }
            return toFormattedString(false, template, values);
        };
    });

})();;
(function () {
    "use strict";
    var app = angular.module("app");
    TweenMax.ticker.useRAF(false);
    app.animation(".updating-size-panel", function () {
        return {
            addClass: function (element, className, done) {
                // console.log('updating-size-panel', 'addClass');
                if (className&&className.indexOf("ng-hide") >= 0) {
                    element.hide(0, function () {
                        setTimeout(function () {
                            jQuery(window).resize();
                        });
                    });
                }
            },
            removeClass: function (element, className, done) {
                // console.log('updating-size-panel', 'removeClass');
                if (className&&className.indexOf("ng-hide") >= 0) {
                    element.show(0, function () {
                        setTimeout(function () {
                            jQuery(window).resize();
                        });
                    });

                }
            }
        };
    });
    // home page boxes
    app.animation(".animate-box", function () {
        return {
            removeClass: function (element, className, done) {
                if (className === "ng-hide") {
                    var title = jQuery(element).find(".section-title:first");
                    var description = jQuery(element).find(".section-description:first");
                    var tl = new TimelineMax({ onComplete: done });
                    tl.from(element, 1, { opacity: 0 }).
                    from(title, 1, { opacity: 0, top: -10, position: "relative" }).
                       from(description, 1, { opacity: 0, top: 10, position: "relative" });
                    tl.play();
                }
            }
        };
    });
    //login forms
    app.animation(".animate-panel", function () {
        return {
            addClass: function (element, className, done) {
                if (!element.hasClass("animate-on-hide")) return;
                if (className.indexOf("ng-hide") >= 0) {
                    element.removeClass("ng-hide");
                    var duration = $(element).data("duration") ? parseFloat($(element).data("duration")) : 1;
                    element.css("opacity", "1");
                    TweenLite.to(element, duration, {
                        opacity: 0,
                        //x: 50,
                        ease: Power1.easeInOut,
                        onComplete: function () {
                            element.addClass("ng-hide");
                            jQuery(window).resize();
                            done();
                        }
                    });
                }
            },
            removeClass: function (element, className, done) {

                if (className.indexOf("ng-hide") >= 0) {
                    //  element.show();
                    var duration = $(element).data("duration") ? parseFloat($(element).data("duration")) : 1;
                    element.css("opacity", "1");
                    TweenLite.from(element, duration, {
                        opacity: 0,
                        //x: 50,
                        ease: Power1.easeInOut,
                        onComplete: function () {
                            jQuery(window).resize();
                            done();
                        }
                    });
                }
            }
        };
    });
    //login forms
    app.animation(".animate-seq-panel", function () {
        return {
            addClass: function (element, className, done) {
                if (className.indexOf("ng-hide") >= 0) {
                    // element.hide();
                }
            },
            removeClass: function (element, className, done) {
                if (className.indexOf("ng-hide") >= 0) {
                    // element.show();
                    element.find(element.data("seq-element")).css("opacity", "1");
                    TweenMax.staggerFrom(element.find(element.data("seq-element")), element.data("anim-duration") || .7, {
                        opacity: 0, delay: (element.data("anim-delay") || 0.5), ease: Power1.easeInOut,
                        onComplete: function () {
                            jQuery(window).resize();
                        }
                    }, (element.data("seq-delay") || 0.2));
                }
            }
        };
    });

    //scroll list help overlay
    app.animation(".list-scroll-overlay", function () {
        return {
            // you can also capture these animation events
            addClass: function (element, className, done) {
                if (className === "ng-hide") {
                    element.css("opacity", 1);
                    element.find("[data-animate]").css("opacity", 1);
                    var imgAnim = element.find("img[data-animate]:first");
                    var divAnim = element.find("div[data-animate]");
                    imgAnim.css("opacity", 1).css("position", "relative");
                    divAnim.css("opacity", 1).css("position", "relative");

                    var timeOut = 0;
                    var duration = 100;

                    jQuery(divAnim.get().reverse()).each(function (index, del) {
                        setTimeout(function () {
                            if (index === divAnim.length - 1) {
                                jQuery(del).animate({
                                    opacity: 0,
                                    top: -10,
                                    duration: duration
                                }, function () {
                                    imgAnim.animate({
                                        opacity: 0,
                                        top: -10,
                                        duration: duration
                                    }, function () {

                                        jQuery(element).animate({
                                            opacity: 0,
                                            duration: duration
                                        }, done);
                                    });

                                });
                            } else {
                                jQuery(del).animate({
                                    opacity: 0,
                                    top: -10,
                                    duration: duration
                                });
                            }
                        }, timeOut);
                        timeOut += 100;
                    });
                }
            },
            removeClass: function (element, className, done) {
                if (className === "ng-hide") {
                    element.css("opacity", 0);
                    element.find("[data-animate]").css("opacity", 0);
                    var imgAnim = element.find("img[data-animate]:first");
                    var divAnim = element.find("div[data-animate]");
                    imgAnim.css("opacity", 0).css("position", "relative").css("top", "-10px");
                    divAnim.css("opacity", 0).css("position", "relative").css("top", "-10px");;
                    setTimeout(function () {
                        jQuery(element).animate({
                            opacity: 1,
                            top: 0
                        }, function () {

                            imgAnim.animate({
                                opacity: 1,
                                top: 0
                            }, function () {
                                var timeOut = 0;

                                divAnim.each(function (index, element) {
                                    setTimeout(function () {
                                        if (index === divAnim.length - 1) {
                                            jQuery(element).animate({
                                                opacity: 1,
                                                top: 0
                                            }, done);
                                        } else {
                                            jQuery(element).animate({
                                                opacity: 1,
                                                top: 0
                                            });
                                        }
                                    }, timeOut);
                                    timeOut += 200;
                                });
                            });
                        });
                    }, 300);
                }
            }
        };
    });
}());;
/**
 * Satellizer 0.14.1
 * (c) 2016 Sahat Yalkabov
 * License: MIT
 */

// CommonJS package manager support.
if (typeof module !== 'undefined' && typeof exports !== 'undefined' && module.exports === exports) {
  module.exports = 'satellizer';
}

(function(window, angular, undefined) {
  'use strict';

  if (!window.location.origin) {
    window.location.origin = window.location.protocol + '//' + window.location.hostname + (window.location.port ? (':' + window.location.port) : '');
  }

  angular.module('satellizer', [])
    .constant('SatellizerConfig', {
      httpInterceptor: function() { return true; },
      withCredentials: false,
      tokenRoot: null,
      baseUrl: '/',
      loginUrl: '/auth/login',
      signupUrl: '/auth/signup',
      unlinkUrl: '/auth/unlink',
      tokenName: 'token',
      tokenPrefix: 'satellizer',
      authHeader: 'Authorization',
      authToken: 'Bearer',
      storageType: 'localStorage',
      providers: {
        facebook: {
          name: 'facebook',
          url: '/auth/facebook',
          authorizationEndpoint: 'https://www.facebook.com/v2.5/dialog/oauth',
          redirectUri: window.location.origin + '/',
          requiredUrlParams: ['display', 'scope'],
          scope: ['email'],
          scopeDelimiter: ',',
          display: 'popup',
          oauthType: '2.0',
          popupOptions: { width: 580, height: 400 }
        },
        google: {
          name: 'google',
          url: '/auth/google',
          authorizationEndpoint: 'https://accounts.google.com/o/oauth2/auth',
          redirectUri: window.location.origin,
          requiredUrlParams: ['scope'],
          optionalUrlParams: ['display', 'state'],
          scope: ['profile', 'email'],
          scopePrefix: 'openid',
          scopeDelimiter: ' ',
          display: 'popup',
          oauthType: '2.0',
          popupOptions: { width: 452, height: 633 },
          state: function() {
            var rand = Math.random().toString(36).substr(2);
            return encodeURIComponent(rand);
          }
        },
        github: {
          name: 'github',
          url: '/auth/github',
          authorizationEndpoint: 'https://github.com/login/oauth/authorize',
          redirectUri: window.location.origin,
          optionalUrlParams: ['scope'],
          scope: ['user:email'],
          scopeDelimiter: ' ',
          oauthType: '2.0',
          popupOptions: { width: 1020, height: 618 }
        },
        instagram: {
          name: 'instagram',
          url: '/auth/instagram',
          authorizationEndpoint: 'https://api.instagram.com/oauth/authorize',
          redirectUri: window.location.origin,
          requiredUrlParams: ['scope'],
          scope: ['basic'],
          scopeDelimiter: '+',
          oauthType: '2.0'
        },
        linkedin: {
          name: 'linkedin',
          url: '/auth/linkedin',
          authorizationEndpoint: 'https://www.linkedin.com/uas/oauth2/authorization',
          redirectUri: window.location.origin,
          requiredUrlParams: ['state'],
          scope: ['r_emailaddress'],
          scopeDelimiter: ' ',
          state: 'STATE',
          oauthType: '2.0',
          popupOptions: { width: 527, height: 582 }
        },
        twitter: {
          name: 'twitter',
          url: '/auth/twitter',
          authorizationEndpoint: 'https://api.twitter.com/oauth/authenticate',
          redirectUri: window.location.origin,
          oauthType: '1.0',
          popupOptions: { width: 495, height: 645 }
        },
        twitch: {
          name: 'twitch',
          url: '/auth/twitch',
          authorizationEndpoint: 'https://api.twitch.tv/kraken/oauth2/authorize',
          redirectUri: window.location.origin,
          requiredUrlParams: ['scope'],
          scope: ['user_read'],
          scopeDelimiter: ' ',
          display: 'popup',
          oauthType: '2.0',
          popupOptions: { width: 500, height: 560 }
        },
        live: {
          name: 'live',
          url: '/auth/live',
          authorizationEndpoint: 'https://login.live.com/oauth20_authorize.srf',
          redirectUri: window.location.origin,
          requiredUrlParams: ['display', 'scope'],
          scope: ['wl.emails'],
          scopeDelimiter: ' ',
          display: 'popup',
          oauthType: '2.0',
          popupOptions: { width: 500, height: 560 }
        },
        yahoo: {
          name: 'yahoo',
          url: '/auth/yahoo',
          authorizationEndpoint: 'https://api.login.yahoo.com/oauth2/request_auth',
          redirectUri: window.location.origin,
          scope: [],
          scopeDelimiter: ',',
          oauthType: '2.0',
          popupOptions: { width: 559, height: 519 }
        },
        bitbucket: {
          name: 'bitbucket',
          url: '/auth/bitbucket',
          authorizationEndpoint: 'https://bitbucket.org/site/oauth2/authorize',
          redirectUri: window.location.origin + '/',
          requiredUrlParams: ['scope'],
          scope: ['email'],
          scopeDelimiter: ' ',
          oauthType: '2.0',
          popupOptions: { width: 1028, height: 529 }
        }
      }
    })
    .provider('$auth', ['SatellizerConfig', function(config) {
      Object.defineProperties(this, {
        httpInterceptor: {
          get: function() { return config.httpInterceptor; },
          set: function(value) {
            if (typeof value === 'function') {
              config.httpInterceptor = value;
            } else {
              config.httpInterceptor = function() {
                return value;
              };
            }
          }
        },
        baseUrl: {
          get: function() { return config.baseUrl; },
          set: function(value) { config.baseUrl = value; }
        },
        loginUrl: {
          get: function() { return config.loginUrl; },
          set: function(value) { config.loginUrl = value; }
        },
        signupUrl: {
          get: function() { return config.signupUrl; },
          set: function(value) { config.signupUrl = value; }
        },
        tokenRoot: {
          get: function() { return config.tokenRoot; },
          set: function(value) { config.tokenRoot = value; }
        },
        tokenName: {
          get: function() { return config.tokenName; },
          set: function(value) { config.tokenName = value; }
        },
        tokenPrefix: {
          get: function() { return config.tokenPrefix; },
          set: function(value) { config.tokenPrefix = value; }
        },
        unlinkUrl: {
          get: function() { return config.unlinkUrl; },
          set: function(value) { config.unlinkUrl = value; }
        },
        authHeader: {
          get: function() { return config.authHeader; },
          set: function(value) { config.authHeader = value; }
        },
        authToken: {
          get: function() { return config.authToken; },
          set: function(value) { config.authToken = value; }
        },
        withCredentials: {
          get: function() { return config.withCredentials; },
          set: function(value) { config.withCredentials = value; }
        },
        storageType: {
          get: function() { return config.storageType; },
          set: function(value) { config.storageType = value; }
        }
      });

      angular.forEach(Object.keys(config.providers), function(provider) {
        this[provider] = function(params) {
          return angular.extend(config.providers[provider], params);
        };
      }, this);

      var oauth = function(params) {
        config.providers[params.name] = config.providers[params.name] || {};
        angular.extend(config.providers[params.name], params);
      };

      this.oauth1 = function(params) {
        oauth(params);
        config.providers[params.name].oauthType = '1.0';
      };

      this.oauth2 = function(params) {
        oauth(params);
        config.providers[params.name].oauthType = '2.0';
      };

      this.$get = [
        '$q',
        'SatellizerShared',
        'SatellizerLocal',
        'SatellizerOauth',
        function($q, shared, local, oauth) {
          var $auth = {};

          $auth.login = function(user, opts) {
            return local.login(user, opts);
          };

          $auth.signup = function(user, options) {
            return local.signup(user, options);
          };

          $auth.logout = function() {
            return shared.logout();
          };

          $auth.authenticate = function(name, userData) {
            return oauth.authenticate(name, userData);
          };

          $auth.link = function(name, userData) {
            return oauth.authenticate(name, userData);
          };

          $auth.unlink = function(provider, opts) {
            return oauth.unlink(provider, opts);
          };

          $auth.isAuthenticated = function() {
            return shared.isAuthenticated();
          };

          $auth.getToken = function() {
            return shared.getToken();
          };

          $auth.setToken = function(token) {
            shared.setToken({ access_token: token });
          };

          $auth.removeToken = function() {
            return shared.removeToken();
          };

          $auth.getPayload = function() {
            return shared.getPayload();
          };

          $auth.setStorageType = function(type) {
            return shared.setStorageType(type);
          };

          return $auth;
        }];
    }])
    .factory('SatellizerShared', [
      '$q',
      '$window',
      '$log',
      'SatellizerConfig',
      'SatellizerStorage',
      function($q, $window, $log, config, storage) {
        var Shared = {};

        var tokenName = config.tokenPrefix ? [config.tokenPrefix, config.tokenName].join('_') : config.tokenName;

        Shared.getToken = function() {
          return storage.get(tokenName);
        };

        Shared.getPayload = function() {
          var token = storage.get(tokenName);

          if (token && token.split('.').length === 3) {
            try {
              var base64Url = token.split('.')[1];
              var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
              return JSON.parse(decodeURIComponent(escape(window.atob(base64))));
            } catch(e) {
              return undefined;
            }
          }
        };

        Shared.setToken = function(response) {
          if (!response) {
            return $log.warn('Can\'t set token without passing a value');
          }

          var accessToken = response && response.access_token;
          var token;

          if (accessToken) {
            if (angular.isObject(accessToken) && angular.isObject(accessToken.data)) {
              response = accessToken;
            } else if (angular.isString(accessToken)) {
              token = accessToken;
            }
          }

          if (!token && response) {
            var tokenRootData = config.tokenRoot && config.tokenRoot.split('.').reduce(function(o, x) { return o[x]; }, response.data);
            token = tokenRootData ? tokenRootData[config.tokenName] : response.data && response.data[config.tokenName];
          }

          if (!token) {
            var tokenPath = config.tokenRoot ? config.tokenRoot + '.' + config.tokenName : config.tokenName;
            return $log.warn('Expecting a token named "' + tokenPath);
          }

          storage.set(tokenName, token);
        };

        Shared.removeToken = function() {
          storage.remove(tokenName);
        };

        /**
         * @returns {boolean}
         */
        Shared.isAuthenticated = function() {
          var token = storage.get(tokenName);
          // A token is present
          if (token) {
            // Token with a valid JWT format XXX.YYY.ZZZ
            if (token.split('.').length === 3) {
              // Could be a valid JWT or an access token with the same format
              try {
                var base64Url = token.split('.')[1];
                var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
                var exp = JSON.parse($window.atob(base64)).exp;
                // JWT with an optonal expiration claims
                if (exp) {
                  var isExpired = Math.round(new Date().getTime() / 1000) >= exp;
                  if (isExpired) {
                    // FAIL: Expired token
                    return false;
                  } else {
                    // PASS: Non-expired token
                    return true;
                  }
                }
              } catch(e) {
                // PASS: Non-JWT token that looks like JWT
                return true;
              }
            }
            // PASS: All other tokens
            return true;
          }
          // FAIL: No token at all
          return false;
        };

        Shared.logout = function() {
          storage.remove(tokenName);
          return $q.when();
        };

        Shared.setStorageType = function(type) {
          config.storageType = type;
        };

        return Shared;
      }])
    .factory('SatellizerOauth', [
      '$q',
      '$http',
      'SatellizerConfig',
      'SatellizerUtils',
      'SatellizerShared',
      'SatellizerOauth1',
      'SatellizerOauth2',
      function($q, $http, config, utils, shared, Oauth1, Oauth2) {
        var Oauth = {};

        Oauth.authenticate = function(name, userData) {
          var provider = config.providers[name].oauthType === '1.0' ? new Oauth1() : new Oauth2();
          var deferred = $q.defer();

          provider.open(config.providers[name], userData || {})
            .then(function(response) {
              // This is for a scenario when someone wishes to opt out from
              // Satellizer's magic by doing authorization code exchange and
              // saving a token manually.
              if (config.providers[name].url) {
                shared.setToken(response, false);
              }
              deferred.resolve(response);
            })
            .catch(function(error) {
              deferred.reject(error);
            });

          return deferred.promise;
        };

        Oauth.unlink = function(provider, opts) {
          opts = opts || {};
          opts.url = opts.url ? opts.url : utils.joinUrl(config.baseUrl, config.unlinkUrl);
          opts.data = { provider: provider } || opts.data;
          opts.method = opts.method || 'POST';
          opts.withCredentials = opts.withCredentials || config.withCredentials;

          return $http(opts);
        };

        return Oauth;
      }])
    .factory('SatellizerLocal', [
      '$http',
      'SatellizerUtils',
      'SatellizerShared',
      'SatellizerConfig',
      function($http, utils, shared, config) {
        var Local = {};

        Local.login = function(user, opts) {
          opts = opts || {};
          opts.url = opts.url ? opts.url : utils.joinUrl(config.baseUrl, config.loginUrl);
          opts.data = user || opts.data;
          opts.method = opts.method || 'POST';
          opts.withCredentials = opts.withCredentials || config.withCredentials;

          return $http(opts).then(function(response) {
            shared.setToken(response);
            return response;
          });
        };

        Local.signup = function(user, opts) {
          opts = opts || {};
          opts.url = opts.url ? opts.url : utils.joinUrl(config.baseUrl, config.signupUrl);
          opts.data = user || opts.data;
          opts.method = opts.method || 'POST';
          opts.withCredentials = opts.withCredentials || config.withCredentials;

          return $http(opts);
        };

        return Local;
      }])
    .factory('SatellizerOauth2', [
      '$q',
      '$http',
      '$window',
      '$timeout',
      'SatellizerPopup',
      'SatellizerUtils',
      'SatellizerConfig',
      'SatellizerStorage',
      function($q, $http, $window, $timeout, popup, utils, config, storage) {
        return function() {
          var Oauth2 = {};

          var defaults = {
            defaultUrlParams: ['response_type', 'client_id', 'redirect_uri'],
            responseType: 'code',
            responseParams: {
              code: 'code',
              clientId: 'clientId',
              redirectUri: 'redirectUri'
            }
          };

          Oauth2.open = function(options, userData) {
            defaults = utils.merge(options, defaults);
            var defer = $q.defer();

            $timeout(function () {
              var url;
              var openPopup;
              var stateName = defaults.name + '_state';

              if (angular.isFunction(defaults.state)) {
                storage.set(stateName, defaults.state());
              } else if (angular.isString(defaults.state)) {
                storage.set(stateName, defaults.state);
              }

              url = [defaults.authorizationEndpoint, Oauth2.buildQueryString()].join('?');

              if (window.cordova) {
                openPopup = popup.open(url, defaults.name, defaults.popupOptions, defaults.redirectUri).eventListener(defaults.redirectUri);
              } else {
                openPopup = popup.open(url, defaults.name, defaults.popupOptions, defaults.redirectUri).pollPopup(defaults.redirectUri);
              }

              openPopup
                .then(function(oauthData) {
                  // When no server URL provided, return popup params as-is.
                  // This is for a scenario when someone wishes to opt out from
                  // Satellizer's magic by doing authorization code exchange and
                  // saving a token manually.
                  if (defaults.responseType === 'token' || !defaults.url) {
                    return defer.resolve(oauthData);
                  }

                  if (oauthData.state && oauthData.state !== storage.get(stateName)) {
                    return defer.reject(
                      'The value returned in the state parameter does not match the state value from your original ' +
                      'authorization code request.'
                    );
                  }

                  defer.resolve(Oauth2.exchangeForToken(oauthData, userData));
                }, function (err) {
                  defer.reject(err);
                });
            });

            return defer.promise;
          };

          Oauth2.exchangeForToken = function(oauthData, userData) {
            var data = angular.extend({}, userData);

            angular.forEach(defaults.responseParams, function(value, key) {
              switch (key) {
                case 'code':
                  data[value] = oauthData.code;
                  break;
                case 'clientId':
                  data[value] = defaults.clientId;
                  break;
                case 'redirectUri':
                  data[value] = defaults.redirectUri;
                  break;
                default:
                  data[value] = oauthData[key];
              }
            });

            if (oauthData.state) {
              data.state = oauthData.state;
            }

            var exchangeForTokenUrl = config.baseUrl ? utils.joinUrl(config.baseUrl, defaults.url) : defaults.url;

            return $http.post(exchangeForTokenUrl, data, { withCredentials: config.withCredentials });
          };

          Oauth2.buildQueryString = function() {
            var keyValuePairs = [];
            var urlParamsCategories = ['defaultUrlParams', 'requiredUrlParams', 'optionalUrlParams'];

            angular.forEach(urlParamsCategories, function(paramsCategory) {
              angular.forEach(defaults[paramsCategory], function(paramName) {
                var camelizedName = utils.camelCase(paramName);
                var paramValue = angular.isFunction(defaults[paramName]) ? defaults[paramName]() : defaults[camelizedName];

                if (paramName === 'redirect_uri' && !paramValue) {
                    return;
                }

                if (paramName === 'state') {
                  var stateName = defaults.name + '_state';
                  paramValue = encodeURIComponent(storage.get(stateName));
                }

                if (paramName === 'scope' && Array.isArray(paramValue)) {
                  paramValue = paramValue.join(defaults.scopeDelimiter);

                  if (defaults.scopePrefix) {
                    paramValue = [defaults.scopePrefix, paramValue].join(defaults.scopeDelimiter);
                  }
                }

                keyValuePairs.push([paramName, paramValue]);
              });
            });

            return keyValuePairs.map(function(pair) {
              return pair.join('=');
            }).join('&');
          };

          return Oauth2;
        };
      }])
    .factory('SatellizerOauth1', [
      '$q',
      '$http',
      'SatellizerPopup',
      'SatellizerConfig',
      'SatellizerUtils',
      function($q, $http, popup, config, utils) {
        return function() {
          var Oauth1 = {};

          var defaults = {
            url: null,
            name: null,
            popupOptions: null,
            redirectUri: null,
            authorizationEndpoint: null
          };

          Oauth1.open = function(options, userData) {
            angular.extend(defaults, options);
            var popupWindow;
            var serverUrl = config.baseUrl ? utils.joinUrl(config.baseUrl, defaults.url) : defaults.url;

            if (!window.cordova) {
                popupWindow = popup.open('', defaults.name, defaults.popupOptions, defaults.redirectUri);
            }

            return $http.post(serverUrl, defaults)
              .then(function(response) {
                var url = [defaults.authorizationEndpoint, Oauth1.buildQueryString(response.data)].join('?');

                if (window.cordova) {
                  popupWindow = popup.open(url, defaults.name, defaults.popupOptions, defaults.redirectUri);
                } else {
                  popupWindow.popupWindow.location = url;
                }

                var popupListener;

                if (window.cordova) {
                  popupListener = popupWindow.eventListener(defaults.redirectUri);
                } else {
                  popupListener = popupWindow.pollPopup(defaults.redirectUri);
                }

                return popupListener
                  .then(function(response) {
                    return Oauth1.exchangeForToken(response, userData);
                  });
              });

          };

          Oauth1.exchangeForToken = function(oauthData, userData) {
            var data = angular.extend({}, userData, oauthData);
            var exchangeForTokenUrl = config.baseUrl ? utils.joinUrl(config.baseUrl, defaults.url) : defaults.url;
            return $http.post(exchangeForTokenUrl, data, { withCredentials: config.withCredentials });
          };

          Oauth1.buildQueryString = function(obj) {
            var str = [];

            angular.forEach(obj, function(value, key) {
              str.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
            });

            return str.join('&');
          };

          return Oauth1;
        };
      }])
    .factory('SatellizerPopup', [
      '$q',
      '$interval',
      '$window',
      'SatellizerConfig',
      'SatellizerUtils',
      function($q, $interval, $window, config, utils) {
        var Popup = {};

        Popup.url = '';
        Popup.popupWindow = null;

        Popup.open = function(url, name, options) {
          Popup.url = url;

          var stringifiedOptions = Popup.stringifyOptions(Popup.prepareOptions(options));
          var UA = $window.navigator.userAgent;
          var windowName = (window.cordova || UA.indexOf('CriOS') > -1) ? '_blank' : name;

          Popup.popupWindow = $window.open(url, windowName, stringifiedOptions);

          $window.popup = Popup.popupWindow;

          if (Popup.popupWindow && Popup.popupWindow.focus) {
            Popup.popupWindow.focus();
          }

          return Popup;
        };

        Popup.eventListener = function(redirectUri) {
          var deferred = $q.defer();

          Popup.popupWindow.addEventListener('loadstart', function(event) {
            if (event.url.indexOf(redirectUri) !== 0) {
              return;
            }

            var parser = document.createElement('a');
            parser.href = event.url;

            if (parser.search || parser.hash) {
              var queryParams = parser.search.substring(1).replace(/\/$/, '');
              var hashParams = parser.hash.substring(1).replace(/\/$/, '');
              var hash = utils.parseQueryString(hashParams);
              var qs = utils.parseQueryString(queryParams);

              angular.extend(qs, hash);

              if (!qs.error) {
                deferred.resolve(qs);
              }

              Popup.popupWindow.close();
            }
          });

          Popup.popupWindow.addEventListener('loaderror', function() {
            deferred.reject('Authorization Failed');
          });

          return deferred.promise;
        };

        Popup.pollPopup = function(redirectUri) {
          var deferred = $q.defer();

          var redirectUriParser = document.createElement('a');
          redirectUriParser.href = redirectUri;

          var redirectUriPath = utils.getFullUrlPath(redirectUriParser);

          var polling = $interval(function() {
            if (!Popup.popupWindow || Popup.popupWindow.closed || Popup.popupWindow.closed === undefined) {
              deferred.reject('The popup window was closed.');
              $interval.cancel(polling);
            }

            try {
              var popupWindowPath = utils.getFullUrlPath(Popup.popupWindow.location);

              // Redirect has occurred.
              if (popupWindowPath === redirectUriPath) {
                // Contains query/hash parameters as expected.
                if (Popup.popupWindow.location.search || Popup.popupWindow.location.hash) {
                  var queryParams = Popup.popupWindow.location.search.substring(1).replace(/\/$/, '');
                  var hashParams = Popup.popupWindow.location.hash.substring(1).replace(/[\/$]/, '');
                  var hash = utils.parseQueryString(hashParams);
                  var qs = utils.parseQueryString(queryParams);

                  angular.extend(qs, hash);

                  if (qs.error) {
                    deferred.reject(qs);
                  } else {
                    deferred.resolve(qs);
                  }
                } else {
                  // Does not contain query/hash parameters, can't do anything at this point.
                  deferred.reject(
                    'Redirect has occurred but no query or hash parameters were found. ' +
                    'They were either not set during the redirect, or were removed before Satellizer ' +
                    'could read them, e.g. AngularJS routing mechanism.'
                  );
                }

                $interval.cancel(polling);
                Popup.popupWindow.close();
              }
            } catch (error) {
              // Ignore DOMException: Blocked a frame with origin from accessing a cross-origin frame.
              // A hack to get around same-origin security policy errors in IE.
            }
          }, 20);

          return deferred.promise;
        };

        Popup.prepareOptions = function(options) {
          options = options || {};
          var width = options.width || 500;
          var height = options.height || 500;

          return angular.extend({
            width: width,
            height: height,
            left: $window.screenX + (($window.outerWidth - width) / 2),
            top: $window.screenY + (($window.outerHeight - height) / 2.5)
          }, options);
        };

        Popup.stringifyOptions = function(options) {
          var parts = [];
          angular.forEach(options, function(value, key) {
            parts.push(key + '=' + value);
          });
          return parts.join(',');
        };

        return Popup;
      }])
    .service('SatellizerUtils', function() {
      this.getFullUrlPath = function(location) {
        var isHttps = location.protocol === 'https:';
        return location.protocol + '//' + location.hostname +
          ':' + (location.port || (isHttps ? '443' : '80')) +
          (/^\//.test(location.pathname) ? location.pathname : '/' + location.pathname);
      };

      this.camelCase = function(name) {
        return name.replace(/([\:\-\_]+(.))/g, function(_, separator, letter, offset) {
          return offset ? letter.toUpperCase() : letter;
        });
      };

      this.parseQueryString = function(keyValue) {
        var obj = {}, key, value;
        angular.forEach((keyValue || '').split('&'), function(keyValue) {
          if (keyValue) {
            value = keyValue.split('=');
            key = decodeURIComponent(value[0]);
            obj[key] = angular.isDefined(value[1]) ? decodeURIComponent(value[1]) : true;
          }
        });
        return obj;
      };

      this.joinUrl = function(baseUrl, url) {
        if (/^(?:[a-z]+:)?\/\//i.test(url)) {
          return url;
        }

        var joined = [baseUrl, url].join('/');

        var normalize = function(str) {
          return str
            .replace(/[\/]+/g, '/')
            .replace(/\/\?/g, '?')
            .replace(/\/\#/g, '#')
            .replace(/\:\//g, '://');
        };

        return normalize(joined);
      };

      this.merge = function(obj1, obj2) {
        var result = {};
        for (var i in obj1) {
          if (obj1.hasOwnProperty(i)) {
            if ((i in obj2) && (typeof obj1[i] === 'object') && (i !== null)) {
              result[i] = this.merge(obj1[i], obj2[i]);
            } else {
              result[i] = obj1[i];
            }
          }
        }
        for (i in obj2) {
          if (obj2.hasOwnProperty(i)) {
            if (i in result) {
              continue;
            }
            result[i] = obj2[i];
          }

        }
        return result;
      };
    })
    .factory('SatellizerStorage', ['$window', '$log', 'SatellizerConfig', function($window, $log, config) {

      var store = {};

      // Check if localStorage or sessionStorage is available or enabled
      var isStorageAvailable = (function() {
        try {
          var supported = config.storageType in $window && $window[config.storageType] !== null;

          if (supported) {
            var key = Math.random().toString(36).substring(7);
            $window[config.storageType].setItem(key, '');
            $window[config.storageType].removeItem(key);
          }

          return supported;
        } catch (e) {
          return false;
        }
      })();

      if (!isStorageAvailable) {
        $log.warn(config.storageType + ' is not available.');
      }

      return {
        get: function(key) {
          return isStorageAvailable ? $window[config.storageType].getItem(key) : store[key];
        },
        set: function(key, value) {
          return isStorageAvailable ? $window[config.storageType].setItem(key, value) : store[key] = value;
        },
        remove: function(key) {
          return isStorageAvailable ? $window[config.storageType].removeItem(key): delete store[key];
        }
      };

    }])
    .factory('SatellizerInterceptor', [
      '$q',
      'SatellizerConfig',
      'SatellizerStorage',
      'SatellizerShared',
      function($q, config, storage, shared) {
        return {
          request: function(request) {
            if (request.skipAuthorization) {
              return request;
            }

            if (shared.isAuthenticated() && config.httpInterceptor(request)) {
              var tokenName = config.tokenPrefix ? config.tokenPrefix + '_' + config.tokenName : config.tokenName;
              var token = storage.get(tokenName);

              if (config.authHeader && config.authToken) {
                token = config.authToken + ' ' + token;
              }

              request.headers[config.authHeader] = token;
            }

            return request;
          },
          responseError: function(response) {
            return $q.reject(response);
          }
        };
      }])
    .config(['$httpProvider', function($httpProvider) {
      $httpProvider.interceptors.push('SatellizerInterceptor');
    }]);

})(window, window.angular);
;
'use strict';

/**
 * @ngdoc module
 * @name angular-bootstrap-select.extra
 * @description
 * Angular bootstrap-select extra.
 */

angular.module('angular-bootstrap-select.extra', [])
  .directive('dropdownToggle', [dropdownToggleDirective])
  .directive('dropdownClose', [dropdownCloseDirective]);

/**
 * @ngdoc directive
 * @name dropdownToggle
 * @restrict ACE
 *
 * @description
 * This extra directive provide dropdown toggle specifically to bootstrap-select without loading bootstrap.js.
 *
 * @usage
 * ```html
 * <div class="dropdown-toggle">
 *   <select class="selectpicker">
 *      <option value="">Select one</option>
 *      <option>Mustard</option>
 *      <option>Ketchup</option>
 *      <option>Relish</option>
 *   </select>
 * </div>
 *
 * <div dropdown-toggle>
 *   <select class="selectpicker">
 *      <option value="">Select one</option>
 *      <option>Mustard</option>
 *      <option>Ketchup</option>
 *      <option>Relish</option>
 *   </select>
 * </div>
 *
 * <dropdown-toggle>
 *   <select class="selectpicker">
 *      <option value="">Select one</option>
 *      <option>Mustard</option>
 *      <option>Ketchup</option>
 *      <option>Relish</option>
 *   </select>
 * </dropdown-toggle>
 * ```
 */

function dropdownToggleDirective() {
  return {
    restrict: 'ACE',
    priority: 101,
    link: function (scope, element, attrs) {
      var toggleFn = function (e) {
        var parent = angular.element(this).parent();

        angular.element('.bootstrap-select.open', element)
          .not(parent)
          .removeClass('open');

        parent.toggleClass('open');
      };

      element.on('click.bootstrapSelect', '.dropdown-toggle', toggleFn);

      scope.$on('$destroy', function () {
        element.off('.bootstrapSelect');
      });
    }
  };
}

/**
 * @ngdoc directive
 * @name dropdownClear
 * @restrict ACE
 *
 * @description
 * This extra directive provide the closing of ALL open dropdowns clicking away
 *
 * @usage
 * ```html
 * <div class="dropdown-close">
 *   <select class="selectpicker">
 *      <option value="">Select one</option>
 *      <option>Mustard</option>
 *      <option>Ketchup</option>
 *      <option>Relish</option>
 *   </select>
 * </div>
 *
 * <div dropdown-close>
 *   <select class="selectpicker">
 *      <option value="">Select one</option>
 *      <option>Mustard</option>
 *      <option>Ketchup</option>
 *      <option>Relish</option>
 *   </select>
 * </div>
 *
 * <dropdown-close>
 *   <select class="selectpicker">
 *      <option value="">Select one</option>
 *      <option>Mustard</option>
 *      <option>Ketchup</option>
 *      <option>Relish</option>
 *   </select>
 * </dropdown-close>
 * ```
 */

function dropdownCloseDirective() {
  return {
    restrict: 'ACE',
    priority: 101,
    link: function (scope, element, attrs) {
      var hideFn = function (e) {
        var parent = e.target.tagName !== 'A' && angular.element(e.target).parents('.bootstrap-select');

        angular.element('.bootstrap-select.open', element)
          .not(parent)
          .removeClass('open');
      };

      angular.element(document).on('click.bootstrapSelect', hideFn);

      scope.$on('$destroy', function () {
        angular.element(document).off('.bootstrapSelect');
      });
    }
  };
}

/**
 * @ngdoc module
 * @name angular-bootstrap-select
 * @description
 * Angular bootstrap-select.
 */

angular.module('angular-bootstrap-select', [])
  .directive('selectpicker', ['$parse', '$timeout', selectpickerDirective]);

/**
 * @ngdoc directive
 * @name selectpicker
 * @restrict A
 *
 * @param {object} selectpicker Directive attribute to configure bootstrap-select, full configurable params can be found in [bootstrap-select docs](http://silviomoreto.github.io/bootstrap-select/).
 * @param {string} ngModel Assignable angular expression to data-bind to.
 *
 * @description
 * The selectpicker directive is used to wrap bootstrap-select.
 *
 * @usage
 * ```html
 * <select selectpicker ng-model="model">
 *   <option value="">Select one</option>
 *   <option>Mustard</option>
 *   <option>Ketchup</option>
 *   <option>Relish</option>
 * </select>
 *
 * <select selectpicker="{dropupAuto:false}" ng-model="model">
 *   <option value="">Select one</option>
 *   <option>Mustard</option>
 *   <option>Ketchup</option>
 *   <option>Relish</option>
 * </select>
 * ```
 */

function selectpickerDirective($parse, $timeout) {
  return {
    restrict: 'A',
    priority: 1000,
    link: function (scope, element, attrs) {
      function refresh(newVal) {
        scope.$applyAsync(function () {
          if (attrs.ngOptions && /track by/.test(attrs.ngOptions)) element.val(newVal);
          element.selectpicker('refresh');
        });
      }

      attrs.$observe('spTheme', function (val) {
        $timeout(function () {
          element.data('selectpicker').$button.removeClass(function (i, c) {
            return (c.match(/(^|\s)?btn-\S+/g) || []).join(' ');
          });
          element.selectpicker('setStyle', val);
        });
      });

      $timeout(function () {
        element.selectpicker($parse(attrs.selectpicker)());
        element.selectpicker('refresh');
      });

      if (attrs.ngModel) {
        scope.$watch(attrs.ngModel, refresh, true);
      }

      if (attrs.ngDisabled) {
        scope.$watch(attrs.ngDisabled, refresh, true);
      }

      scope.$on('$destroy', function () {
        $timeout(function () {
          element.selectpicker('destroy');
        });
      });
    }
  };
}
;
(function($) {
    "use strict";

    angular.module("app").config(["$stateProvider", "$urlRouterProvider",  function ($stateProvider, $urlRouterProvider) {
        //
        // For any unmatched url, redirect to /state1
        //$urlRouterProvider.otherwise("/state1");
        //
        // Now set up the states
        $stateProvider
            .state("account-info", {
                url: "/account-info",
                templateUrl: "/scripts/app/views/partials/account/account-info.html"
            }).state("bookings", {
                url: "/bookings",
                templateUrl: "/scripts/app/views/partials/account/bookings.html"
            })
            .state("commissions", {
                url: "/commissions",
                templateUrl: "/scripts/app/views/partials/account/commissions.html"
            })
             .state("agency-contacts", {
                 url: "/agency-contacts",
                 templateUrl: "/scripts/app/views/partials/account/agency-contacts.html"
             }).
            state("my-cards", {
                url: "/my-cards",
                templateUrl: "/scripts/app/views/partials/account/my-cards.html"
            })
        .state("email-password", {
            url: "/email-and-password",
            templateUrl: "/scripts/app/views/partials/account/email-password.html"
        });

    }]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").config([
        "$stateProvider", "$urlRouterProvider", function ($stateProvider, $urlRouterProvider) {
            //
            // For any unmatched url, redirect to /state1
            //$urlRouterProvider.otherwise("/state1");
            //
            // Now set up the states
            $stateProvider
                .state("select-ticket", {
                    url: "/select-ticket",
                    templateUrl: "/scripts/app/views/partials/activity/select-ticket.html",
                    redirectTo: 'select-ticket.book-adventure'
                })
                .state("select-ticket.book-adventure", {
                    url: "/book-adventure",
                    // templateUrl: "/scripts/app/views/partials/activity/book-adventure.html",
                    templateUrl: function () {
                        var targetEl = jQuery("[data-activity-product-category]:first");
                        var code = targetEl && targetEl.data("activity-product-code");
                        var productType = targetEl && targetEl.data("activity-product-type");
                        //debugger;
                        var categ = targetEl ? targetEl.data("activity-product-category") : undefined;
                        if (categ && categ.toLowerCase().indexOf("tour") >= 0) {
                            return "/scripts/app/views/partials/activity/book-tour.html";
                        }

                        if (productType == "SPA-C" || (code && code.toLowerCase().indexOf("spa") >= 0) || (categ && categ.toLowerCase().indexOf("spa") >= 0)) {
                            return "/scripts/app/views/partials/activity/book-spa.html";
                        }
                        return "/scripts/app/views/partials/activity/book-adventure.html";
                        //var section = "";
                        //if ($stateParams.packageProductCategory.trim().toLowerCase() .indexOf=== "tour") {
                        //    section = "hotel";
                        //    return "/scripts/app/views/partials/" + section + "/book-package.html";
                        //}
                        return "";
                    }
                })
                .state("select-ticket.packages", {
                    url: "/package-summaries",
                    templateUrl: "/scripts/app/views/partials/packages/package-summaries.html",
                    redirectTo: 'select-ticket.book-adventure'
                })
                .state("package-details-nodate", {
                    url: "/package-details/{packageCode}",
                    controller: ["$scope", "$state", "$stateParams", function ($scope, $state, $stateParams) {
                        $state.go("package-details", { date: "today", packageCode: $stateParams.packageCode }, { notify: true });
                    }]
                    //
                })
                .state("package-details", {
                    url: "/package-details/:date/:packageCode/{adults:[0-9]+}/{children:[0-9]+}/{infants:[0-9]+}",
                    params: {
                        adults: { squash: true, value: null },
                        children: { squash: true, value: null },
                        infants: { squash: true, value: null }
                    },
                    templateUrl: "/scripts/app/views/partials/packages/package-details.html"                    
                })
                //.state("package-details-withdate", { 
                //    url: "/package-details/{date:[0-9]{4}-[0-9]{2}-[0-9]{2}}/:packageCode", // (^\d{4}-\d{2}-\d{2}$)
                //    templateUrl: "/scripts/app/views/partials/packages/package-details.html"
                //})
                .state("checkout", {
                    url: "/checkout",
                    templateUrl: "/scripts/app/views/partials/activity/checkout.html"
                })
                .state("package-details.select", {
                    url: "/{packageProductCode:(?!final)}/:packageProductCategory",
                    templateUrl: function ($stateParams) {
                        var section = "";
                        if ($stateParams.packageProductCategory.trim().toLowerCase() === "hotel") {
                            section = "hotel";
                            return "/scripts/app/views/partials/" + section + "/book-package.html";
                        } else {
                            section = "packages";
                            return "/scripts/app/views/partials/" + section + "/book-package-component.html";
                        }
                        return "";
                    },
                    controller: function ($scope, $stateParams, $state) {
                        //$scope.requestArguments = {
                        //    date: $stateParams.date,
                        //    packageCode: $stateParams.packageCode,
                        //    packageProductCode: $stateParams.packageProductCode,
                        //    packageProductCategory: $stateParams.packageProductCategory
                        //};
                    }
                })
                .state("package-details.final", {
                    url: "/final",
                    templateUrl: "/scripts/app/views/partials/packages/package-final.html"
                })

                .state("print-order", {
                    url: "/print-order",
                    templateUrl: "/scripts/app/views/partials/activity/print-order.html"
                });
        }
    ]);
})(jQuery);;
(function($) {
    "use strict";

    angular.module("app").
        config([
            "$authProvider", function($authProvider) {
                var settings = jQuery.parseJSON($("#externalAuthProviderSettings").val());

                $.each(settings, function(key, value) {
                    if (value.Name.toLowerCase().indexOf("facebook") >= 0) {
                        // Optional: For client-side use (Implicit Grant), set responseType to 'token'
                        $authProvider.facebook({
                            clientId: value.ClientId,
                            authorizationEndpoint: value.AuthUrl,
                            url: "",
                            scope: ["email", "public_profile"],
                            responseType: "token"
                        });
                    } else if (value.Name.toLowerCase().indexOf("google") >= 0) {
                        $authProvider.google({
                            clientId: value.ClientId,
                            authorizationEndpoint: value.AuthUrl
                        });
                    } else if (value.Name.toLowerCase().indexOf("twitter") >= 0) {
                        // No additional setup required for Twitter
                    }
                });

            }
        ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").config(["$stateProvider", "$urlRouterProvider", function ($stateProvider, $urlRouterProvider) {
        //
        // For any unmatched url, redirect to /state1
        //$urlRouterProvider.otherwise("/state1");
        //
        // Now set up the states
        $stateProvider
            .state("select-booking-type", {
                url: "/select-booking-type",
                templateUrl: "/scripts/app/views/partials/hotel/select-booking-type.html",
                redirectTo: 'select-booking-type.book-stay'
            }).state("select-booking-type.book-stay", {
                url: "/book-stay",
                templateUrl: "/scripts/app/views/partials/hotel/book-stay.html"
            }).state("select-booking-type.book-stay.rate", {
                url: "/:rateCode",
                templateUrl: "/scripts/app/views/partials/hotel/book-stay.html"
            }).state("select-booking-type.packages", {
                url: "/package-summaries",
                templateUrl: "/scripts/app/views/partials/packages/package-summaries.html",
                redirectTo: 'select-booking-type.book-stay'
            });

    }]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").config(["$stateProvider", "$urlRouterProvider", function ($stateProvider, $urlRouterProvider) {
        //
        // For any unmatched url, redirect to /state1
        //$urlRouterProvider.otherwise("/state1");
        //
        // Now set up the states
        $stateProvider
            .state("select-transport-ticket", {
                url: "/select-transportation-ticket",
                templateUrl: "/scripts/app/views/partials/transportation/select-ticket.html",
                redirectTo: 'select-transport-ticket.book-adventure'
            })
            .state("select-transport-ticket.book-adventure", {
                url: "/book-transportation-adventure?ticketType&departure&return&leavingFrom&goingTo&adults&children",
                templateUrl: "/scripts/app/views/partials/transportation/book-adventure.html"
            }).state("select-transport-ticket.packages", {
                url: "/package-summaries",
                templateUrl: "/scripts/app/views/partials/packages/package-summaries.html",
                redirectTo: 'select-transport-ticket.book-adventure'
            });

    }]);
})(jQuery);;
(function () {
    "use strict";

    angular.module('app')
        .factory("productsFactory", [
            "$http", "jwtService", function ($http, jwtService) {
                var productsFactory = {};
                var absoluteUrl = jQuery("body").data("weburl") ? jQuery("body").data("weburl") : "";
                var urlBase = absoluteUrl + '/api/product';

                productsFactory.getHotelCheckInCalendar = function (token, startDate, productCode, rateCode, numberOfAdults, numberOfChildren, numberOfDays) {
                   
                    return $http({
                        method: 'GET',
                        url: urlBase + "/hotelcheckincalendar/" + startDate + "/" + productCode + "/" + rateCode + "/" + numberOfAdults + "/" + numberOfChildren + (numberOfDays ? ("/" + numberOfDays) : ""),
                        headers: { "Authorization": token }
                    });;
                };
                productsFactory.getHotelCheckOutCalendar = function (token, startDate, productCode, rateCode, numberOfAdults, numberOfChildren, numberOfDays) {
                  
                    return $http({
                        method: 'GET',
                        url: urlBase + "/hotelcheckoutcalendar/" + startDate + "/" + productCode + "/" + rateCode + "/" + numberOfAdults + "/" + numberOfChildren, //+ (numberOfDays ? ("/" + numberOfDays) : ""),
                        headers: { "Authorization": token }
                    });;
                };

                productsFactory.getPrices = function (token, productCode, productCategory, productType, unitCode, travelDate) {
                    return $http({
                        method: 'GET',
                        url: urlBase + "/prices/" + productCode + "/" + productCategory + "/" + productType + "/" + unitCode + "/" + travelDate,
                        headers: { "Authorization": token }
                    });;
                };

                productsFactory.getDynamicPrices = function (token, productCode, month, year) {
                    return $http({
                        method: 'GET',
                        url: urlBase + "/dynamicprices/" + productCode + "/" + month + "/" + year,
                        headers: { "Authorization": token }
                    });;
                };

                productsFactory.getDynamicProductCategoryPrices = function (token, productCode, month, year) {
                    return $http({
                        method: 'GET',
                        url: urlBase + "/DynamicProductCategoryPrices/" + productCode + "/" + month + "/" + year,
                        headers: { "Authorization": token }
                    });;
                };

                productsFactory.getDynamicPackagePrices = function (token, packageCode, month, year) {
                    return $http({
                        method: 'GET',
                        url: urlBase + "/dynamicpackageprices/" + packageCode + "/" + month + "/" + year,
                        headers: { "Authorization": token }
                    });;
                };


                productsFactory.getUpgradePrices = function (request) {
                    return $http({
                        method: 'GET',
                        url: urlBase + "/upgradePrices/" + request.productCode + "/" + request.unitCode + "/" + request.currentComponentPrice
                            + "/" + request.numberOfAdults + "/" + request.numberOfChildren + "/" + request.numberOfSeniors + "/" + request.numberOfStudents
                            + "/" + request.year + "/" + request.month,
                        headers: { "Authorization": request.token }
                    });;
                };

                productsFactory.getHotelProduct = function (token, productCode, travelDate, nights, adults, children) {
                    var addQ = "";
                    if (adults) {
                        addQ += "/" + adults;
                        if (params.children) {
                            addQ += "/" + children;
                        }
                    }
                    return $http({
                        method: "GET",
                        url: urlBase + "/hotelproduct/" + productCode + "/" + travelDate + "/" + nights + addQ,
                        headers: { "Authorization": token }
                    });
                };

                productsFactory.getProduct = function (token, productCode, productCategory, travelDate, loadPrices) {
                    return $http({
                        method: 'GET',
                        url: urlBase + "/product/" + productCode + "/" + productCategory + "/" + travelDate + (loadPrices ? "/true" : ""),
                        headers: { "Authorization": token }
                    });
                };
                productsFactory.getProductWithCallback = function (params, callback) {
                    return productsFactory.getProduct(params.token, params.productCode, params.productCategory, params.travelDate, params.loadPrices).then(
                        function (result) {
                            callback({ success: true, data: result.data.products, error: undefined });
                        },
                        function (response) {
                            callback({ success: false, data: undefined, error: response.data });
                            console.log(response);
                        }
                    );
                };

                productsFactory.GetProductWithPackages = function (token, productCode, productCategory, travelDate) {
                    return $http({
                        method: 'GET',
                        url: urlBase + "/productwithpackages/" + productCode + "/" + productCategory + "/" + travelDate,
                        headers: { "Authorization": token }
                    });
                };

                productsFactory.getProductWithHiddenUnits = function (token, productCode, productCategory, travelDate) {
                    return $http({
                        method: 'GET',
                        url: urlBase + "/productwithhiddenunits/" + productCode + "/" + productCategory + "/" + travelDate,
                        headers: { "Authorization": token }
                    });
                };

                productsFactory.getProductWithHiddenUnitsWithCallback = function (params, callback) {
                    return productsFactory.getProductWithHiddenUnits(params.token, params.productCode, params.productCategory, params.travelDate).then(
                        function (result) {
                            callback({ success: true, data: result.data.products, error: undefined });
                        },
                        function (response) {
                            callback({ success: false, data: undefined, error: response.data });
                            console.log(response);
                        }
                    );
                };

                productsFactory.getRelatedServicesMulti = function (params, callback) {
                    return $http({
                        method: "POST",
                        url: urlBase + "/relatedservicesmulti",
                        headers: {
                            "Authorization": params.token,
                            "Content-Type": "application/json"
                        },
                        data: params.data
                    }).then(
                        function (result) {
                            callback({ success: true, data: result.data.relatedProducts, error: undefined });
                        },
                        function (response) {
                            callback({ success: false, data: response.data ? response.data.relatedProducts : undefined, error: response.data });
                            console.log(response);
                        }
                    );
                };

                productsFactory.getEnhanceYourExperience = function (params, callback) {
                    return $http({
                        method: "POST",
                        url: urlBase + "/enhanceyourexperience",
                        headers: {
                            "Authorization": params.token,
                            "Content-Type": "application/json"
                        },
                        data: params.data
                    }).then(
                        function (result) {
                            callback({ success: true, data: result.data.relatedProducts, error: undefined });
                        },
                        function (response) {
                            callback({ success: false, data: response.data ? response.data.relatedProducts : undefined, error: response.data });
                            console.log(response);
                        }
                    );
                };

                productsFactory.getTimeBetweenAttractions = function (params, callback) {
                    $http({
                        method: "GET",
                        url: urlBase + "/timeBetweenAttractions",
                        headers: {
                            "Authorization": params.token,
                            "Content-Type": "application/json"
                        }
                    }).then(
                        function (result) {
                            callback({ success: true, data: result.data.timesBetweenAttractions, error: undefined });
                        },
                        function (response) {
                            callback({ success: false, data: response.data ? response.data.timesBetweenAttractions : undefined, error: response.data });
                            console.log(response);
                        }
                    );
                };

                productsFactory.fillProductUnitsRelatedServicesMulti = function (requestParams, callback) {
                    if (!requestParams || !requestParams.product || !(requestParams.product.units || "").length) {
                        if (callback)
                            callback();
                        return;
                    }
                    var travelDate = moment(requestParams.product.startDate).format("YYYY-MM-DD");
                    var productQueries = _.map(requestParams.product.units,
                        function (unit) {
                            var obj = {
                                ProductCode: requestParams.product.code,
                                UnitCode: unit.unitCode,
                                TravelDate: travelDate
                            };

                            return obj;
                        });
                    var dataToPost = { ProductQueries: productQueries };
                    var requestParamsMulti = {
                        token: requestParams.token,
                        data: dataToPost
                    };

                    productsFactory.getRelatedServicesMulti(requestParamsMulti, function (relatedProducts) {

                        if (relatedProducts && relatedProducts.data && relatedProducts.data.length) {
                            var index = 0;
                            $.each(relatedProducts.data, function (key, value) {
                                var unit = requestParams.product.units[index];
                                if (unit) {
                                    unit.relatedProducts = value;
                                    if (unit.relatedProducts && (unit.relatedProducts.attractionTimes || '').length) {
                                        unit.upTimeProduct = _.find(unit.relatedProducts.attractionTimes, function (at) { return at.isPrimary; });
                                        unit.downTimeProduct = _.find(unit.relatedProducts.attractionTimes, function (at) { return !at.isPrimary; });

                                        if (unit.upTimeProduct) {
                                            var isCurrDate = moment(unit.upTimeProduct.startDate).isSame(jwtService.getServerMomentDate());

                                            // If the second time is sold out or unavailable, the corresponding first time should not be selectable in the initial dropdown
                                            var filterConstaintUpTimeByDownTime = function (primaryTimeUnit) {
                                                if (requestParams.totalGuests && (unit.durationType || "").toUpperCase() == 'DAY' && unit.downTimeProduct && !unit.downTimeProduct.canModifyTime && unit.downTimeProduct.recommendedIntervalInMinutes) {

                                                    var startMin = moment(primaryTimeUnit.startTime);
                                                    var startRecomm = moment(primaryTimeUnit.startTime);

                                                    var interval = unit.downTimeProduct.minimumIntervalInMinutes
                                                        ? parseInt(unit.downTimeProduct.minimumIntervalInMinutes) : 0;

                                                    startMin.add(interval, "m");

                                                    var downTimeProductFilteredUnits = _.filter(unit.downTimeProduct.units, function (un) {
                                                        return startMin <= moment(un.startTime);
                                                    });

                                                    if (!(downTimeProductFilteredUnits || "").length) {
                                                        return false;
                                                    }

                                                    interval = parseInt(unit.downTimeProduct.recommendedIntervalInMinutes);
                                                    startRecomm.add(interval, "m");

                                                    var downTimeUnit = _.find(downTimeProductFilteredUnits, function (un) {
                                                        return startRecomm <= moment(un.startTime) && un.availability >= requestParams.totalGuests;
                                                    });

                                                    if (!downTimeUnit) {
                                                        return false;
                                                    }
                                                }

                                                return true;
                                            };

                                            if (isCurrDate && unit.upTimeProduct.bookingRestrictionTime > 0) {
                                                var tc = jwtService.getServerMomentDate(true);

                                                tc.add(parseInt(unit.upTimeProduct.bookingRestrictionTime), "m");
                                                var timeLimit = moment(tc.format("hh:mm A"), "hh:mm A");

                                                unit.upTimeProduct.filteredUnits = _.filter(unit.upTimeProduct.units, function (un) {
                                                    var timeStr = moment(un.startTime).format("hh:mm A");
                                                    var unitTimeVal = moment(timeStr, "hh:mm A");
                                                    var startTimeConstraint = unitTimeVal > timeLimit;

                                                    if (!startTimeConstraint) return false;

                                                    // If the second time is sold out or unavailable, the corresponding first time should not be selectable in the initial dropdown
                                                    return filterConstaintUpTimeByDownTime(un);
                                                });

                                                if (unit.upTimeProduct.filteredUnits.length == 0)
                                                    unit.upTimeProduct.filteredUnits = [{ isDisabled: true, unitCode: "" }];

                                            } else {
                                                unit.upTimeProduct.filteredUnits = _.filter(unit.upTimeProduct.units, function (un) {
                                                    // If the second time is sold out or unavailable, the corresponding first time should not be selectable in the initial dropdown
                                                    return filterConstaintUpTimeByDownTime(un);
                                                });
                                            }
                                        }


                                    }
                                }
                                index++;
                            });
                        }
                        if (callback)
                            callback();
                    });
                };

                productsFactory.fillPackageRelatedServicesMulti = function (requestParams, callback) {
                    if (!requestParams || !requestParams.pkg || !(requestParams.pkg.components || "").length) {
                        if (callback)
                            callback();
                        return;
                    }

                    var productQueries = _.map(requestParams.pkg.components,
                        function (component) {
                            var compDate = component.selectedDate && moment(component.selectedDate) || moment(component.product.startDate);
                            var compDateStr = compDate.isValid() ? compDate.format("YYYY-MM-DD") : "";

                            var obj = {
                                ProductCode: component.product.code,
                                TravelDate: compDateStr ? compDateStr : requestParams.travelDate
                            };
                            var selectedUnit = component.product.selectedUnit || (component.product.units && component.product.units[0]);
                            if (selectedUnit) {
                                obj.UnitCode = selectedUnit.unitCode;
                            }
                            return obj;
                        });
                    var dataToPost = { ProductQueries: productQueries };
                    var requestParamsMulti = {
                        token: requestParams.token,
                        data: dataToPost
                    };

                    productsFactory.getRelatedServicesMulti(requestParamsMulti, function (relatedProducts) {

                        if (relatedProducts && relatedProducts.data && relatedProducts.data.length) {
                            $.each(relatedProducts.data, function (key, value) {
                                var comp = _.find(requestParams.pkg.components, function (c) { return c.product.code.toLowerCase() === value.relatedProductCode.toLowerCase(); });
                                comp.relatedProducts = value;
                                if (comp.relatedProducts && (comp.relatedProducts.attractionTimes || '').length) {
                                    var oldUptimeProduct = comp.upTimeProduct;
                                    var oldDowntimeProduct = comp.downTimeProduct;

                                    comp.upTimeProduct = _.find(comp.relatedProducts.attractionTimes, function (at) { return at.isPrimary; });
                                    if (comp.upTimeProduct) {
                                        var isCurrDate = moment(comp.upTimeProduct.startDate).isSame(jwtService.getServerMomentDate());

                                        if (isCurrDate && comp.upTimeProduct.bookingRestrictionTime > 0) {
                                            var tc = jwtService.getServerMomentDate(true);

                                            tc.add(parseInt(comp.upTimeProduct.bookingRestrictionTime), "m");
                                            var timeLimit = moment(tc.format("hh:mm A"), "hh:mm A");

                                            comp.upTimeProduct.filteredUnits = _.filter(comp.upTimeProduct.units, function (un) {
                                                var timeStr = moment(un.startTime).format("hh:mm A");
                                                var unitTimeVal = moment(timeStr, "hh:mm A");
                                                return unitTimeVal > timeLimit;
                                            });

                                            //if (comp.upTimeProduct.filteredUnits.length == 0)
                                            //    comp.upTimeProduct.filteredUnits = [{ isDisabled: true, unitCode: "" }];

                                        } else {
                                            comp.upTimeProduct.filteredUnits = comp.upTimeProduct.units;
                                        }

                                        //remove the “I’ll choose later” option for tour times
                                        var mainPackage = requestParams && requestParams.pkg;
                                        //!comp.upTimeProduct.isRequiredRelatedProduct && (mainPackage && mainPackage.type != "ATTRACTION") &&
                                        if ((comp.upTimeProduct.filteredUnits || "").length && (mainPackage && mainPackage.type != "ATTRACTION")) {
                                            comp.upTimeProduct.filteredUnits = [{ isDisabled: true, unitCode: "" }].concat(comp.upTimeProduct.filteredUnits);
                                        }

                                        if (oldUptimeProduct && oldUptimeProduct.selectedUnit) {
                                            comp.upTimeProduct.selectedUnit = comp.upTimeProduct.units
                                                && comp.upTimeProduct.units.find(function (item) { return item.unitCode == oldUptimeProduct.selectedUnit.unitCode; });
                                        }

                                        comp.upTimeProduct.selectedUnit = comp.upTimeProduct.selectedUnit || comp.upTimeProduct.filteredUnits && comp.upTimeProduct.filteredUnits[0];
                                    }
                                    comp.downTimeProduct = _.find(comp.relatedProducts.attractionTimes, function (at) { return !at.isPrimary; });
                                    if (comp.downTimeProduct && oldDowntimeProduct && oldDowntimeProduct.selectedUnit) {
                                        comp.downTimeProduct.selectedUnit = comp.downTimeProduct.units
                                            && comp.downTimeProduct.units.find(function (item) { return item.unitCode == oldDowntimeProduct.selectedUnit.unitCode; });
                                    }
                                }
                            });
                        }
                        if (callback)
                            callback();
                    });
                };

                return productsFactory;
            }
        ]);
}());
(function () {
    "use strict";

    angular.module("app")
        .factory("taskFactory", [
            function () {
                var taskFactory = {
                    task: {}
                };

                taskFactory.addTask = function (name, data) {
                    taskFactory.task = { name:name, data:data };
                };

                return taskFactory;
            }
        ]);
}());
(function () {
    "use strict";

    angular.module("app")
        .factory("utilsFactory", [
            function () {
                var utilsFactory = {};
                utilsFactory.getAnonymUserLabel = function (user, primaryLabelName, secondaryLabelName) {
                    if (!user || !user.labels) return undefined;
                    if (user.labels[primaryLabelName] && typeof user.labels[primaryLabelName] == "object") {
                        return secondaryLabelName ? user.labels[primaryLabelName][secondaryLabelName] : user.labels[primaryLabelName];
                    }
                    return user.labels[primaryLabelName];
                };
                utilsFactory.labelsConfig = undefined;
                utilsFactory.fillJsonConfig = function () {

                    if (this.labelsConfig || !jQuery("#labelsConfig").length) return;
                    try {
                        var configTemp = jQuery.parseJSON(jQuery("#labelsConfig").html());
                        this.labelsConfig = Object.create(null);
                        _.each(configTemp, function (val) {
                            this.labelsConfig[val.key || val.Key] = val.value || val.Value;
                        }, this);
                    }
                    catch (e) {
                        console.log(e);
                    }
                };

                utilsFactory.getQueryStringParameterByName = 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, ' '));
                }

                utilsFactory.addPersistentQueryStringsParams = function (url) {
                    if (!url) return url;
                    var persistentParams = utilsFactory.getPersistentQueryStringsParams();
                    if (!persistentParams) return url;

                    let base = window.location.origin; // Use current origin for relative URLs
                    let urlObj = new URL(url, url.startsWith('http') ? undefined : base); // Handle both absolute & relative

                    Object.keys(persistentParams).forEach(key => {
                        urlObj.searchParams.set(key, persistentParams[key]); // Add or update query param
                    });

                    return url.startsWith('http') ? urlObj.toString() : urlObj.pathname + urlObj.search + urlObj.hash;

                }

                utilsFactory.getPersistentQueryStringsParams = function () {
                    var qparams = (jQuery("body").data("persistquerystringparams") || "").split("|");
                    if (!qparams.length) return null;

                    var paramObj = Object.create(null);

                    qparams.forEach(function (qItem) {
                        var qItemValue = utilsFactory.getQueryStringParameterByName(qItem);
                        if (!qItemValue) return;
                        paramObj[qItem] = qItemValue;
                    });
                    if (!Object.keys(paramObj).length) {
                        return null;
                    }
                    return paramObj;
                }

                utilsFactory.getLabel = function (key, returnEmpty) {
                    this.fillJsonConfig();
                    var fallbackValue = typeof returnEmpty != "string" ? (returnEmpty ? "" : key) :
                        returnEmpty;
                    if (fallbackValue != key) fallbackValue = this.labelsConfig[fallbackValue];

                    if (!this.labelsConfig) return fallbackValue;

                    return this.labelsConfig[key] || fallbackValue;
                };

                utilsFactory.getProductLabel = function (val, productCode) {
                    if (!productCode || !val) return undefined;

                    var modal = _.find(val, function (m) {
                        return m.codes && m.codes.indexOf(productCode) > -1;
                    });
                    //if (!modal) return defaultModal;
                    return modal;
                };
                utilsFactory.getProductLabelByRegion = function (val, regionCode) {
                    if (!regionCode || !val) return undefined;

                    var modal = _.find(val, function (m) {
                        return m.regions && m.regions.indexOf(regionCode) > -1;
                    });
                    //if (!modal) return defaultModal;
                    return modal;
                };

                utilsFactory.getModalLabelsObs = function (key, productCode) {
                    if (!productCode || !this.labelsConfig) return undefined;
                    productCode = productCode.toUpperCase();
                    var val = this.labelsConfig[key];
                    if (!val || !val.length) return undefined;
                    var modal = _.find(val, function (m) {
                        return m.codes && m.codes.indexOf(productCode) > -1;
                    });
                    //if (!modal) return defaultModal;
                    return modal;
                }

                return utilsFactory;
            }
        ]);
}());
(function ($) {
    "use strict";

    angular.module("app").service("activitiesService", ["localStorageService", "$http", function (localStorageService, $http) {
        this.removeAllStoredData = function () {
            if (localStorageService.isSupported) {
                localStorageService.remove("activitiesFilters");
                localStorageService.remove("prevActivity");
                localStorageService.remove("activityWizardModel");
            }
        };

        this.getLocations = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/usercode/locations/city",
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data.activityLocations, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.getActivitiesFilters = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/usercode/searchfilters/Activities",
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };
        this.getActivitiesByType = function (params, callback) {

            $http({
                method: "GET",
                url: params.urlPrefix + "/api/product/GetActivitiesByType/" + params.type + "/" + params.date + (params.productCodeOverride ? ("/" + params.productCodeOverride) : ""),
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };
        this.getToursByType = function (params, callback) {
            var aditionalParam = params.fromLocationCode + "/" + params.fromLocationName + "/" + params.toLocationCode + "/" + params.toLocationName + "/" + params.pickupCode + "/" + (params.dropoffCode ? params.dropoffCode : "");

            $http({
                method: "GET",
                url: params.urlPrefix + "/api/product/ToursByType/" + params.type + "/" + params.date + "/" + aditionalParam,
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };
        this.getToursByTypeWithPackages = function (params, callback) {
            var aditionalParam = "";
            if (params.fromLocationCode) {
                aditionalParam = params.fromLocationCode + "/" + params.fromLocationName + "/" + params.toLocationCode + "/" + params.toLocationName + "/";

                if (params.pickupCode) {
                    aditionalParam += params.pickupCode + "/" + (params.dropoffCode ? params.dropoffCode : "")
                }
            }
            var queryParams = "";
            if (params.loadPickupsAndDropoffs) {
                queryParams = "?loadpickupsanddropoffs=true";
            }

            $http({
                method: "GET",
                url: params.urlPrefix + "/api/product/toursbytypewithpackages/" + params.type + "/" + params.date + "/" + aditionalParam + queryParams,
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.getActivitiesByDate = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/product/productsbycategory/" + (params.id || "Activities") + "/" + params.date,
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.getProductByCodeCategoryAndTravelDate = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/product/product/" + params.productCode + "/" + params.productCategory + "/" + params.travelDate,
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.getProductWithPackagesByCodeCategoryAndTravelDate = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/product/productwithpackages/" + params.productCode + "/" + params.productCategory + "/" + params.travelDate,
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.getProductDescriptionByCode = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/product/productdescription/" + params.productCode,
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.getTicketTypes = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/product/tickettypes/" + params.productCode + "/" + params.productCategory + "/" + params.travelDate,
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data.types, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response });
                    console.log(response);
                }
            );
        };

        this.removeActivitiesFilters = function () {
            if (localStorageService.isSupported) {
                localStorageService.remove("activitiesFilters");
            }
        };

        this.persistActivitiesFilters = function (id, filters, callback) {
            if (localStorageService.isSupported) {
                var expireDate = new Date();
                filters.expire = expireDate;
                filters.id = id;
                localStorageService.set("activitiesFilters", filters);
                if (callback) {
                    callback({ success: true, data: filters, error: undefined });
                }
            } else {
                if (callback) {
                    callback({ success: false, data: undefined, error: "Local Storage is not supported!" });
                }
            }
        };

        this.getPersistedActivitiesFilters = function (id, callback) {
            if (localStorageService.isSupported) {
                var filters = localStorageService.get("activitiesFilters");

                if (filters && filters.expire) {
                    var date = new Date(filters.expire);
                    var today = new Date();
                    if (filters.id != id || date.getDate() !== today.getDate() || date.getMonth() !== today.getMonth() || date.getFullYear() !== today.getFullYear()) {
                        localStorageService.remove("activitiesFilters");
                        filters = null;
                    }
                } else {
                    localStorageService.remove("activitiesFilters");
                    filters = null;
                }
                callback({ success: true, data: filters, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: "Local Storage is not supported!" });
            }
        };

        this.setIsFromFilters = function (val, callback) {
            if (localStorageService.isSupported) {
                localStorageService.set("isFromFilters", val);
                callback({ success: true, error: undefined });
            } else {
                callback({ success: false, error: undefined });
            }
        };
        this.getIsFromFilters = function () {
            if (localStorageService.isSupported) {
                var val = localStorageService.get("isFromFilters");
                return val;
            } else {
                return undefined;
            }
        };

        this.setIsFromActivityDetails = function (val, callback) {
            if (localStorageService.isSupported) {
                localStorageService.set("isFromActivityDetails", val);
                callback({ success: true, error: undefined });
            } else {
                callback({ success: false, error: undefined });
            }
        };
        this.getIsFromActivityDetails = function () {
            if (localStorageService.isSupported) {
                var val = localStorageService.get("isFromActivityDetails");
                return val;
            } else {
                return undefined;
            }
        };

        this.getSelectedActivity = function (callback) {
            if (localStorageService.isSupported) {
                var activity = localStorageService.get("prevActivity");

                if (activity && activity.expire) {
                    var date = new Date(activity.expire);
                    var today = new Date();
                    if (date.getDate() !== today.getDate() || date.getMonth() !== today.getMonth() || date.getFullYear() !== today.getFullYear()) {
                        localStorageService.remove("prevActivity");
                        activity = null;
                    }
                } else {
                    localStorageService.remove("prevActivity");
                    activity = null;
                }
                callback({ success: true, data: activity, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: undefined });
            }
        };

        this.setSelectedActivity = function (activity, callback) {
            if (localStorageService.isSupported) {
                var expireDate = new Date();
                activity.expire = expireDate;
                localStorageService.set("prevActivity", activity);
                callback({ success: true, data: activity, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: undefined });
            }
        };

        this.getActivityWizardModel = function (callback) {
            if (localStorageService.isSupported) {
                var wizardModel = localStorageService.get("activityWizardModel");
                if (wizardModel && wizardModel.expire) {
                    var date = new Date(wizardModel.expire);
                    var today = new Date();
                    if (date.getDate() !== today.getDate() || date.getMonth() !== today.getMonth() || date.getFullYear() !== today.getFullYear()) {
                        localStorageService.remove("activityWizardModel");
                        wizardModel = null;
                    }
                } else {
                    localStorageService.remove("activityWizardModel");
                    wizardModel = null;
                }
                callback({ success: true, data: wizardModel, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: undefined });
            }
        };

        this.removeActivityWizardModel = function (callback) {
            if (localStorageService.isSupported) {
                localStorageService.remove("activityWizardModel");
                // localStorageService.remove("prevActivity");
            }
            if (callback)
                callback();
        };

        this.setActivityWizardModel = function (wizardModel, callback) {
            if (localStorageService.isSupported) {
                var expireDate = new Date();
                wizardModel.expire = expireDate;
                localStorageService.set("activityWizardModel", wizardModel);
                callback({ success: true, data: wizardModel, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: undefined });
            }
        };
    }]);

})(jQuery);
(function ($) {
    "use strict";

    angular.module("app").service("borgunPaymentService", [
        "localStorageService", "$http", "$rootScope", function (localStorageService, $http, $rootScope) {
            var paymentService = this;

            this.getFilteredCards = function (sourceCards) {
                return sourceCards;
                var filteredCards = [];
                if (sourceCards && sourceCards.length > 0) {
                    var groupedCards = _.groupBy(sourceCards, function (card) { return card.cardnumber; });

                    var distict = _.uniq(sourceCards, function (card) { return card.cardnumber; });

                    for (var i = 0; i < distict.length; i++) {
                        var sortedCards = _.sortBy(groupedCards[distict[i].cardnumber], function (ct) { return ct.version });
                        sortedCards[0].cardNumber = sortedCards[0].cardnumber;
                        filteredCards.push(sortedCards[0]);
                    }

                    /*for (var i = 0; i < sourceCards.length; i++) {
                        /*if (sourceCards[i].version === "0") {#1#
                            sourceCards[i].cardNumber = sourceCards[i].cardnumber;
                            filteredCards.push(sourceCards[i]);
                        /*}#1#
                    }*/
                }

                return filteredCards;
            }

            this.getCreditCards = function (params, callback) {
                $http({
                    method: "GET",
                    url: params.urlPrefix + "/api/paymentborgun/creditcards",
                    headers: { "Authorization": params.token }
                }).then(
                    function (result) {
                        var filteredCards = paymentService.getFilteredCards(result.data.tokenizedcreditcards);

                        callback({ success: true, data: filteredCards, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response.data });
                        console.log(response);
                    }
                );
            };

            this.postCreditCard = function (params, callback) {
                // return temporary stub of data

                /*var card = {
                    tokenizedCreditCards: [],
                    echo: null,
                    errors: [],
                    displayErrors: ""
                };

                var tokinizedCard = {
                    address: "1 Main street",
                    businesspartnerid: 1001,
                    businesspartnernumber: "number_1001",
                    cardid: "11111111",
                    cardNumber: "XXXXXXXXXXXX1111",
                    city: "Vancouver",
                    country: "CA",
                    createddate: "09/16",
                    expirydate: "09/18",
                    nameoncard: "Victor Lungu",
                    firstName: "Victor",
                    lastName: "Lungu",
                    expirationMonth: "09",
                    expirationYear: "18",
                    pacificcardtype: "Visa",
                    postalcode: "VC-2020",
                    city: "BC",
                    version: "1.0"
                }

                card.tokenizedCreditCards.push(tokinizedCard);

                callback({ success: true, data: card.tokenizedCreditCards, error: undefined });

                return;*/

                var service = this;
                var p = params;
                $http({
                    method: "POST",
                    url: params.urlPrefix + "/api/paymentborgun/creditcard",
                    headers: { "Authorization": params.token },
                    data: {
                        "cardToken": params.cardToken,
                    }
                }).then(
                    function (res) {

                        var createdCardToken = res && res.data && (res.data.tokenizedcreditcards || "").length ?
                            res.data.tokenizedcreditcards[0].cardTokenValue
                            : undefined;
                        var getParams = { urlPrefix: p.urlPrefix, token: p.token }
                        service.getCreditCards(getParams, function (result) {
                            var filteredCards = paymentService.getFilteredCards(result.data);
                            _.each(filteredCards, function (c) { if (c.cardTokenValue === createdCardToken) c.cardCreated = true; });

                            callback({ success: true, data: filteredCards, error: undefined });
                        });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response.data });
                        console.log(response);
                    }
                );
            };

            this.deleteCardById = function (params, callback) {
                $http({
                    method: "DELETE",
                    url: params.urlPrefix + "/api/paymentborgun/creditcard/" + params.cardToken,
                    headers: { "Authorization": params.token }
                }).then(
                    function (result) {
                        callback({ success: true, data: result, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response.data });
                        console.log(response);
                    }
                );
            }

            this.borgun3DSCheck = function (params, callback) {
                var service = this;
                var p = params;
                $http({
                    method: "POST",
                    url: params.urlPrefix + "/api/paymentborgun/borgun3dscheck",
                    headers: { "Authorization": params.token },
                    data: {
                        "CardDetails": {
                            "PaymentType": params.isTokenMulti ? "TokenMulti" : "TokenSingle",
                            "Token": params.cardToken
                        },
                        PurchAmount: params.purchAmount,
                        Currency: params.currency,
                        Exponent: 0,
                        TermUrl: params.termUrl,
                        MD: "echo data",
                    }
                }).then(
                    function (res) {
                        callback({ success: true, data: res, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response });
                        console.log(response);
                    }
                );
            };
            // 

            this.borgunPaResValidationRequestFor3DSecure = function (params, callback) {
                var service = this;
                var p = params;
                $http({
                    method: "POST",
                    url: params.urlPrefix + "/api/paymentborgun/borgunparesvalidation",
                    headers: { "Authorization": params.token },
                    data: {
                        PaRes: params.PaRes,
                        CRes: params.CRes || "",
                        Exponent: 0,
                        MD: "echo data",
                    }
                }).then(
                    function (res) {
                        callback({ success: true, data: res, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response });
                        console.log(response);
                    }
                );
            };
        }
    ]);

})(jQuery);
(function ($) {
    "use strict";

    angular.module("app").service("cresecureService", ["localStorageService", "$http", "$httpParamSerializerJQLike", "$sce", function (localStorageService, $http, $httpParamSerializerJQLike, $sce) {

        this.generateCreSecureIframeUrl = function (cresecureParams) {
            if (!cresecureParams) {
                var d = new Date();
                cresecureParams = {
                    merchPass: $("body").attr("data-cresecure-merchPass"),
                    allowed_types: "Visa|MasterCard|American Express",
                    cre_tokenize: "store_only",
                    sessionId: "testSession123",
                    name: "John Stamos",
                    formType: 0,
                    required: "minimum",//"all", // all/minimum
                    collectAddress: null,//2,
                    address: "100 Gopher Street",
                    currency_code: "CAD",
                    city: "Banff",
                    state: "AB",
                    zip: "T3L2R9",
                    country: "CA",
                    timestamp: d.getMilliseconds()
                }
            }

            var crescurePrefixUrl = $("body").attr("data-cresecure-url");
            var crescureCallbackUrl = $("body").attr("data-cresecure-callback-url");
            var crescureCssUrl = $("body").attr("data-cresecure-css-url");

            if (!cresecureParams.callback_url) {
                cresecureParams.callback_url = crescureCallbackUrl;
            }

            if (!cresecureParams.css_url) {
                cresecureParams.css_url = crescureCssUrl;
            }

            var crescureUrl = crescurePrefixUrl + $httpParamSerializerJQLike(cresecureParams);

            return $sce.trustAsResourceUrl(crescureUrl);
        };

        this.getCountryCodeByName = function(countryName, countries) {
            var contryCode = null;

            for (var i = 0; i < countries.length; i++) {
                if (countries[i].name.toLowerCase() === countryName.toLowerCase()) {
                    contryCode = countries[i].code;
                    break;
                }
            }

            return contryCode ? contryCode : countryName;
        };

        this.getCountryByNameCode = function (countryCode, countries) {
            var contryName = null;

            try {
                for (var i = 0; i < countries.length; i++) {
                    if (countries[i].code.toLowerCase() === countryCode.toLowerCase()) {
                        contryName = countries[i].name;
                        break;
                    }
                }

                return contryName ? contryName : countryCode;
            } catch (e) {
            }
            
            return contryName;
        };

        this.getParamValue = function (name, url) {
            if (!url) {
                url = window.location.href;
            }
            var results = new RegExp("[\\?&]" + name + "=([^&#]*)").exec(url);
            if (!results) {
                return undefined;
            }
            return decodeURIComponent(results[1]) || undefined;
        }

        /*this.getSessionCards = function() {
            var cards = sessionStorage.getItem("sessionCards");

            if (!cards) {
                return [];
            } else {
                return JSON.parse(cards);
            }
        }*/

        /*this.setSessionCards = function (cardsArray) {
            sessionStorage.setItem("sessionCards", JSON.stringify(cardsArray));
        }*/

        this.getErrorMessages = function (codes) {
            var tempMessages = [];
            var codesArray = codes.split("|");
            if (codesArray && codesArray.length > 0) {
                var service = this;
                _.map(codesArray, function (code) {
                    if (code !== "") {
                        try {
                            var intCode = parseInt(code);
                            tempMessages.push(service.getErrorByCode(intCode));
                        }
                        catch(e) {}
                    }
                });
            }

            return tempMessages;
        }

        this.getErrorByCode = function(code) {
            switch (code) {
                case 100:
                    return "Merchant Identifier left blank or not valid. Indicates a corrupt or hacked payment form. The transaction was not processed.";
                case 110:
                    return "Session Identifier left blank. Indicates a corrupt or hacked payment form. The transaction was not processed.";
                case 200:
                    return "Name is missing.";
                case 500:
                    return "Address field required but left blank.";
                case 510:
                    return "City field required but left blank.";
                case 520:
                    return "State field required but left blank.";
                case 530:
                    return "ZIP/postal code field required but left blank.";
                case 531:
                    return "Invalid Postal Code.";
                case 550:
                    return "Country is missing.";
                case 300:
                    return "Amount not specified or invalid value entered.";
                case 310:
                    return "Credit card number left blank.";
                case 315:
                    return "Credit card number is invalid";
                case 320:
                    return "Credit card type is invalid";
                case 330:
                    return "Expiration month is invalid.";
                case 340:
                    return "Expiration year is invalid.";
                case 350:
                    return "CVV2 field submitted but does not match the card.";
                case 355:
                    return "CVC code is missing or invalid.";
                case 357:
                    return "Invalid CVV2 field submitted.";
                case 360:
                    return "Card declined by the processor. Please try again.";
                case 370:
                    return "Expiration date invalid.";
                case 400:
                    return "Tracer value does not match. The tracer value is a regularly updated number that indicates the origin of the payment information. If the tracer value changes it indicates a corrupt or hacked payment form, and the transaction will not be processed.";
               
                case 700:
                    return "Fraudulent Order.";
                default:
                    return "Unknown error. Error code: " + code;
            }
        }
    }]);

})(jQuery);
(function ($) {
    "use strict";

    angular.module("app").service("currenciesService", ["localStorageService", "$http", "$window", function (localStorageService, $http, $window) {
        this.selectedCurrencyCode = null;

        function shouldInitCurrencyConvertor(geographyCode) {
            return (geographyCode || "").toUpperCase().indexOf("SKL") >= 0 || ((geographyCode || "").toUpperCase().indexOf("FOI") >= 0);
        }

        this.getCurrencyRates = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/viadapi/currencyexchange/getrates/"
            }).then(
                function (result) {
                    callback({ success: true, data: result.data.rates, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.initCurrencyRates = function (geographyCode, callback) {
            if (!shouldInitCurrencyConvertor(geographyCode)) return;

            var url = ($("body").data("pursuitmainsiteurl") ? $("body").data("pursuitmainsiteurl") : null);
            if (!(url || "").length) { callback({ success: false, error: "Site url is null" }); return; }
            url = url.trim();
            // trim last /
            if (url[url.length - 1] == "/") {
                url = url.substring(0, url.length - 1);
            }

            this.getCurrencyRates({
                urlPrefix: url
            }, function (ratesResult) {
                if (ratesResult.success && ratesResult.data) {
                    $window.fx.rates = ratesResult.data;
                    callback({ success: !!ratesResult.data, error: null });
                } else {
                    callback({ success: false, error: ratesResult });
                }
            });
        };

        this.getPriceInSelectedCurrency = function (value, originalCurrencyCode, selectedCurrencyCode) {
            var selectedCurrencyCode = selectedCurrencyCode || this.selectedCurrencyCode;
            if (!value || !selectedCurrencyCode || !originalCurrencyCode || !$window.fx) return value;

            return $window.fx(value).from(originalCurrencyCode).to(selectedCurrencyCode);
        };

        this.getCurrenciesByGeographyCode = function (geographyCode) {
            if (!shouldInitCurrencyConvertor(geographyCode)) {
                return null;
            }

            return [
                { icon: "/Content/images/icons/currencies/is.svg", symbol: "kr", code: "ISK", displayCodeAsSymbol: true },
                { icon: "/Content/images/icons/currencies/us.svg", symbol: "$", code: "USD" },
                { icon: "/Content/images/icons/currencies/ca.svg", symbol: "$", code: "CAD" },
                { icon: "/Content/images/icons/currencies/eu.svg", symbol: "€", code: "EUR" },
                { icon: "/Content/images/icons/currencies/gb.svg", symbol: "£", code: "GBP" }
            ];
        };

        this.setSelectedCurrencyCode = function (currencyCode) {
            this.selectedCurrencyCode = currencyCode;
            if (localStorageService.isSupported) {
                localStorageService.set("selectedCurrencyCode", currencyCode);
            }
        };

        this.getSelectedCurrencyCode = function () {
            if (!!this.selectedCurrencyCode) return this.selectedCurrencyCode;

            if (localStorageService.isSupported) {
                this.selectedCurrencyCode = localStorageService.get("selectedCurrencyCode");
            }

            return this.selectedCurrencyCode;
        };

    }]);

})(jQuery);
(function ($) {
    "use strict";

    angular.module("app").service("customerService", [
        "localStorageService", "$http", "trackingService", function (localStorageService, $http, trackingService) {
            this.registerCustomer = function (requestParams, callback) {
                $http({
                    method: "POST",
                    url: requestParams.apiUrl,
                    headers: {
                        "Authorization": requestParams.token,
                        "Content-Type": "application/json"
                    },
                    data: requestParams.customerToPost
                })
                    .then(
                        function (result) {
                            if (result && result.data && result.data.token) {
                                requestParams.jwtService.setCustomerToken(result.data);
                            }

                            callback(result);
                        },
                        function (error) {

                            callback(error);
                        });
            };

            this.updateCustomer = function (requestParams, callback) {
                $http({
                    method: "POST",
                    url: requestParams.apiUrl,
                    headers: {
                        "Authorization": requestParams.token,
                        "Content-Type": "application/json"
                    },
                    data: requestParams.customerToPost
                })
                    .then(
                        function (result) {
                            callback(result);
                        },
                        function (error) {
                            callback(error);
                        });
            };

            this.customerBookingSummaries = function (requestParams, callback) {
                $http({
                    method: "GET",
                    url: requestParams.apiUrl,
                    headers: {
                        "Authorization": requestParams.token,
                        "Content-Type": "application/json"
                    }
                })
                    .then(
                        function (result) {
                            callback(result);
                        },
                        function (error) {
                            callback(error);
                        });
            };

            this.agentCommissions = function (requestParams, callback) {
                var apiUrl = $("body").data("weburl") ? $("body").data("weburl") : "";

                $http({
                    method: "GET",
                    url: apiUrl + "/api/booking/commissions/" + requestParams.travelStart + "/" + requestParams.travelEnd,
                    headers: {
                        "Authorization": requestParams.token,
                        "Content-Type": "application/json"
                    }
                })
                    .then(
                        function (result) {
                            callback({ success: true, data: result ? result.data : result, error: undefined });
                        },
                        function (error) {
                            callback({ success: false, data: undefined, error: error ? error.data : undefined });
                        });
            };

            this.persistAgencyContacts = function (contacts, callback) {
                if (localStorageService.isSupported) {
                    localStorageService.set("agencyContacts", contacts);
                    callback({ success: true, data: contacts, error: undefined });
                } else {
                    callback({ success: false, data: undefined, error: "Local Storage is not supported!" });
                }
            };

            this.getPersistedAgencyContacts = function (callback) {
                if (localStorageService.isSupported) {
                    var contacts = localStorageService.get("agencyContacts");

                    callback({ success: true, data: contacts, error: undefined });
                } else {
                    callback({ success: false, data: undefined, error: "Local Storage is not supported!" });
                }
            };

            this.getAgencyContactsAsync = function (requestParams, callback) {
                var apiUrl = $("body").data("weburl") ? $("body").data("weburl") : "";

                $http({
                    method: "GET",
                    url: apiUrl + "/api/customer/agencycontacts/",
                    headers: {
                        "Authorization": requestParams.token,
                        "Content-Type": "application/json"
                    }
                })
                    .then(
                        function (result) {
                            callback({ success: true, data: result ? result.data : result, error: undefined });
                        },
                        function (error) {
                            callback({ success: false, data: undefined, error: error ? error.data : undefined });
                        });
            };

            this.addAgencyContact = function (params, callback) {
                var apiUrl = $("body").data("weburl") ? $("body").data("weburl") : "";

                $http({
                    method: "POST",
                    url: apiUrl + "/api/customer/createagencycontact/",
                    headers: { 'Content-Type': "application/json", "Authorization": params.token },
                    data: params.dataToPost
                }).then(
                    function (result) {
                        callback({ success: true, data: result.data, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response.data });
                        console.log(response);
                    }
                );
            };

            this.deleteAgencyContact = function (requestParams, callback) {
                var apiUrl = $("body").data("weburl") ? $("body").data("weburl") : "";

                $http({
                    method: "DELETE",
                    url: apiUrl + "/api/customer/deleteagencycontact?id=" + requestParams.id,
                    headers: {
                        "Authorization": requestParams.token,
                        "Content-Type": "application/json"
                    }
                })
                    .then(
                        function (result) {
                            callback({ success: true, data: result ? result.data : result, error: undefined });
                        },
                        function (error) {
                            callback({ success: false, data: undefined, error: error ? error.data : undefined });
                        });
            };

            this.customerBooking = function (requestParams, callback) {
                $http({
                    method: "GET",
                    url: requestParams.apiUrl + "?bookingNumber=" + requestParams.bookingNumber,
                    headers: {
                        "Authorization": requestParams.token,
                        "Content-Type": "application/json"
                    }
                })
                    .then(
                        function (result) {
                            callback({ success: true, data: result ? result.data : result, error: undefined });
                        },
                        function (error) {
                            callback({ success: false, data: undefined, error: error ? error.data : undefined });
                        });
            };

            this.cancelBooking = function (requestParams, callback) {
                var bookingId = requestParams.bookingId ? "bookingId=" + requestParams.bookingId:"";
                var bookingNumber = requestParams.bookingNumber ? "bookingNumber=" + requestParams.bookingNumber : ""; 
                var q = "?" + bookingId + (bookingId?"&":"") + bookingNumber;

                $http({
                    method: "DELETE",
                    url: requestParams.apiUrl + q,
                    headers: {
                        "Authorization": requestParams.token,
                        "Segment-Anonymous-Id": trackingService.getSegmentUserId(),
                        "Content-Type": "application/json"
                    }
                })
                    .then(
                        function (result) {
                            callback({ success: true, data: result ? result.data : result, error: undefined });
                        },
                        function (error) {
                            callback({ success: false, data: undefined, error: error ? error.data : undefined });
                        });
            };

            this.getBookingInvoice = function (requestParams, callback) {
                $http({
                    method: "GET",
                    url: requestParams.apiUrl + "?bookingNumber=" + requestParams.bookingNumber,
                    headers: {
                        "Authorization": requestParams.token,
                        "Content-Type": "application/pdf"
                    },
                    responseType: "arraybuffer"
                })
                    .then(
                        function (result) {
                            if (result) {
                                var file = new Blob([result.data ? result.data : result], { type: "application/pdf" });
                                var fileUrl = URL.createObjectURL(file);
                                if (window.navigator.msSaveOrOpenBlob) { //IE doesn't support displaying blobs directly but they can be downloaded
                                    window.navigator.msSaveOrOpenBlob(file, "Invoice.pdf");
                                } else {
                                    //other browsers can open the PDF in another tab 
                                    window.open(fileUrl, "_blank");
                                }
                            }
                            callback({ success: true, data: undefined, error: undefined });
                        },
                        function (error) {
                            callback({ success: false, data: undefined, error: error ? error.data : undefined });
                        });
            };

            function b64toBlob(b64Data, contentType, sliceSize) {
                contentType = contentType || '';
                sliceSize = sliceSize || 512;

                var byteCharacters = atob(b64Data);
                var byteArrays = [];

                for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
                    var slice = byteCharacters.slice(offset, offset + sliceSize);

                    var byteNumbers = new Array(slice.length);
                    for (var i = 0; i < slice.length; i++) {
                        byteNumbers[i] = slice.charCodeAt(i);
                    }

                    var byteArray = new Uint8Array(byteNumbers);

                    byteArrays.push(byteArray);
                }

                var blob = new Blob(byteArrays, { type: contentType });
                return blob;
            }

            this.getAllBookingDocuments = function (requestParams, callback) {
                $http({
                    method: "GET",
                    url: requestParams.apiUrl + "?bookingNumber=" + requestParams.bookingNumber,
                    headers: {
                        "Authorization": requestParams.token,
                        "Content-Type": "application/json"
                    }//,
                    //  responseType: "arraybuffer"
                })
                    .then(
                        function (result) {
                            if (result && result.data && result.data.documents) {
                                _.each(result.data.documents, function (doc) {
                                    var file = b64toBlob(doc.documentBytes, "application/pdf");
                                    var fileUrl = URL.createObjectURL(file);
                                    if (window.navigator.msSaveOrOpenBlob) { //IE doesn't support displaying blobs directly but they can be downloaded
                                        window.navigator.msSaveOrOpenBlob(file, doc.documentName + ".pdf");
                                    } else {
                                        //other browsers can open the PDF in another tab 
                                        window.open(fileUrl, "_blank");
                                    }
                                });
                            }
                            callback({ success: true, data: undefined, error: undefined });
                        },
                        function (error) {
                            callback({ success: false, data: undefined, error: error ? error.data : undefined });
                        });
            };

            this.getDocument = function (requestParams, callback) {
                $http({
                    method: "GET",
                    url: requestParams.apiUrl + "?documentType=" + requestParams.documentType,
                    headers: {
                        "Authorization": requestParams.token,
                        "Content-Type": "application/pdf"
                    },
                    responseType: "arraybuffer"
                })
                    .then(
                        function (result) {
                            if (result) {
                                var file = new Blob([result.data ? result.data : result], { type: "application/pdf" });
                                var fileUrl = URL.createObjectURL(file);
                                if (window.navigator.msSaveOrOpenBlob) { //IE doesn't support displaying blobs directly but they can be downloaded
                                    window.navigator.msSaveOrOpenBlob(file, "TermsAndConditions.pdf");
                                } else {
                                    //other browsers can open the PDF in another tab 
                                    window.open(fileUrl, "_blank");
                                }
                            }
                            callback({ success: true, data: undefined, error: undefined });
                        },
                        function (error) {
                            callback({ success: false, data: undefined, error: error ? error.data : undefined });
                        });
            };

        }
    ]);

})(jQuery);
(function ($) {
    "use strict";

    angular.module("app").service("hotelsService", ["localStorageService", "$http", function (localStorageService, $http) {
        this.removeAllStoredData = function () {
            if (localStorageService.isSupported) {
                localStorageService.remove("hotelsFilters");
                localStorageService.remove("prevHotel");
                localStorageService.remove("hotelWizardModel");
            }
        };

        this.getHotelsFilters = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/usercode/searchfilters/Hotels",
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.getHotelsByDate = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/product/productsbycategory/" + (params.id || "Hotels") + "/" + params.date,
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        }

        this.getRates = function (params, callback) {
            var addQ = "";
            //if (params.adults) {
            addQ += "/" + (params.adults || 0);
            // if (params.children) {
            addQ += "/" + (params.children || 0);
            if (params.blockId) {
                addQ += "/" + (params.blockId || 0);
            }
            //  }
            // }

            $http({
                method: "GET",
                url: params.urlPrefix + "/api/product/getratesandavailability/" + params.productCode + "/" + params.travelDate + "/" + params.nights + addQ,
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.getHotelProduct = function (params, callback) {
            var addQ = "";
            if (params.adults) {
                addQ += "/" + params.adults;
                if (params.children) {
                    addQ += "/" + params.children;
                }
            }
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/product/hotelproduct/" + params.productCode + "/" + params.travelDate + "/" + params.nights + addQ,
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        }

        this.getHotelProductWithPackages = function (params, callback) {

            var addQ = "";
            if (params.adults) {
                addQ += "/" + params.adults;
                if (params.children) {
                    addQ += "/" + params.children;
                }
            }
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/product/hotelproductwithpackages/" + params.productCode + "/" + params.travelDate + "/" + params.nights + addQ,
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        }

        this.removeActivitiesFilters = function () {
            if (localStorageService.isSupported) {
                localStorageService.remove("hotelsFilters");
            }
        }

        this.persistHotelsFilters = function (id, filters, callback) {
            if (localStorageService.isSupported) {
                var expireDate = new Date();
                filters.id = id;
                filters.expire = expireDate;
                localStorageService.set("hotelsFilters", filters);
                callback({ success: true, data: filters, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: "Local Storage is not supported!" });
            }
        }

        this.getPersistedHotelsFilters = function (id, callback) {
            if (localStorageService.isSupported) {
                var filters = localStorageService.get("hotelsFilters");
                if (filters && filters.expire) {
                    var date = new Date(filters.expire);
                    var today = new Date();
                    if (filters.id != id || date.getDate() !== today.getDate() || date.getMonth() !== today.getMonth() || date.getFullYear() !== today.getFullYear()) {
                        localStorageService.remove("hotelsFilters");
                        filters = null;
                    }
                } else {
                    localStorageService.remove("hotelsFilters");
                    filters = null;
                }
                callback({ success: true, data: filters, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: "Local Storage is not supported!" });
            }
        }

        this.setIsFromFilters = function (val, callback) {
            if (localStorageService.isSupported) {
                localStorageService.set("isFromFilters", val);
                callback({ success: true, error: undefined });
            } else {
                callback({ success: false, error: undefined });
            }
        };
        this.getIsFromFilters = function () {
            if (localStorageService.isSupported) {
                var val = localStorageService.get("isFromFilters");
                return val;
            } else {
                return undefined;
            }
        };

        this.setIsFromHotelDetails = function (val, callback) {
            if (localStorageService.isSupported) {
                localStorageService.set("isFromHotelDetails", val);
                callback({ success: true, error: undefined });
            } else {
                callback({ success: false, error: undefined });
            }
        };
        this.getIsFromHotelDetails = function () {
            if (localStorageService.isSupported) {
                var val = localStorageService.get("isFromHotelDetails");
                return val;
            } else {
                return undefined;
            }
        };

        this.getSelectedHotel = function (callback) {
            if (localStorageService.isSupported) {
                var hotel = localStorageService.get("prevHotel");
                if (hotel && hotel.expire) {
                    var date = new Date(hotel.expire);
                    var today = new Date();
                    if (date.getDate() !== today.getDate() || date.getMonth() !== today.getMonth() || date.getFullYear() !== today.getFullYear()) {
                        localStorageService.remove("prevHotel");
                        hotel = null;
                    }
                } else {
                    localStorageService.remove("prevHotel");
                    hotel = null;
                }
                callback({ success: true, data: hotel, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: undefined });
            }
        }

        this.setSelectedHotel = function (hotel, callback) {
            if (localStorageService.isSupported) {
                var expireDate = new Date();
                hotel.expire = expireDate;
                localStorageService.set("prevHotel", hotel);
                callback({ success: true, data: hotel, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: undefined });
            }
        }

        this.getHotelWizardModel = function (callback) {
            if (localStorageService.isSupported) {
                var wizardModel = localStorageService.get("hotelWizardModel");
                if (wizardModel && wizardModel.expire) {
                    var date = new Date(wizardModel.expire);
                    var today = new Date();
                    if (date.getDate() !== today.getDate() || date.getMonth() !== today.getMonth() || date.getFullYear() !== today.getFullYear()) {
                        localStorageService.remove("hotelWizardModel");
                        wizardModel = null;
                    }
                } else {
                    localStorageService.remove("hotelWizardModel");
                    wizardModel = null;
                }
                callback({ success: true, data: wizardModel, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: undefined });
            }
        }

        this.removeHotelWizardModel = function (callback) {
            if (localStorageService.isSupported) {
                localStorageService.remove("hotelWizardModel");
                // localStorageService.remove("prevActivity");
            }
            if (callback)
                callback();
        };

        this.setHotelWizardModel = function (wizardModel, callback) {
            if (localStorageService.isSupported) {
                var expireDate = new Date();
                wizardModel.expire = expireDate;
                localStorageService.set("hotelWizardModel", wizardModel);
                callback && callback({ success: true, data: wizardModel, error: undefined });
            } else {
                callback && callback({ success: false, data: undefined, error: undefined });
            }
        }
    }]);

})(jQuery);
(function ($) {
    "use strict";

    angular.module("app").service("jwtService", [
        "localStorageService", "$http", "$rootScope", "shoppingCartService", function (localStorageService, $http, $rootScope, shoppingCartService) {
            var jwtExpiration = 4;
            var serverDate = undefined;
            this.getServerMomentDate = function (withTime) {
                if (!jQuery("body").attr("data-server-date")) {
                    serverDate = moment();
                    return serverDate;
                }
                var val = jQuery("body").attr("data-server-date");
                serverDate = withTime ? moment(val, "YYYY-MM-DD HH:mm:ss") : moment(val, "YYYY-MM-DD");

                if (!serverDate || !serverDate.isValid()) {
                    serverDate = moment();
                    return serverDate;
                }
                return serverDate;
            };
            this.getServerStrDate = function () {
                return this.getServerMomentDate().format("YYYY-MM-DD");
            };
            this.getTokenObj = function () {
                if (localStorageService.isSupported) {
                    var tokenObj = localStorageService.get("token");

                    if (tokenObj && tokenObj.token && tokenObj.expire) {
                        var date = new Date(tokenObj.expire);

                        if (date < new Date()) {
                            localStorageService.remove("token");
                            return null;
                        }
                        return tokenObj;
                    }
                }
                return null;
            };

            this.getToken = function () {
                var tokenObj = this.getTokenObj();
                if (tokenObj) {
                    return tokenObj.token;
                }
                return null;
            };

            //remove - not used
            this.getTokenGeography = function () {
                var tokenObj = this.getTokenObj();
                if (tokenObj) {
                    return tokenObj.geographyCode;
                }
                return null;
            };

            this.getCurrency = function () {
                var tokenObj = this.getTokenObj();
                if (tokenObj) {
                    return tokenObj.currency;
                }
                return null;
            };

            this.getPrincipalTokenCurrency = function () {
                if (localStorageService.isSupported) {
                    var tokenObj = this.getCustomerTokenObj();
                    if (tokenObj) {
                        return tokenObj.currency;
                    }
                    tokenObj = this.getTokenObj();
                    if (tokenObj) {
                        return tokenObj.currency;
                    }
                    return undefined;
                }
                return null;
            };

            this.setToken = function (token) {
                var expireDate = new Date();
                expireDate.setHours(expireDate.getHours() + jwtExpiration);
                var tokenObj = {
                    "token": token.token,
                    "currency": token.currency,
                    "maxQuantityOfReservedTimes": token.maxQuantityOfReservedTimes,
                    "anonymousTicketRedirectURL": token.anonymousTicketRedirectURL,

                    "expire": expireDate
                };

                if (localStorageService.isSupported) {
                    localStorageService.set("token", tokenObj);
                }
            };

            this.getCustomerTokenObj = function () {
                if (localStorageService.isSupported) {
                    var tokenObj = localStorageService.get("customerToken");

                    if (tokenObj && tokenObj.token && tokenObj.expire) {
                        var date = new Date(tokenObj.expire);

                        if (date < new Date()) {
                            localStorageService.remove("customerToken");
                            return null;
                        }
                        return tokenObj;
                    }
                }

                return null;
            };
            this.getCustomerToken = function () {
                var tokenObj = this.getCustomerTokenObj();
                if (tokenObj) {
                    return tokenObj.token;
                }
                return null;
            };

            //not used
            this.getCustomerTokenGeography = function () {
                var tokenObj = this.getCustomerTokenObj();
                if (tokenObj) {
                    return tokenObj.geographyCode;
                }
                return null;
            };

            this.setCustomerToken = function (token) {
                if (!token || !token.token) return;

                var expireDate = new Date();
                expireDate.setHours(expireDate.getHours() + jwtExpiration);
                var tokenObj = {
                    "token": token.token,
                    "currency": token.currency,
                    "maxQuantityOfReservedTimes": token.maxQuantityOfReservedTimes,
                    "anonymousTicketRedirectURL": token.anonymousTicketRedirectURL,
                    "maxNumberOfAdults": token.maxNumberOfAdults,
                    "expire": expireDate,
                    "loginType": token.loginType
                };

                if (localStorageService.isSupported) {
                    localStorageService.set("customerToken", tokenObj);
                }
            };

            this.getCustomer = function () {
                var token = this.getCustomerToken();
                if (token) {
                    if (localStorageService.isSupported) {
                        return localStorageService.get("customer");
                    }
                } else {
                    localStorageService.remove("customer");
                }

                return null;
            };

            this.setCustomer = function (customer) {
                if (localStorageService.isSupported) {
                    if (customer) {
                        localStorageService.set("customer", customer);
                    } else {
                        localStorageService.remove("customer");
                    }
                }
            };

            this.setCustomerLogin = function (customerLogin) {
                if (localStorageService.isSupported) {
                    if (customerLogin) {
                        localStorageService.set("customerLoginEmail", customerLogin);
                    } else {
                        localStorageService.remove("customerLoginEmail");
                    }
                }
            };

            this.getCustomerLogin = function () {
                var token = this.getCustomerToken();
                if (token) {
                    if (localStorageService.isSupported) {
                        return localStorageService.get("customerLoginEmail");
                    }
                } else {
                    localStorageService.remove("customerLoginEmail");
                }

                return null;
            };

            //not used
            this.setGeographyPrincipalToken = function (newToken, geographyCode) {
                if (localStorageService.isSupported) {
                    var custmerToken = this.getCustomerTokenObj();
                    if (custmerToken) {
                        custmerToken.token = newToken.token;
                        this.setCustomerToken(custmerToken, geographyCode);
                        return true;
                    }
                    this.setToken(newToken, geographyCode);
                    return true;
                }
                return false;
            };

            //remove
            this.getPrincipalTokenGeography = function () {
                if (localStorageService.isSupported) {
                    var tokenObj = this.getCustomerTokenObj();
                    if (tokenObj) {
                        return tokenObj.geographyCode;
                    }
                    tokenObj = this.getTokenObj();
                    if (tokenObj) {
                        return tokenObj.geographyCode;
                    }
                    return undefined;
                }
                return null;
            };

            this.getPrincipalTokenObj = function () {
                if (localStorageService.isSupported) {

                    var custmerToken = this.getCustomerTokenObj();
                    if (custmerToken) {
                        return custmerToken;
                    }

                    return this.getTokenObj();
                }
                return null;
            };

            this.getPrincipalToken = function () {
                if (localStorageService.isSupported) {

                    var custmerToken = this.getCustomerToken();
                    if (custmerToken) {
                        return custmerToken;
                    }

                    return this.getToken();
                }
                return null;
            };

            this.persistGeographies = function (geographies, callback) {
                if (localStorageService.isSupported) {
                    var expireDate = new Date();
                    geographies.expire = expireDate;
                    localStorageService.set("geographies", geographies);
                    callback({ success: true, data: geographies, error: undefined });
                } else {
                    callback({ success: false, data: undefined, error: "Local Storage is not supported!" });
                }
            };

            this.getPersistedGeographies = function (callback) {
                if (localStorageService.isSupported) {
                    var geographies = localStorageService.get("geographies");
                    if (geographies && geographies.expire) {
                        var date = new Date(geographies.expire);
                        var today = new Date();
                        if (date.getDate() !== today.getDate() || date.getMonth() !== today.getMonth() || date.getFullYear() !== today.getFullYear()) {
                            localStorageService.remove("geographies");
                            geographies = null;
                        }
                    } else {
                        localStorageService.remove("geographies");
                        geographies = null;
                    }
                    callback({ success: true, data: geographies, error: undefined });
                } else {
                    callback({ success: false, data: undefined, error: "Local Storage is not supported!" });
                }
            };

            this.getGeographiesAsync = function (params, callback) {
                $http({
                    method: "GET",
                    url: params.urlPrefix + "/api/authentication/Geographies",
                    headers: { "Authorization": params.token }
                }).then(
                    function (result) {
                        callback({ success: true, data: result.data, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response.data });
                        console.log(response);
                    }
                );
            };




            //product search category options
            this.persistProductCategorySearchOptions = function (productcategorysearchoptions, callback) {
                if (localStorageService.isSupported) {
                    var expireDate = new Date();
                    productcategorysearchoptions.expire = expireDate;
                    localStorageService.set("productcategorysearchoptions", productcategorysearchoptions);
                    callback({ success: true, data: productcategorysearchoptions, error: undefined });
                } else {
                    callback({ success: false, data: undefined, error: "Local Storage is not supported!" });
                }
            };

            this.getPersistedProductCategorySearchOptions = function (callback) {
                if (localStorageService.isSupported) {
                    var productsearchoptions = localStorageService.get("productcategorysearchoptions");
                    if (productsearchoptions && productsearchoptions.expire) {
                        var date = new Date(productsearchoptions.expire);
                        var today = new Date();
                        if (date.getDate() !== today.getDate() || date.getMonth() !== today.getMonth() || date.getFullYear() !== today.getFullYear()) {
                            localStorageService.remove("productcategorysearchoptions");
                            productsearchoptions = null;
                        }
                    } else {
                        localStorageService.remove("productcategorysearchoptions");
                        productsearchoptions = null;
                    }
                    callback({ success: true, data: productsearchoptions, error: undefined });
                } else {
                    callback({ success: false, data: undefined, error: "Local Storage is not supported!" });
                }
            };

            this.getProductCategorySearchOptionsAsync = function (params, callback) {
                $http({
                    method: "GET",
                    url: params.urlPrefix + "/api/usercode/productcategorysearchoptions",
                    headers: { "Authorization": params.token }
                }).then(
                    function (result) {
                        callback({ success: true, data: result.data, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response.data });
                        console.log(response);
                    }
                );
            };

            this.refreshCart = function (newToken, callback) {
                var service = this;
                shoppingCartService.getStorageCart(function (shoppingCart) {
                    if (shoppingCart && (shoppingCart.Items || "").length) {
                        var requestParams = {
                            apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                            token: newToken || service.getPrincipalToken(),
                            promoCodes: shoppingCart.DiscountCodes
                        };

                        shoppingCartService.refreshPromoCodesQuote(requestParams, function (shoppingCart) {
                            callback();
                        });
                    } else
                        callback();
                });
            };

            function processPrincipalTokenAndRegionAsync(webUrl, regionCode, trackingInfo, callback, isSameRegion, isSameLanguage) {
                var service = this;

                service.getAnonymousUsers(function (users) {
                    var defaultUser = _.find(users, function (user) { return user.default; });
                    var currUrl = window.location.hostname;
                    var selectedRegion = undefined;
                    var selectedLanguage = "en";

                    var selectedUser = regionCode ?
                        _.find(users, function (user) {
                            var isFound = user.geographyCode === regionCode;
                            if (!isFound && (user.languages || '').length) {
                                isFound = _.find(user.languages, function (lang) { if (lang.geographyCode == regionCode) { selectedLanguage = lang.languageCode; selectedRegion = lang.geographyCode; return true; }; return false; }) != undefined;
                            }
                            return isFound;
                        }) :
                        _.find(users, function (user) {
                            if (!(user.urls || "").length) return false;
                            return _.find(user.urls, function (url) { return currUrl.indexOf(url) > -1; });
                        });//find default user by url

                    if (!selectedUser && !defaultUser) {
                        callback();
                        return;
                    }
                    if (!selectedUser) selectedUser = defaultUser;

                    var processLanguage = undefined;

                    selectedLanguage = selectedLanguage && selectedLanguage.split('-')[0].toLowerCase();

                    if (selectedLanguage && ((isSameRegion && !isSameLanguage) || selectedLanguage != "en")) {
                        processLanguage = function (token, langCallback) {
                            $http({
                                method: "POST",
                                url: webUrl + "/api/authentication/setlanguage/" + selectedLanguage,
                                headers: {
                                    "Authorization": token,
                                    'Content-Type': "application/json"
                                }
                            }).success(function (data, status, headers, config) {
                                var jwt = data; //.token;
                                var customertoken = service.getCustomerToken();
                                if (customertoken) {
                                    service.setCustomerToken(jwt);
                                } else {
                                    service.setToken(jwt);
                                }
                                service.setGeography(selectedRegion || selectedUser.geographyCode);

                                // $rootScope.$broadcast("getPrincipalToken", data.token);
                                service.refreshCart(jwt.token, function () { langCallback(jwt); });
                            }).
                                error(function (data, status, headers, config) {
                                    console.log(data);
                                    if (data && (data.token || "").length) {
                                        var customertoken = service.getCustomerToken();
                                        if (customertoken) {
                                            service.setCustomerToken(data);
                                        } else {
                                            service.setToken(data);
                                        }

                                        // $rootScope.$broadcast("getPrincipalToken", data.token);
                                        service.refreshCart(data.token, function () { langCallback(data); });
                                    }
                                });
                        };
                    }

                    var dataToPost = {
                        "Username": selectedUser.username,
                        "Password": selectedUser.password
                    };
                    var oldWebLink = service.getWebLink();
                    dataToPost.WebLink = isSameRegion ? oldWebLink : null;

                    if (trackingInfo) {
                        dataToPost.CRMVisitId = trackingInfo.CRMVisitId;
                        dataToPost.CRMVisitorId = trackingInfo.CRMVisitorId;
                        if (trackingInfo.WebLink) {
                            dataToPost.WebLink = trackingInfo.WebLink;
                        }
                    }


                    var postUrl = "/api/authentication/login/";
                    service.clearStorage(!isSameRegion, true);
                    //  $http.post(webUrl + postUrl).

                    // if weblink is present reauthenticate
                    if (service.getToken() && isSameRegion && (!trackingInfo.WebLink || oldWebLink == trackingInfo.WebLink)) {
                        if (processLanguage) {
                            processLanguage(service.getPrincipalToken(), function (newjwt) {
                                $rootScope.$broadcast("getPrincipalToken", newjwt.token);
                                callback(newjwt);
                            });
                        } else {
                            callback(undefined);
                        }
                    } else {
                        $http({
                            method: "POST",
                            url: webUrl + postUrl,
                            headers: {
                                'Content-Type': "application/json"
                            },
                            data: dataToPost
                        }).success(function (data, status, headers, config) {
                            var jwt = data; //.token;
                            service.setWebLink(dataToPost.WebLink);
                            service.setToken(jwt);
                            service.setGeography(selectedRegion || selectedUser.geographyCode);
                            if (processLanguage) {
                                processLanguage(jwt.token, function (newjwt) {
                                    $rootScope.$broadcast("getPrincipalToken", newjwt.token);
                                    callback(newjwt);
                                });
                            } else {
                                $rootScope.$broadcast("getPrincipalToken", jwt.token);
                                callback(jwt);
                            }

                        }).
                            error(function (data, status, headers, config) {
                                console.log(data);
                                if (data && (data.token || "").length) {
                                    service.setToken(data);
                                    if (processLanguage) {
                                        processLanguage(data.token, function (newdata) {
                                            $rootScope.$broadcast("getPrincipalToken", newdata.token);
                                            callback(newdata);
                                        });
                                    } else {
                                        $rootScope.$broadcast("getPrincipalToken", data.token);
                                        callback(data);
                                    }
                                }
                            });
                    }

                });
            }

            this.setPrincipalTokenAndRegionAsync = function (webUrl, regionCode, trackingInfo, callback) {

                var service = this;

                regionCode = (regionCode || "").trim();
                var selectedGeo = (service.getGeography() || "").toLowerCase();
                var currGeo = regionCode.toLowerCase();
                var isSameRegion = selectedGeo.indexOf(currGeo) >= 0 || currGeo.indexOf(selectedGeo) >= 0;
                var isSameLang = selectedGeo === currGeo;

                //var currGeo = service.getGeography();

                if (localStorageService.isSupported) {
                    var custmerToken = this.getCustomerToken();
                    var initAnonym = true;

                    if (custmerToken) {
                        if (!regionCode || isSameLang) {
                            initAnonym = false;
                            callback(custmerToken);
                        } else if (!isSameRegion) {
                            service.clearStorage(true);
                            localStorageService.remove("customer");
                            localStorageService.remove("customerToken");
                            localStorageService.remove("customerLoginEmail");
                        }
                    } else {
                        if (!isSameRegion) {
                            service.clearStorage(true);
                            localStorageService.remove("customer");
                            localStorageService.remove("customerToken");
                            localStorageService.remove("customerLoginEmail");
                        }
                    }

                    if (initAnonym) {
                        //when to return current token - if token exists and region is null or region same as current token
                        var token = service.getToken();
                        var oldWebLink = service.getWebLink();

                        if (token && (!regionCode || isSameLang) && (!trackingInfo.WebLink || oldWebLink == trackingInfo.WebLink)) {
                            callback(token);
                            return;
                        }
                        //wait for EnvokeIDs init
                        var maxAttempts = 30;//30*200 = 6sec
                        var attemptCount = 0;
                        if (!trackingInfo.IsInit) {
                            var waitForTracking = setInterval(function () {
                                attemptCount++;

                                if (window.nvk) {
                                    trackingInfo.CRMVisitId = window.nvk.visit_id;
                                    trackingInfo.CRMVisitorId = window.nvk.visitor_id;
                                    trackingInfo.IsInit = true;
                                    clearInterval(waitForTracking);
                                    processPrincipalTokenAndRegionAsync.call(service, webUrl, regionCode, trackingInfo, callback, isSameRegion, isSameLang);
                                } else if (attemptCount === maxAttempts) {
                                    processPrincipalTokenAndRegionAsync.call(service, webUrl, regionCode, trackingInfo, callback, isSameRegion, isSameLang);
                                }
                            }, 200);
                        } else {
                            processPrincipalTokenAndRegionAsync.call(service, webUrl, regionCode, trackingInfo, callback, isSameRegion, isSameLang);
                        }
                    }
                } else {
                    callback(null);
                }
            };

            //remove cart- false by default, remove checkout - true by default
            this.clearStorage = function (removeCart, leaveCheckout) {
                localStorageService.remove("activitiesFilters");
                localStorageService.remove("prevActivity");
                localStorageService.remove("activityWizardModel");

                localStorageService.remove("hotelsFilters");
                localStorageService.remove("prevHotel");
                localStorageService.remove("hotelWizardModel");

                localStorageService.remove("transportationsFilters");
                localStorageService.remove("prevTransportation");
                localStorageService.remove("transportationWizardModel");
                if (removeCart) {
                    localStorageService.remove("shoppingCart");
                    localStorageService.remove("bookingOrder");
                    localStorageService.remove("weblink");
                }
                localStorageService.remove("productCategory");
                if (!leaveCheckout) {
                    localStorageService.remove("selectedCard");
                    localStorageService.remove("checkoutModel");
                }
                localStorageService.remove("productcategorysearchoptions");

                localStorageService.remove("agencyContacts");
                localStorageService.remove("worldCountries");
                localStorageService.remove("geographies");
            };

            this.setPrincipalTokenAsync = function (webUrl, trackingInfo, callback) {
                var service = this;

                if (localStorageService.isSupported) {
                    var custmerToken = this.getCustomerToken();
                    if (custmerToken) {
                        callback(custmerToken);
                    } else {
                        var token = this.getToken();
                        var oldWebLink = this.getWebLink();

                        if (token && (!trackingInfo.WebLink || oldWebLink == trackingInfo.WebLink)) {
                            callback(token);
                        } else {
                            service.getDefaultAnonymousUser(function (user) {

                                var dataToPost = {
                                    "Username": user.username,
                                    "Password": user.password
                                };

                                var hasTracking = trackingInfo &&
                                    (trackingInfo.CRMVisitId || trackingInfo.CRMVisitorId);

                                if (hasTracking) {
                                    dataToPost.CRMVisitId = trackingInfo.CRMVisitId;
                                    dataToPost.CRMVisitorId = trackingInfo.CRMVisitorId;
                                }

                                dataToPost.WebLink = (trackingInfo && trackingInfo.WebLink) || oldWebLink;


                                var postUrl = "/api/authentication/login/";// + user.username + "/" + user.password + "/" + crmVisitParams;

                                $http({
                                    method: "POST",
                                    url: webUrl + postUrl,
                                    headers: {
                                        'Content-Type': "application/json"
                                    },
                                    data: dataToPost
                                }).
                                    success(function (data, status, headers, config) {
                                        var jwt = data; //.token;
                                        service.setWebLink(dataToPost.WebLink);
                                        service.setToken(jwt);
                                        service.setGeography(user.geographyCode);

                                        $rootScope.$broadcast("getPrincipalToken", data.token);
                                        callback(jwt);
                                    }).
                                    error(function (data, status, headers, config) {
                                        console.log(data);
                                        if (data && (data.token || "").length) {
                                            service.setToken(data);
                                            $rootScope.$broadcast("getPrincipalToken", data.token);
                                            callback(data);
                                        }

                                    });
                            });
                        }
                    }
                } else {
                    callback(null);
                }
            };

            this.customerLogout = function (webUrl, callback) {
                var jwtService = this;
                $http.post(webUrl + "/api/authentication/customerlogout").
                    success(function (data, status, headers, config) {
                        jwtService.setCustomer(null);

                        callback();
                    }).
                    error(function (data, status, headers, config) {
                        console.log(data);
                    });
            };

            this.setWebLink = function (weblink) {
                if (localStorageService.isSupported) {
                    localStorageService.set("weblink", weblink);
                }
            };
            this.removeWebLink = function () {
                if (localStorageService.isSupported) {
                    localStorageService.remove("weblink");
                }
            };
            this.getWebLink = function () {
                if (localStorageService.isSupported) {
                    return localStorageService.get("weblink");
                }
                return null;
            };

            this.setProductCategory = function (category) {
                if (localStorageService.isSupported) {
                    localStorageService.set("productCategory", category);
                }
            };

            this.getProductCategory = function () {
                if (localStorageService.isSupported) {
                    return localStorageService.get("productCategory");
                }
                return null;
            };

            this.setGeography = function (geographyCode) {
                if (localStorageService.isSupported) {
                    localStorageService.set("geographyCode", geographyCode);
                }
            };
            this.removeGeography = function () {
                if (localStorageService.isSupported) {
                    localStorageService.remove("geographyCode");
                }
            };

            this.getCurrentCard = function () {
                if (localStorageService.isSupported) {
                    return localStorageService.get("selectedCard");
                }
                return null;
            };

            this.setCurrentCard = function (card) {
                if (localStorageService.isSupported) {
                    localStorageService.set("selectedCard", card);
                }
            };

            this.clearSelectedCard = function () {
                localStorageService.remove("selectedCard");
            };

            this.getGeography = function () {
                if (localStorageService.isSupported) {
                    var code = localStorageService.get("geographyCode");
                    if (!code) {
                        var geographiesData = localStorageService.get("geographies");
                        if (!geographiesData || !(geographiesData.geographies || "").length) return null;
                        this.setGeography(geographiesData.geographies[0].code);
                        return geographiesData.geographies[0].code;
                    } else {
                        return code;
                    }
                }
                return null;
            };

            this.setCheckoutModel = function (checkoutModel) {
                if (localStorageService.isSupported) {
                    localStorageService.set("checkoutModel", checkoutModel);
                }
            };

            this.getCheckoutModel = function (remove) {
                if (localStorageService.isSupported) {
                    var model = localStorageService.get("checkoutModel");

                    if (remove) {
                        localStorageService.set("checkoutModel", null);
                        localStorageService.remove("checkoutModel");
                    }
                    return model;
                }
                return null;
            };

            this.getAnonymousUsers = function (callback) {
                if (localStorageService.isSupported) {
                    var model = localStorageService.get("anonymouseUsers");
                    var getUsersFromApi = (!model || !model.result || !model.expire);
                    if (!getUsersFromApi) {
                        var date = new Date(model.expire);

                        if (date < new Date()) {
                            localStorageService.remove("anonymouseUsers");
                            getUsersFromApi = true;
                        }
                    }

                    if (!getUsersFromApi) {
                        callback(model.result);
                        return;
                    }

                    var version = Math.random().toString(36).substring(7);
                    $http.get("/content/configs/anonymoususers.json?v=" + version)
                        .then(function (res) {
                            var expireDate = new Date();
                            expireDate.setHours(expireDate.getHours() + 4);

                            var modelObj = { "result": (res ? res.data : undefined), "expire": expireDate };
                            localStorageService.set("anonymouseUsers", modelObj);

                            callback(res ? res.data : undefined);
                        });
                } else {
                    callback();
                }
            };


            this.getDefaultAnonymousUser = function (callback) {
                this.getAnonymousUsers(function (res) {
                    var defaultUser = _.find(res, function (user) { return user.default; });
                    callback(defaultUser);
                });
            };

            this.getAnonymousUserByGeography = function (geographyCode, callback) {
                this.getAnonymousUsers(function (res) {
                    // if (!geographyCode)

                    var defaultUser = _.find(res, function (user) { return user.default; });
                    if (!geographyCode) {
                        callback(defaultUser,true);
                        return;
                    }

                    var user = _.find(res, function (user) {
                        var isFound = user.geographyCode === geographyCode;

                        var selectedLanguage = (user.languages || '').length && _.find(user.languages, function (lang) { return lang.geographyCode == geographyCode; }) || null;
                        user.selectedLanguage = selectedLanguage;

                        if (!isFound) {
                            isFound = !!selectedLanguage;
                        }

                        return isFound;
                    });

                    callback(user || defaultUser, !user);
                });
            };

            this.getAnonymUserByDomain = function (callback) {
                this.getAnonymousUsers(function (res) {
                    if (!res) {
                        callback();
                        return;
                    }
                    var currUrl = window.location.hostname;

                    var selectedUser =
                        _.find(res, function (user) {
                            if (!(user.urls || "").length) return false;
                            return _.find(user.urls, function (url) { return currUrl.indexOf(url) > -1; });
                        });//find default user by url
                    if (!selectedUser) {
                        selectedUser = _.find(res, function (user) { return user.default; });
                    }
                    callback(selectedUser);
                });
            };

            this.setCurrentProduct = function (params, callback) {
                $http({
                    method: "POST",
                    url: params.urlPrefix + "/api/authentication/currentproduct",
                    data: {
                        "ProductCode": params.productCode,
                        "ProductTitle": params.productTitle
                    }
                }).then(
                    function (result) {
                        callback({ success: true, data: result.data, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response.data });
                        console.log(response);
                    }
                );
            };

            this.setDisableExitIntent = function (checkoutModel) {
                if (localStorageService.isSupported) {
                    localStorageService.set("disableExitIntent", true);
                }
            };

            this.getIsDisabledExitIntent = function () {
                if (localStorageService.isSupported) {
                    var disableExitIntent = localStorageService.get("disableExitIntent");
                    return disableExitIntent;
                }
                return null;
            };

            this.setAnonymousTicketHolder = function (params, callback) {
                $http({
                    method: "POST",
                    url: params.urlPrefix + "/api/authentication/setanonymousticketholder/",
                    data: {
                        accessCodes: params.accessCodes
                    },
                    headers: { "Authorization": params.token }
                }).then(
                    function (result) {
                        callback({ success: true, data: result.data, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response.data });
                        console.log(response);
                    }
                );
            };

            this.membershipLogin = function (params, callback) {
                $http({
                    method: "POST",
                    url: params.urlPrefix + "/api/authentication/setmembershiplogin/",
                    data: {
                        MembershipNumbers: params.membershipNumbers
                    },
                    headers: { "Authorization": params.token }
                }).then(
                    function (result) {
                        callback({ success: true, data: result.data, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response.data });
                        console.log(response);
                    }
                );
            };
        }
    ]);

})(jQuery);
(function ($) {
    "use strict";

    angular.module("app").service("packagesService", [
        "localStorageService", "$http", "$rootScope", function (localStorageService, $http, $rootScope) {


            this.getPackageDurationLabel = function (pck) {
                var hasHotelComponent = _.find(pck.Components, function (pckComp) {
                    return pckComp.ProductCategory.trim().toLowerCase() === "hotel";
                });
                var durationLabels = {
                    "singleNight": "Night",
                    "multipleNights": "Nights",
                    "singleDay": "Day",
                    "multipleDays": "Days"
                }
                if (pck.Duration < 2) {
                    return pck.Duration + " " + (hasHotelComponent ? durationLabels["singleNight"] : durationLabels["singleDay"]);
                }
                else {
                    return pck.Duration + " " + (hasHotelComponent ? durationLabels["multipleNights"] : durationLabels["multipleDays"]);
                }
            };

            this.getPackageDescriptions = function (params, callback) {
                $http({
                    method: "GET",
                    url: params.urlPrefix + "/api/product/packageDescriptions/" + params.packageCode + (params.travelDate ? ("/" + params.travelDate) : ""),
                    headers: { "Authorization": params.token }
                }).then(
                    function (result) {
                        if (result.data && !result.data.packages) {
                            result.data.packages = [
                                {
                                    code: params.packageCode,
                                    packageCode: params.packageCode,
                                    packageDescriptions: result.data.data,
                                    startDate: result.data.data && result.data.data.nextAvailableDate,
                                    nextAvailableDate: result.data.data && result.data.data.nextAvailableDate,
                                    isDynamicallyPrice: result.data.data && result.data.data.isDynamicallyPrice,
                                    type: result.data.data && result.data.data.type,
                                }
                            ];
                        }

                        callback({ success: true, data: result.data, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response ? response.data : response });
                        console.log(response);
                    }
                );
            };

            this.getPackageSummaries = function (params, callback) {
                $http({
                    method: "GET",
                    url: params.urlPrefix + "/api/product/packagesummariesforproduct/" + params.productCode + (params.travelDate ? ("/" + params.travelDate) : ""),
                    headers: { "Authorization": params.token }
                }).then(
                    function (result) {
                        callback({ success: true, data: result.data, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response ? response.data : response });
                        console.log(response);
                    }
                );
            };

            this.getPackageSummariesByProductType = function (params, callback) {

                $http({
                    method: "GET",
                    url: params.urlPrefix + "/api/product/packagesummariesbyproducttype/" + params.productCategory + "/" + params.productType + (params.travelDate ? ("/" + params.travelDate) : ""),
                    headers: { "Authorization": params.token }
                }).then(
                    function (result) {
                        callback({ success: true, data: result.data, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response ? response.data : response });
                        console.log(response);
                    }
                );
            };

            this.getPackageSummariesForProductCategory = function (params, callback) {
                $http({
                    method: "GET",
                    url: params.urlPrefix + "/api/product/packagesummariesforproductcategory/" + params.category + (params.travelDate ? ("/" + params.travelDate) : ""),
                    headers: { "Authorization": params.token }
                }).then(
                    function (result) {
                        callback({ success: true, data: result.data, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response ? response.data : response });
                        console.log(response);
                    }
                );
            };


            this.getPackageDetailsPromise = function (params) {
                var additionalParam = "";

                additionalParam += "/" + (params.adults || "0");

                additionalParam += "/" + (params.children || "0");

                if (params.nights) {
                    additionalParam += "/" + params.nights;
                }

                return $http({
                    method: "GET",
                    url: params.urlPrefix + "/api/product/package/" + params.productCode + "/" + params.travelDate + additionalParam,
                    headers: { "Authorization": params.token }
                });
            };

            this.getPackageDetails = function (params, callback) {
                this.getPackageDetailsPromise(params).then(
                    function (result) {
                        callback({ success: true, data: result.data, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response ? response.data : response });
                        console.log(response);
                    }
                );
            };

        }
    ]);

})(jQuery);
(function ($) {
    "use strict";

    angular.module("app").service("paymentService", [
        "localStorageService", "$http", "$rootScope", function (localStorageService, $http, $rootScope) {
            var paymentService = this;

            this.getGiftCardBalanceCards = function (params, callback) {
                $http({
                    method: "GET",
                    url: params.urlPrefix + "/api/payment/giftcardbalance/" + params.giftCardProvider + "/" + params.giftCardID,
                    headers: { "Authorization": params.token }
                }).then(
                    function (result) {
                        callback({ success: true, data: result && result.data, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response.data });
                        console.log(response);
                    }
                );
            };

            this.getFilteredCards = function (sourceCards) {
                return sourceCards;
                var filteredCards = [];
                if (sourceCards && sourceCards.length > 0) {
                    var groupedCards = _.groupBy(sourceCards, function (card) { return card.cardnumber; });

                    var distict = _.uniq(sourceCards, function (card) { return card.cardnumber; });

                    for (var i = 0; i < distict.length; i++) {
                        var sortedCards = _.sortBy(groupedCards[distict[i].cardnumber], function (ct) { return ct.version });
                        sortedCards[0].cardNumber = sortedCards[0].cardnumber;
                        filteredCards.push(sortedCards[0]);
                    }

                    /*for (var i = 0; i < sourceCards.length; i++) {
                        /*if (sourceCards[i].version === "0") {#1#
                            sourceCards[i].cardNumber = sourceCards[i].cardnumber;
                            filteredCards.push(sourceCards[i]);
                        /*}#1#
                    }*/
                }

                return filteredCards;
            }

            this.getCreditCards = function (params, callback) {
                $http({
                    method: "GET",
                    url: params.urlPrefix + "/api/payment/creditcard",
                    headers: { "Authorization": params.token }
                }).then(
                    function (result) {
                        var filteredCards = paymentService.getFilteredCards(result.data.tokenizedcreditcards);

                        callback({ success: true, data: filteredCards, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response.data });
                        console.log(response);
                    }
                );
            };



            this.postCreditCard = function (params, callback) {
                // return temporary stub of data

                /*var card = {
                    tokenizedCreditCards: [],
                    echo: null,
                    errors: [],
                    displayErrors: ""
                };

                var tokinizedCard = {
                    address: "1 Main street",
                    businesspartnerid: 1001,
                    businesspartnernumber: "number_1001",
                    cardid: "11111111",
                    cardNumber: "XXXXXXXXXXXX1111",
                    city: "Vancouver",
                    country: "CA",
                    createddate: "09/16",
                    expirydate: "09/18",
                    nameoncard: "Victor Lungu",
                    firstName: "Victor",
                    lastName: "Lungu",
                    expirationMonth: "09",
                    expirationYear: "18",
                    pacificcardtype: "Visa",
                    postalcode: "VC-2020",
                    city: "BC",
                    version: "1.0"
                }

                card.tokenizedCreditCards.push(tokinizedCard);

                callback({ success: true, data: card.tokenizedCreditCards, error: undefined });

                return;*/

                var service = this;
                var p = params;
                $http({
                    method: "POST",
                    url: params.urlPrefix + "/api/payment/creditcard",
                    headers: { "Authorization": params.token },
                    data: {
                        "CresecureHpfCallbackFullQueryParams": params.fullQuery,
                    }
                }).then(
                    function (res) {

                        var createdCardId = res && res.data && (res.data.tokenizedcreditcards || "").length ?
                            res.data.tokenizedcreditcards[0].cardid
                            : undefined;
                        var getParams = { urlPrefix: p.urlPrefix, token: p.token }
                        service.getCreditCards(getParams, function (result) {
                            var filteredCards = paymentService.getFilteredCards(result.data);
                            _.each(filteredCards, function (c) { if (c.cardid === createdCardId) c.cardCreated = true; });

                            callback({ success: true, data: filteredCards, error: undefined });
                        });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response.data });
                        console.log(response);
                    }
                );
            };

            this.deleteCardById = function (params, callback) {
                $http({
                    method: "DELETE",
                    url: params.urlPrefix + "/api/payment/creditcard/" + params.cardid,
                    headers: { "Authorization": params.token }
                }).then(
                    function (result) {
                        callback({ success: true, data: result, error: undefined });
                    },
                    function (response) {
                        callback({ success: false, data: undefined, error: response.data });
                        console.log(response);
                    }
                );
            }
        }
    ]);

})(jQuery);
(function ($) {
    "use strict";

    angular.module("app").service("shoppingCartService", [
        "localStorageService", "utilsFactory", "$http", "trackingService", function (localStorageService, utilsFactory, $http, trackingService) {
            this.utils = {
                packageLabel: utilsFactory.getLabel("checkout.details.package"),//"Package",
                packageDurationLabel: utilsFactory.getLabel("checkout.details.package-duration"),//"Duration",
                isGreaterThanMin: function (dateStr) {
                    return new Date(dateStr) > 2000;
                },
                formatDate: function (date, format) {

                    return moment(date).format(format ? format : "DD MMMM YYYY");
                },
                getStartTime: function (comp, defaultVal) {
                    return (comp.PickupLocation && comp.PickupLocation.time) ? comp.PickupLocation.time : defaultVal;
                },
                showEndDate: function (productCategory) {
                    switch (productCategory) {
                        case "Hotel":
                            return true;
                        default:
                            return false;
                    }
                },
                showFirstIfAttraction: function (productCategory, index) {
                    var isAttraction = productCategory === "Attraction";
                    return isAttraction && index === 0 || !isAttraction;
                },
                isTransportation: function (productCategory) {
                    return productCategory === "Transportation";
                },
                isTour: function (productCategory) {
                    return productCategory == "Tour";
                },
                isAttraction: function (productCategory) {
                    return productCategory == "Attraction";
                },
                isGiftComponent: function (comp) {
                    return comp && ((comp.ProductCode || "").toLowerCase().indexOf("gift") >= 0);
                },
                isFee: function (comp) {
                    return comp && (comp.productType || comp.ProductType) == "FEE";
                },
                isTimeComponent: function (comp) {
                    return comp.hasOwnProperty("IsPrimary") || (comp.productType || comp.ProductType) === "FLT-TIME";
                },
                isTransportationFirstIndex: function (component, components, index) {
                    var isTransportation = component.productCategory === "Transportation";

                    if (index === 0) {
                        return isTransportation;
                    }

                    if (index > 0) {
                        var previousComponent = components[index - 1];
                        var previousComponentIsTransportaion = previousComponent && previousComponent.productCategory === "Transportation";

                        if (isTransportation && previousComponentIsTransportaion) {
                            return component.startingLocation.code !== previousComponent.destination.code;
                        }
                    }

                    return isTransportation;
                },
                getTimeDescription: function (name) {
                    return name;
                    //var parts = (name || "").split("-");
                    //if (parts.length == 2) return parts[1].trim();
                    //return parts[0];
                },
                getTransportationProductNameFromBookingQuote: function (components, selectedComp) {

                    var mainTitle = (((selectedComp && selectedComp.ProductDescriptions && selectedComp.ProductDescriptions.titles) || '')[0] || '');
                    var resultTitle = "";

                    if (components.length > 0) {
                        var isTransportation = components[0].ProductCategory === "Transportation";
                        if (isTransportation) {
                            var firstComponent = components[0];
                            var title = (firstComponent.Name) ? firstComponent.Name : "";

                            if (title === "") {
                                if (components.length === 1) {
                                    resultTitle = firstComponent.Name;
                                    // return;
                                } else {
                                    var secondComponent = components[1];

                                    var secondTitle = (secondComponent.Name) ? secondComponent.Name : "";
                                    if (secondTitle === "") {
                                        resultTitle = firstComponent.Name;
                                        //return;
                                    } else {
                                        resultTitle = secondTitle;
                                    }
                                    //   return secondTitle;
                                }
                            } else {
                                resultTitle = title;
                                // return title;
                            }

                            if (resultTitle && mainTitle) {
                                resultTitle = mainTitle + ": " + resultTitle;
                            }
                        }
                    }

                    return resultTitle;
                },
                getTransportationProductName: function (component, components, index) {
                    var isTransportation = component.productCategory === "Transportation";

                    if (index === 0) {
                        if (components.length > 0) {
                            var nextComonent = components[index + 1];
                            var nextComponentIsTransportaion = nextComonent && nextComonent.productCategory === "Transportation";

                            if (isTransportation && nextComponentIsTransportaion) {
                                if (component.startingLocation.code === nextComonent.destination.code) {
                                    if (component.name) {
                                        return component.name;
                                    }

                                    if (nextComonent.name) {
                                        return nextComonent.name;
                                    }
                                }
                            } else {
                                return component.name;
                            }
                        }

                        return isTransportation;
                    }

                    if (index > 0) {
                        var previousComponent = components[index - 1];
                        var previousComponentIsTransportaion = previousComponent && previousComponent.productCategory === "Transportation";

                        if (isTransportation && previousComponentIsTransportaion) {
                            if (component.name) {
                                return component.name;
                            }

                            if (previousComponent.name) {
                                return previousComponent.name;
                            }
                        } else {
                            if (components.length >= index + 1) {
                                var nextComonent1 = components[index + 1];
                                var nextComponentIsTransportaion1 = nextComonent1 && nextComonent1.productCategory === "Transportation";

                                if (isTransportation && nextComponentIsTransportaion1) {
                                    if (component.startingLocation.code === nextComonent1.destination.code) {
                                        if (component.name) {
                                            return component.name;
                                        }

                                        if (nextComonent1.name) {
                                            return nextComonent1.name;
                                        }
                                    }
                                }
                            }
                        }
                    }

                    return component.name;
                },
                isHotel: function (productCategory) {
                    return productCategory === "Hotel";
                },
                getTypeLabel: function (productCategory) {
                    if (!productCategory) return utilsFactory.getLabel("checkout.details.type");

                    switch (productCategory) {
                        case "Hotel":
                            return utilsFactory.getLabel("checkout.details.hotel-room")// "Room";
                        case "Transportation":
                            return utilsFactory.getLabel("checkout.details.transportation-description")
                        default:
                            return utilsFactory.getLabel("checkout.details.type");//Type
                    }
                },
                getStartDateLabel: function (productCategory) {
                    switch (productCategory) {
                        case "Hotel":
                            return utilsFactory.getLabel("checkout.details.hotel-start-date")// "Check-in";
                        default:
                            return utilsFactory.getLabel("checkout.details.date");
                    }
                },
                getStartTimeLabel: function (productCategory) {
                    switch (productCategory) {
                        default:
                            return utilsFactory.getLabel("checkout.details.time");// "Time";
                    }
                },
                getEndDateLabel: function (productCategory) {
                    switch (productCategory) {
                        case "Hotel":
                            return utilsFactory.getLabel("checkout.details.hotel-end-date")// "Check-out";
                        default:
                            return utilsFactory.getLabel("checkout.details.date");
                    }
                },
                getEndTimeLabel: function (productCategory) {
                    switch (productCategory) {
                        default:
                            return utilsFactory.getLabel("checkout.details.time");// "Time";
                    }
                },
                formatPrice: function (price) {
                    return parseFloat(price).toFixed(2);
                },
                getPhrase: function (unitCount, unitDesc, productCategory, productType, compName) {
                    var countLabels = (utilsFactory.getLabel("checkout.details.capacity", true) || {});

                    // debugger;
                    var unitDescription = ["", ""];
                    if (productType != "SPA") {
                        switch (productCategory) {
                            case "Transportation":
                                unitDescription = ["passenger", "passengers"];
                                break;
                            case "Attraction":
                            case "Tour":
                                unitDescription = ["ticket", "tickets"];
                                break;
                            case "Hotel":
                                unitDescription = ["guest", "guests"];
                                break;
                        }
                    }
                    var result = "";
                    try {
                        var count = parseInt(unitCount);
                        if (count > 1) {
                            result = unitDescription[1] ? countLabels[unitDesc + "." + unitDescription[1]].replace("{0}", count) : countLabels[unitDesc].replace("{0}", count);
                            // return count + " " + unitDesc + " " + unitDescription[1];
                        } else if (count === 1) {
                            result = unitDescription[0] ? countLabels[unitDesc + "." + unitDescription[0]] : countLabels[unitDesc];;
                            //return "1 " + unitDesc + " " + unitDescription[0];
                        }
                    } catch (e) { }
                    return result;
                },
                getPassesCountPhrase: function (count) {
                    return utilsFactory.getLabel("checkout.details.numberOfPasses").replace("{0}", count);
                },
                getDurationCountPhrase: function (count) {
                    return utilsFactory.getLabel("checkout.details.durationHours").replace("{0}", count);
                },
                getAdutsPhrase: function (adultsCount, productCategory, productType, compName) {
                    var isSpa = productType == "SPA";
                    var expr = adultsCount > 1 && (!productCategory || isSpa) ? "adults" : "adult";
                    return this.getPhrase(adultsCount, expr, productCategory, productType, compName);
                },
                getChildrenPhrase: function (childCount, productCategory, productType, compName) {
                    var isSpa = productType == "SPA";
                    var expr = childCount > 1 && (!productCategory || isSpa) ? "children" : "child";
                    if (isSpa) {
                        expr = childCount > 1 ? "child.youths" : "child.youth";
                    }
                    return this.getPhrase(childCount, expr, productCategory, productType, compName);
                },
                getSeniorsPhrase: function (seniorsCount, productCategory, productType, compName) {
                    var isSpa = productType == "SPA";
                    var expr = seniorsCount > 1 && (!productCategory || isSpa) ? "seniors" : "senior";
                    return this.getPhrase(seniorsCount, expr, productCategory, productType, compName);
                },
                getStudentsPhrase: function (studentsCount, productCategory, productType, compName) {
                    var isSpa = productType == "SPA";
                    var expr = studentsCount > 1 && (!productCategory || isSpa) ? "students" : "student";
                    return this.getPhrase(studentsCount, expr, productCategory, productType, compName);
                },
                getInfantPhrase: function (infantsCount, productCategory, productType, compName) {
                    var isSpa = productType == "SPA";
                    var expr = infantsCount > 1 && (!productCategory || isSpa) ? "infants" : "infant";
                    return this.getPhrase(infantsCount, expr, productCategory, productType, compName);
                },
                //
                getPromoCodes: function (cart) {
                    var codes = "";
                    if (cart && cart.DiscountCodes) {
                        for (var i = 0; i < cart.DiscountCodes.length; i++) {
                            if (i === 0) {
                                codes += cart.DiscountCodes[i];
                            } else {
                                codes += ", " + cart.DiscountCodes[i];
                            }
                        }
                    }

                    return codes;
                },
                test: function (comp, item) {
                    debugger;
                },
                setEnhancePageVisited: function (reset) {
                    return localStorageService.isSupported && localStorageService.set("wasEnhancePageVisited", !reset);
                },
                getEnhancePageVisited: function () {
                    return localStorageService.isSupported && localStorageService.get("wasEnhancePageVisited");
                },
                getAfterAddToCartPageUrl: function (selectedGeographyCode, isEnhanceBookingPageEnabled) {
                    var wasEnhancePageVisited = this.getEnhancePageVisited();

                    if (!isEnhanceBookingPageEnabled || wasEnhancePageVisited) {
                        return (selectedGeographyCode ? "/" + selectedGeographyCode : "") + "/checkout";
                    }

                    return (selectedGeographyCode ? "/" + selectedGeographyCode : "") + "/enhance";
                }
            };

            this.getDateFormat = function () {
                return "MM/DD/YYYY";
            };
            this.getHotelsDateFormat = function () {
                return "MMM D, YYYY";
            };

            this.removeAllStoredData = function () {
                if (localStorageService.isSupported) {
                    localStorageService.remove("shoppingCart");
                    localStorageService.remove("bookingOrder");
                    localStorageService.remove("wasEnhancePageVisited");
                }
            };

            this.attachSecondaryComponents = function (cart) {

                if (!cart || !cart.Items || cart.isAttachProcessed) return;

                var utils = this.utils;

                _.each(cart.Items, function (item) {
                    if (item.BookingToQuote) {
                        //reset cotrol fields
                        _.each(item.BookingToQuote.Components, function (it) {
                            it.isAttachedToParent = false;
                            it.attachedTimeComponents = [];
                            it.attachedRequiredComponents = [];
                        });

                        _.each(item.BookingToQuote.Packages, function (it) {
                            if (!it.Components) return;
                            var pckDate = moment(it.StartDate);
                            _.each(it.Components, function (pComp) {
                                pComp.attachedTimeComponents = [];
                                pComp.attachedRequiredComponents = [];
                                pComp.sameDateAsParent = moment(pComp.StartDate).isSame(pckDate); // for hotels since they don't have time component
                            });
                        });
                        //end reset fields
                        //debugger;
                        _.each(item.BookingToQuote.Components, function (attachComp) {
                            if (attachComp.isAttachedToParent) return;

                            var attachCompDate = attachComp.StartDate;
                            _.each(item.BookingToQuote.Packages, function (pck) {
                                var pckDate = moment(pck.StartDate);
                                _.each(pck.Components, function (pckComp) {
                                    // when handspecialproducts returns a new booking, it can contain added packages
                                    if (attachComp.ParentCode && attachComp.ParentCode == pckComp.ProductCode) {//!attachComp.isAttachedToParent && //&& attachComp.ProductCode.indexOf(pckComp.ProductCode) >= 0) {
                                        if (utils.isTimeComponent(attachComp)) {
                                            pckComp.attachedTimeComponents = pckComp.attachedTimeComponents || [];
                                            pckComp.attachedTimeComponents.push(attachComp);
                                        } else {
                                            pckComp.attachedRequiredComponents = pckComp.attachedRequiredComponents || [];
                                            pckComp.attachedRequiredComponents.push(attachComp);
                                        }
                                        attachComp.isAttachedToParent = true;
                                        attachComp.sameDateAsParent = moment(attachCompDate).isSame(pckDate);
                                        return;
                                    }
                                });
                                //if (attachComp.isAttachedToParent) return;
                            });

                            if (attachComp.isAttachedToParent) return;
                            _.each(item.BookingToQuote.Components, function (comp) {
                                if (utils.isTimeComponent(comp)) return;
                                if (!attachComp.isAttachedToParent && attachComp.ParentCode && attachComp.ParentCode == comp.ProductCode) {//attachComp.ProductCode.indexOf(comp.ProductCode) >= 0) {
                                    if (utils.isTimeComponent(attachComp)) {
                                        comp.attachedTimeComponents = comp.attachedTimeComponents || [];
                                        comp.attachedTimeComponents.push(attachComp);
                                    } else {
                                        comp.attachedRequiredComponents = comp.attachedRequiredComponents || [];
                                        comp.attachedRequiredComponents.push(attachComp);
                                    }
                                    attachComp.isAttachedToParent = true;
                                    attachComp.sameDateAsParent = moment(attachCompDate).isSame(moment(comp.StartDate));
                                    return;
                                }
                            });
                        });
                    }
                });
                cart.isAttachProcessed = true;
            };

            this.getStorageCart = function (callback) {
                if (localStorageService.isSupported) {
                    var cart = localStorageService.get("shoppingCart");
                    if (cart && cart.expire) {
                        var date = new Date(cart.expire);
                        var today = new Date();
                        if (date.getDate() !== today.getDate() || date.getMonth() !== today.getMonth() || date.getFullYear() !== today.getFullYear()) {
                            localStorageService.remove("shoppingCart");
                            localStorageService.remove("wasEnhancePageVisited");
                            cart = null;
                        }
                    } else {
                        localStorageService.remove("shoppingCart");
                        localStorageService.remove("wasEnhancePageVisited");
                        cart = null;
                    }

                    this.attachSecondaryComponents(cart);
                    if (callback) {
                        callback(cart);
                    } else {
                        return cart;
                    }

                }
                return null;
            };

            this.setStorageCart = function (cartObject, callback) {
                cartObject.isAttachProcessed = false;
                if (localStorageService.isSupported) {
                    var subTotal = 0;
                    cartObject.FeesTotal = 0;

                    if (cartObject.Quote && cartObject.Quote.Components) {
                        _.map(cartObject.Quote.Components, function (quoteComponent) {
                            // debugger;
                            if (quoteComponent.IsFee && !quoteComponent.ShowInCart && !quoteComponent.IsShippingItem && !quoteComponent.IsWrappingItem) {
                                cartObject.FeesTotal += quoteComponent.Price;
                            } else {
                                subTotal += quoteComponent.PriceWithoutDiscounts || quoteComponent.Price;
                            }
                        });
                    }

                    if (cartObject.Quote && cartObject.Quote.Packages) {
                        _.map(cartObject.Quote.Packages, function (pkg) {
                            subTotal += pkg.Price;
                        });
                    }

                    cartObject.Subtotal = subTotal.toFixed(2);

                    if (cartObject.Quote && (cartObject.Quote.PriceWithoutDiscounts || cartObject.Quote.Price)) {
                        if (cartObject.Quote.TotalTaxes) {
                            cartObject.Taxes = cartObject.Quote.TotalTaxes;
                        } else {
                            cartObject.Taxes = ((cartObject.Quote.PriceWithoutDiscounts || cartObject.Quote.Price) - subTotal).toFixed(2);
                        }
                        //cartObject.Taxes += feesTotal || 0;
                    }
                    var expireDate = new Date();
                    cartObject.expire = expireDate;

                    this.attachSecondaryComponents(cartObject);
                    localStorageService.set("shoppingCart", cartObject);

                    if (callback != null) {
                        callback(localStorageService.get("shoppingCart"));
                    }
                }
            };

            this.updateQuote = function (url, token, bookingQuoteToPost, currentCart, callback) {
                var shoppingCartService = this;
                currentCart.isAttachProcessed = false;
                if (currentCart.Items && currentCart.Items.length > 0) {
                    _.map(currentCart.Items, function (item) {
                        if (item.BookingToQuote && item.BookingToQuote.Components) {
                            _.map(item.BookingToQuote.Components, function (component) {
                                bookingQuoteToPost.BookingToQuote.Components.push(component);
                            });
                        }
                        if (item.BookingToQuote && item.BookingToQuote.Packages) {
                            _.map(item.BookingToQuote.Packages, function (pkg) {
                                bookingQuoteToPost.BookingToQuote.Packages.push(pkg);
                            });
                        }
                    });

                    //                  
                    if (currentCart && currentCart.UpdatedBooking && currentCart.UpdatedBooking.bookingId
                        && !bookingQuoteToPost.BookingToQuote.BookingId
                    ) {
                        bookingQuoteToPost.BookingToQuote.BookingId = currentCart.UpdatedBooking.bookingId;
                    }

                    if (currentCart && currentCart.UpdatedBooking && currentCart.UpdatedBooking.bookingNumber
                        && !bookingQuoteToPost.BookingToQuote.BookingNumber
                    ) {
                        bookingQuoteToPost.BookingToQuote.BookingNumber = currentCart.UpdatedBooking.bookingNumber;
                    }

                    if (currentCart && currentCart.UpdatedBooking && currentCart.UpdatedBooking.customers
                        && !(bookingQuoteToPost.BookingToQuote.Customers||"").length
                    ) {
                        bookingQuoteToPost.BookingToQuote.Customers = currentCart.UpdatedBooking.customers;
                    }
                    //

                    var self = this;
                    $http({
                        method: "POST",
                        url: url,
                        headers: {
                            "Authorization": token,
                            "Content-Type": "application/json"
                        },
                        data: bookingQuoteToPost
                    }).then(
                        function (result) {
                            currentCart.Quote = result.data.Quote;
                            self.mergeCartQuotes(currentCart);

                            currentCart.DiscountCodes = _.map(currentCart.Quote && currentCart.Quote.Discounts, function (item) { return item && item.DiscountCode; }) || [];
                            //if (bookingQuoteToPost.BookingToQuote.DiscountCodes && bookingQuoteToPost.BookingToQuote.DiscountCodes.length > 0) {
                            //    currentCart.DiscountCodes = bookingQuoteToPost.BookingToQuote.DiscountCodes;
                            //} else {
                            //    currentCart.DiscountCodes = [];
                            //}

                            shoppingCartService.setStorageCart(currentCart);

                            callback(currentCart);
                        },
                        function (response) {
                            shoppingCartService.setStorageCart(shoppingCartService.getEmptyCart(), null);
                            callback(shoppingCartService.getEmptyCart());
                        }
                    );

                } else {
                    currentCart.DiscountCodes = [];
                    shoppingCartService.setStorageCart(currentCart);
                    callback(currentCart);
                }
            };

            this.updateCartComponents = function (requestParams, callback) {
                var currentCart = this.getCurrentCart();


                //var indexes = this.getQuoteIndexes(currentCart, requestParams.index, requestParams.isPackage);

                if (currentCart && currentCart.Items && currentCart.Items.length > 0 && currentCart.Quote) {

                    var exItemById = currentCart.Items[requestParams.index];
                    var newQuoteComponents = [];

                    //var excIndex = [];

                    //if (exItemById) {
                    //    excIndex = exItemById.quoteIndex;
                    //}

                    //currentCart.Items.splice(requestParams.index, 1);

                    //for (var j = 0; j < currentCart.Quote.Components.length; j++) {
                    //    if (excIndex.indexOf(j) < 0)
                    //        newQuoteComponents.push(currentCart.Quote.Components[j]);
                    //    //currentCart.Quote.Components.splice(indexes.startIndex, 1);
                    //}

                    if (requestParams.productCode || requestParams.removeAllShippingAndWrappings) {

                        var removeItems = _.filter(currentCart.Items, function (ci) {
                            var toRemove = exItemById == ci;
                            if (toRemove)
                                return toRemove;

                            if (requestParams.removeAllShippingAndWrappings) {
                                toRemove = ci.isWrappingItem || ci.isShippingItem;
                            }

                            return toRemove || (requestParams.productCode && ci.relatedProductCode == requestParams.productCode);
                        });

                        _.each(removeItems, function (exItem) {
                            var excIndex = [];
                            if (exItem) {
                                excIndex = exItem.quoteIndex;
                            }
                            var rindex = _.findIndex(currentCart.Items, function (ci) { return (ci.ProductCode == exItem.productCode || ci.ProductCode == exItem.ProductCode) && ci.UnitCode == exItem.UnitCode; });
                            if (rindex >= 0) {
                                currentCart.Items.splice(rindex, 1);
                            }

                            for (var j = 0; j < currentCart.Quote.Components.length; j++) {
                                if (excIndex.indexOf(j) < 0)
                                    newQuoteComponents.push(currentCart.Quote.Components[j]);
                            }
                        });
                    } else {
                        var excIndex = [];
                        if (exItemById) {
                            excIndex = exItemById.quoteIndex;
                        }

                        if (requestParams.index >= 0) {
                            currentCart.Items.splice(requestParams.index, 1);
                        }


                        for (var j = 0; j < currentCart.Quote.Components.length; j++) {
                            if (excIndex.indexOf(j) < 0)
                                newQuoteComponents.push(currentCart.Quote.Components[j]);
                            //currentCart.Quote.Components.splice(indexes.startIndex, 1);
                        }
                    }

                    currentCart.Quote.Components = newQuoteComponents;
                }

                if (requestParams.skipQuote) {
                    callback && callback(currentCart);
                    return;
                }

                var bookingQuoteToPost = {
                    BookingToQuote: {
                        Components: [],
                        Packages: [],
                        DiscountCodes: currentCart.DiscountCodes
                    }
                };

                this.updateQuote(requestParams.apiUrl + "/api/booking/quote/", requestParams.token, bookingQuoteToPost, currentCart, callback);
            };

            this.applyPromoCode = function (requestParams, callback) {
                var currentCart = this.getCurrentCart();

                if (!(currentCart.DiscountCodes || "").length) {
                    currentCart.DiscountCodes = [requestParams.promoCode];
                } else {
                    var foundCode = _.find(currentCart.DiscountCodes, function (discountCode) {
                        return discountCode === requestParams.promoCode;
                    });

                    if (!foundCode) {
                        currentCart.DiscountCodes.push(requestParams.promoCode);
                    }
                }

                var bookingQuoteToPost = {
                    BookingToQuote: { Components: [], Packages: [], DiscountCodes: currentCart.DiscountCodes }
                };

                this.updateQuote(requestParams.apiUrl + "/api/booking/quote/", requestParams.token, bookingQuoteToPost, currentCart, callback);
            };

            this.refreshPromoCodesQuote = function (requestParams, callback) {

                var currentCart = this.getCurrentCart();
                currentCart.DiscountCodes = requestParams.promoCodes;


                var bookingQuoteToPost = {
                    BookingToQuote: { Components: [], Packages: [], DiscountCodes: currentCart.DiscountCodes }
                };

                this.updateQuote(requestParams.apiUrl + "/api/booking/quote/", requestParams.token, bookingQuoteToPost, currentCart, callback);
            };

            this.refreshQuote = function (requestParams, callback) {
                var currentCart = this.getCurrentCart();
                var bookingQuoteToPost = {
                    BookingToQuote: { Components: [], Packages: [], DiscountCodes: [] }
                };

                if (requestParams.includeDiscountCodes) {
                    bookingQuoteToPost.BookingToQuote.DiscountCodes = currentCart.DiscountCodes;
                }

                this.updateQuote(requestParams.apiUrl + "/api/booking/quote/", requestParams.token, bookingQuoteToPost, currentCart, callback);
            };

            this.parsePriceBreakdown = function (priceBreakdownList) {
                var service = this;

                if (!(priceBreakdownList || "").length) return priceBreakdownList;
                _.each(priceBreakdownList, function (pb) {
                    if (pb && pb.Summary) {
                        var momentObj = moment(pb.Summary);
                        if (momentObj.isValid()) {
                            pb.ParsedSummary = service.utils.formatDate(momentObj);
                        }
                    }
                });
                return priceBreakdownList;
            };
            this.mergeCartQuotes = function (currentCart) {
                var utils = this;
                if (currentCart && currentCart.Items && currentCart.Items.length > 0 &&
                    currentCart.Quote && ((currentCart.Quote.Components || "").length ||
                        ((currentCart.Quote.Packages || "").length))) {

                    // map quote order 
                    var qm = Object.create(null);
                    var i = 0;
                    _.map(currentCart.Quote.Components, function (item) {
                        var mapId = item.ProductCode + (item.UnitCode ? item.UnitCode : "");

                        if (mapId in qm) {
                            qm[mapId].push({ item: item, priceIncludingTaxes: item.PriceIncludingTaxes, price: item.PriceWithoutDiscounts || item.Price, index: i, priceBreakdown: utils.parsePriceBreakdown(item.PriceBreakdown) });
                        } else {
                            qm[mapId] = [{ item: item, priceIncludingTaxes: item.PriceIncludingTaxes, price: item.PriceWithoutDiscounts || item.Price, index: i, priceBreakdown: utils.parsePriceBreakdown(item.PriceBreakdown) }];
                        }
                        i++;
                    });

                    var j = 0;
                    var pm = Object.create(null);
                    var packIndex = -1;
                    _.map(currentCart.Quote.Packages, function (pkg) {
                        packIndex++;
                        // some packages don't have a package code
                        if (!pkg.PackageCode) {
                            pkg.PackageCode = "_p" + packIndex;
                        }

                        var mapId = pkg.PackageCode;

                        var componentsPrice = Object.create(null);
                        var pckNeedPassListCompProductCode = undefined; // package component Code that NeedFullPassengerList
                        _.each(pkg.Components, function (pcomp) {
                            if (pcomp.NeedFullPassengerList) {
                                pckNeedPassListCompProductCode = pcomp.ProductCode;
                            }
                            componentsPrice[pcomp.ProductCode + pcomp.UnitCode] = pcomp.PriceWithoutDiscounts || pcomp.Price;
                        });

                        if (mapId in pm) {
                            pm[mapId].push({ pkg: pkg, price: pkg.Price, priceIncludingTaxes: pkg.PriceIncludingTaxes, priceBreakdown: utils.parsePriceBreakdown(pkg.PriceBreakdown), needFullPassengerList: pkg.NeedFullPassengerList, pckNeedPassListCompProductCode: pckNeedPassListCompProductCode, index: j, componentsPrice: componentsPrice });
                        } else {
                            pm[mapId] = [{ pkg: pkg, price: pkg.Price, priceIncludingTaxes: pkg.PriceIncludingTaxes, priceBreakdown: utils.parsePriceBreakdown(pkg.PriceBreakdown), needFullPassengerList: pkg.NeedFullPassengerList, pckNeedPassListCompProductCode: pckNeedPassListCompProductCode, index: j, componentsPrice: componentsPrice }];
                        }
                        j++;
                    });

                    var itemIndexes = Object.create(null);

                    _.map(currentCart.Items, function (item) {
                        if (item.BookingToQuote &&
                            ((item.BookingToQuote.Components || "").length ||
                                ((item.BookingToQuote.Packages || "").length))) {
                            var quoteIndex = [];
                            var itemPrice = 0;
                            var itemPriceWithTax = 0;

                            var isPkg = (item.BookingToQuote.Packages || "").length;

                            if (isPkg) {
                                var packIndex = -1;
                                _.map(item.BookingToQuote.Packages, function (pkg) {
                                    packIndex++;
                                    // some packages don't have a package code
                                    if (!pkg.PackageCode) {
                                        pkg.PackageCode = "_p" + packIndex;
                                    }

                                    var mapId = pkg.PackageCode;
                                    var qval = pm[mapId];
                                    if (qval) {
                                        var ind = (mapId in itemIndexes) ? itemIndexes[mapId] : 0;

                                        var quoteVal = ind in qval ? qval[ind] : qval[0];

                                        if (quoteVal) {
                                            itemPrice += quoteVal.price;
                                            itemPriceWithTax += quoteVal.priceIncludingTaxes;

                                            quoteIndex.push(quoteVal.index);

                                            //
                                            pkg.NeedFullPassengerList = quoteVal.needFullPassengerList;
                                            pkg.pckNeedPassListCompProductCode = quoteVal.pckNeedPassListCompProductCode;
                                            pkg.PriceBreakdown = quoteVal.priceBreakdown;
                                            pkg.Price = quoteVal.price;
                                            pkg.PriceIncludingTaxes = quoteVal.priceIncludingTaxes;

                                            //add package price component from quote
                                            if (quoteVal.componentsPrice) {
                                                _.each(pkg.Components, function (pcomp) {
                                                    pcomp.Price = quoteVal.componentsPrice[pcomp.ProductCode + pcomp.UnitCode] || 0;
                                                });
                                            }
                                            //
                                            pkg.ExpressConsentOptions = (quoteVal.pkg && quoteVal.pkg.ExpressConsentOptions);
                                        }

                                        itemIndexes[mapId] = ind + 1;

                                    }
                                });
                                //
                            }

                            _.map(item.BookingToQuote.Components, function (comp) {

                                var mapId = comp.ProductCode + (comp.UnitCode ? comp.UnitCode : "");
                                var qval = qm[mapId];
                                if (qval) {

                                    var ind = (mapId in itemIndexes) ? itemIndexes[mapId] : 0;

                                    var quoteVal = ind in qval ? qval[ind] : qval[0];

                                    if (quoteVal) {
                                        quoteVal.isAssignedToCartItem = true;

                                        quoteVal.item.IsFee = utils.utils.isFee(comp);
                                        quoteVal.item.ShowInCart = comp.ShowInCart;

                                        quoteVal.item.IsShippingItem = item.isShippingItem;
                                        quoteVal.item.IsWrappingItem = item.isWrappingItem;

                                        // debugger;

                                        if (!quoteVal.item.IsFee || item.isShippingItem || item.isWrappingItem) { // || quoteVal.item.ShowInCart
                                            itemPrice += quoteVal.price;
                                            itemPriceWithTax += quoteVal.priceIncludingTaxes;
                                        }
                                        quoteIndex.push(quoteVal.index);
                                        comp.NeedFullPassengerList = quoteVal.item.NeedFullPassengerList;
                                        comp.PriceBreakdown = quoteVal.priceBreakdown;
                                        comp.Price = quoteVal.price;
                                        comp.PriceIncludingTaxes = quoteVal.priceIncludingTaxes;

                                        //
                                        comp.ExpressConsentOptions = quoteVal.item.ExpressConsentOptions;
                                    }

                                    itemIndexes[mapId] = ind + 1;
                                }
                            });

                            item.totalCalcPrice = itemPrice;
                            item.totalCalcPriceWithTax = itemPriceWithTax;
                            item.quoteIndex = quoteIndex;
                            //add quote index to item
                            //add price
                        }

                    });
                    //
                    var unassignedQuoteComponents = [];
                    for (var key in qm) {
                        if (qm[key] && qm[key].length) {
                            _.each(qm[key], function (qVal) {
                                if (!qVal.isAssignedToCartItem && qVal.item) {
                                    unassignedQuoteComponents.push(qVal.item);
                                }
                            });
                        }
                    }
                    console.log("unassignedQuoteComponents: ", unassignedQuoteComponents);
                    currentCart.Quote.unassignedQuoteComponents = unassignedQuoteComponents;
                    //
                }

            };

            this.handleSpecialProducts = function (requestParams, callback) {
                $http({
                    method: "POST",
                    url: requestParams.apiUrl + "/api/booking/handlespecialproducts/",
                    headers: {
                        "Authorization": requestParams.token,
                        "Content-Type": "application/json"
                    },
                    data: requestParams.dataToPost
                }).then(
                    function (result) {
                        var newBooking = result && result.data && (result.data.Bookings || [null])[0];
                        if (newBooking) {
                            // keep the custom fields from the request
                            var prevBooking = requestParams.dataToPost.Booking;
                            var compDict = Object.create(null);
                            _.each(prevBooking.Components, function (prevcomp) {
                                compDict[prevcomp["Id"]] = prevcomp;
                            });

                            _.each(newBooking.Components, function (newcomp) {
                                var prevComp = compDict[newcomp["Id"]];
                                if (prevComp) {
                                    for (var reqKey in prevComp) {
                                        if (!(reqKey in newcomp)) {
                                            newcomp[reqKey] = prevComp[reqKey];
                                        }
                                    }
                                }
                            });

                            var pkgDict = Object.create(null);
                            _.each(prevBooking.Packages, function (prevPkg) {
                                pkgDict[prevPkg["PackageCode"]] = prevPkg;
                            });

                            _.each(newBooking.Packages, function (newPkg) {
                                var prevPkg = pkgDict[newPkg["PackageCode"]];
                                if (prevPkg) {
                                    for (var reqKey in prevPkg) {
                                        if (!(reqKey in newPkg)) {
                                            newPkg[reqKey] = prevPkg[reqKey];
                                        }
                                    }
                                    // set old custom fields to package components
                                    var pkgCompDict = Object.create(null);
                                    _.each(prevPkg.Components, function (prevPkgComp) {
                                        pkgCompDict[(prevPkgComp["ProductCode"] || "") + (prevPkgComp["UnitCode"] || "")] = prevPkgComp;
                                    });
                                    //
                                    _.each(newPkg.Components, function (newPkgComp) {
                                        var prevPkgComp = pkgCompDict[(newPkgComp["ProductCode"] || "") + (newPkgComp["UnitCode"] || "")];
                                        if (prevPkgComp) {
                                            for (var reqKey in prevPkgComp) {
                                                if (!(reqKey in newPkgComp)) {
                                                    newPkgComp[reqKey] = prevPkgComp[reqKey];
                                                }
                                            }
                                        }
                                    });
                                    //
                                }
                            });

                            for (var reqKey in prevBooking) {
                                if (!(reqKey in newBooking)) {
                                    newBooking[reqKey] = prevBooking[reqKey];
                                }
                            }
                        }

                        if (callback) {
                            callback(newBooking);
                        }
                    },
                    function (response) {
                        if (callback) {
                            callback(null);
                        }
                    }
                );
            };

            this.updateNewCart = function (requestParams, callback) {
                var currentCart = this.getEmptyCart();
                currentCart.isUpdate = true;
                currentCart.updateBookingUrl = requestParams.updateBookingUrl;
                currentCart.DiscountCodes = (requestParams.booking && requestParams.booking.discountCodes) || [];
                currentCart.Items = requestParams.items;
                currentCart.UpdatedBooking = requestParams.booking;
                //this.setStorageCart(currentCart);

                var bookingToQuoteRequestObj = {
                    BookingId: requestParams.booking && requestParams.booking.bookingId,
                    BookingNumber: requestParams.booking && requestParams.booking.bookingNumber, 
                    Components: [],
                    Packages: [],
                    DiscountCodes: currentCart.DiscountCodes
                };

                //
                if (requestParams.booking && requestParams.booking.customers) {
                    bookingToQuoteRequestObj.Customers = requestParams.booking.customers;
                }
                //

                var bookingQuoteToPost = {
                    BookingToQuote: bookingToQuoteRequestObj,
                    QuoteIsForBookingModification: true
                };

                _.map(currentCart.Items, function (item) {
                    if (item.BookingToQuote && item.BookingToQuote.Components) {
                        _.map(item.BookingToQuote.Components, function (component) {
                            bookingQuoteToPost.BookingToQuote.Components.push(component);
                        });
                    }
                    if (item.BookingToQuote && item.BookingToQuote.Packages) {
                        _.map(item.BookingToQuote.Packages, function (pkg) {
                            bookingQuoteToPost.BookingToQuote.Packages.push(pkg);
                        });
                    }
                });


                var shoppingCartService = this;

                $http({
                    method: "POST",
                    url: requestParams.apiUrl + "/api/booking/quote/",
                    headers: {
                        "Authorization": requestParams.token,
                        "Content-Type": "application/json"
                    },
                    data: bookingQuoteToPost
                }).then(
                    function (result) {
                        currentCart.Quote = result.data.Quote;
                        shoppingCartService.mergeCartQuotes(currentCart);
                        shoppingCartService.setStorageCart(currentCart);
                        if (callback) {
                            callback(result);
                        }
                    },
                    function (response) {
                        if (callback) {
                            callback(undefined, response);
                        }
                    }
                );
            };
            this.quoteComponents = function (requestParams, callback) {
                var currentCart = this.getCurrentCart();
                if (currentCart.isUpdate) {
                    currentCart = this.getEmptyCart();
                }
                currentCart.optionalExtras = [];
                var addedItems = 0;
                if (requestParams.dataToPost &&
                    requestParams.dataToPost.BookingToQuote &&
                    (requestParams.dataToPost.BookingToQuote.Components ||
                        requestParams.dataToPost.BookingToQuote.Packages)
                ) {
                    var updateExistingCartItem = null; // for gift tickets, we need to group cart items that have the same product code & unit code into 1 item, because of the quote api result

                    var firstRequestComp = requestParams.dataToPost.BookingToQuote.Components && requestParams.dataToPost.BookingToQuote.Components[0];

                    if (firstRequestComp && firstRequestComp.IsGiftTicket) {

                        updateExistingCartItem = _.find(currentCart.Items, function (currItem) {
                            // currItem.StartDateChk == firstRequestComp.StartDate &&
                            return currItem.ProductCode == firstRequestComp.ProductCode && currItem.UnitCode == firstRequestComp.UnitCode;
                        });
                    }

                    if (updateExistingCartItem && (updateExistingCartItem.BookingToQuote.Components || "").length) {
                        updateExistingCartItem.BookingToQuote.Components[0].NumberOfAdults += firstRequestComp.NumberOfAdults;
                        updateExistingCartItem.BookingToQuote.Components[0].NumberOfChildren += firstRequestComp.NumberOfChildren;
                        // updateExistingCartItem.BookingToQuote.Components[0].NumberOfUnits += firstRequestComp.NumberOfUnits;
                    } else {
                        var item = {
                            ProductCode: undefined,
                            ProductCategory: undefined,
                            UnitCode: undefined,
                            StartDate: undefined,
                            StartTime: undefined,
                            EndDate: undefined,
                            EndTime: undefined,
                            BookingToQuote: {
                                Components: [],
                                Packages: []
                            },
                            relatedProductCode: undefined,
                            hideItemInCart: requestParams.hideItemInCart,
                            isShippingItem: requestParams.isShippingItem,
                            isWrappingItem: requestParams.isWrappingItem,
                        };

                        _.map(requestParams.dataToPost.BookingToQuote.Components, function (component, index) {
                            if (index === 0) {
                                item.ProductCode = component.ProductCode;
                                item.ProductCategory = component.ProductCategory;
                                item.UnitCode = component.UnitCode;
                                item.StartDateChk = component.StartDate;

                                item.StartDate = requestParams.startDate;
                                item.StartTime = requestParams.startTime;
                                item.EndDate = requestParams.endDate;
                                item.EndTime = requestParams.endTime;
                                item.relatedProductCode = requestParams.relatedProductCode;
                            }
                            component.origPrice = component.Price;
                            item.BookingToQuote.Components.push(component);
                        });

                        _.map(requestParams.dataToPost.BookingToQuote.Packages, function (pkg, index) {
                            item.BookingToQuote.Packages.push(pkg);
                        });
                        currentCart.Items.push(item);
                    }

                    addedItems++;

                }

                //this.setStorageCart(currentCart);

                var bookingQuoteToPost = {
                    BookingToQuote: {                     
                        Components: [],
                        Packages: [],
                        DiscountCodes: currentCart.DiscountCodes
                    }
                };

                //              
                if (requestParams.dataToPost.BookingToQuote.BookingId) {
                    bookingQuoteToPost.BookingToQuote.BookingId = requestParams.dataToPost.BookingToQuote.BookingId;
                }
                if (requestParams.dataToPost.BookingToQuote.BookingNumber) {
                    bookingQuoteToPost.BookingToQuote.BookingNumber = requestParams.dataToPost.BookingToQuote.BookingNumber;
                }
                //
                if (requestParams.dataToPost.BookingToQuote.Customers) {
                    bookingQuoteToPost.BookingToQuote.Customers = requestParams.dataToPost.BookingToQuote.Customers;
                }
                //
                _.map(currentCart.Items, function (item) {
                    if (item.BookingToQuote && item.BookingToQuote.Components) {
                        _.map(item.BookingToQuote.Components, function (component) {
                            bookingQuoteToPost.BookingToQuote.Components.push(component);
                        });
                    }
                    if (item.BookingToQuote && item.BookingToQuote.Packages) {
                        _.map(item.BookingToQuote.Packages, function (pkg) {
                            bookingQuoteToPost.BookingToQuote.Packages.push(pkg);
                        });
                    }
                });


                var shoppingCartService = this;

                $http({
                    method: "POST",
                    url: requestParams.apiUrl + "/api/booking/quote/",
                    headers: {
                        "Authorization": requestParams.token,
                        "Content-Type": "application/json"
                    },
                    data: bookingQuoteToPost
                }).then(
                    function (result) {
                        if (callback) {
                            callback({ quote: result.data.Quote, shoppingCart: currentCart, addedItems: addedItems });
                        }
                    },
                    function (response) {
                        if (callback) {
                            callback(undefined, response);
                        }
                    }
                );
            };

            this.addQuotedDataToCart = function (data, callback) {
                if (!data || !data.quote || !data.shoppingCart) callback && callback();
                var shoppingCartService = this;
                var currentCart = data.shoppingCart;

                currentCart.Quote = data.quote;

                if (data.lastAddedItemDetails) {
                    currentCart.lastAddedItemDetails = data.lastAddedItemDetails;
                }

                shoppingCartService.mergeCartQuotes(currentCart);
                shoppingCartService.setStorageCart(currentCart);
                callback && callback(data.addedItems);
            };

            this.addComponentsToCart = function (requestParams, callback) {
                var shoppingCartService = this;
                this.quoteComponents(requestParams, function (quoteResult) {
                    if (!quoteResult) return callback && callback();
                    quoteResult.lastAddedItemDetails = requestParams.lastAddedItemDetails;

                    shoppingCartService.addQuotedDataToCart(quoteResult, callback);
                });
            };

            this.getCurrentCart = function () {
                var cart = this.getStorageCart(null);

                if (!cart) {
                    cart = this.getEmptyCart();
                }

                return cart;
            };

            this.getEmptyCart = function () {
                var cart = {
                    Items: [],
                    Quote: [],
                    DiscountCodes: [],
                    Subtotal: 0,
                    Taxes: 0,
                    Cards: []
                };
                return cart;
            };

            //not using
            this.getQuoteIndexes = function (cart, index, isPackage) {
                var quoteStartInxed = 0;
                var quoteEndInxed = 0;

                if (index > 0) {
                    for (var i = 0; i < index; i++) {
                        var cartItem = cart.Items[i];
                        if (cartItem && cartItem.BookingToQuote &&
                            (isPackage ? cartItem.BookingToQuote.Packages : cartItem.BookingToQuote.Components)) {
                            quoteStartInxed += (isPackage ? cartItem.BookingToQuote.Packages : cartItem.BookingToQuote.Components).length;
                        }
                    }
                }

                var currentCartItem = cart.Items[index];
                if (currentCartItem && currentCartItem.BookingToQuote && isPackage ? currentCartItem.BookingToQuote.Packages : currentCartItem.BookingToQuote.Components) {
                    quoteEndInxed = quoteStartInxed + ((isPackage ? currentCartItem.BookingToQuote.Packages : currentCartItem.BookingToQuote.Components).length - 1);
                }

                return {
                    startIndex: quoteStartInxed,
                    endIndex: quoteEndInxed
                };
            };

            this.updateComponent = function (current, copy) {
                current.Id = copy.Id;
                if (copy.MappingId) {
                    current.MappingId = copy.MappingId;
                }
                current.ProductCategory = copy.ProductCategory;
                current.ProductType = copy.ProductType;
                current.ProductCode = copy.ProductCode;
                current.StartDate = copy.StartDate;
                current.EndDate = copy.EndDate;
                current.Name = copy.Name;
                current.Description = copy.Description;
                current.Price = copy.Price;
                current.ChildPrice = copy.ChildPrice;
                current.NumberOfAdults = copy.NumberOfAdults;
                current.NumberOfChildren = copy.NumberOfChildren;
                current.NumberOfInfants = copy.NumberOfInfants;
                current.Status = copy.Status;
                current.UnitCode = copy.UnitCode;
                current.UnitDescription = copy.UnitDescription;
                current.PickupLocation = copy.PickupLocation;
                current.DropoffLocation = copy.DropoffLocation;
                current.StartingLocation = copy.StartingLocation;
                current.Destination = copy.Destination;
                current.Remarks = copy.Remarks;

                return current;
            };

            this.createBooking = function (requestParams, callback) {

                $http({
                    method: "POST",
                    url: requestParams.apiUrl,
                    headers: {
                        "Authorization": requestParams.token,
                        "Segment-Anonymous-Id": trackingService.getSegmentUserId(),
                        "Content-Type": "application/json"
                    },
                    data: requestParams.bookingToPost
                }).then(
                    function (result) {
                        if (result.data) {
                            callback(result.data);
                        } else {
                            callback(null);
                        }
                    },
                    function (request, status, error) {

                        callback(error && error.data || request && request.data);

                        //if (error && error.data) {
                        //    callback(error.data);
                        //} else {
                        //    callback(null);
                        //}

                        console.log(error);
                    }
                );
            };

            this.setBooking = function (bookingObj, email, callback) {
                if (localStorageService.isSupported) {
                    var bookingWithCart = {
                        bookings: bookingObj,
                        email: email,
                        shoppingCart: this.getStorageCart(null)
                    };
                    var expireDate = new Date();
                    bookingWithCart.expire = expireDate;
                    localStorageService.set("bookingOrder", bookingWithCart);

                    this.setStorageCart(this.getEmptyCart(), null);

                    if (callback) {
                        callback(localStorageService.get("bookingOrder"));
                    }
                } else {
                    if (callback) {
                        callback(null);
                    }
                }
            };

            this.getBooking = function (callback) {
                if (localStorageService.isSupported) {
                    var bookingObj = localStorageService.get("bookingOrder");
                    if (bookingObj && bookingObj.expire) {
                        var date = new Date(bookingObj.expire);
                        var today = new Date();
                        if (date.getDate() !== today.getDate() || date.getMonth() !== today.getMonth() || date.getFullYear() !== today.getFullYear()) {
                            localStorageService.remove("bookingOrder");
                            bookingObj = null;
                        }
                    } else {
                        localStorageService.remove("bookingOrder");
                        bookingObj = null;
                    }

                    if (callback) {
                        callback(bookingObj);
                    } else {
                        return bookingObj;
                    }
                } else {
                    if (callback) {
                        callback(null);
                    } else {
                        return null;
                    }
                }

                return null;
            };

            this.getHotelsComponents = function (cart, callback) {
                if (cart) {
                    if (cart.Items) {
                        var hotels = [];
                        _.each(cart.Items, function (cartItem) {
                            var pkg = cartItem.BookingToQuote.Packages ? cartItem.BookingToQuote.Packages[0] : undefined;
                            if (pkg) {
                                _.each(pkg.Components, function (packageComponent) {
                                    if ((packageComponent.ProductCategory || "").toLowerCase() === "hotel") {
                                        packageComponent.isPackageComponent = true;
                                        hotels.push(packageComponent);
                                    }
                                });
                            }
                            else
                                if ((cartItem.ProductCategory || "").toLowerCase() === "hotel") {
                                    hotels.push(cartItem);
                                }
                        });

                        if (hotels.length) {
                            if (callback) {
                                callback(hotels);
                            } else {
                                return hotels;
                            }

                        } else {
                            if (callback) {
                                callback(undefined);
                            } else {
                                return undefined;
                            }
                        }
                    }
                } else {
                    if (callback) {
                        callback(undefined);
                    } else {
                        return undefined;
                    }
                }
            };

            this.setExternalPromoCode = function (promoCode) {
                if (localStorageService.isSupported) {
                    if (promoCode) {
                        localStorageService.set("externalPromoCode", promoCode);
                    } else {
                        localStorageService.remove("externalPromoCode");
                    }
                }
            };

            this.getExternalPromoCode = function () {
                if (localStorageService.isSupported) {
                    return localStorageService.get("externalPromoCode");
                }
                return null;
            };

        }
    ]);

})(jQuery);
(function ($) {
    "use strict";

    angular.module("app").service("tempusPaymentService", ["localStorageService", "$http", "$httpParamSerializerJQLike", "$sce", function (localStorageService, $http, $httpParamSerializerJQLike, $sce) {
        var absoluteUrl = jQuery("body").data("weburl") ? jQuery("body").data("weburl") : "";
        //var urlBase = absoluteUrl + '/api/product';

        this.getTempusIframeUrl = function (params, callback) {
            var region = params.region || "BJC";


            var tempusCallbackUrl = $("body").data("tempus-callback-url");

            $http({
                method: "POST",
                url: absoluteUrl + "/api/paymenttempus/initiframesession",
                data: {
                    pursuitBusinessId: region.toUpperCase(),
                    callbackUrl: tempusCallbackUrl
                }
            }).then(
                function (res) {
                    console.log("getTempusIframeUrl:", res);
                    callback({ success: true, data: res&&res.data, error: undefined });
                },
                function (res) {
                    console.log("getTempusIframeUrl error:", res)
                    callback({ success: false, data: undefined, error: res });                  
                });
        };

        this.getCountryCodeByName = function (countryName, countries) {
            var contryCode = null;

            for (var i = 0; i < countries.length; i++) {
                if (countries[i].name.toLowerCase() === countryName.toLowerCase()) {
                    contryCode = countries[i].code;
                    break;
                }
            }

            return contryCode ? contryCode : countryName;
        };

        this.getCountryByNameCode = function (countryCode, countries) {
            var contryName = null;

            try {
                for (var i = 0; i < countries.length; i++) {
                    if (countries[i].code.toLowerCase() === countryCode.toLowerCase()) {
                        contryName = countries[i].name;
                        break;
                    }
                }

                return contryName ? contryName : countryCode;
            } catch (e) {
            }

            return contryName;
        };

        this.getParamValue = function (name, url) {
            if (!url) {
                url = window.location.href;
            }
            var results = new RegExp("[\\?&]" + name + "=([^&#]*)").exec(url);
            if (!results) {
                return undefined;
            }
            return decodeURIComponent(results[1]) || undefined;
        }

        /*this.getSessionCards = function() {
            var cards = sessionStorage.getItem("sessionCards");

            if (!cards) {
                return [];
            } else {
                return JSON.parse(cards);
            }
        }*/

        /*this.setSessionCards = function (cardsArray) {
            sessionStorage.setItem("sessionCards", JSON.stringify(cardsArray));
        }*/

        this.getErrorMessages = function (codes) {
            var tempMessages = [];
            var codesArray = codes.split("|");
            if (codesArray && codesArray.length > 0) {
                var service = this;
                _.map(codesArray, function (code) {
                    if (code !== "") {
                        try {
                            var intCode = parseInt(code);
                            tempMessages.push(service.getErrorByCode(intCode));
                        }
                        catch (e) { }
                    }
                });
            }

            return tempMessages;
        }

        this.getErrorByCode = function (code) {
            switch (code) {
                case 100:
                    return "Merchant Identifier left blank or not valid. Indicates a corrupt or hacked payment form. The transaction was not processed.";
                case 110:
                    return "Session Identifier left blank. Indicates a corrupt or hacked payment form. The transaction was not processed.";
                case 200:
                    return "Name is missing.";
                case 500:
                    return "Address field required but left blank.";
                case 510:
                    return "City field required but left blank.";
                case 520:
                    return "State field required but left blank.";
                case 530:
                    return "ZIP/postal code field required but left blank.";
                case 531:
                    return "Invalid Postal Code.";
                case 550:
                    return "Country is missing.";
                case 300:
                    return "Amount not specified or invalid value entered.";
                case 310:
                    return "Credit card number left blank.";
                case 315:
                    return "Credit card number is invalid";
                case 320:
                    return "Credit card type is invalid";
                case 330:
                    return "Expiration month is invalid.";
                case 340:
                    return "Expiration year is invalid.";
                case 350:
                    return "CVV2 field submitted but does not match the card.";
                case 355:
                    return "CVC code is missing or invalid.";
                case 357:
                    return "Invalid CVV2 field submitted.";
                case 360:
                    return "Card declined by the processor. Please try again.";
                case 370:
                    return "Expiration date invalid.";
                case 400:
                    return "Tracer value does not match. The tracer value is a regularly updated number that indicates the origin of the payment information. If the tracer value changes it indicates a corrupt or hacked payment form, and the transaction will not be processed.";

                case 700:
                    return "Fraudulent Order.";
                default:
                    return "Unknown error. Error code: " + code;
            }
        }
    }]);

})(jQuery);
(function ($) {
    "use strict";

    angular.module("app").service("trackingService", ["$window", "$cookies", function ($window, $cookies) {

        this.buildFlowTrackerObjForPrintPage = function (bookingNumber, bookingId) {
            if (!bookingNumber) return;
            $window.flowtracker = {
                bookingNumber: bookingNumber,
                bookingId: bookingId
            };
            console.log("build flow tracker obj: ", $window.flowtracker);

            this.dispatchIBEReadyGMTEvent();
        };

        this.buildFlowTrackerObj = function (reqParams) {
            if (!reqParams) return;

            var lobTitle = reqParams.lobTitle;
            var packageName = reqParams.packageName;
            var searchDate = reqParams.searchDate;
            var checkoutDate = reqParams.checkoutDate || null;
            var numberOfNights = reqParams.numberOfNights || null;

            var shoppingCart = reqParams.shoppingCart;
            var anonymUser = reqParams.anonymUser;
            var bookingNumber = reqParams.bookingNumber;
            var bookingId = reqParams.bookingId;
            var adults = reqParams.adults;
            var children = reqParams.children;
            var email = (reqParams.email || "").trim().toLowerCase();


            if (!lobTitle && !packageName && (!shoppingCart || !(shoppingCart.Items || '').length)) {
                return;
            }

            var _this = this;
            var searchDate = this.getCleanDateStr(searchDate);


            // console.log("build flow tracker obj: ", lobTitle, packageName, shoppingCart, anonymUser);

            var obj = Object.create(null);

            if (lobTitle || packageName) {
                obj.page = Object.create(null);
                obj.page.lob = lobTitle;
                obj.page.searchDate = searchDate;
                obj.page.checkoutDate = checkoutDate;
                obj.page.numberOfNights = numberOfNights;

                obj.page.package = packageName;
                obj.page.adults = adults;
                obj.page.children = children;
            }

            var defaultPageTracking = {
                lob: null,
                searchDate: null,
                package: null,
                adults: null,
                children: null,
            };

            if (shoppingCart && (shoppingCart.Items || '').length) {
                var getCompName = function (comp) {
                    return comp && (comp.ProductDescriptions && comp.ProductDescriptions.titles && comp.ProductDescriptions.titles.length > 0 ? comp.ProductDescriptions.titles[0] : comp.Name);
                };

                var trackedProducts = [];
                _.each(shoppingCart.Items, function (item) {
                    if (item.BookingToQuote && item.BookingToQuote.Packages) {
                        _.each(item.BookingToQuote.Packages, function (pkg) {
                            var newProd = {
                                "id": pkg.PackageCode,
                                "name": pkg.PackageDescriptions && pkg.PackageDescriptions.titles && pkg.PackageDescriptions.titles.length > 0 ? pkg.PackageDescriptions.titles[0] : (!pkg.PackageDescriptions ? pkg.Name : (item.BookingToQuote.Components[0] && item.BookingToQuote.Components[0].Name || pkg.Name)),
                                "cost": anonymUser && anonymUser.isTaxInclusive ? (pkg.PriceIncludingTaxes || pkg.Price) : pkg.Price,
                                "package": pkg._trackingPackage || null,
                                "lob": pkg._trackingLob || null,
                                "arrival_date": _this.getCleanDateStr(pkg.StartDate)
                            };

                            trackedProducts.push(newProd);
                            if (newProd.lob || newProd.package) {
                                defaultPageTracking.lob = newProd.lob;
                                defaultPageTracking.searchDate = newProd.arrival_date;
                                defaultPageTracking.package = newProd.package;
                                defaultPageTracking.adults = pkg.NumberOfAdults;
                                defaultPageTracking.children = pkg.NumberOfChildren;
                            }
                        });
                    }

                    if (item.BookingToQuote && item.BookingToQuote.Components) {
                        _.each(item.BookingToQuote.Components, function (comp) {
                            if (_this.isCompFee(comp) || comp.isAttachedToParent) return;

                            var fallBackComp = comp.attachedTimeComponents && comp.attachedTimeComponents[0];
                            var newProd = {
                                "id": comp.Id || (fallBackComp && fallBackComp.Id),
                                "name": getCompName(comp) || comp._trackingUnitName || (fallBackComp && (fallBackComp._trackingUnitName || getCompName(fallBackComp))),
                                "cost": anonymUser && anonymUser.isTaxInclusive ? (item.totalCalcPriceWithTax || item.totalCalcPrice) : item.totalCalcPrice,
                                "package": comp._trackingPackage || (fallBackComp && fallBackComp._trackingPackage) || null,
                                "lob": comp._trackingLob || (fallBackComp && fallBackComp._trackingLob) || null,
                                "arrival_date": _this.getCleanDateStr(comp.StartDate)
                            };

                            if (comp.nights || comp.Nights) {
                                newProd.number_of_nights = comp.nights || comp.Nights;
                                newProd.departure_date = _this.getCleanDateStr(comp.EndDate || comp.endDate); //": _this.getCleanDateStr(comp.StartDate)
                            }

                            trackedProducts.push(newProd);
                            if (newProd.lob || newProd.package) {
                                defaultPageTracking.lob = newProd.lob;
                                defaultPageTracking.searchDate = newProd.arrival_date;
                                defaultPageTracking.checkoutDate = newProd.departure_date||null;
                                defaultPageTracking.numberOfNights = newProd.number_of_nights||null;

                                defaultPageTracking.package = newProd.package;
                                defaultPageTracking.adults = comp.NumberOfAdults || comp.NumberOfUnits || 0;
                                defaultPageTracking.children = comp.NumberOfChildren;
                            }
                        });
                    }
                });
                if (trackedProducts.length) {
                    obj.cart = {
                        products: [].concat(trackedProducts), // reference change issue?
                        total_cost: shoppingCart && shoppingCart.Quote && shoppingCart.Quote.Price,
                        currency: shoppingCart && shoppingCart.Quote && shoppingCart.Quote.Currency
                    };
                }
            }

            if (!obj.page && (defaultPageTracking.lob || defaultPageTracking.package)) {
                obj.page = defaultPageTracking;
            }

            if (bookingNumber) {
                obj.bookingNumber = bookingNumber;
                obj.bookingId = bookingId;
            }

            if (email) {
                obj.m5UserId = this.md5(email);
            }

            $window.flowtracker = obj;



            console.log("build flow tracker obj: ", obj);

            this.dispatchIBEReadyGMTEvent();

            //{
            //    "page": {
            //        "lob": lobTitle,
            //        "package": packageName
            //    },
            //    "cart": {
            //        "products": [
            //            { "id": "NR34", "name": "NightRise", "package": "packageA", "lob": "Banff Gondola", "cost": "150.00" },
            //            { "id": "EB45", "name": "Early bird", "package": "packageB", "lob": "Banff Gondola", "cost": "100.00" }
            //        ],
            //        "total_cost": "250.00"
            //    }
            //};
        };

        this.isCompFee = function (comp) {
            return comp && (comp.productType || comp.ProductType) == "FEE";
        }

        this.dispatchIBEReadyGMTEvent = function () {
            window.dataLayer = window.dataLayer || [];
            window.dataLayer.push({
                'event': 'ibe_ready'
            });
            console.log("dispatch ibe_ready", window.dataLayer);
        };

        this.getCleanDateStr = function (date) {
            if (!date) return date;
            date = String(date);
            if (date.indexOf('T') > 0) {
                date = date.substr(0, date.indexOf('T'));
            }
            return date;
        };

        this.getSegmentUserId = function () {
            var overlayCookieName = "ajs_anonymous_id";

            return $cookies.get(overlayCookieName);
        };

        this.md5 = function (inputString) {
            //  A formatted version of a popular md5 implementation.
            //  Original copyright (c) Paul Johnston & Greg Holt.
            //  The function itself is now 42 lines long.

            var hc = "0123456789abcdef";
            function rh(n) { var j, s = ""; for (j = 0; j <= 3; j++) s += hc.charAt((n >> (j * 8 + 4)) & 0x0F) + hc.charAt((n >> (j * 8)) & 0x0F); return s; }
            function ad(x, y) { var l = (x & 0xFFFF) + (y & 0xFFFF); var m = (x >> 16) + (y >> 16) + (l >> 16); return (m << 16) | (l & 0xFFFF); }
            function rl(n, c) { return (n << c) | (n >>> (32 - c)); }
            function cm(q, a, b, x, s, t) { return ad(rl(ad(ad(a, q), ad(x, t)), s), b); }
            function ff(a, b, c, d, x, s, t) { return cm((b & c) | ((~b) & d), a, b, x, s, t); }
            function gg(a, b, c, d, x, s, t) { return cm((b & d) | (c & (~d)), a, b, x, s, t); }
            function hh(a, b, c, d, x, s, t) { return cm(b ^ c ^ d, a, b, x, s, t); }
            function ii(a, b, c, d, x, s, t) { return cm(c ^ (b | (~d)), a, b, x, s, t); }
            function sb(x) {
                var i; var nblk = ((x.length + 8) >> 6) + 1; var blks = new Array(nblk * 16); for (i = 0; i < nblk * 16; i++) blks[i] = 0;
                for (i = 0; i < x.length; i++) blks[i >> 2] |= x.charCodeAt(i) << ((i % 4) * 8);
                blks[i >> 2] |= 0x80 << ((i % 4) * 8); blks[nblk * 16 - 2] = x.length * 8; return blks;
            }
            var i, x = sb(inputString), a = 1732584193, b = -271733879, c = -1732584194, d = 271733878, olda, oldb, oldc, oldd;
            for (i = 0; i < x.length; i += 16) {
                olda = a; oldb = b; oldc = c; oldd = d;
                a = ff(a, b, c, d, x[i + 0], 7, -680876936); d = ff(d, a, b, c, x[i + 1], 12, -389564586); c = ff(c, d, a, b, x[i + 2], 17, 606105819);
                b = ff(b, c, d, a, x[i + 3], 22, -1044525330); a = ff(a, b, c, d, x[i + 4], 7, -176418897); d = ff(d, a, b, c, x[i + 5], 12, 1200080426);
                c = ff(c, d, a, b, x[i + 6], 17, -1473231341); b = ff(b, c, d, a, x[i + 7], 22, -45705983); a = ff(a, b, c, d, x[i + 8], 7, 1770035416);
                d = ff(d, a, b, c, x[i + 9], 12, -1958414417); c = ff(c, d, a, b, x[i + 10], 17, -42063); b = ff(b, c, d, a, x[i + 11], 22, -1990404162);
                a = ff(a, b, c, d, x[i + 12], 7, 1804603682); d = ff(d, a, b, c, x[i + 13], 12, -40341101); c = ff(c, d, a, b, x[i + 14], 17, -1502002290);
                b = ff(b, c, d, a, x[i + 15], 22, 1236535329); a = gg(a, b, c, d, x[i + 1], 5, -165796510); d = gg(d, a, b, c, x[i + 6], 9, -1069501632);
                c = gg(c, d, a, b, x[i + 11], 14, 643717713); b = gg(b, c, d, a, x[i + 0], 20, -373897302); a = gg(a, b, c, d, x[i + 5], 5, -701558691);
                d = gg(d, a, b, c, x[i + 10], 9, 38016083); c = gg(c, d, a, b, x[i + 15], 14, -660478335); b = gg(b, c, d, a, x[i + 4], 20, -405537848);
                a = gg(a, b, c, d, x[i + 9], 5, 568446438); d = gg(d, a, b, c, x[i + 14], 9, -1019803690); c = gg(c, d, a, b, x[i + 3], 14, -187363961);
                b = gg(b, c, d, a, x[i + 8], 20, 1163531501); a = gg(a, b, c, d, x[i + 13], 5, -1444681467); d = gg(d, a, b, c, x[i + 2], 9, -51403784);
                c = gg(c, d, a, b, x[i + 7], 14, 1735328473); b = gg(b, c, d, a, x[i + 12], 20, -1926607734); a = hh(a, b, c, d, x[i + 5], 4, -378558);
                d = hh(d, a, b, c, x[i + 8], 11, -2022574463); c = hh(c, d, a, b, x[i + 11], 16, 1839030562); b = hh(b, c, d, a, x[i + 14], 23, -35309556);
                a = hh(a, b, c, d, x[i + 1], 4, -1530992060); d = hh(d, a, b, c, x[i + 4], 11, 1272893353); c = hh(c, d, a, b, x[i + 7], 16, -155497632);
                b = hh(b, c, d, a, x[i + 10], 23, -1094730640); a = hh(a, b, c, d, x[i + 13], 4, 681279174); d = hh(d, a, b, c, x[i + 0], 11, -358537222);
                c = hh(c, d, a, b, x[i + 3], 16, -722521979); b = hh(b, c, d, a, x[i + 6], 23, 76029189); a = hh(a, b, c, d, x[i + 9], 4, -640364487);
                d = hh(d, a, b, c, x[i + 12], 11, -421815835); c = hh(c, d, a, b, x[i + 15], 16, 530742520); b = hh(b, c, d, a, x[i + 2], 23, -995338651);
                a = ii(a, b, c, d, x[i + 0], 6, -198630844); d = ii(d, a, b, c, x[i + 7], 10, 1126891415); c = ii(c, d, a, b, x[i + 14], 15, -1416354905);
                b = ii(b, c, d, a, x[i + 5], 21, -57434055); a = ii(a, b, c, d, x[i + 12], 6, 1700485571); d = ii(d, a, b, c, x[i + 3], 10, -1894986606);
                c = ii(c, d, a, b, x[i + 10], 15, -1051523); b = ii(b, c, d, a, x[i + 1], 21, -2054922799); a = ii(a, b, c, d, x[i + 8], 6, 1873313359);
                d = ii(d, a, b, c, x[i + 15], 10, -30611744); c = ii(c, d, a, b, x[i + 6], 15, -1560198380); b = ii(b, c, d, a, x[i + 13], 21, 1309151649);
                a = ii(a, b, c, d, x[i + 4], 6, -145523070); d = ii(d, a, b, c, x[i + 11], 10, -1120210379); c = ii(c, d, a, b, x[i + 2], 15, 718787259);
                b = ii(b, c, d, a, x[i + 9], 21, -343485551); a = ad(a, olda); b = ad(b, oldb); c = ad(c, oldc); d = ad(d, oldd);
            }
            return rh(a) + rh(b) + rh(c) + rh(d);
        };

    }]);

})(jQuery);
(function ($) {
    "use strict";

    angular.module("app").service("transportationService", ["localStorageService", "$http", function (localStorageService, $http) {
        this.removeAllStoredData = function () {
            if (localStorageService.isSupported) {
                localStorageService.remove("transportationsFilters");
                localStorageService.remove("prevTransportation");
                localStorageService.remove("transportationWizardModel");
                localStorageService.remove("transportationGeoLocations");
            }
        };

        this.getTransportationFilters = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/usercode/searchfilters/Transportation",
                headers: { "Authorization": params.token }
            }).then(
              function (result) {
                  callback({ success: true, data: result.data, error: undefined });
              },
              function (response) {
                  callback({ success: false, data: undefined, error: response.data });
                  console.log(response);
              }
          );
        };
        this.getLocationsByServiceType = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/Usercode/LocationsByService/" + params.type,
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };
        this.getTransportationsByType = function (params, callback) {
            var aditionalParam = params.fromLocationCode + "/" + params.fromLocationName + "/" + params.toLocationCode + "/" + params.toLocationName + "/" + params.pickupCode + "/" + params.dropoffCode;
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/product/TransportationByType/" + params.type + "/" + params.date + "/"+aditionalParam,
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };
        this.getTransportationsByTypeWithPackages = function (params, callback) {
            var aditionalParam = params.fromLocationCode + "/" + params.fromLocationName + "/" + params.toLocationCode + "/" + params.toLocationName + "/" + params.pickupCode + "/" + params.dropoffCode;
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/product/TransportationByTypeWithPackages/" + params.type + "/" + params.date + "/" + aditionalParam,
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };
        this.getTransportationProduct = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/product/TransportationProduct/" + params.code + "/" + params.date,
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.getTransportationsByDate = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/product/productsbycategory/"+ (params.id || "Transportation") + "/" + params.date,
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.getTransportations = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/product/transportaionproducts",
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.getBusStopsByCity = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/usercode/busstopsbycity/" + params.cityCode + "/" + params.travelDate + "/" + params.serviceType,
                headers: { "Authorization": params.token }
            }).then(
              function (result) {
                  callback({ success: true, data: result.data, error: undefined });
              },
              function (response) {
                  callback({ success: false, data: undefined, error: response.data });
                  console.log(response);
              }
          );
        };

        this.getBusStops = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/usercode/busstops/" + params.productCode + "/" + params.unitCode,
                headers: { "Authorization": params.token }
            }).then(
              function (result) {
                  callback({ success: true, data: result.data, error: undefined });
              },
              function (response) {
                  callback({ success: false, data: undefined, error: response.data });
                  console.log(response);
              }
          );
        };

        this.getTransportationsByDateAndLocations = function (params, callback) {
            var url = params.urlPrefix + "/api/product/productsbycategory/Transportation/" + params.date;

            if (params.locationCode && params.locationCode !== "") {
                url += "/" + params.locationCode;
            } else {
                url += "/" + "undefined";
            }

            if (params.reverseLocationCode && params.reverseLocationCode != "") {
                url += "/" + params.reverseLocationCode;
            } else {
                url += "/" + "undefined";
            }

            $http({
                method: "GET",
                url: url,
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };
        this.persistTransportationsFilters = function (id,filters, callback) {
            if (localStorageService.isSupported) {
                var expireDate = new Date();
                filters.expire = expireDate;
                filters.id = id;
                localStorageService.set("transportationsFilters", filters);
                callback({ success: true, data: filters, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: "Local Storage is not supported!" });
            }
        };
        this.getPersistedTransportationsFilters = function (id, callback) {
           
            if (localStorageService.isSupported) {
                var filters = localStorageService.get("transportationsFilters");
                if (filters && filters.expire) {
                    var date = new Date(filters.expire);
                    var today = new Date();
                  
                    if (filters.id != id || date.getDate() !== today.getDate() || date.getMonth() !== today.getMonth() || date.getFullYear() !== today.getFullYear()) {
                        localStorageService.remove("transportationsFilters");
                        filters = null;
                    }
                } else {
                    localStorageService.remove("transportationsFilters");
                    filters = null;
                }
                callback({ success: true, data: filters, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: "Local Storage is not supported!" });
            }
        };
        this.setIsFromFilters = function (val, callback) {
            if (localStorageService.isSupported) {
                localStorageService.set("isFromFilters", val);
                callback({ success: true, error: undefined });
            } else {
                callback({ success: false, error: undefined });
            }
        };
        this.getIsFromFilters = function () {
            if (localStorageService.isSupported) {
                var val = localStorageService.get("isFromFilters");
                return val;
            } else {
                return undefined;
            }
        };
        this.setIsFromTransportationDetails = function (val, callback) {
            if (localStorageService.isSupported) {
                localStorageService.set("isFromTransportationDetails", val);
                callback({ success: true, error: undefined });
            } else {
                callback({ success: false, error: undefined });
            }
        };
        this.getIsFromTransportationDetails = function () {
            if (localStorageService.isSupported) {
                var val = localStorageService.get("isFromTransportationDetails");
                return val;
            } else {
                return undefined;
            }
        };
        this.getSelectedTransportation = function (callback) {
            if (localStorageService.isSupported) {
                var transport = localStorageService.get("prevTransportation");
                if (transport && transport.expire) {
                    var date = new Date(transport.expire);
                    var today = new Date();
                    if (date.getDate() !== today.getDate() || date.getMonth() !== today.getMonth() || date.getFullYear() !== today.getFullYear()) {
                        localStorageService.remove("prevTransportation");
                        transport = null;
                    }
                } else {
                    localStorageService.remove("prevTransportation");
                    transport = null;
                }
                callback({ success: true, data: transport, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: undefined });
            }
        };
        this.setSelectedTransportation = function (transport, callback) {
            if (localStorageService.isSupported) {
                var expireDate = new Date();
                transport.expire = expireDate;

                localStorageService.set("prevTransportation", transport);
                callback({ success: true, data: transport, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: undefined });
            }
        };
        this.getTransportationWizardModel = function (callback) {
            if (localStorageService.isSupported) {
                var wizardModel = localStorageService.get("transportationWizardModel");
                if (wizardModel && wizardModel.expire) {
                    var date = new Date(wizardModel.expire);
                    var today = new Date();
                    if (date.getDate() !== today.getDate() || date.getMonth() !== today.getMonth() || date.getFullYear() !== today.getFullYear()) {
                        localStorageService.remove("transportationWizardModel");
                        wizardModel = null;
                    }
                } else {
                    localStorageService.remove("transportationWizardModel");
                    wizardModel = null;
                }
                callback({ success: true, data: wizardModel, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: undefined });
            }
        };
        this.setTransportationWizardModel = function (wizardModel, callback) {
            if (localStorageService.isSupported) {
                var expireDate = new Date();
                wizardModel.expire = expireDate;

                localStorageService.set("transportationWizardModel", wizardModel);
                callback({ success: true, data: wizardModel, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: undefined });
            }
        };
        this.setGeoLocations = function (geoLocations, callback) {
            if (localStorageService.isSupported) {
                var expireDate = new Date();
                geoLocations.expire = expireDate;
                localStorageService.set("transportationGeoLocations", geoLocations);
                callback({ success: true, data: geoLocations, error: undefined });
            } else {
                callback({ success: false, data: geoLocations, error: undefined });
            }
        };
        this.getGeoLocationsAsync = function (callback) {
            if (localStorageService.isSupported) {
                var geoLocations = localStorageService.get("transportationGeoLocations");
                if (geoLocations && geoLocations.expire) {
                    var date = new Date(geoLocations.expire);
                    var today = new Date();
                    if (date.getDate() !== today.getDate() || date.getMonth() !== today.getMonth() || date.getFullYear() !== today.getFullYear()) {
                        localStorageService.remove("transportationGeoLocations");
                        geoLocations = null;
                    }
                } else {
                    localStorageService.remove("transportationGeoLocations");
                    geoLocations = null;
                }
                callback({ success: true, data: geoLocations, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: undefined });
            }
        };
    }]);

})(jQuery);
(function ($) {
    "use strict";

    angular.module("app").service("userService", ["localStorageService", "$http", function (localStorageService, $http) {

        this.getCountries = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/usercode/locations/country",
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    var tempCountries = result.data.worldLocations;

                    var usIndex = _.findIndex(tempCountries, function (i) { return i.code === "US" });
                    var clonedUSItem = _.find(tempCountries, function (i) { return i.code === "US" });

                    if (usIndex > 0 && clonedUSItem) {
                        tempCountries.splice(usIndex, 1);

                        tempCountries.splice(0, 0, clonedUSItem);
                    }

                    var canadaIndex = _.findIndex(tempCountries, function (i) { return i.code === "CA" });
                    var clonedCanadaItem = _.find(tempCountries, function (i) { return i.code === "CA" });

                    if (canadaIndex > 0 && clonedCanadaItem) {
                        tempCountries.splice(canadaIndex, 1);

                        tempCountries.splice(0, 0, clonedCanadaItem);
                    }

                    callback({ success: true, data: tempCountries, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.getRegions = function (params, callback) {
            $http({
                method: "GET",
                url: params.urlPrefix + "/api/usercode/regions",
                headers: { "Authorization": params.token }
            }).then(
                function (result) {
                    callback({ success: true, data: result && result.data && result.data.countryRegions, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.persistCountries = function (countries, callback) {
            if (localStorageService.isSupported) {
                var expireDate = new Date();
                var obj = { "countries": countries, "expire": expireDate }

                localStorageService.set("worldCountries", obj);
                callback({ success: true, data: countries, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: "Local Storage is not supported!" });
            }
        };
        this.getPersistedCountries = function (callback) {
            if (localStorageService.isSupported) {
                var worldCountries = localStorageService.get("worldCountries");
                if (worldCountries && worldCountries.expire) {
                    var date = new Date(worldCountries.expire);
                    var today = new Date();
                    if (date.getDate() !== today.getDate() || date.getMonth() !== today.getMonth() || date.getFullYear() !== today.getFullYear()) {
                        localStorageService.remove("worldCountries");
                        worldCountries = null;
                    }
                } else {
                    localStorageService.remove("worldCountries");
                    worldCountries = null;
                }
                callback({ success: true, data: worldCountries, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: undefined });
            }
        };
        this.persistRegions = function (regions, callback) {
            if (localStorageService.isSupported) {
                var expireDate = new Date();
                var obj = { "regions": regions, "expire": expireDate }

                localStorageService.set("regions", obj);
                callback({ success: true, data: regions, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: "Local Storage is not supported!" });
            }
        };
        this.getPersistedRegions = function (callback) {
            if (localStorageService.isSupported) {
                var regions = localStorageService.get("regions");
                if (regions && regions.expire) {
                    var date = new Date(regions.expire);
                    var today = new Date();
                    if (date.getDate() !== today.getDate() || date.getMonth() !== today.getMonth() || date.getFullYear() !== today.getFullYear()) {
                        localStorageService.remove("regions");
                        regions = null;
                    }
                } else {
                    localStorageService.remove("regions");
                    regions = null;
                }
                callback({ success: true, data: regions, error: undefined });
            } else {
                callback({ success: false, data: undefined, error: undefined });
            }
        };

        this.confirmEmail = function (params, callback) {
            $http({
                method: "POST",
                url: params.urlPrefix + "/api/user/confirmemail",
                headers: { 'Content-Type': "application/json" },
                data: params.dataToPost
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.resendEmailConfirmation = function (params, callback) {
            $http({
                method: "POST",
                url: params.urlPrefix + "/api/user/resendemailconfirmation",
                headers: { 'Content-Type': "application/json" },
                data: params.dataToPost
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.confirmEmailChange = function (params, callback) {
            $http({
                method: "POST",
                url: params.urlPrefix + "/api/user/confirmemailchange",
                headers: { 'Content-Type': "application/json" },
                data: params.dataToPost
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.changeEmail = function (params, callback) {
            $http({
                method: "POST",
                url: params.urlPrefix + "/api/user/changenewemail",
                headers: { 'Content-Type': "application/json", "Authorization": params.token },
                data: params.dataToPost
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.updatePassword = function (params, callback) {
            $http({
                method: "POST",
                url: params.urlPrefix + "/api/Authentication/updatepassword",
                headers: { 'Content-Type': "application/json", "Authorization": params.token },
                data: params.dataToPost
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

        this.resetPassword = function (params, callback) {
            $http({
                method: "POST",
                url: params.urlPrefix + "/api/Authentication/ResetPassword",
                headers: { 'Content-Type': "application/json" },
                data: params.dataToPost
            }).then(
                function (result) {
                    callback({ success: true, data: result.data, error: undefined });
                },
                function (response) {
                    callback({ success: false, data: undefined, error: response.data });
                    console.log(response);
                }
            );
        };

    }]);

})(jQuery);
(function ($) {
    "use strict";

    angular.module("app").controller("bookModalCtrl", [
        "$scope", "$uibModalInstance", "ticket", "packageModalLabels", "utilsFactory", function ($scope, $uibModalInstance, ticket, packageModalLabels, utilsFactory) {

            $scope.utils = utilsFactory;
            $scope.packageModalLabels = packageModalLabels;

            $scope.addToCart = function () {
                $uibModalInstance.close(ticket);
            };
            $scope.goToPackages = function () {
                $uibModalInstance.dismiss({ goToPackage: true });
            };
        }
    ]);


    angular.module("app").controller("cartInfoModalCtrl", [
        "$scope", "$uibModalInstance", "count", "isHotel", "utilsFactory", function ($scope, $uibModalInstance, count, isHotel, utilsFactory) {
            $scope.count = count;
            $scope.isHotel = isHotel;
            $scope.utils = utilsFactory;
            $scope.continueToCheckout = function () {
                window.location.href = utilsFactory.addPersistentQueryStringsParams("/checkout");
                // $uibModalInstance.close(cart);
            };

            $scope.continueShopping = function (stayHere) {
                if (!stayHere)
                    window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
                $uibModalInstance.dismiss("cancel");
            };
        }
    ]);



    angular.module("app").controller("requiredProductsModalCtrl", [
        "$scope", "$uibModalInstance", "products", "utilsFactory", function ($scope, $uibModalInstance, products, utilsFactory) {            

            $scope.utils = utilsFactory;
            $scope.products = products.data;
            $scope.yourProductTitle = products.yourProductTitle || "product";
            $scope.followingProductLabel = $scope.products.length > 1 ? products.followingProductMultiple : products.followingProductSingle;

            //for validation
            $scope.submitted = false;
            $scope.isValid = false;

            $scope.continue = function () {
                $scope.submitted = true;
                $scope.isValid = true;
                _.each($scope.products, function (pr) {

                    if (pr && pr.product && pr.product.selectedUnit && (pr.product.selectedUnit.pickups || "").length && pr.product.selectedUnit.pickupLocationRequired && (!pr.product.selectedUnit.selectedPickUp || !pr.product.selectedUnit.selectedPickUp.code)) {
                        $scope.isValid = false;
                    }
                    if (pr && pr.product && pr.product.selectedUnit && (pr.product.selectedUnit.dropoffs || "").length && pr.product.selectedUnit.dropoffLocationRequired && (!pr.product.selectedUnit.selectedDropOff || !pr.product.selectedUnit.selectedDropOff.code)) {
                        $scope.isValid = false;
                    }
                });

                if (!$scope.isValid) return;

                $uibModalInstance.close({ "status": "ok" });
            };

            $scope.cancel = function () {
                $uibModalInstance.dismiss("cancel");
            };
        }
    ]);

    angular.module("app").controller("tripCoverageModalCtrl", [
        "$scope", "$uibModalInstance", "modalInfo", "utilsFactory", function ($scope, $uibModalInstance, modalInfo, utilsFactory) {

            $scope.utils = utilsFactory;
            $scope.modalInfo = modalInfo;

            $scope.continue = function () {
                $uibModalInstance.close({ "status": "ok" });
            };

            $scope.cancel = function () {
                $uibModalInstance.dismiss("cancel");
            };
        }
    ]);

    angular.module("app").controller("expressConsentModalCtrl", [
        "$scope", "$uibModalInstance", "expressConsent", "utilsFactory", function ($scope, $uibModalInstance, expressConsent, utilsFactory) {

            $scope.utils = utilsFactory;
            $scope.components = expressConsent.components;
            $scope.expressConsent = expressConsent;

            $scope.continue = function () {
                $uibModalInstance.close({ "status": "ok", components: $scope.components });
            };

            $scope.cancel = function () {
                $uibModalInstance.dismiss("cancel");
            };
        }
    ]);

    angular.module("app").controller("infoModalCtrl", [
        "$scope", "$uibModalInstance", "info", "utilsFactory", function ($scope, $uibModalInstance, info, utilsFactory) {

            $scope.utils = utilsFactory;
            $scope.info = info;

            $scope.continue = function () {
                $uibModalInstance.close({ "status": "ok" });
            };

            $scope.cancel = function () {
                $uibModalInstance.dismiss("cancel");
            };
        }
    ]);

    angular.module("app").controller("cartPriceChangeModalCtrl", [
        "$scope", "$uibModalInstance", "priceChange", "utilsFactory", function ($scope, $uibModalInstance, priceChange, utilsFactory) {

            $scope.utils = utilsFactory;

            $scope.priceChange = priceChange;

            $scope.continue = function () {
                $uibModalInstance.close({ "status": "ok" });
            };

            $scope.cancel = function () {
                $uibModalInstance.dismiss("cancel");
            };
        }
    ]);


    angular.module("app").controller("confirmRemoveFromCartModalCtrl", [
        "$scope", "$uibModalInstance", "utilsFactory", function ($scope, $uibModalInstance, utilsFactory) {

            $scope.utils = utilsFactory;

            $scope.continue = function () {
                $uibModalInstance.close({ "status": "ok" });
            };

            $scope.cancel = function () {
                $uibModalInstance.dismiss("cancel");
            };
        }
    ]);

    angular.module("app").controller("generalCtrl", [
        "utilsFactory",
        "trackingService", "$scope", "$rootScope", "$element", "$window", "localStorageService", "$uibModal", "$http", "$auth", "ExternalAuthProvider", "jwtService", "shoppingCartService", "activitiesService", "hotelsService", "transportationService", "taskFactory", "currenciesService", "$timeout","$location",
        function (utilsFactory, trackingService, $scope, $rootScope, $element, $window, localStorageService, $uibModal, $http, $auth, ExternalAuthProvider, jwtService, shoppingCartService, activitiesService, hotelsService, transportationService, taskFactory, currenciesService, $timeout, $location) {

            try {
                var searchParams = new URLSearchParams(window.location.search);
                $scope.currentQueryString = searchParams.toString() ? '?' + searchParams.toString() : '';
            } catch (e) {
                console.log("General controller init: ",e);
            }

            $scope.utils = utilsFactory;
            $scope.labelUtils = utilsFactory;

            $scope.loadingMsg = $scope.utils.getLabel("general.loadingMsg");

            //init tracking
            $scope.trackingInfo = {
                "CRMVisitId": "",
                "CRMVisitorId": "",
                "IsInit": false,
                "WebLink": jQuery("body").data("weblink")
            };

            $scope.$watch(function () {
                return window.nvk;
            }, function (value) {
                if (value) {
                    $scope.trackingInfo.CRMVisitId = value.visit_id;
                    $scope.trackingInfo.CRMVisitorId = value.visitor_id;
                    $scope.trackingInfo.IsInit = true;
                }
            });

            $scope.privacyPolicyLabels = (utilsFactory.getLabel("privacypolicy", true) || [])[0];

            $scope.logo = ""; //"/Content/images/pursuit.png";
            $scope.mobileLogo = "";
            $scope.footerLogo = "";
            $scope.footerSecondaryLogo = "";
            $scope.phone = $scope.utils.getLabel("general.tel-number");

            $scope.isFOC = "";

            TweenMax.ticker.useRAF(false);
            jQuery(window).focus(function () {
                jQuery(window).resize();

            });

            $(window).blur(function () {
                jQuery(window).resize();
            });

            $scope.actionRegionCode = $($element).attr("data-region-code");
            $scope.detailsInitialized = false;

            $scope.showModal = {};
            $scope.modalData = {};

            var navbarHeight = jQuery(".navbar:first").height();//60;
            var mobBreakpoint = 767;


            $scope.customer = null;

            $scope.mainSection = null;
            $scope.isHomePage = $($element).hasClass("home-page");

            $scope.isLoggedIn = function () {
                var tk = jwtService.getCustomerToken();
                return tk && tk.length;
            };
            $scope.globalErrors = [];
            $scope.showModal["GlobalErrors"] = false;

            $scope.cleanGlobalErrors = function () {
                $scope.globalErrors = [];
                $scope.showModal["GlobalErrors"] = false;
            };

            $scope.$on("mergeGlobalErros", function (event, args) {

                $scope.isLoading = false;
                if (!args) {
                    $scope.cleanGlobalErrors();
                    return;
                }

                setTimeout(function () {
                    var serverError = null;
                    var apiErrors = [];

                    jQuery.each($scope.globalErrors, function (index, value) {
                        if (value.serverSide) {
                            serverError = value;
                        } else {
                            apiErrors.push(value);
                        }
                    });

                    jQuery.each(args, function (index, value) {
                        if (value.serverSide) {
                            serverError = value;
                        } else {
                            apiErrors.push(value);
                        }
                    });

                    if (apiErrors.length > 0) {
                        $scope.globalErrors = apiErrors;
                    } else if (serverError) {
                        $scope.globalErrors = [serverError];
                    }


                    $scope.showModal["GlobalErrors"] = true;
                    $scope.$apply();
                }, 0);

            });

            function setHeight() {
                if (($($element).attr("data-enable-for-mobile") === "true") || ($($window).width() > mobBreakpoint)) {
                    //var cookieConsent = jQuery(".CookieConsent");
                    //var cookieConsentHeight = 0;
                    //if (cookieConsent.is(":visible")) {
                    //    cookieConsentHeight = cookieConsent.height();
                    //}

                    $scope.wHeight = $window.innerHeight - navbarHeight; //- cookieConsent;
                    $(".select-button.set-pos").css("width", "");
                } else {
                    $scope.wHeight = "";
                    $(".select-button.set-pos").css("width", "100%");
                }
            }

            $scope.getCartItemsCount = function () {
                var cc = shoppingCartService.getCurrentCart();
                if (cc) {
                    return cc.Items.length;
                }
                return 0;
            };

            $scope.getWebUrl = function () {
                return $("body").data("weburl") ? $("body").data("weburl") : "";
            };

            $scope.geographies = undefined;
            $scope.selectedGeographyCode = undefined;


            currenciesService.initCurrencyRates($scope.actionRegionCode, function (result) {
                $scope.currencyRatesLoaded = result && result.success;
            });


            function initMultiCurrencies() {
                if (!!$scope.selectedCurrency) return; // it's already intiialized

                var selectedCurrencyCode = currenciesService.getSelectedCurrencyCode();
                selectedCurrencyCode = $("body").data("currency") || selectedCurrencyCode;

                $scope.currencies = currenciesService.getCurrenciesByGeographyCode($scope.selectedGeographyCode) || [];
                if (!$scope.currencies) return;

                $scope.selectedCurrency = _.find($scope.currencies, function (it) { return it.code == selectedCurrencyCode; }) || $scope.currencies[0];
                currenciesService.setSelectedCurrencyCode($scope.selectedCurrency && $scope.selectedCurrency.code);
            }

            $scope.getCurrencyBySelectedCode = function () {
                if ((!$scope.currencies || "").length) return;
                var selectedCurrencyCode = currenciesService.getSelectedCurrencyCode();

                return (selectedCurrencyCode && _.find($scope.currencies, function (it) { return it.code == selectedCurrencyCode; })) || $scope.currencies[0];
            };

            $scope.setSelectedCurrency = function (selectedCurrency) {
                $scope.selectedCurrency = selectedCurrency;
            };

            $scope.getPriceInSelectedCurrency = function (value, originalCurrency, selectedCurrency) {
                var targetCurrencyCode = (selectedCurrency && selectedCurrency.code) || ($scope.selectedCurrency && $scope.selectedCurrency.code);

                if (!$scope.currencyRatesLoaded || !targetCurrencyCode || !originalCurrency) return value;

                return currenciesService.getPriceInSelectedCurrency(value, originalCurrency, targetCurrencyCode);

                //if (!$scope.selectedCurrency || !$window.fx) return value;

                //return $window.fx(value).from(originalCurrency).to($scope.selectedCurrency.code);
            };


            $scope.getSelectedGeographyLabel = function () {
                var gc = $scope.getSelectedGeographyCode();
                if (!gc || !($scope.geographies || "").length) return "";

                var gr = _.find($scope.geographies,
                    function (g) {
                        return g.code.toLowerCase() === gc.toLowerCase();
                    });
                if (!gr) return "";

                return gr.name;
            };

            $scope.getSelectedGeographyCode = function () {
                if (!$scope.selectedGeographyCode && ($scope.geographies || "").length) {
                    $scope.selectedGeographyCode = $scope.geographies[0].code;
                }
                return $scope.selectedGeographyCode;
            };

            $scope.getGeographiesAsync = function (callback) {
                jwtService.getPersistedGeographies(function (geographiesResult) {
                    if (geographiesResult.success && geographiesResult.data && geographiesResult.data.geographies) {
                        $scope.geographies = geographiesResult.data.geographies;

                        if (callback) {
                            callback();
                        }
                        return;
                    }
                    jwtService.getGeographiesAsync(
                        {
                            urlPrefix: $scope.getWebUrl(),
                            token: jwtService.getPrincipalToken()
                        },
                        function (result) {
                            if (result.success && result.data) {
                                $scope.geographies = result.data.geographies;

                                jwtService.persistGeographies({
                                    geographies: $scope.geographies
                                }, function () { });
                            }
                            if (callback) {
                                callback();
                            }
                        });
                });
            };



            $scope.setGeography = function (geography) {
                if ($scope.isLoading || $scope.showOverlayLoading) return;
                // $scope.isLoading = true;
                $scope.showOverlayLoading = true;
                $scope.selectedGeographyCode = geography.code;
                jwtService.clearStorage();
                //debugger;
                window.location = utilsFactory.addPersistentQueryStringsParams("/" + geography.code);

            };

            $scope.getProductCategorySearchOptionsAsync = function (callback) {
                $scope.mainSectionId = $($element).data("sectionid");
                var mainLinkId = ($($element).data("linkid") || "").toLowerCase();

                if (!$($element).find("#hdSearchCategoryConstants").val()) {
                    if (callback) {
                        callback();
                    }
                    return;
                }
                var constants = jQuery.parseJSON($($element).find("#hdSearchCategoryConstants").val());
                //debugger;
                jwtService.getPersistedProductCategorySearchOptions(function (searchOptionsResult) {

                    if (searchOptionsResult.success && searchOptionsResult.data && searchOptionsResult.data.searchCategories) {
                        $scope.searchCategories = searchOptionsResult.data.searchCategories;

                        if ($scope.searchCategories && $scope.searchCategories.length) {
                            _.each($scope.searchCategories, function (it) {
                                if (it.URL) {
                                    it.URL = utilsFactory.addPersistentQueryStringsParams(it.URL);
                                }
                            });
                        }

                        if ($scope.mainSectionId) {
                            $scope.mainSection = _.find($scope.searchCategories, function (sc) {
                                return sc.id == $scope.mainSectionId;
                            });
                        }

                        if (!$scope.mainSection && mainLinkId) {
                            $scope.mainSection = _.find($scope.searchCategories, function (sc) {
                                return sc.LinkId.toLowerCase().indexOf(mainLinkId.toLowerCase()) >= 0;
                            });
                        }
                        //
                        if ($scope.isHomePage && $scope.searchCategories.length == 1) {
                            if (activitiesService.getIsFromFilters()) {
                                activitiesService.setIsFromFilters(0, function () {
                                    if (callback) {
                                        callback();
                                    }
                                });
                                return;
                            } else {
                                window.location.href = $scope.searchCategories[0].URL;//utilsFactory.addPersistentQueryStringsParams($scope.searchCategories[0].URL);
                                //if (callback) {
                                //    callback();
                                //}
                            }
                        } else
                            if (callback) {
                                callback();
                            }
                        //

                        return;
                    }
                    jwtService.getProductCategorySearchOptionsAsync(
                        {
                            urlPrefix: $scope.getWebUrl(),
                            token: jwtService.getPrincipalToken()
                        },
                        function (result) {
                            if (result.success && result.data) {
                                $scope.searchCategories = result.data.searchCategories;

                                for (var i = 0; i < $scope.searchCategories.length; i++) {
                                    jQuery.each(constants, function (j, val) {
                                        if ($scope.searchCategories[i].LinkId.toLocaleLowerCase().indexOf(val.Name.toLowerCase()) >= 0) {
                                            $scope.searchCategories[i].URL = val.Url + "/" + $scope.searchCategories[i].id;
                                            if (!$scope.searchCategories[i].imageURL) {
                                                $scope.searchCategories[i].imageURL = val.SectionImageUrl;
                                            }
                                        }
                                    });
                                }
                                if ($scope.mainSectionId) {
                                    $scope.mainSection = _.find($scope.searchCategories, function (sc) {
                                        return sc.id == $scope.mainSectionId;
                                    });
                                }

                                if (!$scope.mainSection && mainLinkId) {
                                    $scope.mainSection = _.find($scope.searchCategories, function (sc) {
                                        return sc.LinkId.toLowerCase().indexOf(mainLinkId.toLowerCase()) >= 0;
                                    });
                                }

                                jwtService.persistProductCategorySearchOptions({
                                    searchCategories: $scope.searchCategories
                                }, function () { });
                            }

                            //
                            if ($scope.isHomePage && $scope.searchCategories.length == 1) {
                                if (activitiesService.getIsFromFilters()) {
                                    activitiesService.setIsFromFilters(0, function () {
                                        if (callback) {
                                            callback();
                                        }
                                    });
                                    return;
                                } else {
                                    window.location.href = $scope.searchCategories[0].URL;// utilsFactory.addPersistentQueryStringsParams($scope.searchCategories[0].URL);
                                }
                            } else
                                if (callback) {
                                    callback();
                                }
                            //
                        });
                });
            };
            $scope.getHomePageBoxes = function () {
                $scope.isLoading = true;

                $http({
                    method: "GET",
                    url: $scope.getWebUrl() + "/api/usercode/productcategorysearchoptions",
                    headers: {
                        "Authorization": jwtService.getPrincipalToken()
                    }
                }).then(
                    function (result) {
                        $scope.$broadcast("mainSectionReady");
                        $scope.searchCategories = result.data.searchCategories;
                        var constants = jQuery.parseJSON($($element).find("#hdSearchCategoryConstants").val());
                        //var mainSectionId = $($element).data("sectionid");
                        for (var i = 0; i < $scope.searchCategories.length; i++) {
                            jQuery.each(constants, function (j, val) {
                                if ($scope.searchCategories[i].LinkId.toLocaleLowerCase().indexOf(val.Name.toLowerCase()) >= 0) {
                                    $scope.searchCategories[i].URL = val.Url;
                                    $scope.searchCategories[i].imageURL = val.SectionImageUrl; //TODO:Remove it once the image exists from api
                                    if ($scope.mainSectionId && val.Name.toLowerCase().indexOf($scope.mainSectionId.toLowerCase()) >= 0) {
                                        $scope.mainSection = $scope.searchCategories[i];
                                    }
                                }
                            });
                        }
                        $scope.isLoading = false;
                    },
                    function (response) {
                        $scope.isLoading = false;
                        console.log(response);
                    }
                );

                return false;
            };

            $scope.toggleModal = function (name) {
                $scope.showModal[name] = $scope.showModal[name] === null ? false : !$scope.showModal[name];
                return false;
            };

            $scope.closeMobileMenu = function () {
                jQuery(".mobile-menu-wrapper").removeClass("menu-open");
                jQuery("a.hamburger-menu:first img").show();
                return false;
            };
            window.addEventListener("resize", $scope.closeMobileMenu);

            $scope.showModalWithData = function (name, data) {
                $scope.showModal[name] = true;
                $scope.modalData[name] = data;
                return false;
            };

            $scope.toggleModalWithData = function (name, data) {
                $scope.showModal[name] = $scope.showModal[name] === null ? false : !$scope.showModal[name];
                $scope.modalData[name] = data;
                return false;
            };

            $scope.getCustomer = function () {
                if ($scope.customer == null) {
                    $scope.customer = jwtService.getCustomer();
                }
                return $scope.customer;
            };

            $scope.setLanguage = function (selectedLang) {
                shoppingCartService.utils.setEnhancePageVisited(true); // reset value to allow visiting the enhance booking page again

                var currRegionCode = $scope.selectedLanguage.geographyCode || $scope.anonymGeneralUser.geographyCode
                    || ($scope.anonymGeneralUser.languages && $scope.anonymGeneralUser.languages[0] && $scope.anonymGeneralUser.languages[0].geographyCode);


                $scope.selectedLanguage = selectedLang;


                if (currRegionCode) {
                    var currRegionCodeAdjustedFromUrl = null;
                    var startPos = window.location.pathname.toLowerCase().indexOf(currRegionCode.toLowerCase());
                    if (startPos >= 0) {
                        var ending = window.location.pathname.toLowerCase().indexOf("/", startPos);

                        currRegionCodeAdjustedFromUrl = window.location.pathname.substring(startPos, ending > -1 ? ending : currRegionCode.length);
                    }
                    window.location.pathname = utilsFactory.addPersistentQueryStringsParams(window.location.pathname.replace(currRegionCodeAdjustedFromUrl || currRegionCode, $scope.selectedLanguage.geographyCode));
                } else {
                    window.location.pathname = utilsFactory.addPersistentQueryStringsParams("/" + $scope.selectedLanguage.geographyCode);
                }
            };

            $scope.saveCustomer = function () {
                jwtService.setCustomer($scope.customer);
                $scope.$broadcast("customer-changed", {});
            };
            $scope.initCustomerRecordWithCallback = function (reinitCustomerData, callback) {
                if (jwtService.getCustomerToken() == null) {
                    $scope.customer = null;
                    $scope.saveCustomer();
                    if (callback) {
                        callback(false);
                    }
                    return false;
                }

                $scope.getCustomer();

                if (!reinitCustomerData && $scope.customer) {
                    if (callback) {
                        callback(true);
                    }
                    return false;
                }

                $scope.customer = null;
                $scope.getCustomerLoading = true;

                $http({
                    method: "GET",
                    url: $scope.getWebUrl() + "/api/customer/me",
                    headers: {
                        "Authorization": jwtService.getCustomerToken()
                    }
                }).then(
                    function (result) {
                        if (result.data && result.data.customers && result.data.customers.length > 0) {
                            $scope.customer = result.data.customers[0];
                        } else {
                            $scope.customer = null;
                            localStorageService.remove("customerToken");
                        }
                        $scope.saveCustomer();
                        $scope.getCustomerLoading = false;

                        if (callback) {
                            callback(true);
                        }
                    },
                    function (response) {
                        localStorageService.remove("customerToken");
                        if (callback) {
                            callback(false);
                        }
                        $scope.getCustomerLoading = false;
                        console.log(response);
                    }
                );
                return false;
            };

            $scope.initCustomerRecord = function (reinitCustomerData) {
                $scope.initCustomerRecordWithCallback(reinitCustomerData, null);
            };

            $scope.refreshCart = function (newToken, callback) {
                shoppingCartService.getStorageCart(function (shoppingCart) {
                    if (shoppingCart && (shoppingCart.Items || "").length) {
                        var requestParams = {
                            apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                            token: newToken || jwtService.getPrincipalToken(),
                            promoCodes: shoppingCart.DiscountCodes
                        };

                        shoppingCartService.refreshPromoCodesQuote(requestParams, function (shoppingCart) {
                            callback();
                        });
                    } else
                        callback();
                });
            };

            $scope.logOut = function () {
                $scope.customer = null;
                $scope.isLoading = true;
                //$scope.refreshCart(function () {
                $scope.isLoading = false;
                if (localStorageService.isSupported) {
                    jwtService.clearStorage(true);
                    localStorageService.remove("customer");
                    localStorageService.remove("customerToken");
                    localStorageService.remove("customerLoginEmail");

                    //
                    localStorageService.remove("token");
                    localStorageService.remove("geographyCode");
                }

                $rootScope.$broadcast("LoggedOut", {

                });

                $scope.initCustomerRecord();

                jwtService.customerLogout($scope.getWebUrl(), function () {
                    window.location.href = utilsFactory.addPersistentQueryStringsParams("/LogoutRedirect");
                });
                // });
            };

            $scope.hasMainSections = function () {
                return $($element).hasClass("home-page") || $($element).data("sectionid");
            };


            // GDPR Cookie Notice
            $scope.allowCookies = {
                createCookie: function (name, value, days) {

                    var expires;
                    if (days) {
                        var date = new Date();
                        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
                        expires = "; expires=" + date.toGMTString();
                    }
                    else {
                        expires = "";
                    }

                    var hostname = window.location.hostname.replace("www.", "");
                    if ((hostname.match(/\./g) || []).length > 1) {
                        hostname = hostname.substr(hostname.indexOf('.'));
                    }
                    if ((hostname.match(/\./g) || []).length > 1 && hostname[0] != '.') {
                        hostname = "." + hostname;
                    }
                    document.cookie = name + "=" + value + expires + "; path=/;domain=" + hostname;
                },
                getCookie: function (cName) {
                    if (document.cookie.length > 0) {
                        var cStart = document.cookie.indexOf(cName + "=");
                        if (cStart != -1) {
                            cStart = cStart + cName.length + 1;
                            var cEnd = document.cookie.indexOf(";", cStart);
                            if (cEnd == -1) {
                                cEnd = document.cookie.length;
                            }
                            return unescape(document.cookie.substring(cStart, cEnd));
                        }
                    }
                    return "";
                },
                init: function (cookieName) {
                    // set policy link
                    var hostname = window.location.hostname.replace("www.", "");
                    if ((hostname.match(/\./g) || []).length > 1) {
                        hostname = hostname.substr(hostname.indexOf('.') + 1);
                    }
                    $scope.cookiePolicyLink = window.location.protocol + "//" + hostname + "/privacy-policy/#Inquire";

                    var self = this;

                    // check cookie
                    if (!self.getCookie(cookieName)) {
                        jQuery("body").addClass("cookieNoticeOpen");
                        setTimeout(function () {
                            jQuery(".CookieConsent").slideDown(400);
                            jQuery(".CookieConsentMobile").slideDown(400, function () {
                                // make cookie consent fixed
                                // jQuery(this).addClass("fixed");
                                //var placeholder = jQuery('<div/>', {
                                //    id: 'CookieConsentMobilePlaceholder'
                                //});
                                //placeholder.height(jQuery(this).height() || 78);
                                //placeholder.addClass('CookieConsentMobile');
                                //jQuery(this).after(placeholder);
                            });
                        }, 700);
                    }

                    jQuery(".acceptCookieConsent").click(function () {
                        jQuery("body").removeClass("cookieNoticeOpen");
                        // set cookie
                        self.createCookie(cookieName, 1, 365);
                        jQuery(".CookieConsent").slideUp(400, function () {
                            jQuery(window).resize();
                            $scope.$apply();
                        });
                        jQuery(".CookieConsentMobile").slideUp();
                    });


                }
            };

            $scope.initExitIntentPopup = function (popupHtmlMsg) {
                $scope.wasExitModalShown = false;
                var displayModal = function () {
                    $scope.wasExitModalShown = true;

                    var isExitIntentDisabled = jwtService.getIsDisabledExitIntent();
                    if (isExitIntentDisabled) return;

                    var intentModalInstance = $uibModal.open({
                        animation: true,
                        templateUrl: "exitIntentPopupPartial.html",
                        controller: "exitIntentPopupCtrl",
                        size: "lg",
                        resolve: {
                            popupData: { popupContent: popupHtmlMsg }
                        },
                        backdrop: "true"
                    });

                    intentModalInstance.result.then(function (result) {
                        // ok btn
                    }, function () {
                        // cancel
                    });
                };
                // separate functionality for mobile
                var isMobile = (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent));


                if (isMobile) {
                    var getBodyScrollTop = function () {
                        var el = document.scrollingElement || document.documentElement;
                        return el.scrollTop;
                    }

                    // Let the user scroll up by some significant amount
                    var percentUp = 250;
                    var scrollInterval = 150;

                    var scrollStart = getBodyScrollTop();
                    var pageHeight = document.documentElement.offsetHeight;

                    var interval = null;

                    if (pageHeight > 0) {
                        // Only check the scroll position every few seconds, to avoid bogging the UI
                        interval = setInterval(function () {

                            if ($scope.wasExitModalShown) {
                                clearInterval(interval);
                                interval = null;
                                return;
                            }

                            var scrollAmount = scrollStart - getBodyScrollTop();
                            if (scrollAmount < 0) {
                                scrollAmount = 0;
                                scrollStart = getBodyScrollTop();
                            }

                            var upScrollPercent =
                                parseFloat(scrollAmount) / parseFloat(pageHeight);
                            if (upScrollPercent > parseFloat(percentUp) / 100) {
                                // cancel if a dropdown was clicked
                                if (jQuery("md-select[aria-expanded=true]").length) {
                                    return;
                                }

                                displayModal();
                            }
                        }, scrollInterval);
                    }

                }

                jQuery(document).mouseout(function (e) {
                    if ($scope.wasExitModalShown) return;

                    e = e ? e : window.event;

                    // If this is an autocomplete element.
                    if (e.target.tagName.toLowerCase() == "input")
                        return;

                    // Get the current viewport width.
                    var vpWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);

                    // If the current mouse X position is within 50px of the right edge
                    // of the viewport, return.
                    if (e.clientX >= (vpWidth - 50))
                        return;

                    // If the current mouse Y position is not within 50px of the top
                    // edge of the viewport, return.
                    if (e.clientY >= 50)
                        return;

                    // Reliable, works on mouse exiting window and
                    // user switching active program
                    var from = e.relatedTarget || e.toElement;
                    if (from) return;
                    displayModal();
                });
            };

            $scope.checkExitIntentPopup = function (anonymGeneralUser, productCode) {
                if (!productCode || !anonymGeneralUser) return;

                var isExitIntentDisabled = jwtService.getIsDisabledExitIntent();
                if (isExitIntentDisabled) return;

                // disable for agents 
                var customerTokenObj = jwtService.getCustomerTokenObj();
                var isAgent = (customerTokenObj && customerTokenObj.loginType && customerTokenObj.loginType === "agent");
                if (isAgent) return;

                // check if to display the message 
                var selectedLanguage = anonymGeneralUser.selectedLanguage;
                var popupMsgData = ((selectedLanguage && selectedLanguage.userlabels || anonymGeneralUser)).exitIntentPopupContent;
                if (!popupMsgData) return;

                var popupMsg = null;

                if ((typeof popupMsgData) == "string") {
                    popupMsg = popupMsgData;
                } else if (Array.isArray(popupMsgData)) {
                    var popupMsgItem = _.find(popupMsgData, function (val) {
                        if (Array.isArray(val.productCode)) {
                            return val.productCode.indexOf(productCode) >= 0;
                        } else {
                            return val.productCode == productCode;
                        }
                    });

                    popupMsg = popupMsgItem && popupMsgItem.html;
                }

                if (popupMsg) {
                    setTimeout(function () {
                        $scope.initExitIntentPopup(popupMsg);
                    }, 0);
                }
            };


            function init() {
                var externalPromoCode = $("body").data("promocode");
                if (externalPromoCode) {
                    shoppingCartService.setExternalPromoCode(externalPromoCode);
                }

                setTimeout(function () {
                    $scope.allowCookies.init("brewster_cookieconsent");
                });

                jQuery("a.hamburger-menu:first").on("click", function () {
                    //if (jQuery(".menu-wrapper").length) {
                    //    jQuery(".menu-wrapper").toggleClass("menu-open");
                    //}
                    if (jQuery(".mobile-menu-wrapper").length) {

                        jQuery(".mobile-menu-wrapper").css('top', jQuery('.page-wrapper').position().top + 'px').toggleClass("menu-open");
                        jQuery("a.hamburger-menu:first img").hide();
                    }
                });
                //jQuery(".menu-wrapper .close:first").on("click", function () {
                //    jQuery(".menu-wrapper").removeClass("menu-open");
                //});
                jQuery(".mobile-menu-wrapper .close:first").on("click", function () {
                    jQuery(".mobile-menu-wrapper").removeClass("menu-open");
                    jQuery("a.hamburger-menu:first img").show();
                });


                $scope.isLoading = true;

                var initLogoFn = $scope.actionRegionCode ? jwtService.getAnonymousUserByGeography.bind(jwtService, $scope.actionRegionCode)
                    : jwtService.getAnonymUserByDomain.bind(jwtService);

                jwtService.getAnonymousUserByGeography($scope.actionRegionCode, function (user, userNotFound) {
                    $scope.anonymGeneralUser = user;

                    if (user && userNotFound) {
                        window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
                        return;
                    }

                    $scope.selectedLanguage = _.find($scope.anonymGeneralUser.languages, function (lang) {
                        return lang.geographyCode == $scope.actionRegionCode;
                    });

                    if (user && user.logo) {
                        $scope.logo = user.logo;
                        $scope.mobileLogo = user.mobileLogo;
                        $scope.footerLogo = user.footerLogo;
                        $scope.footerSecondaryLogo = user.footerSecondaryLogo;
                    }
                    $scope.logoLinkUrl = ($scope.selectedLanguage && $scope.selectedLanguage.logoLinkUrl) || $scope.anonymGeneralUser.logoLinkUrl;

                    $scope.loadingMsg = ($scope.selectedLanguage && $scope.selectedLanguage.userlabels && $scope.selectedLanguage.userlabels.loadingMsg) || $scope.loadingMsg;

                    if (user && user.callCentrePhone) {
                        $scope.phone = $scope.selectedLanguage && $scope.selectedLanguage.callCentrePhone || user.callCentrePhone;
                    }


                    $scope.isFOC = ($scope.actionRegionCode || "").indexOf("FOC") >= 0 ? "-FOC" : "";

                    //
                    initLogoFn(function (ldata) {
                        if (ldata) {
                            $scope.logo = (typeof ldata == "string") ? ldata :
                                (ldata.logo ? ldata.logo : $scope.logo);

                            $scope.mobileLogo = ldata.mobileLogo || $scope.mobileLogo;
                            $scope.footerLogo = ldata.footerLogo || $scope.footerLogo;
                            $scope.footerSecondaryLogo = ldata.footerSecondaryLogo || $scope.footerSecondaryLogo;

                            $scope.logoLinkUrl = ($scope.selectedLanguage && $scope.selectedLanguage.logoLinkUrl) || $scope.anonymGeneralUser.logoLinkUrl;

                            $scope.loadingMsg = ($scope.selectedLanguage && $scope.selectedLanguage.userlabels && $scope.selectedLanguage.userlabels.loadingMsg) || $scope.loadingMsg;

                            if (ldata.callCentrePhone) {
                                $scope.phone = $scope.selectedLanguage && $scope.selectedLanguage.callCentrePhone || ldata.callCentrePhone;
                            }
                        }

                        $scope.isFOC = ($scope.selectedGeographyCode || "").indexOf("FOC") >= 0 ? "-FOC" : "";
                        jwtService.setPrincipalTokenAndRegionAsync($scope.getWebUrl(),
                            $scope.actionRegionCode // ($scope.anonymGeneralUser && $scope.anonymGeneralUser.geographyCode) ||
                            , $scope.trackingInfo
                            , function (token) {
                                $scope.selectedGeographyCode = jwtService.getGeography();
                                initMultiCurrencies();

                                $scope.isFOC = ($scope.selectedGeographyCode || "").indexOf("FOC") >= 0 ? "-FOC" : "";

                                //jwtService.getAnonymousUserByGeography($scope.selectedGeographyCode, function (user) {
                                //    $scope.anonymGeneralUser = user;

                                //    $scope.selectedLanguage = _.find($scope.anonymGeneralUser.languages, function (lang) {
                                //        return lang.geographyCode == $scope.selectedGeographyCode;
                                //    });

                                //    if (user && user.logo) {
                                //        $scope.logo = user.logo;
                                //    }

                                //    if (user && user.callCentrePhone) {
                                //        $scope.phone = user.callCentrePhone;
                                //    }

                                //    $scope.isFOC = ($scope.selectedGeographyCode || "").indexOf("FOC") >= 0 ? "-FOC" : "";
                                //});

                                //if ($scope.selectedGeographyCode != $scope.actionRegionCode) {


                                //} else {
                                //    $scope.isFOC = $scope.selectedGeographyCode == "FOC" ? "-FOC" : "";
                                //}
                                //$scope.checkExitIntentPopup();
                                $scope.getGeographiesAsync(function () {
                                    $scope.getProductCategorySearchOptionsAsync(function () {
                                        taskFactory.filtersTask = { name: "FiltersInit", data: 1 };
                                        $scope.isLoading = false;

                                        $scope.initCustomerRecord();
                                        //
                                        var loginParam = utilsFactory.getQueryStringParameterByName("login");
                                        if (!$scope.isLoggedIn() && loginParam && (String(loginParam).toLowerCase() == "true" || loginParam == true || loginParam == "1")) {
                                            $scope.toggleModal('Login');
                                        }
                                        //

                                        $scope.generalCtrlReady = true;
                                        $rootScope.$broadcast("generalCtrlReady");

                                        // tracking 
                                        var shouldInitTrackObjGeneral = !$("div[ng-controller='printOrderCtrl']").length && !$("div[ng-controller='transportationDetailsCtrl']").length && !$("div[ng-controller='activityDetailsCtrl']").length && !$("div[ng-controller='hotelDetailsCtrl']").length;
                                        if (shouldInitTrackObjGeneral) {
                                            shoppingCartService.getStorageCart(function (shoppingCart) {
                                                var trackerReq = {
                                                    lobTitle: null,
                                                    packageName: null,
                                                    searchDate: null,
                                                    adults: null,
                                                    children: null,
                                                    shoppingCart: shoppingCart,
                                                    anonymUser: $scope.anonymGeneralUser,
                                                    bookingNumber: null,
                                                    bookingId: null
                                                };
                                                trackingService.buildFlowTrackerObj(trackerReq);
                                            });
                                        }

                                        $scope.$watch("detailsInitialized", function () {
                                            if ($scope.detailsInitialized) {
                                                $rootScope.$broadcast("generalControllerInitilized");
                                            }
                                        });
                                    });
                                });
                            });
                    });
                    //
                });



                setHeight();
                $($window).bind("resize", function () {
                    setHeight();
                    $scope.$apply();
                });
            }

            init();

            $scope.$on("activityDetailsCtrlInitialized", function (event, data) {
                $scope.detailsInitialized = true;
            });

            $scope.$on("transportationDetailsCtrlInitialized", function (event, data) {
                $scope.detailsInitialized = true;
            });

            $scope.$on("hotelDetailsCtrlInitialized", function (event, data) {
                $scope.detailsInitialized = true;
            });


        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("productDetailsWrapperCtrl", [
        "$scope", "$state", "$element", "$http", "localStorageService", "jwtService", function ($scope, $state, $element, $http, localStorageService, jwtService) {
            $scope.showModal = {};
            $.material.init();
            $scope.isLoading = false;

            $scope.isCreateButtonVisible = true;
            $scope.checkoutScope = null;

            $scope.createAccountModel = {
                response: null,
                username: "",
                firstName: "",
                lastName: "",
                password: "",
                password_c: "",
                emailAddress: "",
                emailAddress_c: "",
                submitted: false,
                errors: []
            }

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            $scope.createBookingCallback = undefined;

            $scope.createAccount = function (isValid) {
                var token = jwtService.getPrincipalToken();

                $scope.createAccountModel.submitted = true;
                var generalCtrl = $scope.$parent;

                if (isValid) {

                    $scope.isLoading = true;

                    if ($scope.isLoading === true) {
                        var dataToPost = {
                            "Email": $scope.createAccountModel.emailAddress,
                            "FirstName": $scope.createAccountModel.firstName,
                            "LastName": $scope.createAccountModel.lastName,
                            "Username": $scope.createAccountModel.emailAddress,
                            "Password": $scope.createAccountModel.password
                        }

                        $http({
                            method: "POST",
                            url: $scope.getWebUrl() + "/api/authentication/register",
                            headers: {
                                "Authorization": token,
                                "Content-Type": "application/json"
                            },
                            data: dataToPost
                        })
                        .then(
                            function (result) {
                                if (!result || !result.data) {
                                    $scope.registerModel.error = "An error occurred during registration. Please try again later.";
                                    $scope.isLoading = false;
                                } else {
                                    if (result.data.token) {
                                        jwtService.setCustomerToken(result.data);

                                        if (generalCtrl.initCustomerRecordWithCallback) {
                                            generalCtrl.initCustomerRecordWithCallback(true, function() {
                                                $scope.showModal["CreateAccount"] = false;
                                                $scope.isCreateButtonVisible = false;
                                                $scope.checkoutScope.isCreateButtonVisible = false;
                                                $scope.isLoading = false;
                                            });
                                        }
                                    } else {
                                        if (result.data.errors && result.data.errors.length > 0) {
                                            $scope.createAccountModel.errors = result.data.errors;
                                        }

                                        $scope.isLoading = false;
                                    }
                                }
                            },
                            function (response) {
                                $scope.isLoading = false;

                                if (response.data.errors && response.data.errors.length > 0) {
                                    $scope.createAccountModel.errors = response.data.errors;
                                } else {
                                    $scope.createAccountModel.error.push("An error occurred registration. Please try again later.");
                                }
                                
                                console.log(response);
                            });
                    }
                }

                return false;
            };

            $scope.createAnAccountClick = function (checkoutScope) {
                $scope.createAccountModel.submitted = false;
                $scope.createAccountModel.errors = [];
                $scope.checkoutScope = checkoutScope;
                $scope.showModal["CreateAccount"] = $scope.showModal["CreateAccount"] === null ? false : !$scope.showModal["CreateAccount"];
            };

            $scope.init = function () {
                if (jwtService.getCustomer()) {
                    $scope.isCreateButtonVisible = false;
                }

                jwtService.setProductCategory(jQuery($element).data("category"));
            };

            $scope.init();
        }
    ]);
})(jQuery);;
console.log("Init V2025-06-10-v1");
;
(function ($) {
    "use strict";

    angular.module("app").controller("accountAgencyContactsCtrl", [
       "userService", "utilsFactory", "$scope", "$state", "customerService", "jwtService", "paymentService",
        function (userService, utilsFactory, $scope, $state, customerService, jwtService, paymentService) {

            $scope.utils = utilsFactory;
            $.material.init();

            $scope.isLoading = true;
            var webUrl = ($("body").data("weburl") ? $("body").data("weburl") : "");
            var timeoutId = null;
            function resizeSliderPanel() {
                window.clearTimeout(timeoutId);
                timeoutId = setTimeout(function () {
                    jQuery(window).resize();
                }, 100);
            }

            $scope.addAgencyContactModel = {
                firstName: "",
                lastName: ""
            };

            $scope.deleteContact = function (id, msg) {
                var dlt = confirm(msg);
                if (!dlt) {
                    return false;
                }
                var requestParams = {
                    id: id,
                    token: jwtService.getCustomerToken()
                };
                $scope.isLoading = true;
                resizeSliderPanel();
                $scope.resetAddAgencyContactForm();
                customerService.deleteAgencyContact(requestParams, function (result) {
                    $scope.isLoading = false;
                    resizeSliderPanel();
                    $scope.getAgencyContacts();
                });
            };

            $scope.resetAddAgencyContactForm = function () {
                $scope.addAgencyContactModel.firstName = "";
                $scope.addAgencyContactModel.lastName = "";
                $scope.addAgencyContactModel.submitted = false;
                $scope.addAgencyContactModel.showResponse = false;
            };

            $scope.submitAddAgencyContact = function (isValid) {
                if ($scope.isLoading)
                    return false;
                $scope.addAgencyContactModel.submitted = true;
                if (!isValid) return false;
                $scope.isLoading = true;
                resizeSliderPanel();
                $scope.errors = [];
                customerService.addAgencyContact({
                    token: jwtService.getCustomerToken(),
                    dataToPost: {
                        "FirstName": $scope.addAgencyContactModel.firstName,
                        "LastName": $scope.addAgencyContactModel.lastName
                    }
                }, function (result) {
                    if (!result.success || ((result.data && result.data.errors) || "").length) {
                        $scope.addAgencyContactModel.showResponse = false;
                        $scope.addAgencyContactModel.errors = (result.data && result.data.errors) ?
                            _.pluck(result.data.errors, "errorMessage") : ["An error has occured!"];
                        // $scope.isLoading = false;
                        $scope.getAgencyContacts();
                    }
                    else {
                        $scope.addAgencyContactModel.submitted = false;
                        $scope.addAgencyContactModel.firstName = "";
                        $scope.addAgencyContactModel.lastName = "";

                        $scope.addAgencyContactModel.showResponse = true;
                        $scope.getAgencyContacts();
                    }


                });
                return true;
            };

            $scope.getAgencyContacts = function () {
                $scope.isLoading = true;
                resizeSliderPanel();
                customerService.getAgencyContactsAsync({ token: jwtService.getPrincipalToken() },
                    function (result) {
                        if (result.success && result.data) {
                            $scope.agencyContacts = result.data.customers;
                        }
                        $scope.isLoading = false;
                        resizeSliderPanel();
                    });
            };

            $scope.getAgencyContacts();

        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("accountBookingsCtrl", [
        "utilsFactory", "jwtService", "$scope", "$state", "$rootScope", "validHelper", "customerService", "$element", "$window", "shoppingCartService", "$timeout",
        function (utilsFactory, jwtService, $scope, $state, $rootScope, validHelper, customerService, $element, $window, shoppingCartService, $timeout) {


            var webUrl = ($("body").data("weburl") ? $("body").data("weburl") : "");
            $.material.init();
            $scope.labelUtils = utilsFactory;
            $scope.utils = shoppingCartService.utils;
            $scope.validHelper = validHelper;
            $scope.isLoading = false;
            $scope.isItemLoading = {};


            $scope.upcomingBookings = [];
            $scope.historyBookings = [];

            $scope.cancelBookingModel = {};
            $scope.viewBookingModal = {};
            var SearchType = { "travelDate": 1, "bookingDate": 2, "name": 3, "bookingNo": 4 };
            $scope.searchType = SearchType.travelDate;

            $scope.$on("customer-changed", function (event, args) {
                $scope.init();
            });

            function checkIfLogedIn() {
                var token = jwtService.getCustomerToken();
                if (!token || token.length === 0) {
                    $window.location.href = "/";
                    return false;
                }
                return true;
            }

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;

                for (var propertyName in $scope.isItemLoading) {
                    $scope.isItemLoading[propertyName] = false;
                }

            });

            $scope.search = function () {
                if ($scope.isLoading) return;

                $scope.filter.wasSearch = true;
                $scope.isLoading = true;
                resizeSliderPanel();

                $scope.bookings = [];
                $scope.historyBookings = [];
                $scope.upcomingBookings = [];
                var requestParams = {};

                if ($scope.searchType === SearchType.bookingNo) {
                    if (!$scope.filter.bookingNumber) {
                        $scope.isLoading = false;
                        $scope.filter.wasSearch = false;
                        return;
                    }

                    requestParams = {
                        apiUrl: webUrl + "/api/booking/customerbooking",
                        token: jwtService.getCustomerToken(),
                        bookingNumber: $scope.filter.bookingNumber
                    };
                    customerService.customerBooking(requestParams, function (result) {
                        if (result && result.data) {
                            processBookings(result.data);
                        }
                        $scope.isLoading = false;

                        resizeSliderPanel();
                    });
                } else {
                    if ($scope.searchType === SearchType.name) {
                        if (($scope.filter.firstName || "").trim().length || ($scope.filter.lastName || "").trim().length) {
                            requestParams = {
                                apiUrl: webUrl + "/api/booking/BookingSummariesByCustomerName?firstName=" + ($scope.filter.firstName || "").trim() + "&lastName=" + ($scope.filter.lastName || "").trim(),
                                token: jwtService.getCustomerToken()
                            };
                        } else {
                            $scope.isLoading = false;
                            $scope.filter.wasSearch = false;
                        }
                    }
                    else {
                        if ($scope.searchType === SearchType.travelDate) {
                            var startdate = $("#startdaterange").val();
                            var enddate = $("#enddaterange").val();

                            var strStartDate = moment(startdate, shoppingCartService.getDateFormat()).format("YYYY-MM-DD");
                            var strEndDate = moment(enddate, shoppingCartService.getDateFormat()).format("YYYY-MM-DD");

                            requestParams = {
                                apiUrl: webUrl + "/api/booking/customerbookingsummaries?travelStart=" + strStartDate + "&travelEnd=" + strEndDate,
                                token: jwtService.getCustomerToken()
                            };
                        } else if ($scope.searchType === SearchType.bookingDate) {
                            var bookingDate = $("#bookdaterange").val();
                            var strBookingDate = moment(bookingDate, shoppingCartService.getDateFormat()).format("YYYY-MM-DD");


                            requestParams = {
                                apiUrl: webUrl + "/api/booking/customerbookingsummaries?bookedOnDate=" + strBookingDate,
                                token: jwtService.getCustomerToken()
                            };
                        }
                    }

                    customerService.customerBookingSummaries(requestParams, function (result) {
                        $scope.isLoading = false;
                        resizeSliderPanel();
                        if (result && result.data) {
                            processBookings(result.data);
                        }
                    });
                }


            };

            function processBookings(data) {
                var today = new Date().getTime();
                _.map(data.bookings, function (booking) {
                    booking.guests = _.map(booking.customers, function (customer) {
                        return customer.fullName;
                    }).join();

                    if ((booking.components && booking.components.length) || (booking.packages || '').length) {

                        //var hasAttraction = false;
                        //booking.components && _.each(booking.components, function (component) {
                        //    if (hasAttraction) return;
                        //    hasAttraction = component.productCategory == 'Attraction' && component.productType == 'ATTR';
                        //});

                        //if (!hasAttraction) {
                        //    booking.packages && _.each(booking.packages, function (pkg) {
                        //        if (hasAttraction || pkg.type != "COMBO") return;

                        //        pkg.Components && _.each(pkg.Components, function (pkgComp) {
                        //            if (hasAttraction) return;
                        //            hasAttraction = pkgComp.ProductCategory == 'Attraction' && pkgComp.ProductType == 'ATTR';
                        //        });
                        //    });
                        //}

                        booking._canCancel = true; // !hasAttraction;

                        booking.displayTitle = "";
                        if ((booking.components || '').length) {
                            booking.displayDate = moment(booking.components[0].startDate);

                            for (var i = 0; i < booking.components.length; i++) {
                                var cDate = moment(booking.components[i].startDate);
                                if (cDate < booking.displayDate) {
                                    booking.displayDate = cDate;
                                }

                                booking.displayTitle = $scope.appentTitle(booking.displayTitle, booking.components, i);
                            }
                        } else if ((booking.packages || '').length) {
                            booking.displayDate = moment(booking.packages[0].StartDate);
                        } else {
                            booking.displayDate = moment(booking.created).add("5", "d");
                        }

                        /*_.map(booking.components, function (component) {
                            var cDate = moment(component.startDate);
                            if (cDate < booking.displayDate) {
                                booking.displayDate = cDate;
                            }

                            booking.displayTitle += (booking.displayTitle.length ? ", " : "") + ((component.productDescriptions && component.productDescriptions.titles && component.productDescriptions.titles.length > 0) ? component.productDescriptions.titles[0] : component.description);
                        });*/

                        if (booking.displayDate >= today) {
                            $scope.upcomingBookings.push(booking);
                        } else {
                            $scope.historyBookings.push(booking);
                        }
                    } else {
                        booking.displayTitle =
                            booking.status.toLowerCase().indexOf('cancel') < 0 ?
                                "Booking #" + booking.bookingNumber : booking.status;
                        $scope.historyBookings.push(booking);
                    }
                });
            }
            function bindBookings() {
                $scope.isLoading = true;



            }

            $scope.appentTitle = function (currentTitle, components, index) {
                var title = "";
                if (components[index].productCategory === "Transportation") {
                    title = shoppingCartService.utils.getTransportationProductName(components[index], components, index);
                } else {
                    title = components[index].description;
                }

                currentTitle = currentTitle.length ? currentTitle + "<br/> " + title : title;

                return currentTitle;
            }

            $scope.handlePrint = function () {
                if (!checkIfLogedIn() || !$scope.viewBookingModel || !$scope.viewBookingModel.bookingNumber) return;
                var requestParams = {
                    //   apiUrl: webUrl + "/api/booking/bookinginvoice",
                    apiUrl: webUrl + "/api/booking/alldocuments",

                    token: jwtService.getCustomerToken(),
                    bookingNumber: $scope.viewBookingModel.bookingNumber
                };
                $scope.isItemLoading[$scope.viewBookingModel.bookingNumber] = true;
                //customerService.getBookingInvoice(requestParams, function (result) {
                //    $scope.isItemLoading[$scope.viewBookingModel.bookingNumber] = false;
                //});

                customerService.getAllBookingDocuments(requestParams, function (result) {
                    $scope.isItemLoading[$scope.viewBookingModel.bookingNumber] = false;
                });

                //$(".print-order-body:first").print({
                //    globalStyles: true,
                //    mediaPrint: false,
                //    stylesheet: null,
                //    noPrintSelector: ".no-print",
                //    iframe: true,
                //    append: null,
                //    prepend: null,
                //    manuallyCopyFormValues: true,
                //    deferred: $.Deferred(),
                //    timeout: 250,
                //    title: "Booking #" + $scope.viewBookingModel.bookingNumber,
                //    doctype: '<!doctype html>'
                //});
            };

            $scope.getBookingDetails = function (item) {
                $scope.showModal["CancelBooking"] = false;

                if (!checkIfLogedIn() || !item || !item.bookingNumber) return;

                $scope.viewBookingModel = item;
                $scope.showModal["ViewBooking"] = true;

                if (item.details) {
                    $scope.isItemLoading[item.bookingNumber] = false;
                    return;
                } else {
                    $scope.isItemLoading[item.bookingNumber] = true;
                }

                var requestParams = {
                    apiUrl: webUrl + "/api/booking/customerbooking",
                    token: jwtService.getCustomerToken(),
                    bookingNumber: item.bookingNumber
                };
                customerService.customerBooking(requestParams, function (result) {
                    item.details = (result && result.data && result.data.bookings && result.data.bookings[0]) || (result && result.error && result.error.bookings && result.error.bookings[0]) || null;
                    $scope.isItemLoading[item.bookingNumber] = false;
                });
            };


            $scope.updateBooking = function (item) {
                if (item && item.bookingNumber) {
                    window.location = ($scope.selectedGeographyCode ? "/" + $scope.selectedGeographyCode : "") + "/loadbooking?BookingNumber=" + item.bookingNumber;
                    return;
                }
            };

            $scope.openCancelBookingModal = function (item) {
                $scope.cancelBookingModel = item;
                $scope.showModal["CancelBooking"] = true;
            };

            $scope.cancelBooking = function (item) {
                if (!checkIfLogedIn() || !item || !item.bookingId || $scope.isItemLoading[item.bookingNumber]) return;

                $scope.isItemLoading[item.bookingNumber] = true;
                item.wasCancelRequested = true;
                var requestParams = {
                    apiUrl: webUrl + "/api/booking/IBECancel",
                    token: jwtService.getCustomerToken(),
                    bookingNumber: item.bookingNumber,
                    bookingId: item.bookingId
                };
                customerService.cancelBooking(requestParams, function (result) {
                    $scope.isItemLoading[item.bookingNumber] = false;
                    if (result && result.success) {
                        item.details = null;
                        item.isCanceled = true;
                    }
                });
            };

            $scope.filter = {
                isLoading: false,
                wasSearch: false
            };

            var timeoutID = null;
            function resizeSliderPanel() {
                window.clearTimeout(timeoutID);

                timeoutID = setTimeout(function () {
                    jQuery(window).resize();
                }, 50);
            }

            $scope.setSerchByBookingDate = function () {
                $scope.filter.wasSearch = false;
                $scope.searchType = SearchType.bookingDate;
            };

            $scope.setSerchByTravelDate = function () {
                $scope.filter.wasSearch = false;
                $scope.searchType = SearchType.travelDate;
            };
            $scope.setSerchByName = function () {
                $scope.filter.wasSearch = false;
                $scope.searchType = SearchType.name;
            };
            $scope.setSerchByBookingNo = function () {
                $scope.filter.wasSearch = false;
                $scope.searchType = SearchType.bookingNo;
            };



            $scope.init = function () {
                if ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) {
                    moment.locale($scope.selectedLanguage.languageCode);
                }

                if (!checkIfLogedIn()) {
                    return;
                }

                var customer = jwtService.getCustomer();
                if (!customer) return;

                jQuery($element).find('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
                    setTimeout(function () {
                        jQuery(window).resize();
                    }, 0);
                });


                $scope.startdaterangepicker = $("#startdaterange").daterangepicker({
                    singleDatePicker: true,
                    //  minDate: moment(),
                    showDropdowns: true,
                    locale: {
                        format: shoppingCartService.getDateFormat()
                    }
                });

                $scope.enddaterangepicker = $("#enddaterange").daterangepicker({
                    singleDatePicker: true,
                    //  minDate: moment(),
                    showDropdowns: true,
                    locale: {
                        format: shoppingCartService.getDateFormat()
                    }
                });

                $scope.bookdaterangepicker = $("#bookdaterange").daterangepicker({
                    singleDatePicker: true,
                    //  minDate: moment(),
                    showDropdowns: true,
                    locale: {
                        format: shoppingCartService.getDateFormat()
                    }
                });

                $scope.startdaterangepicker.on("apply.daterangepicker", function (ev, picker) {
                    $scope.filter.wasSearch = false;
                });
                $scope.enddaterangepicker.on("apply.daterangepicker", function (ev, picker) {
                    $scope.filter.wasSearch = false;
                });
                // bindBookings();
            };

            var isGeneralCtrlReady = $scope.$parent.generalCtrlReady;
            if (isGeneralCtrlReady) {
                $timeout($scope.init);
            } else {
                $scope.$on("generalCtrlReady", function (event, args) {
                    $timeout($scope.init);
                });
            }


        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("accountChangeEmailPwdCtrl", [
       "utilsFactory","jwtService", "userService", "$scope", "$state", "$rootScope", "validHelper", "customerService", "$element", "$window",
        function (utilsFactory,jwtService, userService, $scope, $state, $rootScope, validHelper, customerService, $element, $window) {

            $scope.utils = utilsFactory;
            $.material.init();
            var webUrl = ($("body").data("weburl") ? $("body").data("weburl") : "");

            $scope.customer = jwtService.getCustomer();
            $scope.customerLogin = jwtService.getCustomerLogin();

            $scope.changeEmailModel = {
                emailAddress: "",
                oldEmailAddress: ($scope.customer && $scope.customer.email ? $scope.customer.email : ""),//$scope.customerLogin ? $scope.customerLogin : ,
                showResponse: false,
                submitted: false,
                isLoading: false,
                errors: []
            };

            $scope.resetPwdModel = {
                email: "",
                oldPassword: "",
                password: "",
                password_c: "",
                isLoading: false,
                showResponse: false,
                submitted: false,
                errors: []
            };

             
            $scope.submitChangeEmail = function (isValid) {
                if ($scope.changeEmailModel.isLoading)
                    return false;

                if (isValid) {
                    $scope.changeEmailModel.isLoading = true;
                    $scope.changeEmailModel.errors = [];
                    userService.changeEmail({
                        urlPrefix: webUrl,
                        token: jwtService.getCustomerToken(),
                        dataToPost: {
                            "OldEmailAddress": $scope.changeEmailModel.oldEmailAddress,
                            "NewEmailAddress": $scope.changeEmailModel.emailAddress
                        }
                    }, function (result) {
                        if (!result.success) {
                            $scope.changeEmailModel.showResponse = false;
                            $scope.changeEmailModel.errors = (result.error && result.error.errors) ?
                                _.pluck(result.error.errors, "errorMessage") : ["An error has occured!"];
                        }
                        else {
                            $scope.changeEmailModel.showResponse = true;
                        }

                        $scope.changeEmailModel.isLoading = false;
                    });
                }
                $scope.changeEmailModel.submitted = true;
                return true;
            };

            $scope.submitResetPassword = function (isValid) {
                if ($scope.resetPwdModel.isLoading)
                    return false;

                if (isValid) {
                    $scope.resetPwdModel.isLoading = true;
                    $scope.resetPwdModel.errors = [];

                    userService.updatePassword({
                        urlPrefix: webUrl,
                        token: jwtService.getCustomerToken(),
                        dataToPost: {
                            "Username": $scope.customerLogin,//jwtService.getCustomer().email,
                            "OldPassword": $scope.resetPwdModel.oldPassword,
                            "NewPassword": $scope.resetPwdModel.password
                        }
                    }, function (result) {
                        if (!result.success) {
                            $scope.resetPwdModel.showResponse = false;
                            $scope.resetPwdModel.errors = (result.error && result.error.errors) ?
                                _.pluck(result.error.errors, "errorMessage") : ["An error has occured!"];
                        }
                        else {
                            $scope.resetPwdModel.showResponse = true;

                            $scope.resetPwdModel.oldPassword = "";
                            $scope.resetPwdModel.password = "";
                            $scope.resetPwdModel.password_c = "";
                            $scope.resetPwdModel.password_c = "";

                            $scope.resetPwdModel.submitted = false;
                        }

                        $scope.resetPwdModel.isLoading = false;
                    });
                }
                $scope.resetPwdModel.submitted = true;
                return true;
            };

        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("accountCommissionsCtrl", [
        "utilsFactory", "jwtService", "$scope", "$state", "$rootScope", "validHelper", "customerService", "$element", "$window", "shoppingCartService",
        function (utilsFactory, jwtService, $scope, $state, $rootScope, validHelper, customerService, $element, $window, shoppingCartService) {

            var webUrl = ($("body").data("weburl") ? $("body").data("weburl") : "");
            $.material.init();
            $scope.labelUtils = utilsFactory;
            $scope.utils = shoppingCartService.utils;
            $scope.validHelper = validHelper;
            $scope.isLoading = false;
            $scope.totalSales = 0;
            $scope.totalCommissions = 0;
            var displayDateFormat = "DD MMM YYYY";

            $scope.$on("customer-changed", function (event, args) {
                $scope.init();
            });

            function checkIfLogedIn() {
                var token = jwtService.getCustomerToken();
                if (!token || token.length === 0) {
                    $window.location.href = "/";
                    return false;
                }
                return true;
            }

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            $scope.formatNumberWithComma = function (x) {
                if (isNaN(x)) x = 0;
                x = x.toFixed(2);
                var parts = x.toString().split(".");
                parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
                return parts.join(".");
            };

            $scope.formatNumber = function (x) {
                if (isNaN(x)) x = 0;
                return x.toFixed(2);
            };

            $scope.travelStart = $("#travelStart").daterangepicker({
                singleDatePicker: true,
                showDropdowns: true,
                locale: {
                    format: shoppingCartService.getDateFormat()
                }
            });

            $scope.travelEnd = $("#travelEnd").daterangepicker({
                singleDatePicker: true,
                showDropdowns: true,
                locale: {
                    format: shoppingCartService.getDateFormat()
                }
            });

            $scope.travelStart.on("apply.daterangepicker", function (ev, picker) {
                if ($scope.isLoading) return;
                if ($scope.travelEnd.data().daterangepicker.startDate
                    .isSameOrBefore($scope.travelStart.data().daterangepicker.startDate)) {
                    $scope.travelEnd.data().daterangepicker.setStartDate($scope.travelStart.data().daterangepicker.startDate);
                    $scope.travelEnd.data().daterangepicker.setEndDate($scope.travelStart.data().daterangepicker.startDate);
                }
                //$scope.getCommissions();
            });

            $scope.travelEnd.on("apply.daterangepicker", function (ev, picker) {
                if ($scope.isLoading) return;
                if ($scope.travelEnd.data().daterangepicker.startDate
                    .isSameOrBefore($scope.travelStart.data().daterangepicker.startDate)) {
                    $scope.travelStart.data().daterangepicker.setStartDate($scope.travelEnd.data().daterangepicker.startDate);
                    $scope.travelStart.data().daterangepicker.setEndDate($scope.travelEnd.data().daterangepicker.startDate);
                }
                //$scope.getCommissions();
            });

            $scope.handlePrint = function () {
                $(".commissions-container:first").print({
                    globalStyles: true,
                    mediaPrint: false,
                    stylesheet: null,
                    noPrintSelector: ".no-print",
                    iframe: true,
                    append: null,
                    prepend: null,
                    manuallyCopyFormValues: true,
                    deferred: $.Deferred(),
                    timeout: 250,
                    title: "Commisions from " + $scope.travelStart.data().daterangepicker.startDate.format(displayDateFormat) + " to " + $scope.travelEnd.data().daterangepicker.startDate.format(displayDateFormat),
                    doctype: '<!doctype html>'
                });
                // window.print();
            };

            $scope.getCommissions = function () {
                $scope.isLoading = true;
                $scope.commissions = [];
                $scope.totalSales = 0;
                $scope.totalCommissions = 0;

                var requestParams = {
                    token: jwtService.getCustomerToken(),
                    travelStart: $scope.travelStart.data().daterangepicker.startDate.format("YYYY-MM-DD"),
                    travelEnd: $scope.travelEnd.data().daterangepicker.startDate.format("YYYY-MM-DD")
                };
                customerService.agentCommissions(requestParams, function (result) {
                    $scope.isLoading = false;

                    if (result && result.data) {
                        $scope.commissions = _.map(result.data.commissions, function (com) {
                            com.bookedondatestr = moment(com.bookedondate).format(displayDateFormat);
                            com.startdatestr = moment(com.startdate).format(displayDateFormat);
                            com.totalcommissions = 0;
                            com.descriptions = "";
                            var devider = "";
                            com.totalsales = 0;
                            com.travelDate = undefined;
                            com.currency = com.componentcommissions && com.componentcommissions[0] && com.componentcommissions[0].currency;

                            _.each(com.componentcommissions, function (compItem) {
                                //if (!com.travelDate) {
                                //    com.travelDate = moment(compItem.travelDate);
                                //} else {
                                //    var compTravelDate = moment(compItem.travelDate);
                                //    if (com.travelDate < compTravelDate) {
                                //        com.travelDate = compTravelDate;
                                //    }
                                //}
                                com.totalcommissions += compItem.amount;
                                com.totalsales += compItem.commissionableamount;
                                com.descriptions += devider + compItem.description;
                                devider = " ";
                            });
                            // com.travelDateStr =com.travelDate && com.travelDate.format("DD-MM-YYYY");

                            $scope.totalSales += com.totalsales;
                            $scope.totalCommissions += com.totalcommissions;
                            if (!$scope.currency) {
                                $scope.currency = com.currency;
                            }

                            return com;
                        });
                    }
                    setTimeout(function () {
                        jQuery(window).resize();
                    });
                });
            };

            $scope.init = function () {
                if (!checkIfLogedIn()) {
                    return;
                }

                var customer = jwtService.getCustomer();
                if (!customer) return;
                if (!customer.isAgent) {
                    $state.go("account-info", {});
                    return;
                }

                $scope.getCommissions();
            };

            $scope.init();
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("accountMyCardsCtrl", [
       "userService", "utilsFactory", "$scope", "$state", "cresecureService", "jwtService", "paymentService","borgunPaymentService",
        function (userService, utilsFactory, $scope, $state, cresecureService, jwtService, paymentService, borgunPaymentService) {

            $scope.utils = utilsFactory;
            $scope.manageAccountCtrl = null;
            $scope.isLoading = true;
            $scope.creCards = [];
            $scope.selectedCreCard = null;
            $scope.deleteCardButtonDisabled = false;
            $scope.model = {               
                cardNumber: "",                
                expirationMonth: "",
                expirationYear: "",
                cvcCode: ""                
            };
            $scope.inlineCC = {
                errorList: []
            };
            $scope.availableCCYears = [];
            var currentYear = jwtService.getServerMomentDate().year();//new Date().getFullYear();

            for (var i = currentYear; i < currentYear + 10; i++) {
                var str = i.toString();
                $scope.availableCCYears.push(str);
            }

            $scope.availableMonths = [
                { text: "1", value: "01" }, { text: "2", value: "02" }, { text: "3", value: "03" }, { text: "4", value: "04" }, { text: "5", value: "05" }, { text: "6", value: "06" },
                { text: "7", value: "07" }, { text: "8", value: "08" }, { text: "9", value: "09" }, { text: "10", value: "10" }, { text: "11", value: "11" }, { text: "12", value: "12" }
            ];

            $scope.availableCountries = [
                {
                    name: "USA",
                    countryCode: "US"
                },
                {
                    name: "Canada",
                    countryCode: "CA"
                }
            ];

            $scope.selectCard = function (card) {
                $scope.selectedCreCard = card;
            }

            $scope.deleteCard = function (card) {
                $scope.isLoading = true;
                var cardid = card.cardid;
                var cardToken = card.cardTokenValue;

                if (cardToken) {
                    var foundCard = _.find($scope.creCards, function (card) {
                        return card.cardTokenValue === cardToken;
                    });

                    if (foundCard) {
                        $scope.deleteCardButtonDisabled = true;
                        var deleteParams = {
                            urlPrefix: ($("body").data("weburl") ? $("body").data("weburl") : ""),
                            token: jwtService.getPrincipalToken(),
                            cardToken: foundCard.cardTokenValue
                        }

                        borgunPaymentService.deleteCardById(deleteParams, function (deleteResult) {
                            $scope.deleteCardButtonDisabled = false;
                            $scope.selectedCreCard = null;

                            $scope.creCards = _.reject($scope.creCards, function (card) {
                                return card.cardTokenValue === cardToken;
                            });

                            $scope.isLoading = false;
                        });
                    } else {
                        $scope.isLoading = false;
                    }
                } else {
                    var foundCard = _.find($scope.creCards, function (card) {
                        return card.cardid === cardid;
                    });

                    if (foundCard) {
                        $scope.deleteCardButtonDisabled = true;
                        var deleteParams = {
                            urlPrefix: ($("body").data("weburl") ? $("body").data("weburl") : ""),
                            token: jwtService.getPrincipalToken(),
                            cardid: foundCard.cardid
                        }

                        paymentService.deleteCardById(deleteParams, function (deleteResult) {
                            $scope.deleteCardButtonDisabled = false;
                            $scope.selectedCreCard = null;

                            $scope.creCards = _.reject($scope.creCards, function (card) {
                                return card.cardid === cardid;
                            });

                            $scope.isLoading = false;
                        });
                    } else {
                        $scope.isLoading = false;
                    }
                }
              
            };

            $scope.addInlineCardClick = function () {
                var hasErrors = false;
                $scope.inlineCC.errors = [];

                if (BAPIjs.isValidCardNumber($scope.model.cardNumber) === false) {
                    $scope.inlineCC.errors.push($scope.labelUtils.getLabel("checkout.validation.card-invalid"));
                    hasErrors = true;
                }
                if (BAPIjs.isValidExpDate($scope.model.expirationMonth, $scope.model.expirationYear) === false) {
                    $scope.inlineCC.errors.push($scope.labelUtils.getLabel("checkout.validation.expiry-date"));
                    hasErrors = true;
                }
                if (BAPIjs.isValidCVC($scope.model.cvcCode) === false) {
                    $scope.inlineCC.errors.push($scope.labelUtils.getLabel("checkout.validation.cvc-invalid"));
                    hasErrors = true;
                }

                if (hasErrors) { return; }
                $scope.isLoading = true;
                $scope.showLoadValidCardMsg = true;
                // The function that parses the response from Borgun.
                var borgunResponseHandler = function (status, data) {
                    if (status.statusCode === 201) {
                        $scope.model.cardNumber = undefined;
                        $scope.model.expirationMonth = undefined;
                        $scope.model.expirationYear = undefined;
                        $scope.model.cvcCode = undefined;

                        // start
                        var tempCard = {
                            cardNumber: data.PAN,
                            expirationMonth: data.ExpMonth,
                            expirationYear: data.ExpYear,
                            enabled: data.Enabled,
                            used: data.Used,
                            token: data.Token,
                            validUntil: data.ValidUntil
                        };
                        if ($scope.model.useCustomerCard) {
                            tempCard.doNotSaveCardToken = { value: false };
                            tempCard.isTemp = true;
                        }

                        var customerToken = jwtService.getCustomerToken();
                        if (customerToken && !$scope.model.useCustomerCard) {
                            $scope.isLoading = true;
                            $scope.showLoadValidCardMsg = true;
                            try {
                                //try to persist card against user profile
                                var postParams = {
                                    urlPrefix: ($("body").data("weburl") ? $("body").data("weburl") : ""),
                                    token: jwtService.getCustomerToken(),
                                    cardToken: tempCard.token
                                }

                                borgunPaymentService.postCreditCard(postParams, function (postResult) {
                                    if (postResult.success && postResult.data && postResult.data.length > 0) {
                                        //data.push(postResult.data[0]);

                                        $scope.creCards = _.union([], postResult.data);
                                     //   var selectedCard = _.find($scope.creCards, function (cc) { return cc.cardCreated; });
                                    //    $scope.changedCurrentCard(selectedCard ? selectedCard : $scope.creCards[0]);
                                    } else {
                                        // data.push(tempCard);
                                        $scope.creCards.push(tempCard);
                                        //   $scope.creCards = data;
                                      //  $scope.changedCurrentCard(tempCard);
                                    }
                                    $scope.isLoading = false;
                                    $scope.showLoadValidCardMsg = false;
                                });
                            } catch (e) {
                                data.push(tempCard);

                                $scope.creCards = [].pushdata;
                                $scope.selectedCreCard = tempCard;


                                _.each($scope.creCards, function (val, index) { val.index = index; });
                                $scope.isLoading = false;
                                $scope.showLoadValidCardMsg = false;
                            }
                        } else {
                            $scope.creCards.push(tempCard);
                            $scope.selectedCreCard = tempCard;
                           // $scope.changedCurrentCard(tempCard);

                            _.each($scope.creCards, function (val, index) { val.index = index; });
                            $scope.isLoading = false;
                            $scope.showLoadValidCardMsg = false;
                        }

                        // end
                    } else if (status.statusCode === 401) {
                        console.log(status.statusCode + " " + status.message);
                        $scope.inlineCC.errors.push("An error occurred! " + (status.message || ''));
                        // Unauthorized                   
                        $scope.isLoading = false;
                        $scope.showLoadValidCardMsg = false;
                    } else if (status.statusCode) {
                        console.log(status.statusCode + " " + status.message);
                        $scope.inlineCC.errors.push("An error occurred! " + (status.message || ''));
                        $scope.isLoading = false;
                        $scope.showLoadValidCardMsg = false;
                    } else {
                        console.log(status.statusCode + " " + status.message);
                        $scope.inlineCC.errors.push("An error occurred! " + (status.message || ''));
                        $scope.isLoading = false;
                        $scope.showLoadValidCardMsg = false;
                    }
                };

                // Disable Pay button.
                // $('.submit-button').prop("disabled", true);
                // Request single use token from Borgun.
                BAPIjs.getToken({
                    'pan': $scope.model.cardNumber,
                    'expMonth': $scope.model.expirationMonth,
                    'expYear': $scope.model.expirationYear,
                    'cvc': $scope.model.cvcCode,
                    'tokenLifetime': 600
                }, borgunResponseHandler);

                // $scope.selectedCreCard = undefined;
                //$scope.model.cardNumber = "";
                //$scope.model.expirationMonth = "";
                //$scope.model.expirationYear = "";
                //$scope.model.cvcCode = "";
                $scope.addCartSubmitted = true;
            };

            $scope.addCardClick = function () {
                $scope.manageAccountCtrl.showModal["AddCard"] = true;
                $scope.manageAccountCtrl.addCartSubmitted = true;

                var customer = jwtService.getCustomer();

                var errors = $scope.getAddCardSummaryCustomerErrors(customer);

                if (errors.length > 0) {
                    $scope.manageAccountCtrl.showAddCardSummaryCusotmerErrors = true;
                    $scope.manageAccountCtrl.creSummaryCustomerErrors = errors;
                } else {
                    $scope.manageAccountCtrl.showAddCardSummaryCusotmerErrors = false;
                    $scope.manageAccountCtrl.creSummaryCustomerErrors = [];

                    var d = new Date();
                    var params = {
                        merchPass: $scope.anonymUser && $scope.anonymUser.creSecureMerchPass ? $scope.anonymUser.creSecureMerchPass : $("body").attr("data-cresecure-merchPass"),
                        allowed_types: $scope.anonymUser && $scope.anonymUser.allowedCardTypes ? $scope.anonymUser.allowedCardTypes : "Visa|MasterCard|American Express",
                        cre_tokenize: "store_only",
                        sessionId: "testSession123",
                        name: (customer.firstName||"") + " " + (customer.lastName||""),
                        formType: 0,
                        required: "minimum", //"all", // all/minimum
                        collectAddress: null,//2,
                        address: customer.address.street ? customer.address.street : "",
                        currency_code: jwtService.getCurrency(),
                        city: customer.address.city || "",
                        state: customer.address.additionalInfo || "",
                        zip: customer.address.postalCode || "",
                        country: customer.address.country ? cresecureService.getCountryCodeByName(customer.address.country, $scope.availableCountries) : "",
                        timestamp: d.getMilliseconds()
                    }

                    $scope.manageAccountCtrl.crescureIframeUrl = cresecureService.generateCreSecureIframeUrl(params);
                    $scope.manageAccountCtrl.urlModel = {
                        crescureIframeUrls: [$scope.manageAccountCtrl.crescureIframeUrl]
                    };
                }
            }

            $scope.getAddCardSummaryCustomerErrors = function (customerObject) {
                var errors = [];
                if (!customerObject) {
                    errors.push("customer is null");
                    return errors;
                } else {
                    if (!customerObject.firstName || customerObject.firstName === "") {
                        errors.push("First Name is required.");
                    }
                    if (!customerObject.lastName || customerObject.lastName === "") {
                        errors.push("Last Name is required.");
                    }
                    if (!customerObject.address) {
                        errors.push("Address is required.");
                    } else {
                        if (!customerObject.address.country) {
                            errors.push("Billing Country is required.");
                        }
                        if (!customerObject.address.city) {
                            errors.push("Billing City is required.");
                        }
                        if (!customerObject.address.street) {
                            errors.push("Billing Address is required.");
                        }
                        if (!customerObject.address.province) {
                            errors.push("Prov / State is required.");
                        }
                        if (!customerObject.address.postalCode) {
                            errors.push("Zip Code is required.");
                        }
                    }
                }

                return [];
                //return errors;
            };

            $scope.$on("add-cre-card-processed", function (event, args) {
                var tempCard = {
                    cardNumber: cresecureService.getParamValue("ccNumber", args),
                    expirationMonth: cresecureService.getParamValue("expMonth", args),
                    expirationYear: cresecureService.getParamValue("expYear", args),
                    cardType: cresecureService.getParamValue("ccType", args),
                    fullQuery: args
                };

                /*var foundCode = _.find($scope.creCards, function (card) {
                    return card.cardNumber.toLowerCase() === tempCard.cardNumber.toLowerCase();
                        /*&& card.expirationMonth.toLowerCase() === tempCard.expirationMonth.toLowerCase()
                        && card.expirationYear.toLowerCase() === tempCard.expirationYear.toLowerCase();#1#
                });*/

                /*if (!foundCode) {*/
                var postParams = {
                    urlPrefix: ($("body").data("weburl") ? $("body").data("weburl") : ""),
                    token: jwtService.getPrincipalToken(),
                    fullQuery: tempCard.fullQuery
                }
                $scope.isLoading = true;
                paymentService.postCreditCard(postParams, function (postResult) {
                    $scope.isLoading = false;
                    if (postResult.success) {
                        $scope.creCards = postResult.data; //.push(postResult.data[0]);
                        //$scope.selectedCreCard = postResult.data[0];

                        /*setTimeout(function () {
                            jQuery("#addCard").change();
                        }, 0);*/
                    }
                });
                /*}*/
            });

            //$scope.getCardForUI = function (card) {
            //    if (card.pacificcardtype && card.nameoncard) {
            //        return card.pacificcardtype + " - " + card.cardnumber + " - " + card.nameoncard + " - " + moment(card.expirydate).format("MM") + "/" + moment(card.expirydate).format("YYYY");
            //    }
            //    return   card.cardnumber  + " - " + moment(card.expirydate).format("MM") + "/" + moment(card.expirydate).format("YYYY");
            //}

            $scope.getCardForUI = function (card) {
                if (!card) return "";

                if (!card.expirationMonth || !card.expirationYear) {
                    if (card.expirydate) {
                        var expiryDate = moment(card.expirydate);
                        card.expirationMonth = expiryDate.format("MM");
                        card.expirationYear = expiryDate.format("YYYY");
                        return (card.cardnumber || card.cardNumber) + " - " + card.expirationMonth + "/" + card.expirationYear;
                    }
                }
                else {
                    return (card.cardnumber || card.cardNumber) + " - " + card.expirationMonth + "/" + card.expirationYear;
                }


                return (card.cardnumber || card.cardNumber);
            }

            $scope.getCreCardNumberParam = function (fullQueryString) {
                return cresecureService.getParamValue("ccNumber", fullQueryString);
            }

            $scope.init = function () {               
                if ($scope.isTempusPaymentProvider) {
                    $state.go("account-info");
                    return;
                }

                setTimeout(function () {
                    jQuery("input.form-control").change();
                });

                if ($scope.displayInlineCCInput) {
                    BAPIjs.setPublicToken($scope.anonymUser && $scope.anonymUser.borgunPublicApiKey);
                }

                $scope.manageAccountCtrl = $scope.$parent.$parent;

                var getParams = {
                    urlPrefix: ($("body").data("weburl") ? $("body").data("weburl") : ""),
                    token: jwtService.getPrincipalToken()
                }
                $scope.isLoading = true;
                var paymentServiceInstance = $scope.displayInlineCCInput ? borgunPaymentService : paymentService;
                paymentServiceInstance.getCreditCards(getParams, function (getResult) {
                    if (getResult.success) {
                        $scope.creCards = getResult.data;
                    }
                    $scope.isLoading = false;
                    
                });
            }


            $scope.getLocations = function (callback) {
                userService.getPersistedCountries(function (persistedResult) {
                    if (persistedResult.success && persistedResult.data && persistedResult.data.countries) {
                        $scope.availableCountries = persistedResult.data.countries;
                        callback();
                    } else {
                        var params = {
                            urlPrefix: $scope.$parent.getWebUrl(),
                            token: jwtService.getPrincipalToken()
                        };
                        userService.getCountries(params, function (countriesResult) {
                            if (countriesResult.success && (countriesResult.data || "").length) {
                                $scope.availableCountries = countriesResult.data;
                                userService.persistCountries(countriesResult.data, function () { });
                            }
                            callback();
                        });
                    }
                }); 
            };

           

            $scope.anonymUser = undefined;
            $scope.initCurrentAnonymUser = function (callback) {
                jwtService.getAnonymousUserByGeography($scope.$parent.$parent.selectedGeographyCode, function (user) {
                    $scope.anonymUser = user;
                    $scope.displayInlineCCInput = $scope.anonymUser && ($scope.anonymUser.ccProcessingMethod || '').trim().toLowerCase() == "borgun";
                    callback();
                });
            };

            $scope.prepareData = function () {
                $scope.getLocations($scope.initCurrentAnonymUser.bind(null, $scope.init));
            };

            var isGeneralCtrlReady = $scope.$parent.generalCtrlReady;
            if (isGeneralCtrlReady) {
                $scope.prepareData();
            } else {
                $scope.$on("generalCtrlReady", function (event, args) {
                    $scope.prepareData();
                });
            }

                 

        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("accountUpdateProfileCtrl", [
        "userService","utilsFactory", "jwtService", "$scope", "$state", "$rootScope", "validHelper", "customerService", "$element", "$window",
        function (userService,utilsFactory, jwtService, $scope, $state, $rootScope, validHelper, customerService, $element, $window) {

            $scope.utils = utilsFactory;
            $.material.init();
            $scope.validHelper = validHelper;
            $scope.isLoading = true;
            $scope.isAgent = false;

            var timeoutID = undefined;

            function resizeSliderPanel() {
                window.clearTimeout(timeoutID);
                timeoutID = setTimeout(function () {
                    _.each(jQuery("input"), function (input) {
                        if (jQuery(input).val()) {
                            jQuery(input).change();
                        }
                    });
                    jQuery(window).resize();
                }, 100);
            }

            $scope.$on("customer-changed", function (event, args) {
                $scope.init();
            });

            $scope.availableCountries = [
                {
                    name: "United States",
                    countryCode: "US"
                },
                {
                    name: "Canada",
                    countryCode: "CA"
                }
            ];
            $scope.showStateProvForCountries = _.pluck($scope.availableCountries, "name");

            $scope.showStateProv = function () {
                return $scope.model.country && $scope.showStateProvForCountries.indexOf($scope.model.country) > -1;
            };

            $scope.fillAvailableRegions = function () {
                var prevState = $scope.model.provState;
                $scope.model.provState = undefined;
                if (!$scope.showStateProv() || !$scope.model.country) {
                    $scope.availableRegions = [];
                    return;
                }
                var selectedCountry = _.find($scope.availableCountries, function (cntr) { return cntr.name == $scope.model.country; });
                if (!selectedCountry) {
                    $scope.availableRegions = [];
                    return;
                }

                $scope.availableRegions = _.filter($scope.allRegions || [], function (reg) { return reg.countryCode == selectedCountry.code; });
                
                var existRegion=_.find($scope.availableRegions || [], function (reg) { return reg.regionName == prevState; });
             
                if (prevState && existRegion) {
                    $scope.model.provState = prevState;
                } else {
                    $scope.model.provState = undefined;
                }
            };

            $scope.model = {
                firstName: "",
                lastName: "",
                address: "",
                city: "",
                provState: "",
                country: "",
                zipCode: "",
                phone: "",
                email:""
            };

            $scope.countryChanged = function (country) {
                $scope.model.country = country.name;
            };

            function checkIfLogedIn() {
                var token = jwtService.getCustomerToken();
                if (!token || token.length === 0) {
                    window.location.href = "/";
                    return false;
                }
                return true;
            }

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });



            $scope.submitUpdateAccountInfo = function (isValid) {
                // check to make sure the form is completely valid
                var customer = jwtService.getCustomer();

                if (isValid && checkIfLogedIn() && customer) {
                    $scope.submitted = false;
                    $scope.isLoading = true;
                    var customerData = {
                        "CustomerNumber": customer.customerNumber,
                        "FirstName": $scope.model.firstName,
                        "LastName": $scope.model.lastName,
                        "Address": {
                            "Street": $scope.model.address,
                            "City": $scope.model.city,
                            "PostalCode": $scope.model.zipCode,
                            "Country": $scope.model.country,
                            "Province": $scope.model.provState
                        }
                    };
                    if (($scope.model.email||"").length) {
                        customerData.Email = $scope.model.email;
                    }

                    if (($scope.model.phone || "").length) {
                        var assigned = false;
                        var phoneNumbers = _.map(customer.phoneNumbers, function (pn) {
                            var phoneNumber = pn.number;
                            if (pn.type === "Mobile") {
                                phoneNumber = $scope.model.phone;
                                assigned = true;
                            }
                            return { "Type": pn.type, "Number": phoneNumber };
                        });
                        if (!assigned) {
                            var newPhone = { "Type": "Mobile", "Number": $scope.model.phone };
                            if ((phoneNumbers || "").length) {
                                phoneNumbers.push(newPhone);
                            } else {
                                phoneNumbers=[newPhone];
                            }
                        }
                        customerData.PhoneNumbers = phoneNumbers;
                    }

                    var requestParams = {
                        apiUrl: ($("body").data("weburl") ? $("body").data("weburl") : "") + "/api/customer/update",
                        token: jwtService.getCustomerToken(),
                        customerToPost: { "customer": customerData }
                    };
                    $scope.model.errors = [];
                    customerService.updateCustomer(requestParams, function (result) {

                        if (!result || !result.data ||(result.data.errors||"").length > 0) {
                            $scope.isLoading = false;
                            $scope.submitted = true;
                            $scope.model.errors = result.data || result.data.errors.length > 0 ? result.data.errors : [
                                {
                                    "errorMessage": utilsFactory.getLabel("general.unexpected-error")
                                }
                            ];
                        } else {
                            $scope.submitted = true;
                            $scope.$parent.$parent.initCustomerRecordWithCallback(true, function () {
                                $scope.isLoading = false;
                            });
                        }

                    });

                } else {
                    $scope.submitted = true;
                }
            };

            $scope.getLocations = function (callback) {
                return new Promise(function (resolve, reject) {
                    userService.getPersistedCountries(function (persistedResult) {
                        if (persistedResult.success && persistedResult.data && persistedResult.data.countries) {
                            $scope.availableCountries = persistedResult.data.countries;
                            //  callback();
                            resolve();
                        } else {
                            var params = {
                                urlPrefix: $scope.$parent.getWebUrl(),
                                token: jwtService.getPrincipalToken()
                            };
                            userService.getCountries(params, function (countriesResult) {
                                if (countriesResult.success && (countriesResult.data || "").length) {
                                    $scope.availableCountries = countriesResult.data;
                                    userService.persistCountries(countriesResult.data, function () { });
                                }
                                resolve();
                            });
                        }
                    });
                });
            };
            $scope.getRegions = function () {
                return new Promise(function (resolve, reject) {
                    userService.getPersistedRegions(function (persistedResult) {
                        if (persistedResult.success && persistedResult.data && persistedResult.data.regions) {
                            $scope.allRegions = persistedResult.data.regions;
                            resolve();
                            // callback();
                        } else {
                            var params = {
                                urlPrefix: $scope.$parent.getWebUrl(),
                                token: jwtService.getPrincipalToken()
                            };
                            userService.getRegions(params, function (regionsResult) {
                                if (regionsResult.success && (regionsResult.data || "").length) {
                                    $scope.allRegions = regionsResult.data;
                                    userService.persistRegions(regionsResult.data, function () { });
                                }
                                //callback();
                                resolve();
                            });
                        }
                    });
                });// \promise
            };

            resizeSliderPanel();

            $scope.init = function () {
                $scope.isLoading = false;
                if (!checkIfLogedIn()) {
                    return;
                }
                var customer = jwtService.getCustomer();
                if (!customer) return;
                var customerTokenObj = jwtService.getCustomerTokenObj();
                $scope.isAgent = (customerTokenObj && customerTokenObj.loginType && customerTokenObj.loginType === "agent");

                $scope.model.firstName = customer.firstName;
                $scope.model.lastName = customer.lastName;
                $scope.model.address = customer.address.street;
                $scope.model.city = customer.address.city;
                $scope.model.country = customer.address.country;
                $scope.model.provState = customer.address.province;
                $scope.model.zipCode = customer.address.postalCode;
                $scope.model.email = customer.email;
                var mobilePhone = _.find(customer.phoneNumbers, function(ph) { return ph.type === "Mobile"; });
                $scope.model.phone = mobilePhone ? mobilePhone.number : "";
                resizeSliderPanel();
                $scope.fillAvailableRegions();
            };

            $scope.prepareData = function () {
                Promise.all([$scope.getRegions(), $scope.getLocations()]).then($scope.init);
              //  $scope.getLocations($scope.init);
            };

            var isGeneralCtrlReady = $scope.$parent.generalCtrlReady;
            if (isGeneralCtrlReady) {
                $scope.prepareData();
            } else {
                $scope.$on("generalCtrlReady", function (event, args) {
                    $scope.prepareData();
                });
            }            
             
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("confirmEmailChangeCtrl", [
        "utilsFactory", "jwtService", "userService", "$scope", "$state", "$rootScope", "validHelper", "customerService", "$element", "$window", "shoppingCartService",
        function (utilsFactory,jwtService, userService, $scope, $state, $rootScope, validHelper, customerService, $element, $window, shoppingCartService) {

            $scope.utils = utilsFactory;
            var webUrl = ($("body").data("weburl") ? $("body").data("weburl") : "");

            $scope.isLoading = true;
            $scope.errors = [];

            $scope.username = $($element).attr("data-username");
            $scope.newemail = $($element).attr("data-new-email");
            $scope.confirmToken = $($element).attr("data-confirm-token");

            $scope.confirmEmailChange= function () {
                $scope.isLoading = true;
                userService.confirmEmailChange({
                    urlPrefix: webUrl,
                    dataToPost: {
                        "Username": $scope.username,
                        "Emailconfirmationtoken": $scope.confirmToken,
                        "NewEmailAddress": $scope.newemail
                    }
                }, function (result) {
                    if (!result.success) {
                        $scope.errors = (result.error && result.error.errors) ?
                            _.pluck(result.error.errors, "errorMessage") : ["An error has occured!"];
                    }

                    $scope.isLoading = false;
                });
            };

            $scope.init = function () {
                if (!$scope.username || !$scope.confirmToken || !$scope.newemail) {
                    window.location = "/";
                    return;
                }
                $scope.confirmEmailChange();
            };

            //var t = jwtService.getPrincipalToken();

            //if (t && t.length > 0) {
            //    $scope.init();
            //} else {
            //    $scope.isLoading = true;
            //    $scope.$on("getPrincipalToken", function (event, args) {
            //        $scope.init();
            //    });
            //};

           

            var isGeneralCtrlReady = $scope.$parent.generalCtrlReady;
            if (isGeneralCtrlReady) {
                $scope.init();
            } else {
                $scope.$on("generalCtrlReady", function (event, args) {
                    $scope.init();
                });
            }


        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("confirmEmailCtrl", [
        "utilsFactory", "jwtService", "userService", "$scope", "$state", "$rootScope", "validHelper", "customerService", "$element", "$window", "shoppingCartService",
        function (utilsFactory, jwtService, userService, $scope, $state, $rootScope, validHelper, customerService, $element, $window, shoppingCartService) {

            $scope.utils = utilsFactory;
            var webUrl = ($("body").data("weburl") ? $("body").data("weburl") : "");

            $scope.isLoading = true;

            $scope.tokenRequest = false;
            $scope.showReconfirmEmailBtn = false;
            $scope.errors = [];

            $scope.username = $($element).attr("data-username");
            $scope.confirmToken = $($element).attr("data-confirm-token");

            $scope.confirmEmail = function () {
                $scope.isLoading = true;
                $scope.tokenRequest = true;
                $scope.resendConfirmationEmailRequest = false;

                userService.confirmEmail({
                    urlPrefix: webUrl,
                    dataToPost: {
                        "Username": $scope.username,
                        "Emailconfirmationtoken": $scope.confirmToken
                    }
                }, function (result) {
                    if (!result.success) {
                        $scope.errors = (result.error && result.error.errors) ?
                            _.pluck(result.error.errors, "errorMessage") : ["An error has occured!"];

                        $scope.showReconfirmEmailBtn = result.error && result.error.HttpResponseCode == 400;
                    }

                    $scope.isLoading = false;
                });
            };

            $scope.resendConfirmationEmail = function () {
                $scope.isLoading = true;
                $scope.tokenRequest = false;
                $scope.resendConfirmationEmailRequest = true;
                $scope.errors = [];

                userService.resendEmailConfirmation({
                    urlPrefix: webUrl,
                    dataToPost: {
                        "Username": $scope.username
                    }
                }, function (result) {
                    if (!result.success) {
                        $scope.errors = (result.error && result.error.errors) ?
                            _.pluck(result.error.errors, "errorMessage") : ["An error has occured!"];
                    } else {
                        $scope.showReconfirmEmailBtn = false;
                    }

                    $scope.isLoading = false;
                });
            };

            $scope.init = function () {
                if (!$scope.username || !$scope.confirmToken) {
                    window.location = "/";
                    return;
                }
                $scope.confirmEmail();
            };

            var t = jwtService.getPrincipalToken();

            if (t && t.length > 0) {
                $scope.init();
            } else {
                $scope.isLoading = true;
                $scope.$on("getPrincipalToken", function (event, args) {
                    $scope.init();
                });
            };


        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("manageAccountCtrl", [
        "utilsFactory", "$scope", "$state", "cresecureService", "$timeout", "$rootScope", "jwtService",
        function (utilsFactory, $scope, $state, cresecureService, $timeout, $rootScope, jwtService) {

            var timeoutID = undefined;

            function resizeSliderPanel() {
                window.clearTimeout(timeoutID);
                timeoutID = setTimeout(function () {
                    _.each(jQuery("input"), function (input) {
                        if (jQuery(input).val()) {
                            jQuery(input).change();
                        }
                    });
                    jQuery(window).resize();
                }, 100);
            }
            $rootScope.$on("$stateChangeSuccess",
                function (event, toState, toParams, fromState, fromParams) {
                    resizeSliderPanel();
                });

            $scope.utils = utilsFactory;
            $scope.customer = null;

            $scope.showModal["AddCard"] = false;
            $scope.selectedCreCard = null;
            $scope.isCreProcessing = false;
            $scope.showCreSummaryErrors = false;
            $scope.showAddCardSummaryCusotmerErrors = false;
            $scope.creSummaryErrors = [];
            $scope.creSummaryCustomerErrors = [];
            $scope.crescureIframeUrl = "";

            $scope.logOut = function () {
                $scope.$parent.logOut();
            };

            $scope.completeCREPayment = function (params) {
                if (params.fullQuery.toLowerCase().indexOf("processstart=1") === -1) {
                    $scope.showModal["AddCard"] = false;

                    $scope.isCreProcessing = false;

                    $scope.showCreSummaryErrors = false;
                    $scope.creSummaryErrors = [];

                    $scope.$broadcast("add-cre-card-processed", params.fullQuery);
                } else {
                    $scope.isCreProcessing = true;
                }
            }

            $scope.cancelCREPayment = function () {
                $scope.showModal["AddCard"] = false;
            }

            $scope.creHandleDetailErrors = function (errorCode, gatewayCode, gatewayMessage) {
                $scope.isCreProcessing = false;

                $scope.showCreSummaryErrors = true;
                $scope.creSummaryErrors = cresecureService.getErrorMessages(errorCode);
            }

            $scope.creHandleErrors = function (errorCode) {
                $scope.isCreProcessing = false;

                $scope.showCreSummaryErrors = true;
                $scope.creSummaryErrors = cresecureService.getErrorMessages(errorCode);
            }

            $scope.whatCVV2 = function () {
                $scope.isCreProcessing = false;
                alert("whatCVV2 called");
            }

            $scope.anonymUser = undefined;
            $scope.initCurrentAnonymUser = function (callback) {
                jwtService.getAnonymousUserByGeography($scope.selectedGeographyCode, function (user) {
                    $scope.anonymUser = user;
                    $scope.isTempusPaymentProvider = $scope.anonymUser && ($scope.anonymUser.ccProcessingMethod || '').trim().toLowerCase() == "tempus";
                    callback && callback();
                });
            };

            $scope.init = function () {
                $scope.initialized = true;
                $scope.customer = jwtService.getCustomer();
                $state.go("account-info", {});
                resizeSliderPanel();

                $scope.initCurrentAnonymUser();
            };

            $scope.init();
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("resetPasswordCtrl", [
       "utilsFactory", "jwtService", "userService", "$scope", "$state", "$rootScope", "validHelper", "customerService", "$element", "$window", "shoppingCartService", function (utilsFactory,jwtService, userService, $scope, $state, $rootScope, validHelper, customerService, $element, $window, shoppingCartService) {

           $scope.utils = utilsFactory;
            var webUrl = ($("body").data("weburl") ? $("body").data("weburl") : "");

            $scope.isLoading = true;
            $scope.errors = [];
            $scope.showForm = true;

            $scope.username = $($element).attr("data-username");
            $scope.resetToken = $($element).attr("data-reset-token");

            $scope.resetPwdModel = {
                emailAddress: $scope.username,
                password: "",
                password_c: ""
            };

            if (($scope.username || "").length) {
                setTimeout(function () {
                    jQuery($element).find("#resetPwdEmailAddress").change();
                }, 0);
            }

            $scope.submitResetPassword = function (isValid) {
                if ($scope.isLoading)
                    return false;

                if (isValid) {
                    $scope.isLoading = true;
                    $scope.errors = [];
                    userService.resetPassword({
                        urlPrefix: webUrl,
                        dataToPost: {
                            "Username": $scope.username,
                            "Email": $scope.resetPwdModel.emailAddress,
                            "NewPassword": $scope.resetPwdModel.password,
                            "ConfirmNewPassword": $scope.resetPwdModel.password_c,
                            "ResetToken": $scope.resetToken
                        }
                    }, function (result) {
                        if (!result.success) {
                            $scope.errors = (result.error && result.error.errors) ?
                                _.pluck(result.error.errors, "errorMessage") : ["An error has occured!"];
                        }
                        else {
                            $scope.showForm = false;
                        }

                        $scope.isLoading = false;
                    });
                }
                $scope.resetPwdModel.submitted = true;
                return true;
            };

            $scope.init = function () {
                if (!$scope.username || !$scope.resetToken) {
                    window.location = "/";
                    return;
                }
                $scope.isLoading = false;
            };

            var t = jwtService.getPrincipalToken();

            if (t && t.length > 0) {
                $scope.init();
            } else {
                $scope.isLoading = true;
                $scope.$on("getPrincipalToken", function (event, args) {
                    $scope.init();
                });
            };


        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("activitiesFilterCtrl", [
        "utilsFactory", "currenciesService", "$scope", "$http", "$element", "localStorageService", "jwtService", "activitiesService", "taskFactory", "$timeout", "$filter",
        function (utilsFactory, currenciesService, $scope, $http, $element, localStorageService, jwtService, activitiesService, taskFactory, $timeout, $filter) {

            $scope.utils = utilsFactory;
            TweenMax.ticker.useRAF(false);
            $scope.detailsUrl = $($element).attr("data-activity-details") || "";
            $scope.activities = [];
            $scope.allItems = [];
            $scope.filteredItems = [];

            $scope.categories = [];
            $scope.locations = [];
            $scope.priceRanges = [];
            $scope.geographyCode = jwtService.getGeography();

            $scope.filter = {
                selectedCategory: null,
                selectedLocation: null,
                selectedPriceRange: null
            };

            $scope.resultfilter = {
                selectedCategory: null,
                selectedLocation: null,
                selectedPriceRange: null
            };

            $scope.orderBy = {
                predicate: "name",
                reverse: false
            };

            $scope.listIsLoading = false;
            $scope.showNavArrows = false;
            $scope.getProductDate = function (date) {
                return !date ? date : date.substring(0, date.toLowerCase().indexOf("t"));
            };

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.listIsLoading = false;
                $scope.isLoading = false;
            });
            $scope.setActivitesName = function () {
                _.each($scope.activities, function (activity) {
                    var serviceCategoryTitle = activity.productDescriptions && activity.productDescriptions.serviceCategoryTitle;

                    if ((serviceCategoryTitle || '').length) {
                        activity.name = serviceCategoryTitle;
                    } else {
                        activity.name = (activity.productDescriptions && (activity.productDescriptions.titles || "").length) ? activity.productDescriptions.titles[0] : activity.name;
                    }
                });
            };
            $scope.handleFilter = function (e) {
                if ($scope.listIsLoading) return;

                var sectionid = $("[data-sectionid]").data("sectionid") || 0;
                activitiesService.persistActivitiesFilters(sectionid, {
                    activities: $scope.activities,
                    filters: $scope.filter,
                    locations: $scope.locations,
                    categories: $scope.categories,
                    priceRanges: $scope.priceRanges,
                    orderBy: $scope.orderBy
                }, function (result) {
                    if (e) {
                        //slide up
                        $(e.currentTarget).parent().parent().prev().click();
                    }

                    if (result.success) {
                        $scope.resultfilter.selectedCategory = result.data.filters.selectedCategory;
                        $scope.resultfilter.selectedPriceRange = result.data.filters.selectedPriceRange;
                        $scope.resultfilter.selectedLocation = result.data.filters.selectedLocation;
                    } else {
                        console.log(result.error);
                    }
                });
            };

            $scope.addAvailableStartingDate = function () {
                if (!$scope.activities) return;
                var currDate = jwtService.getServerMomentDate();

                _.each($scope.activities, function (activity) {
                    if (!activity.startDate) return;

                    var activityStartDate = moment(activity.startDate, "YYYY-MM-DD");
                    if (activityStartDate > currDate) {
                        activity.availableStartingDate = activityStartDate.format("DD MMMM YYYY");
                    }
                });
            };



            $scope.goToProductDetailsIfSingle = function () {
                var sectionid = $("[data-sectionid]").data("sectionid") || 0;
                if (($scope.allItems || "").length === 1) {
                    //debugger;
                    if (activitiesService.getIsFromActivityDetails()) {
                        activitiesService.setIsFromActivityDetails(0, function () {
                            activitiesService.setIsFromFilters(1, function () { });
                            window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
                        });
                        return true;
                    }
                    var firstProduct = $scope.allItems[0];
                    if (firstProduct.isPackage) {


                        window.location.href = utilsFactory.addPersistentQueryStringsParams("/" + $scope.geographyCode + $scope.detailsUrl.trim().replace(/[\/\\]$/, "") + "/"
                            + (sectionid ? sectionid + "/" : "")
                            + firstProduct.code + "/Package#/package-details/" + (firstProduct.startDateStr || "date") + "/" + firstProduct.code);
                    } else {
                        window.location.href = utilsFactory.addPersistentQueryStringsParams("/" + $scope.geographyCode + $scope.detailsUrl.trim().replace(/[\/\\]$/, "") + "/"
                            + (sectionid ? sectionid + "/" : "")
                            + (firstProduct.isHeader ? firstProduct.productType : firstProduct.code) + "/" + firstProduct.productCategory);
                    }


                    return true;
                }
                activitiesService.setIsFromActivityDetails(0, function () { });
                return false;
            };

            $scope.getActivities = function (e) {
                if ($scope.listIsLoading) return;
                if (e) {
                    $(e.currentTarget).parent().parent().prev().click();
                }
                var sectionid = $("[data-sectionid]").data("sectionid") || 0;

                $scope.resultfilter.selectedCategory = $scope.filter.selectedCategory;
                $scope.resultfilter.selectedPriceRange = $scope.filter.selectedPriceRange;

                $scope.resultfilter.selectedLocation = $scope.filter.selectedLocation;

                var token = jwtService.getPrincipalToken();
                //  var date = new Date();
                ////  date.setDate(date.getDate() + 1); //TODO: Remove when fixed
                //  var myDate = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
                $scope.listIsLoading = true;

                activitiesService.getPersistedActivitiesFilters(sectionid, function (filtersResult) {
                    if (filtersResult.success && filtersResult.data) {

                        $scope.activities = filtersResult.data.activities;
                        $scope.packages = filtersResult.data.packages;

                        var allItems = [].concat($scope.activities || [])
                            .concat(filtersResult.data.packages || []);

                        $scope.allItems = $filter('orderBy')(allItems, "ibeSortOrder", false);

                        $scope.addAvailableStartingDate();
                        $scope.setActivitesName();

                        setTimeout(function () {
                            jQuery(".scroll-list[list-scroll]").trigger("checkArrows");
                        }, 0);
                        if (!$scope.goToProductDetailsIfSingle()) {
                            $scope.listIsLoading = false;
                        }
                    } else {
                        activitiesService.getActivitiesByDate({
                            token: token,
                            id: sectionid,
                            date: jwtService.getServerStrDate(), urlPrefix: $scope.$parent.getWebUrl()
                        }, function (result) {
                            if (result.success) {
                                $scope.activities = result.data.products;
                                $scope.packages = result.data.packages;

                                _.each($scope.packages, function (el) {
                                    // el.sortOrder = el.ibeSortOrder;
                                    el.isPackage = true;
                                    el.name = el.packageDescriptions && ((el.packageDescriptions.titles || "").length > 0 ? el.packageDescriptions.titles[0] : "");

                                    // process start date str
                                    if (!el.startDate) return;

                                    var packageDate = moment(el.startDate, "YYYY-MM-DD");
                                    var currDate = jwtService.getServerMomentDate();
                                    // package start date can have a min date value
                                    if (!packageDate || !packageDate.isValid() || packageDate.year() < 2019) {
                                        packageDate = currDate;
                                    } else if (packageDate > currDate) {
                                        el.availableStartingDate = packageDate.format("DD MMMM YYYY");
                                    }

                                    el.startDateStr = packageDate.format("YYYY-MM-DD");
                                });
                                // 
                                var allItems = [].concat($scope.activities || [])
                                    .concat($scope.packages || []);
                                $scope.allItems = $filter('orderBy')(allItems, "ibeSortOrder", false);

                                $scope.setActivitesName();
                                activitiesService.persistActivitiesFilters(sectionid, {
                                    activities: $scope.activities,
                                    packages: $scope.packages,
                                    filters: $scope.filter,
                                    locations: $scope.locations,
                                    categories: $scope.categories,
                                    priceRanges: $scope.priceRanges,
                                    orderBy: $scope.orderBy
                                }, function () {
                                    $scope.addAvailableStartingDate();
                                });

                            } else {
                                console.log(result.error);
                            }

                            if (!$scope.goToProductDetailsIfSingle()) {
                                $scope.listIsLoading = false;
                                setTimeout(function () {
                                    jQuery(".scroll-list[list-scroll]").trigger("checkArrows");
                                }, 0);
                            }
                        });
                    }
                });

            };

            $scope.getActivitiesFilters = function (callback) {
                $scope.listIsLoading = true;
                var sectionid = $("[data-sectionid]").data("sectionid") || 0;
                activitiesService.getPersistedActivitiesFilters(sectionid, function (filtersResult) {
                    if (filtersResult.success && filtersResult.data) {

                        $scope.locations = filtersResult.data.locations;
                        $scope.priceRanges = filtersResult.data.priceRanges;
                        $scope.categories = filtersResult.data.categories;
                        // $scope.orderBy = filtersResult.data.orderBy;

                        //  $scope.resultfilter.selectedCategory = $scope.filter.selectedCategory = filtersResult.data.filters.selectedCategory;
                        //   $scope.resultfilter.selectedPriceRange = $scope.filter.selectedPriceRange = filtersResult.data.filters.selectedPriceRange;
                        //  $scope.resultfilter.selectedLocation = $scope.filter.selectedLocation = filtersResult.data.filters.selectedLocation;
                        $scope.listIsLoading = false;
                        if (callback) {
                            callback();
                        }
                    } else {
                        activitiesService.getActivitiesFilters({ urlPrefix: $scope.$parent.getWebUrl(), token: jwtService.getPrincipalToken() }, function (result) {
                            if (result.success) {
                                $.each(result.data, function (key, value) {
                                    if (key.toLowerCase().indexOf("location") >= 0) {
                                        $scope.locations = value;
                                    } else if (key.toLowerCase().indexOf("pricerangefilters") >= 0) {
                                        $scope.priceRanges = value;
                                    } else if (key.toLowerCase().indexOf("marketingtags") >= 0) {
                                        $scope.categories = value;
                                    }
                                });

                            } else {
                                console.log(result.error);
                            }

                            $scope.listIsLoading = false;

                            if (callback) {
                                callback();
                            }
                        });
                    }

                });
            };

            $scope.selectCurrency = function (currency) {
                $scope.selectedCurrency = currency;
                $scope.setSelectedCurrency($scope.selectedCurrency);
                currenciesService.setSelectedCurrencyCode(currency && currency.code);
            };

            $scope.isSkylagoon = function () {
                return ($scope.geographyCode || "").toLowerCase().indexOf("skl") >= 0;
            };

            $scope.showCurrencyDropdown = function () {
                var firstItem = $scope.allItems && $scope.allItems.find(function (item) {
                    return item.productType == "SPA-C";
                });

                return $scope.isSkylagoon() && firstItem;
            };

            $scope.init = function () {
                $scope.listIsLoading = false;
                $scope.geographyCode = jwtService.getGeography();
                $scope.getActivitiesFilters($scope.getActivities);
                jwtService.setProductCategory("Activities");

                if (!$scope.mainSectionId) {
                    window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
                    return;
                }
            };

            if ($scope.$parent.hasMainSections()) {
                $scope.listIsLoading = true;

                var initialized = false;

                $scope.$watch(function () {
                    return taskFactory.filtersTask;
                },
                    function (val) {
                        if (!val || !val.name || initialized) return;
                        initialized = true;

                        $timeout(function () {
                            $scope.listIsLoading = false;
                            $scope.init();
                        });
                    }, true);

                //$scope.$on("mainSectionReady", function (event, args) {
                //    $scope.listIsLoading = false;
                //    $scope.init();
                //});
            } else {
                var t = jwtService.getPrincipalToken();
                if (t && t.length > 0) {
                    $scope.init();
                } else {
                    $scope.listIsLoading = true;
                    $scope.$on("getPrincipalToken", function (event, args) {
                        $scope.listIsLoading = false;
                        $scope.init();
                    });
                }
            }

            $scope.$on("geographyCodeChanged", function (event, args) {
                jwtService.clearStorage();
                $scope.init();
                $scope.geographyCode = jwtService.getGeography();
            });

            $scope.selectCategory = function (categ) {
                $scope.filter.selectedCategory = categ;
            };
            $scope.selectLocation = function (location) {
                $scope.filter.selectedLocation = location;
            };
            $scope.selectPriceRange = function (priceRange) {
                $scope.filter.selectedPriceRange = priceRange;
            };

            $scope.selectActivity = function (product, $event) {
                $event.preventDefault();
                activitiesService.setSelectedActivity(product, function () { });

                if ($event && $event.currentTarget) {
                    var params = {
                        urlPrefix: ($("body").data("weburl") ? $("body").data("weburl") : ""),
                        productCode: product.code ? product.code : product.productType,
                        productTitle: (product.productDescriptions && (product.productDescriptions.serviceCategoryTitle || '').length)
                            ? product.productDescriptions.serviceCategoryTitle
                            : (product.productDescriptions && product.productDescriptions.titles) ? product.productDescriptions.titles[0] : product.name
                    };

                    jwtService.setCurrentProduct(params, function (result) {
                        var urlToRedirect = jQuery($event.currentTarget).attr("href");
                        window.location.href = utilsFactory.addPersistentQueryStringsParams(urlToRedirect);
                    });
                }
            };


            $scope.order = function (predicate, reverse) {
                $scope.orderBy.reverse = reverse;//($scope.orderBy.predicate === predicate) ? !$scope.orderBy.reverse : false;
                $scope.orderBy.predicate = predicate;

                activitiesService.persistActivitiesFilters({
                    activities: $scope.activities,
                    filters: $scope.filter,
                    locations: $scope.locations,
                    categories: $scope.categories,
                    priceRanges: $scope.priceRanges,
                    orderBy: $scope.orderBy
                }, function (result) {
                    //do nothing
                });
            };
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("activityBookAdventureCtrl", [
        "utilsFactory", "trackingService", "currenciesService", "$scope", "$state", "$http", "$uibModal", "productsFactory", "activitiesService", "$rootScope", "validHelper", "shoppingCartService", "jwtService", "taskFactory", "$timeout", "$element", "$filter",
        function (utilsFactory, trackingService, currenciesService, $scope, $state, $http, $uibModal, productsFactory, activitiesService, $rootScope, validHelper, shoppingCartService, jwtService, taskFactory, $timeout, $element, $filter) {

            var webUrl = $("body").data("weburl") ? $("body").data("weburl") : "";

            $scope.maxUnits = $("body").attr("data-max-attractions-available-units") ? parseInt($("body").attr("data-max-attractions-available-units")) : 15;
            $scope.maxAdultsChildrenTotal = $("body").attr("data-max-activity-available-adults-child-total") ? parseInt($("body").attr("data-max-activity-available-adults-child-total")) : 5;
            $scope.maxAdults = 0; //Not used $("body").attr("data-max-attractions-available-adults") ? parseInt($("body").attr("data-max-attractions-available-adults")) : 5;
            $scope.maxChildren = $("body").attr("data-max-attractions-available-children") ? parseInt($("body").attr("data-max-attractions-available-children")) : 5;

            $scope.maxSeniors = $("body").attr("data-max-activity-seniors") ? parseInt($("body").attr("data-max-activity-seniors")) : 5;
            $scope.maxStudents = $("body").attr("data-max-activity-students") ? parseInt($("body").attr("data-max-activity-students")) : 5;
            $scope.isChildAvailable = true;
            $scope.isSeniorsAvailable = false;
            $scope.isStudentsAvailable = false;
            $scope.isInfantsAvailable = false;
            $scope.isFOC = "";
            $scope.allItems = [];
            $scope.filteredItems = [];
            $scope.dynamicPrices = Object.create(null);
            $scope.showQuantityPicker = false;

            var activitySelectTicketCtrl = $scope.$parent;
            var activityDetailsCtrl = activitySelectTicketCtrl.$parent;
            var generalCtrl = activityDetailsCtrl.$parent;

            if (activityDetailsCtrl.isPackageOnly) {
                activityDetailsCtrl.back();
                return;
            }

            $scope.showPackageModal = $("body").attr("data-attractions-show-modal") === "1";

            $scope.utils = utilsFactory;
            $scope.getAgeRangeInfo = function (secondaryLabel) {
                if (!$scope.anonymUser) return undefined;

                var selectedLanguage = $scope.anonymUser.selectedLanguage;
                return $scope.utils.getAnonymUserLabel((selectedLanguage && selectedLanguage.userlabels) || $scope.anonymUser, "ageRangesInfo", secondaryLabel);
            };
            $scope.wasSearch = false;

            $scope.globalErrors = [];
            $scope.resultfilter = {
                type: null,
                totalTickets: 0
            };

            $scope.orderByLabels = {
                "all": $scope.utils.getLabel("filters.sortBy"),
                "sortOrder": $scope.utils.getLabel("filters.sortByMostPopular"),
                "priceAsc": $scope.utils.getLabel("filters.sortByPriceASC"),
                "priceDesc": $scope.utils.getLabel("filters.sortByPriceDESC")
            };

            $scope.getOrderByLabel = function (key, reverse) {
                if (!key || key == "all") return $scope.orderByLabels["all"];
                if (key == "sortOrder") {
                    return $scope.orderByLabels[key];
                } else {
                    return $scope.orderByLabels[key + (reverse ? "Desc" : "Asc")];
                }
            };

            $scope.orderBy = {
                predicate: "all",
                reverse: false
            };

            $scope.filterBy = function (type) {
                if ($scope.resultfilter.type == type) {
                    $scope.resultfilter.type = null;
                    $scope.filterItems();
                    return;
                }
                $scope.resultfilter.type = type;
                $scope.filterItems();
            };

            $scope.order = function (predicate, reverse, preventResize) {
                $scope.orderBy.reverse = reverse;
                if (predicate != "all") {
                    $scope.orderBy.predicate = predicate;
                }
                $scope.filteredItems = $filter('orderBy')($scope.filteredItems, predicate == "all" ? "sortOrder" : $scope.orderBy.predicate, $scope.orderBy.reverse);
                if (!preventResize) {
                    setTimeout(function () {
                        jQuery(window).resize();
                    });
                }
            };

            $rootScope.$on("$stateChangeSuccess",
                function (event, toState, toParams, fromState, fromParams) {
                    $scope.selectedCurrency = $scope.getCurrencyBySelectedCode();
                    $scope.setSelectedCurrency($scope.selectedCurrency);
                });


            $scope.selectCurrency = function (currency) {
                $scope.selectedCurrency = currency;
                $scope.setSelectedCurrency($scope.selectedCurrency);
                currenciesService.setSelectedCurrencyCode(currency && currency.code);
            };

            $scope.filterItems = function () {
                $scope.resultfilter.totalTickets = parseInt($scope.selectedAdults) + parseInt($scope.selectedChild) +
                    parseInt($scope.selectedSeniors) + parseInt($scope.selectedStudents);

                $scope.filteredItems = $filter('filterAttractions')($scope.allItems, $scope.resultfilter);
                $scope.order($scope.orderBy.predicate, $scope.orderBy.reverse, true);
                setTimeout(function () {
                    jQuery(window).resize();
                });
            };


            $.material.init();


            //var loadingMsgs = [                
            //    "Life is either a daring adventure or nothing.",               
            //    "Adventure is worthwhile in itself.",
            //    "The world is a book, and those who do not travel read only one page.",
            //    "Travel far enough, you meet yourself.",
            //    "One way to get the most out of life is to look upon it as an adventure.",
            //    "The danger of adventure is worth a thousand days of ease and comfort.",
            //    "Then one day, when you least expect it, the great adventure finds you.",
            //    "The biggest adventure you can take is to live the life of your dreams.",
            //    "If we were meant to stay in one place, we’d have roots instead of feet.",
            //    "Travel doesn’t become adventure until you leave yourself behind.",
            //    "Take every chance you get in life, because some things only happen once.",
            //    "Live your life by a compass, not a clock.",
            //    "He who climbs upon the highest mountains laughs at all tragedies, real or imaginary.",
            //    "Life movies pretty fast, if you don’t stop and look around every once in a while you could miss it."
            //];

            //$scope.shuffleLoadingIndex = function () {
            //    var randIndex = Math.floor(Math.random() * loadingMsgs.length);
            //    console.log("shuffle - ", randIndex)
            //    $scope.loadingMsg = loadingMsgs[randIndex];
            //    $scope.loadingMsg = loadingMsgs[0];
            //};

            //$scope.shuffleLoadingIndex();

            $scope.requestArguments = {
                activityId: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-id"),
                productCode: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-product-code"),
                unitCode: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-unit-code"),
                productCategory: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-product-category"),
                travelDate: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-travel-date"),
                isDefaultDate: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-is-default-date"),
                adults: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-adults"),
                child: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-child"),
                updateCartItemCode: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-updateCartItem"),
                autoSelectUnit: ["1", "true"].indexOf(($("div[ng-controller='activityDetailsCtrl']").attr("data-activity-autoselectunit") || "").toLowerCase()) >= 0,
                hidedatepicker: ($("div[ng-controller='activityDetailsCtrl']").attr("data-hidedatepicker") || "").toLowerCase() == 'true',
                productcodeswithexpandeddescriptionbydefault: $("div[ng-controller='activityDetailsCtrl']").attr("data-productcodeswithexpandeddescriptionbydefault"),
                unitcodeswithexpandedtilesdescriptionbydefault: $("div[ng-controller='activityDetailsCtrl']").data("unitcodeswithexpandedtilesdescriptionbydefault"),
                defaultselectedadultsbyproductcode: $("div[ng-controller='activityDetailsCtrl']").data("defaultselectedadultsbyproductcode"),
                fromwebtray: ["1", "true"].indexOf(($("div[ng-controller='activityDetailsCtrl']").attr("data-activity-fromwebtray") || "").toLowerCase()) >= 0,
                showboardingtimeforproductcodes: $("div[ng-controller='activityDetailsCtrl']").data("showboardingtimeforproductcodes"),
                maxdurationoverwriteforunitcodes: ($("div[ng-controller='activityDetailsCtrl']").attr("data-activity-maxdurationoverwriteforunitcodes") || "").split("|"),
            };
            $scope.requestArguments.expanddescriptionbydefault = ($scope.requestArguments.productcodeswithexpandeddescriptionbydefault || []).indexOf($scope.requestArguments.productCode) >= 0;

            $scope.hideGuestsSelector = $scope.requestArguments.productCode == 'PH-SKL';

            $scope.packageModalLabels = utilsFactory.getModalLabelsObs("activity.packageModals", $scope.requestArguments.productCode);
            $scope.productLabels = utilsFactory.getLabel("activity.specificProduct", true);
            $scope.getProductLabel = function (productCode, key) {
                var obj = utilsFactory.getProductLabel($scope.productLabels, productCode);
                if (!obj) {
                    var currentRegion = (generalCtrl.selectedGeographyCode || "").toUpperCase();
                    obj = utilsFactory.getProductLabelByRegion($scope.productLabels, currentRegion);
                }

                if (!obj || !key) return obj;
                return obj[key];
            };

            $scope.validHelper = validHelper;
            $scope.isLoading = true;
            //$scope.shuffleLoadingIndex();
            $scope.wasSearch = false;
            $scope.submitted = Object.create(null);

            var selectedActivity = $scope.$parent.getPrevActivity();

            selectedActivity = selectedActivity && ((selectedActivity.isHeader && selectedActivity.productType === $scope.requestArguments.productCode) ||
                !(selectedActivity.isHeader && selectedActivity.code === $scope.requestArguments.productCode)) ? selectedActivity : undefined;
            // if an update item is required don't init the travel date
            $scope.requestArguments.travelDate = ($scope.requestArguments.isDefaultDate !== "1" || (!selectedActivity || !selectedActivity.startDate)) ? $scope.requestArguments.travelDate : $scope.$parent.getProductDate(selectedActivity.startDate);

            if ($scope.requestArguments.updateCartItemCode || jwtService.getServerMomentDate() > moment($scope.requestArguments.travelDate)) {
                $scope.requestArguments.travelDate = jwtService.getServerStrDate();
                $scope.requestArguments.isDefaultDate = true;
            }

            //$("#daterange").hide();

            $scope.isTileDescriptionExpandedByDefault = function (unitCode) {
                return unitCode && ($scope.requestArguments.unitcodeswithexpandedtilesdescriptionbydefault || []).indexOf(unitCode) >= 0;
            };

            $scope.resetSubmitted = function () {
                for (var a in $scope.submitted) {
                    $scope.submitted[a] = false;
                }
            };

            $scope.searchProducts = function () {
                if ($scope.isLoading) return;
                $scope.wasSearch = true;
                $scope.resultfilter.type = null;
                $scope.resetSubmitted();

                var strDate = $scope.getSelectedDate();

                var trackerReq = {
                    lobTitle: $scope.trackLobTitle,
                    packageName: null,
                    searchDate: strDate,
                    adults: parseInt($scope.selectedAdults),
                    children: parseInt($scope.selectedChild),
                    shoppingCart: $scope.cart,
                    anonymUser: $scope.anonymGeneralUser,
                    bookingNumber: null,
                    bookingId: null
                };
                trackingService.buildFlowTrackerObj(trackerReq);

                $scope.getProductUnits(strDate);
            };



            $scope.currentDate = new Date(jwtService.getServerMomentDate());
            $scope.dateChanged = function () {
                //if ($scope.isLoading) return;
                //var strDate = moment($scope.currentDate).format("YYYY-MM-DD");
                //$scope.getProductUnits(strDate);

            }

            function strRange(min, max) {
                min = min || 0;
                max = max || 0;

                if (min == 0 && max == 0) {
                    return ["0"];
                }

                function toString(val) {
                    return val.toString();
                }

                return _.map(_.range(min, max), toString);
            }

            $scope.selectedQuantity = 1;

            $scope.selectedAdults = ($scope.actionRegionCode || "").toLowerCase().indexOf("skl") >= 0 && ($scope.requestArguments.productCode || "").toLowerCase().indexOf("gift") >= 0 ? 1 : 2;
            if (($scope.requestArguments.defaultselectedadultsbyproductcode || '').length > 0) {
                var defaultSelectedAdultsStr = _.find($scope.requestArguments.defaultselectedadultsbyproductcode, function (item) {
                    return item.split(' ')[0] == $scope.requestArguments.productCode;
                });
                if (defaultSelectedAdultsStr) {
                    var defaultSelectedAdults = parseInt(defaultSelectedAdultsStr.split(' ')[1]);
                    if (defaultSelectedAdults > 0) {
                        $scope.selectedAdults = defaultSelectedAdults;
                    }
                }
            }


            $scope.selectedChild = 0;

            $scope.selectedSeniors = 0;
            $scope.selectedStudents = 0;
            $scope.selectedInfants = 0;

            $scope.noTime = { key: utilsFactory.getLabel("general.anytime"), value: null };
            $scope.attractionTimes = [];
            $scope.optionalExtras = [];
            $scope.selectedTime = $scope.noTime;

            $scope.availableQuantity = strRange(1, ($scope.maxUnits || 100) + 1);
            $scope.minAdults = ($scope.actionRegionCode || "").toLowerCase().indexOf("foi") >= 0 ? 1 : 0;

            $scope.availableAdults = strRange($scope.minAdults, $scope.maxAdultsChildrenTotal + 1);
            $scope.availableChild = strRange(0, ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors) -
                parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

            $scope.availableSeniors = strRange(0, ($scope.maxAdultsChildrenTotal -
                parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) -
                parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

            $scope.availableStudents = strRange(0, ($scope.maxAdultsChildrenTotal -
                parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) -
                parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);
            $scope.availableInfants = strRange(0, ($scope.maxAdultsChildrenTotal -
                parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) -
                parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            $scope.getTotalGuests = function () {
                var totalGuests = 0;
                if ($scope.showQuantityPicker) {
                    totalGuests = totalGuests || parseInt($scope.selectedQuantity || 0);
                } else {
                    totalGuests = totalGuests || (parseInt($scope.selectedAdults || 0) + parseInt($scope.selectedChild || 0) +
                        parseInt($scope.selectedSeniors || 0) + parseInt($scope.selectedStudents, 0) + parseInt($scope.selectedInfants, 0));
                }
                return totalGuests;
            };

            $scope.isUnitAvailable = function (unit, totalGuests) {//checkFlag=1-upload 2-download 3 - both default
                if (!unit) return false;

                totalGuests = $scope.getTotalGuests();

                return unit.availability >= (totalGuests);
            };

            $scope.isPackageAvailableByAdvancedLimit = function (pkg) {
                if (!pkg || !pkg.advancedBookingDaysLimit) return true;
                var currentDate = jwtService.getServerMomentDate();
                var limitDate = currentDate.add(pkg.advancedBookingDaysLimit, 'days');
                var searchDate = $scope.getSelectedDate(null, true);
                return searchDate.isSameOrBefore(limitDate, 'day');
            };

            $scope.getUnavailablePackageByAdvancedLimit = function (pkg) {
                if (!pkg) return null;
                return utilsFactory.getLabel("packages.unavailableInAdvance").replace("{0}", pkg.advancedBookingDaysLimit);
            }

            $scope.scrollToResultsIfMobile = function () {
                //if (jQuery(window).width() < 760) {
                setTimeout(function () {
                    if ($("#loadingContainer").length && $("#resultsContainer").length) {
                        var page = $("html, body");

                        page.animate({ scrollTop: $scope.isLoading ? $("#loadingContainer").offset().top : $("#resultsContainer").offset().top }, 1000, function () {
                            page.off("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove");
                        });

                        page.on("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove", function () {
                            setTimeout(function () {
                                page.stop();
                            });
                        });
                    }
                });
                //  }
            };


            $scope.isSelectedUnitAvailable = function (ticket) {//checkFlag=1-upload 2-download 3 - both default
                if (!ticket) return false;

                var totalGuests = 0;
                if ($scope.showQuantityPicker) {
                    totalGuests = parseInt($scope.selectedQuantity || 0);
                } else {
                    totalGuests = parseInt($scope.selectedAdults || 0) + parseInt($scope.selectedChild || 0) +
                        parseInt($scope.selectedSeniors || 0) + parseInt($scope.selectedStudents, 0) + parseInt($scope.selectedInfants, 0);
                }

                if (ticket.upTimeProduct && ticket.upTimeProduct.selectedUnit) {
                    var isAvailable = $scope.isUnitAvailable(ticket.upTimeProduct.selectedUnit, totalGuests);
                    if (!isAvailable) {
                        return false;
                    }
                }

                if (ticket.downTimeProduct && ticket.downTimeProduct.selectedUnit) {
                    isAvailable = $scope.isUnitAvailable(ticket.downTimeProduct.selectedUnit, totalGuests);
                    if (!isAvailable) {
                        return false;
                    }
                }

                return true;
            };

            //get rangeid: 1-adult(16-100)2-child(6-15)
            function isInRange(str, rangeA, rangeB) {
                if (!str) return true;
                var rangeStr = str.replace(/ /g, "").split("-");
                if (rangeStr.length !== 2) return false;
                return (rangeA >= parseInt(rangeStr[0]) && rangeB <= parseInt(rangeStr[1]));
            }

            $scope.showSoldOutNotice = function () {
                setTimeout(function () {
                    if ($scope.product && $scope.product.productDescriptions && $scope.product.productDescriptions.soldOutNotice) {
                        var showSoldOutNotice = true;
                        _.each($scope.product.units, function (unit) {
                            showSoldOutNotice = showSoldOutNotice && (unit.availability < 1);
                        });
                        if (showSoldOutNotice) {
                            generalCtrl.toggleModalWithData("SoldOutNotice", $scope.product.productDescriptions.soldOutNotice);
                        }
                    }
                });
            };

            $scope.getPrices = function (travelDate, units, index) {
                if (!units) return;
                for (var i = 0; i < units.length; i++) {
                    var unit = units[i];
                    if (unit.ageBasedPriceBreakdown) {
                        if (unit.ageBasedPriceBreakdown.adultPrice) {
                            unit.price = unit.ageBasedPriceBreakdown.adultPrice;
                        }
                        unit.childPrice = unit.ageBasedPriceBreakdown.childPrice;
                        unit.additionalChildPrice = unit.ageBasedPriceBreakdown.additionalChildPrice;
                        unit.seniorPrice = unit.ageBasedPriceBreakdown.seniorPrice;
                        unit.studentPrice = unit.ageBasedPriceBreakdown.studentPrice;
                    }
                    //unit.currency = (prices && prices[0] && prices[0].currency) || "USD";
                    unit.culture = ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) || "en";
                }


                $scope.product._isProcessed = true;
                $scope.persistCriteria();
                $scope.isLoading = false;
                setTimeout(function () {
                    jQuery(window).resize();
                });
                $scope.scrollToResultsIfMobile();
                $scope.showSoldOutNotice();

            };


            $scope.getProductUnits = function (travelDate) {
                activitiesService.getSelectedActivity(function (result) {
                    if (result.success && result.data) {
                        var activity = result.data;

                        var productCode = activity.code;
                        var productCategory = activity.productCategory;
                        //$scope.shuffleLoadingIndex();
                        $scope.isLoading = true;

                        $scope.wasSearch = true;
                        $scope.scrollToResultsIfMobile();
                        $scope.product = undefined;
                        $scope.packages = undefined;
                        $scope.allItems = undefined;
                        $scope.filteredItems = undefined;

                        productsFactory.GetProductWithPackages(jwtService.getPrincipalToken(), productCode, productCategory, travelDate).then(
                            function (result) {
                                $scope.product = undefined;

                                if (!(result.data.products || "").length && !(result.data.packages || "").length) {
                                    $scope.isLoading = false;
                                    $scope.scrollToResultsIfMobile();
                                    return;
                                }

                                if ((result.data.products || "").length) {
                                    $scope.product = result.data.products[0];
                                }


                                $scope.packages = result.data.packages || [];
                                _.each($scope.packages, function (el) {
                                    el.sortOrder = el.ibeSortOrder;
                                    el.isPackage = true;

                                    // set price
                                    if (el.ageBasedPriceBreakdown) {

                                        el.price = el.ageBasedPriceBreakdown.adultPrice;
                                        el.childPrice = el.ageBasedPriceBreakdown.childPrice;
                                        el.additionalChildPrice = el.ageBasedPriceBreakdown.additionalChildPrice;
                                        el.seniorPrice = el.ageBasedPriceBreakdown.seniorPrice;
                                        el.studentPrice = el.ageBasedPriceBreakdown.studentPrice;

                                        el.showPriceDescription = !el.ageBasedPriceBreakdown.adultPrice
                                            && !el.ageBasedPriceBreakdown.childPrice && !el.ageBasedPriceBreakdown.additionalChildPrice
                                            && !el.ageBasedPriceBreakdown.seniorPrice
                                            && !el.ageBasedPriceBreakdown.studentPrice;

                                    } else {
                                        el.showPriceDescription = true;
                                    }
                                    //el.currency = (prices && prices[0] && prices[0].currency) || "USD";
                                    el.culture = ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) || "en";
                                });

                                //filter units by unitCode from url
                                if ($scope.requestArguments.unitCode && $scope.product && $scope.product.units) {
                                    var rUnits = $scope.requestArguments.unitCode.split("|");
                                    $scope.product.units = _.filter($scope.product.units, function (unit) {
                                        return rUnits.indexOf(unit.unitCode) >= 0;
                                    });
                                }

                                if ($scope.product) {
                                    $.each($scope.product.units, function (key, value) {
                                        value.name = value.description;
                                        value.childPrice = 0;
                                    });
                                }

                                $scope.allItems = [].concat(($scope.product && $scope.product.units) || [])
                                    .concat($scope.packages || []);
                                $scope.processUnitIfInTableView();
                                $scope.filterItems();
                                $scope.persistCriteria();

                                var requestParamsMulti = {
                                    token: jwtService.getPrincipalToken(),
                                    product: $scope.product,
                                    totalGuests: $scope.getTotalGuests()
                                };
                                if (!$scope.product || $scope.product.units.length === 0) {
                                    $scope.isLoading = false;
                                } else {
                                    productsFactory.fillProductUnitsRelatedServicesMulti(requestParamsMulti, function () {
                                        if ($scope.updateItem && !$scope.updateItem.isUpdateCompSynced) {
                                            var firstComp = $scope.updateItem.BookingToQuote.Components[0];
                                            if (firstComp && (firstComp.attachedTimeComponents || "").length) {
                                                var productUnit = _.find($scope.product.units, function (unit) {
                                                    return firstComp.UnitCode == unit.unitCode;
                                                });
                                                if (productUnit) {
                                                    if (productUnit.upTimeProduct) {
                                                        var updateItemProductTime = _.find(firstComp.attachedTimeComponents, function (comp) {
                                                            return comp.ProductCode == productUnit.upTimeProduct.code;
                                                        });
                                                        if (updateItemProductTime) {
                                                            productUnit.upTimeProduct.selectedUnit = _.find(productUnit.upTimeProduct.units, function (unit) {
                                                                return unit.unitCode == updateItemProductTime.UnitCode;
                                                            });
                                                            if (!productUnit.upTimeProduct.selectedUnit && (productUnit.upTimeProduct.units || "").length == 1) {
                                                                productUnit.upTimeProduct.selectedUnit = productUnit.upTimeProduct.units[0];
                                                            }

                                                            $scope.setUnitBoardingTime(productUnit);
                                                            $scope.setDownTimes(productUnit);
                                                            $scope.setDurationHours(productUnit);

                                                            if (productUnit.upTimeProduct.selectedUnit) {
                                                                productUnit.upTimeProduct.selectedDuration = String(firstComp.Duration);
                                                            } else {
                                                                productUnit.upTimeProduct.selectedDuration = undefined;
                                                            }
                                                        }
                                                        $scope.checkIfFullDayAvailable(productUnit);
                                                    }

                                                    if (productUnit.downTimeProduct) {
                                                        var updateItemProductTime = _.find(firstComp.attachedTimeComponents, function (comp) {
                                                            return comp.ProductCode == productUnit.downTimeProduct.code;
                                                        });
                                                        if (updateItemProductTime) {

                                                            productUnit.downTimeProduct.selectedUnit = _.find(productUnit.downTimeProduct.filteredUnits, function (unit) {
                                                                return unit.unitCode == updateItemProductTime.UnitCode;
                                                            });
                                                            if (!productUnit.downTimeProduct.selectedUnit && (productUnit.downTimeProduct.filteredUnits || "").length == 1) {
                                                                productUnit.downTimeProduct.selectedUnit = productUnit.downTimeProduct.units[0];
                                                            }
                                                        }
                                                    }
                                                }
                                            }

                                            $scope.updateItem.isUpdateCompSynced = true;
                                        } else {
                                            _.each($scope.product.units, function (productUnit) {
                                                if (productUnit.upTimeProduct) {
                                                    if (!productUnit.upTimeProduct.selectedUnit && (productUnit.upTimeProduct.units || "").length == 1) {
                                                        productUnit.upTimeProduct.selectedUnit = productUnit.upTimeProduct.units[0];
                                                        $scope.setDownTimes(productUnit);
                                                        $scope.setUnitBoardingTime(productUnit);
                                                        $scope.setDurationHours(productUnit);
                                                    }
                                                    $scope.checkIfFullDayAvailable(productUnit);
                                                }
                                                if (productUnit.downTimeProduct) {
                                                    if (!productUnit.downTimeProduct.selectedUnit && (productUnit.downTimeProduct.filteredUnits || "").length == 1) {
                                                        productUnit.downTimeProduct.selectedUnit = productUnit.downTimeProduct.units[0];
                                                    }
                                                }
                                            });
                                        }
                                        // gift giving shipping delivery
                                        var loadOptionalExtrasProductsPromises = [];
                                        var shouldLoadOptionalExtrasProducts = (generalCtrl.selectedGeographyCode || "").toLowerCase().indexOf("skl") >= 0;
                                        if (shouldLoadOptionalExtrasProducts) {
                                            //
                                            _.each($scope.product.units, function (productUnit) {
                                                if (productUnit.relatedProducts && (productUnit.relatedProducts.optionalExtras || '').length) {
                                                    loadOptionalExtrasProductsPromises.push(new Promise(function (resolve, reject) {
                                                        $scope.fillOptionalProductDetailsRecursive(productUnit, productUnit.relatedProducts.optionalExtras, 0, resolve);
                                                    }));
                                                }

                                                //$scope.fillOptionalProductDetailsRecursive();
                                            });
                                            //
                                        }

                                        Promise.all(loadOptionalExtrasProductsPromises).then(function (result) {
                                            console.log("loadOptionalExtrasProductsPromises result: ", result);



                                            $scope.getPrices(travelDate, $scope.product.units, 0);

                                            if ($scope.requestArguments.autoSelectUnit && ($scope.filteredItems || "").length == 1) {
                                                $scope.gotoCheckout($scope.filteredItems[0], true);
                                            }
                                        });
                                    });
                                }
                            },
                            function (response) {
                                $scope.isLoading = false;
                                $scope.product = undefined;
                                $scope.persistCriteria();
                                console.log(response);
                            }
                        );
                    } else {
                        $scope.isLoading = false;
                        $scope.scrollToResultsIfMobile();
                    }
                });
            };

            $scope.processUnitIfInTableView = function () {
                if (!$scope.showTableView) return;

                var elDateStr = $scope.product.startDate.substring(0, $scope.product.startDate.indexOf("T"));
                var timeLimit = jwtService.getServerMomentDate(true);

                if ($scope.product.bookingRestrictionTime > 0) {
                    timeLimit.add(parseInt($scope.product.bookingRestrictionTime), "m");
                }

                var currHourLimit = jwtService.getServerMomentDate(true);
                var priceObj = undefined;
                _.each($scope.allItems, function (unit) {
                    if (unit.isPackage) return;

                    unit.timeStr = moment(unit.startTime).format("hh:mm A");
                    var newDateTime = elDateStr + unit.startTime.substring(unit.startTime.indexOf("T"));
                    unit.timeVal = moment(newDateTime);

                    //if (isCurrDate) {
                    var unitTimeLimit = undefined;
                    unit.isInPast = unit.timeVal <= currHourLimit;

                    if (unit.bookingRestrictionTime > 0) {
                        unitTimeLimit = jwtService.getServerMomentDate(true);
                        unitTimeLimit.add(parseInt(unit.bookingRestrictionTime), "m");
                        //timeLimit = moment(tc.format("hh:mm A"), "hh:mm A");
                    }

                    if (!unit.isInPast && (unitTimeLimit || timeLimit)) {
                        unit.isTimeRestricted = unit.timeVal <= (unitTimeLimit || timeLimit);
                    }

                    //get price 
                    //unit.currency = (prices && prices[0] && prices[0].currency) || "USD";                                
                    unit.currency = unit.currency || ((jwtService.getGeography() || "").toUpperCase().indexOf("SKL") >= 0 ? "ISK" : "USD");
                    unit.culture = ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) || "en";

                    if (unit.ageBasedPriceBreakdown) {
                        !priceObj && (priceObj = {
                            ageBasedPriceBreakdown: unit.ageBasedPriceBreakdown,
                            preSalePrices: unit.preSalePrices,
                            culture: unit.culture,
                            currency: unit.currency
                        });

                        if (unit.ageBasedPriceBreakdown.adultPrice) {
                            unit.price = unit.ageBasedPriceBreakdown.adultPrice;
                        }
                        unit.childPrice = unit.ageBasedPriceBreakdown.childPrice;
                        unit.additionalChildPrice = unit.ageBasedPriceBreakdown.additionalChildPrice;
                        unit.seniorPrice = unit.ageBasedPriceBreakdown.seniorPrice;
                        unit.studentPrice = unit.ageBasedPriceBreakdown.studentPrice;
                    }
                });
                $scope.product.priceObj = priceObj;
            };


            $scope.timeChanged = function (hour) {
                $scope.selectedTime = hour;
                $scope.persistCriteria();
            };

            $scope.quantityChanged = function () {
                $scope.wasSearch = false;
                $scope.persistCriteria();
                // if datepicker is hidden perform an autosearch
                if ($scope.requestArguments.hidedatepicker) {
                    $scope.searchProducts();
                }
            };

            $scope.adultsChanged = function () {
                $scope.wasSearch = false;
                $scope.availableChild = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors)
                        - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableChild.indexOf(($scope.selectedChild || "").toString()) < 0) {
                    $scope.selectedChild = $scope.availableChild[0];
                }
                $scope.availableSeniors = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableSeniors.indexOf(($scope.selectedSeniors || "").toString()) < 0) {
                    $scope.selectedSeniors = $scope.availableSeniors[0];
                }

                $scope.availableStudents = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableStudents.indexOf(($scope.selectedStudents || "").toString()) < 0) {
                    $scope.selectedStudents = $scope.availableStudents[0];
                }

                $scope.availableInfants = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

                if ($scope.availableInfants.indexOf(($scope.selectedInfants || "").toString()) < 0) {
                    $scope.selectedInfants = $scope.availableInfants[0];
                }

                $scope.persistCriteria();
                // if datepicker is hidden perform an autosearch
                if ($scope.requestArguments.hidedatepicker) {
                    $scope.searchProducts();
                }
            };

            $scope.childChanged = function () {
                $scope.wasSearch = false;

                var maxAdults = ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants));

                if ($scope.maxAdults > 0 && maxAdults > $scope.maxAdults) {
                    maxAdults = $scope.maxAdults;
                }

                $scope.availableAdults = strRange($scope.minAdults, maxAdults + 1);
                if ($scope.availableAdults.indexOf(($scope.selectedAdults || "").toString()) < 0) {
                    $scope.selectedAdults = $scope.availableAdults[0];
                }

                $scope.availableSeniors = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableSeniors.indexOf(($scope.selectedSeniors || "").toString()) < 0) {
                    $scope.selectedSeniors = $scope.availableSeniors[0];
                }

                $scope.availableStudents = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableStudents.indexOf(($scope.selectedStudents || "").toString()) < 0) {
                    $scope.selectedStudents = $scope.availableStudents[0];
                }

                $scope.availableInfants = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

                if ($scope.availableInfants.indexOf(($scope.selectedInfants || "").toString()) < 0) {
                    $scope.selectedInfants = $scope.availableInfants[0];
                }

                $scope.persistCriteria();
                if ($scope.requestArguments.hidedatepicker) {
                    $scope.searchProducts();
                }
            };

            $scope.seniorChanged = function () {
                $scope.wasSearch = false;
                //selectedSeniors
                //availableSeniors

                var maxAdults = ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants));

                if ($scope.maxAdults > 0 && maxAdults > $scope.maxAdults) {
                    maxAdults = $scope.maxAdults;
                }

                $scope.availableAdults = strRange($scope.minAdults, maxAdults + 1);

                if ($scope.availableAdults.indexOf(($scope.selectedAdults)) < 0) {
                    $scope.selectedAdults = $scope.availableAdults[0];
                }
                $scope.availableChild = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableChild.indexOf(($scope.selectedChild || "").toString()) < 0) {
                    $scope.selectedChild = $scope.availableChild[0];
                }
                $scope.availableStudents = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableStudents.indexOf(($scope.selectedStudents || "").toString()) < 0) {
                    $scope.selectedStudents = $scope.availableStudents[0];
                }

                $scope.availableInfants = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

                if ($scope.availableInfants.indexOf(($scope.selectedInfants || "").toString()) < 0) {
                    $scope.selectedInfants = $scope.availableInfants[0];
                }
                $scope.persistCriteria();
                if ($scope.requestArguments.hidedatepicker) {
                    $scope.searchProducts();
                }
            };

            $scope.studentChanged = function () {
                $scope.wasSearch = false;

                var maxAdults = ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants));

                if ($scope.maxAdults > 0 && maxAdults > $scope.maxAdults) {
                    maxAdults = $scope.maxAdults;
                }

                $scope.availableAdults = strRange($scope.minAdults, maxAdults + 1);

                if ($scope.availableAdults.indexOf(($scope.selectedAdults || "").toString()) < 0) {
                    $scope.selectedAdults = $scope.availableAdults[0];
                }

                $scope.availableChild = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableChild.indexOf(($scope.selectedChild || "").toString()) < 0) {
                    $scope.selectedChild = $scope.availableChild[0];
                }
                $scope.availableSeniors = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableSeniors.indexOf(($scope.selectedSeniors || "").toString()) < 0) {
                    $scope.selectedSeniors = $scope.availableSeniors[0];
                }

                $scope.availableInfants = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

                if ($scope.availableInfants.indexOf(($scope.selectedInfants || "").toString()) < 0) {
                    $scope.selectedInfants = $scope.availableInfants[0];
                }
                $scope.persistCriteria();
                if ($scope.requestArguments.hidedatepicker) {
                    $scope.searchProducts();
                }
            };

            $scope.infantChanged = function () {
                $scope.wasSearch = false;

                var maxAdults = ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants));

                if ($scope.maxAdults > 0 && maxAdults > $scope.maxAdults) {
                    maxAdults = $scope.maxAdults;
                }

                $scope.availableAdults = strRange($scope.minAdults, maxAdults + 1);
                if ($scope.availableAdults.indexOf(($scope.selectedAdults || "").toString()) < 0) {
                    $scope.selectedAdults = $scope.availableAdults[0];
                }

                $scope.availableChild = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableChild.indexOf(($scope.selectedChild || "").toString()) < 0) {
                    $scope.selectedChild = $scope.availableChild[0];
                }
                $scope.availableSeniors = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableSeniors.indexOf(($scope.selectedSeniors || "").toString()) < 0) {
                    $scope.selectedSeniors = $scope.availableSeniors[0];
                }

                $scope.availableStudents = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableStudents.indexOf(($scope.selectedStudents || "").toString()) < 0) {
                    $scope.selectedStudents = $scope.availableStudents[0];
                }
                $scope.persistCriteria();
                if ($scope.requestArguments.hidedatepicker) {
                    $scope.searchProducts();
                }
            };

            $scope.showAddToCart = function (unit) {
                return !unit.upTimeProduct || (unit.upTimeProduct.units || "").length;
            };

            $scope.gotoPackageDetails = function (selectedItem) {

                var productSelectTicketCtrl = $scope.$parent;
                if (!productSelectTicketCtrl.$parent) {
                    return;
                }
                var productDetailsCtrl = productSelectTicketCtrl.$parent;
                productDetailsCtrl.setSelectedPackage(selectedItem);
                var packageDetailsParam = {
                    packageCode: selectedItem.code,
                    date: $scope.getSelectedDate() //moment($("#daterange").val(), shoppingCartService.getDateFormat()).format("YYYY-MM-DD")
                };


                var packagesCriteria = activityDetailsCtrl.getPackagesSearchCriteria();
                // packagesCriteria.date = $("#daterange").val(),
                packagesCriteria.children = $scope.selectedChild;
                packagesCriteria.adults = $scope.selectedAdults;
                packagesCriteria.infants = $scope.selectedInfants;
                packagesCriteria.seniors = $scope.selectedSeniors;
                packagesCriteria.students = $scope.selectedStudents;

                activityDetailsCtrl.savePackagesSearchCriteria(packagesCriteria);
                productDetailsCtrl.next($state.$current.name, packageDetailsParam);
            };

            $scope.isDisabledAddToCart = function (unit) {
                return ($scope.showQuantityPicker && $scope.selectedQuantity == 0) || (
                    $scope.selectedAdults == 0 &&
                    (($scope.selectedChild == 0 && $scope.isChildAvailable) || !$scope.selectedChild)
                        (($scope.selectedSeniors == 0 && $scope.isSeniorsAvailable) || !$scope.isSeniorsAvailable)
                    && (($scope.selectedStudents == 0 && $scope.isStudentsAvailable) || !$scope.isStudentsAvailable));
            };

            //additional products
            $scope.fillProductDetailsRecursive = function (ticket, index, callback) {
                if (index === ticket.relatedProducts.requiredProducts.length || !ticket.relatedProducts.requiredProducts[index]) {
                    callback();
                    return;
                }
                var params = {
                    token: jwtService.getPrincipalToken(),
                    productCode: ticket.relatedProducts.requiredProducts[index].productCode,
                    productCategory: ticket.relatedProducts.requiredProducts[index].productCategory,
                    travelDate: $scope.getSelectedDate()//$("#daterange").data().daterangepicker.startDate.format("YYYY-MM-DD")
                };
                productsFactory.getProductWithHiddenUnitsWithCallback(params, function (result) {
                    if (result && result.success && (result.data || "").length) {
                        ticket.relatedProducts.requiredProducts[index].product = result.data[0];
                        ticket.relatedProducts.requiredProducts[index].product.selectedUnit = _.find(ticket.relatedProducts.requiredProducts[index].product.units, function (u) {
                            return ticket.relatedProducts.requiredProducts[index].unitCode === u.unitCode;
                        });
                        if (!ticket.requiredProducts) {
                            ticket.requiredProducts = [];
                        }
                        ticket.requiredProducts.push(ticket.relatedProducts.requiredProducts[index]);
                    }
                    $scope.fillProductDetailsRecursive(ticket, index + 1, callback);
                });
            };

            $scope.fillOptionalProductDetailsRecursive = function (parentProduct, products, index, callback) {
                if (index === products.length || !products[index]) {
                    callback();
                    return;
                }
                var params = {
                    token: jwtService.getPrincipalToken(),
                    productCode: products[index].productCode,
                    productCategory: products[index].productCategory,
                    travelDate: $scope.getSelectedDate()
                };
                productsFactory.getProductWithCallback(params, function (result) {
                    if (result && result.success && (result.data || "").length) {
                        products[index].product = result.data[0];
                        products[index].product.selectedUnit = _.find(products[index].product.units, function (u) {
                            return products[index].unitCode === u.unitCode;
                        });
                        if (!parentProduct.optionalExtras) {
                            parentProduct.optionalExtras = [];
                        }
                        parentProduct.optionalExtras.push(products[index]);
                    }
                    $scope.fillOptionalProductDetailsRecursive(parentProduct, products, index + 1, callback);
                });
            };


            $scope.showRequiredProductsModal = function (ticket) {
                var popupProducts = _.filter(ticket.requiredProducts, function (reqProd) {
                    if (!reqProd.product) return false;
                    if (reqProd.product.productType === "FEE") {
                        reqProd.product.isFee = true;
                        return false;
                    }
                    return true;
                });
                if (popupProducts.length === 0) {
                    $scope.getBookingQuoteObj(ticket);
                    return;
                }
                var requiredModalInstance = $uibModal.open({
                    animation: true,
                    templateUrl: "requiredProductsModal.html",
                    controller: "requiredProductsModalCtrl",
                    size: "book-required-products",
                    resolve: {
                        "products": { followingProductSingle: "product", followingProductMultiple: "products", yourProductTitle: "attraction", data: popupProducts }
                    },
                    backdrop: "true"
                });
                requiredModalInstance.result.then(function (result) {
                    $scope.getBookingQuoteObj(ticket);
                }, function () {
                    //console.log("dismiss");
                });
            };


            //
            $scope.getAdditionalProducts = function (ticket) {
                console.log("getAdditionalProducts");
                //
                $scope.isLoading = true;
                var getOptionalProductsRelatedServicesPromises = [];
                if ((ticket.optionalExtras || []).length) {
                    _.each(ticket.optionalExtras, function (op) {
                        if (!op.product || !(op.product.units).length) return;
                        getOptionalProductsRelatedServicesPromises.push(new Promise(function (resolve, reject) {
                            var requestParamsMulti = {
                                token: jwtService.getPrincipalToken(),
                                product: op.product,
                                totalGuests: $scope.getTotalGuests()
                            };
                            productsFactory.fillProductUnitsRelatedServicesMulti(requestParamsMulti, resolve);
                        }));
                    });
                }
                //

                Promise.all(getOptionalProductsRelatedServicesPromises).then(function () {
                    //
                    var getGiftWrappingProductPromises = [];
                    if ((ticket.optionalExtras || []).length) {
                        _.each(ticket.optionalExtras, function (op) {
                            if (!op.product || !(op.product.units).length) return;

                            //
                            _.each(op.product.units, function (opUnit) {
                                if (opUnit && opUnit.relatedProducts && (opUnit.relatedProducts.optionalExtras || "").length) {
                                    _.each(opUnit.relatedProducts.optionalExtras, function (opExtra) {
                                        getGiftWrappingProductPromises.push(new Promise(function (resolve, reject) {
                                            //
                                            var params = {
                                                token: jwtService.getPrincipalToken(),
                                                productCode: opExtra.productCode,
                                                productCategory: opExtra.productCategory,
                                                travelDate: $scope.getSelectedDate()
                                            };
                                            productsFactory.getProductWithCallback(params, function (result) {
                                                if (result && result.success && (result.data || "").length) {
                                                    opExtra.product = result.data[0];
                                                    opExtra.product.selectedUnit = opExtra.product.units && _.find(opExtra.product.units, function (u) {
                                                        return opExtra.unitCode === u.unitCode;
                                                    });
                                                }
                                                resolve(1);
                                            });
                                            //
                                        }));
                                    });
                                }
                            });// 

                        });
                    }
                    return Promise.all(getGiftWrappingProductPromises);
                    //
                }).then(function () {
                    if (!(ticket.requiredProducts || "").length) {
                        //$scope.shuffleLoadingIndex();
                        $scope.isLoading = true;

                        if (ticket.relatedProducts && (ticket.relatedProducts.requiredProducts || "").length) {
                            //get product details for each additional required product
                            if (!(ticket.requiredProducts || "").length) {
                                $scope.fillProductDetailsRecursive(ticket, 0, function () {
                                    $scope.isLoading = false;

                                    if ((ticket.requiredProducts || "").length) {
                                        $scope.showRequiredProductsModal(ticket);
                                    } else {
                                        $scope.getBookingQuoteObj(ticket);
                                    }
                                });
                            } else {
                                $scope.isLoading = false;
                                $scope.showRequiredProductsModal(ticket);
                            }

                        } else {
                            //call the callback
                            $scope.getBookingQuoteObj(ticket);
                        }

                    } else {
                        $scope.isLoading = false;
                        $scope.showRequiredProductsModal(ticket);
                    }
                });
            };

            $scope.getBookingQuoteObj = function (ticket) {
                $scope.isLoading = true;
                //$scope.shuffleLoadingIndex();


                var removeExistingCartItemPromise = undefined;

                if ($scope.updateItem) {
                    removeExistingCartItemPromise = new Promise(function (resolve, reject) {
                        var requestParams = {
                            apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                            token: jwtService.getPrincipalToken(),
                            index: $scope.updateIndex,
                            productCode: $scope.updateItem.ProductCode
                        };

                        shoppingCartService.setStorageCart($scope.cart, function () {
                            shoppingCartService.updateCartComponents(requestParams, function (shoppingCart) {
                                if (shoppingCart && (shoppingCart.Items || '').length) {
                                    $scope.cart = shoppingCart;
                                } else {
                                    // window.location = "/";
                                }
                                resolve(1);
                            });
                        });
                    }); // Promise
                } else {
                    removeExistingCartItemPromise = Promise.resolve(1);
                }
                removeExistingCartItemPromise.then(function () {

                    $scope.trackLobTitle = $scope.mainProduct && $scope.mainProduct.productDescriptions
                        && (
                            $scope.mainProduct.productDescriptions.genericTitle || ($scope.mainProduct.productDescriptions.titles && $scope.mainProduct.productDescriptions.titles.length > 0 ? $scope.mainProduct.productDescriptions.titles[0] : $scope.mainProduct.name));

                    var trackingUnitName = ticket.productDescriptions && ticket.productDescriptions.titles && ticket.productDescriptions.titles.length > 0 ? ticket.productDescriptions.titles[0] : ticket.name;

                    var components = [];
                    var bookingComponent = {
                        "Id": $scope.product.code + ticket.unitCode,
                        "ProductCategory": $scope.product.productCategory,
                        "ProductType": $scope.product.productType,
                        "ProductCode": $scope.product.code,
                        "StartDate": $scope.product.startDate,
                        "EndDate": $scope.product.endDate,
                        "Name": $scope.product.name,
                        "Description": $scope.product.description,
                        "ProductDescriptions": $scope.product.productDescriptions,
                        "Price": ticket.price,
                        "ChildPrice": ticket.childPrice,
                        "SeniorPrice": ticket.seniorPrice,
                        "StudentPrice": ticket.studentPrice,
                        "NumberOfAdults": $scope.showQuantityPicker ? 0 : $scope.selectedAdults,
                        "NumberOfChildren": $scope.showQuantityPicker ? 0 : ($scope.isChildAvailable ? $scope.selectedChild : 0),
                        "NumberOfInfants": 0,
                        "Status": "New",
                        "UnitCode": ticket.unitCode,
                        "UnitDescription": (ticket.productDescriptions && ticket.productDescriptions.titles && ticket.productDescriptions.titles.length > 0) ? ticket.productDescriptions.titles[0] : ticket.description,
                        "PickupLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                        "DropoffLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                        "StartingLocation": $scope.product.startingLocation,
                        "Destination": $scope.product.destination,
                        "Remarks": [],
                        "AddedFromWebTray": $scope.requestArguments.fromwebtray,
                        "hideDate": $scope.requestArguments.hidedatepicker,
                        "Duration": (ticket.durationType || "").toUpperCase() == 'HOUR' ? (ticket.upTimeProduct && ticket.upTimeProduct.selectedUnit && parseInt(ticket.upTimeProduct.selectedDuration)) : 0,
                        "NumberOfUnits": $scope.showQuantityPicker ? $scope.selectedQuantity : 0,
                        "pricedPerUnit": $scope.showQuantityPicker,
                        "IsGiftTicket": ticket.isGiftTicket || $scope.product.isGiftTicket,
                        "_trackingLob": $scope.trackLobTitle,
                        "_trackingUnitName": trackingUnitName,
                        "_optionalExtras": ticket.optionalExtras
                    };

                    if (!$scope.showQuantityPicker) {
                        if ($scope.isSeniorsAvailable) {
                            bookingComponent.NumberOfSeniors = $scope.selectedSeniors;
                        }
                        if ($scope.isStudentsAvailable) {
                            bookingComponent.NumberOfStudents = $scope.selectedStudents;
                        }
                        if ($scope.isInfantsAvailable) {
                            bookingComponent.NumberOfInfants = $scope.selectedInfants;
                        }
                    }

                    components.push(bookingComponent);
                    //set selected time

                    var selectedTimeStr = undefined;
                    if ($scope.showQuantityPicker && ((ticket.durationType || "").toUpperCase() == 'HOUR' || (ticket.durationType || "").toUpperCase() == 'DAY')) {
                        var isFullDay = (ticket.durationType || "").toUpperCase() == 'DAY';
                        if (isFullDay && ticket.upTimeProduct) {
                            ticket.upTimeProduct.selectedUnit = ticket.upTimeProduct.units && ticket.upTimeProduct.units[0];
                        }

                        if (ticket.upTimeProduct && ticket.upTimeProduct.selectedUnit) {
                            var timeProduct = ticket.upTimeProduct;
                            //
                            var duration = parseInt(ticket.upTimeProduct.selectedDuration) || 1;
                            var index = _.findIndex(ticket.upTimeProduct.filteredUnits, function (el) { return el.unitCode == ticket.upTimeProduct.selectedUnit.unitCode; });

                            if (index < 0) {
                                console.log("No unit selected!");
                                return;
                            }

                            selectedTimeStr = moment(ticket.upTimeProduct.selectedUnit.startTime).format("hh:mm A");
                            var upperBound = isFullDay ? ticket.upTimeProduct.filteredUnits.length : index + duration;
                            for (var i = index; i < upperBound; i++) {
                                var timeUnit = ticket.upTimeProduct.filteredUnits[i];
                                if (!timeUnit) {
                                    console.log("Time unit is null!");
                                    continue;
                                }

                                var timeComponent = {
                                    "Id": timeProduct.code + timeUnit.unitCode,
                                    "ProductCategory": timeProduct.productCategory,
                                    "ProductType": timeProduct.productType,
                                    "ProductCode": timeProduct.code,
                                    "StartDate": timeProduct.startDate,
                                    "EndDate": timeProduct.endDate,
                                    "Name": timeProduct.name,
                                    "Description": timeProduct.description,
                                    "ProductDescriptions": timeProduct.productDescriptions,
                                    "Price": 0.0,
                                    "ChildPrice": 0,
                                    "NumberOfAdults": 0,
                                    "NumberOfChildren": 0,
                                    "NumberOfInfants": 0,
                                    "Status": "New",
                                    "UnitCode": timeUnit.unitCode,
                                    "UnitDescription": timeUnit.description,
                                    "PickupLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                                    "DropoffLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                                    "StartingLocation": timeProduct.startingLocation,
                                    "Destination": timeProduct.destination,
                                    "Remarks": [],
                                    "IsPrimary": timeProduct.isPrimary,
                                    "ParentCode": $scope.product.code,
                                    "NumberOfUnits": $scope.showQuantityPicker ? $scope.selectedQuantity : 0,
                                    "_trackingLob": $scope.trackLobTitle,
                                    "_trackingUnitName": trackingUnitName
                                };
                                components.push(timeComponent);
                            }
                        }
                    } else {
                        if (ticket.upTimeProduct && ticket.upTimeProduct.selectedUnit) {
                            var timeProduct = ticket.upTimeProduct;
                            var timeUnit = ticket.upTimeProduct.selectedUnit;
                            selectedTimeStr = moment(timeUnit.startTime).format("hh:mm A");
                            var timeComponent = {
                                "Id": timeProduct.code + timeUnit.unitCode,
                                "ProductCategory": timeProduct.productCategory,
                                "ProductType": timeProduct.productType,
                                "ProductCode": timeProduct.code,
                                "StartDate": timeProduct.startDate,
                                "EndDate": timeProduct.endDate,
                                "Name": timeProduct.name,
                                "Description": timeProduct.description,
                                "ProductDescriptions": timeProduct.productDescriptions,
                                "Price": 0.0,
                                "ChildPrice": 0,
                                "NumberOfAdults": $scope.selectedAdults,
                                "NumberOfChildren": $scope.isChildAvailable ? $scope.selectedChild : 0,
                                "NumberOfInfants": 0,
                                "Status": "New",
                                "UnitCode": timeUnit.unitCode,
                                "UnitDescription": timeUnit.description,
                                "PickupLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                                "DropoffLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                                "StartingLocation": timeProduct.startingLocation,
                                "Destination": timeProduct.destination,
                                "Remarks": [],
                                "IsPrimary": timeProduct.isPrimary,
                                "ParentCode": $scope.product.code,
                                "_trackingLob": $scope.trackLobTitle,
                                "_trackingUnitName": trackingUnitName
                            };
                            if ($scope.isSeniorsAvailable) {
                                timeComponent.NumberOfSeniors = $scope.selectedSeniors;
                            }
                            if ($scope.isStudentsAvailable) {
                                timeComponent.NumberOfStudents = $scope.selectedStudents;
                            }
                            if ($scope.isInfantsAvailable) {
                                timeComponent.NumberOfInfants = $scope.selectedInfants;
                            }
                            components.push(timeComponent);
                        }

                        if (ticket.downTimeProduct && ticket.downTimeProduct.selectedUnit) {
                            var dtimeProduct = ticket.downTimeProduct;
                            var dtimeUnit = ticket.downTimeProduct.selectedUnit;
                            //selectedTimeStr = moment(dtimeUnit.startTime).format("hh:mm A");
                            var dtimeComponent = {
                                "Id": dtimeProduct.code + dtimeUnit.unitCode,
                                "ProductCategory": dtimeProduct.productCategory,
                                "ProductType": dtimeProduct.productType,
                                "ProductCode": dtimeProduct.code,
                                "StartDate": dtimeProduct.startDate,
                                "EndDate": dtimeProduct.endDate,
                                "Name": dtimeProduct.name,
                                "Description": dtimeProduct.description,
                                "ProductDescriptions": dtimeProduct.productDescriptions,
                                "Price": 0.0,
                                "ChildPrice": 0,
                                "NumberOfAdults": $scope.selectedAdults,
                                "NumberOfChildren": $scope.isChildAvailable ? $scope.selectedChild : 0,
                                "NumberOfInfants": 0,
                                "Status": "New",
                                "UnitCode": dtimeUnit.unitCode,
                                "UnitDescription": dtimeUnit.description,
                                "PickupLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                                "DropoffLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                                "StartingLocation": dtimeProduct.startingLocation,
                                "Destination": dtimeProduct.destination,
                                "Remarks": [],
                                "IsPrimary": dtimeProduct.isPrimary,
                                "ParentCode": $scope.product.code,
                                "_trackingLob": $scope.trackLobTitle,
                                "_trackingUnitName": trackingUnitName
                            };
                            if ($scope.isSeniorsAvailable) {
                                dtimeComponent.NumberOfSeniors = $scope.selectedSeniors;
                            }
                            if ($scope.isStudentsAvailable) {
                                dtimeComponent.NumberOfStudents = $scope.selectedStudents;
                            }
                            if ($scope.isInfantsAvailable) {
                                dtimeComponent.NumberOfInfants = $scope.selectedInfants;
                            }
                            components.push(dtimeComponent);
                        }
                    }

                    if (ticket.requiredProducts) {
                        _.each(ticket.requiredProducts, function (reqProd) {
                            components.push({
                                "Id": reqProd.product.id,
                                "ProductCategory": reqProd.product.productCategory,
                                "ProductType": reqProd.product.productType,
                                "ProductCode": reqProd.product.code,
                                "StartDate": reqProd.product.startDate,
                                "EndDate": reqProd.product.endDate,
                                "Name": reqProd.product.name,
                                "Description": reqProd.product.description,
                                "ProductDescriptions": reqProd.product.productDescriptions,
                                "Price": reqProd.product.price,
                                "ChildPrice": reqProd.product.price,
                                "NumberOfAdults": $scope.selectedAdults,
                                "NumberOfChildren": $scope.isChildAvailable ? $scope.selectedChild : 0,
                                "NumberOfSeniors": $scope.isSeniorsAvailable ? $scope.selectedSeniors : 0,
                                "NumberOfStudents": $scope.isStudentsAvailable ? $scope.selectedStudents : 0,
                                "NumberOfInfants": $scope.isInfantsAvailable ? $scope.selectedInfants : 0,
                                "Status": "New",
                                "UnitCode": reqProd.product.selectedUnit ? reqProd.product.selectedUnit.unitCode : reqProd.unitCode,
                                "UnitDescription": reqProd.product.selectedUnit ? reqProd.product.selectedUnit.description : reqProd.product.description,
                                "PickupLocation": reqProd.product.selectedUnit ? reqProd.product.selectedUnit.selectedPickUp : undefined,
                                "DropoffLocation": reqProd.product.selectedUnit ? reqProd.product.selectedUnit.selectedDropOff : undefined,
                                "StartingLocation": reqProd.product.startingLocation,
                                "Destination": undefined,
                                "Remarks": [],
                                "IsFee": reqProd.product.isFee,
                                "ShowInCart": reqProd.showInCart,
                                "IsGiftTicket": reqProd.product.selectedUnit && reqProd.product.selectedUnit.isGiftTicket || reqProd.product.isGiftTicket || false,
                                "_trackingLob": $scope.trackLobTitle,
                                "_trackingUnitName": trackingUnitName
                            });
                        });
                    }

                    var bookingToQuote = {
                        "Components": components
                    };

                    var specialProductsRequestParams = {
                        apiUrl: $scope.$parent.$parent.getWebUrl(),
                        token: jwtService.getPrincipalToken(),
                        dataToPost: {
                            "Booking": bookingToQuote
                        }
                    };

                    shoppingCartService.handleSpecialProducts(specialProductsRequestParams, function (result) {
                        if (!result) {
                            $scope.isLoading = false;
                            return;
                        }

                        var requestParams = {
                            apiUrl: $scope.$parent.$parent.getWebUrl(),
                            token: jwtService.getPrincipalToken(),
                            dataToPost: {
                                "BookingToQuote": result
                            },
                            startDate: $scope.getSelectedDate(shoppingCartService.getDateFormat()), //$("#daterange").val(),
                            endDate: undefined,
                            startTime: selectedTimeStr ? selectedTimeStr : utilsFactory.getLabel("general.anytime"),
                            endTime: undefined
                        };


                        //shoppingCartService.addComponentsToCart(requestParams,);
                        var successCartUpdateCallback = function (result) {
                            if (result) {
                                var isEnhanceBookingPageEnabled = ($scope.selectedLanguage && $scope.selectedLanguage.enableEnhanceBookingPage) || ($scope.anonymUser && $scope.anonymUser.enableEnhanceBookingPage);
                                var redirectToUrl = shoppingCartService.utils.getAfterAddToCartPageUrl(generalCtrl.selectedGeographyCode, isEnhanceBookingPageEnabled);
                                window.location = utilsFactory.addPersistentQueryStringsParams(redirectToUrl);
                            } else {
                                $scope.isLoading = false;
                            }
                        };


                        //shoppingCartService.addComponentsToCart(requestParams, function (result) {                            
                        //    if (result) {
                        //        window.location = (generalCtrl.selectedGeographyCode ? "/" + generalCtrl.selectedGeographyCode : "") + "/checkout";
                        //    } else {
                        //        $scope.isLoading = false;
                        //    }
                        //});                               

                        shoppingCartService.quoteComponents(requestParams, function (quoteResult) {
                            var self = this;
                            if (!quoteResult || !quoteResult.quote) return;
                            if (quoteResult.quote.ExpressConsentRequired) {
                                $scope.isLoading = false;
                                var compsThatRequireConsent = [];
                                _.each(quoteResult.quote.Components, function (qComp, i) {
                                    if (qComp && qComp.ExpressConsentOptions && qComp.ExpressConsentOptions.ExpressConsentRequired) {
                                        compsThatRequireConsent.push({ details: requestParams.dataToPost.BookingToQuote.Components[i], expressConsentOptions: qComp.ExpressConsentOptions });
                                    }
                                });
                                var requiredModalInstance = $uibModal.open({
                                    animation: true,
                                    templateUrl: "expressConsentModal.html",
                                    controller: "expressConsentModalCtrl",
                                    size: "book-required-products",
                                    resolve: {
                                        "expressConsent": {
                                            title: utilsFactory.getLabel("general.expressConsent.ConfirmModalTitle"),
                                            message: utilsFactory.getLabel("general.expressConsent.ConfirmModalMessage"),
                                            components: compsThatRequireConsent
                                        }
                                    },
                                    backdrop: "true"
                                });
                                // "components": { followingProductSingle: "product", followingProductMultiple: "products", yourProductTitle: "attraction", data: popupProducts }

                                requiredModalInstance.result.then(function (result) {
                                    $scope.product.selectedUnit = ticket;
                                    quoteResult.lastAddedItemDetails = $scope.product;

                                    shoppingCartService.addQuotedDataToCart(quoteResult, successCartUpdateCallback)
                                }, function (e) {
                                    //console.log("dismiss");
                                    // debugger;
                                });
                            } else {
                                $scope.product.selectedUnit = ticket;
                                quoteResult.lastAddedItemDetails = $scope.product;

                                shoppingCartService.addQuotedDataToCart(quoteResult, successCartUpdateCallback)
                            }
                            // if (!result) return callback && callback();
                            // this.addQuotedDataToCart(result, callback);
                        });

                    });
                }); // EndPromise resolve            


            };

            $scope.handleNext = function (ticket) {

                //if ($scope.showPackageModal && $scope.packageModalLabels) {
                //    activitiesService.getActivityWizardModel(function (wizardResult) {
                //        if (wizardResult.success && wizardResult.data) {
                //            var ticketTypes = wizardResult.data.ticketTypes;
                //            var containsPackages = false;
                //            if (ticketTypes) {
                //                containsPackages = _.some(ticketTypes, function (val) {
                //                    return val.name && val.name.toLowerCase().indexOf("package") >= 0;
                //                });
                //            }

                //            if (containsPackages && !wizardResult.data.bookedModalShowed) {

                //                var modalInstance = $uibModal.open({
                //                    animation: true,
                //                    templateUrl: "bookModal.html",
                //                    controller: "bookModalCtrl",
                //                    size: "lg",
                //                    resolve: {
                //                        ticket: function () {
                //                            return ticket;
                //                        },
                //                        packageModalLabels: function () {
                //                            return $scope.packageModalLabels;
                //                        }
                //                    }
                //                });

                //                modalInstance.result.then(function (ticket) {
                //                    wizardResult.data.bookedModalShowed = true;
                //                    wizardResult.data.ticket = ticket;

                //                    activitiesService.setActivityWizardModel(wizardResult.data, function () {
                //                        $rootScope.$broadcast("ActivityWizardModelChanged", {
                //                            wizardModel: wizardResult.data,
                //                            callback: function () {
                //                                //$scope.getBookingQuoteObj(ticket);
                //                                $scope.getAdditionalProducts(ticket);
                //                            }
                //                        });
                //                    });
                //                }, function (reason) {
                //                    if (reason && reason.goToPackage) {
                //                        var activitySelectTicketCtrl = $scope.$parent;
                //                        var activityDetailsCtrl = activitySelectTicketCtrl.$parent;
                //                        //set package criteria filters
                //                        var packagesCriteria = activityDetailsCtrl.getPackagesSearchCriteria();
                //                        packagesCriteria.date = $("#daterange").val(),
                //                        packagesCriteria.children = $scope.selectedChild;
                //                        packagesCriteria.adults = $scope.selectedAdults;
                //                        activityDetailsCtrl.savePackagesSearchCriteria(packagesCriteria);

                //                        $state.go("select-ticket.packages");
                //                    } else {
                //                        //$scope.getBookingQuoteObj(ticket);
                //                        $scope.getAdditionalProducts(ticket);
                //                    }
                //                });

                //            } else {
                //                //$scope.getBookingQuoteObj(ticket);
                //                $scope.getAdditionalProducts(ticket);
                //            }
                //        } else {
                //            //$scope.getBookingQuoteObj(ticket);
                //            $scope.getAdditionalProducts(ticket);
                //        }
                //    });
                //} else {
                //$scope.getBookingQuoteObj(ticket);
                $scope.getAdditionalProducts(ticket);
                //}
            };

            $scope.moveNext = function () {
                var activitySelectTicketCtrl = $scope.$parent;
                if (activitySelectTicketCtrl.$parent) {
                    var activityDetailsCtrl = activitySelectTicketCtrl.$parent;
                    activityDetailsCtrl.next($state.$current.name);
                }
            };

            $scope.isSelectedTimeValid = function (ticket) {
                if (!ticket) return true;

                var isValid = true;
                if (ticket.upTimeProduct && (ticket.upTimeProduct.units || '').length && !ticket.upTimeProduct.selectedUnit)//|| !(ticket.upTimeProduct.units || "").length
                    isValid = false;

                if (ticket.downTimeProduct && (ticket.downTimeProduct.units || '').length && !ticket.downTimeProduct.selectedUnit)
                    isValid = false;

                return isValid;
            };

            $scope.gotoCheckout = function (ticket, $valid) {
                var hasError = false;
                if (!$valid) {
                    $scope.resetSubmitted();
                    $scope.submitted[ticket.unitCode] = true;

                    // return;
                }
                $scope.globalErrors = [];

                //var activitySelectTicketCtrl = $scope.$parent;
                //var activityDetailsCtrl = activitySelectTicketCtrl.$parent;
                //var generalCtrl = activityDetailsCtrl.$parent;

                var totalGuests = $scope.showQuantityPicker ? parseInt($scope.selectedQuantity) : (
                    parseInt($scope.selectedAdults || 0) + parseInt($scope.selectedChild || 0) +
                    parseInt($scope.selectedSeniors || 0) + parseInt($scope.selectedStudents, 0) + parseInt($scope.selectedInfants, 0));

                if (ticket.upTimeProduct && ticket.upTimeProduct.selectedUnit) {
                    var isAvailable = ticket.upTimeProduct.selectedUnit.availability >= (totalGuests);
                    if (!isAvailable) {
                        $scope.globalErrors.push(utilsFactory.getLabel("activity.error.unitUnavailable").replace("{0}",
                            ticket.upTimeProduct.selectedUnit.availability));
                        generalCtrl.toggleModalWithData("SubmitActivityErrors", $scope.globalErrors);
                        return;
                    } else if (ticket.downTimeProduct && ticket.downTimeProduct.selectedUnit) {
                        isAvailable = ticket.downTimeProduct.selectedUnit.availability >= (totalGuests);
                        if (!isAvailable) {
                            $scope.globalErrors.push(utilsFactory.getLabel("activity.error.unitUnavailable").replace("{0}",
                                ticket.downTimeProduct.selectedUnit.availability));
                            generalCtrl.toggleModalWithData("SubmitActivityErrors", $scope.globalErrors);

                            return;
                        }
                    }
                }

                if ($scope.showQuantityPicker) {
                    var isFullDay = (ticket.durationType || "").toUpperCase() == 'DAY';
                    if (isFullDay && ticket.upTimeProduct) {
                        ticket.upTimeProduct.selectedUnit = ticket.upTimeProduct.units && ticket.upTimeProduct.units[0];
                    }
                }

                if (ticket.upTimeProduct && (ticket.upTimeProduct.units || '').length && !ticket.upTimeProduct.selectedUnit)//|| !(ticket.upTimeProduct.units || "").length
                    $scope.globalErrors.push(utilsFactory.getLabel("activity.error.requiredUpTime"));

                if (ticket.downTimeProduct && (ticket.downTimeProduct.units || '').length && !ticket.downTimeProduct.selectedUnit)
                    $scope.globalErrors.push(utilsFactory.getLabel("activity.error.requiredDownTime"));


                if ($scope.globalErrors.length) {
                    generalCtrl.toggleModalWithData("SubmitActivityErrors", $scope.globalErrors);

                    return;
                }

                if (!$valid) {
                    return;
                }
                $scope.handleNext(ticket);
                // $scope.getBookingQuoteObj(ticket);
            };

            $scope.persistCriteria = function () {
                if ($scope.$parent) {
                    var activitySelectTicketCtrl = $scope.$parent;
                    if (activitySelectTicketCtrl.$parent) {
                        var activityDetailsCtrl = activitySelectTicketCtrl.$parent;

                        var criteria = {
                            date: $scope.getSelectedDate(shoppingCartService.getDateFormat()),//$("#daterange").val(),
                            time: $scope.selectedTime ? $scope.selectedTime : $scope.noTime,
                            quantity: $scope.quantity,
                            adults: $scope.selectedAdults,
                            child: $scope.selectedChild,
                            seniors: $scope.selectedSeniors,
                            students: $scope.selectedStudents,
                            infants: $scope.selectedInfants,
                            product: $scope.product,
                            packages: $scope.packages,
                            attractionTimes: $scope.attractionTimes,
                            optionalExtras: $scope.optionalExtras
                        };
                        activityDetailsCtrl.saveSearchCriteria(criteria);
                    }
                }
            };
            $scope.getCriteria = function () {
                if ($scope.$parent) {
                    var activitySelectTicketCtrl = $scope.$parent;
                    if (activitySelectTicketCtrl.$parent) {
                        var activityDetailsCtrl = activitySelectTicketCtrl.$parent;

                        return activityDetailsCtrl.getSearchCriteria();
                    }
                }

                return undefined;
            };

            $scope.getSearchBtnLabel = function () {
                return ($scope.actionRegionCode || "").toLowerCase().indexOf("folv") >= 0
                    ? utilsFactory.getLabel("general.findTicketsBtn")
                    : utilsFactory.getLabel("general.searchbtn");
            };

            $scope.getDatePickerLabel = function () {
                return ($scope.actionRegionCode || "").toLowerCase().indexOf("folv") >= 0
                    ? utilsFactory.getLabel("general.ride-date-filter")
                    : utilsFactory.getLabel("general.arriving-on-filter");
            };

            $scope.getTimeDescription = function (timeUnit, timeProduct) {
                if (!timeUnit) {
                    return "";
                }

                if (timeUnit.isDisabled) {
                    return utilsFactory.getLabel("general.no-avail-times");
                }
                if (timeUnit.description) return timeUnit.description;

                switch (timeProduct.productType) {
                    case "FLT-TIME":
                        return moment(timeUnit.startTime).format("hh:mm A");
                    default:
                        return moment(timeUnit.startTime).format("hh:mm A");
                }
            };

            $scope.checkIfFullDayAvailable = function (unit) {
                if (!$scope.showQuantityPicker || !unit || (unit.durationType || "").toUpperCase() != 'DAY' || !unit.upTimeProduct) return;

                var prevTime = undefined;
                unit.isFullDayAvailable = unit.upTimeProduct.filteredUnits.length > 0;

                for (var i = 0; i < unit.upTimeProduct.filteredUnits.length; i++) {
                    var timeUnit = unit.upTimeProduct.filteredUnits[i];
                    var currTime = timeUnit && timeUnit.startTime && new Date(timeUnit.startTime);

                    if (!timeUnit || !$scope.isUnitAvailable(timeUnit) || $scope.isUnitSoldOut(timeUnit) || (prevTime && prevTime.getHours() + 1 != currTime.getHours())) {
                        unit.isFullDayAvailable = false;
                        break;
                    }
                    prevTime = currTime;
                }
            };

            $scope.setDurationHours = function (unit) {
                if (!unit || (unit.durationType || "").toUpperCase() != 'HOUR' || !unit.upTimeProduct) return;

                if (!unit.upTimeProduct.selectedUnit) {
                    // strange issue, setDownTimes is called with no selectedUnit, and the selected time of the updated item is lost
                    if (!$scope.updateItem) {
                        unit.upTimeProduct.selectedDuration = undefined;
                    }
                    return;
                }
                var productCode = ($scope.product && $scope.product.code) || ($scope.mainProduct && $scope.mainProduct.code);
                var unitCode = unit.unitCode;
                var maxDurationOverwriteValue = -1;
                // 
                var maxDurationOverwriteData = $scope.requestArguments.maxdurationoverwriteforunitcodes && _.find($scope.requestArguments.maxdurationoverwriteforunitcodes, function (item) {
                    var itemKey = item && item.split(' ')[0];
                    return itemKey == unitCode || itemKey == (productCode + "_" + unitCode);
                });

                if (maxDurationOverwriteData) {
                    maxDurationOverwriteValue = parseInt(maxDurationOverwriteData.split(' ')[1]);
                }
                //

                var index = _.findIndex(unit.upTimeProduct.filteredUnits, function (el) { return el.unitCode == unit.upTimeProduct.selectedUnit.unitCode; });
                if (index < 0) {
                    return;
                }

                var maxHours = 1;
                if (maxDurationOverwriteValue >= 1) {
                    maxHours = maxDurationOverwriteValue+1; // underscore range end param is exclusive
                } else {
                    var prevTime = undefined; //unit.upTimeProduct.filteredUnits[index - 1] && unit.upTimeProduct.filteredUnits[index - 1].startTime && new Date(unit.upTimeProduct.filteredUnits[index - 1].startTime);

                    for (var i = index; i < unit.upTimeProduct.filteredUnits.length; i++) {
                        var timeUnit = unit.upTimeProduct.filteredUnits[i];
                        var currTime = timeUnit && timeUnit.startTime && new Date(timeUnit.startTime);

                        if (!timeUnit || !$scope.isUnitAvailable(timeUnit) || $scope.isUnitSoldOut(timeUnit) || (prevTime && prevTime.getHours() + 1 != currTime.getHours())) {
                            break;
                        }
                        prevTime = currTime;
                        maxHours++;
                    }
                }

                unit.upTimeProduct.availableDurationHours = strRange(1, maxHours);

                if (unit.upTimeProduct.availableDurationHours.indexOf(String(unit.upTimeProduct.selectedDuration)) < 0) {
                    unit.upTimeProduct.selectedDuration = unit.upTimeProduct.availableDurationHours[0];
                }
            };

            $scope.setUnitBoardingTime = function (unit) {
                if (!$scope.showBoardingTimeInfo) return;

                var selectedTimeUnit = unit && unit.upTimeProduct && unit.upTimeProduct.selectedUnit;
                if (!selectedTimeUnit || !selectedTimeUnit.startTime) return;

                var momentObj = moment(selectedTimeUnit.startTime);
                if (!momentObj || !momentObj.isValid()) return;

                var timeStr = momentObj.subtract(15, 'minutes').format("hh:mm A");
                selectedTimeUnit._boardingTime = timeStr;
            };

            $scope.setDownTimes = function (unit, fromUI) {
                if (!unit || (unit.durationType || "").toUpperCase() == 'HOUR' || !unit.upTimeProduct || !unit.downTimeProduct) return;
                if (!unit.upTimeProduct.selectedUnit) {
                    // strange issue, setDownTimes is called with no selectedUnit, and the selected time of the updated item is lost
                    if (!$scope.updateItem) {
                        unit.downTimeProduct.selectedUnit = undefined;
                    }
                    return;
                }

                var startMin = moment(unit.upTimeProduct.selectedUnit.startTime);
                var startRecomm = moment(unit.upTimeProduct.selectedUnit.startTime);

                var interval = unit.downTimeProduct.minimumIntervalInMinutes
                    ? parseInt(unit.downTimeProduct.minimumIntervalInMinutes) : 0;

                startMin.add(interval, "m");

                unit.downTimeProduct.filteredUnits = _.filter(unit.downTimeProduct.units, function (un) {
                    return startMin <= moment(un.startTime);
                });

                if (!(unit.downTimeProduct.filteredUnits || "").length) { // || !unit.downTimeProduct.recommendedIntervalInMinutes
                    unit.downTimeProduct.selectedUnit = undefined;
                    return;
                }

                if (unit.downTimeProduct.recommendedIntervalInMinutes) {
                    interval = parseInt(unit.downTimeProduct.recommendedIntervalInMinutes);
                    startRecomm.add(interval, "m");

                    if (!unit.downTimeProduct.canModifyTime || !unit.downTimeProduct.selectedUnit || startRecomm > moment(unit.downTimeProduct.selectedUnit.startTime)) {
                        unit.downTimeProduct.selectedUnit = _.find(unit.downTimeProduct.filteredUnits, function (un) {
                            return startRecomm <= moment(un.startTime);
                        });
                    }
                }

                if (!unit.downTimeProduct.selectedUnit) {
                    unit.downTimeProduct.selectedUnit = unit.downTimeProduct.filteredUnits[0];
                }
            };

            $scope.isUnitSoldOut = function (unit) {
                return unit.upTimeProduct &&
                    ((!(unit.upTimeProduct.units || '').length) ||
                        (
                            !(unit.upTimeProduct.filteredUnits || '').length
                            || ((unit.upTimeProduct.filteredUnits || '').length == 1 && unit.upTimeProduct.filteredUnits[0].isDisabled)));
            };

            $scope.isFullDayUnitNotAvailable = function (unit) {
                if (!unit || (unit.durationType || "").toUpperCase() != 'DAY') return false;
                return unit.isFullDayAvailable === false ? true : false;
            };

            $scope.isUnitMultiplesRequiredInvalid = function (unit) {
                // 
                if (!unit || !(unit.multiplesRequired > 0)) return false;

                if ($scope.selectedAdults == 0) return true;


                return $scope.selectedAdults % unit.multiplesRequired != 0;
            };

            $scope.getDynamicPricesKey = function (month, year) {
                var productCode = ($scope.product && $scope.product.code) || ($scope.mainProduct && $scope.mainProduct.code);
                if (!productCode) return;

                month++; // month start at 0, so we need to increment
                return String(month) + String(year) + productCode.toLowerCase();
            };

            $scope.loadCalendarPrices = function (month, year) {
                var productCode = ($scope.product && $scope.product.code) || ($scope.mainProduct && $scope.mainProduct.code);
                if (!productCode) return;
                var priceObjKey = $scope.getDynamicPricesKey(month, year);

                month++; // month start at 0, so we need to increment              
                if ($scope.dynamicPrices[priceObjKey]) return; // if the dynamic prices were already loaded return;

                $scope.calendarIsLoading = true;
                $scope.inlineDatePicker.toggleLoading($scope.calendarIsLoading);

                productsFactory.getDynamicPrices(jwtService.getPrincipalToken(), productCode, month, year).then(
                    function (result) {
                        var prices = result.data.prices;
                        if ((prices || "").length) {
                            var monthPrices = Object.create(null);
                            $.each(prices, function (key, value) {
                                var vdate = moment(value.date, 'YYYY-MM-DDTHH:mm:ss').date()
                                monthPrices[vdate] = { price: value.price, className: (value.projectedVisitation || "").toLowerCase(), isClosed: value.isClosed, closedReason: value.closedReason };
                            });
                            $scope.dynamicPrices[priceObjKey] = monthPrices;
                        }
                        $scope.calendarIsLoading = false;

                        $scope.inlineDatePicker.toggleLoading($scope.calendarIsLoading);
                        $scope.inlineDatePicker.update();
                    },
                    function (response) {
                        $scope.calendarIsLoading = false;
                        $scope.inlineDatePicker.toggleLoading($scope.calendarIsLoading);
                    });
            };

            $scope.getSelectedDate = function (dateFormat, returnMoment) {
                dateFormat = dateFormat || "YYYY-MM-DD";
                if ($scope.inlineDatePicker) {
                    // use the inline picker
                    var result = (($scope.inlineDatePicker.selectedDates || "").length ?
                        moment($scope.inlineDatePicker.selectedDates[0]) : moment());
                    return returnMoment ? result : result.format(dateFormat);
                } else {
                    var date = $("#daterange").val();
                    var result = moment(date, shoppingCartService.getDateFormat());
                    return returnMoment ? result : result.format(dateFormat);
                }
            };

            $scope.setSelectedDate = function (newDate) {
                var newDateMoment = moment(newDate, shoppingCartService.getDateFormat());

                if ($scope.inlineDatePicker) {
                    // use the inline picker
                    return $scope.inlineDatePicker.selectDate(newDateMoment.toDate());
                } else {
                    $("#daterange").val(newDate);

                    $("#daterange").data().daterangepicker.startDate = newDateMoment;
                    $("#daterange").data().daterangepicker.endDate = newDateMoment;
                }
            };

            $scope.showFilters = function () {
                return (generalCtrl.selectedGeographyCode || "").toLowerCase().indexOf("skl") < 0;
            };

            $scope.init = function () {
                $scope.showBoardingTimeInfo = (($scope.requestArguments.showboardingtimeforproductcodes || '').length > 0 ? $scope.requestArguments.showboardingtimeforproductcodes : []).indexOf(($scope.mainProduct && $scope.mainProduct.productCode) || $scope.requestArguments.productCode) >= 0;

                $scope.showTableView = (generalCtrl.selectedGeographyCode || "").toLowerCase().indexOf("skl") >= 0 && ($scope.requestArguments.productCode || "").toLowerCase().indexOf("time") > 0;

                $scope.isFOC = generalCtrl.selectedGeographyCode == "FOC" ? "-FOC" : "";
                $scope.isLoading = false;

                var principalTokenObj = jwtService.getPrincipalTokenObj();

                if (principalTokenObj
                    && principalTokenObj.maxQuantityOfReservedTimes > 0
                    && principalTokenObj.maxQuantityOfReservedTimes < $scope.maxAdultsChildrenTotal
                    && (principalTokenObj.anonymousTicketRedirectURL || "").toLowerCase().indexOf("/" + ($scope.requestArguments.productCode || "").toLowerCase() + "/") > 0) {
                    $scope.maxAdultsChildrenTotal = parseInt(principalTokenObj.maxQuantityOfReservedTimes);
                    $scope.availableAdults = strRange($scope.minAdults, $scope.maxAdultsChildrenTotal + 1);
                    if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
                        $scope.selectedAdults = $scope.availableAdults[$scope.availableAdults.length - 1];
                    }
                    $scope.adultsChanged();
                } else if (principalTokenObj
                    && principalTokenObj.maxNumberOfAdults > 0) {

                    $scope.maxAdults = parseInt(principalTokenObj.maxNumberOfAdults);

                    if ($scope.maxAdults > $scope.maxAdultsChildrenTotal) {
                        $scope.maxAdultsChildrenTotal = $scope.maxAdults;
                    }

                    $scope.availableAdults = strRange($scope.minAdults, $scope.maxAdults + 1);
                    if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
                        $scope.selectedAdults = $scope.availableAdults[$scope.availableAdults.length - 1];
                    }
                    $scope.adultsChanged();
                }

                //$("#daterange").show();
                var reqTravelDate = moment($scope.requestArguments.travelDate);

                if ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) {
                    moment.locale($scope.selectedLanguage.languageCode);
                }

                $scope.checkExitIntentPopup($scope.anonymUser, $scope.requestArguments.productCode);

                if ($scope.mainProduct.isDynamicallyPriced) {
                    var isMobile = false; //initiate as false
                    // device detection
                    if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
                        || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0, 4))) {
                        isMobile = true;
                    }

                    var popoverTimeout = null;
                    var inlineDatePickerSettings = {
                        language: 'en',
                        minDate: reqTravelDate.toDate(),
                        onSelect: function (formattedDate, date, inst) {
                            //$timeout(function () {
                            $scope.wasSearch = false;
                            //});
                        },
                        onChangeView: function (view, month, year) {
                            if (view == "days") {
                                $scope.loadCalendarPrices(month, year);
                            }
                        },
                        onChangeDecade: function (decade) {
                        },
                        onChangeMonth: function (month, year) {
                            $scope.loadCalendarPrices(month, year);
                        },
                        onChangeYear: function (year) {
                            $scope.loadCalendarPrices(0, year);
                        },
                        onRenderCell: function (date, cellType, isOtherMonthCell) {
                            var currentDate = date.getDate();

                            if (cellType == 'day') {
                                var monthPriceKey = $scope.getDynamicPricesKey(date.getMonth(), date.getFullYear());
                                var monthPrices = $scope.dynamicPrices[monthPriceKey];
                                var dayPrice = !isOtherMonthCell && monthPrices && monthPrices[currentDate]; // don't show prices from other months
                                var priceLabel = ($scope.anonymUser && $scope.anonymUser.labels
                                    && $scope.anonymUser.labels["dynamicPricingCalendarPriceLabel"]) || $scope.labelUtils.getLabel("dynamicPricing.calendarPriceLabel");

                                var closedTooltipHtml = dayPrice && dayPrice.isClosed && dayPrice.closedReason;
                                var closedTooltipClass = "";
                                var closedTooltipAttributes = "";
                                if (closedTooltipHtml) {
                                    closedTooltipClass = "closed-tooltip";
                                    closedTooltipHtml = closedTooltipHtml.replace(/\'/g, '&apos;');

                                    closedTooltipAttributes = 'data-toggle="popover" data-trigger="' + (isMobile ? 'focus' : 'hover focus') + '" data-html="true" data-content="' + closedTooltipHtml + '"';
                                }
                                clearTimeout(popoverTimeout);
                                popoverTimeout = setTimeout(function () {
                                    jQuery('[data-toggle="popover"].closed-tooltip').each(function () {
                                        var $this = $(this);
                                        $this.popover({
                                            container: $this,
                                            delay: { show: isMobile ? 0 : 300, hide: 0 }
                                        });

                                        if ($this.parent().hasClass("-selected-")) {
                                            if (!isMobile) {
                                                setTimeout(function () { $this.popover("show"); }, 50);
                                            } else {
                                                $this.popover("show");
                                            }
                                        }

                                    });//.popover()
                                }, 20);

                                var html = "";
                                if (dayPrice && dayPrice.isClosed) {
                                    html = '<div ' + closedTooltipAttributes + ' class="day-label closed ' + closedTooltipClass + '"><span class="date">' + currentDate + '</span></div>';
                                } else {
                                    html = '<div ' + closedTooltipAttributes + ' class="day-label ' + closedTooltipClass + ' ' + (dayPrice && dayPrice.price ? "has-price" : "") + '"><span class="date">' + currentDate + '</span><span class="from">' + priceLabel + '</span></div>' + (dayPrice && dayPrice.price ? '<div class="from-price"> $' + (dayPrice && dayPrice.price) + '</div>' : '');
                                }
                                return {
                                    disabled: dayPrice && dayPrice.isClosed,
                                    classes: (dayPrice && dayPrice.isClosed ? "closed" : "") + " " + (dayPrice && dayPrice.className),
                                    html: html
                                }
                            }
                        }
                    };
                    if ($scope.updateItem) {
                        inlineDatePickerSettings.selectedDates = [$scope.updateItem.startDateMoment.toDate()];
                    }
                    $scope.inlineDatePicker = $("#inlineDatePicker").datepicker(inlineDatePickerSettings).data('datepicker');


                    if ($scope.updateItem) {
                        $scope.inlineDatePicker.selectDate($scope.updateItem.startDateMoment.toDate());
                        $scope.loadCalendarPrices($scope.updateItem.startDateMoment.month(), $scope.updateItem.startDateMoment.year());
                    }
                    else {
                        $scope.loadCalendarPrices(reqTravelDate.month(), reqTravelDate.year());
                    }
                } else {
                    var datepickersettings = {
                        singleDatePicker: true,
                        minDate: reqTravelDate,
                        showDropdowns: true,
                        locale: {
                            format: shoppingCartService.getDateFormat()
                        },
                        parentEl: "#daterangecontainer"
                    };
                    if ($scope.updateItem) {
                        datepickersettings.startDate = $scope.updateItem.startDateMoment;
                    }
                    // set date
                    $scope.daterangepicker = $("#daterange").daterangepicker(datepickersettings);
                    $scope.daterangepicker.on("apply.daterangepicker", function (ev, picker) {
                        if ($scope.isLoading) return false;
                        $timeout(function () {
                            $scope.wasSearch = false;
                        });
                    });
                }

                var criteria = ($scope.updateItem) ? Object.create(null) : $scope.getCriteria();

                if (!$scope.updateItem) {
                    activitiesService.getSelectedActivity(function (result) {
                        var activity = (result.success && result.data) ? result.data : undefined;
                        if (activity) {
                            $scope.showQuantityPicker = !activity.pricedPerPerson;

                            $scope.isChildAvailable = activity.childRatesAvailable;
                            $scope.isSeniorsAvailable = activity.seniorRateAvailable;
                            $scope.isStudentsAvailable = activity.studentRateAvailable;
                            $scope.isInfantsAvailable = activity.infantRateAvailable;

                            if (activity.maximumQuantity > 0 && activity.maximumQuantity < $scope.maxAdultsChildrenTotal) {
                                $scope.maxAdultsChildrenTotal = activity.maximumQuantity;
                                $scope.availableAdults = strRange($scope.minAdults, $scope.maxAdultsChildrenTotal + 1);
                                if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
                                    $scope.selectedAdults = $scope.availableAdults[$scope.availableAdults.length - 1];
                                }
                                $scope.adultsChanged();
                            }

                            // $scope.availableQuantity = strRange(1, $scope.maxAdultsChildrenTotal || 100);
                        }


                        $scope.requestArguments.travelDate = $scope.requestArguments.isDefaultDate !== "1" || (!activity || !activity.startDate) ? $scope.requestArguments.travelDate : $scope.$parent.getProductDate(activity.startDate);

                        if (jwtService.getServerMomentDate() > moment($scope.requestArguments.travelDate)) {
                            $scope.requestArguments.travelDate = activity && activity.startDate ? $scope.$parent.getProductDate(activity.startDate) : jwtService.getServerStrDate();
                        }

                        if (!criteria.date || criteria.date == "Invalid date" || (moment(criteria.date, shoppingCartService.getDateFormat()) < jwtService.getServerMomentDate())) {

                            if (jwtService.getServerMomentDate() > moment($scope.requestArguments.travelDate)) {
                                $scope.requestArguments.travelDate = jwtService.getServerStrDate();
                            }
                            criteria.date = $scope.requestArguments.travelDate ? moment($scope.requestArguments.travelDate, "YYYY-MM-DD").format(shoppingCartService.getDateFormat())
                                : jwtService.getServerMomentDate();
                        }

                        if (criteria.date) {
                            $scope.setSelectedDate(criteria.date);
                        }
                    });
                }

                if ($scope.updateItem) {
                    $scope.resultfilter.type = "ticket";
                    var firstComp = $scope.updateItem.BookingToQuote.Components[0];
                    $scope.updateItem.isUpdateCompSynced = false;

                    $scope.showQuantityPicker = !$scope.mainProduct.pricedPerPerson;
                    $scope.isChildAvailable = $scope.mainProduct.childRatesAvailable;
                    $scope.isSeniorsAvailable = $scope.mainProduct.seniorRateAvailable;
                    $scope.isStudentsAvailable = $scope.mainProduct.studentRateAvailable;
                    $scope.isInfantsAvailable = $scope.mainProduct.infantRateAvailable;

                    //$scope.availableQuantity = strRange(1, ($scope.maxAdultsChildrenTotal || 100));
                    $scope.selectedQuantity = firstComp.NumberOfUnits || 0;

                    $scope.selectedAdults = firstComp.NumberOfAdults || 2;
                    $scope.selectedChild = firstComp.NumberOfChildren || 0;
                    $scope.selectedSeniors = firstComp.NumberOfSeniors || 0;
                    $scope.selectedStudents = firstComp.NumberOfStudents || 0;
                    $scope.selectedInfants = firstComp.NumberOfInfants || 0;

                    $scope.wasSearch = false;

                    if ($scope.mainProduct.maximumQuantity > 0 && $scope.mainProduct.maximumQuantity < $scope.maxAdultsChildrenTotal) {
                        $scope.maxAdultsChildrenTotal = $scope.mainProduct.maximumQuantity;
                        $scope.availableAdults = strRange($scope.minAdults, $scope.maxAdultsChildrenTotal + 1);
                        if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
                            $scope.selectedAdults = $scope.availableAdults[$scope.availableAdults.length - 1];
                        }
                        $scope.adultsChanged();
                    }


                    $scope.searchProducts();
                }
                else {
                    if (criteria.time) {
                        $scope.selectedTime = criteria.time;
                    }

                    if (criteria.quantity) {
                        $scope.selectedQuantity = criteria.quantity;
                    } else if ($scope.requestArguments.adults > 0) {
                        $scope.selectedQuantity = $scope.requestArguments.adults;
                    }

                    if (criteria.adults) {
                        $scope.selectedAdults = criteria.adults;
                    } else if ($scope.requestArguments.adults > 0) {
                        $scope.selectedAdults = $scope.requestArguments.adults;
                    }

                    if (criteria.child) {
                        $scope.selectedChild = criteria.child;
                    } else if ($scope.requestArguments.child > 0) {
                        $scope.selectedChild = $scope.requestArguments.child;
                    }

                    if (criteria.seniors) {
                        $scope.selectedSeniors = criteria.seniors;
                    }

                    if (criteria.students) {
                        $scope.selectedStudents = criteria.students;
                    }

                    if (criteria.infants) {
                        $scope.selectedInfants = criteria.infants;
                    }

                    if (criteria.product) {
                        $scope.product = criteria.product;


                        if ($scope.requestArguments.unitCode && $scope.product && $scope.product.units) {
                            var rUnits = $scope.requestArguments.unitCode.split("|");
                            $scope.product.units = _.filter($scope.product.units, function (unit) {
                                return rUnits.indexOf(unit.unitCode) >= 0;
                            });
                        }
                        $scope.allItems = [].concat($scope.product.units || []);
                        $scope.processUnitIfInTableView();
                    }

                    if (criteria.packages) {
                        $scope.packages = criteria.packages;
                        _.each($scope.packages, function (el) {
                            el.isPackage = true; el.sortOrder = el.ibeSortOrder;
                            // set price
                            if (el.ageBasedPriceBreakdown) {

                                el.price = el.ageBasedPriceBreakdown.adultPrice;
                                el.childPrice = el.ageBasedPriceBreakdown.childPrice;
                                el.additionalChildPrice = el.ageBasedPriceBreakdown.additionalChildPrice;
                                el.seniorPrice = el.ageBasedPriceBreakdown.seniorPrice;
                                el.studentPrice = el.ageBasedPriceBreakdown.studentPrice;

                                el.showPriceDescription = !el.ageBasedPriceBreakdown.adultPrice
                                    && !el.ageBasedPriceBreakdown.childPrice && !el.ageBasedPriceBreakdown.additionalChildPrice
                                    && !el.ageBasedPriceBreakdown.seniorPrice
                                    && !el.ageBasedPriceBreakdown.studentPrice;

                            } else {
                                el.showPriceDescription = true;
                            }
                            //el.currency = (prices && prices[0] && prices[0].currency) || "USD";
                            el.culture = ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) || "en";
                        });
                        $scope.allItems = $scope.allItems.concat($scope.packages || []);
                    }
                    $scope.filterItems();

                    if (criteria.optionalExtras) {
                        $scope.optionalExtras = criteria.optionalExtras;
                    }

                    if (!$scope.product || !$scope.product.units || !$scope.product._isProcessed) {
                        $scope.wasSearch = false;
                        //$scope.daterangepicker.trigger("apply.daterangepicker");
                    } else {
                        setTimeout(function () {
                            $scope.wasSearch = true;
                            jQuery($element).find("select.unit-time-select").change();
                        });
                        $scope.showSoldOutNotice();
                    }

                    if ($scope.requestArguments.hidedatepicker) {
                        $scope.searchProducts();
                    }
                }

                //var activitySelectTicketCtrl = $scope.$parent;
                //var activityDetailsCtrl = activitySelectTicketCtrl.$parent;
                //var generalCtrl = activityDetailsCtrl.$parent;

                $scope.trackLobTitle = $scope.mainProduct && $scope.mainProduct.productDescriptions
                    && (
                        $scope.mainProduct.productDescriptions.genericTitle || ($scope.mainProduct.productDescriptions.titles && $scope.mainProduct.productDescriptions.titles.length > 0 ? $scope.mainProduct.productDescriptions.titles[0] : $scope.mainProduct.name));

                var trackerReq = {
                    lobTitle: $scope.trackLobTitle,
                    packageName: null,
                    searchDate: null,
                    adults: null,
                    children: null,
                    shoppingCart: $scope.cart,
                    anonymUser: $scope.anonymGeneralUser,
                    bookingNumber: null,
                    bookingId: null
                };

                trackingService.buildFlowTrackerObj(trackerReq); // ($scope.mainProduct && $scope.mainProduct.startDate)
            };

            var initialized = false;

            $scope.anonymUser = undefined;
            $scope.initCurrentAnonymUser = function (callback) {

                jwtService.getAnonymousUserByGeography(generalCtrl.selectedGeographyCode, function (user) {
                    $scope.anonymUser = user;

                    callback();
                });
            };

            $scope.$watch(function () {
                return taskFactory.task;
            },
                function (val) {
                    if (!val || !val.name || initialized) return;
                    initialized = true;

                    var initShoppingCart = new Promise(function (resolve, reject) {
                        shoppingCartService.getStorageCart(function (shoppingCart) {
                            if (shoppingCart) {
                                $scope.cart = shoppingCart;

                                $scope.updateItem = undefined;
                                $scope.updateIndex = -1;

                                if (($scope.requestArguments.updateCartItemCode || "").length && $scope.cart && $scope.cart.Items) {
                                    $scope.updateItem = _.find($scope.cart.Items, function (cartItem) {
                                        $scope.updateIndex++;
                                        var relatedComponent = _.find(cartItem.BookingToQuote && cartItem.BookingToQuote.Components, function (comp) {
                                            return comp.ProductCode == $scope.requestArguments.updateCartItemCode;
                                        });
                                        return relatedComponent != null;
                                    });
                                    if ($scope.updateItem) {
                                        $scope.updateItem.startDateMoment = moment($scope.updateItem.BookingToQuote.Components[0].StartDate);
                                    }
                                }
                            }
                            resolve(1);
                        });
                    });
                    initShoppingCart.then(function () {
                        $timeout($scope.initCurrentAnonymUser.bind(null, $scope.init)); //$scope.init);
                    });
                }, true);
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    // Setup the filter
    angular.module("app").filter("filterSpas", function () {

        // Create the return function and set the required parameter as well as an optional paramater
        return function (input, filterObj) {

            if (filterObj && (filterObj.isDeparture || filterObj.isReturn) && (filterObj.selectedTime || "").length) {
                var out = [];

                angular.forEach(input, function (value, key) {
                    if (value.timeStr === filterObj.selectedTime) {
                        out.push(value);
                    }
                }, out);

                return out;

            } else {
                return input;
            }

        };
    });
    angular.module("app").controller("activityBookSpaCtrl", [
        "utilsFactory", "trackingService", "$window", "$scope", "$element", "$state", "$http", "$uibModal", "productsFactory", "activitiesService", "$rootScope", "validHelper", "shoppingCartService", "jwtService", "taskFactory", "$timeout", "transportationService", "$filter", "currenciesService",
        function (utilsFactory, trackingService, $window, $scope, $element, $state, $http, $uibModal, productsFactory, activitiesService, $rootScope, validHelper, shoppingCartService, jwtService, taskFactory, $timeout, transportationService, $filter, currenciesService) {
            var webUrl = $("body").data("weburl") ? $("body").data("weburl") : "";
            $.material.init();
            $scope.utils = utilsFactory;
            $scope.emptyObj = {};

            $scope.getUserLabel = function (fieldName) {
                if (!$scope.anonymUser) return undefined;
                var selectedLanguage = $scope.anonymUser.selectedLanguage && $scope.anonymUser.selectedLanguage.userlabels;
                return (selectedLanguage && selectedLanguage.labels && selectedLanguage.labels[fieldName]) || ($scope.anonymUser.labels && $scope.anonymUser.labels[fieldName]);
            };

            $scope.getAgeRangeInfo = function (secondaryLabel) {
                if (!$scope.anonymUser) return undefined;
                var selectedLanguage = $scope.anonymUser.selectedLanguage;
                return $scope.utils.getAnonymUserLabel((selectedLanguage && selectedLanguage.userlabels) || $scope.anonymUser, "ageRangesInfo", secondaryLabel);
            };

            $scope.requestArguments = {
                activityId: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-id"),
                productCode: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-product-code"),
                unitCode: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-unit-code"),
                productCategory: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-product-category"),
                travelDate: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-travel-date"),
                productCodeOverride: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-product-code-override"),
                hidedatepicker: ($("div[ng-controller='activityDetailsCtrl']").attr("data-hidedatepicker") || "").toLowerCase() == 'true',
                updateCartItemCode: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-updateCartItem"),
                isDefaultDate: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-is-default-date"),
                productcodeswithexpandeddescriptionbydefault: $("div[ng-controller='activityDetailsCtrl']").attr("data-productcodeswithexpandeddescriptionbydefault"),
                unitcodeswithexpandedtilesdescriptionbydefault: $("div[ng-controller='activityDetailsCtrl']").data("unitcodeswithexpandedtilesdescriptionbydefault"),
                defaultselectedadultsbyproductcode: $("div[ng-controller='activityDetailsCtrl']").data("defaultselectedadultsbyproductcode"),
                fromwebtray: ["1", "true"].indexOf(($("div[ng-controller='activityDetailsCtrl']").attr("data-activity-fromwebtray") || "").toLowerCase()) >= 0,
            };
            $scope.requestArguments.expanddescriptionbydefault = ($scope.requestArguments.productcodeswithexpandeddescriptionbydefault || []).indexOf($scope.requestArguments.productCode) >= 0;

            $scope.maxAdultsChildrenTotal = $("body").attr("data-max-activity-available-adults-child-total") ? parseInt($("body").attr("data-max-activity-available-adults-child-total")) : 5;
            $scope.maxAdults = $("body").attr("data-max-attractions-available-adults") ? parseInt($("body").attr("data-max-attractions-available-adults")) : 5;
            $scope.maxChildren = $("body").attr("data-max-attractions-available-children") ? parseInt($("body").attr("data-max-attractions-available-children")) : 5;

            $scope.maxSeniors = $("body").attr("data-max-activity-seniors") ? parseInt($("body").attr("data-max-activity-seniors")) : 5;
            $scope.maxStudents = $("body").attr("data-max-activity-students") ? parseInt($("body").attr("data-max-activity-students")) : 5;

            $scope.isChildAvailable = true;
            $scope.isSeniorsAvailable = false;
            $scope.isStudentsAvailable = false;
            $scope.isInfantsAvailable = false;

            $scope.wasSearch = false;
            $scope.isLoading = true;
            $scope.allLocations = {};
            $scope.showLeavingFromCities = false;
            $scope.submitted = false;
            $scope.showModal = {
                "SubmitErrors": false
            };
            $scope.compareModel = { compareAll: false, isAnySelected: false };

            var activitySelectTicketCtrl = $scope.$parent;
            var activityDetailsCtrl = activitySelectTicketCtrl.$parent;
            var generalCtrl = activityDetailsCtrl.$parent;

            $scope.allItems = [];
            $scope.filteredItems = [];

            $scope.resultfilter = {
                type: null
            };



            $scope.selectCurrency = function (currency) {
                $scope.selectedCurrency = currency;
                $scope.setSelectedCurrency($scope.selectedCurrency);
                currenciesService.setSelectedCurrencyCode(currency && currency.code);
            };


            $scope.orderByLabels = {
                "all": $scope.utils.getLabel("filters.sortBy"),
                "sortOrder": $scope.utils.getLabel("filters.sortByMostPopular"),
                "priceAsc": $scope.utils.getLabel("filters.sortByPriceASC"),
                "priceDesc": $scope.utils.getLabel("filters.sortByPriceDESC")
            };

            $scope.getOrderByLabel = function (key, reverse) {
                if (!key || key == "all") return $scope.orderByLabels["all"];
                if (key == "sortOrder") {
                    return $scope.orderByLabels[key];
                } else {
                    return $scope.orderByLabels[key + (reverse ? "Desc" : "Asc")];
                }
            };


            $scope.orderBy = {
                predicate: "all",
                reverse: false
            };

            $scope.filterBy = function (type) {
                if ($scope.resultfilter.type == type) {
                    $scope.resultfilter.type = null;
                    $scope.filterItems();
                    return;
                }
                $scope.resultfilter.type = type;
                $scope.filterItems();
            };

            $scope.order = function (predicate, reverse, preventResize) {
                $scope.orderBy.reverse = reverse;
                if (predicate != "all") {
                    $scope.orderBy.predicate = predicate;
                }

                $scope.filteredItems = $filter('orderBy')($scope.filteredItems, predicate == "all" ? "sortOrder" : $scope.orderBy.predicate, $scope.orderBy.reverse);

                if (!preventResize) {
                    setTimeout(function () {
                        jQuery(window).resize();
                    });
                }
            };

            $scope.filterItems = function () {
                var prevCompareSelected = _.find($scope.filteredItems, function (item) {
                    return item.isCompare;
                });

                $scope.filteredItems = $filter('filterAttractions')($scope.allItems, $scope.resultfilter);
                var currentCompareTobeSelected = prevCompareSelected && _.find($scope.filteredItems, function (item) {
                    return prevCompareSelected.code == item.code;
                });
                if (currentCompareTobeSelected) {
                    currentCompareTobeSelected.isCompare = true;
                    $scope.compareModel.isAnySelected = true;
                }

                $scope.order($scope.orderBy.predicate, $scope.orderBy.reverse, true);
                setTimeout(function () {
                    jQuery(window).resize();
                });
            };


            $scope.globalErrors = [];
            var timeoutID = undefined;

            function resizeSliderPanel() {
                window.clearTimeout(timeoutID);
                timeoutID = setTimeout(function () {
                    jQuery(window).resize();
                }, 100);
            }

            $scope.isTileDescriptionExpandedByDefault = function (unitCode) {
                return unitCode && ($scope.requestArguments.unitcodeswithexpandedtilesdescriptionbydefault || []).indexOf(unitCode) >= 0;
            };

            $scope.getDefaultLeavingFromLocation = function () {
                return { value: { code: "" }, destination: [] };
            };

            $scope.scrollToResultsIfMobile = function () {
                //if (jQuery(window).width() < 760) {
                setTimeout(function () {
                    var page = $("html, body");

                    page.animate({ scrollTop: $scope.isLoading ? $("#loadingContainer").offset().top : $("#resultsContainer").offset().top }, 1000, function () {
                        page.off("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove");
                    });

                    page.on("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove", function () {
                        setTimeout(function () {
                            page.stop();
                        });
                    });
                });
                // }
            };

            $scope.showGoingToCities = false;

            $scope.getDefaultGoingToCityLocation = function () {
                return { code: "" };
            };

            $scope.selectedLeavingFromCity = undefined;
            $scope.selectedGoingToCity = undefined;
            //$scope.hideDropOff = false;
            //$scope.checkHideDropOff = function () {
            //    if (!$scope.selectedLeavingFromCity || !$scope.selectedGoingToCity) {
            //        $scope.hideDropOff = false;
            //        return;
            //    }
            //    $scope.hideDropOff = $scope.selectedLeavingFromCity.code == $scope.selectedGoingToCity.code;
            //};

            function strRange(min, max) {
                min = min || 0;
                max = max || 0;

                if (min == 0 && max == 0) {
                    return ["0"];
                }

                function toString(val) {
                    return val.toString();
                }

                return _.map(_.range(min, max), toString);
            }

            $scope.selectedAdults = "2";
            if (($scope.requestArguments.defaultselectedadultsbyproductcode || '').length > 0) {
                var defaultSelectedAdultsStr = _.find($scope.requestArguments.defaultselectedadultsbyproductcode, function (item) {
                    var pcode = item.split(' ')[0];
                    return pcode == $scope.requestArguments.productCode || pcode == $scope.requestArguments.productCodeOverride;
                });
                if (defaultSelectedAdultsStr) {
                    var defaultSelectedAdults = parseInt(defaultSelectedAdultsStr.split(' ')[1]);
                    if (defaultSelectedAdults > 0) {
                        $scope.selectedAdults = String(defaultSelectedAdults);
                    }
                }
            }

            $scope.selectedChild = "0";

            $scope.selectedSeniors = "0";
            $scope.selectedStudents = "0";
            $scope.selectedInfants = "0";



            //  $scope.availableAdults = strRange(0, $scope.maxAdultsChildrenTotal + 1);
            //  $scope.availableChild = strRange(0, ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults)) + 1);

            $scope.availableAdults = strRange(0, $scope.maxAdultsChildrenTotal + 1);
            $scope.availableChild = strRange(0, ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors) -
                parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

            $scope.availableSeniors = strRange(0, ($scope.maxAdultsChildrenTotal -
                parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) -
                parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

            $scope.availableStudents = strRange(0, ($scope.maxAdultsChildrenTotal -
                parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) -
                parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);
            $scope.availableInfants = strRange(0, ($scope.maxAdultsChildrenTotal -
                parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) -
                parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);


            $scope.allItems = [];
            $scope.reducedProducts = [];
            $scope.availableDepartures = [];

            $scope.showNext = false;

            $scope.getObjLength = function (obj) {
                return !obj ? 0 : Object.keys(obj).length;
            };

            $scope.isUnitAvailable = function (unit) {
                var totalGuests = parseInt($scope.selectedAdults || 0) + parseInt($scope.selectedChild || 0) +
                    parseInt($scope.selectedSeniors || 0) + parseInt($scope.selectedStudents, 0) + parseInt($scope.selectedInfants, 0);


                return unit && unit.availability >= (totalGuests);
            };

            //$scope.$watch("filteredDepartures", function (newVal, oldVal) {
            //    if (newVal === oldVal) return;
            //    $timeout(function () {
            //        if (($scope.filteredDepartures || "").length) {
            //            var availableDepartures = _.filter($scope.filteredDepartures, function (fd) { return fd.selectedUnit && !fd.selectedUnit.isInPast && !fd.selectedUnit.isTimeRestricted; });
            //            if ((availableDepartures || "").length === 1) {
            //                $scope.setSelectedDepartureProduct(availableDepartures[0]);
            //            }
            //        }
            //    });
            //});

            $scope.selectedDepartureProduct = undefined;
            $scope.selectedDeparturePickUp = undefined;
            $scope.selectedDepartureDropOff = undefined;

            $scope.debug = function (dropOff) {
                $scope.selectedDeparturePickUp;
                $scope.selectedDepartureDropOff;

            };
            $scope.departurePickUpChanged = function (pickUp) {
                $scope.selectedDeparturePickUp = pickUp;
            };

            $scope.departureDropOffChanged = function (dropOff) {
                $scope.selectedDepartureDropOff = dropOff;
            };

            $scope.selectDefaultProducts = function () {
                var firstDeparture = undefined;
                if (($scope.allItems || "").length) {
                    var availableDepartures = _.filter($scope.allItems, function (fd) { return !fd.isInPast; });
                    firstDeparture = (availableDepartures || "").length === 1 && $scope.selectedDepartureProduct !== availableDepartures[0] ? availableDepartures[0] : undefined;
                }

                firstDeparture = firstDeparture && firstDeparture.selectedUnit && firstDeparture.selectedUnit.isTimeRestricted ? undefined : firstDeparture;

                if (firstDeparture) {
                    $scope.setSelectedDepartureProduct(firstDeparture, function () { });
                }

                // $scope.showNext = $scope.canContinue($scope.setSelectedDepartureProduct);
            };

            $scope.setSelectedDepartureProduct = function (product) {
                if (!product.selectedUnit || product.selectedUnit.isInPast || product.selectedUnit.isTimeRestricted) {
                    $scope.showNext = false;
                    return;
                }

                $scope.selectedDepartureProduct = product;
                $scope.selectedDepartureProduct.requiredProducts = [];

                //   $scope.setBusStopsForProductUnit($scope.selectedDepartureProduct, $scope.selectedDepartureProduct.selectedUnit);
                //   $scope.showNext = $scope.canContinue();
            };

            $scope.getProductBusStops = function (product, callback) {
                if ($scope.isLoading) return;
                if (callback) {
                    callback();
                }

                // $scope.isLoading = false;
                var requestParams = {
                    urlPrefix: $("body").data("weburl") ? $("body").data("weburl") : "",
                    token: jwtService.getPrincipalToken(),
                    productCode: product.code,
                    unitCode: product.selectedUnit.unitCode
                };

                $scope.isLoading = true;

                transportationService.getBusStops(requestParams, function (dateResult) {
                    product.busStops = dateResult.data;
                    if (callback) {
                        callback();
                    }
                    $scope.isLoading = false;
                });
            };

            $scope.fillProductDetailsRecursive = function (parentProduct, products, index, callback) {
                if (index === products.length || !products[index]) {
                    callback();
                    return;
                }
                var params = {
                    token: jwtService.getPrincipalToken(),
                    productCode: products[index].productCode,
                    productCategory: products[index].productCategory,
                    travelDate: $("#departure").data().daterangepicker.startDate.format("YYYY-MM-DD")
                };
                productsFactory.getProductWithHiddenUnitsWithCallback(params, function (result) {
                    if (result && result.success && (result.data || "").length) {
                        products[index].product = result.data[0];
                        products[index].product.selectedUnit = _.find(products[index].product.units, function (u) {
                            return products[index].unitCode === u.unitCode;
                        });
                        if (!parentProduct.requiredProducts) {
                            parentProduct.requiredProducts = [];
                        }
                        parentProduct.requiredProducts.push(products[index]);
                    }
                    $scope.fillProductDetailsRecursive(parentProduct, products, index + 1, callback);
                });

            };

            $scope.showRequiredProductsModal = function () {
                var popupProducts = _.filter($scope.selectedDepartureProduct.requiredProducts, function (reqProd) {

                    if (!reqProd.product) return false;

                    if (reqProd.product.productType === "FEE") {
                        reqProd.product.isFee = true;
                        return false;
                    }
                    return true;
                });
                if (popupProducts.length == 0) {
                    $scope.bookTour();
                    return;
                }
                var requiredModalInstance = $uibModal.open({
                    animation: true,
                    templateUrl: "requiredProductsModal.html",
                    controller: "requiredProductsModalCtrl",
                    size: "book-required-products",
                    resolve: {
                        "products": { followingProductSingle: "product", followingProductMultiple: "products", yourProductTitle: "tour", data: popupProducts }
                    },
                    backdrop: "true"
                });
                requiredModalInstance.result.then(function (result) {
                    $scope.bookTour();
                }, function () {
                    //console.log("dismiss");
                });
            };

            // on click
            $scope.getAdditionalProducts = function (product, unit) {
                $scope.selectedDepartureProduct = product;
                $scope.selectedDepartureProduct.selectedUnit = unit;
                //  $scope.setBusStopsForProductUnit($scope.selectedDepartureProduct, $scope.selectedDepartureProduct.selectedUnit);
                $scope.submitted = true;
                $scope.globalErrors = [];

                if (!$scope.selectedDepartureProduct.selectedUnit || $scope.selectedDepartureProduct.selectedUnit.isInPast || $scope.selectedDepartureProduct.selectedUnit.isTimeRestricted)
                    $scope.globalErrors.push("Tour is unavailable!");

                //var requiredDeparturePickup = $scope.selectedDepartureProduct
                //    && (($scope.selectedDepartureProduct.selectedUnit.pickupLocationRequired && $scope.selectedDepartureProduct.selectedUnit.selectedPickUp)
                //        || !$scope.selectedDepartureProduct.selectedUnit.pickupLocationRequired);
                //var requiredDepartureDropOff = $scope.selectedDepartureProduct
                //    && (($scope.selectedDepartureProduct.selectedUnit.dropoffLocationRequired && $scope.selectedDepartureProduct.selectedUnit.selectedDropOff)
                //        || !$scope.selectedDepartureProduct.selectedUnit.dropoffLocationRequired);

                //var validDeparture = requiredDeparturePickup && (requiredDepartureDropOff); //|| $scope.hideDropOff

                var totalGuests = parseInt($scope.selectedAdults || 0) + parseInt($scope.selectedChild || 0) +
                    parseInt($scope.selectedSeniors || 0) + parseInt($scope.selectedStudents, 0) + parseInt($scope.selectedInfants, 0);


                var isAvailable = $scope.selectedDepartureProduct.selectedUnit.availability >= (totalGuests);
                if (!isAvailable) {
                    $scope.globalErrors.push(utilsFactory.getLabel("activity.error.unitUnavailable").replace("{0}",
                        $scope.selectedDepartureProduct.selectedUnit.availability));
                }

                //if (!requiredDeparturePickup) {
                //    $scope.globalErrors.push(utilsFactory.getLabel("tours.error.requiredDeparturePickup"));
                //}
                //if (!requiredDepartureDropOff) {
                //    $scope.globalErrors.push(utilsFactory.getLabel("tours.error.requiredDepartureDropOff"));
                //}
                if (totalGuests == 0 || ($scope.selectedAdults == 0 && $scope.selectedChild == 0 && $scope.selectedSeniors == 0 && $scope.selectedStudents == 0)) {
                    $scope.globalErrors.push("Select the number of guests");//utilsFactory.getLabel("tours.error.requiredDepartureDropOff"));
                }
                if ($scope.globalErrors.length) {
                    $scope.showModal["SubmitErrors"] = true;
                    return;
                }

                // if (!validDeparture) return;

                if (!($scope.selectedDepartureProduct.requiredProducts || "").length) {
                    $scope.isLoading = true;
                    //get related services - check required additional products to add
                    var productQueries = [];
                    productQueries.push({
                        ProductCode: $scope.selectedDepartureProduct.code,
                        TravelDate: $("#departure").data().daterangepicker.startDate.format("YYYY-MM-DD"),
                        UnitCode: $scope.selectedDepartureProduct.selectedUnit ?
                            $scope.selectedDepartureProduct.selectedUnit.unitCode : null
                    });

                    var dataToPost = { ProductQueries: productQueries };
                    var relatedServicesRequestParams = {
                        token: jwtService.getPrincipalToken(),
                        data: dataToPost
                    };

                    productsFactory.getRelatedServicesMulti(relatedServicesRequestParams, function (relatedProducts) {

                        if (relatedProducts && (relatedProducts.data || "").length && (relatedProducts.data[0].requiredProducts || "").length) {
                            //get product details for each additional required product
                            if (!($scope.selectedDepartureProduct.requiredProducts || "").length) {
                                $scope.fillProductDetailsRecursive($scope.selectedDepartureProduct, relatedProducts.data[0].requiredProducts, 0, function () {
                                    $scope.isLoading = false;

                                    if (($scope.selectedDepartureProduct.requiredProducts || "").length) {
                                        $scope.showRequiredProductsModal();
                                    } else {
                                        $scope.bookTour();
                                    }
                                });
                            } else {
                                $scope.isLoading = false;
                                $scope.showRequiredProductsModal();
                            }

                        } else {
                            //call the callback
                            $scope.bookTour();
                        }
                    });
                } else {
                    $scope.showRequiredProductsModal();
                }
            };

            $scope.gotoPackageDetails = function (selectedItem) {

                var productSelectTicketCtrl = $scope.$parent;
                if (!productSelectTicketCtrl.$parent) {
                    return;
                }
                var productDetailsCtrl = productSelectTicketCtrl.$parent;
                productDetailsCtrl.setSelectedPackage(selectedItem);
                var packageDetailsParam = {
                    packageCode: selectedItem.code,
                    date: moment($("#departure").val(), shoppingCartService.getDateFormat()).format("YYYY-MM-DD")
                };

                var packagesCriteria = productDetailsCtrl.getPackagesSearchCriteria();
                // packagesCriteria.date = $("#daterange").val(),
                packagesCriteria.children = $scope.selectedChild;
                packagesCriteria.adults = $scope.selectedAdults;
                packagesCriteria.infants = $scope.selectedInfants;
                packagesCriteria.seniors = $scope.selectedSeniors;
                packagesCriteria.students = $scope.selectedStudents;

                productDetailsCtrl.savePackagesSearchCriteria(packagesCriteria);
                productDetailsCtrl.next($state.$current.name, packageDetailsParam);
            };

            $scope.bookTour = function () {

                //var validDeparture = $scope.selectedDepartureProduct
                //    && (($scope.selectedDepartureProduct.selectedUnit.pickupLocationRequired && $scope.selectedDepartureProduct.selectedUnit.selectedPickUp)
                //        || !$scope.selectedDepartureProduct.selectedUnit.pickupLocationRequired)
                //    && (($scope.selectedDepartureProduct.selectedUnit.dropoffLocationRequired && $scope.selectedDepartureProduct.selectedUnit.selectedDropOff)
                //        || !$scope.selectedDepartureProduct.selectedUnit.dropoffLocationRequired); // || $scope.hideDropOff

                //if (!validDeparture) return;

                //var selectedDeparturePickUp = $scope.selectedDepartureProduct.selectedUnit.selectedPickUp;
                //var selectedDepartureDropOff = $scope.selectedDepartureProduct.selectedUnit.selectedDropOff;
                //var hidePickup = ($scope.selectedLeavingFromCity && $scope.selectedLeavingFromCity.pickups.length == 1) ? 1 : 0;
                //var hideDropoff = ($scope.selectedGoingToCity && $scope.selectedGoingToCity.dropoffs.length == 1) ? 1 : 0;
                $scope.isLoading = true;

                var removeExistingCartItemPromise = undefined;

                if ($scope.updateItem) {
                    removeExistingCartItemPromise = new Promise(function (resolve, reject) {
                        var requestParams = {
                            apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                            token: jwtService.getPrincipalToken(),
                            index: $scope.updateIndex,
                            productCode: $scope.updateItem.ProductCode
                        };

                        shoppingCartService.setStorageCart($scope.cart, function () {
                            shoppingCartService.updateCartComponents(requestParams, function (shoppingCart) {
                                if (shoppingCart && (shoppingCart.Items || '').length) {
                                    $scope.cart = shoppingCart;
                                } else {
                                    // window.location = "/";
                                }
                                resolve(1);
                            });
                        });
                    }); // Promise
                } else {
                    removeExistingCartItemPromise = Promise.resolve(1);
                }

                removeExistingCartItemPromise.then(function () {
                    $scope.lobTitle = $scope.mainProduct && $scope.mainProduct.productDescriptions
                        && (
                            $scope.mainProduct.productDescriptions.genericTitle || ($scope.mainProduct.productDescriptions.titles && $scope.mainProduct.productDescriptions.titles.length > 0 ? $scope.mainProduct.productDescriptions.titles[0] : $scope.mainProduct.name));

                    var components = [];
                    components.push({
                        "Id": $scope.selectedDepartureProduct.id,
                        "ProductCategory": $scope.selectedDepartureProduct.productCategory,
                        "ProductType": $scope.selectedDepartureProduct.productType,
                        "ProductCode": $scope.selectedDepartureProduct.code,
                        "StartDate": $scope.selectedDepartureProduct.startDate,
                        "EndDate": $scope.selectedDepartureProduct.endDate,
                        "Name": $scope.selectedDepartureProduct.name,
                        "Description": $scope.selectedDepartureProduct.description,
                        "ProductDescriptions": $scope.selectedDepartureProduct.productDescriptions,
                        "Price": $scope.selectedDepartureProduct.price,
                        "ChildPrice": $scope.selectedDepartureProduct.childPrice,
                        "NumberOfAdults": $scope.selectedAdults,
                        "NumberOfChildren": $scope.selectedChild,
                        "NumberOfSeniors": $scope.selectedSeniors,
                        "NumberOfStudents": $scope.selectedStudents,
                        "NumberOfInfants": $scope.selectedInfants,
                        "Status": "New",
                        "UnitCode": $scope.selectedDepartureProduct.selectedUnit ? $scope.selectedDepartureProduct.selectedUnit.unitCode : "",
                        "UnitDescription": $scope.selectedDepartureProduct.selectedUnit ? $scope.selectedDepartureProduct.selectedUnit.description : "",
                        "PickupLocation": undefined, //selectedDeparturePickUp ? selectedDeparturePickUp : undefined,
                        "DropoffLocation": undefined,//selectedDepartureDropOff ? selectedDepartureDropOff : undefined,
                        "StartingLocation": $scope.selectedDepartureProduct.startingLocation,
                        "Destination": $scope.selectedDepartureProduct.destination,
                        "Remarks": [],
                        "HidePickup": false,
                        "HideDropoff": false,//hideDropoff,
                        "AddedFromWebTray": $scope.requestArguments.fromwebtray,
                        "hideDate": $scope.requestArguments.hidedatepicker,
                        "_trackingLob": $scope.lobTitle
                    });

                    if ($scope.selectedDepartureProduct.requiredProducts) {
                        _.each($scope.selectedDepartureProduct.requiredProducts, function (reqProd) {
                            components.push({
                                "Id": reqProd.product.id,
                                "ProductCategory": reqProd.product.productCategory,
                                "ProductType": reqProd.product.productType,
                                "ProductCode": reqProd.product.code,
                                "StartDate": reqProd.product.startDate,
                                "EndDate": reqProd.product.endDate,
                                "Name": reqProd.product.name,
                                "Description": reqProd.product.description,
                                "ProductDescriptions": reqProd.product.productDescriptions,
                                "Price": reqProd.product.price,
                                "ChildPrice": reqProd.product.price,
                                "NumberOfAdults": $scope.selectedAdults,
                                "NumberOfChildren": $scope.selectedChild,
                                "NumberOfSeniors": $scope.selectedSeniors,
                                "NumberOfStudents": $scope.selectedStudents,
                                "NumberOfInfants": $scope.selectedInfants,
                                "Status": "New",
                                "UnitCode": reqProd.product.selectedUnit ? reqProd.product.selectedUnit.unitCode : reqProd.unitCode,
                                "UnitDescription": reqProd.product.selectedUnit ? reqProd.product.selectedUnit.description : reqProd.product.description,
                                "PickupLocation": undefined,
                                "DropoffLocation": undefined,
                                "StartingLocation": reqProd.product.startingLocation,
                                "Destination": undefined,
                                "Remarks": [],
                                "IsFee": reqProd.product.isFee,
                                "ShowInCart": reqProd.showInCart,
                                "ParentCode": $scope.selectedDepartureProduct.code,
                                "_trackingLob": $scope.lobTitle
                            });
                        });
                    }

                    var bookingToQuote = {
                        "Components": components
                    };
                    var data = {
                        "BookingToQuote": bookingToQuote
                    };

                    var requestParams = {
                        apiUrl: $scope.$parent.$parent.getWebUrl(),
                        token: jwtService.getPrincipalToken(),
                        dataToPost: data,
                        startDate: $("#departure").val(),// moment($scope.selectedDepartureProduct.startDate).format("DD MMMM YYYY"),
                        endDate: $("#departure").val(), //moment($scope.selectedDepartureProduct.endDate).format("DD MMMM YYYY"),
                        startTime: undefined, //$scope.selectedDeparturePickUp ? $scope.selectedDeparturePickUp.time : undefined,
                        endTime: undefined, //$scope.selectedDepartureDropOff ? $scope.selectedDepartureDropOff.time : undefined
                        lastAddedItemDetails: $scope.selectedDepartureProduct
                    };

                    shoppingCartService.addComponentsToCart(requestParams, function (result, error) {

                        //var modalInstance = $uibModal.open({
                        //    animation: true,
                        //    templateUrl: "cartInfoModal.html",
                        //    controller: "cartInfoModalCtrl",
                        //    size: "add-to-cart",
                        //    resolve: {
                        //        count: result,
                        //        isHotel: false
                        //    },
                        //    backdrop: "static"
                        //});
                        if (result) {
                            var isEnhanceBookingPageEnabled = ($scope.selectedLanguage && $scope.selectedLanguage.enableEnhanceBookingPage) || ($scope.anonymUser && $scope.anonymUser.enableEnhanceBookingPage);
                            var redirectToUrl = shoppingCartService.utils.getAfterAddToCartPageUrl(generalCtrl.selectedGeographyCode, isEnhanceBookingPageEnabled);

                            window.location = utilsFactory.addPersistentQueryStringsParams(redirectToUrl);
                        } else {
                            $scope.isLoading = false;
                        }
                        // $scope.isLoading = false;
                    });
                }); // EndPromise resolve    

            };

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            var selectedActivity = $scope.$parent.getPrevActivity();

            selectedActivity = selectedActivity && ((selectedActivity.isHeader && selectedActivity.productType === $scope.requestArguments.productCode) ||
                !(selectedActivity.isHeader && selectedActivity.code === $scope.requestArguments.productCode)) ? selectedActivity : undefined;
            $scope.requestArguments.travelDate = $scope.requestArguments.isDefaultDate !== "1" || (!selectedActivity || !selectedActivity.startDate) ? $scope.requestArguments.travelDate : $scope.$parent.getProductDate(selectedActivity.startDate);




            $scope.searchProducts = function () {

                $scope.submittedSearch = true;
                $scope.globalErrors = [];

                if ($scope.isProductMultiplesRequiredInvalid()) {
                    $scope.wasSearch = false;
                    $scope.fillMultiplesRequiredGlobalError();
                }

                //if (!$scope.selectedLeavingFromCity) {
                //    $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredLeavingFromLocation"));
                //}

                //if (!$scope.selectedGoingToCity) {
                //    $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredGoingToLocation"));
                //}
                //if (!$scope.selectedPickUp && $scope.selectedLeavingFromCity && ($scope.selectedLeavingFromCity.pickups || '').length) {
                //    $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredPickupLocation"));
                //}
                //if (!$scope.selectedDropOff && $scope.selectedGoingToCity && ($scope.selectedGoingToCity.dropoffs || '').length) { // !$scope.hideDropOff &&
                //    $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredDropoffLocation"));
                //}

                if ($scope.globalErrors.length) {
                    $timeout(function () {
                        $scope.showModal["SubmitErrors"] = true;
                    });

                    return;
                }
                $scope.getTours();
            };

            $scope.fillMultiplesRequiredGlobalError = function () {
                if (!$scope.globalErrors) {
                    $scope.globalErrors = [];
                }

                $scope.globalErrors.push($scope.utils.getLabel("activity.unit.multiples-required").replace('{0}', $scope.mainProduct.multiplesRequired))
            };

            $scope.isProductMultiplesRequiredInvalid = function () {
                // 
                var multiplesRequired = $scope.mainProduct && $scope.mainProduct.multiplesRequired || 0;
                if (!multiplesRequired || !(multiplesRequired > 0)) return false;

                var selectedTickets = parseInt($scope.selectedAdults || 0) + parseInt($scope.selectedChild || 0) + parseInt($scope.selectedSeniors || 0) + parseInt($scope.selectedStudents || 0);

                if (!selectedTickets) return true;

                return selectedTickets % multiplesRequired != 0;
            };


            //$scope.adultsChanged = function () {
            //    $scope.availableChild = strRange(0, ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults)) + 1);
            //    if ($scope.availableChild.indexOf(String($scope.selectedChild)) < 0) {
            //        $scope.selectedChild = $scope.availableChild[0];
            //    }
            //    if ($scope.selectedAdults == 0 && $scope.selectedChild == 0) {
            //        $scope.selectedChild = 1;
            //    }
            //};

            //$scope.childChanged = function () {
            //    $scope.availableAdults = strRange(0, ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild)) + 1);
            //    if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
            //        $scope.selectedAdults = $scope.availableAdults[0];
            //    }
            //    if ($scope.selectedAdults == 0 && $scope.selectedChild == 0) {
            //        $scope.selectedAdults = 1;
            //    }
            //};
            $scope.adultsChanged = function () {
                $scope.availableChild = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors)
                        - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableChild.indexOf(String($scope.selectedChild)) < 0) {
                    $scope.selectedChild = $scope.availableChild[0];
                }
                $scope.availableSeniors = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableSeniors.indexOf(String($scope.selectedSeniors)) < 0) {
                    $scope.selectedSeniors = $scope.availableSeniors[0];
                }

                $scope.availableStudents = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableStudents.indexOf(String($scope.selectedStudents)) < 0) {
                    $scope.selectedStudents = $scope.availableStudents[0];
                }

                $scope.availableInfants = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

                if ($scope.availableInfants.indexOf(String($scope.selectedInfants)) < 0) {
                    $scope.selectedInfants = $scope.availableInfants[0];
                }

                //
                $scope.globalErrors = [];
                if ($scope.isProductMultiplesRequiredInvalid()) {
                    $scope.wasSearch = false;
                    $scope.fillMultiplesRequiredGlobalError();
                }

                if ($scope.globalErrors.length) {
                    $timeout(function () {
                        $scope.showModal["SubmitErrors"] = true;
                    });

                    return;
                }
                //
            };

            $scope.childChanged = function () {
                $scope.availableAdults = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);
                if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
                    $scope.selectedAdults = $scope.availableAdults[0];
                }

                $scope.availableSeniors = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableSeniors.indexOf(String($scope.selectedSeniors)) < 0) {
                    $scope.selectedSeniors = $scope.availableSeniors[0];
                }

                $scope.availableStudents = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableStudents.indexOf(String($scope.selectedStudents)) < 0) {
                    $scope.selectedStudents = $scope.availableStudents[0];
                }

                $scope.availableInfants = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

                if ($scope.availableInfants.indexOf(String($scope.selectedInfants)) < 0) {
                    $scope.selectedInfants = $scope.availableInfants[0];
                }

                $scope.globalErrors = [];
                if ($scope.isProductMultiplesRequiredInvalid()) {
                    $scope.wasSearch = false;
                    $scope.fillMultiplesRequiredGlobalError();
                }

                if ($scope.globalErrors.length) {
                    $timeout(function () {
                        $scope.showModal["SubmitErrors"] = true;
                    });

                    return;
                }
            };

            $scope.seniorChanged = function () {
                //selectedSeniors
                //availableSeniors

                $scope.availableAdults = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);
                if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
                    $scope.selectedAdults = $scope.availableAdults[0];
                }
                $scope.availableChild = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableChild.indexOf(String($scope.selectedChild)) < 0) {
                    $scope.selectedChild = $scope.availableChild[0];
                }
                $scope.availableStudents = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableStudents.indexOf(String($scope.selectedStudents)) < 0) {
                    $scope.selectedStudents = $scope.availableStudents[0];
                }

                $scope.availableInfants = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

                if ($scope.availableInfants.indexOf(String($scope.selectedInfants)) < 0) {
                    $scope.selectedInfants = $scope.availableInfants[0];
                }
            };

            $scope.studentChanged = function () {
                $scope.availableAdults = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);
                if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
                    $scope.selectedAdults = $scope.availableAdults[0];
                }
                $scope.availableChild = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableChild.indexOf(String($scope.selectedChild)) < 0) {
                    $scope.selectedChild = $scope.availableChild[0];
                }
                $scope.availableSeniors = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableSeniors.indexOf(String($scope.selectedSeniors)) < 0) {
                    $scope.selectedSeniors = $scope.availableSeniors[0];
                }

                $scope.availableInfants = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

                if ($scope.availableInfants.indexOf(String($scope.selectedInfants)) < 0) {
                    $scope.selectedInfants = $scope.availableInfants[0];
                }
            };

            $scope.infantChanged = function () {
                $scope.availableAdults = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);
                if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
                    $scope.selectedAdults = $scope.availableAdults[0];
                }
                $scope.availableChild = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableChild.indexOf(String($scope.selectedChild)) < 0) {
                    $scope.selectedChild = $scope.availableChild[0];
                }
                $scope.availableSeniors = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableSeniors.indexOf(String($scope.selectedSeniors)) < 0) {
                    $scope.selectedSeniors = $scope.availableSeniors[0];
                }

                $scope.availableStudents = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableStudents.indexOf(String($scope.selectedStudents)) < 0) {
                    $scope.selectedStudents = $scope.availableStudents[0];
                }
            };



            $scope.goingToCityChanged = function () {
                if (!$scope.selectedGoingToCity) return;

                if ($scope.selectedLeavingFromCity.value && $scope.selectedLeavingFromCity.value.code) {
                    //$scope.showNext = true;
                    $scope.fillTours();
                } else {
                    $scope.showNext = false;
                }

            };


            $scope.resetSelectedProducts = function () {
                $scope.selectedDepartureProduct = undefined;

                // $scope.showNext = $scope.canContinue();
            };

            $scope.refreshBusStops = function () {
                var travelDate = $("#departure").data().daterangepicker.startDate.format("YYYY-MM-DD");
                if ($scope.selectedLeavingFromCity) {
                    $scope.fillBussStopsForLocation($scope.selectedLeavingFromCity, travelDate, function () {
                        $scope.setSelectedPickUp($scope.selectedLeavingFromCity.pickups);
                        if ($scope.selectedGoingToCity) { // && !$scope.hideDropOff
                            $scope.fillBussStopsForLocation($scope.selectedGoingToCity, travelDate, function () {
                                $scope.setSelectedDropOff($scope.selectedGoingToCity.dropoffs);
                            });
                        }
                    });
                } else if ($scope.selectedGoingToCity) { //&& !$scope.hideDropOff
                    $scope.fillBussStopsForLocation($scope.selectedGoingToCity, travelDate, function () {
                        $scope.setSelectedDropOff($scope.selectedGoingToCity.dropoffs);
                    });
                }
            };

            $scope.fillBussStopsForLocation = function (loc, date, callback) {
                if (!loc) {
                    callback();
                    return;
                }
                var requestParams = {
                    urlPrefix: $("body").data("weburl") ? $("body").data("weburl") : "",
                    token: jwtService.getPrincipalToken(),
                    cityCode: loc.code,
                    travelDate: date,
                    serviceType: $scope.requestArguments.productCode
                };
                $scope.isLoading = true;
                transportationService.getBusStopsByCity(requestParams, function (dateResult) {
                    $scope.isLoading = false;
                    loc.pickups = undefined;
                    loc.dropoffs = undefined;
                    if (dateResult.data) {
                        loc.pickups = (dateResult.data.pickups || "").length ? dateResult.data.pickups : [];
                        loc.dropoffs = (dateResult.data.dropoffs || "").length ? dateResult.data.dropoffs : [];
                    }
                    callback();
                });
            };

            $scope.pickUpChanged = function (pickUp) {
                if ($scope.isLoading) return;
                $scope.selectedPickUp = pickUp;
                $scope.wasSearch = false;
                $scope.resetSelectedProducts();
            };

            $scope.dropOffChanged = function (dropOff) {
                if ($scope.isLoading) return;
                $scope.selectedDropOff = dropOff;
                $scope.wasSearch = false;
                $scope.resetSelectedProducts();
            };
            $scope.setSelectedPickUp = function (data) {
                if (!$scope.selectedPickUp) {
                    if ((data || "").length == 1) {
                        $scope.selectedPickUp = data[0];
                        return;
                    }

                    if (data && $scope.updateItem && !$scope.updateItem.wasPickUpSelected) {
                        $scope.updateItem.wasPickUpSelected = true;
                        var firstUpdateComp = $scope.updateItem && $scope.updateItem.BookingToQuote.Components[0];

                        $scope.selectedPickUp = _.find(data, function (loc) {
                            return loc.code == (firstUpdateComp.PickupLocation && firstUpdateComp.PickupLocation.code);
                        });
                    }
                    return;
                }
                if (!data) {
                    $scope.selectedPickUp = undefined;
                    return;
                }
                $scope.selectedPickUp = _.find(data, function (it) {
                    return it.code == $scope.selectedPickUp.code;
                });
                if (!$scope.selectedPickUp && data.length === 1)
                    $scope.selectedPickUp = data[0];
            };

            $scope.setSelectedDropOff = function (data) {
                if (!$scope.selectedDropOff) {
                    if ((data || "").length == 1) {
                        $scope.selectedDropOff = data[0];
                        return;
                    }
                    if (data && $scope.updateItem && !$scope.updateItem.wasDropoffSelected) {
                        $scope.updateItem.wasDropoffSelected = true;
                        var firstUpdateComp = $scope.updateItem && $scope.updateItem.BookingToQuote.Components[0];

                        $scope.selectedDropOff = _.find(data, function (loc) {
                            return loc.code == (firstUpdateComp.DropoffLocation && firstUpdateComp.DropoffLocation.code);
                        });
                    }
                    return;
                };

                if (!data) {
                    $scope.selectedDropOff = undefined;
                    return;
                }

                $scope.selectedDropOff = _.find(data, function (it) {
                    return it.code == $scope.selectedDropOff.code;
                });

                if (!$scope.selectedDropOff && data.length === 1)
                    $scope.selectedDropOff = data[0];
            };

            $scope.leavingFromCityChanged = function (callback) {
                if (!$scope.selectedLeavingFromCity) return;
                $scope.wasSearch = false;
                //   $scope.resetSelectedProducts();
                var travelDate = $("#departure").data().daterangepicker.startDate.format("YYYY-MM-DD");
                $scope.fillBussStopsForLocation($scope.selectedLeavingFromCity, travelDate, function () {
                    $scope.setSelectedPickUp($scope.selectedLeavingFromCity.pickups);
                    if (callback) callback();
                });
                // $scope.checkHideDropOff();
            };

            $scope.goingToCityChanged = function () {
                if (!$scope.selectedGoingToCity) return;
                $scope.wasSearch = false;
                $scope.resetSelectedProducts();
                var travelDate = $("#departure").data().daterangepicker.startDate.format("YYYY-MM-DD");
                $scope.fillBussStopsForLocation($scope.selectedGoingToCity, travelDate, function () {
                    $scope.setSelectedDropOff($scope.selectedGoingToCity.dropoffs);
                });
                // $scope.checkHideDropOff();
            };

            $scope.setBusStopsForProductUnit = function (product, unit) {
                if (!unit) return;
                if ((unit.pickups || "").length) {
                    unit.selectedPickUp = _.find(unit.pickups, function (pu) {
                        return pu.code == $scope.selectedPickUp.code;
                    });
                    if (unit.selectedPickUp) {
                        unit.selectedPickUpTimeMoment = moment(unit.selectedPickUp.timeObj, "HH:mm");
                        product.pickupStr = unit.selectedPickUpTimeMoment.format("hh:mm A");
                    }
                }
                if ((unit.dropoffs || "").length) { // !$scope.hideDropOff &&
                    unit.selectedDropOff = _.find(unit.dropoffs, function (pu) {
                        return pu.code == $scope.selectedDropOff.code;
                    });
                    if (unit.selectedDropOff) {
                        unit.selectedDropOffTimeMoment = moment(unit.selectedDropOff.timeObj, "HH:mm");
                        product.dropoffStr = unit.selectedDropOffTimeMoment.format("hh:mm A");
                    }
                }
            };

            $scope.getReducedAllProductUnits = function (allItems) {
                if (!allItems || !allItems.length) return [];

                return _.reduce(allItems, function (a, product) {
                    if ((product.units || '').length) {
                        return a.concat(_.map(product.units, function (unit) {
                            return { departure: product, selectedUnit: unit, price: unit.price, sortOrder: unit.sortOrder };
                        }));
                    } else {
                        a.push({ departure: product, selectedUnit: undefined });
                        return a;
                    }

                }, []);
            };

            $scope.getTimeListAndSetUnitDictionaryFromProducts = function (allItems) {
                var timeList = Object.create(null);

                if (!allItems || !allItems.length) return timeList;

                _.each(allItems, function (product) {
                    product.unitDictionary = Object.create(null);
                    _.each(product.units, function (unit) {
                        var timeKey = unit.description;
                        product.unitDictionary[timeKey] = unit;

                        if (!(timeKey in timeList)) {
                            timeList[timeKey] = { key: timeKey, isOffPeakPricing: unit.isOffPeakPricing };
                        }
                    });
                });

                return _.values(timeList);
            };

            $scope.showSoldOutNotice = function (product) {
                setTimeout(function () {
                    if (product && product.productDescriptions && product.productDescriptions.soldOutNotice) {
                        var showSoldOutNotice = true;
                        _.each(product.units, function (unit) {
                            showSoldOutNotice = showSoldOutNotice && (unit.availability < 1);
                        });
                        if (showSoldOutNotice) {
                            generalCtrl.toggleModalWithData("SoldOutNotice", product.productDescriptions.soldOutNotice);
                        }
                    }
                });
            };

            $scope.changeCompare = function (selectedItem) {
                $scope.compareModel.compareAll = selectedItem ? false : true;

                _.each($scope.filteredItems, function (item) {
                    item.isCompare = selectedItem && selectedItem == item || false;
                });

                $scope.compareModel.isAnySelected = true;
            };

            $scope.mainSelectedFilters = utilsFactory.getLabel("spa.selectedFilters", true);


            $scope.getSelectedFiltersLabel = function (mobile) {
                if (!$scope.mainSelectedFilters) return "";
                var adultsLabel = $scope.selectedAdults == 1 ? $scope.mainSelectedFilters.adult : $scope.mainSelectedFilters.adults;
                var childLabel = $scope.selectedChild == 1 ? $scope.mainSelectedFilters.child : $scope.mainSelectedFilters.children;
                var mainLabel = mobile ? $scope.mainSelectedFilters.displayLabelMobile : $scope.mainSelectedFilters.displayLabel;
                mainLabel = mainLabel.replace("{adultsLabel}", adultsLabel);
                mainLabel = mainLabel.replace("{adults}", $scope.selectedAdults);
                mainLabel = mainLabel.replace("{childrenLabel}", childLabel);
                mainLabel = mainLabel.replace("{children}", $scope.selectedChild);
                mainLabel = mainLabel.replace("{date}", $scope.selectedDateStr);
                return mainLabel;
            };

            $scope.selectDate = function (dateMoment) {
                if (!dateMoment || !dateMoment.isValid()) { return; }

                $("#departure").val(dateMoment.format(shoppingCartService.getDateFormat()));

                $("#departure").data().daterangepicker.startDate = dateMoment;
                $("#departure").data().daterangepicker.endDate = dateMoment;

                $scope.searchProducts();
            }

            $scope.isProductTypeBreakfast = function () {
                return $scope.mainProduct && $scope.mainProduct.productType == "SPA-C";
            };

            $scope.getTours = function () {
                $scope.prevDay = $("#departure").data().daterangepicker.startDate.clone().subtract(1, 'day');
                if ($scope.prevDay < $("#departure").data().daterangepicker.minDate) {
                    $scope.prevDay = null;
                }
                $scope.selectedDateStr = $("#departure").data().daterangepicker.startDate.format(shoppingCartService.getDateFormat());
                $scope.nextDay = $("#departure").data().daterangepicker.startDate.clone().add(1, 'day');

                var requestParams = {
                    urlPrefix: $("body").data("weburl") ? $("body").data("weburl") : "",
                    token: jwtService.getPrincipalToken(),
                    date: $("#departure").data().daterangepicker.startDate.format("YYYY-MM-DD"),
                    type: $scope.requestArguments.productCode,
                    productCodeOverride: $scope.requestArguments.productCodeOverride
                    //fromLocationCode: $scope.selectedLeavingFromCity.code,
                    //fromLocationName: $scope.selectedLeavingFromCity.name,
                    //toLocationCode: $scope.selectedGoingToCity.code,
                    //toLocationName: $scope.selectedGoingToCity.name,
                    //pickupCode: $scope.selectedPickUp && $scope.selectedPickUp.code,
                    //dropoffCode: $scope.selectedDropOff && $scope.selectedDropOff.code
                };

                var trackerReq = {
                    lobTitle: $scope.lobTitle,
                    packageName: null,
                    searchDate: requestParams.date,
                    adults: parseInt($scope.selectedAdults),
                    children: parseInt($scope.selectedChild),
                    shoppingCart: $scope.cart,
                    anonymUser: $scope.anonymGeneralUser,
                    bookingNumber: null,
                    bookingId: null
                };
                trackingService.buildFlowTrackerObj(trackerReq);

                // if (!$scope.hideDropOff) {
                //    requestParams.dropoffCode = $scope.selectedDropOff.code;
                // }

                $scope.isLoading = true;
                $scope.wasSearch = true;
                $scope.scrollToResultsIfMobile();
                $scope.allItems = [];
                $scope.reducedProducts = [];
                $scope.packages = [];

                var callback = function (dateResult) {//

                    var allItems = dateResult && dateResult.data ? dateResult.data.products : [];
                    $scope.packages = dateResult && dateResult.data ? dateResult.data.packages : [];

                    //_.each($scope.packages, function (el) {
                    //    el.isPackage = true;
                    //    el.sortOrder = el.ibeSortOrder;

                    //    //var timeLimit = undefined;
                    //    if (el.bookingCutOffTime) {
                    //        var currTime = jwtService.getServerMomentDate(true);
                    //        el.isTimeRestricted = moment(el.bookingCutOffTime).isSameOrBefore(currTime);
                    //    }

                    //    // set price
                    //    if (el.ageBasedPriceBreakdown) {

                    //        el.price = el.ageBasedPriceBreakdown.adultPrice;
                    //        el.childPrice = el.ageBasedPriceBreakdown.childPrice;
                    //        el.additionalChildPrice = el.ageBasedPriceBreakdown.additionalChildPrice;
                    //        el.seniorPrice = el.ageBasedPriceBreakdown.seniorPrice;
                    //        el.studentPrice = el.ageBasedPriceBreakdown.studentPrice;

                    //        el.showPriceDescription = !el.ageBasedPriceBreakdown.adultPrice
                    //            && !el.ageBasedPriceBreakdown.childPrice && !el.ageBasedPriceBreakdown.additionalChildPrice
                    //            && !el.ageBasedPriceBreakdown.seniorPrice
                    //            && !el.ageBasedPriceBreakdown.studentPrice;

                    //    } else {
                    //        el.showPriceDescription = true;
                    //    }
                    //    //el.currency = (prices && prices[0] && prices[0].currency) || "USD";
                    //    el.culture = ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) || "en";
                    //});

                    var soldOutNoticeProduct = undefined;

                    _.each(allItems, function (pr) {
                        if (pr.units) {
                            soldOutNoticeProduct = pr;
                            if ($scope.requestArguments.unitCode) {
                                pr.units = _.filter(pr.units, function (unit) { return unit.unitCode === $scope.requestArguments.unitCode; });
                            }
                            pr.selectedUnit = pr.units[0];
                            // pr.units = _.filter(pr.units, function (un) { return un.availability > 0; }); // change                           
                        }
                    });

                    var isCurrDate = moment(requestParams.date).isSame(jwtService.getServerMomentDate());
                    var currHourLimit = jwtService.getServerMomentDate(true);
                    //moment(tc.format("hh:mm A"), "hh:mm A");

                    var pricePromises = [];

                    _.each(allItems, function (el) {
                        el.selectedTime = undefined;
                        var elDateStr = el.startDate.substring(0, el.startDate.indexOf("T"));

                        var timeLimit = jwtService.getServerMomentDate(true);
                        //var timeLimit = undefined;
                        if (el.bookingRestrictionTime > 0) {
                            timeLimit.add(parseInt(el.bookingRestrictionTime), "m");
                            //timeLimit = moment(tc.format("hh:mm A"), "hh:mm A");
                        }

                        if (el.units && el.units.length > 0) {
                            var priceObj = undefined;
                            _.each(el.units, function (unit) {
                                unit.timeStr = moment(unit.startTime).format("hh:mm A");
                                var newDateTime = elDateStr + unit.startTime.substring(unit.startTime.indexOf("T"));
                                unit.timeVal = moment(newDateTime);

                                //if (isCurrDate) {
                                var unitTimeLimit = undefined;
                                unit.isInPast = unit.timeVal <= currHourLimit;

                                if (unit.bookingRestrictionTime > 0) {
                                    unitTimeLimit = jwtService.getServerMomentDate(true);
                                    unitTimeLimit.add(parseInt(unit.bookingRestrictionTime), "m");
                                    //timeLimit = moment(tc.format("hh:mm A"), "hh:mm A");
                                }

                                if (!unit.isInPast && (unitTimeLimit || timeLimit)) {
                                    unit.isTimeRestricted = unit.timeVal <= (unitTimeLimit || timeLimit);
                                }
                                //                                }

                                //get price                                                         

                                //unit.currency = (prices && prices[0] && prices[0].currency) || "USD";                                
                                unit.currency = unit.currency || ((jwtService.getGeography() || "").toUpperCase().indexOf("SKL") >= 0 ? "ISK" : "USD");
                                unit.culture = ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) || "en";

                                if (unit.ageBasedPriceBreakdown) {
                                    !priceObj && (priceObj = {
                                        ageBasedPriceBreakdown: unit.ageBasedPriceBreakdown,
                                        preSalePrices: unit.preSalePrices,
                                        culture: unit.culture,
                                        currency: unit.currency
                                    });

                                    if (unit.ageBasedPriceBreakdown.adultPrice) {
                                        unit.price = unit.ageBasedPriceBreakdown.adultPrice;
                                    }
                                    unit.childPrice = unit.ageBasedPriceBreakdown.childPrice;
                                    unit.additionalChildPrice = unit.ageBasedPriceBreakdown.additionalChildPrice;
                                    unit.seniorPrice = unit.ageBasedPriceBreakdown.seniorPrice;
                                    unit.studentPrice = unit.ageBasedPriceBreakdown.studentPrice;
                                }

                            });
                            el.priceObj = priceObj;
                            // el.selectedUnit = el.units[0];//_.find(el.units, function (un) { return !un.isInPast; });

                            //  $scope.setBusStopsForProductUnit(el, el.selectedUnit);
                        }
                    });


                    //$scope.reducedProducts = $scope.getReducedAllProductUnits(allItems);
                    $scope.timeList = $scope.getTimeListAndSetUnitDictionaryFromProducts(allItems);
                    $scope.allItems = allItems; //($scope.reducedProducts || []).concat($scope.packages || []);

                    $scope.filterItems();


                    $scope.wasSearch = true;
                    // $scope.selectDefaultProducts();
                    //  $scope.showNext = $scope.canContinue();
                    setTimeout(function () {
                        $scope.isLoading = false;
                        $scope.$apply();
                        $scope.scrollToResultsIfMobile();
                        // $scope.showSoldOutNotice(soldOutNoticeProduct); - disabled for spa
                    });
                    //

                };
                if ($scope.isProductTypeBreakfast()) {
                    productsFactory.GetProductWithPackages(jwtService.getPrincipalToken(), $scope.requestArguments.productCode, $scope.mainProduct.productCategory, requestParams.date).then(callback);
                } else {
                    activitiesService.getActivitiesByType(requestParams, callback);
                }

            };

            $scope.$watch('showNext', function (newVal, oldVal) {
                if (!newVal) {
                    $scope.submitted = false;
                }
            }, true);

            $scope.canContinue = function (unit) {

                //var validDeparture = $scope.selectedDepartureProduct
                //      && (($scope.selectedDepartureProduct.selectedUnit.pickupLocationRequired && $scope.selectedDeparturePickUp)
                //          || !$scope.selectedDepartureProduct.selectedUnit.pickupLocationRequired)
                //      && (($scope.selectedDepartureProduct.selectedUnit.dropoffLocationRequired && $scope.selectedDepartureDropOff)
                //          || !$scope.selectedDepartureProduct.selectedUnit.dropoffLocationRequired);

                if (unit && !unit.isInPast && !unit.isTimeRestricted) {


                    return $scope.isUnitAvailable(unit);
                }

                // $scope.submitted = false;
                return false;
            };

            $scope.fillTours = function () {
                $scope.showNext = false;
                if ($scope.selectedLeavingFromCity && $scope.selectedLeavingFromCity.value.code !== "" && $scope.selectedGoingToCity && $scope.selectedGoingToCity.code !== "") {
                    //reset the filters
                    $scope.selectedDepartureProduct = undefined;

                    $scope.selectedDeparturePickUp = undefined;
                    $scope.selectedDepartureDropOff = undefined;

                    $scope.availableDepartures = _.filter($scope.allItems, function (product) {
                        return product.startingLocation.code === $scope.selectedLeavingFromCity.value.code && product.destination.code === $scope.selectedGoingToCity.code;
                    });

                    resizeSliderPanel();
                }
            };

            $scope.fillLocations = function (products) {
                var startingLocations = [];
                var destinationLocations = [];
                _.map(products, function (product) {
                    startingLocations.push(product.startingLocation);
                    destinationLocations.push(product.destination);
                });

                var mapDepart = Object.create(null);
                _.map(products, function (product) {
                    if (product.startingLocation && product.destination) {
                        if (product.startingLocation.code in mapDepart) {
                            var dest = _.find(mapDepart[product.startingLocation.code].destinations,
                                function (d) {
                                    return d.code === product.destination.code;
                                });
                            if (!dest) {
                                mapDepart[product.startingLocation.code].destinations.push(product.destination);
                            };
                        } else {
                            mapDepart[product.startingLocation.code] = {
                                value: product.startingLocation,
                                destinations: [product.destination]
                            };
                        }
                    }
                });

                $scope.allLocations = mapDepart;
                if (!$scope.getObjLength($scope.allLocations)) {
                    $scope.selectedLeavingFromCity = { value: { code: "" }, destination: [] };
                    $scope.selectedGoingToCity = { code: "" };
                }

                $scope.showLeavingFromCities = true;
                $scope.showGoingToCities = ($scope.selectedLeavingFromCity.value.code && $scope.selectedGoingToCity.code);
                $scope.fillTours();

                $scope.isLoading = false;
            };

            $scope.departureSelectedUnitChanged = function (departure) {
                // departure.selectedUnit = unit;
                if ($scope.selectedDepartureProduct === departure) {
                    $scope.selectedDepartureProduct.requiredProducts = [];
                    //    $scope.setBusStopsForProductUnit(departure, departure.selectedUnit);
                    //   resizeSliderPanel();
                    //$scope.getProductBusStops(departure, function () {
                    //    $scope.selectedDeparturePickUp = undefined; //departure.busStops && departure.busStops.pickups.length ? departure.busStops.pickups[0] : undefined;
                    //    $scope.selectedDepartureDropOff = undefined; //departure.busStops && departure.busStops.dropoffs.length ? departure.busStops.dropoffs[0] : undefined;
                    //    resizeSliderPanel();
                    //});
                }
                // $scope.showNext = $scope.canContinue();
            };

            $scope.getUnitDescription = function (departure) {
                switch (departure.productCategory) {
                    case "Tour":
                        return moment(departure.selectedUnit.startTime).format("hh:mm A") + " Departure";
                    default:
                        return departure.selectedUnit.description;
                }

            };

            $scope.getResultsContainerCssClass = function () {
                var hiddenCssClass = ($scope.compareModel.isAnySelected || $scope.filteredItems.length == 1) ? '' : 'hidden-xs hidden-sm';
                var col = $scope.filteredItems.length == 1 ? "col-md-8 col-md-offset-2" : "";
                return hiddenCssClass + " " + col;
            };

            $scope.initLocations = function (callback) {
                //disabled TODO: check
                $scope.isLoading = false;
                callback();
                return;
                var requestParams = {
                    urlPrefix: $("body").data("weburl") ? $("body").data("weburl") : "",
                    token: jwtService.getPrincipalToken(),
                    type: $scope.requestArguments.productCode
                };
                $scope.isLoading = true;
                transportationService.getLocationsByServiceType(requestParams, function (dateResult) {
                    $scope.isLoading = false;
                    if (dateResult.data) {
                        var departureLocations = (dateResult.data.departureLocations || "").length ? dateResult.data.departureLocations : [];
                        var destinationLocations = (dateResult.data.destinations || "").length ? dateResult.data.destinations : [];
                        $scope.departureLocations = _.sortBy(departureLocations, function (loc) { return loc.name; });
                        $scope.destinationLocations = _.sortBy(destinationLocations, function (loc) { return loc.name; });
                    }
                    callback();
                });
            };

            $scope.init = function () {

                $scope.checkExitIntentPopup($scope.anonymUser, $scope.requestArguments.productCode);

                var selectedActivity = $scope.$parent.getPrevActivity();

                selectedActivity = selectedActivity && ((selectedActivity.isHeader && selectedActivity.productType === $scope.requestArguments.productCode) ||
                    !(selectedActivity.isHeader && selectedActivity.code === $scope.requestArguments.productCode)) ? selectedActivity : undefined;
                $scope.requestArguments.travelDate = $scope.requestArguments.isDefaultDate !== "1" || (!selectedActivity || !selectedActivity.startDate) ? $scope.requestArguments.travelDate : $scope.$parent.getProductDate(selectedActivity.startDate);


                if (selectedActivity) {
                    $scope.isChildAvailable = selectedActivity.childRatesAvailable;
                    $scope.isSeniorsAvailable = selectedActivity.seniorRateAvailable;
                    $scope.isStudentsAvailable = selectedActivity.studentRateAvailable;
                    $scope.isInfantsAvailable = selectedActivity.infantRateAvailable;

                    if (selectedActivity.defaultNumberOfAdults > 0) {
                        $scope.selectedAdults = selectedActivity.defaultNumberOfAdults;
                        $scope.adultsChanged();
                    }

                    if (selectedActivity.maximumQuantity > 0 && selectedActivity.maximumQuantity < $scope.maxAdultsChildrenTotal) {
                        $scope.maxAdultsChildrenTotal = selectedActivity.maximumQuantity;
                        $scope.availableAdults = strRange(0, $scope.maxAdultsChildrenTotal + 1);
                        if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
                            $scope.selectedAdults = $scope.availableAdults[$scope.availableAdults.length - 1];
                        }
                        $scope.adultsChanged();
                    }
                }

                var principalTokenObj = jwtService.getPrincipalTokenObj();
                if (principalTokenObj
                    && principalTokenObj.maxQuantityOfReservedTimes > 0
                    && principalTokenObj.maxQuantityOfReservedTimes < $scope.maxAdultsChildrenTotal
                    && (principalTokenObj.anonymousTicketRedirectURL || "").toLowerCase().indexOf("/" + ($scope.requestArguments.productCode || "").toLowerCase() + "/") > 0) {
                    $scope.maxAdultsChildrenTotal = parseInt(principalTokenObj.maxQuantityOfReservedTimes);
                    $scope.availableAdults = strRange(0, $scope.maxAdultsChildrenTotal + 1);
                    if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
                        $scope.selectedAdults = $scope.availableAdults[$scope.availableAdults.length - 1];
                    }
                    $scope.adultsChanged();
                }


                var minDate = $scope.requestArguments.travelDate
                    &&
                    moment($scope.requestArguments.travelDate, "YYYY-MM-DD") > jwtService.getServerMomentDate()
                    ? moment($scope.requestArguments.travelDate, "YYYY-MM-DD") : jwtService.getServerMomentDate();


                var datepickersettings = {
                    singleDatePicker: true,
                    minDate:
                        minDate,//.add("days", 1),
                    showDropdowns: true,
                    locale: {
                        format: shoppingCartService.getDateFormat()
                    },
                    parentEl: "#daterangecontainer"
                };
                if ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) {
                    moment.locale($scope.selectedLanguage.languageCode);
                }

                if ($scope.updateItem) {
                    var firstUpdateComp = $scope.updateItem && $scope.updateItem.BookingToQuote.Components[0];

                    datepickersettings.minDate = jwtService.getServerMomentDate();
                    datepickersettings.startDate = $scope.updateItem.startDateMoment;

                    $scope.selectedAdults = firstUpdateComp.NumberOfAdults;
                    $scope.selectedChild = firstUpdateComp.NumberOfChildren;

                    $scope.selectedSeniors = firstUpdateComp.NumberOfSeniors;
                    $scope.selectedStudents = firstUpdateComp.NumberOfStudents;
                    $scope.selectedInfants = firstUpdateComp.NumberOfInfants;
                }

                $scope.departure = $("#departure").daterangepicker(datepickersettings);

                if (!$scope.updateItem) {
                    $("#departure").val(minDate.format(shoppingCartService.getDateFormat()));
                    $("#departure").data().daterangepicker.minDate = minDate;
                    $("#departure").data().daterangepicker.startDate = minDate;
                    $("#departure").data().daterangepicker.endDate = minDate;
                }



                $scope.departure.on("apply.daterangepicker", function (ev, picker) {
                    if ($scope.isLoading) return false;
                    $scope.wasSearch = false;
                    $scope.resetSelectedProducts();

                    resizeSliderPanel();

                    $scope.refreshBusStops();
                    // $scope.showNext = $scope.canContinue();
                    // $scope.getTransportations(1);
                    return true;
                });


                $scope.isLoading = false;
                //$scope.initLocations(function () {
                //    var firstUpdateComp = $scope.updateItem && $scope.updateItem.BookingToQuote.Components[0];

                //    //select default options if single
                //    if (($scope.departureLocations || "").length === 1) {
                //        $scope.selectedLeavingFromCity = $scope.departureLocations[0];
                //      // the event will be triggered automatically by angular component
                //      //  $scope.leavingFromCityChanged();
                //    } else if (firstUpdateComp) {
                //        $scope.selectedLeavingFromCity = _.find(departureLocations, function (loc) {
                //            return loc.code == (firstUpdateComp.StartingLocation && firstUpdateComp.StartingLocation.code);
                //        }); 
                //        // the event will be triggered automatically by angular component
                //       // $scope.selectedLeavingFromCity && $scope.leavingFromCityChanged();                        
                //    }

                //    if (($scope.destinationLocations || "").length === 1) {
                //        $scope.selectedGoingToCity = $scope.destinationLocations[0];
                //       // the event will be triggered automatically by angular component
                //       // $scope.goingToCityChanged();
                //    } else if (firstUpdateComp) {
                //        $scope.selectedGoingToCity = _.find(destinationLocations, function (loc) {
                //            return loc.code == (firstUpdateComp.Destination && firstUpdateComp.Destination.code);
                //        });
                //       // the event will be trigger automatically by angular component
                //       // $scope.selectedGoingToCity && $scope.goingToCityChanged();
                //    }

                //});
                //$scope.getTours();

                $scope.lobTitle = $scope.mainProduct && $scope.mainProduct.productDescriptions
                    && (
                        $scope.mainProduct.productDescriptions.genericTitle || ($scope.mainProduct.productDescriptions.titles && $scope.mainProduct.productDescriptions.titles.length > 0 ? $scope.mainProduct.productDescriptions.titles[0] : $scope.mainProduct.name));

                var trackerReq = {
                    lobTitle: $scope.lobTitle,
                    packageName: null,
                    searchDate: null,
                    adults: null,
                    children: null,
                    shoppingCart: $scope.cart,
                    anonymUser: $scope.anonymGeneralUser,
                    bookingNumber: null,
                    bookingId: null
                };
                trackingService.buildFlowTrackerObj(trackerReq); // ($scope.mainProduct && $scope.mainProduct.startDate)
            };

            var initialized = false;
            $scope.anonymUser = undefined;
            $scope.initCurrentAnonymUser = function (callback) {
                //var activitySelectTicketCtrl = $scope.$parent;
                //var activityDetailsCtrl = activitySelectTicketCtrl.$parent;
                //var generalCtrl = activityDetailsCtrl.$parent;

                jwtService.getAnonymousUserByGeography(generalCtrl.selectedGeographyCode, function (user) {
                    $scope.anonymUser = user;
                    callback();
                });
            };

            $scope.$watch(function () {
                return taskFactory.task;
            },
                function (val) {
                    if (!val || !val.name || initialized) return;
                    initialized = true;

                    var initShoppingCart = new Promise(function (resolve, reject) {
                        shoppingCartService.getStorageCart(function (shoppingCart) {
                            if (shoppingCart) {
                                $scope.cart = shoppingCart;

                                $scope.updateItem = undefined;
                                $scope.updateIndex = -1;

                                if (($scope.requestArguments.updateCartItemCode || "").length && $scope.cart && $scope.cart.Items) {
                                    $scope.updateItem = _.find($scope.cart.Items, function (cartItem) {
                                        $scope.updateIndex++;
                                        var relatedComponent = _.find(cartItem.BookingToQuote && cartItem.BookingToQuote.Components, function (comp) {
                                            return comp.ProductCode == $scope.requestArguments.updateCartItemCode;
                                        });
                                        return relatedComponent != null;
                                    });
                                    if ($scope.updateItem) {
                                        $scope.updateItem.startDateMoment = moment($scope.updateItem.BookingToQuote.Components[0].StartDate);
                                    }
                                }
                            }
                            resolve(1);
                        });
                    });
                    initShoppingCart.then(function () {
                        $timeout($scope.initCurrentAnonymUser.bind(null, $scope.init)); //$scope.init);
                    });
                }, true);
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    // Setup the filter
    angular.module("app").filter("filterTours", function () {

        // Create the return function and set the required parameter as well as an optional paramater
        return function (input, filterObj) {

            if (filterObj && (filterObj.isDeparture || filterObj.isReturn) && (filterObj.selectedTime || "").length) {
                var out = [];

                angular.forEach(input, function (value, key) {
                    if (value.timeStr === filterObj.selectedTime) {
                        out.push(value);
                    }
                }, out);

                return out;

            } else {
                return input;
            }

        };
    });
    angular.module("app").controller("activityBookTourCtrl", [
        "utilsFactory", "trackingService", "$scope", "$element", "$state", "$http", "$uibModal", "productsFactory", "activitiesService", "$rootScope", "validHelper", "shoppingCartService", "jwtService", "taskFactory", "$timeout", "transportationService", "$filter",
        function (utilsFactory, trackingService, $scope, $element, $state, $http, $uibModal, productsFactory, activitiesService, $rootScope, validHelper, shoppingCartService, jwtService, taskFactory, $timeout, transportationService, $filter) {
            var webUrl = $("body").data("weburl") ? $("body").data("weburl") : "";
            $.material.init();
            $scope.utils = utilsFactory;
            $scope.getAgeRangeInfo = function (secondaryLabel) {
                if (!$scope.anonymUser) return undefined;
                var selectedLanguage = $scope.anonymUser.selectedLanguage;
                return $scope.utils.getAnonymUserLabel((selectedLanguage && selectedLanguage.userlabels) || $scope.anonymUser, "ageRangesInfo", secondaryLabel);
            };

            $scope.requestArguments = {
                activityId: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-id"),
                productCode: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-product-code"),
                unitCode: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-unit-code"),
                productCategory: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-product-category"),
                travelDate: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-travel-date"),
                updateCartItemCode: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-updateCartItem"),
                isDefaultDate: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-is-default-date"),
                productcodeswithexpandeddescriptionbydefault: $("div[ng-controller='activityDetailsCtrl']").attr("data-productcodeswithexpandeddescriptionbydefault"),
                //expanddescriptionbydefault: ($("div[ng-controller='activityDetailsCtrl']").attr("data-expanddescriptionbydefault") || "").toLowerCase() == 'true',
                unitcodeswithexpandedtilesdescriptionbydefault: $("div[ng-controller='activityDetailsCtrl']").data("unitcodeswithexpandedtilesdescriptionbydefault"),
                defaultselectedadultsbyproductcode: $("div[ng-controller='activityDetailsCtrl']").data("defaultselectedadultsbyproductcode"),
                fromwebtray: ["1", "true"].indexOf(($("div[ng-controller='activityDetailsCtrl']").attr("data-activity-fromwebtray") || "").toLowerCase()) >= 0,
            };
            $scope.showPickupLocationsOnCards = ($scope.requestArguments.productCode || "").indexOf('OTT') == 0;

            $scope.requestArguments.expanddescriptionbydefault = ($scope.requestArguments.productcodeswithexpandeddescriptionbydefault || []).indexOf($scope.requestArguments.productCode) >= 0;

            $scope.maxAdultsChildrenTotal = $("body").attr("data-max-activity-available-adults-child-total") ? parseInt($("body").attr("data-max-activity-available-adults-child-total")) : 5;
            $scope.maxAdults = 0; // $("body").attr("data-max-attractions-available-adults") ? parseInt($("body").attr("data-max-attractions-available-adults")) : 5;
            $scope.maxChildren = $("body").attr("data-max-attractions-available-children") ? parseInt($("body").attr("data-max-attractions-available-children")) : 5;

            $scope.maxSeniors = $("body").attr("data-max-activity-seniors") ? parseInt($("body").attr("data-max-activity-seniors")) : 5;
            $scope.maxStudents = $("body").attr("data-max-activity-students") ? parseInt($("body").attr("data-max-activity-students")) : 5;

            $scope.isChildAvailable = true;
            $scope.isSeniorsAvailable = false;
            $scope.isStudentsAvailable = false;
            $scope.isInfantsAvailable = false;

            $scope.wasSearch = false;
            $scope.isLoading = true;
            $scope.allLocations = {};
            $scope.showLeavingFromCities = false;
            $scope.submitted = false;
            $scope.showModal = {
                "SubmitErrors": false
            };
            var activitySelectTicketCtrl = $scope.$parent;
            var activityDetailsCtrl = activitySelectTicketCtrl.$parent;
            var generalCtrl = activityDetailsCtrl.$parent;

            $scope.allItems = [];
            $scope.filteredItems = [];
            $scope.dynamicPrices = Object.create(null);

            $scope.resultfilter = {
                type: null
            };

            $scope.orderByLabels = {
                "all": $scope.utils.getLabel("filters.sortBy"),
                "sortOrder": $scope.utils.getLabel("filters.sortByMostPopular"),
                "priceAsc": $scope.utils.getLabel("filters.sortByPriceASC"),
                "priceDesc": $scope.utils.getLabel("filters.sortByPriceDESC")
            };

            $scope.getOrderByLabel = function (key, reverse) {
                if (!key || key == "all") return $scope.orderByLabels["all"];
                if (key == "sortOrder") {
                    return $scope.orderByLabels[key];
                } else {
                    return $scope.orderByLabels[key + (reverse ? "Desc" : "Asc")];
                }
            };


            $scope.orderBy = {
                predicate: "all",
                reverse: false
            };

            $scope.filterBy = function (type) {
                if ($scope.resultfilter.type == type) {
                    $scope.resultfilter.type = null;
                    $scope.filterItems();
                    return;
                }
                $scope.resultfilter.type = type;
                $scope.filterItems();
            };

            $scope.order = function (predicate, reverse, preventResize) {
                $scope.orderBy.reverse = reverse;
                if (predicate != "all") {
                    $scope.orderBy.predicate = predicate;
                }

                $scope.filteredItems = $filter('orderBy')($scope.filteredItems, predicate == "all" ? "sortOrder" : $scope.orderBy.predicate, $scope.orderBy.reverse);

                if (!preventResize) {
                    setTimeout(function () {
                        jQuery(window).resize();
                    });
                }
            };

            $scope.filterItems = function () {
                $scope.filteredItems = $filter('filterAttractions')($scope.allItems, $scope.resultfilter);
                $scope.order($scope.orderBy.predicate, $scope.orderBy.reverse, true);
                setTimeout(function () {
                    jQuery(window).resize();
                });
            };


            $scope.globalErrors = [];
            var timeoutID = undefined;

            function resizeSliderPanel() {
                window.clearTimeout(timeoutID);
                timeoutID = setTimeout(function () {
                    jQuery(window).resize();
                }, 100);
            }

            $scope.isTileDescriptionExpandedByDefault = function (unitCode) {
                return unitCode && ($scope.requestArguments.unitcodeswithexpandedtilesdescriptionbydefault || []).indexOf(unitCode) >= 0;
            };

            $scope.getDefaultLeavingFromLocation = function () {
                return { value: { code: "" }, destination: [] };
            };

            $scope.scrollToResultsIfMobile = function () {
                //if (jQuery(window).width() < 760) {
                setTimeout(function () {
                    var page = $("html, body");

                    page.animate({ scrollTop: $scope.isLoading ? $("#loadingContainer").offset().top : $("#resultsContainer").offset().top }, 1000, function () {
                        page.off("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove");
                    });

                    page.on("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove", function () {
                        setTimeout(function () {
                            page.stop();
                        });
                    });
                });
                // }
            };

            $scope.showGoingToCities = false;

            $scope.getDefaultGoingToCityLocation = function () {
                return { code: "" };
            };

            $scope.selectedLeavingFromCity = undefined;
            $scope.selectedGoingToCity = undefined;
            //$scope.hideDropOff = false;
            //$scope.checkHideDropOff = function () {
            //    if (!$scope.selectedLeavingFromCity || !$scope.selectedGoingToCity) {
            //        $scope.hideDropOff = false;
            //        return;
            //    }
            //    $scope.hideDropOff = $scope.selectedLeavingFromCity.code == $scope.selectedGoingToCity.code;
            //};

            function strRange(min, max) {
                min = min || 0;
                max = max || 0;

                if (min == 0 && max == 0) {
                    return ["0"];
                }

                function toString(val) {
                    return val.toString();
                }

                return _.map(_.range(min, max), toString);
            }

            $scope.selectedAdults = "2";
            if (($scope.requestArguments.defaultselectedadultsbyproductcode || '').length > 0) {
                var defaultSelectedAdultsStr = _.find($scope.requestArguments.defaultselectedadultsbyproductcode, function (item) {
                    var pcode = item.split(' ')[0];
                    return pcode == $scope.requestArguments.productCode;
                });
                if (defaultSelectedAdultsStr) {
                    var defaultSelectedAdults = parseInt(defaultSelectedAdultsStr.split(' ')[1]);
                    if (defaultSelectedAdults > 0) {
                        $scope.selectedAdults = String(defaultSelectedAdults);
                    }
                }
            }

            $scope.selectedChild = "0";

            $scope.selectedSeniors = "0";
            $scope.selectedStudents = "0";
            $scope.selectedInfants = "0";



            //  $scope.availableAdults = strRange(0, $scope.maxAdultsChildrenTotal + 1);
            //  $scope.availableChild = strRange(0, ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults)) + 1);

            $scope.availableAdults = strRange(0, $scope.maxAdultsChildrenTotal + 1);
            $scope.availableChild = strRange(0, ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors) -
                parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

            $scope.availableSeniors = strRange(0, ($scope.maxAdultsChildrenTotal -
                parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) -
                parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

            $scope.availableStudents = strRange(0, ($scope.maxAdultsChildrenTotal -
                parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) -
                parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);
            $scope.availableInfants = strRange(0, ($scope.maxAdultsChildrenTotal -
                parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) -
                parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);


            $scope.allItems = [];
            $scope.reducedProducts = [];
            $scope.availableDepartures = [];

            $scope.showNext = false;

            $scope.getObjLength = function (obj) {
                return !obj ? 0 : Object.keys(obj).length;
            };

            $scope.isUnitAvailable = function (unit) {
                var totalGuests = parseInt($scope.selectedAdults || 0) + parseInt($scope.selectedChild || 0) +
                    parseInt($scope.selectedSeniors || 0) + parseInt($scope.selectedStudents, 0) + parseInt($scope.selectedInfants, 0);


                return unit && unit.availability >= (totalGuests);
            };

            //$scope.$watch("filteredDepartures", function (newVal, oldVal) {
            //    if (newVal === oldVal) return;
            //    $timeout(function () {
            //        if (($scope.filteredDepartures || "").length) {
            //            var availableDepartures = _.filter($scope.filteredDepartures, function (fd) { return fd.selectedUnit && !fd.selectedUnit.isInPast && !fd.selectedUnit.isTimeRestricted; });
            //            if ((availableDepartures || "").length === 1) {
            //                $scope.setSelectedDepartureProduct(availableDepartures[0]);
            //            }
            //        }
            //    });
            //});

            $scope.selectedDepartureProduct = undefined;
            $scope.selectedDeparturePickUp = undefined;
            $scope.selectedDepartureDropOff = undefined;

            $scope.debug = function (dropOff) {
                $scope.selectedDeparturePickUp;
                $scope.selectedDepartureDropOff;

            };
            $scope.departurePickUpChanged = function (pickUp) {
                $scope.selectedDeparturePickUp = pickUp;
            };

            $scope.departureDropOffChanged = function (dropOff) {
                $scope.selectedDepartureDropOff = dropOff;
            };

            $scope.selectDefaultProducts = function () {
                var firstDeparture = undefined;
                if (($scope.allItems || "").length) {
                    var availableDepartures = _.filter($scope.allItems, function (fd) { return !fd.isInPast; });
                    firstDeparture = (availableDepartures || "").length === 1 && $scope.selectedDepartureProduct !== availableDepartures[0] ? availableDepartures[0] : undefined;
                }

                firstDeparture = firstDeparture && firstDeparture.selectedUnit && firstDeparture.selectedUnit.isTimeRestricted ? undefined : firstDeparture;

                if (firstDeparture) {
                    $scope.setSelectedDepartureProduct(firstDeparture, function () { });
                }

                // $scope.showNext = $scope.canContinue($scope.setSelectedDepartureProduct);
            };

            $scope.setSelectedDepartureProduct = function (product) {
                if (!product.selectedUnit || product.selectedUnit.isInPast || product.selectedUnit.isTimeRestricted) {
                    $scope.showNext = false;
                    return;
                }

                $scope.selectedDepartureProduct = product;
                $scope.selectedDepartureProduct.requiredProducts = [];

                //   $scope.setBusStopsForProductUnit($scope.selectedDepartureProduct, $scope.selectedDepartureProduct.selectedUnit);
                //   $scope.showNext = $scope.canContinue();
            };

            $scope.getProductBusStops = function (product, callback) {
                if ($scope.isLoading) return;
                if (callback) {
                    callback();
                }

                // $scope.isLoading = false;
                var requestParams = {
                    urlPrefix: $("body").data("weburl") ? $("body").data("weburl") : "",
                    token: jwtService.getPrincipalToken(),
                    productCode: product.code,
                    unitCode: product.selectedUnit.unitCode
                };

                $scope.isLoading = true;

                transportationService.getBusStops(requestParams, function (dateResult) {
                    product.busStops = dateResult.data;
                    if (callback) {
                        callback();
                    }
                    $scope.isLoading = false;
                });
            };

            $scope.fillProductDetailsRecursive = function (parentProduct, products, index, callback) {
                if (index === products.length || !products[index]) {
                    callback();
                    return;
                }
                var params = {
                    token: jwtService.getPrincipalToken(),
                    productCode: products[index].productCode,
                    productCategory: products[index].productCategory,
                    travelDate: $scope.getSelectedDate()//$("#departure").data().daterangepicker.startDate.format("YYYY-MM-DD")
                };
                productsFactory.getProductWithHiddenUnitsWithCallback(params, function (result) {
                    if (result && result.success && (result.data || "").length) {
                        products[index].product = result.data[0];
                        products[index].product.selectedUnit = _.find(products[index].product.units, function (u) {
                            return products[index].unitCode === u.unitCode;
                        });
                        if (!parentProduct.requiredProducts) {
                            parentProduct.requiredProducts = [];
                        }
                        parentProduct.requiredProducts.push(products[index]);
                    }
                    $scope.fillProductDetailsRecursive(parentProduct, products, index + 1, callback);
                });

            };

            $scope.showRequiredProductsModal = function () {
                var popupProducts = _.filter($scope.selectedDepartureProduct.requiredProducts, function (reqProd) {

                    if (!reqProd.product) return false;

                    if (reqProd.product.productType === "FEE") {
                        reqProd.product.isFee = true;
                        return false;
                    }
                    return true;
                });
                if (popupProducts.length == 0) {
                    $scope.bookTour();
                    return;
                }
                var requiredModalInstance = $uibModal.open({
                    animation: true,
                    templateUrl: "requiredProductsModal.html",
                    controller: "requiredProductsModalCtrl",
                    size: "book-required-products",
                    resolve: {
                        "products": { followingProductSingle: "product", followingProductMultiple: "products", yourProductTitle: "tour", data: popupProducts }
                    },
                    backdrop: "true"
                });
                requiredModalInstance.result.then(function (result) {
                    $scope.bookTour();
                }, function () {
                    //console.log("dismiss");
                });
            };

            // on click
            $scope.getAdditionalProducts = function (product, unit) {

                $scope.selectedDepartureProduct = product;
                $scope.selectedDepartureProduct.selectedUnit = unit;
                $scope.setBusStopsForProductUnit($scope.selectedDepartureProduct, $scope.selectedDepartureProduct.selectedUnit);
                $scope.submitted = true;
                $scope.globalErrors = [];

                if (!$scope.selectedDepartureProduct.selectedUnit || $scope.selectedDepartureProduct.selectedUnit.isInPast || $scope.selectedDepartureProduct.selectedUnit.isTimeRestricted)
                    $scope.globalErrors.push("Tour is unavailable!");

                var requiredDeparturePickup = !$scope.showPickupLocationsOnCards || ($scope.selectedDepartureProduct
                    && (($scope.selectedDepartureProduct.selectedUnit.pickupLocationRequired && $scope.selectedDepartureProduct.selectedUnit.selectedPickUp)
                        || !$scope.selectedDepartureProduct.selectedUnit.pickupLocationRequired));
                var requiredDepartureDropOff = !$scope.showPickupLocationsOnCards || ($scope.selectedDepartureProduct
                    && (($scope.selectedDepartureProduct.selectedUnit.dropoffLocationRequired && $scope.selectedDepartureProduct.selectedUnit.selectedDropOff)
                        || !$scope.selectedDepartureProduct.selectedUnit.dropoffLocationRequired));

                var validDeparture = requiredDeparturePickup && (requiredDepartureDropOff); //|| $scope.hideDropOff

                var totalGuests = parseInt($scope.selectedAdults || 0) + parseInt($scope.selectedChild || 0) +
                    parseInt($scope.selectedSeniors || 0) + parseInt($scope.selectedStudents, 0) + parseInt($scope.selectedInfants, 0);


                var isAvailable = $scope.selectedDepartureProduct.selectedUnit.availability >= (totalGuests);
                if (!isAvailable) {
                    $scope.globalErrors.push(utilsFactory.getLabel("activity.error.unitUnavailable").replace("{0}",
                        $scope.selectedDepartureProduct.selectedUnit.availability));
                }

                if (!requiredDeparturePickup) {
                    $scope.globalErrors.push(utilsFactory.getLabel("tours.error.requiredDeparturePickup"));
                }
                if (!requiredDepartureDropOff) {
                    $scope.globalErrors.push(utilsFactory.getLabel("tours.error.requiredDepartureDropOff"));
                }
                if (totalGuests == 0 || ($scope.selectedAdults == 0 && $scope.selectedChild == 0 && $scope.selectedSeniors == 0 && $scope.selectedStudents == 0)) {
                    $scope.globalErrors.push("Select the number of guests");//utilsFactory.getLabel("tours.error.requiredDepartureDropOff"));
                }
                if ($scope.globalErrors.length) {
                    $scope.showModal["SubmitErrors"] = true;
                }

                if (!validDeparture) return;

                if (!($scope.selectedDepartureProduct.requiredProducts || "").length) {
                    $scope.isLoading = true;
                    //get related services - check required additional products to add
                    var productQueries = [];
                    productQueries.push({
                        ProductCode: $scope.selectedDepartureProduct.code,
                        TravelDate: $scope.getSelectedDate(),// $("#departure").data().daterangepicker.startDate.format("YYYY-MM-DD"),
                        UnitCode: $scope.selectedDepartureProduct.selectedUnit ?
                            $scope.selectedDepartureProduct.selectedUnit.unitCode : null
                    });

                    var dataToPost = { ProductQueries: productQueries };
                    var relatedServicesRequestParams = {
                        token: jwtService.getPrincipalToken(),
                        data: dataToPost
                    };

                    productsFactory.getRelatedServicesMulti(relatedServicesRequestParams, function (relatedProducts) {

                        if (relatedProducts && (relatedProducts.data || "").length && (relatedProducts.data[0].requiredProducts || "").length) {
                            //get product details for each additional required product
                            if (!($scope.selectedDepartureProduct.requiredProducts || "").length) {
                                $scope.fillProductDetailsRecursive($scope.selectedDepartureProduct, relatedProducts.data[0].requiredProducts, 0, function () {
                                    $scope.isLoading = false;

                                    if (($scope.selectedDepartureProduct.requiredProducts || "").length) {
                                        $scope.showRequiredProductsModal();
                                    } else {
                                        $scope.bookTour();
                                    }
                                });
                            } else {
                                $scope.isLoading = false;
                                $scope.showRequiredProductsModal();
                            }

                        } else {
                            //call the callback
                            $scope.bookTour();
                        }
                    });
                } else {
                    $scope.showRequiredProductsModal();
                }
            };

            $scope.gotoPackageDetails = function (selectedItem) {

                var productSelectTicketCtrl = $scope.$parent;
                if (!productSelectTicketCtrl.$parent) {
                    return;
                }
                var productDetailsCtrl = productSelectTicketCtrl.$parent;
                productDetailsCtrl.setSelectedPackage(selectedItem);
                var packageDetailsParam = {
                    packageCode: selectedItem.code,
                    date: $scope.getSelectedDate() //moment($("#departure").val(), shoppingCartService.getDateFormat()).format("YYYY-MM-DD")
                };

                var packagesCriteria = productDetailsCtrl.getPackagesSearchCriteria();
                // packagesCriteria.date = $("#daterange").val(),
                packagesCriteria.children = $scope.selectedChild;
                packagesCriteria.adults = $scope.selectedAdults;
                packagesCriteria.infants = $scope.selectedInfants;
                packagesCriteria.seniors = $scope.selectedSeniors;
                packagesCriteria.students = $scope.selectedStudents;

                productDetailsCtrl.savePackagesSearchCriteria(packagesCriteria);
                productDetailsCtrl.next($state.$current.name, packageDetailsParam);
            };

            $scope.bookTour = function () {

                var validDeparture = $scope.selectedDepartureProduct
                    && (($scope.selectedDepartureProduct.selectedUnit.pickupLocationRequired && $scope.selectedDepartureProduct.selectedUnit.selectedPickUp)
                        || !$scope.selectedDepartureProduct.selectedUnit.pickupLocationRequired)
                    && (($scope.selectedDepartureProduct.selectedUnit.dropoffLocationRequired && $scope.selectedDepartureProduct.selectedUnit.selectedDropOff)
                        || !$scope.selectedDepartureProduct.selectedUnit.dropoffLocationRequired); // || $scope.hideDropOff

                if (!validDeparture) return;

                var selectedDeparturePickUp = $scope.selectedDepartureProduct.selectedUnit.selectedPickUp;
                var selectedDepartureDropOff = $scope.selectedDepartureProduct.selectedUnit.selectedDropOff;
                var hidePickup = ($scope.selectedLeavingFromCity && $scope.selectedLeavingFromCity.pickups.length == 1) ? 1 : 0;
                var hideDropoff = ($scope.selectedGoingToCity && $scope.selectedGoingToCity.dropoffs.length == 1) ? 1 : 0;
                $scope.isLoading = true;

                var removeExistingCartItemPromise = undefined;

                if ($scope.updateItem) {
                    removeExistingCartItemPromise = new Promise(function (resolve, reject) {
                        var requestParams = {
                            apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                            token: jwtService.getPrincipalToken(),
                            index: $scope.updateIndex,
                            productCode: $scope.updateItem.ProductCode
                        };

                        shoppingCartService.setStorageCart($scope.cart, function () {
                            shoppingCartService.updateCartComponents(requestParams, function (shoppingCart) {
                                if (shoppingCart && (shoppingCart.Items || '').length) {
                                    $scope.cart = shoppingCart;
                                } else {
                                    // window.location = "/";
                                }
                                resolve(1);
                            });
                        });
                    }); // Promise
                } else {
                    removeExistingCartItemPromise = Promise.resolve(1);
                }

                removeExistingCartItemPromise.then(function () {
                    var components = [];
                    components.push({
                        "Id": $scope.selectedDepartureProduct.id,
                        "ProductCategory": $scope.selectedDepartureProduct.productCategory,
                        "ProductType": $scope.selectedDepartureProduct.productType,
                        "ProductCode": $scope.selectedDepartureProduct.code,
                        "StartDate": $scope.selectedDepartureProduct.startDate,
                        "EndDate": $scope.selectedDepartureProduct.endDate,
                        "Name": $scope.selectedDepartureProduct.name,
                        "Description": $scope.selectedDepartureProduct.description,
                        "ProductDescriptions": $scope.selectedDepartureProduct.productDescriptions,
                        "Price": $scope.selectedDepartureProduct.price,
                        "ChildPrice": $scope.selectedDepartureProduct.childPrice,
                        "NumberOfAdults": $scope.selectedAdults,
                        "NumberOfChildren": $scope.selectedChild,
                        "NumberOfSeniors": $scope.selectedSeniors,
                        "NumberOfStudents": $scope.selectedStudents,
                        "NumberOfInfants": $scope.selectedInfants,
                        "Status": "New",
                        "UnitCode": $scope.selectedDepartureProduct.selectedUnit ? $scope.selectedDepartureProduct.selectedUnit.unitCode : "",
                        "UnitDescription": $scope.selectedDepartureProduct.selectedUnit ? $scope.selectedDepartureProduct.selectedUnit.description : "",
                        "PickupLocation": selectedDeparturePickUp ? selectedDeparturePickUp : undefined,
                        "DropoffLocation": selectedDepartureDropOff ? selectedDepartureDropOff : undefined,
                        "StartingLocation": $scope.selectedDepartureProduct.startingLocation,
                        "Destination": $scope.selectedDepartureProduct.destination,
                        "Remarks": [],
                        "HidePickup": hidePickup,
                        "HideDropoff": hideDropoff,
                        "AddedFromWebTray": $scope.requestArguments.fromwebtray,
                        "_trackingLob": $scope.lobTitle
                    });

                    if ($scope.selectedDepartureProduct.requiredProducts) {
                        _.each($scope.selectedDepartureProduct.requiredProducts, function (reqProd) {
                            components.push({
                                "Id": reqProd.product.id,
                                "ProductCategory": reqProd.product.productCategory,
                                "ProductType": reqProd.product.productType,
                                "ProductCode": reqProd.product.code,
                                "StartDate": reqProd.product.startDate,
                                "EndDate": reqProd.product.endDate,
                                "Name": reqProd.product.name,
                                "Description": reqProd.product.description,
                                "ProductDescriptions": reqProd.product.productDescriptions,
                                "Price": reqProd.product.price,
                                "ChildPrice": reqProd.product.price,
                                "NumberOfAdults": $scope.selectedAdults,
                                "NumberOfChildren": $scope.selectedChild,
                                "NumberOfSeniors": $scope.selectedSeniors,
                                "NumberOfStudents": $scope.selectedStudents,
                                "NumberOfInfants": $scope.selectedInfants,
                                "Status": "New",
                                "UnitCode": reqProd.product.selectedUnit ? reqProd.product.selectedUnit.unitCode : reqProd.unitCode,
                                "UnitDescription": reqProd.product.selectedUnit ? reqProd.product.selectedUnit.description : reqProd.product.description,
                                "PickupLocation": undefined,
                                "DropoffLocation": undefined,
                                "StartingLocation": reqProd.product.startingLocation,
                                "Destination": undefined,
                                "Remarks": [],
                                "IsFee": reqProd.product.isFee,
                                "ShowInCart": reqProd.showInCart,
                                "ParentCode": $scope.selectedDepartureProduct.code,
                                "_trackingLob": $scope.lobTitle
                            });
                        });
                    }

                    var bookingToQuote = {
                        "Components": components
                    };
                    var data = {
                        "BookingToQuote": bookingToQuote
                    };


                    var specialProductsRequestParams = {
                        apiUrl: $scope.$parent.$parent.getWebUrl(),
                        token: jwtService.getPrincipalToken(),
                        dataToPost: {
                            "Booking": bookingToQuote
                        }
                    };


                    shoppingCartService.handleSpecialProducts(specialProductsRequestParams, function (result) {
                        if (!result) {
                            $scope.isLoading = false;
                            return;
                        }

                        var requestParams = {
                            apiUrl: $scope.$parent.$parent.getWebUrl(),
                            token: jwtService.getPrincipalToken(),
                            dataToPost: data,
                            startDate: $scope.getSelectedDate(shoppingCartService.getDateFormat()),//$("#departure").val(),// moment($scope.selectedDepartureProduct.startDate).format("DD MMMM YYYY"),
                            endDate: $scope.getSelectedDate(shoppingCartService.getDateFormat()) , //$("#departure").val(), //moment($scope.selectedDepartureProduct.endDate).format("DD MMMM YYYY"),
                            startTime: $scope.selectedDeparturePickUp ? $scope.selectedDeparturePickUp.time : undefined,
                            endTime: $scope.selectedDepartureDropOff ? $scope.selectedDepartureDropOff.time : undefined
                        };

                        shoppingCartService.quoteComponents(requestParams, function (quoteResult) {
                            if (!quoteResult || !quoteResult.quote) return;

                            var successCartUpdateCallback = function (result) {
                                if (result) {
                                    var isEnhanceBookingPageEnabled = ($scope.selectedLanguage && $scope.selectedLanguage.enableEnhanceBookingPage) || ($scope.anonymUser && $scope.anonymUser.enableEnhanceBookingPage);
                                    var redirectToUrl = shoppingCartService.utils.getAfterAddToCartPageUrl(generalCtrl.selectedGeographyCode, isEnhanceBookingPageEnabled);
                                    window.location = utilsFactory.addPersistentQueryStringsParams(redirectToUrl);
                                } else {
                                    $scope.isLoading = false;
                                }
                            };

                            if (quoteResult.quote.ExpressConsentRequired) {
                                $scope.isLoading = false;
                                var compsThatRequireConsent = [];
                                _.each(quoteResult.quote.Components, function (qComp, i) {
                                    if (qComp && qComp.ExpressConsentOptions && qComp.ExpressConsentOptions.ExpressConsentRequired) {
                                        compsThatRequireConsent.push({ details: requestParams.dataToPost.BookingToQuote.Components[i], expressConsentOptions: qComp.ExpressConsentOptions });
                                    }
                                });
                                var requiredModalInstance = $uibModal.open({
                                    animation: true,
                                    templateUrl: "expressConsentModal.html",
                                    controller: "expressConsentModalCtrl",
                                    size: "book-required-products",
                                    resolve: {
                                        "expressConsent": {
                                            title: utilsFactory.getLabel("general.expressConsent.ConfirmModalTitle"),
                                            message: utilsFactory.getLabel("general.expressConsent.ConfirmModalMessage"),
                                            components: compsThatRequireConsent
                                        }
                                    },
                                    backdrop: "true"
                                });

                                requiredModalInstance.result.then(function (result) {
                                    shoppingCartService.addQuotedDataToCart(quoteResult, successCartUpdateCallback);
                                }, function (e) {
                                    //console.log("dismiss");
                                    // debugger;
                                });
                            } else {
                                shoppingCartService.addQuotedDataToCart(quoteResult, successCartUpdateCallback);
                            }
                        });
                    }); // handle special products 
                }); // EndPromise resolve    

            };

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            var selectedActivity = $scope.$parent.getPrevActivity();

            selectedActivity = selectedActivity && ((selectedActivity.isHeader && selectedActivity.productType === $scope.requestArguments.productCode) ||
                !(selectedActivity.isHeader && selectedActivity.code === $scope.requestArguments.productCode)) ? selectedActivity : undefined;
            $scope.requestArguments.travelDate = $scope.requestArguments.isDefaultDate !== "1" || (!selectedActivity || !selectedActivity.startDate) ? $scope.requestArguments.travelDate : $scope.$parent.getProductDate(selectedActivity.startDate);




            $scope.searchProducts = function () {

                $scope.submittedSearch = true;
                $scope.globalErrors = [];

                if (!$scope.showPickupLocationsOnCards) {
                    if (!$scope.selectedLeavingFromCity) {
                        $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredLeavingFromLocation"));
                    }

                    if (!$scope.selectedGoingToCity) {
                        $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredGoingToLocation"));
                    }


                    if (!$scope.selectedPickUp && $scope.selectedLeavingFromCity && ($scope.selectedLeavingFromCity.pickups || '').length) {
                        $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredPickupLocation"));
                    }
                    if (!$scope.selectedDropOff && $scope.selectedGoingToCity && ($scope.selectedGoingToCity.dropoffs || '').length) { // !$scope.hideDropOff &&
                        $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredDropoffLocation"));
                    }
                }

                if ($scope.globalErrors.length) {
                    $timeout(function () {
                        $scope.showModal["SubmitErrors"] = true;
                    });

                    return;
                }
                $scope.getTours();
            };



            //$scope.adultsChanged = function () {
            //    $scope.availableChild = strRange(0, ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults)) + 1);
            //    if ($scope.availableChild.indexOf(String($scope.selectedChild)) < 0) {
            //        $scope.selectedChild = $scope.availableChild[0];
            //    }
            //    if ($scope.selectedAdults == 0 && $scope.selectedChild == 0) {
            //        $scope.selectedChild = 1;
            //    }
            //};

            //$scope.childChanged = function () {
            //    $scope.availableAdults = strRange(0, ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild)) + 1);
            //    if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
            //        $scope.selectedAdults = $scope.availableAdults[0];
            //    }
            //    if ($scope.selectedAdults == 0 && $scope.selectedChild == 0) {
            //        $scope.selectedAdults = 1;
            //    }
            //};
            $scope.adultsChanged = function () {
                $scope.availableChild = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors)
                        - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableChild.indexOf(String($scope.selectedChild)) < 0) {
                    $scope.selectedChild = $scope.availableChild[0];
                }
                $scope.availableSeniors = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableSeniors.indexOf(String($scope.selectedSeniors)) < 0) {
                    $scope.selectedSeniors = $scope.availableSeniors[0];
                }

                $scope.availableStudents = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableStudents.indexOf(String($scope.selectedStudents)) < 0) {
                    $scope.selectedStudents = $scope.availableStudents[0];
                }

                $scope.availableInfants = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

                if ($scope.availableInfants.indexOf(String($scope.selectedInfants)) < 0) {
                    $scope.selectedInfants = $scope.availableInfants[0];
                }
            };

            $scope.childChanged = function () {
                var maxAdults = ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants));

                if ($scope.maxAdults > 0 && maxAdults > $scope.maxAdults) {
                    maxAdults = $scope.maxAdults;
                }

                $scope.availableAdults = strRange(0, maxAdults + 1);

                if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
                    $scope.selectedAdults = $scope.availableAdults[0];
                }

                $scope.availableSeniors = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableSeniors.indexOf(String($scope.selectedSeniors)) < 0) {
                    $scope.selectedSeniors = $scope.availableSeniors[0];
                }

                $scope.availableStudents = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableStudents.indexOf(String($scope.selectedStudents)) < 0) {
                    $scope.selectedStudents = $scope.availableStudents[0];
                }

                $scope.availableInfants = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

                if ($scope.availableInfants.indexOf(String($scope.selectedInfants)) < 0) {
                    $scope.selectedInfants = $scope.availableInfants[0];
                }
            };

            $scope.seniorChanged = function () {
                //selectedSeniors
                //availableSeniors

                var maxAdults = ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants));

                if ($scope.maxAdults > 0 && maxAdults > $scope.maxAdults) {
                    maxAdults = $scope.maxAdults;
                }

                $scope.availableAdults = strRange(0, maxAdults + 1);

                if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
                    $scope.selectedAdults = $scope.availableAdults[0];
                }
                $scope.availableChild = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableChild.indexOf(String($scope.selectedChild)) < 0) {
                    $scope.selectedChild = $scope.availableChild[0];
                }
                $scope.availableStudents = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableStudents.indexOf(String($scope.selectedStudents)) < 0) {
                    $scope.selectedStudents = $scope.availableStudents[0];
                }

                $scope.availableInfants = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

                if ($scope.availableInfants.indexOf(String($scope.selectedInfants)) < 0) {
                    $scope.selectedInfants = $scope.availableInfants[0];
                }
            };

            $scope.studentChanged = function () {
                var maxAdults = ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants));

                if ($scope.maxAdults > 0 && maxAdults > $scope.maxAdults) {
                    maxAdults = $scope.maxAdults;
                }

                $scope.availableAdults = strRange(0, maxAdults + 1);

                if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
                    $scope.selectedAdults = $scope.availableAdults[0];
                }

                $scope.availableChild = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableChild.indexOf(String($scope.selectedChild)) < 0) {
                    $scope.selectedChild = $scope.availableChild[0];
                }
                $scope.availableSeniors = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableSeniors.indexOf(String($scope.selectedSeniors)) < 0) {
                    $scope.selectedSeniors = $scope.availableSeniors[0];
                }

                $scope.availableInfants = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

                if ($scope.availableInfants.indexOf(String($scope.selectedInfants)) < 0) {
                    $scope.selectedInfants = $scope.availableInfants[0];
                }
            };

            $scope.infantChanged = function () {
                var maxAdults = ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants));

                if ($scope.maxAdults > 0 && maxAdults > $scope.maxAdults) {
                    maxAdults = $scope.maxAdults;
                }

                $scope.availableAdults = strRange(0, maxAdults + 1);

                if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
                    $scope.selectedAdults = $scope.availableAdults[0];
                }

                $scope.availableChild = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableChild.indexOf(String($scope.selectedChild)) < 0) {
                    $scope.selectedChild = $scope.availableChild[0];
                }
                $scope.availableSeniors = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableSeniors.indexOf(String($scope.selectedSeniors)) < 0) {
                    $scope.selectedSeniors = $scope.availableSeniors[0];
                }

                $scope.availableStudents = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableStudents.indexOf(String($scope.selectedStudents)) < 0) {
                    $scope.selectedStudents = $scope.availableStudents[0];
                }
            };



            $scope.goingToCityChanged = function () {
                if (!$scope.selectedGoingToCity) return;

                if ($scope.selectedLeavingFromCity.value && $scope.selectedLeavingFromCity.value.code) {
                    //$scope.showNext = true;
                    $scope.fillTours();
                } else {
                    $scope.showNext = false;
                }

            };


            $scope.resetSelectedProducts = function () {
                $scope.selectedDepartureProduct = undefined;

                // $scope.showNext = $scope.canContinue();
            };

            $scope.refreshBusStops = function () {
                var travelDate = $scope.getSelectedDate(); //$("#departure").data().daterangepicker.startDate.format("YYYY-MM-DD");
                if ($scope.selectedLeavingFromCity) {
                    $scope.fillBussStopsForLocation($scope.selectedLeavingFromCity, travelDate, function () {
                        $scope.setSelectedPickUp($scope.selectedLeavingFromCity.pickups);
                        if ($scope.selectedGoingToCity) { // && !$scope.hideDropOff
                            $scope.fillBussStopsForLocation($scope.selectedGoingToCity, travelDate, function () {
                                $scope.setSelectedDropOff($scope.selectedGoingToCity.dropoffs);
                            });
                        }
                    });
                } else if ($scope.selectedGoingToCity) { //&& !$scope.hideDropOff
                    $scope.fillBussStopsForLocation($scope.selectedGoingToCity, travelDate, function () {
                        $scope.setSelectedDropOff($scope.selectedGoingToCity.dropoffs);
                    });
                }
            };

            $scope.fillBussStopsForLocation = function (loc, date, callback) {
                if (!loc) {
                    callback();
                    return;
                }
                var requestParams = {
                    urlPrefix: $("body").data("weburl") ? $("body").data("weburl") : "",
                    token: jwtService.getPrincipalToken(),
                    cityCode: loc.code,
                    travelDate: date,
                    serviceType: $scope.requestArguments.productCode
                };
                $scope.isLoading = true;
                transportationService.getBusStopsByCity(requestParams, function (dateResult) {
                    $scope.isLoading = false;
                    loc.pickups = undefined;
                    loc.dropoffs = undefined;
                    if (dateResult.data) {
                        loc.pickups = (dateResult.data.pickups || "").length ? dateResult.data.pickups : [];
                        loc.dropoffs = (dateResult.data.dropoffs || "").length ? dateResult.data.dropoffs : [];
                    }
                    callback();
                });
            };

            $scope.pickUpChanged = function (pickUp) {
                if ($scope.isLoading) return;
                $scope.selectedPickUp = pickUp;
                $scope.wasSearch = false;
                $scope.resetSelectedProducts();
            };

            $scope.dropOffChanged = function (dropOff) {
                if ($scope.isLoading) return;
                $scope.selectedDropOff = dropOff;
                $scope.wasSearch = false;
                $scope.resetSelectedProducts();
            };
            $scope.setSelectedPickUp = function (data) {
                if (!$scope.selectedPickUp) {
                    if ((data || "").length == 1) {
                        $scope.selectedPickUp = data[0];
                        return;
                    }

                    if (data && $scope.updateItem && !$scope.updateItem.wasPickUpSelected) {
                        $scope.updateItem.wasPickUpSelected = true;
                        var firstUpdateComp = $scope.updateItem && $scope.updateItem.BookingToQuote.Components[0];

                        $scope.selectedPickUp = _.find(data, function (loc) {
                            return loc.code == (firstUpdateComp.PickupLocation && firstUpdateComp.PickupLocation.code);
                        });
                    }
                    return;
                }
                if (!data) {
                    $scope.selectedPickUp = undefined;
                    return;
                }
                $scope.selectedPickUp = _.find(data, function (it) {
                    return it.code == $scope.selectedPickUp.code;
                });
                if (!$scope.selectedPickUp && data.length === 1)
                    $scope.selectedPickUp = data[0];
            };

            $scope.setSelectedDropOff = function (data) {
                if (!$scope.selectedDropOff) {
                    if ((data || "").length == 1) {
                        $scope.selectedDropOff = data[0];
                        return;
                    }
                    if (data && $scope.updateItem && !$scope.updateItem.wasDropoffSelected) {
                        $scope.updateItem.wasDropoffSelected = true;
                        var firstUpdateComp = $scope.updateItem && $scope.updateItem.BookingToQuote.Components[0];

                        $scope.selectedDropOff = _.find(data, function (loc) {
                            return loc.code == (firstUpdateComp.DropoffLocation && firstUpdateComp.DropoffLocation.code);
                        });
                    }
                    return;
                };

                if (!data) {
                    $scope.selectedDropOff = undefined;
                    return;
                }

                $scope.selectedDropOff = _.find(data, function (it) {
                    return it.code == $scope.selectedDropOff.code;
                });

                if (!$scope.selectedDropOff && data.length === 1)
                    $scope.selectedDropOff = data[0];
            };

            $scope.leavingFromCityChanged = function (callback) {
                if (!$scope.selectedLeavingFromCity) return;
                $scope.wasSearch = false;
                //   $scope.resetSelectedProducts();
                var travelDate = $scope.getSelectedDate(); //$("#departure").data().daterangepicker.startDate.format("YYYY-MM-DD");
                $scope.fillBussStopsForLocation($scope.selectedLeavingFromCity, travelDate, function () {
                    $scope.setSelectedPickUp($scope.selectedLeavingFromCity.pickups);
                    if (callback) callback();
                });
                // $scope.checkHideDropOff();
            };

            $scope.goingToCityChanged = function () {
                if (!$scope.selectedGoingToCity) return;
                $scope.wasSearch = false;
                $scope.resetSelectedProducts();
                var travelDate = $scope.getSelectedDate(); //$("#departure").data().daterangepicker.startDate.format("YYYY-MM-DD");
                $scope.fillBussStopsForLocation($scope.selectedGoingToCity, travelDate, function () {
                    $scope.setSelectedDropOff($scope.selectedGoingToCity.dropoffs);
                });
                // $scope.checkHideDropOff();
            };

            $scope.setBusStopsForProductUnit = function (product, unit) {
                if (!unit) return;
                if ((unit.pickups || "").length) {
                    if (!$scope.showPickupLocationsOnCards) {
                        unit.selectedPickUp = _.find(unit.pickups, function (pu) {
                            return pu.code == $scope.selectedPickUp.code;
                        });
                    }
                    if (unit.selectedPickUp) {
                        unit.selectedPickUpTimeMoment = moment(unit.selectedPickUp.timeObj, "HH:mm");
                        product.pickupStr = unit.selectedPickUpTimeMoment.format("hh:mm A");
                    }
                }
                if ((unit.dropoffs || "").length) { // !$scope.hideDropOff &&
                    if (!$scope.showPickupLocationsOnCards) {
                        unit.selectedDropOff = _.find(unit.dropoffs, function (pu) {
                            return pu.code == $scope.selectedDropOff.code;
                        });
                    }
                    if (unit.selectedDropOff) {
                        unit.selectedDropOffTimeMoment = moment(unit.selectedDropOff.timeObj, "HH:mm");
                        product.dropoffStr = unit.selectedDropOffTimeMoment.format("hh:mm A");
                    }
                }
            };

            $scope.getReducedAllProductUnits = function (allItems) {
                if (!allItems || !allItems.length) return [];
                var getSelectedUnitOrDefault = function () {
                    return this.selectedUnit || (this.units && this.units[0] || Object.create(null));
                };

                return _.map(allItems, function (product) {
                    var newItem = {
                        departure: product,
                        selectedUnit: (product.units || '').length == 1 ? product.units[0] : undefined,
                        units: product.units,
                        price: (product.units && product.units[0] && product.units[0].price) || 0
                    };
                    newItem.getSelectedUnitOrDefault = getSelectedUnitOrDefault.bind(newItem);

                    return newItem;
                });

                //return _.reduce(allItems, function (a, product) {
                //    if ((product.units || '').length) {
                //        return a.concat(_.map(product.units, function (unit) {
                //            return { departure: product, selectedUnit: unit, price: unit.price, sortOrder: unit.sortOrder };
                //        }));
                //    } else {
                //        a.push({ departure: product, selectedUnit: undefined });
                //        return a;
                //    }

                //}, []);
            };

            $scope.showSoldOutNotice = function (product) {
                setTimeout(function () {
                    if (product && product.productDescriptions && product.productDescriptions.soldOutNotice) {
                        var showSoldOutNotice = true;
                        _.each(product.units, function (unit) {
                            showSoldOutNotice = showSoldOutNotice && (unit.availability < 1);
                        });
                        if (showSoldOutNotice) {
                            generalCtrl.toggleModalWithData("SoldOutNotice", product.productDescriptions.soldOutNotice);
                        }
                    }
                });
            };

            $scope.getTours = function () {

                var requestParams = {
                    urlPrefix: $("body").data("weburl") ? $("body").data("weburl") : "",
                    token: jwtService.getPrincipalToken(),
                    date: $scope.getSelectedDate(),//$("#departure").data().daterangepicker.startDate.format("YYYY-MM-DD"),
                    type: $scope.requestArguments.productCode,
                    fromLocationCode: $scope.selectedLeavingFromCity && $scope.selectedLeavingFromCity.code,
                    fromLocationName: $scope.selectedLeavingFromCity && $scope.selectedLeavingFromCity.name,
                    toLocationCode: $scope.selectedGoingToCity && $scope.selectedGoingToCity.code,
                    toLocationName: $scope.selectedGoingToCity && $scope.selectedGoingToCity.name,
                    pickupCode: $scope.selectedPickUp && $scope.selectedPickUp.code,
                    dropoffCode: $scope.selectedDropOff && $scope.selectedDropOff.code,
                    loadPickupsAndDropoffs: $scope.showPickupLocationsOnCards
                };

                var trackerReq = {
                    lobTitle: $scope.lobTitle,
                    packageName: null,
                    searchDate: requestParams.date,
                    adults: parseInt($scope.selectedAdults),
                    children: parseInt($scope.selectedChild),
                    shoppingCart: $scope.cart,
                    anonymUser: $scope.anonymGeneralUser,
                    bookingNumber: null,
                    bookingId: null
                };
                trackingService.buildFlowTrackerObj(trackerReq);

                // if (!$scope.hideDropOff) {
                //    requestParams.dropoffCode = $scope.selectedDropOff.code;
                // }

                $scope.isLoading = true;
                $scope.wasSearch = true;
                $scope.scrollToResultsIfMobile();
                $scope.allItems = [];
                $scope.reducedProducts = [];
                $scope.packages = [];

                activitiesService.getToursByTypeWithPackages(requestParams, function (dateResult) {

                    var allItems = dateResult && dateResult.data ? dateResult.data.products : [];
                    $scope.packages = dateResult && dateResult.data ? dateResult.data.packages : [];
                    _.each($scope.packages, function (el) {
                        el.isPackage = true;
                        el.sortOrder = el.ibeSortOrder;

                        //var timeLimit = undefined;
                        if (el.bookingCutOffTime) {
                            var currTime = jwtService.getServerMomentDate(true);
                            el.isTimeRestricted = moment(el.bookingCutOffTime).isSameOrBefore(currTime);
                        }

                        // set price
                        if (el.ageBasedPriceBreakdown) {

                            el.price = el.ageBasedPriceBreakdown.adultPrice;
                            el.childPrice = el.ageBasedPriceBreakdown.childPrice;
                            el.additionalChildPrice = el.ageBasedPriceBreakdown.additionalChildPrice;
                            el.seniorPrice = el.ageBasedPriceBreakdown.seniorPrice;
                            el.studentPrice = el.ageBasedPriceBreakdown.studentPrice;

                            el.showPriceDescription = !el.ageBasedPriceBreakdown.adultPrice
                                && !el.ageBasedPriceBreakdown.childPrice && !el.ageBasedPriceBreakdown.additionalChildPrice
                                && !el.ageBasedPriceBreakdown.seniorPrice
                                && !el.ageBasedPriceBreakdown.studentPrice;

                        } else {
                            el.showPriceDescription = true;
                        }
                        //el.currency = (prices && prices[0] && prices[0].currency) || "USD";
                        el.culture = ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) || "en";
                    });
                    var soldOutNoticeProduct = undefined;

                    _.each(allItems, function (pr) {
                        if (pr.units) {
                            soldOutNoticeProduct = pr;
                            if ($scope.requestArguments.unitCode) {
                                pr.units = _.filter(pr.units, function (unit) { return unit.unitCode === $scope.requestArguments.unitCode; });
                            }
                            pr.selectedUnit = pr.units[0];
                            // pr.units = _.filter(pr.units, function (un) { return un.availability > 0; }); // change
                        }
                    });

                    var isCurrDate = moment(requestParams.date).isSame(jwtService.getServerMomentDate());
                    var currHourLimit = jwtService.getServerMomentDate(true);
                    //moment(tc.format("hh:mm A"), "hh:mm A");

                    var pricePromises = [];

                    _.each(allItems, function (el) {
                        el.selectedTime = undefined;
                        var elDateStr = el.startDate.substring(0, el.startDate.indexOf("T"));

                        var timeLimit = jwtService.getServerMomentDate(true);
                        //var timeLimit = undefined;
                        if (el.bookingRestrictionTime > 0) {
                            timeLimit.add(parseInt(el.bookingRestrictionTime), "m");
                            //timeLimit = moment(tc.format("hh:mm A"), "hh:mm A");
                        }

                        if (el.units && el.units.length > 0) {
                            _.each(el.units, function (unit) {
                                unit.timeStr = moment(unit.startTime).format("hh:mm A");
                                var newDateTime = elDateStr + unit.startTime.substring(unit.startTime.indexOf("T"));
                                unit.timeVal = moment(newDateTime);

                                //if (isCurrDate) {
                                var unitTimeLimit = undefined;
                                unit.isInPast = unit.timeVal <= currHourLimit;

                                if (unit.bookingRestrictionTime > 0) {
                                    unitTimeLimit = jwtService.getServerMomentDate(true);
                                    unitTimeLimit.add(parseInt(unit.bookingRestrictionTime), "m");
                                    //timeLimit = moment(tc.format("hh:mm A"), "hh:mm A");
                                }

                                if (!unit.isInPast && (unitTimeLimit || timeLimit)) {
                                    unit.isTimeRestricted = unit.timeVal <= (unitTimeLimit || timeLimit);
                                }
                                //                                }

                                //get price                                                         

                                if (unit.ageBasedPriceBreakdown) {
                                    if (unit.ageBasedPriceBreakdown.adultPrice) {
                                        unit.price = unit.ageBasedPriceBreakdown.adultPrice;
                                    }
                                    unit.childPrice = unit.ageBasedPriceBreakdown.childPrice;
                                    unit.additionalChildPrice = unit.ageBasedPriceBreakdown.additionalChildPrice;
                                    unit.seniorPrice = unit.ageBasedPriceBreakdown.seniorPrice;
                                    unit.studentPrice = unit.ageBasedPriceBreakdown.studentPrice;
                                }

                                //unit.currency = (prices && prices[0] && prices[0].currency) || "USD";                                
                                unit.currency = unit.currency || ((jwtService.getGeography() || "").toUpperCase().indexOf("SKL") >= 0 ? "ISK" : "USD");
                                unit.culture = ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) || "en";

                                if ($scope.showPickupLocationsOnCards) {
                                    if (!unit.selectedPickUp && unit.pickupLocationRequired && (unit.pickups || "").length) {
                                        unit.selectedPickUp = unit.pickups[0];
                                    }

                                    if (!unit.selectedDropOff && unit.dropoffLocationRequired && (unit.dropoffs || "").length) {
                                        unit.selectedDropOff = unit.dropoffs[0];
                                    }
                                }
                            });

                            // el.selectedUnit = el.units[0];//_.find(el.units, function (un) { return !un.isInPast; });

                            //  $scope.setBusStopsForProductUnit(el, el.selectedUnit);
                        }
                    });


                    $scope.reducedProducts = $scope.getReducedAllProductUnits(allItems);

                    $scope.allItems = ($scope.reducedProducts || []).concat($scope.packages || []);

                    $scope.filterItems();


                    $scope.wasSearch = true;
                    $scope.selectDefaultProducts();
                    //  $scope.showNext = $scope.canContinue();
                    setTimeout(function () {
                        $scope.isLoading = false;
                        $scope.$apply();
                        $scope.scrollToResultsIfMobile();
                        $scope.showSoldOutNotice(soldOutNoticeProduct);
                    });
                    //

                });
            };

            $scope.$watch('showNext', function (newVal, oldVal) {
                if (!newVal) {
                    $scope.submitted = false;
                }
            }, true);

            $scope.canContinue = function (departure, unit) {

                //var validDeparture = $scope.selectedDepartureProduct
                //      && (($scope.selectedDepartureProduct.selectedUnit.pickupLocationRequired && $scope.selectedDeparturePickUp)
                //          || !$scope.selectedDepartureProduct.selectedUnit.pickupLocationRequired)
                //      && (($scope.selectedDepartureProduct.selectedUnit.dropoffLocationRequired && $scope.selectedDepartureDropOff)
                //          || !$scope.selectedDepartureProduct.selectedUnit.dropoffLocationRequired);

                if (departure &&
                    unit && !unit.isInPast && !unit.isTimeRestricted) {


                    var isAvailable = $scope.isUnitAvailable(unit);
                    if (!isAvailable) return false;
                    if (!$scope.showPickupLocationsOnCards) return true;

                    return ((unit.pickupLocationRequired && unit.selectedPickUp) || !unit.pickupLocationRequired)
                        && ((unit.dropoffLocationRequired && unit.selectedDropOff) || !unit.dropoffLocationRequired);
                }


                // $scope.submitted = false;
                return false;
            };

            $scope.fillTours = function () {
                $scope.showNext = false;
                if ($scope.selectedLeavingFromCity && $scope.selectedLeavingFromCity.value.code !== "" && $scope.selectedGoingToCity && $scope.selectedGoingToCity.code !== "") {
                    //reset the filters
                    $scope.selectedDepartureProduct = undefined;

                    $scope.selectedDeparturePickUp = undefined;
                    $scope.selectedDepartureDropOff = undefined;

                    $scope.availableDepartures = _.filter($scope.allItems, function (product) {
                        return product.startingLocation.code === $scope.selectedLeavingFromCity.value.code && product.destination.code === $scope.selectedGoingToCity.code;
                    });

                    resizeSliderPanel();
                }
            };

            $scope.fillLocations = function (products) {
                var startingLocations = [];
                var destinationLocations = [];
                _.map(products, function (product) {
                    startingLocations.push(product.startingLocation);
                    destinationLocations.push(product.destination);
                });

                var mapDepart = Object.create(null);
                _.map(products, function (product) {
                    if (product.startingLocation && product.destination) {
                        if (product.startingLocation.code in mapDepart) {
                            var dest = _.find(mapDepart[product.startingLocation.code].destinations,
                                function (d) {
                                    return d.code === product.destination.code;
                                });
                            if (!dest) {
                                mapDepart[product.startingLocation.code].destinations.push(product.destination);
                            };
                        } else {
                            mapDepart[product.startingLocation.code] = {
                                value: product.startingLocation,
                                destinations: [product.destination]
                            };
                        }
                    }
                });

                $scope.allLocations = mapDepart;
                if (!$scope.getObjLength($scope.allLocations)) {
                    $scope.selectedLeavingFromCity = { value: { code: "" }, destination: [] };
                    $scope.selectedGoingToCity = { code: "" };
                }

                $scope.showLeavingFromCities = true;
                $scope.showGoingToCities = ($scope.selectedLeavingFromCity.value.code && $scope.selectedGoingToCity.code);
                $scope.fillTours();

                $scope.isLoading = false;
            };

            $scope.departureSelectedUnitChanged = function (departure) {
                // departure.selectedUnit = unit;
                if ($scope.selectedDepartureProduct === departure) {
                    $scope.selectedDepartureProduct.requiredProducts = [];
                    //    $scope.setBusStopsForProductUnit(departure, departure.selectedUnit);
                    //   resizeSliderPanel();
                    //$scope.getProductBusStops(departure, function () {
                    //    $scope.selectedDeparturePickUp = undefined; //departure.busStops && departure.busStops.pickups.length ? departure.busStops.pickups[0] : undefined;
                    //    $scope.selectedDepartureDropOff = undefined; //departure.busStops && departure.busStops.dropoffs.length ? departure.busStops.dropoffs[0] : undefined;
                    //    resizeSliderPanel();
                    //});
                }
                // $scope.showNext = $scope.canContinue();
            };

            $scope.getUnitDescription = function (departure) {
                switch (departure.productCategory) {
                    case "Tour":
                        return moment(departure.selectedUnit.startTime).format("hh:mm A") + " Departure";
                    default:
                        return departure.selectedUnit.description;
                }

            };

            $scope.initLocations = function (callback) {
                if ($scope.showPickupLocationsOnCards) {
                    $scope.isLoading = false;
                    callback();
                    return;
                }

                var requestParams = {
                    urlPrefix: $("body").data("weburl") ? $("body").data("weburl") : "",
                    token: jwtService.getPrincipalToken(),
                    type: $scope.requestArguments.productCode
                };
                $scope.isLoading = true;
                transportationService.getLocationsByServiceType(requestParams, function (dateResult) {
                    $scope.isLoading = false;
                    if (dateResult.data) {
                        var departureLocations = (dateResult.data.departureLocations || "").length ? dateResult.data.departureLocations : [];
                        var destinationLocations = (dateResult.data.destinations || "").length ? dateResult.data.destinations : [];
                        $scope.departureLocations = _.sortBy(departureLocations, function (loc) { return loc.name; });
                        $scope.destinationLocations = _.sortBy(destinationLocations, function (loc) { return loc.name; });
                    }
                    callback();
                });
            };


            $scope.getDynamicPricesKey = function (month, year) {
                var productCode = ($scope.mainProduct && ($scope.mainProduct.productType||$scope.mainProduct.code));
                if (!productCode) return;

                month++; // month start at 0, so we need to increment
                return String(month) + String(year) + productCode.toLowerCase();
            };

            $scope.loadCalendarPrices = function (month, year) {
                var productCode = ($scope.mainProduct && ($scope.mainProduct.productType || $scope.mainProduct.code));
                if (!productCode) return;
                var priceObjKey = $scope.getDynamicPricesKey(month, year);

                month++; // month start at 0, so we need to increment              
                if ($scope.dynamicPrices[priceObjKey]) return; // if the dynamic prices were already loaded return;

                $scope.calendarIsLoading = true;
                $scope.inlineDatePicker.toggleLoading($scope.calendarIsLoading);

                productsFactory.getDynamicProductCategoryPrices(jwtService.getPrincipalToken(), productCode, month, year).then(
                    function (result) {
                        var prices = result.data.prices;
                        if ((prices || "").length) {
                            var monthPrices = Object.create(null);
                            $.each(prices, function (key, value) {
                                var vdate = moment(value.date, 'YYYY-MM-DDTHH:mm:ss').date()
                                monthPrices[vdate] = { price: value.price, className: (value.projectedVisitation || "").toLowerCase(), isClosed: value.isClosed, closedReason: value.closedReason };
                            });
                            $scope.dynamicPrices[priceObjKey] = monthPrices;
                        }
                        $scope.calendarIsLoading = false;

                        $scope.inlineDatePicker.toggleLoading($scope.calendarIsLoading);
                        $scope.inlineDatePicker.update();
                    },
                    function (response) {
                        $scope.calendarIsLoading = false;
                        $scope.inlineDatePicker.toggleLoading($scope.calendarIsLoading);
                    });
            };

            $scope.getSelectedDate = function (dateFormat, returnMoment) {
                dateFormat = dateFormat || "YYYY-MM-DD";
                if ($scope.inlineDatePicker) {
                    // use the inline picker
                    var result = (($scope.inlineDatePicker.selectedDates || "").length ?
                        moment($scope.inlineDatePicker.selectedDates[0]) : moment());
                    return returnMoment ? result : result.format(dateFormat);
                } else {
                    var date = $("#departure").val();
                    var result = moment(date, shoppingCartService.getDateFormat());
                    return returnMoment ? result : result.format(dateFormat);
                }
            };

            $scope.setSelectedDate = function (newDate) {
                var newDateMoment = moment(newDate, shoppingCartService.getDateFormat());

                if ($scope.inlineDatePicker) {
                    // use the inline picker
                    return $scope.inlineDatePicker.selectDate(newDateMoment.toDate());
                } else {
                    $("#departure").val(newDate);

                    $("#departure").data().daterangepicker.startDate = newDateMoment;
                    $("#departure").data().daterangepicker.endDate = newDateMoment;
                }
            };

            $scope.init = function () {

                $scope.checkExitIntentPopup($scope.anonymUser, $scope.requestArguments.productCode);

                var selectedActivity = $scope.$parent.getPrevActivity();

                selectedActivity = selectedActivity && ((selectedActivity.isHeader && selectedActivity.productType === $scope.requestArguments.productCode) ||
                    !(selectedActivity.isHeader && selectedActivity.code === $scope.requestArguments.productCode)) ? selectedActivity : undefined;
                $scope.requestArguments.travelDate = $scope.requestArguments.isDefaultDate !== "1" || (!selectedActivity || !selectedActivity.startDate) ? $scope.requestArguments.travelDate : $scope.$parent.getProductDate(selectedActivity.startDate);


                if (selectedActivity) {
                    $scope.isChildAvailable = selectedActivity.childRatesAvailable;
                    $scope.isSeniorsAvailable = selectedActivity.seniorRateAvailable;
                    $scope.isStudentsAvailable = selectedActivity.studentRateAvailable;
                    $scope.isInfantsAvailable = selectedActivity.infantRateAvailable;

                    if (selectedActivity.maximumQuantity > 0 && selectedActivity.maximumQuantity < $scope.maxAdultsChildrenTotal) {
                        $scope.maxAdultsChildrenTotal = selectedActivity.maximumQuantity;
                        $scope.availableAdults = strRange(0, $scope.maxAdultsChildrenTotal + 1);
                        if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
                            $scope.selectedAdults = $scope.availableAdults[$scope.availableAdults.length - 1];
                        }
                        $scope.adultsChanged();
                    }
                }


                var principalTokenObj = jwtService.getPrincipalTokenObj();
                if (principalTokenObj
                    && principalTokenObj.maxQuantityOfReservedTimes > 0
                    && principalTokenObj.maxQuantityOfReservedTimes < $scope.maxAdultsChildrenTotal
                    && (principalTokenObj.anonymousTicketRedirectURL || "").toLowerCase().indexOf("/" + ($scope.requestArguments.productCode || "").toLowerCase() + "/") > 0) {
                    $scope.maxAdultsChildrenTotal = parseInt(principalTokenObj.maxQuantityOfReservedTimes);
                    $scope.availableAdults = strRange(0, $scope.maxAdultsChildrenTotal + 1);
                    if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
                        $scope.selectedAdults = $scope.availableAdults[$scope.availableAdults.length - 1];
                    }
                    $scope.adultsChanged();
                } else if (principalTokenObj
                    && principalTokenObj.maxNumberOfAdults > 0) {
                    $scope.maxAdults = parseInt(principalTokenObj.maxNumberOfAdults);
                    if ($scope.maxAdults > $scope.maxAdultsChildrenTotal) {
                        $scope.maxAdultsChildrenTotal = $scope.maxAdults;
                    }

                    $scope.availableAdults = strRange(0, $scope.maxAdultsChildrenTotal + 1);
                    if ($scope.availableAdults.indexOf(String($scope.selectedAdults)) < 0) {
                        $scope.selectedAdults = $scope.availableAdults[$scope.availableAdults.length - 1];
                    }
                    $scope.adultsChanged();
                }

                var currentDate = jwtService.getServerMomentDate();
                var productStartDate = $scope.mainProduct && moment($scope.mainProduct.startDate, "YYYY-MM-DD");

                var selectedDate = productStartDate;
                var minDate = productStartDate;

                if (!selectedDate || !selectedDate.isValid() || selectedDate < currentDate) {
                    selectedDate = currentDate;
                    minDate = currentDate;
                }

                var passedDate = $scope.requestArguments.travelDate
                    &&
                    moment($scope.requestArguments.travelDate, "YYYY-MM-DD");

                if (passedDate && passedDate.isValid() && passedDate >= minDate) {
                    selectedDate = passedDate;
                }

                //var minDate = $scope.requestArguments.travelDate
                //    &&
                //    moment($scope.requestArguments.travelDate, "YYYY-MM-DD") > jwtService.getServerMomentDate()
                //    ? moment($scope.requestArguments.travelDate, "YYYY-MM-DD") : jwtService.getServerMomentDate();

                

                //var minDate = jwtService.getServerMomentDate();//TODO: remove

                if ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) {
                    moment.locale($scope.selectedLanguage.languageCode);
                }

               

                if ($scope.mainProduct && $scope.mainProduct.isDynamicallyPriced) { // TODO: change
                    var isMobile = false; //initiate as false
                    // device detection
                    if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
                        || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0, 4))) {
                        isMobile = true;
                    }

                    var popoverTimeout = null;
                    var inlineDatePickerSettings = {
                        language: 'en',
                        minDate: minDate.toDate(),
                        onSelect: function (formattedDate, date, inst) {
                            //$timeout(function () {
                            $scope.wasSearch = false;
                            //});
                        },
                        onChangeView: function (view, month, year) {
                            if (view == "days") {
                                $scope.loadCalendarPrices(month, year);
                            }
                        },
                        onChangeDecade: function (decade) {
                        },
                        onChangeMonth: function (month, year) {
                            $scope.loadCalendarPrices(month, year);
                        },
                        onChangeYear: function (year) {
                            $scope.loadCalendarPrices(0, year);
                        },
                        onRenderCell: function (date, cellType, isOtherMonthCell) {
                            var currentDate = date.getDate();

                            if (cellType == 'day') {
                                var monthPriceKey = $scope.getDynamicPricesKey(date.getMonth(), date.getFullYear());
                                var monthPrices = $scope.dynamicPrices[monthPriceKey];
                                var dayPrice = !isOtherMonthCell && monthPrices && monthPrices[currentDate]; // don't show prices from other months
                                var priceLabel = ($scope.anonymUser && $scope.anonymUser.labels
                                    && $scope.anonymUser.labels["dynamicPricingCalendarPriceLabel"]) || $scope.labelUtils.getLabel("dynamicPricing.calendarPriceLabel");

                                var closedTooltipHtml = dayPrice && dayPrice.isClosed && dayPrice.closedReason;
                                var closedTooltipClass = "";
                                var closedTooltipAttributes = "";
                                if (closedTooltipHtml) {
                                    closedTooltipClass = "closed-tooltip";
                                    closedTooltipHtml = closedTooltipHtml.replace(/\'/g, '&apos;');

                                    closedTooltipAttributes = 'data-toggle="popover" data-trigger="' + (isMobile ? 'focus' : 'hover focus') + '" data-html="true" data-content="' + closedTooltipHtml + '"';
                                }
                                clearTimeout(popoverTimeout);
                                popoverTimeout = setTimeout(function () {
                                    jQuery('[data-toggle="popover"].closed-tooltip').each(function () {
                                        var $this = $(this);
                                        $this.popover({
                                            container: $this,
                                            delay: { show: isMobile ? 0 : 300, hide: 0 }
                                        });

                                        if ($this.parent().hasClass("-selected-")) {
                                            if (!isMobile) {
                                                setTimeout(function () { $this.popover("show"); }, 50);
                                            } else {
                                                $this.popover("show");
                                            }
                                        }

                                    });//.popover()
                                }, 20);

                                var html = "";
                                if (dayPrice && dayPrice.isClosed) {
                                    html = '<div ' + closedTooltipAttributes + ' class="day-label closed ' + closedTooltipClass + '"><span class="date">' + currentDate + '</span></div>';
                                } else {
                                    html = '<div ' + closedTooltipAttributes + ' class="day-label ' + closedTooltipClass + ' ' + (dayPrice && dayPrice.price ? "has-price" : "") + '"><span class="date">' + currentDate + '</span><span class="from">' + priceLabel + '</span></div>' + (dayPrice && dayPrice.price ? '<div class="from-price"> $' + (dayPrice && dayPrice.price) + '</div>' : '');
                                }
                                return {
                                    disabled: dayPrice && dayPrice.isClosed,
                                    classes: (dayPrice && dayPrice.isClosed ? "closed" : "") + " " + (dayPrice && dayPrice.className),
                                    html: html
                                }
                            }
                        }
                    };

                    if ($scope.updateItem) {
                        inlineDatePickerSettings.selectedDates = [$scope.updateItem.startDateMoment.toDate()];
                    } else {
                        inlineDatePickerSettings.selectedDates = [selectedDate.toDate()];
                    }

                    $scope.inlineDatePicker = $("#inlineDatePicker").datepicker(inlineDatePickerSettings).data('datepicker');


                    if ($scope.updateItem) {
                        $scope.inlineDatePicker.selectDate($scope.updateItem.startDateMoment.toDate());
                        $scope.loadCalendarPrices($scope.updateItem.startDateMoment.month(), $scope.updateItem.startDateMoment.year());
                    }
                    else {
                        // ? $scope.inlineDatePicker.selectDate(selectedDate.toDate());
                        $scope.loadCalendarPrices(selectedDate.month(), selectedDate.year());
                    }
                    //
                } else {
                    var datepickersettings = {
                        singleDatePicker: true,
                        minDate:
                            minDate,//.add("days", 1),
                        showDropdowns: true,
                        locale: {
                            format: shoppingCartService.getDateFormat()
                        },
                        parentEl: "#daterangecontainer"
                    };

                    if ($scope.updateItem) {
                        datepickersettings.minDate = jwtService.getServerMomentDate();
                        datepickersettings.startDate = $scope.updateItem.startDateMoment;
                    } else {
                        datepickersettings.startDate = selectedDate;
                    }

                    $scope.departure = $("#departure").daterangepicker(datepickersettings);

                    $scope.departure.on("apply.daterangepicker", function (ev, picker) {
                        if ($scope.isLoading) return false;
                        $scope.wasSearch = false;
                        $scope.resetSelectedProducts();

                        resizeSliderPanel();

                        $scope.refreshBusStops();
                        // $scope.showNext = $scope.canContinue();
                        // $scope.getTransportations(1);
                        return true;
                    });

                  
                }

               
             

                if ($scope.updateItem) {
                    var firstUpdateComp = $scope.updateItem && $scope.updateItem.BookingToQuote.Components[0];

                    //datepickersettings.minDate = jwtService.getServerMomentDate(); // TODO:
                    //datepickersettings.startDate = $scope.updateItem.startDateMoment; // TODO:

                    $scope.selectedAdults = firstUpdateComp.NumberOfAdults;
                    $scope.selectedChild = firstUpdateComp.NumberOfChildren;

                    $scope.selectedSeniors = firstUpdateComp.NumberOfSeniors;
                    $scope.selectedStudents = firstUpdateComp.NumberOfStudents;
                    $scope.selectedInfants = firstUpdateComp.NumberOfInfants;
                }

               

                //if (!$scope.updateItem) { //TODO
                //    $("#departure").val(minDate.format(shoppingCartService.getDateFormat()));
                //    $("#departure").data().daterangepicker.minDate = minDate;
                //    $("#departure").data().daterangepicker.startDate = minDate;
                //    $("#departure").data().daterangepicker.endDate = minDate;
                //}



               


                //$scope.isLoading = false;
                $scope.initLocations(function () {
                    var firstUpdateComp = $scope.updateItem && $scope.updateItem.BookingToQuote.Components[0];

                    //select default options if single
                    if (($scope.departureLocations || "").length === 1) {
                        $scope.selectedLeavingFromCity = $scope.departureLocations[0];
                        // the event will be triggered automatically by angular component
                        //  $scope.leavingFromCityChanged();
                    } else if (firstUpdateComp) {
                        $scope.selectedLeavingFromCity = _.find(departureLocations, function (loc) {
                            return loc.code == (firstUpdateComp.StartingLocation && firstUpdateComp.StartingLocation.code);
                        });
                        // the event will be triggered automatically by angular component
                        // $scope.selectedLeavingFromCity && $scope.leavingFromCityChanged();                        
                    }

                    if (($scope.destinationLocations || "").length === 1) {
                        $scope.selectedGoingToCity = $scope.destinationLocations[0];
                        // the event will be triggered automatically by angular component
                        // $scope.goingToCityChanged();
                    } else if (firstUpdateComp) {
                        $scope.selectedGoingToCity = _.find(destinationLocations, function (loc) {
                            return loc.code == (firstUpdateComp.Destination && firstUpdateComp.Destination.code);
                        });
                        // the event will be trigger automatically by angular component
                        // $scope.selectedGoingToCity && $scope.goingToCityChanged();
                    }

                });
                //$scope.getTours();

                $scope.lobTitle = $scope.mainProduct && $scope.mainProduct.productDescriptions
                    && (
                        $scope.mainProduct.productDescriptions.genericTitle || ($scope.mainProduct.productDescriptions.titles && $scope.mainProduct.productDescriptions.titles.length > 0 ? $scope.mainProduct.productDescriptions.titles[0] : $scope.mainProduct.name));

                var trackerReq = {
                    lobTitle: $scope.lobTitle,
                    packageName: null,
                    searchDate: null,
                    adults: null,
                    children: null,
                    shoppingCart: $scope.cart,
                    anonymUser: $scope.anonymGeneralUser,
                    bookingNumber: null,
                    bookingId: null
                };
                trackingService.buildFlowTrackerObj(trackerReq); // ($scope.mainProduct && $scope.mainProduct.startDate)

            };

            var initialized = false;
            $scope.anonymUser = undefined;
            $scope.initCurrentAnonymUser = function (callback) {
                //var activitySelectTicketCtrl = $scope.$parent;
                //var activityDetailsCtrl = activitySelectTicketCtrl.$parent;
                //var generalCtrl = activityDetailsCtrl.$parent;

                jwtService.getAnonymousUserByGeography(generalCtrl.selectedGeographyCode, function (user) {
                    $scope.anonymUser = user;
                    callback();
                });
            };

            $scope.$watch(function () {
                return taskFactory.task;
            },
                function (val) {
                    if (!val || !val.name || initialized) return;
                    initialized = true;

                    var initShoppingCart = new Promise(function (resolve, reject) {
                        shoppingCartService.getStorageCart(function (shoppingCart) {
                            if (shoppingCart) {
                                $scope.cart = shoppingCart;

                                $scope.updateItem = undefined;
                                $scope.updateIndex = -1;

                                if (($scope.requestArguments.updateCartItemCode || "").length && $scope.cart && $scope.cart.Items) {
                                    $scope.updateItem = _.find($scope.cart.Items, function (cartItem) {
                                        $scope.updateIndex++;
                                        var relatedComponent = _.find(cartItem.BookingToQuote && cartItem.BookingToQuote.Components, function (comp) {
                                            return comp.ProductCode == $scope.requestArguments.updateCartItemCode;
                                        });
                                        return relatedComponent != null;
                                    });
                                    if ($scope.updateItem) {
                                        $scope.updateItem.startDateMoment = moment($scope.updateItem.BookingToQuote.Components[0].StartDate);
                                    }
                                }
                            }
                            resolve(1);
                        });
                    });
                    initShoppingCart.then(function () {
                        $timeout($scope.initCurrentAnonymUser.bind(null, $scope.init)); //$scope.init);
                    });
                }, true);
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("activityDetailsCtrl", [
        "utilsFactory", "$scope", "$state", "$window", "$element", "$http", "localStorageService", "jwtService", "activitiesService", "$rootScope", "taskFactory", "$timeout",
        function (utilsFactory, $scope, $state, $window, $element, $http, localStorageService, jwtService, activitiesService, $rootScope, taskFactory, $timeout) {

            $.material.init();
            $scope.isLoading = true;
            $scope.showModal = {};

            var timeoutID = undefined;

            function resizeSliderPanel() {
                window.clearTimeout(timeoutID);
                timeoutID = setTimeout(function () {
                    jQuery(window).resize();
                }, 100);
            }
            $rootScope.$on("$stateChangeSuccess",
                function (event, toState, toParams, fromState, fromParams) {
                    resizeSliderPanel();
                });

            $scope.isTour = function () {
                return $scope.requestArguments
                    &&
                    $scope.requestArguments.productCategory
                    &&
                    $scope.requestArguments.productCategory.toLowerCase().indexOf("tour") >= 0;
            };

            $scope.isSpa = function () {
                return $scope.requestArguments
                    &&
                    $scope.requestArguments.productCategory
                    &&
                    (
                        //($scope.actionRegionCode || "").toLowerCase().indexOf("skl") >= 0 ||
                        $scope.requestArguments.productCategory.toLowerCase().indexOf("spa") >= 0
                        ||
                        $scope.requestArguments.productCode.toLowerCase().indexOf("spa") >= 0);
            };

            $scope.requestArguments = {
                activityId: $($element).attr("data-activity-id"),
                productCode: $($element).attr("data-activity-product-code"),
                productCategory: $($element).attr("data-activity-product-category"),
                travelDate: $($element).attr("data-activity-travel-date"),
                isDefaultDate: $($element).attr("data-activity-is-default-date"),
                productcodeswithexpandeddescriptionbydefault: $("div[ng-controller='activityDetailsCtrl']").attr("data-productcodeswithexpandeddescriptionbydefault"),
                defaultselectedadultsbyproductcode: $("div[ng-controller='activityDetailsCtrl']").data("defaultselectedadultsbyproductcode"),
                //expanddescriptionbydefault: ($("div[ng-controller='activityDetailsCtrl']").attr("data-expanddescriptionbydefault") || "").toLowerCase() == 'true',
                updateCartItemCode: $($element).attr("data-activity-updateCartItem"),
                productcodeswithhiddendatepicker: $("div[ng-controller='activityDetailsCtrl']").data("productcodeswithhiddendatepicker"),               
                isUpgrade: ["1", "true"].indexOf(($($element).attr("data-activity-isupgrade") || "").toLowerCase()) >= 0,
                autoSelectUnit: ["1", "true"].indexOf(($($element).attr("data-activity-autoselectunit") || "").toLowerCase()) >= 0,
                fromwebtray: ["1", "true"].indexOf(($($element).attr("data-activity-fromwebtray") || "").toLowerCase()) >= 0,

                showboardingtimeforproductcodes: $("div[ng-controller='activityDetailsCtrl']").data("showboardingtimeforproductcodes"),
                
                rockies2025combosflowpackagecodes: ($("body").attr("data-activity-rockies2025combosflowpackagecodes") || "").split("|"),
                rockiescombosflowpackagecodes: ($("body").attr("data-activity-rockiescombosflowpackagecodes") || "").split("|"),
                rockiesvaluecombosflowpackagecodes: ($("body").attr("data-activity-rockiesvaluecombosflowpackagecodes") || "").split("|"),
                rockieslitecombosflowpackagecodes: ($("body").attr("data-activity-rockieslitecombosflowpackagecodes") || "").split("|")                
            };
            $scope.requestArguments.expanddescriptionbydefault = ($scope.requestArguments.productcodeswithexpandeddescriptionbydefault || []).indexOf($scope.requestArguments.productCode) >= 0;

            $scope.isPackageOnly = ($scope.requestArguments.productCategory || "").toLowerCase() == "package";

            $scope.billingDetails = {};
            // if ($scope.isTour()) {
            //    $state.go("select-ticket.book-adventure", {});
            // } else {

            $state.go("select-ticket.book-adventure", {});

            // }


            $scope.wizardModel = {
                activityId: undefined,
                ticketTypes: undefined,
                ticketType: undefined,
                activity: undefined,
                ticketsCriteria: {
                    date: undefined,
                    time: undefined,
                    adults: undefined,
                    child: undefined,
                    product: undefined,
                    attractionTimes: [],
                    optionalExtras: []
                },
                packagesCriteria: {
                    date: undefined,
                    adults: 2,
                    children: 0,
                    packages: undefined,
                    selectedPackage: undefined
                },
                bookedModalShowed: false
            };

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            $scope.getPrevActivity = function () {
                if (localStorageService.isSupported) {
                    return localStorageService.get("prevActivity");
                }
                return null;
            };

            $scope.getButtonLabel = function (state, singleTicket) {
                return utilsFactory.getLabel("activity.go-back");
                //switch (state) {
                //    case "select-ticket":
                //        return utilsFactory.getLabel("activity.see-all");
                //    case "select-ticket.book-adventure":
                //        return singleTicket ? utilsFactory.getLabel("activity.see-all") : utilsFactory.getLabel("activity.go-back"); //$scope.isTour() ||s
                //    default:
                //        return utilsFactory.getLabel("activity.go-back");
                //};
            };

            $scope.persistWizardModel = function (callback) {
                activitiesService.setActivityWizardModel($scope.wizardModel, callback);
            };

            $scope.back = function (state) {
                activitiesService.setActivityWizardModel($scope.wizardModel, function () { });
                var sectionid = $("[data-sectionid]").data("sectionid") || 0;

                if ($scope.isPackageOnly) {
                    activitiesService.setIsFromActivityDetails(1, function () {
                    });
                    var newUrl = "/" + jwtService.getGeography() + "/activities" + (sectionid ? "/" + sectionid : "");
                    $timeout(function () {
                        $window.location.href = utilsFactory.addPersistentQueryStringsParams(newUrl);
                    });
                    return;
                }



                switch (state) {
                    case "select-ticket.book-adventure":
                    case "select-ticket":

                        activitiesService.setIsFromActivityDetails(1, function () {
                        });
                        window.location.href = utilsFactory.addPersistentQueryStringsParams("/" + jwtService.getGeography() + "/activities" + (sectionid ? "/" + sectionid : ""));
                        break;

                    case "select-ticket.packages":
                        //   if ($scope.isTour()) {
                        //      activitiesService.setIsFromActivityDetails(1, function () {
                        //      });
                        //     window.location.href = "/" + jwtService.getGeography() + "/activities";
                        // } else {
                        $state.go("select-ticket.book-adventure");
                        // }
                        break;
                    case "package-details":
                        $state.go("select-ticket.book-adventure");
                        break;

                };
                $scope.$parent.cleanGlobalErrors();
            };

            $scope.next = function (state, params) {
                activitiesService.setActivityWizardModel($scope.wizardModel, function () { });

                switch (state) {
                    case "select-ticket":
                        if ($scope.wizardModel.ticketType && $scope.wizardModel.ticketType.name) {

                            if ($scope.wizardModel.ticketType.name.toLowerCase().indexOf("package") >= 0) {
                                $state.go("select-ticket.packages");
                            } else {
                                $state.go("select-ticket.book-adventure");
                            }
                        }
                        break;
                    case "select-ticket.book-adventure":
                    case "select-ticket.packages":

                        if (!params) break;

                        $state.go("package-details", params);

                        //$state.go("activity-package-details");
                        break;
                }
                $scope.$parent.cleanGlobalErrors();
            };

            $scope.setTicketType = function (ticketType) {
                $scope.wizardModel.ticketType = ticketType;
            };

            $scope.getTicketTypeByName = function (name) {
                var foundTicketType = undefined;
                angular.forEach($scope.wizardModel.ticketTypes, function (ticketType) {
                    if (ticketType.name === name) {
                        foundTicketType = ticketType;
                    }
                });

                return foundTicketType;
            };


            $scope.getProduct = function () {
                return $scope.wizardModel.ticketsCriteria.product;
            };

            $scope.getOptionalExtras = function () {
                return $scope.wizardModel.ticketsCriteria.optionalExtras;
            };

            $scope.saveSearchCriteria = function (criteria) {
                $scope.wizardModel.ticketsCriteria = criteria;
            };

            $scope.getSearchCriteria = function () {
                return $scope.wizardModel.ticketsCriteria;
            };

            $scope.savePackagesSearchCriteria = function (criteria) {
                $scope.wizardModel.packagesCriteria = criteria;
            };

            $scope.getPackagesSearchCriteria = function () {
                return $scope.wizardModel.packagesCriteria;
            };

            $scope.setSelectedPackage = function (selectedPackage) {
                $scope.wizardModel.packagesCriteria.selectedPackage = selectedPackage;
            };

            $scope.getSelectedPackage = function () {
                return $scope.wizardModel.packagesCriteria.selectedPackage;
            };

            $scope.setBillingDetails = function (detail) {
                $scope.billingDetails = detail;
            };

            $scope.getBillingDetails = function () {
                return $scope.billingDetails;
            };

            $scope.getTicketTypes = function (parentParams, callback) {
                var generalCtrl = $scope.$parent;

                var productCode = $scope.wizardModel.activity.code ? $scope.wizardModel.activity.code : $scope.requestArguments.productCode;
                var productCategory = $scope.wizardModel.activity.productCategory ? $scope.wizardModel.activity.productCategory : $scope.requestArguments.productCategory;;


                var params = {
                    urlPrefix: generalCtrl.getWebUrl(),
                    token: jwtService.getPrincipalToken(),
                    productCode: productCode,
                    productCategory: productCategory,
                    travelDate: parentParams.travelDate
                };

                activitiesService.getTicketTypes(params, function (ticketTypesResult) {
                    if (ticketTypesResult.success) {
                        if (ticketTypesResult.data && ticketTypesResult.data.length > 0) {

                            $scope.wizardModel.ticketTypes = ticketTypesResult.data;
                            $scope.wizardModel.ticketType = $scope.wizardModel.ticketTypes[0];

                            activitiesService.setActivityWizardModel($scope.wizardModel, function () { });
                        }
                    } else {
                        console.log(ticketTypesResult.error);
                    }

                    // $scope.isLoading = false;
                    if (callback)
                        callback();
                });
            };

            $scope.setWizardModel = function (params) {
                var getProduct = activitiesService.getProductDescriptionByCode; //params.isDefaultDate ? activitiesService.getProductDescriptionByCode : activitiesService.getProductWithPackagesByCodeCategoryAndTravelDate;

                getProduct(params, function (getProductResult) {
                    if (getProductResult.success
                        && getProductResult.data
                        && getProductResult.data.products
                        && getProductResult.data.products.length > 0) {

                        if (getProductResult.data.products[0]) {
                            if (getProductResult.data.products[0].productDescriptions && getProductResult.data.products[0].productDescriptions.ibePhoneNumberOverride) {
                                $rootScope.customprodphone = getProductResult.data.products[0].productDescriptions.ibePhoneNumberOverride;
                            }

                            if (!getProductResult.data.products[0].productCategory) {
                                getProductResult.data.products[0].productCategory = $scope.requestArguments.productCategory;
                            }

                            var prodDate = moment(getProductResult.data.products[0].startDate);
                            var passDate = moment(params.travelDate);
                            var setDate = (params.isDefaultDate && prodDate.isValid() ? (prodDate >= passDate ? prodDate : passDate) : passDate);
                            if (setDate < jwtService.getServerMomentDate()) setDate = jwtService.getServerMomentDate();

                            params.travelDate = setDate.format("YYYY-MM-DD");

                            if (!getProductResult.data.products[0].startDate) {
                                getProductResult.data.products[0].startDate = params.travelDate;
                            }
                        }

                        activitiesService.setSelectedActivity(getProductResult.data.products[0], function (setActivityResult) {

                            $scope.wizardModel.activity = getProductResult.data.products[0];

                            //if ($scope.wizardModel.activity.price <= 0 && $scope.wizardModel.activity.units && $scope.wizardModel.activity.units.length > 0) {
                            //    $scope.wizardModel.activity.price = _.min($scope.wizardModel.activity.units, function (unit) {
                            //        return unit.price;
                            //    }).price;
                            //}

                            if (!$scope.wizardModel.ticketsCriteria.product) {
                                $scope.wizardModel.ticketsCriteria.product = $scope.wizardModel.activity;
                            }

                            activitiesService.setActivityWizardModel($scope.wizardModel, function () {
                                if (setActivityResult.success) {

                                    $scope.getTicketTypes(params, function () {
                                        taskFactory.addTask("SelectedActivityChanged", $scope.wizardModel.activity);
                                    });
                                }
                                else {
                                    taskFactory.addTask("SelectedActivityChanged", $scope.wizardModel.activity);
                                }

                                setTimeout(function () { $scope.isLoading = false; });

                            });
                        });
                    } else {
                        activitiesService.removeActivityWizardModel(function () {
                            taskFactory.addTask("SelectedActivityChanged", {});
                            $scope.isLoading = false;
                        });
                    }

                });
            };

            $scope.setTourWizardModel = function (params) {

                function setSelectedTour(prod, callback) {
                    activitiesService.setSelectedActivity(prod, function (setActivityResult) {

                        $scope.wizardModel.activity = prod;

                        if (!$scope.wizardModel.ticketsCriteria.product) {
                            $scope.wizardModel.ticketsCriteria.product = $scope.wizardModel.activity;
                        }

                        activitiesService.setActivityWizardModel($scope.wizardModel, function () {

                            if (setActivityResult.success) {
                                $scope.getTicketTypes(params, function () {
                                    taskFactory.addTask("SelectedActivityChanged", $scope.wizardModel.activity);
                                });
                            } else {
                                taskFactory.addTask("SelectedActivityChanged", $scope.wizardModel.activity);
                            }

                            $timeout(function () {
                                if (callback)
                                    callback();
                            });

                        });

                    });
                }
                var sectionid = $("[data-sectionid]").data("sectionid") || 0;
                if (!sectionid && $scope.isSpa()) {
                    sectionid = "SPA";
                }

                activitiesService.getPersistedActivitiesFilters(sectionid, function (filtersResult) {
                    if (filtersResult.success && filtersResult.data && filtersResult.data.activities) {
                        var activities = filtersResult.data.activities;
                        var prod = _.find(activities, function (a) {
                            return (a.productType || "").trim().toLowerCase()
                                === (params.productType || "").trim().toLowerCase();
                        });

                        if (prod) {
                            setSelectedTour(prod, function () {
                                $scope.isLoading = false;
                            });
                        }
                        else { $scope.isLoading = false; }

                    } else {
                        activitiesService.getActivitiesByDate({
                            token: params.token,
                            id: sectionid,
                            date: params.travelDate,
                            urlPrefix: $scope.getWebUrl()
                        }, function (result) {
                            if (result.success && result.data && result.data.products) {
                                var activities = result.data.products;

                                var prod = _.find(activities, function (a) {
                                    return (a.productType || "").trim().toLowerCase()
                                        === (params.productType || "").trim().toLowerCase();
                                });

                                if (prod) {
                                    setSelectedTour(prod, function () {
                                        $scope.isLoading = false;
                                    });
                                } else {
                                    $scope.isLoading = false;
                                    taskFactory.addTask("SelectedActivityChanged", $scope.wizardModel.activity);
                                }

                            } else {
                                $scope.isLoading = false;
                                taskFactory.addTask("SelectedActivityChanged", $scope.wizardModel.activity);
                                console.log(result.error);
                            }
                        });
                    }
                });

            };
            $scope.setTokenAndWizardModel = function (params) {

                if (!params.token) {
                    jwtService.setPrincipalTokenAsync(params.urlPrefix, $scope.$parent.trackingInfo, function (newToken) {
                        params.token = newToken;
                        if ($scope.isTour() || $scope.isSpa()) {
                            $scope.setTourWizardModel(params);
                        } else {
                            $scope.setWizardModel(params);
                        }
                    });
                } else {
                    if ($scope.isTour() || $scope.isSpa()) {
                        $scope.setTourWizardModel(params);
                    } else {
                        $scope.setWizardModel(params);
                    }

                }
            };

            $scope.getProductDate = function (date) {
                return !date ? date : (date.toLowerCase().indexOf("t") > 0 ? date.substring(0, date.toLowerCase().indexOf("t")) : date);
            };

            $scope.init = function () {
                $scope.isLoading = true;
                activitiesService.getActivityWizardModel(function (result) {
                    var selectedActivity = $scope.getPrevActivity();

                    selectedActivity = selectedActivity && ((selectedActivity.isHeader && selectedActivity.productType === $scope.requestArguments.productCode) ||
                        !(selectedActivity.isHeader && selectedActivity.code === $scope.requestArguments.productCode)) ? selectedActivity : undefined;
                    $scope.requestArguments.travelDate = $scope.requestArguments.isDefaultDate !== "1" || (!selectedActivity || !selectedActivity.startDate) ? $scope.requestArguments.travelDate : $scope.getProductDate(selectedActivity.startDate);
                    if (jwtService.getServerMomentDate() > moment($scope.requestArguments.travelDate)) {
                        $scope.requestArguments.travelDate = (!selectedActivity || !selectedActivity.startDate) ? jwtService.getServerStrDate() : $scope.getProductDate(selectedActivity.startDate);
                    }

                    var params = {
                        urlPrefix: $scope.$parent.getWebUrl(),
                        token: undefined,
                        productCode: $scope.requestArguments.productCode,
                        productCategory: $scope.requestArguments.productCategory,
                        travelDate: $scope.requestArguments.travelDate,
                        isDefaultDate: $scope.requestArguments.isDefaultDate === "1"
                    };

                    if ($scope.isTour() || $scope.isSpa()) {
                        params.productCode = "";
                        params.productType = $scope.requestArguments.productCode;
                    }
                    var token = jwtService.getPrincipalToken();

                    params.token = token;

                    //check the date
                    var modelStartDate = (result.data && result.data.activity) ? $scope.getProductDate(result.data.activity.startDate) : undefined;
                    var sameDate = modelStartDate && $scope.getProductDate($scope.requestArguments.travelDate) === modelStartDate;

                    if (!sameDate || !result.data || !result.data.activity) {
                        activitiesService.removeActivityWizardModel(function () { });
                        $scope.setTokenAndWizardModel(params);
                    } else if (result.data && ($scope.isTour() || $scope.isSpa() ? result.data.activity.productType : result.data.activity.code) !== $scope.requestArguments.productCode) {
                        activitiesService.removeActivityWizardModel(function () { });
                        $scope.setTokenAndWizardModel(params);
                    } else {
                        $scope.wizardModel = result.data;

                        if ($scope.wizardModel.activity.productDescriptions && $scope.wizardModel.activity.productDescriptions.ibePhoneNumberOverride) {
                            $rootScope.customprodphone = $scope.wizardModel.activity.productDescriptions.ibePhoneNumberOverride;
                        }

                        activitiesService.setSelectedActivity($scope.wizardModel.activity, function (setActivityResult) {
                            taskFactory.addTask("SelectedActivityChanged", $scope.wizardModel.activity);
                        });

                        $scope.isLoading = false;
                    }



                });
            };

            $rootScope.$broadcast("activityDetailsCtrlInitialized");

            $scope.$on("generalControllerInitilized", function (event, data) {
                var t = jwtService.getPrincipalToken();

                if (t && t.length > 0) {
                    $scope.init();
                } else {
                    $scope.isLoading = true;
                    $scope.$on("getPrincipalToken", function (event, args) {
                        $scope.init();
                    });
                };
            });

            $scope.$on("ActivityWizardModelChanged", function (event, data) {
                $scope.wizardModel = data.wizardModel;

                if (data.callback) {
                    data.callback();
                }
            });
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("activitySelectTicketCtrl", [
        "utilsFactory", "activitiesService", "$scope", "$state", "taskFactory", "$rootScope", function (utilsFactory, activitiesService, $scope, $state, taskFactory, $rootScope) {

            $scope.showNext = false;
            $.material.init();

            $scope.mainProduct = {};
            $scope.utils = utilsFactory;
            $scope.loadingTickets = true;
            $scope.requestArguments = {
                productCategory: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-product-category"),
                travelDate: $("div[ng-controller='activityDetailsCtrl']").attr("data-activity-travel-date"),                 
                setdynamicpricingforproducttypes: $("div[ng-controller='activityDetailsCtrl']").data("setdynamicpricingforproducttypes")                
            };
            $scope.hideTooltips = function () {
                jQuery("[data-toggle=\"tooltip\"]").tooltip("hide");
            };
            $scope.isTour = function () {
                return $scope.requestArguments
                    &&
                    $scope.requestArguments.productCategory
                    &&
                    $scope.requestArguments.productCategory.toLowerCase().indexOf("tour") >= 0;
            };

            $scope.ticketTypes = function () {
                if ($scope.$parent) {
                    return $scope.$parent.wizardModel.ticketTypes;
                } else {
                    return [];
                }
            };

            $scope.getTicketTypeIfOne = function () {
                var ticketTypes = $scope.ticketTypes();
                return ((ticketTypes || "").length === 1) ? ticketTypes[0] : undefined;
            };

            $scope.changeSelectedTicket = function (ticketTypeName) {
                $scope.hideTooltips();
                $scope.showNext = true;
                $scope.selectedTicketTypeName = ticketTypeName;
                $scope.handleNext();
            };


            $scope.getBackButtonLabel = function () {
                var cuurentStateName = $state.$current.name;
                return $scope.$parent.getButtonLabel(cuurentStateName, $scope.getTicketTypeIfOne());
            };

            $scope.backButtonLabel = $scope.getBackButtonLabel();

            $scope.handleBack = function (e) {
              
                var singleTicketType = $scope.getTicketTypeIfOne();
                if (singleTicketType) {
                    $scope.$parent.back("select-ticket");
                } else {
                    if ($scope.$parent) {
                        var cuurentStateName = $state.$current.name;
                        $scope.$parent.back(cuurentStateName);
                    }
                }
            };

            $scope.handleNext = function () {
                if ($scope.$parent) {
                    var getTicket = $scope.$parent.getTicketTypeByName($scope.selectedTicketTypeName);

                    if (getTicket) {
                        $scope.$parent.setTicketType(getTicket);
                    }
                    var cuurentStateName = $state.$current.name;
                    $scope.$parent.next(cuurentStateName);

                    $scope.backButtonLabel = $scope.getBackButtonLabel();
                }
            };

            $scope.goNextIfOneSelectTickets = function (stateName, fromstateName) {           
                if (!stateName) stateName = $state.$current.name;

                if (stateName === "select-ticket") {

                    var ticketType = $scope.getTicketTypeIfOne();
                    if (ticketType) {
                        $scope.changeSelectedTicket(ticketType.name);
                        $scope.handleNext();
                    }


                }
            };

            $rootScope.$on("$stateChangeSuccess",
               function (event, toState, toParams, fromState, fromParams) {
                   $scope.backButtonLabel = $scope.$parent.getButtonLabel(toState.name);
               
                   if ($scope.getTicketTypeIfOne()&&toState === "select-ticket" && fromstateName == "select-ticket.book-adventure") {
                       $scope.handleBack();
                   }
                   else {
                       $scope.goNextIfOneSelectTickets(toState.name, fromState.name);
                   }
               });


            $scope.$watch(function () {
                return taskFactory.task;
            },
                function (val) {
                    if (!val || !val.name) return;

                    $scope.init();
                }, true);

            $scope.selectedTicketTypeName = $scope.$parent && $scope.$parent.wizardModel.ticketType ? $scope.$parent.wizardModel.ticketType.name : undefined;
            $scope.showNext = ($scope.selectedTicketTypeName || "").length;
            $scope.isLoading = true;
            $scope.init = function () {
                $scope.loadingTickets = false;

                $scope.goNextIfOneSelectTickets();
                activitiesService.getSelectedActivity(function (result) {
                    if (result.success && result.data) {
                        $scope.mainProduct = result.data;
                        if ($scope.mainProduct && !$scope.mainProduct.isDynamicallyPriced && $scope.mainProduct.productType && $scope.requestArguments.setdynamicpricingforproducttypes) {
                            $scope.mainProduct.isDynamicallyPriced = ($scope.requestArguments.setdynamicpricingforproducttypes || "").indexOf($scope.mainProduct.productType) >= 0;
                        }

                        $scope.isLoading = false;
                        setTimeout(function () {
                            jQuery(window).resize();
                        }, 0);
                    }
                    else
                        $scope.isLoading = false;
                });
            };
            // $scope.init();
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";


    angular.module("app").controller("packageActivityBookAdventureCtrl", [
        "$scope", "$state", "$http", "$uibModal", "productsFactory", "activitiesService", "$rootScope", "validHelper", "shoppingCartService", "jwtService", "taskFactory", "$timeout",
        function ($scope, $state, $http, $uibModal, productsFactory, activitiesService, $rootScope, validHelper, shoppingCartService, jwtService, taskFactory, $timeout) {

            var webUrl = $("body").data("weburl") ? $("body").data("weburl") : "";
            $.material.init();

            $scope.validHelper = validHelper;
            $scope.isLoading = true;

            $scope.daterangepicker = $("#daterange").daterangepicker({
                singleDatePicker: true,
                minDate: moment(),//.add("days", 1),
                showDropdowns: true,
                locale: {
                    format: shoppingCartService.getDateFormat()
                }
            });

            $scope.selectedAdults = "1";
            $scope.selectedChild = "0";

            $scope.noTime = { key: "Any Time", value: null };
            $scope.attractionTimes = [];
            $scope.optionalExtras = [];
            $scope.selectedTime = $scope.noTime;
            $scope.availableAdults = ["1", "2", "3", "4", "5"];
            $scope.availableChild = ["0", "1", "2", "3", "4", "5"];

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            //get rangeid: 1-adult(16-100)2-child(6-15)
            function isInRange(str, rangeA, rangeB) {
                if (!str) return true;
                var rangeStr = str.replace(/ /g, "").split("-");
                if (rangeStr.length !== 2) return false;
                return (rangeA >= parseInt(rangeStr[0]) && rangeB <= parseInt(rangeStr[1]));
            }

            $scope.getPrices = function (travelDate, units, index) {
                $scope.isLoading = true;
                var ticket = units[index];
                if ($scope.product == null) return;
                var productCode = $scope.product.code;
                var productCategory = $scope.product.productCategory;
                var productType = $scope.product.productType;
                var unitCode = ticket.unitCode;

                productsFactory.getPrices(jwtService.getPrincipalToken(), productCode, productCategory, productType, unitCode, travelDate).then(
                    function (result) {
                        var prices = result.data.prices;

                        $.each(prices, function (key, value) {
                            if (isInRange(value.ageRange, 6, 15)) {
                                ticket.childPrice = value.amount;
                            } else if (isInRange(value.ageRange, 16, 100)) {
                                ticket.price = value.amount;
                            }
                        });

                        if (index === units.length - 1) {
                            $scope.persistCriteria();
                            $scope.isLoading = false;
                            setTimeout(function () {
                                jQuery(window).resize();
                            });
                        } else {
                            $scope.getPrices(travelDate, units, index + 1);
                        }

                    },
                    function (response) {
                        $scope.isLoading = false;
                        console.log(response);
                    }
                );
            };

            $scope.getProductTimes = function (travelDate, callback) {
                $scope.isLoading = true;

                $scope.attractionTimes = [];
                $scope.selectedTime = $scope.noTime;

                $http({
                    method: "GET",
                    url: webUrl + "/api/product/relatedservices/" + $stateParams.packageProductCode + "/" + travelDate,
                    headers: { "Authorization": jwtService.getPrincipalToken() }
                }).then(
                    function (result) {
                        var products = result.data.attractionTimes;
                        if (products.length === 0) {
                            $scope.isLoading = false;
                            if (callback) {
                                callback();
                            }
                            return;
                        }

                        $.each(products, function (key, value) {
                            value.availableHours = [$scope.noTime];
                            var newVal = jQuery.extend(true, {}, value); //prevent json circular parsing error
                            $.each(value.units, function (key1, value1) {
                                value1.product = newVal;
                                value.availableHours.push({ key: moment(value1.startTime).format("hh:mm A"), value: value1 });
                            });
                            $scope.attractionTimes.push(value);
                        });

                        $scope.optionalExtras = result.data.optionalExtras;
                        $scope.isLoading = false;
                        if (callback) {
                            callback();
                        }
                    },
                    function (response) {
                        $scope.isLoading = false;
                        $scope.attractionTimes = [];
                        $scope.optionalExtras = [];
                        if (callback) {
                            callback();
                        }
                        console.log(response);
                    }
                );
            };

            $scope.getAvailableHours = function () {
                if ($scope.attractionTimes.length > 0) {
                    return $scope.attractionTimes[0].availableHours;
                }
                return [$scope.noTime];
            };

            $scope.timeChanged = function (hour) {
                $scope.selectedTime = hour;
            };

            //$scope.adultsChanged = function (adults) {
            //    $scope.selectedAdults = adults;
            //    $scope.persistCriteria();
            //};

            //$scope.childChanged = function (child) {
            //    $scope.selectedChild = child;
            //    $scope.persistCriteria();
            //};

            $scope.selectUnit = function (selectedUnit) {
                $scope.product.selectedUnit = selectedUnit;
                $scope.product.displayTypeId = 1;
                $scope.product.attractionTimes = $scope.attractionTimes;
                if ($scope.selectedTime && $scope.selectedTime.value) {
                    $scope.product.selectedTime = $scope.selectedTime;
                }

                //else {
                //TODO: Redirect to package
                //  }

                $scope.$parent.updateSelectedPackage($scope.criteria.selectedPackage);
                $scope.$parent.nextWizard($stateParams.packageProductCode.toLowerCase().trim());

            };


            $scope.init = function () {
                $scope.isLoading = false;
                $scope.criteria = $scope.$parent.getCriteria();

                var date = undefined;

                if ($stateParams.date) {
                    date = moment($stateParams.date, "YYYY-MM-DD").format(shoppingCartService.getDateFormat());
                    $("#daterange").val(date);
                    $("#daterange").data().daterangepicker.startDate = moment(date, $("#daterange").data().daterangepicker.format);
                    $("#daterange").data().daterangepicker.endDate = moment(date, $("#daterange").data().daterangepicker.format);
                }

                if ($scope.criteria && $scope.criteria.selectedPackage) {
                    for (var i = 0; i < $scope.criteria.selectedPackage.details.components.length; i++) {
                        var comp = $scope.criteria.selectedPackage.details.components[i];
                        if (comp && comp.product && comp.product.code.toLowerCase().trim() === $stateParams.packageProductCode.toLowerCase().trim()) {
                            $scope.product = comp.product;
                            $scope.comp = comp;
                            break;
                        }
                    }
                }
                if ($scope.product.selectedTime) {
                    $scope.selectedTime = $scope.product.selectedTime;
                }

                if ($scope.product.attractionTimes) {
                    $scope.attractionTimes = $scope.product.attractionTimes;
                }

                if ($scope.criteria.adults) {
                    $scope.selectedAdults = $scope.criteria.adults;
                }

                if ($scope.criteria.children) {
                    $scope.selectedChild = $scope.criteria.children;
                }

                if (!$scope.product.attractionTimes) {
                    $scope.getProductTimes($stateParams.date, function () {
                        $scope.product.attractionTimes = $scope.attractionTimes;
                    });
                }
            };

            var initialized = false;

            $scope.$watch(function () {
                return taskFactory.packageTask;
            },
                function (val) {
                    if (!val || !val.name || initialized) return;
                    initialized = true;
                    $timeout($scope.init);
                }, true);

            //var t = jwtService.getPrincipalToken();

            //if (t && t.length > 0) {
            //    $scope.init();
            //} else {
            //    $scope.isLoading = true;
            //    $scope.$on("getPrincipalToken", function(event, args) {
            //        $scope.init();
            //    });
            //};


        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("barcodeCtrl", [
        "utilsFactory", "$scope", "$state", "shoppingCartService", "jwtService", "$timeout",
        function (utilsFactory, $scope, $state, shoppingCartService, jwtService, $timeout) {

            var webUrl = ($("body").data("weburl") ? $("body").data("weburl") : "");
            $scope.labelUtils = utilsFactory;

            $.material.init();

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            $scope.shouldShowComponent = function (comp) {
                return comp && comp.ProductType != 'PKG-HDR';
            };

            $scope.utils = shoppingCartService.utils;
            $scope.dateFormat = shoppingCartService.getDateFormat();

            $scope.model = {
                barcode: undefined,
                barcodes: []
            };
            $scope.errors = [];

            $scope.onBarcodeChange = function () {
                $scope.showBarcodeError && ($scope.showBarcodeError = false);
                $scope.showAddAnotherBarcode = ($scope.model.barcode || "").toString().trim().length > 0;
            };

            $scope.removeBarcode = function (index) {
                $scope.showBarcodeError = false;
                if (index >= ($scope.model.barcodes || '').length || index < 0) return;

                $scope.model.barcodes = _.reject($scope.model.barcodes, function (item, itemIndex) {
                    return itemIndex === index;
                });
            };

            $scope.enterBarcode = function () {
                $scope.showBarcodeError = false;
                if (($scope.model.barcode || "").toString().trim().length == 0) return;

                $scope.model.barcodes.push(($scope.model.barcode || "").toString().trim());
                $scope.model.barcode = "";
                $scope.onBarcodeChange();

                $timeout(function () {
                    jQuery("#barcode").change();
                });
            };

            $scope.applyBarcode = function () {
                if (!($scope.model.barcodes || '').length && !($scope.model.barcode || '').length) {
                    return;
                }

                $scope.isLoading = true;
                $scope.showBarcodeError = false;
                jwtService.setAnonymousTicketHolder({
                    urlPrefix: webUrl,
                    accessCodes: ($scope.model.barcodes || '').length ? $scope.model.barcodes : [$scope.model.barcode],
                    token: jwtService.getPrincipalToken(),
                }, function (result) {
                    $scope.isLoading = false;

                    if ((result && result.success && result.data) && !(result.data.errors || "").length && result.data.anonymousTicketRedirectURL) {                       
                        if (result.data.token) {
                            var tokenObj = {
                                "token": result.data.token,
                                "currency": jwtService.getCurrency(),
                                "maxQuantityOfReservedTimes": result.data.maxQuantityOfReservedTimes,
                                "anonymousTicketRedirectURL": result.data.anonymousTicketRedirectURL,
                                "expire": null
                            };

                            var customertoken = jwtService.getCustomerToken();
                            if (customertoken) {
                                tokenObj.loginType = customertoken.loginType;
                                jwtService.setCustomerToken(tokenObj);
                            } else {
                                jwtService.setToken(tokenObj);
                            }
                        }
                        window.location.href = utilsFactory.addPersistentQueryStringsParams(result.data.anonymousTicketRedirectURL);
                    } else {
                        $scope.errors = result.error && result.error.errors;
                        $scope.showBarcodeError = true;
                    }
                    console.log(result);
                });
            };


            $scope.init = function () {

            };


            $scope.preinit = function () {
                jwtService.getAnonymousUserByGeography($scope.$parent.selectedGeographyCode, function (user) {
                    $scope.anonymUser = user;
                    if ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) {
                        moment.locale($scope.selectedLanguage.languageCode);
                    }
                    $scope.init();
                });
            };

            // var t = jwtService.getPrincipalToken();
            var isGeneralCtrlReady = $scope.$parent.generalCtrlReady;
            if (isGeneralCtrlReady) {
                $scope.preinit();
            } else {
                $scope.isLoading = true;
                $scope.$on('generalCtrlReady', function (event, args) {
                    $scope.isLoading = false;
                    $scope.preinit();
                });
            };
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("bookingUpdateMsgCtrl", [
        "$scope", "$uibModalInstance", "utilsFactory", function ($scope, $uibModalInstance, utilsFactory) {
            $scope.labelUtils = utilsFactory;

            $scope.continue = function () {
                $uibModalInstance.close();
            };
        }
    ]);

    angular.module("app").controller("exitIntentPopupCtrl", [
        "$scope", "$uibModalInstance", "utilsFactory", "popupData", function ($scope, $uibModalInstance, utilsFactory, popupData) {
            $scope.labelUtils = utilsFactory;
            $scope.htmlContent = popupData.popupContent;

            $scope.continue = function () {

                $uibModalInstance.close();
            };
        }
    ]);

    angular.module("app").controller("addAddOnToCartModalCtrl", [
        "$scope", "$uibModalInstance", "utilsFactory", "productsFactory", "shoppingCartService", "$timeout", "jwtService", "product", "cart", "anonymUser",
        function ($scope, $uibModalInstance, utilsFactory, productsFactory, shoppingCartService, $timeout, jwtService, product, cart, anonymUser) {

            $scope.utils = utilsFactory;
            $scope.opItem = product;
            $scope.cart = cart;


            $scope.getAgeRangeInfo = function (secondaryLabel) {
                if (!$scope.anonymUser) return undefined;
                var selectedLanguage = $scope.anonymUser.selectedLanguage;
                return $scope.utils.getAnonymUserLabel((selectedLanguage && selectedLanguage.userlabels) || anonymUser, "ageRangesInfo", secondaryLabel);
            };

            function strRange(min, max) {
                function toString(val) {
                    return val.toString();
                }

                return (_.range(min, max));//_.map(_.range(min, max), toString);
            }

            $scope.maxAdultsChildrenTotal = $("body").attr("data-max-activity-available-adults-child-total") ? parseInt($("body").attr("data-max-activity-available-adults-child-total")) : 5;
            $scope.maxAdults = $("body").attr("data-max-attractions-available-adults") ? parseInt($("body").attr("data-max-attractions-available-adults")) : 5;
            $scope.maxChildren = $("body").attr("data-max-attractions-available-children") ? parseInt($("body").attr("data-max-attractions-available-children")) : 5;

            $scope.maxSeniors = $("body").attr("data-max-activity-seniors") ? parseInt($("body").attr("data-max-activity-seniors")) : 5;
            $scope.maxStudents = $("body").attr("data-max-activity-students") ? parseInt($("body").attr("data-max-activity-students")) : 5;

            $scope.isChildAvailable = $scope.opItem.product.childRatesAvailable;
            $scope.isSeniorsAvailable = $scope.opItem.product.seniorRateAvailable;
            $scope.isStudentsAvailable = $scope.opItem.product.studentRateAvailable;
            $scope.isInfantsAvailable = $scope.opItem.product.infantRateAvailable;

            $scope.selectedAdults = 2;
            $scope.selectedChild = 0;

            $scope.selectedSeniors = 0;
            $scope.selectedStudents = 0;
            $scope.selectedInfants = 0;

            $scope.availableAdults = strRange(0, $scope.maxAdultsChildrenTotal + 1);
            $scope.availableChild = strRange(0, ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors) -
                parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

            $scope.availableSeniors = strRange(0, ($scope.maxAdultsChildrenTotal -
                parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) -
                parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

            $scope.availableStudents = strRange(0, ($scope.maxAdultsChildrenTotal -
                parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) -
                parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);
            $scope.availableInfants = strRange(0, ($scope.maxAdultsChildrenTotal -
                parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) -
                parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

            $scope.adultsChanged = function () {
                $scope.wasSearch = false;
                $scope.availableChild = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors)
                        - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableChild.indexOf(($scope.selectedChild)) < 0) {
                    $scope.selectedChild = $scope.availableChild[0];
                }
                $scope.availableSeniors = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableSeniors.indexOf(($scope.selectedSeniors)) < 0) {
                    $scope.selectedSeniors = $scope.availableSeniors[0];
                }

                $scope.availableStudents = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableStudents.indexOf(($scope.selectedStudents)) < 0) {
                    $scope.selectedStudents = $scope.availableStudents[0];
                }

                $scope.availableInfants = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

                if ($scope.availableInfants.indexOf(($scope.selectedInfants)) < 0) {
                    $scope.selectedInfants = $scope.availableInfants[0];
                }
            };

            $scope.childChanged = function () {
                $scope.wasSearch = false;
                $scope.availableAdults = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);
                if ($scope.availableAdults.indexOf($scope.selectedAdults) < 0) {
                    $scope.selectedAdults = $scope.availableAdults[0];
                }

                $scope.availableSeniors = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableSeniors.indexOf(($scope.selectedSeniors)) < 0) {
                    $scope.selectedSeniors = $scope.availableSeniors[0];
                }

                $scope.availableStudents = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableStudents.indexOf(($scope.selectedStudents)) < 0) {
                    $scope.selectedStudents = $scope.availableStudents[0];
                }

                $scope.availableInfants = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

                if ($scope.availableInfants.indexOf(($scope.selectedInfants)) < 0) {
                    $scope.selectedInfants = $scope.availableInfants[0];
                }


            };

            $scope.seniorChanged = function () {
                $scope.wasSearch = false;
                //selectedSeniors
                //availableSeniors

                $scope.availableAdults = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);
                if ($scope.availableAdults.indexOf(($scope.selectedAdults)) < 0) {
                    $scope.selectedAdults = $scope.availableAdults[0];
                }
                $scope.availableChild = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableChild.indexOf(($scope.selectedChild)) < 0) {
                    $scope.selectedChild = $scope.availableChild[0];
                }
                $scope.availableStudents = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableStudents.indexOf(($scope.selectedStudents)) < 0) {
                    $scope.selectedStudents = $scope.availableStudents[0];
                }

                $scope.availableInfants = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

                if ($scope.availableInfants.indexOf(($scope.selectedInfants)) < 0) {
                    $scope.selectedInfants = $scope.availableInfants[0];
                }

            };

            $scope.studentChanged = function () {
                $scope.wasSearch = false;
                $scope.availableAdults = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);
                if ($scope.availableAdults.indexOf(($scope.selectedAdults)) < 0) {
                    $scope.selectedAdults = $scope.availableAdults[0];
                }
                $scope.availableChild = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableChild.indexOf(($scope.selectedChild)) < 0) {
                    $scope.selectedChild = $scope.availableChild[0];
                }
                $scope.availableSeniors = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableSeniors.indexOf(($scope.selectedSeniors)) < 0) {
                    $scope.selectedSeniors = $scope.availableSeniors[0];
                }

                $scope.availableInfants = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents)) + 1);

                if ($scope.availableInfants.indexOf(($scope.selectedInfants)) < 0) {
                    $scope.selectedInfants = $scope.availableInfants[0];
                }
            };

            $scope.infantChanged = function () {
                $scope.wasSearch = false;
                $scope.availableAdults = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);
                if ($scope.availableAdults.indexOf(($scope.selectedAdults)) < 0) {
                    $scope.selectedAdults = $scope.availableAdults[0];
                }
                $scope.availableChild = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableChild.indexOf(($scope.selectedChild)) < 0) {
                    $scope.selectedChild = $scope.availableChild[0];
                }
                $scope.availableSeniors = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedStudents) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableSeniors.indexOf(($scope.selectedSeniors)) < 0) {
                    $scope.selectedSeniors = $scope.availableSeniors[0];
                }

                $scope.availableStudents = strRange(0,
                    ($scope.maxAdultsChildrenTotal - parseInt($scope.selectedAdults) - parseInt($scope.selectedChild) - parseInt($scope.selectedSeniors) - parseInt($scope.selectedInfants)) + 1);

                if ($scope.availableStudents.indexOf(($scope.selectedStudents)) < 0) {
                    $scope.selectedStudents = $scope.availableStudents[0];
                }

            };

            $scope.daterangepicker = undefined;

            $scope.fillProductDetailsRecursive = function (parentProduct, products, index, callback) {
                if (index === products.length || !products[index]) {
                    callback();
                    return;
                }
                var params = {
                    token: jwtService.getPrincipalToken(),
                    productCode: products[index].productCode,
                    productCategory: products[index].productCategory,
                    travelDate: moment(products[index].startDate).format("YYYY-MM-DD")
                };
                productsFactory.getProductWithHiddenUnitsWithCallback(params, function (result) {
                    if (result && result.success && (result.data || "").length) {
                        products[index].product = result.data[0];
                        products[index].product.selectedUnit = _.find(products[index].product.units, function (u) {
                            return products[index].unitCode === u.unitCode;
                        });
                        if (!parentProduct.requiredProducts) {
                            parentProduct.requiredProducts = [];
                        }
                        parentProduct.requiredProducts.push(products[index]);
                    }
                    $scope.fillProductDetailsRecursive(parentProduct, products, index + 1, callback);
                });
            };

            $scope.loadrelatedservices = function (callback) {
                var productQueries = [];
                productQueries.push({
                    ProductCode: $scope.opItem.productCode,
                    TravelDate:
                        $("#addondaterangemodal").data() && $("#addondaterangemodal").data().daterangepicker
                            ? $("#addondaterangemodal").data().daterangepicker.startDate.format("YYYY-MM-DD") : $scope.opItem.startDate,
                    UnitCode: Array.isArray($scope.opItem.unitCode) ? $scope.opItem.unitCode[0] : $scope.opItem.unitCode
                });

                var dataToPost = { ProductQueries: productQueries };
                var relatedServicesRequestParams = {
                    token: jwtService.getPrincipalToken(),
                    data: dataToPost
                };

                productsFactory.getRelatedServicesMulti(relatedServicesRequestParams, function (relatedProducts) {
                    //  $scope.opItem.relatedProducts=relatedProducts && (relatedProducts.data || "").length;
                    if (relatedProducts && (relatedProducts.data || "").length && (relatedProducts.data[0].requiredProducts || "").length) {
                        //get product details for each additional required product

                        $scope.fillProductDetailsRecursive($scope.opItem.product, relatedProducts.data[0].requiredProducts, 0, function () {
                            callback();
                        });
                    } else {
                        //call the callback
                        callback();
                    }
                });
            };


            $scope.initOp = function () {
                $timeout(function () {
                    if ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) {
                        moment.locale($scope.selectedLanguage.languageCode);
                    }

                    var startDate = moment($scope.opItem.startDate);
                    var endDate = moment($scope.opItem.endDate);
                    if (!startDate.isSame(endDate)) {
                        var datepickersettings = {
                            singleDatePicker: true,
                            minDate: moment($scope.opItem.startDate),
                            maxDate: moment($scope.opItem.endDate),
                            showDropdowns: true,
                            locale: {
                                format: shoppingCartService.getDateFormat()
                            }
                        };
                        //if ($scope.selectedLanguage && $scope.selectedLanguage.calendar) {
                        //    datepickersettings.locale.daysOfWeek = $scope.selectedLanguage.calendar.daysOfWeek;
                        //    datepickersettings.locale.monthNames = $scope.selectedLanguage.calendar.monthNames;
                        //    datepickersettings.locale.firstday = $scope.selectedLanguage.calendar.firstDay;
                        //}
                        $scope.daterangepicker = $("#addondaterangemodal").daterangepicker(datepickersettings);
                    } else {
                        $("#addondaterangemodal").parent().hide();
                    }
                });

            };

            // init 
            $scope.initCurrentAnonymUser = function (callback) {
                $scope.selectedGeographyCode = jwtService.getGeography();
                jwtService.getAnonymousUserByGeography($scope.selectedGeographyCode, function (user) {

                    $scope.anonymUser = user;
                    $scope.selectedLanguage = _.find($scope.anonymUser.languages, function (lang) {
                        return lang.geographyCode == $scope.selectedGeographyCode;
                    });
                    $scope.setGiftCardVisibility();
                    callback();
                });
            };

            // entrypoint
            $scope.initCurrentAnonymUser($scope.initOp.bind(null));


            // $scope.initCurrentAnonymUser();
            // /init  

            $scope.continue = function () {
                $scope.isLoading = true;

                $scope.loadrelatedservices(function () {
                    var oc = $scope.opItem;
                    var product = oc.product;
                    if (!product) return;
                    var cartItem = _.find($scope.cart.Items, function (it) {
                        return (it.ProductCode || "").toLowerCase() === (oc.relatedProductCode || "").toLowerCase() && it.BookingToQuote && (it.BookingToQuote.Components || "").length;
                    });

                    if (!cartItem) return;
                    var productStartDate = $scope.daterangepicker ? $("#addondaterangemodal").data().daterangepicker.startDate.format("YYYY-MM-DD") : cartItem.StartDate;

                    //var date = moment(product.startDate);
                    //var dateStr = "";
                    //if (date.isValid()) {
                    //    dateStr = date.format("YYYY-MM-DD");
                    //}

                    //if (product.productCategory === "Attraction") {
                    //    window.location.href = "/activities/details/" + product.code + "/Attraction/" + (oc.date || dateStr) + "/" + (oc.unitCode || "") + "/#/select-ticket/book-adventure";
                    //    return;
                    //} else if (product.productCategory === "Tour") {
                    //    window.location.href = "/activities/details/" + product.productType + "/Tour/" + (oc.date || dateStr) + "/" + (oc.unitCode || "") + "/#/select-ticket/book-adventure";
                    //    return;
                    //} else if (product.productCategory === "Transportation") {
                    //    window.location.href = "/transportation/details/" + product.productType + "/Transportation/" + (oc.date || dateStr) + "/" + (oc.unitCode || "") + "/#/select-transportation-ticket/book-transportation-adventure";
                    //    return;
                    //}


                    //  $scope.cart.optionalExtras=   _.reject($scope.cart.optionalExtras, function (it) { return it. % 2 == 0; });
                    //delete optional item from list
                    var components = [];
                    var bookingComponent = {
                        "Id": oc.productCode + (oc.unit || product.units[0]).unitCode,
                        "ProductCategory": product.productCategory,
                        "ProductType": product.productType,
                        "ProductCode": product.code,
                        "StartDate": productStartDate,
                        "EndDate": productStartDate,
                        "Name": product.name,
                        "Description": product.description,
                        "Price": product.price,
                        "ChildPrice": product.price,
                        "NumberOfAdults": $scope.selectedAdults,
                        "NumberOfChildren": $scope.selectedChild,
                        "NumberOfInfants": $scope.selectedInfants,
                        "NumberOfSeniors": $scope.selectedSeniors,
                        "NumberOfStudents": $scope.selectedStudents,
                        "Status": "New",
                        "UnitCode": (oc.unit || product.units[0]).unitCode,
                        "UnitDescription": (oc.unit || product.units[0]).description,
                        "PickupLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                        "DropoffLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                        "StartingLocation": product.startingLocation,
                        "Destination": product.destination,
                        "Remarks": [],
                        "AddedFromWebTray": true
                    };
                    components.push(bookingComponent);

                    if (product.requiredProducts) {
                        _.each(product.requiredProducts, function (reqProd) {
                            if (!reqProd.product) return;
                            components.push({
                                "Id": reqProd.product.id,
                                "ProductCategory": reqProd.product.productCategory,
                                "ProductType": reqProd.product.productType,
                                "ProductCode": reqProd.product.code,
                                "StartDate": reqProd.product.startDate,
                                "EndDate": reqProd.product.endDate,
                                "Name": reqProd.product.name,
                                "Description": reqProd.product.description,
                                "ProductDescriptions": reqProd.product.productDescriptions,
                                "Price": reqProd.product.price,
                                "ChildPrice": reqProd.product.price,
                                "NumberOfAdults": $scope.selectedAdults,
                                "NumberOfChildren": $scope.selectedChild,
                                "NumberOfSeniors": $scope.selectedSeniors,
                                "NumberOfStudents": $scope.selectedStudents,
                                "NumberOfInfants": $scope.selectedInfants,
                                "Status": "New",
                                "UnitCode": reqProd.unitCode,
                                "UnitDescription": reqProd.product.description,
                                "PickupLocation": undefined,
                                "DropoffLocation": undefined,
                                "StartingLocation": reqProd.product.startingLocation,
                                "Destination": undefined,
                                "Remarks": [],
                                "IsFee": reqProd.product.productType === "FEE"
                            });
                        });
                    }

                    var bookingToQuote = {
                        "Components": components
                    };
                    var data = {
                        "BookingToQuote": bookingToQuote
                    };

                    var requestParams = {
                        apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                        token: jwtService.getPrincipalToken(),
                        dataToPost: data,
                        startDate: productStartDate,
                        endDate: undefined,
                        startTime: "Any Time",
                        endTime: undefined,
                        relatedProductCode: oc.relatedProductCode
                    };
                    $scope.isLoading = true;
                    var prevOptionalExtras = $scope.cart.optionalExtras;
                    shoppingCartService.addComponentsToCart(requestParams, function (result) {
                        if (result) {
                            shoppingCartService.getStorageCart(function (shoppingCart) {
                                $scope.isLoading = false;
                                if (shoppingCart) {
                                    $scope.cart = shoppingCart;
                                    $scope.setCartCustomFields();
                                    //$scope.checkShippingMethodRequired($scope.cart);
                                    $scope.cart.optionalExtras = prevOptionalExtras;
                                    $uibModalInstance.close({ "status": "ok", "cart": $scope.cart });
                                    // $scope.getOptionalExtras();
                                    // resizeSliderPanel();
                                }
                            });
                        } else {
                            $scope.isLoading = false;
                        }

                    });
                });
            };

            $scope.cancel = function () {
                $uibModalInstance.dismiss("cancel");
            };
        }
    ]);

    angular.module("app").controller("checkoutCtrl", [
        "userService", "$state", "utilsFactory", "$element", "$scope", "shoppingCartService", "productsFactory", "jwtService", "validHelper", "customerService", "$window", "cresecureService", "paymentService", "borgunPaymentService", "tempusPaymentService", "$timeout", "packagesService", "$uibModal", "$http", "$sce",
        function (userService, $state, utilsFactory, $element, $scope, shoppingCartService, productsFactory, jwtService, validHelper, customerService, $window, cresecureService, paymentService, borgunPaymentService, tempusPaymentService, $timeout, packagesService, $uibModal, $http, $sce) {
            var webUrl = ($("body").data("weburl") ? $("body").data("weburl") : "");
            $scope.labelUtils = utilsFactory;
            $scope.utils = shoppingCartService.utils;
            $scope.dateFormat = shoppingCartService.getDateFormat();
            $scope.validHelper = validHelper;
            $scope.submitted = false;
            $scope.addCartSubmitted = false;
            $scope.hiddenOptionalExtras = Object.create(null);
            //   $.material.init();
            $scope.isLoading = true;
            $scope.hasCartHotels = false;
            $scope.specReqComps = [];
            $scope.passengerList = [];
            $scope.showUnaccompaniedChildMessage = false;
            $scope.showModal["AddCard"] = false;
            $scope.showModal["Borgun3DSVerification"] = false;
            $scope.borgunPromiseResolver = null;
            $scope.selectedCreCard = null;
            $scope.isCreProcessing = false;
            $scope.showCreSummaryErrors = false;
            $scope.showAddCardSummaryCusotmerErrors = false;
            $scope.creSummaryErrors = [];
            $scope.creSummaryCustomerErrors = [];
            $scope.creCards = [];
            $scope.crescureIframeUrl = "";
            $scope.addonLoading = false;

            $scope.promoCode = "";
            $scope.giftCardCode = "";

            $scope.urlModel = {
                crescureIframeUrls: []
            };

            $scope.canChangeConfirmationEmailAddress = false;
            $scope.showCanPayAtHotel = false;
            $scope.depositAmountDue = 0;
            $scope.dueOnArrival = 0;
            $scope.showCanPayWithAR = false;//can pay with account receivable
            $scope.agencyContacts = [];
            $scope.selectedAgentContact = undefined;
            $scope.externalReferenceNumber = undefined;

            $scope.showUseCustomerCard = false;

            $scope.availableCCYears = [];
            $scope.useTravelerInfo = false;
            $scope.showLoadValidCardMsg = false;
            $scope.showLoadProcessOrderMsg = false;
            $scope.disclaimers = null;
            $scope.inlineCC = {
                errorList: []
            };
            $scope.giftGivingOptions = Object.create(null);
            $scope.giftGivingOptions.model = Object.create(null);

            $scope.deliveryOptions = Object.create(null);
            $scope.deliveryOptions.model = Object.create(null);

            $scope.promptforguestphoneproductcodes = ($($element).attr("data-promptforguestphoneproductcodes") || "").split('|');
            $scope.mergeproductwithparentforproductcodes = ($($element).attr("data-mergeproductwithparentforproductcodes") || "").split('|');

            $scope.promptforguestphone = false;

            $scope.getPackageDurationLabel = packagesService.getPackageDurationLabel;

            function initDisclaimersFromCart() {
                $scope.disclaimers = null;
                if (!$scope.cart || !$scope.cart.Items) return;
                var disclaimers = [];
                _.each($scope.cart.Items, function (item, index) {
                    if (item.BookingToQuote) {
                        if (item.BookingToQuote.Components) {
                            _.each(item.BookingToQuote.Components, function (comp, index) {
                                var compDisclaimers = comp.disclaimers; // added for hotels
                                if (!(compDisclaimers || "").length) {
                                    compDisclaimers = comp.ProductDescriptions && comp.ProductDescriptions.disclaimers;
                                }

                                if ((compDisclaimers || "").length) {
                                    disclaimers = disclaimers.concat(compDisclaimers);
                                }
                            });
                        }
                        if (item.BookingToQuote.Packages) {
                            _.each(item.BookingToQuote.Packages, function (pak, index) {                               
                                var compDisclaimers = pak.PackageDescriptions && pak.PackageDescriptions.disclaimers;                              

                                if ((compDisclaimers || "").length) {
                                    disclaimers = disclaimers.concat(compDisclaimers);
                                }
                            });
                        }
                        //
                    }
                });
                if (disclaimers.length) {
                    $scope.disclaimers = _.union(disclaimers);
                }
            };

            function initShowConsentCheckbox() {
                if (!$scope.cart || !$scope.cart.Quote) return;

                $scope.showConsentCheckbox = $scope.cart.Quote.ExpressConsentRequired;
                $scope.isConsentGiven = $scope.cart.Quote.ExpressConsentRequired;

                $scope.giftGivingOptions = Object.create(null);
                Object.keys($scope.cart.Quote.GiftGivingOptions || {}).forEach(function (key) {
                    $scope.giftGivingOptions[key] = $scope.cart.Quote.GiftGivingOptions[key];
                });

                $scope.giftGivingOptions.model = Object.create(null);
                $scope.giftGivingOptions.model.giftCustomOption = $scope.giftGivingOptions.GiftCanBeEmailed && $scope.giftGivingOptions.GiftCanBeMailed ? "email" : undefined; // default
                $scope.initGiftGivingDatePicker();

                $scope.initDeliveryDatePicker();
            };


            $scope.checkShippingMethodRequired = function (cart, skipRefreshSelections) {
                cart && (cart.shippingMethodRequired = false);

                if (!cart || !(cart.Items || "").length) return;
                //var shippingMethodUnits = [];
                var shippingMethodProduct = null;
                var nrProductsWithShipping = 0;

                _.each(cart.Items, function (sitem, index) {
                    //if (!!shippingMethodProduct) return;

                    if (sitem.BookingToQuote) {
                        if (sitem.BookingToQuote.Components) {
                            _.each(sitem.BookingToQuote.Components, function (scomp, index) {
                                // if (!!shippingMethodProduct) return;

                                if ((scomp._optionalExtras || "").length) {
                                    _.each(scomp._optionalExtras, function (opExtra, index) {
                                        //  if (!!shippingMethodProduct) return;

                                        if (opExtra.product && (opExtra.product.units || "").length) {
                                            // if the first unit has giftGivingOptions options, then this product is a shipping product
                                            var firstUnit = opExtra.product.units[0];
                                            if (firstUnit.giftGivingOptions && (firstUnit.giftGivingOptions.canBePickedUp || firstUnit.giftGivingOptions.giftCanBeEmailed || firstUnit.giftGivingOptions.giftCanBeMailed)) {
                                                var ticketsNo = (scomp.NumberOfAdults || 0) + (scomp.NumberOfChildren || 0);
                                                if (ticketsNo == 0) {
                                                    ticketsNo = (scomp.NumberOfUnits || 0);
                                                }
                                                nrProductsWithShipping += ticketsNo;
                                                // take the first shipping product
                                                if (!shippingMethodProduct) {
                                                    shippingMethodProduct = opExtra.product;
                                                    shippingMethodProduct._relatedProductCode = scomp.ProductCode;
                                                }
                                            }
                                        }
                                    });
                                }
                            });
                        }
                    }

                });

                cart.shippingMethodRequired = !!shippingMethodProduct;
                // set wrapping product property for ease of access
                if (shippingMethodProduct && shippingMethodProduct.units) {
                    _.each(shippingMethodProduct.units, function (unit) {
                        unit.wrappingProduct = unit.relatedProducts
                            && unit.relatedProducts.optionalExtras && unit.relatedProducts.optionalExtras[0]
                            && unit.relatedProducts.optionalExtras[0].product;
                        unit.wrappingProduct && (unit.wrappingProduct.selectedUnitNumber = 0);
                    });
                }
                cart.shippingMethodProduct = shippingMethodProduct;

                $scope.giftWrappingItem = $scope.cart && _.find($scope.cart.Items, function (item) {
                    return item.isWrappingItem;
                });
                $scope.giftShippingItem = $scope.cart && _.find($scope.cart.Items, function (item) {
                    return item.isShippingItem;
                });
                //
                if (!skipRefreshSelections) {
                    $scope.deliveryOptions.model.nrProductsWithShipping = nrProductsWithShipping;

                    var existingShippingItem = _.find($scope.cart.Items, function (item) {
                        return item.isShippingItem;
                    });

                    var existingShippingUnitCode = existingShippingItem && existingShippingItem.BookingToQuote
                        && existingShippingItem.BookingToQuote.Components && existingShippingItem.BookingToQuote.Components[0]
                        && existingShippingItem.BookingToQuote.Components[0].UnitCode;

                    if (existingShippingUnitCode && cart.shippingMethodProduct && cart.shippingMethodProduct.units) {
                        $scope.deliveryOptions.model.deliveryMethodUnit = cart.shippingMethodProduct.units.find(function (unit) {
                            return existingShippingUnitCode == unit.unitCode;
                        });
                    }
                    // set the wrapping options
                    var existingWrappingItem = _.find($scope.cart.Items, function (item) {
                        return item.isWrappingItem;
                    });
                    var existingWrappingNumberOfUnits = existingWrappingItem && existingWrappingItem.BookingToQuote
                        && existingWrappingItem.BookingToQuote.Components && existingWrappingItem.BookingToQuote.Components[0]
                        && existingWrappingItem.BookingToQuote.Components[0].NumberOfUnits || 0;

                    if ($scope.deliveryOptions.model.deliveryMethodUnit && $scope.deliveryOptions.model.deliveryMethodUnit.wrappingProduct) {
                        $scope.deliveryOptions.model.deliveryMethodUnit.wrappingProduct.selectedUnitNumber = existingWrappingNumberOfUnits;
                    }
                }
            };

            $scope.increaseWrappingUnitNumbers = function (increaseUnit) {
                increaseUnit = increaseUnit || 1;
                if (!$scope.deliveryOptions.model.deliveryMethodUnit || !$scope.deliveryOptions.model.deliveryMethodUnit.wrappingProduct)
                    return;

                var oldSelectedUnitNumber = ($scope.deliveryOptions.model.deliveryMethodUnit.wrappingProduct.selectedUnitNumber || 0);
                var newselectedUnitNumber = oldSelectedUnitNumber + increaseUnit;

                if (newselectedUnitNumber > ($scope.deliveryOptions.model.nrProductsWithShipping || 0)) newselectedUnitNumber = $scope.deliveryOptions.model.nrProductsWithShipping;
                if (newselectedUnitNumber < 0) newselectedUnitNumber = 0;

                if (newselectedUnitNumber == oldSelectedUnitNumber)
                    return;

                $scope.deliveryOptions.model.deliveryMethodUnit.wrappingProduct.selectedUnitNumber = newselectedUnitNumber;
                $scope.requoteAfterWrappingUnitsAdded();
            };

            $scope.requoteAfterShippingChanged = function (callback) {
                // this method will be called automatically on page load, after we set the shipping method

                var product = $scope.cart.shippingMethodProduct; // $scope.deliveryOptions.model.deliveryMethodUnit.wrappingProduct;
                if (!product) {
                    callback && callback();
                    return;
                }

                var unit = $scope.deliveryOptions.model.deliveryMethodUnit;
                var productStartDate = product.startDate;


                var existingShippingItem = _.find($scope.cart.Items, function (item) {
                    return item.isShippingItem;
                });

                // if the product was not changed skip the refresh
                if (product && unit && existingShippingItem && (existingShippingItem.ProductCode == product.code) && (existingShippingItem.UnitCode == unit.unitCode)) {
                    return;
                }

                $scope.isLoading = true;

                var existingShippingItemIndex = _.findIndex($scope.cart.Items, function (item) {
                    return item.isShippingItem;
                });

                var removeExistingShippingItemPromise = Promise.resolve(1);

                if (existingShippingItemIndex > -1) {

                    removeExistingShippingItemPromise = new Promise(function (resolve, reject) {
                        var requestParams = {
                            apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                            token: jwtService.getPrincipalToken(),
                            index: existingShippingItemIndex,
                            removeAllShippingAndWrappings: true,
                            productCode: product._relatedProductCode,
                            skipQuote: unit ? true : false // don't call the api quote since it will be called after the new items will be added to cart
                        };

                        shoppingCartService.updateCartComponents(requestParams, function (shoppingCart) {
                            if (shoppingCart && (shoppingCart.Items || '').length) {
                                $scope.cart = shoppingCart;
                                $scope.setCartCustomFields();
                                $scope.checkShippingMethodRequired($scope.cart, true);
                                // initDisclaimersFromCart();
                                // $scope.getOptionalExtras();
                                // $scope.reloadCartOptions();
                                // $scope.setGiftCardsRedeemAmount();
                            }

                            shoppingCartService.setStorageCart($scope.cart, function () {
                                $scope.refreshInputs('#shippingMethodContainer');
                                resolve(1);
                            });

                        });
                    });
                }

                removeExistingShippingItemPromise.then(function () {
                    if (!unit) {
                        $scope.isLoading = false;
                        callback && callback();
                        try {
                            $timeout(function () { $scope.$apply(); });
                        } catch (e) {
                            console.log(e);
                        }
                        return;
                    }

                    // add the shipping product
                    var components = [];
                    var bookingComponent = {
                        "Id": product.code + unit.unitCode,
                        "ProductCategory": product.productCategory,
                        "ProductType": product.productType,
                        "ProductCode": product.code,
                        "StartDate": productStartDate,
                        "EndDate": productStartDate,
                        "Name": product.name,
                        "Description": product.description,
                        "Price": product.price || unit.price,
                        "ChildPrice": product.price || unit.price,
                        "NumberOfUnits": 1,
                        "NumberOfAdults": 0,
                        "NumberOfChildren": 0,
                        "NumberOfInfants": 0,
                        "NumberOfSeniors": 0,
                        "NumberOfStudents": 0,
                        "Status": "New",
                        "UnitCode": unit.unitCode,
                        "UnitDescription": unit.description,
                        "PickupLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                        "DropoffLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                        "StartingLocation": product.startingLocation,
                        "Destination": product.destination,
                        "Remarks": [],
                        "AddedFromWebTray": false
                    };
                    components.push(bookingComponent);

                    var bookingToQuote = {
                        "Components": components
                    };
                    var data = {
                        "BookingToQuote": bookingToQuote
                    };

                    var requestParams = {
                        apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                        token: jwtService.getPrincipalToken(),
                        dataToPost: data,
                        startDate: productStartDate,
                        endDate: undefined,
                        startTime: "Any Time",
                        endTime: undefined,
                        relatedProductCode: $scope.cart.shippingMethodProduct && $scope.cart.shippingMethodProduct._relatedProductCode,
                        hideItemInCart: true,
                        isShippingItem: true
                    };



                    //var prevOptionalExtras = $scope.cart.optionalExtras;
                    shoppingCartService.addComponentsToCart(requestParams, function (result) {
                        if (result) {
                            shoppingCartService.getStorageCart(function (shoppingCart) {
                                $scope.isLoading = false;
                                if (shoppingCart) {
                                    $scope.cart = shoppingCart;
                                    $scope.setCartCustomFields();
                                    $scope.checkShippingMethodRequired($scope.cart, false);

                                    //$scope.cart.optionalExtras = prevOptionalExtras;
                                }
                                callback && callback();
                            });
                        } else {
                            $scope.isLoading = false;
                            callback && callback();
                        }
                        try {
                            $timeout(function () { $scope.$apply(); });
                        } catch (e) {
                            console.log(e);
                        }
                    });
                });
                //
            };

            $scope.requoteAfterWrappingUnitsAdded = function () {
                var numberOfUnits = ($scope.deliveryOptions.model.deliveryMethodUnit
                    && $scope.deliveryOptions.model.deliveryMethodUnit.wrappingProduct
                    && $scope.deliveryOptions.model.deliveryMethodUnit.wrappingProduct.selectedUnitNumber) || 0;

                var product = $scope.deliveryOptions.model.deliveryMethodUnit.wrappingProduct;
                if (!product) return;

                $scope.isLoading = true;

                var unit = product.units[0];
                var productStartDate = product.startDate;

                var existingWrappingItemIndex = _.findIndex($scope.cart.Items, function (item) {
                    return item.isWrappingItem;
                });

                var removeExistingWrappingItemPromise = Promise.resolve(1);

                if (existingWrappingItemIndex > -1) {
                    removeExistingWrappingItemPromise = new Promise(function (resolve, reject) {
                        var requestParams = {
                            apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                            token: jwtService.getPrincipalToken(),
                            index: existingWrappingItemIndex,
                            //removeAllShippingAndWrappings: true, // it will remove the shipping product
                            productCode: product.code,
                            skipQuote: numberOfUnits > 0 ? true : false // don't call the api quote since it will be called after the new items will be added to cart
                        };

                        shoppingCartService.updateCartComponents(requestParams, function (shoppingCart) {
                            if (shoppingCart && (shoppingCart.Items || '').length) {
                                $scope.cart = shoppingCart;
                                $scope.setCartCustomFields();
                                $scope.checkShippingMethodRequired($scope.cart, true);

                                // initDisclaimersFromCart();
                                // $scope.getOptionalExtras();
                                // $scope.reloadCartOptions();
                                // $scope.setGiftCardsRedeemAmount();
                            }

                            shoppingCartService.setStorageCart($scope.cart, function () {
                                resolve(1);
                            });

                        });
                    });
                }

                removeExistingWrappingItemPromise.then(function () {
                    if (numberOfUnits <= 0) {
                        $scope.isLoading = false;
                        return;
                    }

                    // add one more wrapping product
                    var components = [];
                    var bookingComponent = {
                        "Id": product.code + unit.unitCode,
                        "ProductCategory": product.productCategory,
                        "ProductType": product.productType,
                        "ProductCode": product.code,
                        "StartDate": productStartDate,
                        "EndDate": productStartDate,
                        "Name": product.name,
                        "Description": product.description,
                        "Price": product.price || unit.price,
                        "ChildPrice": product.price || unit.price,
                        "NumberOfUnits": numberOfUnits,
                        "NumberOfAdults": 0,
                        "NumberOfChildren": 0,
                        "NumberOfInfants": 0,
                        "NumberOfSeniors": 0,
                        "NumberOfStudents": 0,
                        "Status": "New",
                        "UnitCode": unit.unitCode,
                        "UnitDescription": unit.description,
                        "PickupLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                        "DropoffLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                        "StartingLocation": product.startingLocation,
                        "Destination": product.destination,
                        "Remarks": [],
                        "AddedFromWebTray": false
                    };
                    components.push(bookingComponent);

                    var bookingToQuote = {
                        "Components": components
                    };
                    var data = {
                        "BookingToQuote": bookingToQuote
                    };

                    var requestParams = {
                        apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                        token: jwtService.getPrincipalToken(),
                        dataToPost: data,
                        startDate: productStartDate,
                        endDate: undefined,
                        startTime: "Any Time",
                        endTime: undefined,
                        relatedProductCode: $scope.cart.shippingMethodProduct && $scope.cart.shippingMethodProduct._relatedProductCode,
                        hideItemInCart: true,
                        isWrappingItem: true
                    };

                    // var prevOptionalExtras = $scope.cart.optionalExtras;
                    shoppingCartService.addComponentsToCart(requestParams, function (result) {
                        if (result) {
                            shoppingCartService.getStorageCart(function (shoppingCart) {
                                $scope.isLoading = false;
                                if (shoppingCart) {
                                    $scope.cart = shoppingCart;
                                    $scope.setCartCustomFields();
                                    $scope.checkShippingMethodRequired($scope.cart);

                                    //$scope.cart.optionalExtras = prevOptionalExtras;
                                }
                            });
                        } else {
                            $scope.isLoading = false;
                        }
                    });
                });
                //
            };


            $scope.isSkylagoon = function () {
                return ($scope.selectedGeographyCode || "").toLowerCase().indexOf("skl") >= 0;
            };

            $scope.initGiftGivingDatePicker = function () {
                $timeout(function () {
                    var giftGivingDatepickersettings = {
                        singleDatePicker: true,
                        minDate: jwtService.getServerMomentDate().toDate(),
                        showDropdowns: true,
                        locale: {
                            format: shoppingCartService.getDateFormat()
                        }
                    };


                    // set date
                    $scope.giftGivingOptions.model.emaildaterangepicker = $("#giftGivingEmailDate").daterangepicker(giftGivingDatepickersettings);
                });
            };

            $scope.initDeliveryDatePicker = function () {
                $timeout(function () {
                    var giftGivingDatepickersettings = {
                        singleDatePicker: true,
                        minDate: jwtService.getServerMomentDate().toDate(),
                        showDropdowns: true,
                        locale: {
                            format: shoppingCartService.getDateFormat()
                        }
                    };

                    // set date
                    $scope.deliveryOptions.model.emaildaterangepicker = $("#deliveryEmailDate").daterangepicker(giftGivingDatepickersettings);

                    //var timeSettings = {
                    //    timeFormat: 'hh:mm p',
                    //    interval: 60,
                    //    minTime: '00:00',
                    //    maxTime: '23:00',
                    //    defaultTime: '08',
                    //    startTime: '00:00',
                    //    dynamic: false,
                    //    dropdown: true,
                    //    scrollbar: true
                    //};

                    //$scope.deliveryOptions.model.emailtimepicker = $("#deliveryEmailTime").timepicker(timeSettings);
                });
            };

            $scope.getGiftGivingAdditionalMessage = function () {
                if (($scope.giftGivingOptions.GiftCanBeEmailed && !$scope.giftGivingOptions.GiftCanBeMailed) || $scope.giftGivingOptions.model.giftCustomOption == 'email') {
                    if ($scope.giftGivingOptions.model.sendGiftTicketsDirectly) {
                        return $scope.labelUtils.getLabel("checkout.giftGiving.sendGiftTicketsDirectlyInfo");
                    } else {
                        return $scope.labelUtils.getLabel("checkout.giftGiving.sendEmailInfo");
                    }
                }
                if (($scope.giftGivingOptions.GiftCanBeMailed && !$scope.giftGivingOptions.GiftCanBeEmailed) || $scope.giftGivingOptions.model.giftCustomOption == 'mail') {
                    return $scope.labelUtils.getLabel("checkout.giftGiving.sendMailInfo");
                }
                return "";
            };

            var timeoutID = undefined;

            function refreshInputs(container) {
                setTimeout(function () {
                    var inputs = (container + " input");
                    jQuery(inputs).change();
                    var selects = (container + " select, " + container + " md-select");
                    jQuery(selects).blur();

                });
            }
            $scope.refreshInputs = refreshInputs;

            function resizeSliderPanel(container, refreshAllInputs) {

                window.clearTimeout(timeoutID);

                timeoutID = setTimeout(function () {


                    _.each(jQuery("input"), function (input) {
                        if (jQuery(input).val()) { // trigger "change" event twice for fixing focus issue
                            jQuery(input).change();
                        }
                    });

                    jQuery(window).resize();
                }, 100);
                if (!$scope.hasUpdatePanelEvent && jQuery(".update-collapse-panel").length) {
                    $scope.hasUpdatePanelEvent = true;
                    jQuery(".update-collapse-panel").on("shown.bs.collapse", function () {
                        resizeSliderPanel();
                    });
                    jQuery(".update-collapse-panel").on("hidden.bs.collapse", function () {
                        resizeSliderPanel();
                    });
                }
            }

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            $scope.$on("customer-changed", function (event, args) {
                //if ($scope.selectedCreCard) {
                //    jwtService.setCurrentCard($scope.selectedCreCard);
                //}
                jwtService.setCheckoutModel($scope.model);
                // $window.location.reload();
            });

            var currentYear = jwtService.getServerMomentDate().year();//new Date().getFullYear();

            for (var i = currentYear; i < currentYear + 10; i++) {
                var str = i.toString();
                $scope.availableCCYears.push(str);
            }

            $scope.availableMonths = [
                { text: "1", value: "01" }, { text: "2", value: "02" }, { text: "3", value: "03" }, { text: "4", value: "04" }, { text: "5", value: "05" }, { text: "6", value: "06" },
                { text: "7", value: "07" }, { text: "8", value: "08" }, { text: "9", value: "09" }, { text: "10", value: "10" }, { text: "11", value: "11" }, { text: "12", value: "12" }
            ];

            $scope.availableCountries = [
                {
                    name: "United States",
                    countryCode: "US"
                },
                {
                    name: "Canada",
                    countryCode: "CA"
                }
            ];

            $scope.showStateProvForCountries = _.pluck($scope.availableCountries, "name");

            $scope.showStateProv = function () {
                return !$scope.model.billingCountry || $scope.showStateProvForCountries.indexOf($scope.model.billingCountry) > -1;
            };
            $scope.showTravelerStateProv = function () {
                return $scope.model.travelerCountry && $scope.showStateProvForCountries.indexOf($scope.model.travelerCountry) > -1;
            };
            $scope.showGiftGivingStateProv = function () {
                return $scope.giftGivingOptions.model.country && $scope.showStateProvForCountries.indexOf($scope.giftGivingOptions.model.country) > -1;
            };
            $scope.showDeliveryStateProv = function () {
                return $scope.deliveryOptions.model.country && $scope.showStateProvForCountries.indexOf($scope.deliveryOptions.model.country) > -1;
            };

            $scope.model = {
                //travelerFirstName: "",
                //travelerLastName: "",
                //travelerAddress: "",
                //travelerCity: "",
                //travelerProvState: "",
                //travelerCountry: "",
                //travelerZipCode: "",
                //travelerEmail: "",
                //travelerPhone: "",

                firstName: "",
                lastName: "",
                billingAddress: "",
                billingCity: "",
                provState: "",
                billingCountry: "",
                zipCode: "",
                cardNumber: "",
                emailAddress: "",
                emailAddress_c: "",
                termsAndConditions: false,
                payAtHotel: false,
                payWithAR: false,
                useCustomerCard: false,
                expirationMonth: "",
                expirationYear: "",
                cvcCode: "",
                //sendNewslettersAndPromotions: false,
                createNewCard: false
            };

            $scope.createAccountModel = {
                response: null,
                username: "",
                firstName: "",
                lastName: "",
                password: "",
                password_c: "",
                emailAddress: "",
                emailAddress_c: "",
                submitted: false,
                errors: []
            }

            // $scope.isCreateButtonVisible = true;

            $scope.showSummaryErrors = false;
            $scope.showAddCardSummaryErrors = false;
            $scope.totalErrors = 0;
            var isResizing = false;
            $scope.hasUpdatePanelEvent = false;

            if (jQuery(".update-collapse-panel").length) {
                $scope.hasUpdatePanelEvent = true;
                jQuery(".update-collapse-panel").on("shown.bs.collapse", function () {
                    resizeSliderPanel();
                });
                jQuery(".update-collapse-panel").on("hidden.bs.collapse", function () {
                    resizeSliderPanel();
                });
            }

            //$scope.$watch("useTravelerInfo", function () {
            //    if ($scope.useTravelerInfo) copyTravelerInfoToBilling();
            //});

            $scope.$watch("model.useCustomerCard", function (a, b) {
                if (a == b) return;

                if ($scope.model.useCustomerCard) {
                    // copyTravelerInfoToBilling();
                } else {
                    $scope.selectedCreCard = null;
                    // $scope.model.cardNumber = null;
                    refreshInputs("#billingInfo");
                }
            });


            //function copyTravelerInfoToBilling() {
            //    $scope.model.firstName = ($scope.model.travelerFirstName || "");
            //    $scope.model.lastName = ($scope.model.travelerLastName || "");
            //    $scope.model.billingAddress = ($scope.model.travelerAddress || "");
            //    $scope.model.billingCity = ($scope.model.travelerCity || "");
            //    $scope.model.provState = ($scope.model.travelerProvState || "");
            //    $scope.model.billingCountry = ($scope.model.travelerCountry || "");
            //    $scope.model.zipCode = ($scope.model.travelerZipCode || "");
            //    $scope.selectedCreCard = null;
            //    $scope.model.cardNumber = null;
            //    refreshInputs("#billingInfo");
            //}

            $scope.$watch("totalErrors", function () {
                resizeSliderPanel();
            });

            $scope.getLabelWith2Placeholders = function (labelKey, replaceValue1, replaceValue2) {
                var labelValue = $scope.labelUtils.getLabel(labelKey);
                if (!labelValue) {
                    return "";
                }

                labelValue = labelValue.replace("{0}", replaceValue1 == null ? "" : replaceValue1);
                labelValue = labelValue.replace("{1}", replaceValue2 == null ? "" : replaceValue2);
                return labelValue;
            };

            $scope.getLabelWithPlaceholder = function (labelKey, replaceValue) {
                var labelValue = $scope.labelUtils.getLabel(labelKey);
                if (!labelValue) {
                    return "";
                }

                return labelValue.replace("{0}", replaceValue == null ? "" : replaceValue);
            };

            $scope.getPriceInSelectedCurrency = function (value) {
                return $scope.$parent.getPriceInSelectedCurrency(value, $scope.getCurrency(false), $scope.selectedCurrency);
            };

            $scope.getCurrency = function (checkSelectedCurrencyFirst) {
                if (checkSelectedCurrencyFirst) {
                    var selectedCurrency = ($scope.currencyRatesLoaded && $scope.selectedCurrency && $scope.selectedCurrency.code);
                    if (!!selectedCurrency) return selectedCurrency;
                }

                //jwtService.getPrincipalTokenCurrency();
                if ($scope.currency) return $scope.currency;

                if ($scope.cart && $scope.cart.Quote) {
                    $scope.currency = $scope.cart.Quote.Currency;
                }
                return $scope.currency || "USD";
            };

            $scope.countryChanged = function (country) {
                $scope.model.billingCountry = country.name;
            }

            $scope.expirationMonthChanged = function (month) {
                $scope.model.expirationMonth = month;
            }

            $scope.expirationYearsChanged = function (year) {
                $scope.model.expirationYear = year;
            }

            $scope.cart = shoppingCartService.getEmptyCart();
            $scope.checkShippingMethodRequired($scope.cart);

            $scope.getTaxes = function (bookingQuoteComponent, quoteComponent) {
                var quotePrice = quoteComponent.Price;
                var numberOfAdults = parseInt(bookingQuoteComponent.NumberOfAdults);
                var numberOfChilds = parseInt(bookingQuoteComponent.NumberOfChildren);

                var totalPrice = numberOfAdults * bookingQuoteComponent.Price + numberOfChilds * bookingQuoteComponent.ChildPrice;

                return parseFloat(quotePrice - totalPrice).toFixed(2);
            };

            $scope.getTotalSummaryErrors = function () {

                var res = ($scope.checkOutForm.travelerFirstName.$invalid ? 1 : 0) +
                    ($scope.checkOutForm.travelerLastName.$invalid ? 1 : 0) +
                    ($scope.checkOutForm.travelerAddress.$invalid ? 1 : 0) +
                    ($scope.checkOutForm.travelerCity.$invalid ? 1 : 0) +
                    ($scope.checkOutForm.travelerProvState && $scope.checkOutForm.travelerProvState.$invalid ? 1 : 0) +
                    ($scope.checkOutForm.travelerCountry.$invalid ? 1 : 0) +
                    ($scope.checkOutForm.travelerZipCode.$invalid ? 1 : 0) +
                    ($scope.checkOutForm.travelerPhone.$invalid ? 1 : 0) +
                    (!$scope.isGuestInfoValid() ? 1 : 0) +
                    //    ($scope.checkOutForm.firstName.$invalid ? 1 : 0) +
                    //($scope.checkOutForm.lastName.$invalid ? 1 : 0) +
                    //($scope.checkOutForm.billingAddress.$invalid ? 1 : 0) +
                    //($scope.checkOutForm.billingCity.$invalid ? 1 : 0) +
                    //($scope.checkOutForm.provState.$invalid ? 1 : 0) +
                    //($scope.checkOutForm.billingCountry.$invalid ? 1 : 0) +
                    //($scope.checkOutForm.zipCode.$invalid ? 1 : 0) +
                    ($scope.checkOutForm.cardNumber && $scope.checkOutForm.cardNumber.$error && $scope.checkOutForm.cardNumber.$error.required ? 1 : 0) +
                    ($scope.checkOutForm.cardNumber && $scope.checkOutForm.cardNumber.$error && $scope.checkOutForm.cardNumber.$error.pattern ? 1 : 0) +
                    ($scope.checkOutForm.expirationMonth && $scope.checkOutForm.expirationMonth.$invalid ? 1 : 0) +
                    ($scope.checkOutForm.expirationYear && $scope.checkOutForm.expirationYear.$invalid ? 1 : 0) +
                    ($scope.checkOutForm.cvcCode && $scope.checkOutForm.cvcCode.$error && $scope.checkOutForm.cvcCode.$error.required ? 1 : 0) +
                    ($scope.checkOutForm.cvcCode && $scope.checkOutForm.cvcCode.$error && $scope.checkOutForm.cvcCode.$error.pattern ? 1 : 0) +
                    ($scope.checkOutForm.termsAndConditions.$error.required ? 1 : 0) +
                    ($scope.checkOutForm.emailAddress && $scope.checkOutForm.emailAddress.$error && $scope.checkOutForm.emailAddress.$error.pattern ? 1 : 0) +
                    ($scope.checkOutForm.emailAddress && $scope.checkOutForm.emailAddress.$error && $scope.checkOutForm.emailAddress.$error.required ? 1 : 0) +
                    //($scope.checkOutForm.emailAddress_c.$error.required ? 1 : 0) +
                    ($scope.checkOutForm.emailAddress_c && $scope.checkOutForm.emailAddress_c.$error && $scope.checkOutForm.emailAddress_c.$error.compareTo ? 1 : 0) +

                    ($scope.checkOutForm.password && $scope.checkOutForm.password.$error && $scope.checkOutForm.password.$error.pattern ? 1 : 0) +
                    ($scope.checkOutForm.password && $scope.checkOutForm.password.$error && $scope.checkOutForm.password.$error.required ? 1 : 0) +
                    //($scope.checkOutForm.password_c.$error.required ? 1 : 0) +
                    ($scope.checkOutForm.password_c && $scope.checkOutForm.password_c.$error && $scope.checkOutForm.password_c.$error.compareTo ? 1 : 0) +

                    ($scope.checkOutForm.travelerEmail.$error.pattern ? 1 : 0) +
                    ($scope.checkOutForm.travelerEmail.$error.required ? 1 : 0) +
                    ($scope.inlineCC && ($scope.inlineCC.errors || '').length ? 1 : 0) +
                    ($scope.checkOutForm.addCard.$invalid ? 1 : 0) +
                    (!$scope.isGiftGivingFieldsValid() ? 1 : 0) +
                    (!$scope.isDeliveryValid() ? 1 : 0) +
                    (!$scope.isDeliveryFieldsValid() ? 1 : 0)
                    ;

                //if ($scope.specReqComps) {

                //    $.each($scope.specReqComps, function (index, item) {
                //        res += ($scope.checkOutForm["contactName_" + index] && $scope.checkOutForm["contactName_" + index].$error.required) ? 1 : 0;
                //        res += ($scope.checkOutForm["contactPhone_" + index] && $scope.checkOutForm["contactPhone_" + index].$error.required) ? 1 : 0;
                //    });
                //}

                $scope.showSummaryErrors = res > 0;

                $scope.totalErrors = res;
                return res;
            };

            $scope.canShowAddCardSummaryErrors = function () {
                /*var res = ($scope.checkOutForm.firstName.$invalid ? 1 : 0) +
                ($scope.checkOutForm.lastName.$invalid ? 1 : 0) +
                ($scope.checkOutForm.billingAddress.$invalid ? 1 : 0) +
                ($scope.checkOutForm.billingCity.$invalid ? 1 : 0) +
                ($scope.checkOutForm.provState.$invalid ? 1 : 0) +
                ($scope.checkOutForm.billingCountry.$invalid ? 1 : 0) +
                ($scope.checkOutForm.zipCode.$invalid ? 1 : 0);
    
                return res > 0;*/

                return false;
            };

            $scope.continueShopping = function () {
                window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
            };

            $scope.goBackToModify = function () {
                if (!($scope.cart && $scope.cart.updateBookingUrl)) return;

                window.location.href = utilsFactory.addPersistentQueryStringsParams($scope.cart.updateBookingUrl);
            };

            $scope.fillAgencyContactsAsync = function (callback) {

                customerService.getPersistedAgencyContacts(function (contactsResult) {

                    if (contactsResult.success && contactsResult.data && contactsResult.data.customers) {
                        $scope.agencyContacts = contactsResult.data.customers;

                        if (callback) {
                            callback();
                        }
                        return;
                    }
                    customerService.getAgencyContactsAsync(
                        {
                            token: jwtService.getPrincipalToken()
                        },
                        function (result) {

                            if (result.success && result.data) {
                                $scope.agencyContacts = result.data.customers;

                                customerService.persistAgencyContacts({
                                    customers: $scope.agencyContacts
                                }, function () { });
                            }
                            if (callback) {
                                callback();
                            }
                        });
                });
            };

            $scope.isGuestInfoValid = function () {

                if (!($scope.passengerList || "").length) return true;
                var isValid = true;
                var formField = undefined;
                for (var i = 0; i < $scope.passengerList.length; i++) {
                    if (!isValid) break;
                    var pas = $scope.passengerList[i];
                    for (var j = 1; j < pas.adults.length; j++) { // first passenger will be main traveler
                        if (!isValid) break;
                        formField = $scope.checkOutForm["pasAdultFirstName_" + i + "_" + j];
                        if (formField) {
                            isValid = !formField.$invalid;
                        }
                        if (!isValid) break;
                        formField = $scope.checkOutForm["pasAdultLastName_" + i + "_" + j];
                        if (formField) {
                            isValid = !formField.$invalid;
                        }

                        if (!isValid) break;
                        formField = $scope.checkOutForm["pasAdultPhone_" + i + "_" + j];
                        if (formField) {
                            isValid = !formField.$invalid;
                        }
                    }

                    for (var j = 0; j < pas.children.length; j++) {
                        if (!isValid) break;
                        formField = $scope.checkOutForm["pasChildFirstName_" + i + "_" + j];
                        if (formField) {
                            isValid = !formField.$invalid;
                        }
                        if (!isValid) break;
                        formField = $scope.checkOutForm["pasChildLastName_" + i + "_" + j];
                        if (formField) {
                            isValid = !formField.$invalid;
                        }
                        if (!isValid) break;
                        formField = $scope.checkOutForm["pasChildAge_" + i + "_" + j];
                        if (formField) {
                            isValid = !formField.$invalid;
                        }
                    }

                    for (var j = 0; j < pas.infants.length; j++) {
                        if (!isValid) break;
                        formField = $scope.checkOutForm["pasInfantFirstName_" + i + "_" + j];
                        if (formField) {
                            isValid = !formField.$invalid;
                        }
                        if (!isValid) break;
                        formField = $scope.checkOutForm["pasInfantLastName_" + i + "_" + j];
                        if (formField) {
                            isValid = !formField.$invalid;
                        }
                        formField = $scope.checkOutForm["pasInfantAge_" + i + "_" + j];
                        if (formField) {
                            isValid = !formField.$invalid;
                        }
                    }
                }
                return isValid;
            };

            $scope.changeConsent = function () {
                // Display modal
                var requiredModalInstance = $uibModal.open({
                    animation: true,
                    templateUrl: "expressConsentModal.html",
                    controller: "expressConsentModalCtrl",
                    size: "book-required-products",
                    resolve: {
                        "expressConsent": {
                            title: utilsFactory.getLabel("general.expressConsent.CartUpdateInfoModalTitle"),
                            message: utilsFactory.getLabel("general.expressConsent.CartUpdateInfoModalMessage"),
                        }
                    },
                    backdrop: "true"
                });
                // "components": { followingProductSingle: "product", followingProductMultiple: "products", yourProductTitle: "attraction", data: popupProducts }

                requiredModalInstance.result.then(function (result) {
                    var removeItemsFromCart = [];

                    _.each($scope.cart.Items, function (sitem, index) {
                        if (sitem.BookingToQuote) {
                            var shouldRemoveItemFromCart = false;

                            if ((sitem.BookingToQuote.Components || "").length) {

                                shouldRemoveItemFromCart = _.find(sitem.BookingToQuote.Components, function (scomp) {
                                    return scomp.ExpressConsentOptions && scomp.ExpressConsentOptions.ExpressConsentRequired && (scomp.ExpressConsentOptions.IfIneligableRateCode || "").length < 1 && (scomp.ExpressConsentOptions.IfIneligableProductUnit || "").length < 1 && (scomp.ExpressConsentOptions.IfIneligableProductCode || "").length < 1;
                                });

                                !shouldRemoveItemFromCart && _.each(sitem.BookingToQuote.Components, function (scomp, index) {
                                    if (scomp.ExpressConsentOptions && scomp.ExpressConsentOptions.ExpressConsentRequired) {
                                        (scomp.ExpressConsentOptions.IfIneligableProductCode || "").length && (scomp.ProductCode = scomp.ExpressConsentOptions.IfIneligableProductCode);
                                        (scomp.ExpressConsentOptions.IfIneligableProductUnit || "").length && (scomp.UnitCode = scomp.ExpressConsentOptions.IfIneligableProductUnit);
                                        (scomp.ExpressConsentOptions.IfIneligableRateCode || "").length && _.each(scomp.PriceBreakdown, function (prBdwn) {
                                            prBdwn.RateCode = scomp.ExpressConsentOptions.IfIneligableRateCode;
                                        });
                                    }
                                });
                            }

                            if ((sitem.BookingToQuote.Packages || "").length) {
                                shouldRemoveItemFromCart = _.filter(sitem.BookingToQuote.Packages, function (spkg) {
                                    return spkg.ExpressConsentOptions && spkg.ExpressConsentOptions.ExpressConsentRequired && (spkg.ExpressConsentOptions.IfIneligableProductCode || "").length < 1;
                                });
                            }

                            if (shouldRemoveItemFromCart) {
                                removeItemsFromCart.push({
                                    index: index,
                                    productCode: sitem.ProductCode
                                });
                            }
                        }
                    });

                    if (removeItemsFromCart.length) {
                        // TODO: remove multiple items from cart if required 
                        var requestParams = {
                            apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                            token: jwtService.getPrincipalToken(),
                            index: removeItemsFromCart[0].index,
                            productCode: removeItemsFromCart[0].productCode,
                            removeAllShippingAndWrappings: true
                        };
                        $scope.isLoading = true;
                        $scope.cart.optionalExtras = [];

                        shoppingCartService.setStorageCart($scope.cart, function () {
                            shoppingCartService.updateCartComponents(requestParams, function (shoppingCart) {
                                $scope.isLoading = false;
                                if (shoppingCart && (shoppingCart.Items || '').length) {
                                    $scope.cart = shoppingCart;
                                    $scope.setCartCustomFields();
                                    $scope.checkShippingMethodRequired($scope.cart);
                                    initDisclaimersFromCart();
                                    $scope.getOptionalExtras();
                                    $scope.reloadCartOptions();
                                    $scope.setGiftCardsRedeemAmount();
                                } else {
                                    window.location = utilsFactory.addPersistentQueryStringsParams("/");
                                }
                            });
                        });
                    } else {
                        var requestParams = {
                            apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                            token: jwtService.getPrincipalToken()
                        };
                        $scope.isLoading = true;

                        shoppingCartService.setStorageCart($scope.cart, function () {
                            shoppingCartService.refreshQuote(requestParams, function (shoppingCart) {
                                $scope.isLoading = false;
                                if (shoppingCart && (shoppingCart.Items || '').length) {
                                    $scope.cart = shoppingCart;
                                    $scope.setCartCustomFields();
                                    $scope.checkShippingMethodRequired($scope.cart);
                                    initDisclaimersFromCart();
                                    $scope.getOptionalExtras();
                                    $scope.reloadCartOptions();
                                    $scope.setGiftCardsRedeemAmount();
                                }
                            });
                        });
                    }

                    //
                }, function (e) {
                    $scope.isConsentGiven = true; // revert back
                });
            };

            $scope.submitUpdate = function (isValid) {
                $scope.submitted = true;
                if (!isValid) return;

                // don't display the exit intent modal
                $scope.wasExitModalShown = true;
                jwtService.setDisableExitIntent();

                var isCustomer = jwtService.getCustomerToken();
                var customer = jwtService.getCustomer();
                var creditCardPayment = {};

                // There’s an amount owing on the booking
                var ccPromise = Promise.resolve(1);
                var bookingHasDifferentPaymentProviderThanExisting = false;

                if ($scope.ccReqForUpdate) {
                    ccPromise = $scope.addBorgunCardPromise().then(function () {
                        if ($scope.selectedCreCard) {
                            creditCardPayment.Amount = $scope.depositAmountDue;

                            if ($scope.isTempusPaymentProvider) {
                                // new tempus payment provider                                            
                                creditCardPayment.CardExpirationMonth = $scope.selectedCreCard.expirationMonth;
                                creditCardPayment.CardExpirationYear = $scope.selectedCreCard.expirationYear;
                                creditCardPayment.CardHolderName = $scope.selectedCreCard.cardHolderName;
                                creditCardPayment.CardLastFour = $scope.selectedCreCard.cardNumber;
                                creditCardPayment.CardToken = $scope.selectedCreCard.cardTokenValue;
                                creditCardPayment.CardType = $scope.selectedCreCard.cardType;
                                creditCardPayment.CustomerId = $scope.isAgent && $scope.selectedAgentContact && $scope.selectedAgentContact.customerId;
                                creditCardPayment.PursuitBusinessId = $scope.selectedCreCard.pursuitBusinessId;

                                creditCardPayment.IsMultiUseToken = !!(isCustomer && !$scope.selectedCreCard.doNotSaveCardToken);

                                creditCardPayment.Is3ds = false;
                                creditCardPayment.ThreeDsMpiToken = null;
                            } else {
                                if ($scope.displayInlineCCInput) {
                                    creditCardPayment.UseExistingCreditCardToken = false; // TODO: check
                                    creditCardPayment.CardTokenValue = $scope.selectedCreCard.cardTokenValue;

                                    if (isCustomer && !$scope.selectedCreCard.useAsAnonymous) {
                                        if ($scope.selectedCreCard.doNotSaveCardToken) {
                                            creditCardPayment.DoNotSaveCardToken = true;
                                        } else {
                                            creditCardPayment.UseExistingCreditCardToken = true;
                                        }
                                    }
                                } else {
                                    if (!isCustomer) {
                                        creditCardPayment.CresecureHpfCallbackFullQueryParams = $scope.selectedCreCard.fullQuery;
                                    } else {
                                        if ($scope.selectedCreCard.useAsAnonymous) {
                                            creditCardPayment.CresecureHpfCallbackFullQueryParams = $scope.selectedCreCard.fullQuery;
                                        } else {
                                            if ($scope.selectedCreCard.doNotSaveCardToken && !$scope.selectedCreCard.value) {
                                                creditCardPayment.DoNotSaveCardToken = true;
                                                creditCardPayment.CresecureHpfCallbackFullQueryParams = $scope.selectedCreCard.fullQuery;
                                            } else {
                                                creditCardPayment.UseExistingCreditCardToken = true;
                                                creditCardPayment.ExistingCardId = $scope.selectedCreCard.cardid;
                                            }
                                        }
                                    }
                                }


                                //override values for travel agents
                                if ($scope.showUseCustomerCard && $scope.model.useCustomerCard) {
                                    creditCardPayment.DoNotSaveCardToken = true;
                                }

                                //if ($scope.model.payAtHotel) {
                                //    creditCardPayment.DoNotSaveCardToken = false;
                                //}
                            }//other payments
                        } else {
                            //Pay with Accounts Receivable
                            creditCardPayment = null;
                        }
                    });
                } // credit card required
                else if ($scope.updateBookingPayStatus < 0) {
                    if ($scope.isTempusPaymentProvider) {
                        if (!$scope.cart.UpdatedBooking.CreditCardPurchaseWithToken) {
                            creditCardPayment = $scope.cart.UpdatedBooking.CreditCardPayment;
                            bookingHasDifferentPaymentProviderThanExisting = true;
                        } else {
                            creditCardPayment = $scope.cart.UpdatedBooking.CreditCardPurchaseWithToken;
                        }
                    } else {
                        creditCardPayment = $scope.cart.UpdatedBooking.CreditCardPayment;
                    }

                    creditCardPayment && (creditCardPayment.Amount = $scope.depositAmountDue);
                }
                //
                ccPromise.then(function () {

                    $scope.cart.UpdatedBooking.CreditCardPayment = ($scope.isTempusPaymentProvider && !bookingHasDifferentPaymentProviderThanExisting) ? null : creditCardPayment;
                    $scope.cart.UpdatedBooking.CreditCardPurchaseWithToken = ($scope.isTempusPaymentProvider && !bookingHasDifferentPaymentProviderThanExisting) ? creditCardPayment : null;

                    $scope.cart.UpdatedBooking.ApplyOnlineCreditCardPayment = !$scope.model.payWithAR && !$scope.skipCC;
                    var data = {
                        "Booking": $scope.cart.UpdatedBooking,
                        "WaiveCxFees": true,
                        "DoNotSendDocuments": false,
                        "ConfirmationEmailOverride": !$scope.isAgent ? $scope.model.emailAddress : ""
                        // SendNewslettersAndPromotions: $scope.model.sendNewslettersAndPromotions
                    };

                    //data.ConfirmationEmailOverride = (!customer || $scope.canChangeConfirmationEmailAddress) ? $scope.model.emailAddress : (customer.email || $scope.model.emailAddress);
                    $scope.isLoading = true;
                    $scope.showLoadProcessOrderMsg = true;
                    // borgun 3ds verification
                    ((!$scope.ccReqForUpdate && Promise.resolve(1)) || (!creditCardPayment && Promise.resolve(1)) || $scope.Borgun3DSVerificationPromise(creditCardPayment.Amount, $scope.getCurrency())).then(function (verData) {
                        console.log("Borgun3DSVerificationPromise success", verData);
                        if (verData && typeof verData == "object") {
                            if (verData.MpiToken) {
                                creditCardPayment.MpiToken = verData.MpiToken;
                            } else {
                                creditCardPayment.PaResValidationResponse = verData;
                                creditCardPayment.MpiToken = $scope.MpiTokenTemp;
                            }
                        }

                        var requestParams = {
                            apiUrl: $scope.getWebUrl() + "/api/booking/update/",
                            token: jwtService.getPrincipalToken(),
                            bookingToPost: data
                        }
                        $scope.errors = [];

                        shoppingCartService.createBooking(requestParams, function (result) {
                            if (!result || (result.errors || "").length) {
                                //$scope.logDebugBookingError({                                    
                                //    response: result,
                                //    localComment: "Update booking - Create booking - error"
                                //});

                                $scope.errors = result && (result.errors || "").length ? result.errors : [{
                                    "errorMessage": "An error occurred."
                                }];
                            }
                            else
                                if (result.bookings) {
                                    var requiredModalInstance = $uibModal.open({
                                        animation: true,
                                        templateUrl: "bookingUpdateMsgPartial.html",
                                        controller: "bookingUpdateMsgCtrl",
                                        size: "book-required-products",
                                        resolve: {

                                        },
                                        backdrop: "true"
                                    });

                                    requiredModalInstance.result.then(function (result) {
                                        shoppingCartService.removeAllStoredData();
                                        window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
                                    }, function () {
                                        shoppingCartService.removeAllStoredData();
                                        window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
                                    });

                                    $scope.bookingUpdated = true;

                                }

                            $scope.isLoading = false;
                            $scope.showLoadProcessOrderMsg = false;
                        });
                    }).catch(function (error) {
                        console.log((error && error.message) || error);
                        $scope.inlineCC.errors = [];
                        $scope.inlineCC.errors.push("An error occurred!");

                        $scope.logDebugBookingError({
                            error: error,
                            localComment: "Update booking - Global catch error"
                        });

                        $scope.isLoading = false;
                        $scope.showLoadProcessOrderMsg = false;
                        try {
                            $timeout(function () { $scope.$apply(); });
                        } catch (e) {
                            console.log(e);
                        }
                    });
                    // borgun 3ds verification
                }, function (error) {
                    console.log(error);
                });
            };
            $scope.isGiftGivingEmailRequired = function (checkByGiftTicketsDirectly) {
                if (!$scope.giftGivingOptions.CartContainsGift || !$scope.cart || $scope.cart.shippingMethodRequired) return false;
                if (checkByGiftTicketsDirectly && $scope.giftGivingOptions.model.sendGiftTicketsDirectly) return false;

                return ($scope.giftGivingOptions.GiftCanBeEmailed && !$scope.giftGivingOptions.GiftCanBeMailed) || $scope.giftGivingOptions.model.giftCustomOption == 'email';
            };
            $scope.isGiftGivingMailRequired = function () {
                if (!$scope.giftGivingOptions.CartContainsGift || !$scope.cart || $scope.cart.shippingMethodRequired) return false;

                return (!$scope.giftGivingOptions.GiftCanBeEmailed && $scope.giftGivingOptions.GiftCanBeMailed) || $scope.giftGivingOptions.model.giftCustomOption == 'mail';
            };
            $scope.handleGiftGivingEmailPattern = (function () {
                var regex = /^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(\.[a-zA-Z]{2,10})$/;

                return {
                    test: function (value) {
                        if ($scope.isGiftGivingEmailRequired()) {
                            return ((value || "").length > 0) ? regex.test(value) : true;
                        } else {
                            return true;
                        }
                    }
                };
            })();

            $scope.isGiftGivingFieldsValid = function () {
                var isValid = true;

                var defaultObj = {
                    $invalid: false
                };
                isValid =
                    !($scope.checkOutForm.giftGiving_EmailOption_FirstName || defaultObj).$invalid &&
                    !($scope.checkOutForm.giftGiving_EmailOption_LastName || defaultObj).$invalid &&
                    !($scope.checkOutForm.giftGiving_EmailOption_Email || defaultObj).$invalid &&

                    !($scope.checkOutForm.giftGiving_MailOption_FirstName || defaultObj).$invalid &&
                    !($scope.checkOutForm.giftGiving_MailOption_LastName || defaultObj).$invalid &&
                    !($scope.checkOutForm.giftGiving_MailOption_Street || defaultObj).$invalid &&
                    !($scope.checkOutForm.giftGiving_MailOption_City || defaultObj).$invalid &&
                    !($scope.checkOutForm.giftGiving_MailOption_Country || defaultObj).$invalid &&
                    !($scope.checkOutForm.giftGiving_MailOption_StateProv || defaultObj).$invalid &&
                    !($scope.checkOutForm.giftGiving_MailOption_PostalCode || defaultObj).$invalid;

                return isValid;
            };
            //
            $scope.isDeliveryEmailRequired = function (checkByGiftTicketsDirectly) {

                if (!$scope.cart || !$scope.cart.shippingMethodRequired || !$scope.deliveryOptions.model.deliveryMethodUnit || !$scope.deliveryOptions.model.deliveryMethodUnit.giftGivingOptions.giftCanBeEmailed) {
                    return false;
                }

                if (checkByGiftTicketsDirectly && $scope.deliveryOptions.model.sendGiftTicketsDirectly) return false;

                return true;
            };

            $scope.isDeliveryMailRequired = function (checkByGiftTicketsDirectly) {
                if (!$scope.cart || !$scope.cart.shippingMethodRequired || !$scope.deliveryOptions.model.deliveryMethodUnit || !$scope.deliveryOptions.model.deliveryMethodUnit.giftGivingOptions.giftCanBeMailed) {
                    return false;
                }

                if (checkByGiftTicketsDirectly && $scope.deliveryOptions.model.sendGiftTicketsDirectly) return false;

                return true;
            };

            $scope.handleDeliveryEmailPattern = (function () {
                var regex = /^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(\.[a-zA-Z]{2,10})$/;

                return {
                    test: function (value) {
                        if ($scope.isDeliveryEmailRequired()) {
                            return ((value || "").length > 0) ? regex.test(value) : true;
                        } else {
                            return true;
                        }
                    }
                };
            })();

            $scope.isDeliveryValid = function () {
                if (!$scope.cart.shippingMethodRequired) return true;

                return $scope.cart.shippingMethodRequired && !!$scope.deliveryOptions.model.deliveryMethodUnit;
            };

            $scope.isDeliveryFieldsValid = function () {
                var isValid = true;

                var defaultObj = {
                    $invalid: false
                };
                isValid =
                    !($scope.checkOutForm.delivery_EmailOption_FirstName || defaultObj).$invalid &&
                    !($scope.checkOutForm.delivery_EmailOption_LastName || defaultObj).$invalid &&
                    !($scope.checkOutForm.delivery_EmailOption_Email || defaultObj).$invalid &&

                    !($scope.checkOutForm.delivery_MailOption_FirstName || defaultObj).$invalid &&
                    !($scope.checkOutForm.delivery_MailOption_LastName || defaultObj).$invalid &&
                    !($scope.checkOutForm.delivery_MailOption_Street || defaultObj).$invalid &&
                    !($scope.checkOutForm.delivery_MailOption_City || defaultObj).$invalid &&
                    !($scope.checkOutForm.delivery_MailOption_Country || defaultObj).$invalid &&
                    !($scope.checkOutForm.delivery_MailOption_StateProv || defaultObj).$invalid &&
                    !($scope.checkOutForm.delivery_MailOption_PostalCode || defaultObj).$invalid; //&&
                // !($scope.checkOutForm.delivery_MailOption_Phone || defaultObj).$invalid;


                return isValid;
            };
            //


            $scope.showConfirmModalIfMultipleProductsDetected = function () {
                var defaultResult = Promise.resolve(1);

                if (!$scope.cart || !($scope.cart.Items || "").length) return defaultResult;

                var hasSameProductMultipleTimes = false;
                var mapCartProductCodes = Object.create(null);

                _.each($scope.cart.Items, function (sitem, index) {
                    if (hasSameProductMultipleTimes) return;

                    if (mapCartProductCodes[sitem.ProductCode]) {
                        hasSameProductMultipleTimes = true;
                    } else {
                        mapCartProductCodes[sitem.ProductCode] = true;
                    }
                });
                if (!hasSameProductMultipleTimes) return defaultResult;

                var requiredModalInstance = $uibModal.open({
                    animation: true,
                    templateUrl: "expressConsentModal.html",
                    controller: "expressConsentModalCtrl",
                    size: "book-required-products",
                    resolve: {
                        "expressConsent": {
                            title: utilsFactory.getLabel("general.bookMultipleProductsModal.Title"),
                            message: utilsFactory.getLabel("general.bookMultipleProductsModal.Message"),
                            acceptLabel: utilsFactory.getLabel("general.bookMultipleProductsModal.Continue"),
                            declineLabel: utilsFactory.getLabel("general.bookMultipleProductsModal.Cancel")
                        }
                    },
                    backdrop: "true"
                });
                // "components": { followingProductSingle: "product", followingProductMultiple: "products", yourProductTitle: "attraction", data: popupProducts }

                return requiredModalInstance.result;
            };

            function showInfoModalIfCartPriceChangeDetected(isSubmit) {
                var defaultResult = Promise.resolve(1);

                // TODO: add timeout check
                if (!$scope.cart || !($scope.cart.Items || "").length) return defaultResult;

                var resultPromise = new Promise(function (resolve, reject) {
                    var requestParams = {
                        apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                        token: jwtService.getPrincipalToken(),
                        includeDiscountCodes: true
                    };
                    $scope.isLoading = true;

                    shoppingCartService.refreshQuote(requestParams, function (shoppingCart) {
                        $scope.isLoading = false;

                        if (shoppingCart && shoppingCart.Quote && $scope.cart && $scope.cart.Quote && shoppingCart.Quote.Price != $scope.cart.Quote.Price) {
                            $scope.cart = shoppingCart;
                            $scope.setCartCustomFields();
                            $scope.checkShippingMethodRequired($scope.cart);

                            var requiredModalInstance = $uibModal.open({
                                animation: true,
                                templateUrl: "cartPriceChangeModal.html",
                                controller: "cartPriceChangeModalCtrl",
                                size: "book-required-products",
                                resolve: {
                                    "priceChange": {
                                        title: utilsFactory.getLabel("general.shoppingcartPriceChangeModal.Title"),
                                        description: utilsFactory.getLabel("general.shoppingcartPriceChangeModal.Description"),
                                        showReviewBtn: isSubmit,
                                        acceptLabel: utilsFactory.getLabel("general.shoppingcartPriceChangeModal.Continue"),
                                        reviewLabel: utilsFactory.getLabel("general.shoppingcartPriceChangeModal.Review")
                                    }
                                },
                                backdrop: "true"
                            });
                            resolve(requiredModalInstance.result);

                            //initDisclaimersFromCart();
                            //$scope.getOptionalExtras();
                            //$scope.reloadCartOptions();
                            //$scope.setGiftCardsRedeemAmount();
                        } else {
                            if (shoppingCart && shoppingCart.Quote) {
                                $scope.cart = shoppingCart;
                                $scope.setCartCustomFields();
                                $scope.checkShippingMethodRequired($scope.cart);
                            }
                            resolve(1);
                        }
                    });

                    // "components": { followingProductSingle: "product", followingProductMultiple: "products", yourProductTitle: "attraction", data: popupProducts }

                    //return requiredModalInstance.result;
                });
                return resultPromise;
            };

            $scope.submitCheckOut = function (isValid) {
                $scope.inlineCC.errors = [];
                // don't display the exit intent modal
                $scope.wasExitModalShown = true;
                jwtService.setDisableExitIntent();

                if ($scope.cart.isUpdate) {
                    $scope.submitUpdate(isValid);
                    return;
                }

                var isShippingValid = !$scope.cart.shippingMethodRequired || ($scope.cart.shippingMethodRequired && !!$scope.deliveryOptions.model.deliveryMethodUnit);
                isValid = isValid && isShippingValid;

                if (isValid) {
                    showInfoModalIfCartPriceChangeDetected(true).then(function (shoppingCartPriceChangeResult) {
                        console.log("shoppingCartPriceChangeResult:", shoppingCartPriceChangeResult);
                        $scope.showConfirmModalIfMultipleProductsDetected().then(function () {

                            var generalCtrl = $scope.$parent;
                            $scope.isLoading = true;
                            $scope.showLoadProcessOrderMsg = true;

                            var createAccountPromise = undefined;
                            if ($scope.createAnAccount) {
                                createAccountPromise = new Promise(function (resolve, reject) {
                                    $scope.createAccountModel.errors = [];

                                    $scope.createAccountModel.firstName = $scope.model.travelerFirstName;// $scope.model.firstName;
                                    $scope.createAccountModel.lastName = $scope.model.travelerLastName;//$scope.model.lastName;
                                    $scope.createAccountModel.emailAddress = $scope.model.emailAddress;
                                    $scope.createAccountModel.emailAddress_c = $scope.model.emailAddress_c;
                                    $scope.createAccountModel.password = $scope.model.password;

                                    if (jwtService.getToken() == null) {
                                        // $scope.init();
                                        reject("Token is null");
                                        return;
                                    }


                                    $http({
                                        method: "POST",
                                        url: $scope.getWebUrl() + "/api/authentication/register",
                                        headers: {
                                            "Authorization": jwtService.getToken(),
                                            'Content-Type': "application/json"
                                        },
                                        data: {
                                            "Email": $scope.createAccountModel.emailAddress,
                                            "FirstName": $scope.createAccountModel.firstName,
                                            "LastName": $scope.createAccountModel.lastName,
                                            "Username": $scope.createAccountModel.emailAddress,
                                            "Password": $scope.createAccountModel.password
                                        }
                                    })
                                        .then(
                                            function (result) {
                                                if (result == null || result.data == null) {
                                                    $scope.createAccountModel.errors = [{ errorMessage: utilsFactory.getLabel("general.loginModal.registration.error") }];
                                                    reject();
                                                    return false;
                                                }

                                                if (result.data.token != null) {
                                                    var oldRegion = jwtService.getGeography();
                                                    jwtService.setCustomerToken(result.data, oldRegion);
                                                    $scope.isAuthenticated = true;
                                                    $scope.createAnAccount = false;
                                                    generalCtrl.initCustomerRecord(true);
                                                    //if ($scope.loginType === "checkout" && ($scope.cart && ($scope.cart.Items || "").length)) {
                                                    //    setTimeout(function () { window.location = "/checkout"; }, 3000);
                                                    //    return true;
                                                    //}
                                                    $scope.createAccountModel.response = utilsFactory.getLabel("general.loginModal.registration.success");
                                                    $scope.createAccountModel.error = [];
                                                    //  $scope.showModal['Login'] = false;                                      


                                                    resolve();
                                                    return;
                                                } else if (result.data.errors != null && result.data.errors.length > 0) {
                                                    $scope.createAccountModel.errors = result.data.errors;
                                                    reject();
                                                    return;
                                                }

                                                reject();
                                            },
                                            function (response) {

                                                if (response.data.errors && response.data.errors.length > 0) {
                                                    $scope.createAccountModel.errors = response.data.errors;
                                                } else {
                                                    $scope.createAccountModel.errors = [
                                                        {
                                                            "errorMessage": utilsFactory.getLabel("general.loginModal.registration.error")
                                                        }
                                                    ];
                                                }

                                                reject();
                                            });
                                });
                                // end create account
                            } else {
                                createAccountPromise = Promise.resolve(1);
                            }

                            createAccountPromise.then(function () {
                                $scope.addBorgunCardPromise().then(function () {

                                    jwtService.setCheckoutModel($scope.model);
                                    var customer = jwtService.getCustomer();

                                    var clients = [];
                                    var client = {
                                        "FirstName": $scope.model.travelerFirstName,
                                        "LastName": $scope.model.travelerLastName,
                                        "Email": $scope.isAgent ? $scope.model.travelerEmail : $scope.model.emailAddress,
                                        "Address": {
                                            "Street": $scope.model.travelerAddress,
                                            "City": $scope.model.travelerCity,
                                            "PostalCode": $scope.model.travelerZipCode,
                                            "Country": $scope.model.travelerCountry,
                                            "Province": $scope.model.travelerProvState
                                        },
                                        "CustomerId": null,
                                        "TravelerId": null,
                                        "CustomerNumber": null,
                                        "DateOfBirth": null,
                                        "AgeBracket": null,
                                        "Remarks": null,
                                        "Gender": null,
                                        "Title": null,
                                        "PhoneNumbers": [
                                            { "Type": "Home", "Number": null }, { "Type": "Mobile", "Number": null }, { "Type": "Emergency", "Number": null },
                                            { "Type": "Fax", "Number": null }
                                        ],
                                        "SalesChannel": null,
                                        "RateType": null,
                                        "Brand": null,
                                        "ARAllowed": false,
                                        "DocumentsToAgency": false,
                                        "DocumentsToCustomer": false,
                                        "FullName": $scope.model.travelerFirstName + " " + $scope.model.travelerLastName,
                                        "IsRTPMapped": false,
                                        "AgencyType": null,
                                        "CreditType": null,
                                        "IsAgency": false
                                    };

                                    if (($scope.model.travelerPhone || "").length) {
                                        var assigned = false;
                                        var phoneNumbers = _.map(!$scope.isAgent && customer ? customer.phoneNumbers : undefined, function (pn) {
                                            var phoneNumber = pn.number;
                                            if (pn.type === "Mobile") {
                                                phoneNumber = $scope.model.travelerPhone;
                                                assigned = true;
                                            }
                                            return { "Type": pn.type, "Number": phoneNumber };
                                        });
                                        if (!assigned) {
                                            var newPhone = { "Type": "Mobile", "Number": $scope.model.travelerPhone };
                                            if ((phoneNumbers || "").length) {
                                                phoneNumbers.push(newPhone);
                                            } else {
                                                phoneNumbers = [newPhone];
                                            }
                                        }
                                        client.PhoneNumbers = phoneNumbers;
                                    }

                                    if (!$scope.isAgent) {
                                        if (customer != null) {
                                            client["CustomerNumber"] = customer.customerNumber;
                                        }
                                    }

                                    clients.push(client);

                                    var components = [];
                                    var packages = [];

                                    var remarks = [];
                                    _.each($scope.specReqComps, function (spCmp) {
                                        if (spCmp.origComp && spCmp.origComp.BookingToQuote && (spCmp.roomRequest || "").length) {
                                            _.each(spCmp.origComp.BookingToQuote.Components, function (scomp) {
                                                scomp.Remarks = [{
                                                    "noteTypeCode": "BEDRQ",
                                                    "noteText": (spCmp.roomRequest || "")
                                                }];
                                            });
                                        }
                                        //if hotel package component
                                        if (spCmp.origComp && spCmp.origComp.isPackageComponent && (spCmp.roomRequest || "").length) {
                                            spCmp.origComp.Remarks = [{
                                                "noteTypeCode": "BEDRQ",
                                                "noteText": (spCmp.roomRequest || "")
                                            }];
                                        }

                                        if ((spCmp.specialRequest || "").length) {
                                            remarks.push({
                                                "noteTypeCode": "SPCRQ",
                                                "noteText": (spCmp.specialRequest || "")
                                            });
                                        }
                                        // var details = (spCmp.contactName || "") + " " + (spCmp.contactPhone || "") + " ";
                                        // details = details.trim().length ? details : "";

                                    });

                                    var assignedGuests = null;

                                    function getDateOfBirth(age) {
                                        //set the birthday to Jan.1 of the proper year 
                                        var dateOfBirth = new Date();
                                        //defaults to today 
                                        dateOfBirth.setFullYear(dateOfBirth.getFullYear() - (parseInt(age) || 0));
                                        dateOfBirth.setMonth(0);
                                        dateOfBirth.setDate(1);
                                        return moment(dateOfBirth).format("YYYY-MM-DD") + "T00:00:00";
                                    }

                                    function addGuest(guestList, pItem) {
                                        guestList.push({
                                            "CustomerId": null,
                                            "TravelerId": null,
                                            "CustomerNumber": pItem.id,
                                            "DateOfBirth": pItem.age ? getDateOfBirth(pItem.age) : "0001-01-01T00:00:00", //pItem.birthDate ? pItem.birthDate + "T00:00:00" : "0001-01-01T00:00:00",
                                            "AgeBracket": null,
                                            "Remarks": null,
                                            "Gender": null,
                                            "Title": null,
                                            "FirstName": pItem.firstName,
                                            "LastName": pItem.lastName,
                                            "Email": null,
                                            "Address": {
                                                "Street": null,
                                                "AdditionalInfo": null,
                                                "City": null,
                                                "Province": null,
                                                "PostalCode": ".",
                                                "POBox": null,
                                                "Country": null,
                                                "IsStreetAddress": false
                                            },
                                            "PhoneNumbers": [{ "Type": "Home", "Number": pItem.phone || null }, { "Type": "Mobile", "Number": null }, { "Type": "Emergency", "Number": null },
                                            { "Type": "Fax", "Number": null }],
                                            "SalesChannel": null,
                                            "RateType": null,
                                            "Brand": null,
                                            "ARAllowed": false,
                                            "DocumentsToAgency": false,
                                            "DocumentsToCustomer": false,
                                            "FullName": pItem.firstName + " " + pItem.lastName,
                                            "IsRTPMapped": false,
                                            "AgencyType": null,
                                            "CreditType": null,
                                            "IsAgency": false
                                        });
                                    }

                                    _.map($scope.cart.Items, function (item) {
                                        assignedGuests = null;

                                        if (item.BookingToQuote && item.BookingToQuote.Components) {
                                            assignedGuests = null;
                                            _.map(item.BookingToQuote.Components, function (component) {
                                                if (assignedGuests) {
                                                    component.ManuallyAssignedCustomers = assignedGuests;
                                                } else {
                                                    assignedGuests = [];
                                                    var pas = _.find($scope.passengerList, function (pas) { return pas.component && ((pas.component.Id && (pas.component.Id == component.Id)) || (pas.component.ProductCode == component.ProductCode && pas.component.UnitCode == component.UnitCode)); });
                                                    if (pas) {
                                                        if (!pas.adults.length) {
                                                            pas.adults.push({
                                                                id: "IBE1",
                                                                firstName: $scope.model.travelerFirstName,
                                                                lastName: $scope.model.travelerLastName,
                                                                isFirst: true
                                                            });
                                                        } else {
                                                            pas.adults[0].firstName = $scope.model.travelerFirstName;
                                                            pas.adults[0].lastName = $scope.model.travelerLastName;
                                                            pas.adults[0].phone = $scope.model.travelerPhone;
                                                            pas.adults[0].isFirst = true;
                                                        }

                                                        _.each(pas.adults, function (pAdult) {
                                                            // first guest should be main travel
                                                            if (pAdult.isFirst) {
                                                                // use the client
                                                                if (!client.CustomerNumber) {
                                                                    client.CustomerNumber = pAdult.id;
                                                                }
                                                                assignedGuests.push(client);
                                                            } else {
                                                                addGuest(assignedGuests, pAdult);
                                                                clients.push(assignedGuests[assignedGuests.length - 1]);
                                                            }
                                                        });
                                                        _.each(pas.children, function (pChild) { addGuest(assignedGuests, pChild); clients.push(assignedGuests[assignedGuests.length - 1]); });
                                                        _.each(pas.infants, function (pInfant) { addGuest(assignedGuests, pInfant); clients.push(assignedGuests[assignedGuests.length - 1]); });
                                                        component.ManuallyAssignedCustomers = assignedGuests;
                                                    }
                                                }
                                                //
                                                if (item.isShippingItem) {
                                                    component.Remarks = [{
                                                        "noteTypeCode": "SHIP",
                                                        "noteText": ($scope.deliveryOptions.model.deliveryInstructions || "")
                                                    }];
                                                }
                                                //
                                                components.push(component);
                                            });
                                            //
                                            //if((assignedGuests||'').length) {
                                            //    clients = assignedGuests; //clients.concat(assignedGuests);
                                            //}
                                        }
                                        if (item.BookingToQuote && item.BookingToQuote.Packages) {
                                            _.map(item.BookingToQuote.Packages, function (pkg) {
                                                assignedGuests = [];

                                                var pas = _.find($scope.passengerList, function (pas) { return pas.pck === pkg; });
                                                if (pas) {
                                                    if (!pas.adults.length) {
                                                        pas.adults.push({
                                                            id: "IBE1",
                                                            firstName: $scope.model.travelerFirstName,
                                                            lastName: $scope.model.travelerLastName,
                                                            isFirst: true
                                                        });
                                                    } else {
                                                        pas.adults[0].firstName = $scope.model.travelerFirstName;
                                                        pas.adults[0].lastName = $scope.model.travelerLastName;
                                                        pas.adults[0].isFirst = true;
                                                    }

                                                    _.each(pas.adults, function (pAdult) {
                                                        // first guest should be main travel
                                                        if (pAdult.isFirst) {
                                                            // use the client
                                                            if (!client.CustomerNumber) {
                                                                client.CustomerNumber = pAdult.id;
                                                            }
                                                            assignedGuests.push(client);
                                                        } else {
                                                            addGuest(assignedGuests, pAdult);
                                                            //if(.indexOf())
                                                            if (!_.contains(clients, assignedGuests[assignedGuests.length - 1])) {
                                                                clients.push(assignedGuests[assignedGuests.length - 1]);
                                                            }
                                                        }
                                                    });
                                                    _.each(pas.children, function (pChild) {
                                                        addGuest(assignedGuests, pChild);
                                                        if (!_.contains(clients, assignedGuests[assignedGuests.length - 1])) {
                                                            clients.push(assignedGuests[assignedGuests.length - 1]);
                                                        }
                                                    });
                                                    _.each(pas.infants, function (pInfant) {
                                                        addGuest(assignedGuests, pInfant);
                                                        if (!_.contains(clients, assignedGuests[assignedGuests.length - 1])) {
                                                            clients.push(assignedGuests[assignedGuests.length - 1]);
                                                        }
                                                    });
                                                    pkg.ManuallyAssignedCustomers = assignedGuests;
                                                }
                                                packages.push(pkg);
                                            });
                                        }
                                    });

                                    // add the extra components from the quote reponse in the create call
                                    if ($scope.cart.Quote && ($scope.cart.Quote.unassignedQuoteComponents || '').length > 0) {
                                        _.each($scope.cart.Quote.unassignedQuoteComponents, function (component) {
                                            components.push(component);
                                        });
                                    }
                                    //

                                    var isCustomer = jwtService.getCustomerToken();

                                    var creditCardPayment = {};

                                    if ($scope.selectedCreCard) {
                                        creditCardPayment.Amount = $scope.showCanPayAtHotel ? $scope.depositAmountDue : ($scope.cart.Quote.Price || 0);

                                        if (($scope.cart.GiftCards || "").length) {
                                            var giftCardAmount = _.reduce($scope.cart.GiftCards, function (memo, giftCard) { return memo + (giftCard.giftCardBalance || 0); }, 0);
                                            if (giftCardAmount > 0) {
                                                creditCardPayment.Amount -= giftCardAmount;
                                                creditCardPayment.Amount = creditCardPayment.Amount > 0 ? creditCardPayment.Amount : 0;
                                            }
                                        }

                                        if ($scope.isTempusPaymentProvider) {
                                            // new tempus payment provider                                            
                                            creditCardPayment.CardExpirationMonth = $scope.selectedCreCard.expirationMonth;
                                            creditCardPayment.CardExpirationYear = $scope.selectedCreCard.expirationYear;
                                            creditCardPayment.CardHolderName = $scope.selectedCreCard.cardHolderName;
                                            creditCardPayment.CardLastFour = $scope.selectedCreCard.cardNumber;
                                            creditCardPayment.CardToken = $scope.selectedCreCard.cardTokenValue;
                                            creditCardPayment.CardType = $scope.selectedCreCard.cardType;
                                            creditCardPayment.CustomerId = $scope.isAgent && $scope.selectedAgentContact && $scope.selectedAgentContact.customerId;
                                            creditCardPayment.PursuitBusinessId = $scope.selectedCreCard.pursuitBusinessId;

                                            creditCardPayment.IsMultiUseToken = !!(isCustomer && !$scope.selectedCreCard.doNotSaveCardToken);

                                            creditCardPayment.Is3ds = false;
                                            creditCardPayment.ThreeDsMpiToken = null;
                                        } else {
                                            if ($scope.displayInlineCCInput) {
                                                creditCardPayment.UseExistingCreditCardToken = false; // TODO: check
                                                creditCardPayment.CardTokenValue = $scope.selectedCreCard.cardTokenValue;

                                                if (isCustomer && !$scope.selectedCreCard.useAsAnonymous) {
                                                    if ($scope.selectedCreCard.doNotSaveCardToken) {
                                                        creditCardPayment.DoNotSaveCardToken = true;
                                                    } else {
                                                        creditCardPayment.UseExistingCreditCardToken = true;
                                                    }
                                                }
                                            } else {
                                                if (!isCustomer) {
                                                    creditCardPayment.CresecureHpfCallbackFullQueryParams = $scope.selectedCreCard.fullQuery;
                                                } else {
                                                    if ($scope.selectedCreCard.useAsAnonymous) {
                                                        creditCardPayment.CresecureHpfCallbackFullQueryParams = $scope.selectedCreCard.fullQuery;
                                                    } else {
                                                        if ($scope.selectedCreCard.doNotSaveCardToken && !$scope.selectedCreCard.value) {
                                                            creditCardPayment.DoNotSaveCardToken = true;
                                                            creditCardPayment.CresecureHpfCallbackFullQueryParams = $scope.selectedCreCard.fullQuery;
                                                        } else {
                                                            // if the user was new registred, and before that he entered a credit card, submit it as an anonymous user
                                                            if (!$scope.selectedCreCard.cardid) {
                                                                creditCardPayment.DoNotSaveCardToken = false;
                                                                creditCardPayment.CresecureHpfCallbackFullQueryParams = $scope.selectedCreCard.fullQuery;
                                                            } else {
                                                                creditCardPayment.UseExistingCreditCardToken = true;
                                                                creditCardPayment.ExistingCardId = $scope.selectedCreCard.cardid;
                                                            }
                                                        }
                                                    }
                                                }
                                            }



                                            //override values for travel agents
                                            if ($scope.showUseCustomerCard && $scope.model.useCustomerCard) {
                                                creditCardPayment.DoNotSaveCardToken = true;
                                            }

                                            //if ($scope.model.payAtHotel) {
                                            //    creditCardPayment.DoNotSaveCardToken = false;
                                            //}
                                        }// other payment providers
                                    } else {
                                        //Pay with Accounts Receivable
                                        creditCardPayment = null;
                                    }

                                    var giftCards = [];
                                    if (($scope.cart.GiftCards || "").length) {
                                        $scope.setGiftCardsRedeemAmount();
                                        giftCards = _.map($scope.cart.GiftCards, function (giftCard) {
                                            return {
                                                "GiftCardProvider": giftCard.giftCardProvider,
                                                "GiftCardID": giftCard.giftCardID,
                                                "RedemptionAmount": giftCard.redeemAmount
                                            };
                                        });
                                    }

                                    var booking = {
                                        "Currency": $scope.cart.Quote.Currency,
                                        "Components": components,
                                        "Packages": packages,
                                        "Remarks": remarks,
                                        "Customers": clients,
                                        "ApplyOnlineCreditCardPayment": !$scope.model.payWithAR && !$scope.skipCC,
                                        "CreditCardPayment": $scope.isTempusPaymentProvider ? null : creditCardPayment,
                                        "CreditCardPurchaseWithToken": $scope.isTempusPaymentProvider ? creditCardPayment : null,
                                        "DiscountCodes": $scope.cart.DiscountCodes,
                                        "GiftCardPayments": giftCards
                                    };

                                    if ($scope.isAgent && $scope.selectedAgentContact) {
                                        booking.Agency = {
                                            "AgencyContact": {
                                                "CustomerId": $scope.selectedAgentContact.customerId,
                                                "CustomerNumber": $scope.selectedAgentContact.customerNumber,
                                                "FirstName": $scope.selectedAgentContact.firstName,
                                                "LastName": $scope.selectedAgentContact.lastName
                                            }
                                        }
                                    }

                                    var giftRecipientDetails = null;
                                    if ($scope.cart.shippingMethodRequired) {
                                        var dateFormat = "YYYY-MM-DD";
                                        if ($scope.deliveryOptions.model.deliveryMethodUnit && $scope.deliveryOptions.model.deliveryMethodUnit.giftGivingOptions.giftCanBeEmailed) {
                                            var date = $("#deliveryEmailDate").val();
                                            //var time = $("#deliveryEmailTime").val();
                                            var formattedDate = moment(date, shoppingCartService.getDateFormat()).format(dateFormat);
                                            formattedDate = formattedDate + "T00:00:00";

                                            //var timeMoment = moment(time, ["h:mm A"]);
                                            //if (timeMoment.isValid()) {
                                            //   formattedDate = formattedDate + "T" + timeMoment.format("HH:mm:00");
                                            // }

                                            giftRecipientDetails = {
                                                "SendViaEmail": true,
                                                "SendViaMail": false,
                                                "FirstName": $scope.deliveryOptions.model.firstName,
                                                "LastName": $scope.deliveryOptions.model.lastName,
                                                "EmailAddress": $scope.deliveryOptions.model.sendGiftTicketsDirectly ? $scope.model.emailAddress : $scope.deliveryOptions.model.email,
                                                "StreetAddress": null,
                                                "City": null,
                                                "Province": null,
                                                "Country": null,
                                                "PostalCode": null,
                                                "RequestedDeliveryDate": $scope.deliveryOptions.model.sendGiftTicketsDirectly ? null : formattedDate,
                                                "CustomMessageForRecipient": $scope.deliveryOptions.model.sendGiftTicketsDirectly ? null : $scope.deliveryOptions.model.customMessage
                                            };
                                        } else if ($scope.deliveryOptions.model.deliveryMethodUnit && $scope.deliveryOptions.model.deliveryMethodUnit.giftGivingOptions.giftCanBeMailed) {
                                            giftRecipientDetails = {
                                                "SendViaEmail": false,
                                                "SendViaMail": true,
                                                "FirstName": $scope.deliveryOptions.model.sendGiftTicketsDirectly ? $scope.model.travelerFirstName : $scope.deliveryOptions.model.firstName,
                                                "LastName": $scope.deliveryOptions.model.sendGiftTicketsDirectly ? $scope.model.travelerLastName : $scope.deliveryOptions.model.lastName,
                                                "EmailAddress": null,
                                                "StreetAddress": $scope.deliveryOptions.model.sendGiftTicketsDirectly ? $scope.model.travelerAddress : $scope.deliveryOptions.model.streetAddress,
                                                "City": $scope.deliveryOptions.model.sendGiftTicketsDirectly ? $scope.model.travelerCity : $scope.deliveryOptions.model.city,
                                                "Province": $scope.deliveryOptions.model.sendGiftTicketsDirectly ? $scope.model.travelerProvState : $scope.deliveryOptions.model.stateProv || null,
                                                "Country": $scope.deliveryOptions.model.sendGiftTicketsDirectly ? $scope.model.travelerCountry : $scope.deliveryOptions.model.country,
                                                "PostalCode": $scope.deliveryOptions.model.sendGiftTicketsDirectly ? $scope.model.travelerZipCode : $scope.deliveryOptions.model.postalCode,
                                                "RequestedDeliveryDate": null,
                                                "CustomMessageForRecipient": $scope.deliveryOptions.model.sendGiftTicketsDirectly ? null : $scope.deliveryOptions.model.customMessage
                                                //"Phone": $scope.deliveryOptions.model.sendGiftTicketsDirectly ? $scope.model.travelerPhone : $scope.deliveryOptions.model.phone,
                                            };
                                        }
                                    } else if ($scope.giftGivingOptions.CartContainsGift) {
                                        var dateFormat = "YYYY-MM-DD";

                                        var isEmail = ($scope.giftGivingOptions.GiftCanBeEmailed && !$scope.giftGivingOptions.GiftCanBeMailed) || $scope.giftGivingOptions.model.giftCustomOption == 'email';
                                        if (isEmail) {
                                            var date = $("#giftGivingEmailDate").val();

                                            giftRecipientDetails = {
                                                "SendViaEmail": true,
                                                "SendViaMail": false,
                                                "FirstName": $scope.giftGivingOptions.model.firstName,
                                                "LastName": $scope.giftGivingOptions.model.lastName,
                                                "EmailAddress": $scope.giftGivingOptions.model.sendGiftTicketsDirectly ? $scope.model.emailAddress : $scope.giftGivingOptions.model.email,
                                                "StreetAddress": null,
                                                "City": null,
                                                "Province": null,
                                                "Country": null,
                                                "PostalCode": null,
                                                "RequestedDeliveryDate": $scope.giftGivingOptions.model.sendGiftTicketsDirectly ? null : moment(date, shoppingCartService.getDateFormat()).format(dateFormat),
                                                "CustomMessageForRecipient": $scope.giftGivingOptions.model.sendGiftTicketsDirectly ? null : $scope.giftGivingOptions.model.customMessage
                                            };
                                        } else {
                                            giftRecipientDetails = {
                                                "SendViaEmail": false,
                                                "SendViaMail": true,
                                                "FirstName": $scope.giftGivingOptions.model.firstName,
                                                "LastName": $scope.giftGivingOptions.model.lastName,
                                                "EmailAddress": null,
                                                "StreetAddress": $scope.giftGivingOptions.model.streetAddress,
                                                "City": $scope.giftGivingOptions.model.city,
                                                "Province": $scope.giftGivingOptions.model.stateProv || null,
                                                "Country": $scope.giftGivingOptions.model.country,
                                                "PostalCode": $scope.giftGivingOptions.model.postalCode,
                                                "RequestedDeliveryDate": null,
                                                "CustomMessageForRecipient": null
                                            };
                                        }
                                    }

                                    var data = {
                                        "ExpressConsentGivenForEmailMarketing": $scope.isConsentGiven || $scope.checkoutEmailMarketingConsentChk || false,
                                        "ExpressConsentSource": $scope.isConsentGiven ? "pursuit rewards" : ($scope.checkoutEmailMarketingConsentChk ? "checkout" : null),
                                        "Booking": booking,
                                        "GiftRecipientDetails": giftRecipientDetails
                                        // SendNewslettersAndPromotions: $scope.model.sendNewslettersAndPromotions
                                    };

                                    data.ConfirmationEmailOverride = (!customer || $scope.canChangeConfirmationEmailAddress) ? $scope.model.emailAddress : (customer.email || $scope.model.emailAddress);
                                    if ($scope.externalReferenceNumber) {
                                        data.ExternalReferenceNumber = $scope.externalReferenceNumber;
                                        booking.ExternalReferenceNumber = $scope.externalReferenceNumber;
                                    }

                                    var requestParams = {
                                        apiUrl: ($("body").data("weburl") ? $("body").data("weburl") : "") + "/api/booking/create/",
                                        token: jwtService.getPrincipalToken(),
                                        bookingToPost: data
                                    }

                                    $scope.isLoading = true;
                                    (!creditCardPayment && Promise.resolve(1) || $scope.Borgun3DSVerificationPromise(creditCardPayment.Amount, $scope.getCurrency())).then(function (data) {
                                        console.log("Borgun3DSVerificationPromise success", data);
                                        if (data && typeof data == "object") {
                                            if (data.MpiToken) {
                                                creditCardPayment.MpiToken = data.MpiToken;
                                            } else {
                                                creditCardPayment.PaResValidationResponse = data;
                                                creditCardPayment.MpiToken = $scope.MpiTokenTemp;
                                            }
                                        }
                                        //return; //TODO remove
                                        //

                                        var startBookingCreateTime = new Date().getTime();

                                        shoppingCartService.createBooking(requestParams, function (result) {
                                            //
                                            // Get the current timestamp again after your code or operations
                                            var endBookingCreateTime = new Date().getTime();

                                            // Calculate the time difference in milliseconds
                                            var elapsedTime = endBookingCreateTime - startBookingCreateTime;

                                            // Convert the elapsed time to seconds if needed
                                            var elapsedSeconds = elapsedTime / 1000;
                                            //

                                            if (result && (result.bookings || "").length) {

                                                shoppingCartService.setBooking(result.bookings, $scope.model.emailAddress, function (bookingOrder) {

                                                    if (bookingOrder) {
                                                        jwtService.getCheckoutModel(true);
                                                        window.location.href = utilsFactory.addPersistentQueryStringsParams("/printorder");
                                                    } else {
                                                        $scope.isLoading = false;
                                                        $scope.showLoadProcessOrderMsg = false;
                                                        $scope.inlineCC.errors = [];
                                                        // $scope.inlineCC.errors.push("An error occurred!");
                                                        try {
                                                            $timeout(function () { $scope.$apply(); });
                                                        } catch (e) {
                                                            console.log(e);
                                                        }
                                                    }

                                                });
                                            } else {
                                                //
                                                $scope.logDebugBookingError({
                                                    api: "/api/booking/create/",
                                                    // postData: requestParams,
                                                    result: result,
                                                    requestElapsedSeconds: elapsedSeconds,
                                                    localComment: "Create booking API failed"
                                                });
                                                //
                                                $scope.isLoading = false;
                                                $scope.showLoadProcessOrderMsg = false;
                                                $scope.inlineCC.errors = [];
                                                //$scope.inlineCC.errors.push("An error occurred!");
                                                try {
                                                    $timeout(function () { $scope.$apply(); });
                                                } catch (e) {
                                                    console.log(e);
                                                }
                                            }
                                        });
                                        // 
                                    }).catch(function (error) {
                                        console.log((error && error.message) || error);
                                        $scope.inlineCC.errors = [];
                                        $scope.inlineCC.errors.push("An error occurred!");

                                        $scope.logDebugBookingError({
                                            error: error,
                                            localComment: "Create booking - Global catch error"
                                        });

                                        $scope.isLoading = false;
                                        $scope.showLoadProcessOrderMsg = false;
                                        try {
                                            $timeout(function () { $scope.$apply(); });
                                        } catch (e) {
                                            console.log(e);
                                        }
                                    });

                                }, function (error) {
                                    console.log((error && error.message) || error);
                                    $scope.isLoading = false;
                                    $scope.showLoadProcessOrderMsg = false;
                                }).catch(function (error) {
                                    console.log((error && error.message) || error);
                                    $scope.isLoading = false;
                                    $scope.showLoadProcessOrderMsg = false;
                                })
                            }, function (error) {
                                console.log((error && error.message) || error);
                                $scope.isLoading = false;
                                $scope.showLoadProcessOrderMsg = false;
                            }).catch(function (error) {
                                console.log((error && error.message) || error);
                                $scope.isLoading = false;
                                $scope.showLoadProcessOrderMsg = false;
                            });
                        });
                    }).catch(function (shoppingCartPriceChangeReason) {
                        console.log("shoppingCartPriceChangeReason:", shoppingCartPriceChangeReason);
                    });
                } // is valid

                $scope.submitted = true;
                resizeSliderPanel();
            };

            $scope.complete3DSVerification = function (PaRes, CRes) {
                $scope.logDebugBorgun3dsCallback(PaRes, CRes);

                $scope.preventLoadingFalseOnBorgunModalClose = true;
                $scope.showModal["Borgun3DSVerification"] = false;
                if ($scope.borgunPromiseResolver) {
                    //
                    var postParams = {
                        urlPrefix: ($("body").data("weburl") ? $("body").data("weburl") : ""),
                        token: jwtService.getPrincipalToken(),
                        PaRes: PaRes,
                        CRes: CRes
                    };
                    borgunPaymentService.borgunPaResValidationRequestFor3DSecure(postParams, function (postResult) {
                        console.log("borgunPaResValidationRequestFor3DSecure result: ", postResult);

                        var resultData = postResult.data && postResult.data.data;
                        if (postResult.success && resultData && resultData.MdStatus && resultData.MdStatus != 0 && resultData.MdStatus != 8) {
                            $scope.borgunPromiseResolver.resolve(resultData);
                        } else {
                            // display error
                            $scope.borgunPromiseResolver.reject(resultData);

                            $scope.logDebugBookingError({
                                api: "/api/paymentborgun/borgunparesvalidation",
                                postData: postParams,
                                result: resultData || postResult,
                                localComment: "Complete3DSVerification - An error occurred! Check resultData.MdStatus!=0&&resultData.MdStatus!=8"
                            });
                        }
                    });
                    //
                } else {
                    $scope.isLoading = false;
                }
            };

            $scope.logDebugBorgun3dsCallback = function (PaRes, CRes) {
                if (true) { // enable later !PaRes
                    $http({
                        method: "POST",
                        url: ($("body").data("weburl") ? $("body").data("weburl") : "") + "/api/debug/borgun3dscallback",
                        // headers: { "Authorization": params.token },
                        data: {
                            GuestFirstName: $scope.model.travelerFirstName,
                            GuestLastName: $scope.model.travelerLastName,
                            GuestEmail: $scope.isAgent ? $scope.model.travelerEmail : $scope.model.emailAddress,
                            MpiToken: $scope.MpiTokenTemp,
                            PaRes: PaRes,
                            CRes: CRes
                        }
                    }).then(
                        function (res) {
                            console.log("log success: ", res);
                        },
                        function (response) {
                            console.log("log error: ", response);
                        }
                    );
                }
            };

            $scope.logDebugBookingError = function (datadump) {
                try {
                    $http({
                        method: "POST",
                        url: ($("body").data("weburl") ? $("body").data("weburl") : "") + "/api/debug/frontendbookingerror",
                        // headers: { "Authorization": params.token },
                        data: {
                            GuestFirstName: $scope.model.travelerFirstName,
                            GuestLastName: $scope.model.travelerLastName,
                            GuestEmail: $scope.isAgent ? $scope.model.travelerEmail : $scope.model.emailAddress,
                            DataDump: datadump && JSON.stringify(datadump)
                        }
                    }).then(
                        function (res) {
                            console.log("log success: ", res);
                        },
                        function (response) {
                            console.log("log error: ", response);
                        }
                    );

                } catch (e) {
                    console.error(e);
                }

            };

            $scope.createAnAccountChanged = function () {
                $scope.createAccountModel.submitted = false;
                $scope.createAccountModel.errors = [];
            };

            $scope.createAnAccountClick = function () {
                $scope.createAccountModel.submitted = false;
                $scope.createAccountModel.errors = [];

                $scope.createAccountModel.firstName = $scope.model.travelerFirstName;// $scope.model.firstName;
                $scope.createAccountModel.lastName = $scope.model.travelerLastName;//$scope.model.lastName;
                $scope.createAccountModel.emailAddress = $scope.model.emailAddress;
                $scope.createAccountModel.emailAddress_c = $scope.model.emailAddress_c;

                $scope.showModal["CreateAccount"] = $scope.showModal["CreateAccount"] === null ? false : !$scope.showModal["CreateAccount"];
            };

            $scope.getChildMinAge = function () {

            };

            $scope.toggleInlineCC = function () {
                $scope.displayInlineCC = !($scope.displayInlineCC || false);
                $scope.selectedCreCard = undefined;
                //setTimeout(function () {
                //    refreshInputs("#InlineCreditCardContainer");
                //});
            };

            $scope.addBorgunCardPromise = function () {
                if ($scope.isTempusPaymentProvider || !$scope.displayInlineCCInput || (!$scope.displayInlineCC && $scope.getCreditCards().length > 0)) {
                    return Promise.resolve(1);
                }

                var isCCShownOnPage = (!$scope.skipCC && ($scope.cart.isUpdate && $scope.ccReqForUpdate || !$scope.cart.isUpdate));
                var isCardFilled = ($scope.model.cardNumber || '').toString().length;

                if (!isCCShownOnPage || !isCardFilled) {
                    return Promise.resolve(1);
                }

                var resultPromise = new Promise(function (resolve, reject) {
                    var hasErrors = false;
                    $scope.inlineCC.errors = [];

                    if (BAPIjs.isValidCardNumber(($scope.model.cardNumber || '').toString()) === false) {
                        $scope.inlineCC.errors.push($scope.labelUtils.getLabel("checkout.validation.card-invalid"));
                        hasErrors = true;
                    }
                    if (BAPIjs.isValidExpDate(($scope.model.expirationMonth || '').toString(), ($scope.model.expirationYear || '').toString()) === false) {
                        $scope.inlineCC.errors.push($scope.labelUtils.getLabel("checkout.validation.expiry-date"));
                        hasErrors = true;
                    }
                    if (BAPIjs.isValidCVC(($scope.model.cvcCode || '').toString()) === false) {
                        $scope.inlineCC.errors.push($scope.labelUtils.getLabel("checkout.validation.cvc-invalid"));
                        hasErrors = true;
                    }

                    if (hasErrors) { reject("CC validation not passed"); return; }
                    // $scope.isLoading = true;
                    //  $scope.showLoadValidCardMsg = true;
                    // The function that parses the response from Borgun.
                    var borgunResponseHandler = function (status, data) {


                        if (status.statusCode === 201) {
                            $scope.model.cardNumber = undefined;
                            $scope.model.expirationMonth = undefined;
                            $scope.model.expirationYear = undefined;
                            $scope.model.cvcCode = undefined;

                            // start
                            var tempCard = {
                                cardNumber: data.PAN,
                                expirationMonth: data.ExpMonth,
                                expirationYear: data.ExpYear,
                                enabled: data.Enabled,
                                used: data.Used,
                                cardTokenValue: data.Token,
                                validUntil: data.ValidUntil
                            };

                            if ($scope.model.useCustomerCard) {
                                tempCard.doNotSaveCardToken = {
                                    value: false
                                };
                                tempCard.isTemp = true;
                            }

                            var customerToken = jwtService.getCustomerToken();
                            if (customerToken && !$scope.model.useCustomerCard) {
                                // $scope.isLoading = true;
                                //$scope.showLoadValidCardMsg = true;
                                try {
                                    //try to persist card against user profile
                                    var postParams = {
                                        urlPrefix: ($("body").data("weburl") ? $("body").data("weburl") : ""),
                                        token: jwtService.getCustomerToken(),
                                        cardToken: tempCard.cardTokenValue
                                    }

                                    borgunPaymentService.postCreditCard(postParams, function (postResult) {
                                        if (postResult.success && postResult.data && postResult.data.length > 0) {
                                            //data.push(postResult.data[0]);

                                            $scope.creCards = _.union([], postResult.data);
                                            $scope.ensureCreditCardId();
                                            var selectedCard = _.find($scope.creCards, function (cc) {
                                                return cc.cardCreated;
                                            });
                                            $scope.changedCurrentCard(selectedCard ? selectedCard : $scope.creCards[0]);
                                            resolve();
                                        } else {
                                            // data.push(tempCard);
                                            $scope.creCards.push(tempCard);
                                            $scope.ensureCreditCardId();
                                            //   $scope.creCards = data;
                                            $scope.changedCurrentCard(tempCard);
                                            resolve();
                                            // reject("CC validation not passed");
                                        }
                                        //   $scope.isLoading = false;
                                        //   $scope.showLoadValidCardMsg = false;
                                    });
                                } catch (e) {
                                    data.push(tempCard);

                                    $scope.creCards = [].pushdata;
                                    $scope.ensureCreditCardId();
                                    $scope.selectedCreCard = tempCard;


                                    _.each($scope.creCards, function (val, index) {
                                        val.index = index;
                                    });
                                    resolve();
                                    // $scope.isLoading = false;
                                    //  $scope.showLoadValidCardMsg = false;
                                }
                            } else {
                                $scope.creCards.push(tempCard);
                                $scope.ensureCreditCardId();

                                $scope.selectedCreCard = tempCard;
                                $scope.changedCurrentCard(tempCard);

                                _.each($scope.creCards, function (val, index) {
                                    val.index = index;
                                });
                                //$scope.isLoading = false;
                                // $scope.showLoadValidCardMsg = false;
                                resolve();
                            }

                            // end
                        } else if (status.statusCode === 401) {
                            console.log(status.statusCode + " " + status.message);
                            $scope.inlineCC.errors.push("An error occurred! " + (status.message || ''));
                            reject("cc error - 401");
                            // Unauthorized                   
                            // $scope.isLoading = false;
                            //  $scope.showLoadValidCardMsg = false;
                        } else if (status.statusCode) {
                            console.log(status.statusCode + " " + status.message);
                            $scope.inlineCC.errors.push("An error occurred! " + (status.message || ''));
                            reject("CC validation not passed");
                            //  $scope.isLoading = false;
                            // $scope.showLoadValidCardMsg = false;
                        } else {
                            console.log(status.statusCode + " " + status.message);
                            $scope.inlineCC.errors.push("An error occurred! " + (status.message || ''));
                            reject("CC validation not passed");
                            // $scope.isLoading = false;
                            //  $scope.showLoadValidCardMsg = false;
                        }
                    };

                    // Disable Pay button.
                    // $('.submit-button').prop("disabled", true);
                    // Request single use token from Borgun.
                    BAPIjs.getToken({
                        'pan': $scope.model.cardNumber,
                        'expMonth': $scope.model.expirationMonth,
                        'expYear': $scope.model.expirationYear,
                        'cvc': $scope.model.cvcCode,
                        'tokenLifetime': 600
                    }, borgunResponseHandler);

                    // $scope.selectedCreCard = undefined;
                    //$scope.model.cardNumber = "";
                    //$scope.model.expirationMonth = "";
                    //$scope.model.expirationYear = "";
                    //$scope.model.cvcCode = "";
                    $scope.addCartSubmitted = true;
                });

                return resultPromise;
            };

            $scope.borgun3DSVerificationModalHide = function () {
                if ($scope.preventLoadingFalseOnBorgunModalClose) return;
                console.log("borgun: on modal trigger hide");
                $scope.isLoading = false;
                try {
                    $timeout(function () { $scope.$apply(); });
                } catch (e) {
                    console.log(e);
                }
            };

            $scope.Borgun3DSVerificationPromise = function (purchAmount, currency) {
                var isEnabledBorgun3DSCheck = $scope.anonymUser && $scope.anonymUser.enableBorgun3DSCheck;

                if (!isEnabledBorgun3DSCheck || !$scope.displayInlineCCInput || !$scope.selectedCreCard || !$scope.selectedCreCard.cardTokenValue) {
                    return Promise.resolve(1);
                }

                var isCCShownOnPage = (!$scope.skipCC && ($scope.cart.isUpdate && $scope.ccReqForUpdate || !$scope.cart.isUpdate));

                if (!isCCShownOnPage) {
                    return Promise.resolve(1);
                }

                $scope.preventLoadingFalseOnBorgunModalClose = false;
                var resultPromise = new Promise(function (resolve, reject) {
                    $scope.borgunPromiseResolver = { resolve: resolve, reject: reject };

                    var isCustomer = jwtService.getCustomerToken();

                    var postParams = {
                        urlPrefix: ($("body").data("weburl") ? $("body").data("weburl") : ""),
                        token: jwtService.getPrincipalToken(),
                        termUrl: $($element).attr("data-borgun3DSCallbackUrl"),
                        cardToken: $scope.selectedCreCard.cardTokenValue,
                        purchAmount: Math.ceil(purchAmount),
                        currency: currency,
                        isTokenMulti: (isCustomer && !$scope.selectedCreCard.doNotSaveCardToken) // $scope.isSkylagoon() ||
                    }
                    borgunPaymentService.borgun3DSCheck(postParams, function (postResult) {
                        var resultData = postResult && postResult.data && postResult.data.data;
                        if (!resultData || !postResult.success) {
                            $scope.logDebugBookingError({
                                api: "/api/paymentborgun/borgun3dscheck",
                                postData: postParams,
                                result: resultData || postResult,
                            });

                            reject("An error occurred!");
                            return;
                        }

                        console.log("borgun3DSCheck", postResult);

                        if (resultData.MdStatus === "9") { // 
                            if (resultData.RedirectToACSForm) {
                                $scope.MpiTokenTemp = resultData.MpiToken;
                                // $('#Borgun3DSecureiFrameContainer').html("<div id='clickToContinueBorgunModal' class='text-center' style='display:none'>" + $scope.labelUtils.getLabel("checkout.borgunModalCCVerification.ClickBtnToContinueMsg") + "</div>");
                                $('#Borgun3DSiFrame').remove();
                                var iframe = jQuery("<iframe id='Borgun3DSiFrame' width='100%' height='500px'></iframe>");
                                var frameContentLoadedException = false;

                                iframe.load(function () {
                                    // jQuery("#clickToContinueBorgunModal").show();

                                    if (frameContentLoadedException) {
                                        jQuery(this).contents().find('body').html(resultData.RedirectToACSForm);
                                    }
                                });

                                iframe.appendTo('#Borgun3DSecureiFrameContainer');

                                try {
                                    if (iframe[0] && iframe[0].contentWindow && iframe[0].contentWindow.document) {
                                        var doc = iframe[0].contentWindow.document;
                                        doc.open();
                                        doc.write(resultData.RedirectToACSForm);
                                        doc.close();
                                    } else {
                                        frameContentLoadedException = true;
                                    }
                                } catch (e) {
                                    console.log(e);
                                    frameContentLoadedException = true;
                                }


                                //$('#Borgun3DSecureiFrameContainer').html("<iframe id='Borgun3DSiFrame' width='100%' height='500px'></iframe>");
                                //$('#Borgun3DSiFrame').contents().find('body').append(resultData.RedirectToACSForm);
                                $scope.showModal["Borgun3DSVerification"] = true;
                            } else {
                                reject("RedirectToACSForm is null");
                                $scope.logDebugBookingError({
                                    api: "/api/paymentborgun/borgun3dscheck",
                                    postData: postParams,
                                    result: resultData || postResult,
                                    localComment: "RedirectToACSForm is null"
                                });
                            }
                        }// status==9   
                        else if (resultData.MdStatus === "50") { // LEGACY: shouldn't be triggered
                            if (resultData.TdsMethodContent) {
                                $scope.MpiTokenTemp = resultData.MpiToken;
                                //$('#Borgun3DSecureiFrameContainer').html(resultData.TdsMethodContent);
                                $('#Borgun3DSecureiFrameContainer').html(resultData.TdsMethodContent + "<div id='loadingBorgunVerModal' style='margin-top:150px;margin-bottom:20px'>Please wait...</div>");

                                //var iframe = jQuery("<iframe id='Borgun3DSiFrame' width='100%' height='500px'></iframe>");
                                //iframe.load(function () {
                                //    jQuery("#loadingBorgunVerModal").remove();
                                //    jQuery(this).contents().find('body').html(resultData.TdsMethodContent);
                                //});
                                //iframe.appendTo('#Borgun3DSecureiFrameContainer');                                

                                $scope.showModal["Borgun3DSVerification"] = true;
                                console.log({
                                    XId: resultData.XId,
                                    TxId: resultData.TxId
                                });

                                setTimeout(function () {
                                    console.log("second enrollment");
                                    BAPIjs.requestSecondEnrollment({
                                        XId: resultData.XId,
                                        TxId: resultData.TxId
                                    }, function (status, secondData) {
                                        console.log("requestSecondEnrollment: ", status, secondData);

                                        $scope.showModal["Borgun3DSVerification"] = false;

                                        if (secondData.MdStatus === "9") { //
                                            if (secondData.RedirectToACSForm) {

                                                $('#Borgun3DSecureiFrameContainer').html("<div id='loadingBorgunVerModal'>Loading...</div>");
                                                $('#Borgun3DSiFrame').remove();
                                                var iframe = jQuery("<iframe id='Borgun3DSiFrame' width='100%' height='500px'></iframe>");
                                                iframe.load(function () {
                                                    jQuery("#loadingBorgunVerModal").remove();
                                                    jQuery(this).contents().find('body').html(secondData.RedirectToACSForm);
                                                });
                                                iframe.appendTo('#Borgun3DSecureiFrameContainer');
                                                //$('#Borgun3DSecureiFrameContainer').html("<iframe id='Borgun3DSiFrame' width='100%' height='500px'></iframe>");
                                                //$('#Borgun3DSiFrame').contents().find('body').append(resultData.RedirectToACSForm);
                                                $scope.showModal["Borgun3DSVerification"] = true;
                                            } else {
                                                reject("RedirectToACSForm is null");
                                                $scope.logDebugBookingError({
                                                    api: "/api/paymentborgun/borgun3dscheck",
                                                    postData: postParams,
                                                    result: resultData || postResult,
                                                    localComment: "Second enrollment - RedirectToACSForm is null! Check Second Enrollment Response",
                                                    secondEnrollmentResponse: secondData
                                                });
                                            }
                                        } else if (secondData && secondData.MdStatus !== "0" && secondData.MdStatus !== "8") {
                                            resolve(resultData.MpiToken && { MpiToken: resultData.MpiToken, Borgun3DSCheckMdStatus: 1 });
                                        }
                                        else {
                                            reject("An error occurred! Second Enrollment Response: " + secondData);
                                            $scope.logDebugBookingError({
                                                api: "/api/paymentborgun/borgun3dscheck",
                                                postData: postParams,
                                                result: resultData || postResult,
                                                localComment: "Second enrollment - An error occurred! Check Second Enrollment Response",
                                                secondEnrollmentResponse: secondData
                                            });
                                        }
                                    });
                                }, 6000);

                            } else {
                                reject("TdsMethodContent is null");
                                $scope.logDebugBookingError({
                                    api: "/api/paymentborgun/borgun3dscheck",
                                    postData: postParams,
                                    result: resultData || postResult,
                                    localComment: "TdsMethodContent is null"
                                });
                            }
                        } else if (resultData.MdStatus && resultData.MdStatus !== "0" && resultData.MdStatus !== "8") { // resultData.MdStatus === "1"
                            resolve(resultData.MpiToken && { MpiToken: resultData.MpiToken, Borgun3DSCheckMdStatus: 1 });
                        }
                        else {
                            reject("An error occurred! MDStatus is " + resultData.MdStatus);
                            $scope.logDebugBookingError({
                                api: "/api/paymentborgun/borgun3dscheck",
                                postData: postParams,
                                result: resultData || postResult,
                                localComment: "An error occurred! MDStatus is " + resultData.MdStatus
                            });
                        }
                    });
                });

                return resultPromise;
            };



            $scope.addCardClick = function () {
                if ($scope.isTempusPaymentProvider) {
                    $scope.addTempusCard();
                } else {
                    $scope.addCreSecureCard();
                }
            };

            $scope.addTempusCard = function () {
                $scope.tempusIframeUrl = null;
                $scope.selectedCreCard = undefined;
                // $scope.model.cardNumber = "";
                // $scope.model.expirationMonth = "";
                // $scope.model.expirationYear = "";
                // $scope.model.cvcCode = "";


                $scope.addCartSubmitted = true;
                $scope.isCreProcessing = true;
                $scope.showModal["AddTempusCard"] = true;

                // $scope.showAddCardSummaryErrors = $scope.canShowAddCardSummaryErrors();

                tempusPaymentService.getTempusIframeUrl({ region: $scope.anonymUser && ($scope.anonymUser.pursuitBusinessId || $scope.anonymUser.geographyCode) }, function (response) {
                    console.log("get tempus iframe url response: ", response);
                    $scope.isCreProcessing = false;
                    var url = response && response.data && response.data.iframeUrl;
                    if (url) {
                        $scope.tempusIframeUrl = $sce.trustAsResourceUrl(url);
                    } else {
                        $timeout(function () { $scope.showModal["AddTempusCard"] = false; $scope.$apply(); }, 700); // should be higher than modal transition
                    }
                });

                //$scope.tempusIframeUrl = cresecureService.generateCreSecureIframeUrl(params);                
            };

            $scope.addCreSecureCard = function () {
                $scope.selectedCreCard = undefined;
                // $scope.model.cardNumber = "";
                // $scope.model.expirationMonth = "";
                // $scope.model.expirationYear = "";
                // $scope.model.cvcCode = "";

                $scope.showModal["AddCard"] = true;
                $scope.addCartSubmitted = true;

                var params = {};
                var d = jwtService.getServerMomentDate();


                $scope.showAddCardSummaryErrors = $scope.canShowAddCardSummaryErrors();
                //
                params = {
                    merchPass: $scope.anonymUser && $scope.anonymUser.creSecureMerchPass ? $scope.anonymUser.creSecureMerchPass : $("body").attr("data-cresecure-merchPass"),
                    allowed_types: $scope.anonymUser && $scope.anonymUser.allowedCardTypes ? $scope.anonymUser.allowedCardTypes : "Visa|MasterCard|American Express",
                    cre_tokenize: "store_only",
                    sessionId: "testSession123",
                    name: "",//($scope.model.firstName || "") + " " + ($scope.model.lastName || ""),
                    formType: 0,//$scope.isAgent ? 0 : 1,
                    required: "minimum", // all/minimum
                    collectAddress: null,//2,
                    address: "",//$scope.model.billingAddress || "",
                    currency_code: jwtService.getCurrency(),
                    city: "",//$scope.model.billingCity || "",
                    state: "",// $scope.model.provState || "",
                    zip: "",//$scope.model.zipCode || "",
                    country: $scope.model.travelerCountry ? cresecureService.getCountryCodeByName($scope.model.travelerCountry, $scope.availableCountries) : "",
                    timestamp: d.millisecond()
                }

                if ($scope.isAgent) {
                    params.collectAddress = null;
                    params.address = null;
                    params.city = null;
                    params.state = null;
                    params.zip = null;
                    params.country = null;
                    params.required = "minimum";

                    if ($scope.model.useCustomerCard) {
                        params.name = ($scope.model.travelerFirstName || "") + " " + ($scope.model.travelerLastName || "");
                    }
                }

                if ($scope.useTravelerInfo) {
                    params.name = ($scope.model.travelerFirstName || "") + " " + ($scope.model.travelerLastName || "");
                    params.address = ($scope.model.travelerAddress || "");
                    params.city = ($scope.model.travelerCity || "");
                    params.state = ($scope.model.travelerProvState || "");
                    params.zip = ($scope.model.travelerZipCode || "");
                    params.country = $scope.model.travelerCountry ? cresecureService.getCountryCodeByName($scope.model.travelerCountry, $scope.availableCountries) : "";
                }

                $scope.crescureIframeUrl = cresecureService.generateCreSecureIframeUrl(params);
                $scope.urlModel = { crescureIframeUrls: [$scope.crescureIframeUrl] };
            };

            $scope.ensureCreditCardId = function () {
                // ensure credit card id used for credit card selector tracking
                _.each($scope.creCards, function (card) {
                    if (card.tempid) return;
                    card.tempid = card.cardTokenValue || card.cardid;
                });
            };

            $scope.deleteCard = function (card) {
                $scope.inlineCC.errors = [];

                var allCards = $scope.getCreditCards();

                var cardid = card.cardid;
                var cardToken = card.cardTokenValue;

                if (card.cardTokenValue) {
                    $scope.isLoading = true;
                    var foundCard = _.find(allCards, function (fcard) {
                        return fcard.cardTokenValue === cardToken;
                    });

                    if (foundCard) {
                        if ($scope.isTempusPaymentProvider) {
                            $scope.selectedCreCard = null;
                            $scope.creCards = _.reject($scope.creCards, function (card) {
                                return card.cardTokenValue === cardToken;
                            });
                            $scope.isLoading = false;
                        } else {
                            $scope.deleteCardButtonDisabled = true;
                            var deleteParams = {
                                urlPrefix: ($("body").data("weburl") ? $("body").data("weburl") : ""),
                                token: jwtService.getPrincipalToken(),
                                cardToken: foundCard.cardTokenValue
                            }

                            borgunPaymentService.deleteCardById(deleteParams, function (deleteResult) {
                                $scope.deleteCardButtonDisabled = false;
                                $scope.selectedCreCard = null;

                                $scope.creCards = _.reject($scope.creCards, function (card) {
                                    return card.cardTokenValue === cardToken;
                                });

                                $scope.isLoading = false;
                            });
                        }
                    } else {
                        $scope.isLoading = false;
                    }
                } else
                    if (cardid) {
                        $scope.isLoading = true;
                        var foundCard = _.find($scope.getCreditCards(), function (card) {
                            return card.cardid === cardid;
                        });

                        if (foundCard) {
                            if ($scope.isTempusPaymentProvider) {
                                $scope.selectedCreCard = null;
                                $scope.creCards = _.reject($scope.creCards, function (card) {
                                    return card.cardid === cardid;
                                });
                                $scope.isLoading = false;
                            } else {
                                $scope.deleteCardButtonDisabled = true;
                                var deleteParams = {
                                    urlPrefix: ($("body").data("weburl") ? $("body").data("weburl") : ""),
                                    token: jwtService.getPrincipalToken(),
                                    cardid: foundCard.cardid
                                }

                                paymentService.deleteCardById(deleteParams, function (deleteResult) {
                                    $scope.deleteCardButtonDisabled = false;
                                    $scope.selectedCreCard = null;

                                    $scope.creCards = _.reject($scope.creCards, function (card) {
                                        return card.cardid === cardid;
                                    });

                                    $scope.isLoading = false;
                                });
                            }
                        } else {
                            $scope.isLoading = false;
                        }
                    }
                    else {
                        $scope.deleteCardButtonDisabled = false;
                        $scope.selectedCreCard = null;

                        $scope.creCards = _.reject($scope.creCards, function (c) {
                            return c.index === card.index;
                        });
                    }
            };

            $scope.cancelCREPayment = function () {
                $scope.showModal["AddCard"] = false;
            };

            $scope.getCreditCards = function () {

                if ($scope.model.useCustomerCard) {
                    return _.filter($scope.creCards, function (cc) {
                        return cc.isTemp;
                    });
                } else {
                    return _.filter($scope.creCards, function (cc) {
                        return !cc.isTemp;
                    });
                }
            };

            $scope.getFirstLastNameFromQuery = function (str) {
                var a = ["", ""];
                var splits = _.filter(str.split(" "), function (v) { return v.length; });

                for (var i = 0; i < splits.length; i++) {
                    if (i === 0 || i !== (splits.length - 1)) {
                        a[0] += (a[0].length ? " " : "") + splits[i];
                    } else {
                        a[1] = splits[i];
                    }
                }

                return a;
            };

            $scope.shouldShowComponent = function (comp) {
                return comp && !comp.isHidden && comp.ProductType != 'PKG-HDR';
            };

            $scope.completeTempusVerification = function (params) {
                console.log("complete tempus verification: ", params);
                if (params.REPTOKEN) {
                    var tempCard = {
                        pursuitBusinessId: $scope.anonymUser && ($scope.anonymUser.pursuitBusinessId || $scope.anonymUser.geographyCode),
                        cardNumber: params.CCACCOUNT,
                        cardType: params.CCCARDTYPE,
                        cardHolderName: params.REPCCNAME,
                        expirationMonth: params.CCEXP && params.CCEXP.substr(0, 2),
                        expirationYear: params.CCEXP && params.CCEXP.substr(2),
                        enabled: true,
                        used: false,
                        cardTokenValue: params.REPTOKEN,
                        validUntil: null, //data.ValidUntil
                    };
                    if ($scope.model.useCustomerCard) {
                        tempCard.doNotSaveCardToken = {
                            value: false
                        };
                        tempCard.isTemp = true;
                    }
                    // send the full year
                    if ((tempCard.expirationYear || "").length == 2) {
                        tempCard.expirationYear = "20" + tempCard.expirationYear;
                    }

                    // TODO: push CC and not replace!                    $scope.creCards.push(tempCard);
                    $scope.creCards = [tempCard];

                    $scope.ensureCreditCardId();
                    //   $scope.creCards = data;
                    $scope.changedCurrentCard(tempCard);

                } else {
                    // TODO: show error
                    alert("An error has occurred!")
                }
                $timeout(function () { $scope.showModal["AddTempusCard"] = false; $scope.$apply(); }, 300);
            };

            $scope.completeCREPayment = function (params) {
                if (params.fullQuery.toLowerCase().indexOf("processstart=1") === -1) {
                    var tempCard = {
                        cardNumber: cresecureService.getParamValue("ccNumber", params.fullQuery),
                        expirationMonth: cresecureService.getParamValue("expMonth", params.fullQuery),
                        expirationYear: cresecureService.getParamValue("expYear", params.fullQuery),
                        firstName: "",//$scope.model.firstName || "",
                        lastName: "",//$scope.model.lastName || "",
                        billingAddress: "",// $scope.model.billingAddress || "",
                        billingCity: "",//$scope.model.billingCity || "",
                        provState: "",//$scope.model.provState || "",
                        billingCountry: "",//$scope.model.billingCountry || "",
                        zipCode: "",//$scope.model.zipCode || "",
                        fullQuery: params.fullQuery,
                        tempid: Math.random().toString(36).replace(/[^a-z]+/g, '').substr(2, 10)
                    };

                    if ($scope.model.useCustomerCard) {
                        tempCard = {
                            cardNumber: cresecureService.getParamValue("ccNumber", params.fullQuery),
                            expirationMonth: cresecureService.getParamValue("expMonth", params.fullQuery),
                            expirationYear: cresecureService.getParamValue("expYear", params.fullQuery),
                            firstName: $scope.getFirstLastNameFromQuery(cresecureService.getParamValue("name", params.fullQuery))[0],
                            lastName: $scope.getFirstLastNameFromQuery(cresecureService.getParamValue("name", params.fullQuery))[1],
                            billingAddress: cresecureService.getParamValue("address1", params.fullQuery) + (cresecureService.getParamValue("address2", params.fullQuery) ? " " + cresecureService.getParamValue("address2", params.fullQuery) : ""),
                            billingCity: cresecureService.getParamValue("city", params.fullQuery),
                            provState: cresecureService.getParamValue("province", params.fullQuery),
                            billingCountry: cresecureService.getCountryByNameCode(cresecureService.getParamValue("country", params.fullQuery), $scope.availableCountries),
                            zipCode: cresecureService.getParamValue("postal_code", params.fullQuery),
                            fullQuery: params.fullQuery,
                            doNotSaveCardToken: { value: false },
                            isTemp: true,
                            tempid: Math.random().toString(36).replace(/[^a-z]+/g, '').substr(2, 10)
                        }
                    }

                    var data = null; //cresecureService.getSessionCards();

                    if (!data) {
                        data = [];
                    }

                    //var foundCode = _.find(data, function (card) {
                    //    return card.cardId === tempCard.cardid;
                    //    /*&& card.expirationMonth.toLowerCase() === tempCard.expirationMonth.toLowerCase()
                    //    && card.expirationYear.toLowerCase() === tempCard.expirationYear.toLowerCase()
                    //    && card.firstName.toLowerCase() === tempCard.firstName.toLowerCase()
                    //    && card.lastName.toLowerCase() === tempCard.lastName.toLowerCase();*/
                    //});

                    /*if (!foundCode) {*/
                    var customerToken = jwtService.getCustomerToken();
                    if (customerToken && !$scope.model.useCustomerCard) {
                        $scope.isLoading = true;
                        $scope.showLoadValidCardMsg = true;
                        try {
                            //try to persist card against user profile
                            var postParams = {
                                urlPrefix: ($("body").data("weburl") ? $("body").data("weburl") : ""),
                                token: jwtService.getCustomerToken(),
                                fullQuery: tempCard.fullQuery
                            }

                            paymentService.postCreditCard(postParams, function (postResult) {
                                if (postResult.success && postResult.data && postResult.data.length > 0) {
                                    //data.push(postResult.data[0]);

                                    $scope.creCards = _.union(data || [], postResult.data);
                                    $scope.ensureCreditCardId();
                                    var selectedCard = _.find($scope.creCards, function (cc) { return cc.cardCreated; });
                                    $scope.changedCurrentCard(selectedCard ? selectedCard : $scope.creCards[0]);
                                } else {
                                    // data.push(tempCard);
                                    $scope.creCards.push(tempCard);
                                    $scope.ensureCreditCardId();
                                    //   $scope.creCards = data;
                                    $scope.changedCurrentCard(tempCard);
                                }
                                $scope.isLoading = false;
                                $scope.showLoadValidCardMsg = false;
                            });
                        } catch (e) {
                            data.push(tempCard);

                            $scope.creCards = data;
                            $scope.ensureCreditCardId();
                            $scope.selectedCreCard = tempCard;
                            $scope.isLoading = false;
                            $scope.showLoadValidCardMsg = false;
                        }
                    } else {
                        //if (!foundCode) {
                        // data.push(tempCard);
                        //  $scope.creCards = data;
                        $scope.creCards.push(tempCard);
                        $scope.ensureCreditCardId();
                        $scope.selectedCreCard = tempCard;
                        $scope.changedCurrentCard(tempCard);
                        //}
                        //else {
                        //    var newArray = _.reject(data, function (card) { return card.cardid === tempCard.cardid });
                        //    newArray.push(tempCard);

                        //    scope.creCards = data;
                        //    $scope.selectedCreCard = tempCard;
                        //    $scope.changedCurrentCard(tempCard);
                        //}

                    }
                    /*} else {
                        $scope.creCards = data;
                        $scope.selectedCreCard = foundCode;
                    }*/
                    _.each($scope.creCards, function (val, index) { val.index = index; });
                    //setTimeout(function () {
                    //    jQuery("#addCard").change();
                    //}, 0);

                    //cresecureService.setSessionCards(data);

                    // $scope.model.cardNumber = cresecureService.getParamValue("ccNumber", params.fullQuery);
                    //  $scope.model.expirationMonth = cresecureService.getParamValue("expMonth", params.fullQuery);
                    //  $scope.model.expirationYear = cresecureService.getParamValue("expYear", params.fullQuery);

                    //  $scope.model.cvcCode = "123";

                    //$scope.selectedCreCard = tempCard;

                    $scope.showModal["AddCard"] = false;

                    $scope.isCreProcessing = false;

                    $scope.showCreSummaryErrors = false;
                    $scope.creSummaryErrors = [];
                } else {
                    $scope.isCreProcessing = true;
                }
            }

            $scope.changedCurrentCard = function (card) {
                if (!card) {
                    $scope.selectedCreCard = undefined;
                    //$scope.model.cardNumber = "";
                    //$scope.model.expirationMonth = "";
                    //$scope.model.expirationYear = "";
                    //$scope.model.cvcCode = "";

                    return;
                }
                $scope.displayInlineCC = false;
                $scope.selectedCreCard = card;

                // $scope.model.cardNumber = card.fullQuery ? cresecureService.getParamValue("ccNumber", card.fullQuery) : (card.cardNumber ? card.cardNumber : card.cardnumber);

                if (!$scope.selectedCreCard.cardNumber) {
                    $scope.selectedCreCard.cardNumber = card.fullQuery ? cresecureService.getParamValue("ccNumber", card.fullQuery) : (card.cardnumber);
                }

                if (!$scope.selectedCreCard.expirationMonth || !$scope.selectedCreCard.expirationYear) {
                    var momentExpireDate = moment(card.expirydate);
                    $scope.selectedCreCard.expirationMonth = momentExpireDate.format("MM");
                    $scope.selectedCreCard.expirationYear = momentExpireDate.format("YYYY");
                }

                if ($scope.selectedCreCard.nameoncard) {
                    if (!$scope.selectedCreCard.firstName) {
                        $scope.selectedCreCard.firstName = $scope.getFirstLastNameFromQuery($scope.selectedCreCard.nameoncard)[0]
                    }
                    if (!$scope.selectedCreCard.lastName) {
                        $scope.selectedCreCard.lastName = $scope.getFirstLastNameFromQuery($scope.selectedCreCard.nameoncard)[1];
                    }
                }

                // $scope.model.expirationMonth = card.fullQuery ? cresecureService.getParamValue("expMonth", card.fullQuery) : $scope.selectedCreCard.expirationMonth = moment(card.expirydate).format("MM");
                // $scope.model.expirationYear = card.fullQuery ? cresecureService.getParamValue("expYear", card.fullQuery) : $scope.selectedCreCard.expirationYear = moment(card.expirydate).format("YYYY");

                //$scope.model.firstName = card.fullQuery ? $scope.getFirstLastNameFromQuery(cresecureService.getParamValue("name", card.fullQuery))[0] : $scope.selectedCreCard.firstName = card.firstName ? card.firstName : $scope.getFirstLastNameFromQuery(card.nameoncard)[0];
                //$scope.model.lastName = card.fullQuery ? $scope.getFirstLastNameFromQuery(cresecureService.getParamValue("name", card.fullQuery))[1] : $scope.selectedCreCard.lastName = card.lastName ? card.lastName : $scope.getFirstLastNameFromQuery(card.nameoncard)[1];
                //$scope.model.billingAddress = card.fullQuery ? cresecureService.getParamValue("address1", card.fullQuery) : card.billingAddress ? card.billingAddress : card.address;
                //$scope.model.billingCity = card.fullQuery ? cresecureService.getParamValue("city", card.fullQuery) : card.billingCity ? card.billingCity : card.city;
                //$scope.model.provState = card.fullQuery ? cresecureService.getParamValue("province", card.fullQuery) : card.provState ? card.provState : card.state;
                //$scope.model.billingCountry = card.fullQuery ? cresecureService.getCountryByNameCode(cresecureService.getParamValue("country", card.fullQuery), $scope.availableCountries) : card.billingCountry ? card.billingCountry : cresecureService.getCountryByNameCode(card.country, $scope.availableCountries);
                //$scope.model.zipCode = card.fullQuery ? cresecureService.getParamValue("postal_code", card.fullQuery) : card.zipCode ? card.zipCode : card.postalcode;



                //  $scope.model.cvcCode = "123";

                resizeSliderPanel();
            }

            $scope.getCardForUI = function (card) {
                if (!card) return "";

                if (!card.expirationMonth || !card.expirationYear) {
                    if (card.expirydate) {
                        var expiryDate = moment(card.expirydate);
                        card.expirationMonth = expiryDate.format("MM");
                        card.expirationYear = expiryDate.format("YYYY");
                        return (card.cardnumber || card.cardNumber) + " - " + card.expirationMonth + "/" + card.expirationYear;
                    }
                }
                else {
                    return (card.cardnumber || card.cardNumber) + " - " + card.expirationMonth + "/" + card.expirationYear;
                }


                return (card.cardnumber || card.cardNumber);
            }

            $scope.getCreCardNumberParam = function (fullQueryString) {
                return cresecureService.getParamValue("ccNumber", fullQueryString);
            }

            $scope.creHandleDetailErrors = function (errorCode, gatewayCode, gatewayMessage) {
                $scope.isCreProcessing = false;

                $scope.showCreSummaryErrors = true;
                $scope.creSummaryErrors = cresecureService.getErrorMessages(errorCode);
            }

            $scope.creHandleErrors = function (errorCode) {
                $scope.isCreProcessing = false;

                $scope.showCreSummaryErrors = true;
                $scope.creSummaryErrors = cresecureService.getErrorMessages(errorCode);
            }

            $scope.whatCVV2 = function () {
                $scope.isCreProcessing = false;
                alert("whatCVV2 called");
            }

            $scope.createAccount = function (isValid) {
                $scope.createAccountModel.submitted = true;
                var generalCtrl = $scope.$parent;

                if (isValid) {

                    $scope.isLoading = true;

                    if ($scope.isLoading === true) {
                        var dataToPost = {
                            "Email": $scope.createAccountModel.emailAddress,
                            "FirstName": $scope.createAccountModel.firstName,
                            "LastName": $scope.createAccountModel.lastName,
                            "Username": $scope.createAccountModel.emailAddress,
                            "Password": $scope.createAccountModel.password
                        }

                        var requestParams = {
                            apiUrl: ($("body").data("weburl") ? $("body").data("weburl") : "") + "/api/authentication/register",
                            token: jwtService.getPrincipalToken(),
                            customerToPost: dataToPost,
                            jwtService: jwtService
                        }
                        $scope.createAccountModel.errors = [];
                        customerService.registerCustomer(requestParams, function (result) {
                            if (!result || !result.data) {
                                $scope.createAccountModel.errors.push("An error occurred during registration. Please try again later.");
                                $scope.isLoading = false;
                            } else {
                                if (result.data.token) {
                                    jwtService.setCustomerToken(result.data);

                                    if (generalCtrl.initCustomerRecordWithCallback) {
                                        generalCtrl.initCustomerRecordWithCallback(true, function () {
                                            $scope.showModal["CreateAccount"] = false;
                                            $scope.isCreateButtonVisible = false;

                                            $scope.model.travelerFirstName = ($scope.model.travelerFirstName || "").length ? $scope.model.travelerFirstName : $scope.createAccountModel.firstName;
                                            $scope.model.travelerLastName = ($scope.model.travelerLastName || "").length ? $scope.model.travelerLastName : $scope.createAccountModel.lastName;

                                            //$scope.model.firstName = $scope.createAccountModel.firstName;
                                            //$scope.model.lastName = $scope.createAccountModel.lastName;

                                            $scope.model.emailAddress = $scope.createAccountModel.emailAddress;
                                            $scope.model.emailAddress_c = $scope.createAccountModel.emailAddress_c;

                                            //setTimeout(function () {
                                            //    jQuery($element).find("input:not(.ng-empty)").change();
                                            //    $scope.checkOutForm.billingCountry.activated = true;
                                            //}, 0);
                                            resizeSliderPanel();
                                            $scope.isLoading = false;
                                        });
                                    }
                                } else {
                                    if (result.data.errors && result.data.errors.length > 0) {
                                        $scope.createAccountModel.errors = result.data.errors;
                                    }

                                    $scope.isLoading = false;
                                }
                            }
                        });
                    }
                }

                return false;
            };
            $scope.handleBack = function () {
                var productCategory = jwtService.getProductCategory();
                var redirect = true;

                jwtService.setCheckoutModel($scope.model);
                window.location = utilsFactory.addPersistentQueryStringsParams("/");
                return;
                switch (productCategory) {
                    case "Activities":
                        redirect = false;
                        window.history.go(-1);
                        break;

                }
                if (redirect) {
                    window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
                }
            };


            //$scope.getPromoCodes = function () {
            //    var promoCodes = shoppingCartService.utils.getPromoCodes($scope.cart);
            //    if (promoCodes !== "") {
            //        $scope.showPromoCodes = true;
            //    } else {
            //        $scope.showPromoCodes = false;
            //    }

            //    return promoCodes;
            //};

            $scope.getAddonImage = function (opItem) {
                if (!opItem || (!opItem.product && !opItem.package)) return;

                var productDescriptions = opItem.product ? ((opItem.unit && opItem.unit.productDescriptions) || (opItem.product.productDescriptions))
                    : opItem.package.packageDescriptions;

                if (!productDescriptions) {
                    return {};
                }

                if ((productDescriptions.mainImageUrls || "").length) {
                    return { 'background-image': 'url(' + productDescriptions.mainImageUrls[0] + ')' };
                }

                if ((productDescriptions.extraImageUrls || "").length) {
                    return { 'background-image': 'url(' + productDescriptions.extraImageUrls[0] + ')' };
                }

                return {};
            };


            $scope.getAddonTitle = function (opItem, showUpsell) {
                if (!opItem || (!opItem.product && !opItem.package)) return;
                if (opItem.product) {

                    if (opItem.product.productDescriptions && opItem.product.productDescriptions.webTrayTitle) {
                        return opItem.product.productDescriptions.webTrayTitle;
                    }

                    var productDescriptions = (opItem.unit && opItem.unit.productDescriptions) || (opItem.product.productDescriptions);
                    if (!productDescriptions) {
                        return opItem.product.name;
                    }

                    if (showUpsell && opItem.product.productDescriptions.upsellDescription) {
                        return opItem.product.productDescriptions.upsellDescription;
                    }

                    var title = (productDescriptions
                        && (productDescriptions.titles || "").length > 0) ?
                        productDescriptions.titles[0] : opItem.productDescription;

                    return title;
                } if (opItem.package) {
                    var productDescriptions = opItem.package.packageDescriptions;
                    if (!productDescriptions) {
                        return opItem.package.description;
                    }

                    if (productDescriptions.webTrayTitle) {
                        return productDescriptions.webTrayTitle;
                    }

                    if (showUpsell && productDescriptions.upsellDescription) {
                        return productDescriptions.upsellDescription;
                    }

                    var title = (productDescriptions.titles || "").length > 0 ?
                        productDescriptions.titles[0] : opItem.package.description;
                    return title;
                }

            };

            $scope.getPromoCodes = function () {
                if ($scope.cart && ($scope.cart.DiscountCodes || "").length) {
                    $scope.showPromoCodes = true;
                    return $scope.cart.DiscountCodes;
                }
                $scope.showPromoCodes = false;
                return [];
            };
            $scope.removePromoCode = function (index) {
                if (!$scope.cart || !($scope.cart.DiscountCodes || "").length) return;

                var rvItem = $scope.cart.DiscountCodes[index];
                if (!rvItem) return;

                var newCodes = _.reject($scope.cart.DiscountCodes, function (item, itemIndex) {
                    return itemIndex === index;
                });
                var requestParams = {
                    apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                    token: jwtService.getPrincipalToken(),
                    promoCodes: newCodes
                };
                $scope.isLoading = true;
                shoppingCartService.refreshPromoCodesQuote(requestParams, function (shoppingCart) {
                    if (shoppingCart) {
                        $scope.cart = shoppingCart;
                        $scope.setCartCustomFields();
                        $scope.checkShippingMethodRequired($scope.cart);
                        initDisclaimersFromCart();
                        resizeSliderPanel();
                        $scope.getOptionalExtras();
                        $scope.reloadCartOptions();
                        $scope.setGiftCardsRedeemAmount();
                    }
                    $scope.isLoading = false;
                });
            };



            //  gift cards 
            $scope.setGiftCardsRedeemAmount = function () {
                var giftCardRedeemed = 0;
                if ($scope.cart && ($scope.cart.GiftCards || "").length) {
                    var total = $scope.showCanPayAtHotel ? $scope.depositAmountDue : ($scope.cart.Quote.Price || 0);

                    _.each($scope.cart.GiftCards, function (card) {
                        if (total >= (card.giftCardBalance || 0)) {
                            card.redeemAmount = card.giftCardBalance;
                            total -= card.giftCardBalance;
                        } else {
                            card.redeemAmount = total;
                            total = 0;
                        }

                        if (total < 0) total = 0;
                        if (card.redeemAmount < 0) card.redeemAmount = 0;
                        giftCardRedeemed += card.redeemAmount;
                    });
                    $scope.cart.outsandingCCPay = total;
                    $scope.cart.giftCardsRedeemed = giftCardRedeemed;
                    $scope.skipCC = !$scope.showCanPayAtHotel && $scope.cart.outsandingCCPay == 0;
                }
            };

            $scope.getGiftCards = function () {
                if ($scope.cart && ($scope.cart.GiftCards || "").length) {
                    $scope.showGiftCardCodes = true;
                    return $scope.cart.GiftCards;
                }
                $scope.showGiftCardCodes = false;
                return [];
            };
            $scope.removeGiftCard = function (index) {
                if (!$scope.cart || !($scope.cart.GiftCards || "").length) return;

                var rvItem = $scope.cart.GiftCards[index];
                if (!rvItem) return;

                var newCards = _.reject($scope.cart.GiftCards, function (item, itemIndex) {
                    return itemIndex === index;
                });
                $scope.cart.GiftCards = newCards;
                $scope.getGiftCards();
                $scope.setGiftCardsRedeemAmount();
            };

            $scope.applyGiftCardCode = function () {
                if (!$scope.giftCardCode || !($scope.anonymUser && ($scope.anonymUser.giftCardProvider || "").length)) {
                    return;
                }
                $scope.showGiftCardError = false;

                $scope.giftCardCode = $scope.giftCardCode.trim();
                if (!$scope.cart.GiftCards) {
                    $scope.cart.GiftCards = [];
                }
                var existingCard = _.find($scope.cart.GiftCards, function (card) { return card.giftCardID == $scope.giftCardCode; });
                if (existingCard) {
                    console.log("The cardid was already added");
                    $scope.giftCardCode = "";
                    $timeout(function () {
                        jQuery("#giftcardcode").change();
                    });
                    return;
                }

                var requestParams = {
                    urlPrefix: ($("body").data("weburl") ? $("body").data("weburl") : ""),
                    token: jwtService.getPrincipalToken(),
                    giftCardProvider: $scope.anonymUser.giftCardProvider,
                    giftCardID: ($scope.giftCardCode || "").trim()
                };
                $scope.isGiftCardLoading = true;

                paymentService.getGiftCardBalanceCards(requestParams, function (result) {
                    if (result.success && result.data) {
                        $scope.cart.GiftCards.push({
                            giftCardBalance: result.data.giftCardBalance,
                            giftCardID: result.data.giftCardID,
                            giftCardProvider: result.data.giftCardProvider
                        });
                        $scope.giftCardCode = "";
                        $timeout(function () {
                            jQuery("#giftcardcode").change();
                        });
                        $scope.getGiftCards();
                    } else {
                        $scope.showGiftCardError = true;
                    }
                    $scope.setGiftCardsRedeemAmount();
                    $scope.isGiftCardLoading = false;
                });

            };

            //
            $scope.getLocations = function () {
                return new Promise(function (resolve, reject) {
                    userService.getPersistedCountries(function (persistedResult) {
                        if (persistedResult.success && persistedResult.data && persistedResult.data.countries) {
                            $scope.availableCountries = persistedResult.data.countries;
                            resolve();
                            // callback();
                        } else {
                            var params = {
                                urlPrefix: $scope.$parent.getWebUrl(),
                                token: jwtService.getPrincipalToken()
                            };
                            userService.getCountries(params, function (countriesResult) {
                                if (countriesResult.success && (countriesResult.data || "").length) {
                                    $scope.availableCountries = countriesResult.data;
                                    userService.persistCountries(countriesResult.data, function () { });
                                }
                                //callback();
                                resolve();
                            });
                        }
                    });
                });// \promise
            };

            $scope.fillAvailableRegions = function (firsttime) {

                //  $scope.model.travelerProvState = undefined;

                if (!$scope.showTravelerStateProv() || !$scope.model.travelerCountry) {
                    $scope.availableRegions = [];
                    if ($scope.model.travelerProvState)
                        $scope.model.travelerProvState = undefined;
                    return;
                }
                var selectedCountry = _.find($scope.availableCountries, function (cntr) { return cntr.name == $scope.model.travelerCountry; });
                if (!selectedCountry) {
                    $scope.availableRegions = [];
                    if ($scope.model.travelerProvState)
                        $scope.model.travelerProvState = undefined;
                    return;
                }

                $scope.availableRegions = _.filter($scope.allRegions || [], function (reg) { return reg.countryCode == selectedCountry.code; });
                if (firsttime && $scope.prevtravelerProvState && _.find($scope.availableRegions || [], function (reg) { return reg.regionName == $scope.prevtravelerProvState; })) {
                    $timeout(function () {
                        $scope.model.travelerProvState = $scope.prevtravelerProvState;
                    });
                } else {
                    $scope.model.travelerProvState = undefined;
                }
            };

            $scope.fillGiftGivingAvailableRegions = function () {

                if (!$scope.showGiftGivingStateProv() || !$scope.giftGivingOptions.model.country) {
                    $scope.giftGivingAvailableRegions = [];
                    if ($scope.giftGivingOptions.model.stateProv)
                        $scope.giftGivingOptions.model.stateProv = undefined;
                    return;
                }
                var selectedCountry = _.find($scope.availableCountries, function (cntr) { return cntr.name == $scope.giftGivingOptions.model.country; });
                if (!selectedCountry) {
                    $scope.giftGivingAvailableRegions = [];
                    if ($scope.giftGivingOptions.model.stateProv)
                        $scope.giftGivingOptions.model.stateProv = undefined;
                    return;
                }

                $scope.giftGivingAvailableRegions = _.filter($scope.allRegions || [], function (reg) { return reg.countryCode == selectedCountry.code; });

                $scope.giftGivingOptions.model.stateProv = undefined;
            };

            $scope.fillDeliveryAvailableRegions = function () {

                if (!$scope.showDeliveryStateProv() || !$scope.deliveryOptions.model.country) {
                    $scope.deliveryAvailableRegions = [];
                    if ($scope.deliveryOptions.model.stateProv)
                        $scope.deliveryOptions.model.stateProv = undefined;
                    return;
                }
                var selectedCountry = _.find($scope.availableCountries, function (cntr) { return cntr.name == $scope.deliveryOptions.model.country; });
                if (!selectedCountry) {
                    $scope.deliveryAvailableRegions = [];
                    if ($scope.deliveryOptions.model.stateProv)
                        $scope.deliveryOptions.model.stateProv = undefined;
                    return;
                }

                $scope.deliveryAvailableRegions = _.filter($scope.allRegions || [], function (reg) { return reg.countryCode == selectedCountry.code; });

                $scope.deliveryOptions.model.stateProv = undefined;
            };

            $scope.getRegions = function () {
                return new Promise(function (resolve, reject) {
                    userService.getPersistedRegions(function (persistedResult) {
                        if (persistedResult.success && persistedResult.data && persistedResult.data.regions) {
                            $scope.allRegions = persistedResult.data.regions;
                            resolve();
                            // callback();
                        } else {
                            var params = {
                                urlPrefix: $scope.$parent.getWebUrl(),
                                token: jwtService.getPrincipalToken()
                            };
                            userService.getRegions(params, function (regionsResult) {
                                if (regionsResult.success && (regionsResult.data || "").length) {
                                    $scope.allRegions = regionsResult.data;
                                    userService.persistRegions(regionsResult.data, function () { });
                                }
                                //callback();
                                resolve();
                            });
                        }
                    });
                });// \promise
            };

            $scope.prepareData = function () {
                Promise.all([$scope.getRegions(), $scope.getLocations()]).then($scope.initCurrentAnonymUser.bind(null, $scope.init));
                // $scope.getLocations($scope.initCurrentAnonymUser.bind(null, $scope.init));
            };

            function canShowUnaccompaniedChildMessage() {
                if (!$scope.cart || !($scope.cart.Items || "").length) return false;

                var result = _.find($scope.cart.Items, function (cartItem) {
                    if ((cartItem.ProductCategory || "").toLowerCase() === "transportation") {
                        var firstComponent = cartItem.BookingToQuote && (cartItem.BookingToQuote.Components || "").length ? cartItem.BookingToQuote.Components[0] : undefined;
                        if (!firstComponent || parseInt(firstComponent.NumberOfAdults) > 0) return false;

                        return true;
                    }
                    return false;
                });

                if (result) return true;
                else return false;
            };

            //$scope.displayInlineCCInput = function () {
            //    return $scope.anonymUser && ($scope.anonymUser.ccProcessingMethod || '').trim().toLowerCase() == "borgun";
            //};

            $scope.getTermsConditionsDoc = function () {
                var requestParams = {
                    apiUrl: webUrl + "/api/booking/document",
                    token: jwtService.getPrincipalToken(),
                    documentType: "TermsAndConditions"
                };
                $scope.isLoading = true;
                customerService.getDocument(requestParams, function (result) {
                    $scope.isLoading = false;
                });
            };

            $scope.handleTermsConditionDocLinkClick = function (event) {
                console.log('Terms Doc Link clicked!', event.target.nodeName);
                if (event.target.nodeName === 'A') {
                    console.log('Link clicked!');
                    event.preventDefault();

                    $scope.getTermsConditionsDoc();
                }
            };

            $scope.anonymUser = undefined;
            $scope.ageRanges = {};

            $scope.initCurrentAnonymUser = function (callback) {

                jwtService.getAnonymousUserByGeography($scope.$parent.selectedGeographyCode, function (user) {

                    $scope.anonymUser = user;
                    if ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) {
                        moment.locale($scope.selectedLanguage.languageCode);
                    }
                    $scope.setGiftCardVisibility();

                    $scope.displayInlineCCInput = $scope.anonymUser && ($scope.anonymUser.ccProcessingMethod || '').trim().toLowerCase() == "borgun";
                    $scope.isTempusPaymentProvider = $scope.anonymUser && ($scope.anonymUser.ccProcessingMethod || '').trim().toLowerCase() == "tempus";

                    if ($scope.anonymUser.checkoutConfig && $scope.anonymUser.checkoutConfig.childGuestAgeRange) {
                        var childAgeRange = $scope.anonymUser.checkoutConfig.childGuestAgeRange.split("-");

                        $scope.ageRanges.childGuestAgeMin = parseInt(childAgeRange[0] || 0);
                        $scope.ageRanges.childGuestAgeMax = parseInt(childAgeRange[1] || childAgeRange[0]);

                    }
                    if ($scope.anonymUser.checkoutConfig && $scope.anonymUser.checkoutConfig.infantGuestAgeRange) {

                        var infantAgeRange = $scope.anonymUser.checkoutConfig.infantGuestAgeRange.split("-");
                        $scope.ageRanges.infantGuestAgeMin = parseInt(infantAgeRange[0] || 0);
                        $scope.ageRanges.infantGuestAgeMax = parseInt(infantAgeRange[1] || infantAgeRange[0]);
                    }
                    callback();
                });
            };

            $scope.skipCC = false;

            function fillProductDetails(source, index, callback) {
                var item = source[index];
                if (!item) {
                    callback();
                }
                var getProductPromise = null;
                if (item.productCategory == null || item.productCategory == "Package") {
                    //getProductPromise = Promise.resolve({ data: { products: null } });
                    var params = {
                        urlPrefix: webUrl,
                        token: jwtService.getPrincipalToken(),
                        productCode: item.productCode,
                        travelDate: item.date,
                        adults: 1,
                        children: 0,
                        nights: 0
                    };

                    getProductPromise = packagesService.getPackageDetailsPromise(params);;
                }
                else if (item.productCategory == "Hotel") {
                    // productCode, travelDate, nights, adults, children
                    getProductPromise = productsFactory.getHotelProduct(jwtService.getPrincipalToken(), item.productCode, item.date, 1);
                } else {
                    getProductPromise = productsFactory.getProduct(jwtService.getPrincipalToken(), item.productCode, item.productCategory, item.date);
                }

                getProductPromise.then(
                    function (result) {
                        item.product = undefined;

                        if ((!result.data.products || result.data.products.length === 0) && (!result.data.packages || result.data.packages.length === 0)) {
                            if (source.length > index + 1) {
                                fillProductDetails(source, index + 1, callback);
                            } else {
                                callback();
                            }
                            return;
                        }

                        if (result.data.products) {
                            item.product = result.data.products[0];

                            var selectedUnit = (Array.isArray(item.unitCode) && item.unitCode[0]) || !Array.isArray(item.unitCode) && item.unitCode;

                            if (selectedUnit && (item.product.units || "").length) {
                                item.unit = _.find(item.product.units, function (un) { return un.unitCode == selectedUnit; })
                            }
                            //else if ((item.product.units || "").length) {
                            //    item.unit = item.product.units[0];
                            //}
                        } else if (result.data.packages) {
                            item.package = result.data.packages[0];
                        }

                        if (source.length > index + 1) {
                            fillProductDetails(source, index + 1, callback);
                        }
                        else {
                            callback();
                        }
                    }, function () {
                        if (source.length > index + 1) {
                            fillProductDetails(source, index + 1, callback);
                        }
                        else {
                            callback();
                        }
                    });
            }

            $scope.setGiftCardVisibility = function () {
                if (!$scope.anonymUser) {
                    $scope.showGiftCardInput = false;
                    return;
                }
                $scope.showGiftCardInput = ($scope.anonymUser.giftCardProvider || "").toString().length > 0;
            };

            $scope.getDiscountRemainingUsesLabel = function (code) {
                var discounts = $scope.cart.Quote.Discounts;
                if (!(discounts || '').length) return null;

                var cartDiscount = _.find(discounts, function (it) {
                    return it.DiscountCode == code;
                });
                if (!cartDiscount || cartDiscount.RemainingUses == null || cartDiscount.RemainingUses < 0) return null;

                return $scope.getLabelWith2Placeholders("cart.promo-code-remaining-uses",
                    cartDiscount.RemainingUses == 0 ? 0 : cartDiscount.RemainingUses - 1, code);
            };

            $scope.applyPromoCode = function () {
                $scope.showPromoCodeError = false;
                if ($scope.promoCode && $scope.promoCode !== "") {
                    $scope.promoCode = $scope.promoCode.toUpperCase();
                    var requestParams = {
                        apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                        token: jwtService.getPrincipalToken(),
                        promoCode: $scope.promoCode
                    };
                    $scope.isLoading = true;
                    var prevDiscount = $scope.cart.Quote && $scope.cart.Quote.TotalDiscountAmount;

                    shoppingCartService.applyPromoCode(requestParams, function (shoppingCart) {
                        if (shoppingCart) {
                            $scope.cart = shoppingCart;
                            $scope.setCartCustomFields();
                            $scope.checkShippingMethodRequired($scope.cart);
                            initDisclaimersFromCart();
                            // TODO:Revert back
                            //if (prevDiscount == ($scope.cart.Quote && $scope.cart.Quote.TotalDiscountAmount)) {
                            //    // remove promoCode
                            //    //  display promo code error
                            //    $scope.cart.DiscountCodes = _.find($scope.cart.DiscountCodes, function (discountCode) {
                            //        return discountCode != $scope.promoCode;
                            //    });
                            //    shoppingCartService.setStorageCart($scope.cart);
                            //    $scope.showPromoCodeError = true;
                            //}
                            $scope.promoCode = "";
                            $timeout(function () {
                                jQuery("#promocode").change();
                            });
                            // resizeSliderPanel();
                            $scope.getPromoCodes();
                            $scope.getOptionalExtras();
                            $scope.reloadCartOptions();
                            $scope.setGiftCardsRedeemAmount();
                        }
                        else {
                            window.location = utilsFactory.addPersistentQueryStringsParams("/");
                        }
                        $scope.isLoading = false;
                    });
                }
            };

            $scope.removeItemFromCart = function (index, ritem) {
                var confirmRemoveModalInstance = $uibModal.open({
                    animation: true,
                    templateUrl: "removeFromCartModal.html",
                    controller: "confirmRemoveFromCartModalCtrl",
                    size: "confirm-remove-cart",
                    resolve: {
                    },
                    backdrop: "true"
                });
                confirmRemoveModalInstance.result.then(function (result) {
                    //relatedProductCode
                    //var relatedItemsToRemove = [];
                    //_.each(cart.Items, function (ci, index) { if (ci.relatedProductCode == ritem.ProductCode) relatedItemsToRemove.push(index); });

                    $scope.hiddenOptionalExtras[ritem.ProductCode + ritem.UnitCode] = false;

                    var requestParams = {
                        apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                        token: jwtService.getPrincipalToken(),
                        index: index,
                        removeAllShippingAndWrappings: true,
                        productCode: ritem.ProductCode
                    };
                    $scope.isLoading = true;
                    $scope.cart.optionalExtras = [];



                    shoppingCartService.setStorageCart($scope.cart, function () {
                        shoppingCartService.updateCartComponents(requestParams, function (shoppingCart) {
                            $scope.isLoading = false;
                            if (shoppingCart && (shoppingCart.Items || '').length) {
                                $scope.cart = shoppingCart;
                                $scope.setCartCustomFields();
                                $scope.checkShippingMethodRequired($scope.cart);
                                initDisclaimersFromCart();
                                $scope.getOptionalExtras();
                                $scope.reloadCartOptions();
                                $scope.setGiftCardsRedeemAmount();

                                $scope.deliveryOptions.model.deliveryMethodUnit = null;
                                $scope.requoteAfterShippingChanged();
                                $scope.refreshInputs('#shippingMethodContainer');
                            } else {
                                window.location = utilsFactory.addPersistentQueryStringsParams("/");
                            }
                        });
                    });
                }, function () {
                    //console.log("dismiss");
                });
            };

            $scope.showOptionalExtras = function () {
                if ($scope.isEnhanceBookingPageEnabled() || !$scope.cart || !($scope.cart.optionalExtras || "").length) {
                    return false;
                }
                var r = _.find($scope.cart.optionalExtras,
                    function (opItem) {
                        return !opItem.hidden &&
                            (opItem.product && (opItem.product.units || "").length || opItem.productCategory == "Package");
                    });
                return r != undefined;
            };

            $scope.checkOptionalProductVisbility = function (val) { return !val.hidden; };

            $scope.hideOptionalProduct = function (oc) {
                oc.hidden = true;
                $scope.hiddenOptionalExtras[oc.productCode + oc.unitCode] = true;
                shoppingCartService.setStorageCart($scope.cart, function () { });
            };

            $scope.reloadCartOptions = function () {
                // reload cart options
                if ($scope.cart.Quote) {
                    $scope.showCanPayAtHotel = $scope.cart.Quote.CanPayAtHotel;
                    $scope.depositAmountDue = parseFloat($scope.cart.Quote.DepositAmountDue);
                    $scope.dueOnArrival = parseFloat($scope.cart.Quote.DueOnArrival);

                    $scope.canChangeConfirmationEmailAddress = $scope.cart.Quote.CanChangeConfirmationEmailAddress;
                    $scope.showCanPayWithAR = $scope.isAgent && $scope.cart.Quote.CanPayWithAccountsReceivable;
                    $scope.model.payWithAR = $scope.showCanPayWithAR;//checked by default
                }

                $scope.skipCC = $scope.cart.Quote && parseInt($scope.cart.Quote.Price) <= 0 && !$scope.showCanPayAtHotel; //(shoppingCart.DiscountCodes || "").length &&


                $scope.showUnaccompaniedChildMessage = canShowUnaccompaniedChildMessage();
                //

                $scope.passengerList = [];
                $scope.promptforguestphone = false;

                var custIndex = 1;// main traveler will be passenger#1
                _.each($scope.cart.Items, function (sitem, index) {
                    if (sitem.BookingToQuote) {
                        if (sitem.BookingToQuote.Components) {
                            _.each(sitem.BookingToQuote.Components, function (scomp, index) {
                                if (scomp.NeedFullPassengerList) {
                                    $scope.promptforguestphone = $scope.promptforguestphone || $scope.promptforguestphoneproductcodes.indexOf(scomp.ProductCode) >= 0;
                                    $scope.passengerList.push({
                                        item: sitem,
                                        component: scomp,
                                        adults: [],
                                        children: [],
                                        infants: []
                                    });
                                    for (var i = 0; i < scomp.NumberOfAdults; i++) { // main traveler will be passenger#1
                                        $scope.passengerList[$scope.passengerList.length - 1].adults.push({
                                            id: "IBE" + (i === 0 ? 1 : (custIndex)),
                                            firstName: "",
                                            lastName: ""
                                        });
                                        custIndex++;
                                    }

                                    for (var j = 0; j < scomp.NumberOfChildren; j++) {
                                        $scope.passengerList[$scope.passengerList.length - 1].children.push({
                                            id: "IBE" + (custIndex++),
                                            firstName: "",
                                            lastName: ""
                                        });
                                    }

                                    for (var k = 0; k < scomp.NumberOfInfants; k++) {
                                        $scope.passengerList[$scope.passengerList.length - 1].infants.push({
                                            id: "IBE" + (custIndex++),
                                            firstName: "",
                                            lastName: ""
                                        });
                                    }

                                }
                            }); //end each
                        }

                        if (sitem.BookingToQuote.Packages) {
                            _.each(sitem.BookingToQuote.Packages, function (pck, index) {
                                var pckComp = _.find(pck.Components, function (pckComp) {
                                    return pckComp.ProductCode == pck.pckNeedPassListCompProductCode;
                                });
                                if (pck.NeedFullPassengerList && pckComp) {
                                    $scope.passengerList.push({
                                        item: sitem,
                                        pck: pck,
                                        pckComp: pckComp,
                                        adults: [],
                                        children: [],
                                        infants: []
                                    });
                                    for (var i = 0; i < pck.NumberOfAdults; i++) { // main traveler will be passenger#1
                                        if ((i == 0 && $scope.passengerList[$scope.passengerList.length - 1].adults.length == 0) || i > 0) {
                                            $scope.passengerList[$scope.passengerList.length - 1].adults.push({
                                                id: "IBE" + (i === 0 ? 1 : (custIndex)),
                                                firstName: "",
                                                lastName: ""
                                            });
                                            custIndex++;
                                        }
                                    }

                                    for (var j = 0; j < pck.NumberOfChildren; j++) {
                                        $scope.passengerList[$scope.passengerList.length - 1].children.push({
                                            id: "IBE" + (custIndex++),
                                            firstName: "",
                                            lastName: ""
                                        });
                                    }

                                    for (var k = 0; k < pck.NumberOfInfants; k++) {
                                        $scope.passengerList[$scope.passengerList.length - 1].infants.push({
                                            id: "IBE" + (custIndex++),
                                            firstName: "",
                                            lastName: ""
                                        });
                                    }

                                }
                            }); //end each
                        }//

                    }
                });

                shoppingCartService.getHotelsComponents($scope.cart, function (spComps) {
                    if (spComps && spComps.length > 0) {
                        $scope.hasCartHotels = true;
                        var tempComps = [];
                        _.map(spComps, function (spCmp) {
                            tempComps.push(
                                {
                                    name: spCmp.isPackageComponent ? spCmp.ProductName : spCmp.BookingToQuote.Components[0].Name,
                                    contactName: "",
                                    phoneNumber: "",
                                    specialRequest: "",
                                    roomRequest: "",
                                    origComp: spCmp
                                });
                        });

                        $scope.specReqComps = tempComps;
                        // resizeSliderPanel();
                    } else {
                        $scope.specReqComps = [{
                            name: undefined,
                            isGeneric: true,
                            contactName: "",
                            phoneNumber: "",
                            specialRequest: "",
                            roomRequest: "",
                            origComp: undefined
                        }];
                        // resizeSliderPanel();
                    }
                });
                // end reload cart
            };

            $scope.editItem = function (index, item) {
                var region = jwtService.getGeography();
                var regionParam = (region && ("/" + region) || "");

                var pkg = item && item.BookingToQuote && item.BookingToQuote.Packages;
                pkg = pkg && pkg[0];
                if (pkg) {
                    var q = "?updateCartItem=" + pkg.PackageCode;
                    var strDate = (pkg.StartDate || '').split('T')[0];
                    var url = regionParam + "/activities/details/" + pkg.PackageCode + "/Package" + q + "#/package-details/" + (strDate || 'date') + "/" + pkg.PackageCode;
                    window.location = utilsFactory.addPersistentQueryStringsParams(url);
                    return;
                }
                //
                var components = item && item.BookingToQuote && item.BookingToQuote.Components;
                if (!(components || "").length) return;

                var mainComponent = _.find(components, function (comp) { return !shoppingCartService.utils.isTimeComponent(comp); }) || item.BookingToQuote.Components[0];
                if (!mainComponent) return;

                var productCategory = mainComponent.ProductCategory;
                //if (productCategory != "Attraction" && productCategory != "Hotel") return;

                var productCode = mainComponent.ProductCode;
                var productType = mainComponent.ProductType;
                var date = moment(mainComponent.StartDate).format("YYYY-MM-DD");


                var unitCode = mainComponent.UnitCode || "";
                if (Array.isArray(unitCode)) {
                    if (unitCode.length && unitCode[0]) {
                        unitCode = unitCode.join("|");
                    } else {
                        unitCode = "";
                    }
                }

                if (productType == "SPA") {
                    var url = regionParam + "/spa/details/" + productType + "/" + productCategory + "/" + date; //                  
                    url = url + "?updateCartItem=" + productCode;
                    url = url + "#/select-ticket/book-adventure";
                    window.location = utilsFactory.addPersistentQueryStringsParams(url);
                    return;
                } else if (productCategory == "Attraction") {
                    var url = regionParam + "/activities/details/" + productCode + "/" + productCategory + "/" + date; //
                    if (unitCode) {
                        url = url + "/" + unitCode;
                    }

                    if (mainComponent.NumberOfAdults || mainComponent.NumberOfChildren) {
                        url = url + "/" + mainComponent.NumberOfAdults + "/" + mainComponent.NumberOfChildren;
                    }
                    url = url + "?updateCartItem=" + productCode;
                    url = url + "#/select-ticket/book-adventure";
                    window.location = utilsFactory.addPersistentQueryStringsParams(url);
                    return;
                } if (productCategory == "Tour") {
                    var url = regionParam + "/activities/details/" + productType + "/" + productCategory + "/" + date; //                  
                    url = url + "?updateCartItem=" + productCode;
                    url = url + "#/select-ticket/book-adventure";
                    window.location = utilsFactory.addPersistentQueryStringsParams(url);
                    return;
                }
                else if (productCategory == "Hotel") {
                    var url = regionParam + "/hotels/details/" + productCode + "/" + productCategory + "/" + date; //
                    if (unitCode) {
                        url = url + "/" + unitCode;
                    }

                    url = url + "?updateCartItem=" + productCode;
                    url = url + "#/select-booking-type/book-stay";
                    window.location = utilsFactory.addPersistentQueryStringsParams(url);
                    return;
                } else if (productCategory == "Transportation") {
                    var url = regionParam + "/transportation/details/" + productType + "/" + productCategory;//+ "/" + date; //                   

                    url = url + "?updateCartItem=" + productCode;
                    url = url + "#/select-transportation-ticket/book-transportation-adventure";
                    window.location = utilsFactory.addPersistentQueryStringsParams(url);
                    return;
                }
            };

            $scope.addOptionalProduct = function (oc) {
                // new logic
                var date = moment(oc.startDate).format("YYYY-MM-DD");
                var region = jwtService.getGeography();
                var productCode = oc.productCode;
                var productCategory = oc.productCategory;
                var relatedProductCode = oc.relatedProductCode;
                var unitCode = oc.unitCode || "";
                var regionParam = (region && ("/" + region) || "");
                if (Array.isArray(unitCode)) {
                    if (unitCode.length && unitCode[0]) {
                        unitCode = unitCode.join("|");
                    } else {
                        unitCode = "";
                    }
                }

                // find the related cart item
                var relatedProductCode = oc.relatedProductCode;
                var relatedComponent = null;
                var cartItem = _.find($scope.cart.Items, function (cartItem) {
                    relatedComponent = _.find(cartItem.BookingToQuote && cartItem.BookingToQuote.Components, function (comp) {
                        return comp.ProductCode == relatedProductCode;
                    });
                    return relatedComponent != null;
                    //return cartItem && cartItem.ProductCode && cartItem.ProductCode.toLowerCase() === relatedProductCode.toLowerCase();
                });
                var adults = 0, children = 0;
                if (cartItem && relatedComponent) {
                    adults = relatedComponent.NumberOfAdults || 0;
                    children = relatedComponent.NumberOfChildren || 0;
                }
                var simpleEnhancement = (oc.product && oc.product.simpleIBEEnhancement);

                var url = undefined;

                var isUpgradeParams = "";
                var paramSeparator = "";
                if (oc.isUpgrade) {
                    isUpgradeParams = "updateCartItem=" + (relatedComponent && relatedComponent.ProductCode) + "&isUpgrade=1";
                    paramSeparator = "&";
                }
                var queryStringParams = "?" + isUpgradeParams + paramSeparator + "fromwebtray=1";

                switch (productCategory) {
                    case "Package":
                        var url = regionParam + "/activities/details/" + productCode + "/Package" + queryStringParams + "#/package-details/" + (date || 'date') + "/" + productCode;
                        break;
                    case "Attraction":
                        if (simpleEnhancement) {
                            var addOnToCartModalInstance = $uibModal.open({
                                animation: true,
                                templateUrl: "addAddOnToCartModal.html",
                                controller: "addAddOnToCartModalCtrl",
                                size: "md",
                                resolve: {
                                    "product": oc, "cart": $scope.cart, "anonymUser": $scope.anonymUser
                                },
                                backdrop: false
                            });

                            addOnToCartModalInstance.result.then(function (result, args) {
                                if (result && result.cart) {
                                    $scope.cart = result.cart;
                                    $scope.setCartCustomFields();
                                    $scope.checkShippingMethodRequired($scope.cart);
                                    initDisclaimersFromCart();
                                    $scope.hideOptionalProduct(oc);
                                    $scope.reloadCartOptions();
                                    $scope.setGiftCardsRedeemAmount();
                                }
                            }, function (error, args) {

                                //console.log("dismiss");
                            });
                        }
                        else {

                            var url = regionParam + "/activities/details/" + productCode + "/" + productCategory + "/" + date; //
                            if (unitCode) {
                                url = url + "/" + unitCode;
                            }

                            if (adults || children) {
                                var adults = adults;
                                var children = children;
                                url = url + "/" + adults + "/" + children;
                            }
                            url = url + queryStringParams;
                            url = url + "#/select-ticket/book-adventure";

                            window.location = utilsFactory.addPersistentQueryStringsParams(url);
                        }
                        return;
                        break;
                    case "Hotel":
                        url = regionParam + "/hotels/details/" + productCode + "/" + productCategory + "/" + date + queryStringParams + "#/select-booking-type/book-stay";
                        break;
                    case "Tour":
                        url = regionParam + "/activities/details/" + productCode + "/" + productCategory + "/" + date; //
                        if (unitCode) {
                            url = url + "/" + unitCode;
                        }
                        url = url + "/" + adults + "/" + children;
                        url = url + queryStringParams;
                        url = url + "#/select-ticket/book-adventure";
                        break;
                    case "Transportation":
                        var productType = oc.product && oc.product.productType || productCode;
                        url = regionParam + "/transportation/details/" + productType + "/" + productCategory + "/" + date + queryStringParams + "#/select-transportation-ticket/book-transportation-adventure";
                        break;
                }

                if (url) {
                    window.location = utilsFactory.addPersistentQueryStringsParams(url);
                }

                return;
            };

            $scope.isEnhanceBookingPageEnabled = function () {
                var isEnhanceBookingPageEnabled = ($scope.selectedLanguage && $scope.selectedLanguage.enableEnhanceBookingPage) || ($scope.anonymUser && $scope.anonymUser.enableEnhanceBookingPage);
                return isEnhanceBookingPageEnabled;
            }

            $scope.getOptionalExtras = function () {
                if ($scope.isEnhanceBookingPageEnabled()) {
                    return;
                }

                if ($scope.addonLoading || !$scope.cart || $scope.cart.isUpdate || !($scope.cart.Items || "").length) { // || $scope.isLoading
                    return;
                }
                var productQueries = [];
                var mapUniqueProducts = Object.create(null);
                _.each($scope.cart.Items, function (item) {
                    if (item && item.ProductCode) {
                        var itKey = item.ProductCode
                            + moment(item.StartDate, shoppingCartService.getDateFormat()).format("YYYY-MM-DD")
                            + (item.UnitCode ? item.UnitCode : "");
                        if (!(itKey in mapUniqueProducts)) {
                            productQueries.push({
                                ProductCode: item.ProductCode,
                                TravelDate: moment(item.StartDate, shoppingCartService.getDateFormat()).format("YYYY-MM-DD"),
                                UnitCode: item.UnitCode ? item.UnitCode : null
                            });
                            mapUniqueProducts[itKey] = 1;
                        }
                    }
                });


                if (!productQueries.length) {
                    return;
                }



                var dataToPost = { ProductQueries: productQueries };
                var requestParams = {
                    token: jwtService.getPrincipalToken(),
                    data: dataToPost
                };
                $scope.addonLoading = true;
                $scope.cart.optionalExtras = [];

                productsFactory.getEnhanceYourExperience(requestParams, function (relatedProducts) {

                    if (relatedProducts && relatedProducts.data && relatedProducts.data.length) {
                        var result = [];
                        _.each(relatedProducts.data, function (item) {
                            if ((item.ibeCartEnhancements || "").length) {

                                var parentCartItem = _.find($scope.cart.Items, function (cartItem) {
                                    return cartItem && cartItem.ProductCode && cartItem.ProductCode.toLowerCase() === item.relatedProductCode.toLowerCase();
                                });

                                var date = moment(parentCartItem.StartDate).format("YYYY-MM-DD");
                                _.each(item.ibeCartEnhancements, function (optionItem) {
                                    optionItem.relatedProductCode = item.relatedProductCode;
                                    optionItem.date = date;
                                    result.push(optionItem);
                                });
                            }
                        });
                        if (result.length) {
                            fillProductDetails(result, 0, function () {
                                $scope.cart.optionalExtras = result;
                                $scope.hideOptionalExtras(); // hide optional products if they were added from the listing page
                                // hide optional extras if they are added directed on the checkout page - old
                                _.each($scope.cart.optionalExtras, function (oc) {
                                    if ($scope.hiddenOptionalExtras[oc.productCode + oc.unitCode]) {
                                        oc.hidden = true;
                                    }
                                });

                                shoppingCartService.setStorageCart($scope.cart, function () { });
                                $scope.addonLoading = false;
                            });
                        } else {
                            $scope.addonLoading = false;

                        }
                    } else {
                        $scope.addonLoading = false;
                    }
                });
            };

            // hide the optional extras
            $scope.hideOptionalExtras = function () {
                var citems = Object.create(null);
                _.each($scope.cart.Items, function (cartItem) {
                    citems[cartItem.ProductCode + cartItem.UnitCode] = true;
                });

                _.each($scope.cart.optionalExtras, function (opExtra) {
                    if (citems[opExtra.productCode + opExtra.unitCode]) {
                        opExtra.hidden = true;
                    }
                });
            };


            $scope.setCartCustomFields = function () {
                if (!$scope.rockieslitecombosflowpackagecodes) {
                    $scope.rockies2025combosflowpackagecodes = ($("body").attr("data-activity-rockies2025combosflowpackagecodes") || "").split("|");
                    $scope.rockiescombosflowpackagecodes = ($("body").attr("data-activity-rockiescombosflowpackagecodes") || "").split("|");
                    $scope.rockiesvaluecombosflowpackagecodes = ($("body").attr("data-activity-rockiesvaluecombosflowpackagecodes") || "").split("|");
                    $scope.rockieslitecombosflowpackagecodes = ($("body").attr("data-activity-rockieslitecombosflowpackagecodes") || "").split("|");
                }

                //console.log("TODO: set shopping cart custom fields - merge fee", $scope.mergeproductwithparentforproductcodes);

                var isTaxInclusive = $scope.anonymUser && $scope.anonymUser.isTaxInclusive;

                $scope.cart && $scope.cart.Items && _.each($scope.cart.Items, function (sitem, index) {
                    sitem._mergedProductsPrice = 0;
                    var isMergedProductParentAssigned = false;

                    sitem.BookingToQuote && sitem.BookingToQuote.Components && _.each(sitem.BookingToQuote.Components, function (scomp, index) {
                        if (!isMergedProductParentAssigned && !$scope.utils.isFee(scomp) && !scomp.isAttachedToParent) {
                            isMergedProductParentAssigned = true;
                            scomp._isMergedProductParent = false;
                        }

                        if ($scope.mergeproductwithparentforproductcodes && $scope.mergeproductwithparentforproductcodes.indexOf(scomp.ProductCode) >= 0) {
                            scomp.ShowInCart = false; // overwrite

                            var priceToBeMerged = isTaxInclusive ? (scomp.PriceIncludingTaxes || scomp.Price) : scomp.Price;
                            sitem._mergedProductsPrice += priceToBeMerged;
                        }
                    });

                    sitem.BookingToQuote && sitem.BookingToQuote.Packages && _.each(sitem.BookingToQuote.Packages, function (pkg, index) {
                        var packageCode = pkg.PackageCode;
                        var isRockies2025CombosFlow = ($scope.rockies2025combosflowpackagecodes || "").length && $scope.rockies2025combosflowpackagecodes.indexOf(packageCode) >= 0;
                        var isRockiesCombosFlow = ($scope.rockiescombosflowpackagecodes || "").length && $scope.rockiescombosflowpackagecodes.indexOf(packageCode) >= 0;
                        var isRockiesValueCombosFlow = ($scope.rockiesvaluecombosflowpackagecodes || "").length && $scope.rockiesvaluecombosflowpackagecodes.indexOf(packageCode) >= 0;
                        //var isRockiesLiteCombosFlow = ($scope.rockieslitecombosflowpackagecodes || "").length && $scope.rockieslitecombosflowpackagecodes.indexOf(packageCode) >= 0;
                        pkg._hideValidFromLabel = isRockies2025CombosFlow || isRockiesCombosFlow || isRockiesValueCombosFlow;

                        if (pkg.TravelWindow > 0) {
                            var label = $scope.labelUtils.getLabel("checkout.details.pkg-valid-window").replace("{0}", $scope.utils.formatDate(pkg.StartDate, $scope.dateFormat));

                            label = label.replace("{1}", moment(pkg.StartDate).add(pkg.TravelWindow - 1, "days").format($scope.dateFormat));
                            pkg._travelWindowDatesLabel = label;
                        }
                    });
                });
            };

            var phoneDummyInput = null;
            var phoneDummyObj = null;
            function validatePhoneInputInternal(inputValue, countryValue) {
                if (!phoneDummyInput) {
                    phoneDummyInput = document.getElementById("phoneDummy");
                    phoneDummyObj = phoneDummyInput && window.intlTelInput(phoneDummyInput, {
                        //loadUtilsOnInit: "path/to/utils.js"     
                        strictMode: false,
                        formatAsYouType: true,
                        separateDialCode: true,
                        initialCountry: "ca",
                        countryOrder: ["us", "ca", "uk", "is", "de"]
                    }) || null;
                }
                if (!phoneDummyInput || !phoneDummyObj) return true; // leave
                phoneDummyInput.value = inputValue;
                if (countryValue) {
                    //phoneDummyObj
                    var foundCountry = $scope.availableCountries && $scope.availableCountries.find(function (country) { return country && country.name == countryValue; });
                    if (foundCountry && foundCountry.code) {
                        phoneDummyObj.setCountry(foundCountry.code.toLowerCase());
                    }
                }

                return phoneDummyObj.isValidNumber();
            }

            function getPhoneInputValidatedInternal(inputValue, countryValue, fallbackValue) {
                var origInput = (inputValue || "").trim();
                if (!origInput) return fallbackValue || "";

                // validate the initial value
                var origInputValid = validatePhoneInputInternal(origInput, countryValue);
                if (origInputValid) return origInput;

                if (origInput[0] != "+") {
                    origInput = "+" + origInput;
                    origInputValid = validatePhoneInputInternal(origInput, countryValue);
                    if (origInputValid) {
                        return origInput;
                    }
                }

                return fallbackValue || "";                  
            }

            $scope.init = function () {
                if ($scope.displayInlineCCInput) {
                    BAPIjs.setPublicToken($scope.anonymUser && $scope.anonymUser.borgunPublicApiKey);
                }

                var customerTokenObj = jwtService.getCustomerTokenObj();
                var customer = jwtService.getCustomer();

                $scope.isAuthenticated = customer ? true : false;
                $scope.isAgent = customer && customer.isAgency;//(customerTokenObj && customerTokenObj.loginType && customerTokenObj.loginType === "agent");
                var fillAgentContactsIfAgent = $scope.isAgent ? $scope.fillAgencyContactsAsync : function (callback) { callback(); };


                $scope.isAffiliate = customer && !customer.documentsToAgency;

                fillAgentContactsIfAgent(function () {
                    shoppingCartService.getStorageCart(function (shoppingCart) {
                        $scope.isFOC = $scope.$parent.selectedGeographyCode == "FOC";
                        $scope.isFOLV = $scope.$parent.selectedGeographyCode == "FOLV";
                        $scope.cart = shoppingCart;
                        $scope.setCartCustomFields();
                        $scope.checkShippingMethodRequired($scope.cart);

                        showInfoModalIfCartPriceChangeDetected().then(function (result) {
                            console.log("check shopping cart price change: ", result);

                            if (shoppingCart && shoppingCart.Items && shoppingCart.Items.length > 0) {

                                initDisclaimersFromCart();
                                initShowConsentCheckbox();
                                if (!($scope.cart.optionalExtras || "").length) {
                                    $scope.getOptionalExtras();
                                } else {
                                    $scope.hideOptionalExtras();
                                }

                                //set price breakdown for packages
                                //disabled, will come from booking quote
                                //_.each($scope.cart.Items, function (cartItem) {
                                //    if (((cartItem.BookingToQuote && cartItem.BookingToQuote.Packages) || "").length) {
                                //        var priceBreakdownComp = _.find(cartItem.BookingToQuote.Packages[0].Components, function (pcomp) {
                                //            return (pcomp.PriceBreakdown || "").length;
                                //        });
                                //        if (priceBreakdownComp) {
                                //            cartItem.BookingToQuote.Packages[0].PriceBreakdown = shoppingCartService.parsePriceBreakdown(priceBreakdownComp.PriceBreakdown);
                                //        }
                                //    }
                                //});

                                //
                                //$scope.checkExitIntentPopup();
                                // only apply if there's a product in the cart and the productCode is found
                                var firstCartItem = $scope.cart && (($scope.cart.Items || "").length == 1 ? $scope.cart.Items[0] : null);
                                var firstComp = firstCartItem && firstCartItem.BookingToQuote
                                    && firstCartItem.BookingToQuote.Components && firstCartItem.BookingToQuote.Components[0];

                                firstComp && $scope.checkExitIntentPopup($scope.anonymUser, firstComp.ProductCode);

                            } else {
                                window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
                                return;
                            }


                            $scope.isLoading = false;
                            setTimeout(function () { jQuery("body").click(); });

                            if (shoppingCart.Quote) {
                                $scope.showCanPayAtHotel = shoppingCart.Quote.CanPayAtHotel;
                                $scope.depositAmountDue = parseFloat(shoppingCart.Quote.DepositAmountDue);
                                $scope.dueOnArrival = parseFloat(shoppingCart.Quote.DueOnArrival);
                                if (shoppingCart.isUpdate && shoppingCart.UpdatedBooking) {
                                    $scope.ammountPaid = parseFloat(shoppingCart.UpdatedBooking.amountPaid || 0);
                                    $scope.depositAmountDue = $scope.depositAmountDue - $scope.ammountPaid;
                                    $scope.ccReqForUpdate = false;
                                    $scope.updateBookingPayStatus = 0; // 0 - no payment required, 1: amount is owed, -1: needs refund
                                    if ($scope.depositAmountDue > 0) { // There’s an amount owing on the booking
                                        $scope.updateBookingPayStatus = 1;
                                        $scope.ccReqForUpdate = true;
                                    } else if ($scope.depositAmountDue < 0) { //	There’s a refund owing on the booking                                  
                                        // The user has exactly one credit card payment on their booking
                                        //    - We need to process the refund against the original payment.When you load a booking, 
                                        //      if booking.CreditCardPayment.PaymentDetailId is not null / empty,
                                        //      then we will process the refund against that payment.Do not collect a credit card from the user on checkout,
                                        //      instead, inform hem that the refund will be processed on the card that was used for the booking. 
                                        //      In the UpdateBooking API call, pass the booking.CreditCardPayment object back to us(with the PaymentDetailId property set)
                                        $scope.updateBookingPayStatus = -1;
                                        $scope.ccReqForUpdate = true;

                                        if ((shoppingCart.UpdatedBooking.payments || []).length > 0 && ((shoppingCart.UpdatedBooking.CreditCardPayment && shoppingCart.UpdatedBooking.CreditCardPayment.PaymentDetailId) || !!shoppingCart.UpdatedBooking.CreditCardPurchaseWithToken)) {
                                            $scope.ccReqForUpdate = false;
                                        }
                                    }
                                }

                                $scope.canChangeConfirmationEmailAddress = shoppingCart.Quote.CanChangeConfirmationEmailAddress;
                                $scope.showCanPayWithAR = $scope.isAgent && shoppingCart.Quote.CanPayWithAccountsReceivable;
                                $scope.model.payWithAR = $scope.showCanPayWithAR;//checked by default
                            }

                            $scope.skipCC = shoppingCart.Quote && parseInt(shoppingCart.Quote.Price) <= 0 && !$scope.showCanPayAtHotel; //(shoppingCart.DiscountCodes || "").length &&


                            $scope.showUnaccompaniedChildMessage = canShowUnaccompaniedChildMessage();

                            if ($scope.cart.isUpdate && $scope.cart.UpdatedBooking) {
                                $scope.isCreateButtonVisible = false;
                                if ($scope.cart.UpdatedBooking.customers[0]) {
                                    var cust = $scope.cart.UpdatedBooking.customers[0];
                                    $scope.model.emailAddress = $scope.model.emailAddress_c = (cust.email) || undefined;
                                    $scope.model.travelerFirstName = cust.firstName;
                                    $scope.model.travelerLastName = cust.lastName;                                   
                                    $scope.model.travelerEmail = cust.email;
                                    if (cust.address) {
                                        if (cust.address.city)
                                            $scope.model.travelerCity = cust.address.city;
                                        if (cust.address.country)
                                            $scope.model.travelerCountry = cust.address.country;
                                        if (cust.address.postalCode)
                                            $scope.model.travelerZipCode = cust.address.postalCode;
                                        if (cust.address.street)
                                            $scope.model.travelerAddress = cust.address.street;

                                        if (cust.address.province)
                                            $scope.prevtravelerProvState = cust.address.province;

                                        $scope.model.billingCity = cust.address.city;
                                        $scope.model.billingCountry = cust.address.country;
                                        $scope.model.zipCode = cust.address.postalCode;
                                        $scope.model.billingAddress = cust.address.street;
                                        $scope.model.provState = cust.address.province;
                                    }
                                    //
                                    var phone = cust.phoneNumbers.find(function (ph) {
                                        return ph.type.toLowerCase() == "mobile";
                                    });
                                    if (phone && phone.number) {
                                        //$scope.model.travelerPhone = phone.number;
                                        $scope.model.travelerPhone = getPhoneInputValidatedInternal(phone.number, $scope.model.travelerCountry, phone.number);
                                    }

                                   
                                    //
                                }
                                $scope.fillAvailableRegions(true);
                                resizeSliderPanel();

                            } else {
                                if (customer) {
                                    $scope.isCreateButtonVisible = false;

                                    //fill default values


                                    //$scope.model.firstName = customer.firstName;
                                    //$scope.model.lastName = customer.lastName;

                                    $scope.model.emailAddress = $scope.model.emailAddress_c = customer.email;

                                    var checkoutModel = jwtService.getCheckoutModel(false);
                                    if (checkoutModel) {
                                        $scope.model.travelerFirstName = checkoutModel.travelerFirstName;
                                        $scope.model.travelerLastName = checkoutModel.travelerLastName;
                                        $scope.model.travelerPhone = checkoutModel.travelerPhone;
                                        if (checkoutModel.travelerEmail)
                                            $scope.model.travelerEmail = checkoutModel.travelerEmail;

                                        if (checkoutModel.email)
                                            $scope.model.emailAddress = $scope.model.emailAddress_c = checkoutModel.email;
                                    }


                                    if (!$scope.isAgent) {
                                        $scope.model.travelerFirstName = ($scope.model.travelerFirstName || "").length ? $scope.model.travelerFirstName : customer.firstName;
                                        $scope.model.travelerLastName = ($scope.model.travelerLastName || "").length ? $scope.model.travelerLastName : customer.lastName;


                                        if (($scope.model.travelerPhone || "").length === 0) {
                                            var mobilePhone = _.find(customer.phoneNumbers, function (ph) { return ph.type === "Mobile"; });
                                            $scope.model.travelerPhone = mobilePhone ? mobilePhone.number : "";
                                        }
                                    }


                                    if (customer.address) {

                                        if (!$scope.isAgent) {
                                            if (customer.address.city)
                                                $scope.model.travelerCity = customer.address.city;
                                            if (customer.address.country)
                                                $scope.model.travelerCountry = customer.address.country;
                                            if (customer.address.postalCode)
                                                $scope.model.travelerZipCode = customer.address.postalCode;
                                            if (customer.address.street)
                                                $scope.model.travelerAddress = customer.address.street;

                                            if (customer.address.province)
                                                $scope.prevtravelerProvState = customer.address.province;
                                        }

                                        if (checkoutModel) {
                                            if (checkoutModel.travelerCity)
                                                $scope.model.travelerCity = checkoutModel.travelerCity;
                                            if (checkoutModel.travelerCountry)
                                                $scope.model.travelerCountry = checkoutModel.travelerCountry;
                                            if (checkoutModel.travelerZipCode)
                                                $scope.model.travelerZipCode = checkoutModel.travelerZipCode;
                                            if (checkoutModel.travelerAddress)
                                                $scope.model.travelerAddress = checkoutModel.travelerAddress;
                                            if (checkoutModel.travelerProvState)
                                                $scope.prevtravelerProvState = checkoutModel.travelerProvState;
                                        }


                                        $scope.model.billingCity = customer.address.city;
                                        $scope.model.billingCountry = customer.address.country;
                                        $scope.model.zipCode = customer.address.postalCode;
                                        $scope.model.billingAddress = customer.address.street;
                                        $scope.model.provState = customer.address.province;

                                        if (checkoutModel && !$scope.model.billingCity && !$scope.model.billingCountry && !$scope.model.zipCode && !$scope.model.billingAddress && !$scope.model.provState) {
                                            $scope.model.billingCity = checkoutModel.billingCity;
                                            $scope.model.billingCountry = checkoutModel.billingCountry;
                                            $scope.model.zipCode = checkoutModel.zipCode;
                                            $scope.model.billingAddress = checkoutModel.billingAddress;
                                            $scope.model.provState = checkoutModel.provState;
                                        }

                                    } else {
                                        if (checkoutModel.travelerCity)
                                            $scope.model.travelerCity = checkoutModel.travelerCity;
                                        if (checkoutModel.travelerCountry)
                                            $scope.model.travelerCountry = checkoutModel.travelerCountry;
                                        if (checkoutModel.travelerZipCode)
                                            $scope.model.travelerZipCode = checkoutModel.travelerZipCode;
                                        if (checkoutModel.travelerAddress)
                                            $scope.model.travelerAddress = checkoutModel.travelerAddress;
                                        if (checkoutModel.travelerProvState)
                                            $scope.prevtravelerProvState = checkoutModel.travelerProvState;

                                        $scope.model.billingCity = checkoutModel.billingCity;
                                        $scope.model.billingCountry = checkoutModel.billingCountry;
                                        $scope.model.zipCode = checkoutModel.zipCode;
                                        $scope.model.billingAddress = checkoutModel.billingAddress;
                                        $scope.model.provState = checkoutModel.provState;


                                    }

                                    $scope.fillAvailableRegions(true);
                                    //$scope.model.sendNewslettersAndPromotions = checkoutModel ? checkoutModel.sendNewslettersAndPromotions : $scope.model.sendNewslettersAndPromotions;
                                    $scope.model.termsAndConditions = checkoutModel ? checkoutModel.termsAndConditions : $scope.model.termsAndConditions;
                                    //   $scope.model.payAtHotel = checkoutModel ? checkoutModel.payAtHotel : $scope.model.payAtHotel;
                                    $scope.model.payWithAR = checkoutModel ? checkoutModel.payWithAR : $scope.model.payWithAR;

                                    resizeSliderPanel();
                                } else {
                                    var anonymousCheckoutModel = jwtService.getCheckoutModel(false);
                                    if (anonymousCheckoutModel) {
                                        $scope.model = anonymousCheckoutModel;
                                        $scope.fillAvailableRegions();
                                        //$scope.model.cardNumber = "";
                                        //$scope.model.expirationMonth = "";
                                        //$scope.model.expirationYear = "";
                                        // $scope.model.cvcCode = "";
                                        resizeSliderPanel();
                                    }
                                }
                            }


                            // resizeSliderPanel();

                            $scope.passengerList = [];
                            $scope.promptforguestphone = false;
                            var custIndex = 1;// main traveler will be passenger#1
                            _.each(shoppingCart.Items, function (sitem, index) {
                                if (sitem.BookingToQuote) {
                                    if (sitem.BookingToQuote.Components) {
                                        _.each(sitem.BookingToQuote.Components, function (scomp, index) {
                                            if (scomp.NeedFullPassengerList) {
                                                $scope.promptforguestphone = $scope.promptforguestphone || $scope.promptforguestphoneproductcodes.indexOf(scomp.ProductCode) >= 0;
                                                $scope.passengerList.push({
                                                    item: sitem,
                                                    component: scomp,
                                                    adults: [],
                                                    children: [],
                                                    infants: []
                                                });
                                                for (var i = 0; i < scomp.NumberOfAdults; i++) { // main traveler will be passenger#1
                                                    $scope.passengerList[$scope.passengerList.length - 1].adults.push({
                                                        id: "IBE" + (i === 0 ? 1 : (custIndex)),
                                                        firstName: "",
                                                        lastName: ""
                                                    });
                                                    custIndex++;
                                                }

                                                for (var j = 0; j < scomp.NumberOfChildren; j++) {
                                                    $scope.passengerList[$scope.passengerList.length - 1].children.push({
                                                        id: "IBE" + (custIndex++),
                                                        firstName: "",
                                                        lastName: ""
                                                    });
                                                }

                                                for (var k = 0; k < scomp.NumberOfInfants; k++) {
                                                    $scope.passengerList[$scope.passengerList.length - 1].infants.push({
                                                        id: "IBE" + (custIndex++),
                                                        firstName: "",
                                                        lastName: ""
                                                    });
                                                }

                                            }
                                        }); //end each
                                    }

                                    if (sitem.BookingToQuote.Packages) {
                                        _.each(sitem.BookingToQuote.Packages, function (pck, index) {
                                            var pckComp = _.find(pck.Components, function (pckComp) {
                                                return pckComp.ProductCode == pck.pckNeedPassListCompProductCode;
                                            });
                                            if (pck.NeedFullPassengerList && pckComp) {
                                                $scope.passengerList.push({
                                                    item: sitem,
                                                    pck: pck,
                                                    pckComp: pckComp,
                                                    adults: [],
                                                    children: [],
                                                    infants: []
                                                });
                                                for (var i = 0; i < pck.NumberOfAdults; i++) { // main traveler will be passenger#1
                                                    if ((i == 0 && $scope.passengerList[$scope.passengerList.length - 1].adults.length == 0) || i > 0) {
                                                        $scope.passengerList[$scope.passengerList.length - 1].adults.push({
                                                            id: "IBE" + (i === 0 ? 1 : (custIndex)),
                                                            firstName: "",
                                                            lastName: ""
                                                        });
                                                        custIndex++;
                                                    }
                                                }

                                                for (var j = 0; j < pck.NumberOfChildren; j++) {
                                                    $scope.passengerList[$scope.passengerList.length - 1].children.push({
                                                        id: "IBE" + (custIndex++),
                                                        firstName: "",
                                                        lastName: ""
                                                    });
                                                }

                                                for (var k = 0; k < pck.NumberOfInfants; k++) {
                                                    $scope.passengerList[$scope.passengerList.length - 1].infants.push({
                                                        id: "IBE" + (custIndex++),
                                                        firstName: "",
                                                        lastName: ""
                                                    });
                                                }

                                            }
                                        }); //end each
                                    }//

                                }
                            });



                            shoppingCartService.getHotelsComponents(shoppingCart, function (spComps) {
                                if (spComps && spComps.length > 0) {
                                    $scope.hasCartHotels = true;
                                    var tempComps = [];
                                    _.map(spComps, function (spCmp) {
                                        tempComps.push(
                                            {
                                                name: spCmp.isPackageComponent ? spCmp.ProductName : spCmp.BookingToQuote.Components[0].Name,
                                                contactName: "",
                                                phoneNumber: "",
                                                specialRequest: "",
                                                roomRequest: "",
                                                origComp: spCmp
                                            });
                                    });

                                    $scope.specReqComps = tempComps;
                                    resizeSliderPanel();
                                } else {
                                    $scope.specReqComps = [{
                                        name: undefined,
                                        isGeneric: true,
                                        contactName: "",
                                        phoneNumber: "",
                                        specialRequest: "",
                                        roomRequest: "",
                                        origComp: undefined
                                    }];
                                    resizeSliderPanel();
                                }
                            });

                            if (!jwtService.getCustomerToken()) {
                                //$scope.creCards = cresecureService.getSessionCards();
                                resizeSliderPanel();
                                //setTimeout(function () {
                                //    refreshInputs("#InlineCreditCardContainer");
                                //});
                            } else {
                                //cresecureService.setSessionCards([]);

                                if (!$scope.isTempusPaymentProvider) {
                                    var getParams = {
                                        urlPrefix: ($("body").data("weburl") ? $("body").data("weburl") : ""),
                                        token: jwtService.getPrincipalToken()
                                    }
                                    $scope.isLoading = true;
                                    var paymentServiceInstance = $scope.displayInlineCCInput ? borgunPaymentService : paymentService;

                                    paymentServiceInstance.getCreditCards(getParams, function (getResult) {
                                        $scope.isLoading = false;
                                        if (getResult.success) {
                                            $scope.creCards = getResult.data;
                                            $scope.ensureCreditCardId();
                                            resizeSliderPanel();

                                        }

                                        var card = jwtService.getCurrentCard();
                                        if (card) {
                                            $scope.creCards.push(card);
                                            $scope.ensureCreditCardId();
                                            $scope.selectedCreCard = card;
                                            $scope.selectedCreCard.useAsAnonymous = true;
                                            _.each($scope.creCards, function (val, index) { val.index = index; });

                                            //$scope.model.cardNumber = $scope.selectedCreCard.cardNumber || $scope.selectedCreCard.cardnumber;
                                            // $scope.model.expirationMonth = $scope.selectedCreCard.expirationMonth;
                                            // $scope.model.expirationYear = $scope.selectedCreCard.expirationYear;

                                            //$scope.model.cvcCode = "123";

                                            setTimeout(function () {
                                                jQuery($element).find("[name='addCard']").change();
                                            }, 0);
                                            resizeSliderPanel();
                                            //setTimeout(function () {
                                            //    refreshInputs("#InlineCreditCardContainer");
                                            //});
                                            jwtService.clearSelectedCard();
                                        }
                                    });
                                }

                                if ($scope.isAgent && !$scope.isTempusPaymentProvider) {
                                    $scope.showUseCustomerCard = $scope.isAffiliate;
                                    $scope.model.useCustomerCard = $scope.isAffiliate;
                                    resizeSliderPanel();
                                    //setTimeout(function () {
                                    //    jQuery($element).find("input:not(.ng-empty)").change();
                                    //}, 0);
                                }
                            }

                            var externalPromoCode = shoppingCartService.getExternalPromoCode();
                            if (externalPromoCode) {
                                $scope.promoCode = (externalPromoCode || "").trim();
                                $scope.applyPromoCode();
                                shoppingCartService.setExternalPromoCode(null);
                            }
                        });
                    });
                });
            };

            var isGeneralCtrlReady = $scope.$parent.generalCtrlReady;
            if (isGeneralCtrlReady) {
                $scope.prepareData();
            } else {
                $scope.$on("generalCtrlReady", function (event, args) {
                    $scope.prepareData();
                });
            }
            //var t = jwtService.getPrincipalToken();

            //if (t && t.length > 0) {


            //    $scope.$on("generalControllerInitilized", function (event, args) { //generalControllerInitilized            
            //        $scope.prepareData();
            //    });

            //} else {
            //    $scope.isLoading = true;
            //    $scope.$on("getPrincipalToken", function (event, args) { //generalControllerInitilized
            //        $scope.prepareData();
            //    });
            //};


            $scope.$on("LoggedOut", function (event, data) {
                //$scope.isCreateButtonVisible = true;
            });

        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("customerLoginCtrl", [
        "utilsFactory", "jwtService", "$scope", "$rootScope", "userService", "validHelper", "customerService", "shoppingCartService", "$element", "$window", "$http", "$auth", "ExternalAuthProvider",
        function (utilsFactory, jwtService, $scope, $rootScope, userService, validHelper, customerService, shoppingCartService, $element, $window, $http, $auth, ExternalAuthProvider) {

            $scope.utils = utilsFactory;
            $scope.validHelper = validHelper;
            $scope.isLoading = true;
            $scope.showLoginFormId = 1;
            $scope.forgotModel = {
                username: ""
            };

            $scope.loginType = $($element).attr("data-login-type");

            $scope.loginModel = {                
                username: "",
                password: "",
                loading: false,
                resendConfirmationEmailUsername:"" 
            };
            $scope.registerModel = {
                username: "",
                password: "",
                password_c: ""
            };

            $scope.$watch("showModal.Login", function (newValue, oldValue) {
                if (!newValue) {
                    $scope.showLoginFormId = 1;
                }
            });

            $scope.submitRegister = function (isValid) {
                var generalCtrl = $scope.$parent;

                if ($scope.loginModel.isLoading === true)
                    return false;
                if (isValid) {

                    if (jwtService.getToken() == null) {
                        // $scope.init();
                        return false;
                    }


                    $scope.loginModel.isLoading = true;
                    $scope.registerModel.response = null;
                    $scope.registerModel.errors = [];
                    $http({
                        method: "POST",
                        url: $scope.getWebUrl() + "/api/authentication/register",
                        headers: {
                            "Authorization": jwtService.getToken(),
                            'Content-Type': "application/json"
                        },
                        data: {
                            "Email": $scope.registerModel.emailAddress,
                            "FirstName": $scope.registerModel.firstName,
                            "LastName": $scope.registerModel.lastName,
                            "Username": $scope.registerModel.emailAddress,
                            "Password": $scope.registerModel.password
                        }
                    })
                        .then(
                            function (result) {
                                if (result == null || result.data == null) {
                                    $scope.registerModel.errors = [{ errorMessage: utilsFactory.getLabel("general.loginModal.registration.error") }];
                                    $scope.loginModel.isLoading = false;
                                    return false;
                                }

                                if (result.data.token != null) {
                                    var oldRegion = jwtService.getGeography();
                                    jwtService.setCustomerToken(result.data, oldRegion);
                                    generalCtrl.initCustomerRecord(true);
                                    if ($scope.loginType === "checkout" && ($scope.cart && ($scope.cart.Items || "").length)) {
                                        setTimeout(function () { window.location = "/checkout"; }, 3000);
                                        return true;
                                    }
                                    $scope.registerModel.response = utilsFactory.getLabel("general.loginModal.registration.success");
                                    $scope.registerModel.error = null;
                                    //  $scope.showModal['Login'] = false;
                                } else if (result.data.errors != null && result.data.errors.length > 0) {
                                    $scope.registerModel.errors = result.data.errors;
                                }

                                $scope.loginModel.isLoading = false;
                                //  init();
                                return true;
                            },
                            function (response) {
                                $scope.loginModel.isLoading = false;

                                if (response.data.errors && response.data.errors.length > 0) {
                                    $scope.registerModel.errors = response.data.errors;
                                } else {
                                    $scope.registerModel.errors = [
                                        {
                                            "errorMessage": utilsFactory.getLabel("general.loginModal.registration.error")
                                        }
                                    ];
                                }

                                console.log(response);
                            });
                }
                $scope.registerModel.submitted = true;
                return false;
            };
            $scope.submitForgotPassword = function (isValid, $forgotModel, $loadingModel) {
                if ($loadingModel.isLoading) return false;
                // check to make sure the form is completely valid
                $forgotModel.submitted = true;
                if (isValid) {
                    $loadingModel.isLoading = true;
                    $forgotModel.error = null;
                    $forgotModel.response = null;
                    $http({
                        method: "POST",
                        url: $scope.getWebUrl() + "/api/authentication/forgotpassword",
                        headers: {
                            "Authorization": jwtService.getToken(),
                            'Content-Type': "application/json"
                        },
                        data: {
                            "Username": $forgotModel.username
                        }
                    })
                        .then(
                            function (result) {
                                if (result == null) {
                                    $forgotModel.error = utilsFactory.getLabel("general.loginModal.forgotPwd.error");
                                    $loadingModel.isLoading = false;
                                    return false;
                                }

                                if (result.data && result.data.errors != null && result.data.errors.length > 0) {
                                    $forgotModel.error = result.data.errors[0].errorMessage;
                                } else {
                                    $scope.forgotForm.username.activated = false;
                                    $forgotModel.username = "";
                                    $forgotModel.submitted = false;
                                    $forgotModel.response = utilsFactory.getLabel("general.loginModal.forgotPwd.success");
                                }

                                $loadingModel.isLoading = false;
                                //  init();
                                return true;
                            },
                            function (response) {
                                $loadingModel.isLoading = false;
                                $forgotModel.error = utilsFactory.getLabel("general.loginModal.forgotPwd.error");
                                console.log(response);
                            });
                }


                return false;
            };

            $scope.resendConfirmationEmail = function (isValid) {
                if (!isValid) return;
                if ($scope.loginModel.isLoading) return false;

                $scope.loginModel.isLoading = true;
                $scope.loginModel.resendConfirmationEmailUsername = $scope.loginModel.username;
                $scope.loginModel.errors = [];

                $scope.showConfirmationEmailResponse = false;

                userService.resendEmailConfirmation({
                    urlPrefix: $scope.getWebUrl(),
                    dataToPost: {
                        "Username": $scope.loginModel.username
                    }
                }, function (result) {
                    $scope.loginModel.isLoading = false;
                    if (!result.success) {
                        $scope.loginModel.errors = (result.error.errors || "").length > 0 ? result.error.errors : [{ errorMessage: "An error has occured!" }];
                    } else {
                        $scope.showConfirmationEmailResponse = true;
                        $scope.showReconfirmEmailBtn = false;
                    }
                });
            };

            $scope.submitLogin = function (isValid) {
                $scope.showConfirmationEmailResponse = false;

                var generalCtrl = $scope.$parent;

                if ($scope.loginModel.isLoading) return false;

                if (jwtService.getToken() == null) {
                    //  init();
                    return false;
                }

                // check to make sure the form is completely valid
                if (isValid) {
                    $scope.showReconfirmEmailBtn = false;

                    $scope.loginModel.resendConfirmationEmailUsername = $scope.loginModel.username;
                    $scope.loginModel.isLoading = true;
                    $scope.loginModel.errors = [];

                    var hasTracking = $scope.$parent.trackingInfo &&
                        ($scope.$parent.trackingInfo.CRMVisitId || $scope.$parent.trackingInfo.CRMVisitorId);
                    var dataToPost = {
                        "Username": $scope.loginModel.username,
                        "Password": $scope.loginModel.password
                    };
                    var oldWebLink = jwtService.getWebLink();
                    dataToPost.WebLink = ($scope.$parent.trackingInfo && $scope.$parent.trackingInfo.WebLink) || oldWebLink;


                    if (hasTracking) {
                        dataToPost.CRMVisitId = $scope.$parent.trackingInfo.CRMVisitId;
                        dataToPost.CRMVisitorId = $scope.$parent.trackingInfo.CRMVisitorId;
                    }

                    $http({
                        method: "POST",
                        url: $scope.getWebUrl() + "/api/authentication/customerlogin",
                        headers: {
                            "Authorization": jwtService.getToken(),
                            'Content-Type': "application/json"
                        },
                        data: dataToPost
                    })
                        .then(
                            function (result) {
                                if (result == null || result.data == null) {
                                    $scope.loginModel.errors = [{ errorMessage: utilsFactory.getLabel("general.loginModal.login.error") }];
                                    $scope.loginModel.isLoading = false;
                                    return false;
                                }
                                if (result.data.token != null) {
                                    generalCtrl.refreshCart(result.data.token, function () {
                                        var oldRegion = jwtService.getGeography();
                                        result.data.loginType = $scope.loginType;
                                        var customerToken = result.data;
                                        jwtService.setCustomerToken(result.data, oldRegion);
                                        jwtService.setCustomerLogin($scope.loginModel.username);

                                        generalCtrl.initCustomerRecordWithCallback(true, function (data) {
                                            var customer = generalCtrl.getCustomer();

                                            if (customer) {
                                                customer.isAgent = customer.isAgency;
                                                jwtService.setCustomer(customer);

                                                if ($scope.loginType === "checkout" && ($scope.cart && ($scope.cart.Items || "").length)) {
                                                    window.location = "/checkout";
                                                    return;
                                                }

                                                if (customer.isAgent) {
                                                    customerToken.loginType = "agent";
                                                    jwtService.setCustomerToken(customerToken);

                                                    if ($scope.loginType === "agent") {
                                                        window.location = "/"; // /choose-region
                                                    } else {
                                                        location.reload();
                                                    }

                                                    // 
                                                    return;
                                                }


                                                $scope.loginModel.errors = [];
                                                $scope.showModal["Login"] = false;

                                                if ($scope.loginType === "agent") {
                                                    window.location = "/"; // /choose-region
                                                } else {
                                                    location.reload();
                                                }
                                            } else {
                                                $scope.loginModel.isLoading = false;
                                            }
                                        });
                                    });
                                } else {
                                    if (result.data.errors != null && result.data.errors.length > 0) {
                                        $scope.loginModel.errors = result.data.errors;
                                    } else {
                                        $scope.loginModel.errors = [{ errorMessage: utilsFactory.getLabel("general.loginModal.login.error") }];
                                    }
                                    $scope.loginModel.isLoading = false;
                                }

                                $scope.showReconfirmEmailBtn = result && result.data && !result.data.emailConfirmed && (result.data.HttpResponseCode == 401);
                                //  init();
                                return true;
                            },
                            function (response) {
                                $scope.loginModel.isLoading = false;
                                if (response && response.data && response.data.errors && response.data.errors.length > 0) {
                                    $scope.loginModel.errors = response.data.errors;
                                } else {
                                    $scope.loginModel.errors = [{ errorMessage: utilsFactory.getLabel("general.loginModal.login.error") }];
                                }

                                console.log(response);
                            });
                }

                $scope.loginModel.submitted = true;
                return false;
            };

            $scope.submitExternalRegister = function (registerModel) {
                var generalCtrl = $scope.$parent;
                if (!registerModel) {
                    return false;
                }
                if (jwtService.getToken() == null) {
                    init();
                    return false;
                }

                $scope.loginModel.isLoading = true;

                $http({
                    method: "POST",
                    url: $scope.getWebUrl() + "/api/authentication/externalregister",
                    headers: {
                        "Authorization": jwtService.getToken(),
                        'Content-Type': "application/json"
                    },
                    data: {
                        "Email": registerModel.Email,
                        "FirstName": registerModel.FirstName,
                        "LastName": registerModel.LastName,
                        "AccessToken": registerModel.AccessToken,
                        "Provider": registerModel.Provider
                    }
                })
                    .then(
                        function (result) {
                            if (result == null || result.data == null) {
                                $scope.loginModel.externalError = utilsFactory.getLabel("general.loginModal.externalLogin.error");
                                $scope.loginModel.isLoading = false;
                                return false;
                            }

                            if (result.data.token != null) {
                                var oldRegion = jwtService.getGeography();
                                jwtService.setCustomerToken(result.data, oldRegion);
                                generalCtrl.initCustomerRecordWithCallback(true, function (data) {
                                    $scope.loginModel.isLoading = false;
                                    $scope.loginModel.errors = [];
                                    $scope.showModal["Login"] = false;
                                });
                            } else if (result.data.errors != null && result.data.errors.length > 0) {
                                $scope.loginModel.externalError = result.data.errors[0].errorMessage;
                            }

                            $scope.loginModel.isLoading = false;
                            //  init();
                            return true;
                        },
                        function (response) {
                            $scope.loginModel.isLoading = false;
                            $scope.loginModel.externalError = utilsFactory.getLabel("general.loginModal.externalLogin.error");
                            console.log(response);
                        });


                return true;
            };

            $scope.submitExternalLogin = function (provider, externalToken) {
                var generalCtrl = $scope.$parent;
                if (jwtService.getToken() == null) {
                    //init();
                    return false;
                }

                if ($scope.loginModel.isLoading) return false;

                $scope.loginModel.isLoading = true;

                $http({
                    method: "POST",
                    url: $scope.getWebUrl() + "/api/authentication/externallogin",
                    headers: {
                        "Authorization": jwtService.getToken(),
                        'Content-Type': "application/json"
                    },
                    data: {
                        "AccessToken": externalToken,
                        "Provider": provider
                    }
                })
                    .then(
                        function (result) {
                            if (result == null || result.data == null) {
                                $scope.loginModel.externalError = utilsFactory.getLabel("general.loginModal.externalLogin.error");
                                $scope.loginModel.isLoading = false;
                                return false;
                            }
                            if (result.data.token != null) {
                                var oldRegion = jwtService.getGeography();
                                jwtService.setCustomerToken(result.data, oldRegion);
                                generalCtrl.initCustomerRecordWithCallback(true, function (data) {
                                    $scope.loginModel.isLoading = false;
                                    $scope.loginModel.errors = [];
                                    $scope.showModal["Login"] = false;
                                });
                            } else {
                                if (result.data.errors != null && result.data.errors.length > 0) {
                                    $scope.loginModel.externalError = result.data.errors[0].errorMessage;
                                } else {
                                    $scope.loginModel.externalError = utilsFactory.getLabel("general.loginModal.externalLogin.error");
                                }
                            }

                            $scope.loginModel.isLoading = false;
                            //  init();
                            return true;
                        },
                        function (response) {
                            $scope.loginModel.isLoading = false;
                            //user doesn't exist so register
                            if ($scope.externalUser == null) {
                                $scope.loginModel.externalError = utilsFactory.getLabel("general.loginModal.externalLogin.error");
                                return false;
                            }
                            var registerModel = {
                                "Email": $scope.externalUser.email,
                                "FirstName": $scope.externalUser.first_name,
                                "LastName": $scope.externalUser.last_name,
                                "AccessToken": externalToken,
                                "Provider": provider
                            };

                            $scope.submitExternalRegister(registerModel);

                            return true;
                        });

                return false;
            };

            $scope.externalAuthenticate = function (provider) {
                $scope.loginModel.externalError = "";
                $scope.loginModel.isLoading = true;
                $auth.authenticate(provider.toLowerCase()).then(function (r) {
                    $scope.loginModel.isLoading = false;
                    if (r && r.access_token) {
                        $scope.loginModel.isLoading = true;
                        ExternalAuthProvider.getProfile(r.access_token)
                            .then(function (response) {
                                $scope.loginModel.isLoading = false;
                                $scope.loginModel.externalError = "";
                                $scope.externalUser = response.data;
                                $scope.submitExternalLogin(provider, r.access_token);
                            })
                            .catch(function (response) {
                                $scope.loginModel.isLoading = false;
                                $scope.loginModel.externalError = utilsFactory.getLabel("general.loginModal.externalLogin.error");
                                console.log(response.data.message, response.status);
                            });
                    }
                })
                    .catch(function (error) {
                        $scope.loginModel.isLoading = false;
                        $scope.loginModel.externalError = utilsFactory.getLabel("general.loginModal.externalLogin.error");
                        if (error.error) {

                            // Popup error - invalid redirect_uri, pressed cancel button, etc.
                            console.log(error.error);
                        } else if (error.data) {
                            // HTTP response error from server
                            console.log(error.data.message, error.status);
                        } else {
                            console.log(error);
                        }
                    });
                return false;
            };

            $scope.init = function () {
                shoppingCartService.getStorageCart(function (shoppingCart) {

                    if (shoppingCart && shoppingCart.Items && shoppingCart.Items.length > 0) {
                        $scope.cart = shoppingCart;
                    }
                    //var customer = jwtService.getCustomer();

                    //if (customer && $scope.loginType === "checkout" && ($scope.cart && ($scope.cart.Items || "").length)) {
                    //    window.location = "/checkout";
                    //    return;
                    //}
                    setTimeout(function () { jQuery("body").click(); });
                    $scope.isLoading = false;
                });
            };

            $scope.continueWithoutLogin = function () {
                window.location = "/checkout";
            }

            $scope.init();

        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("enhanceBookingCtrl", [
        "userService", "$state", "utilsFactory", "$element", "$scope", "shoppingCartService", "productsFactory", "jwtService", "validHelper", "customerService", "$window", "cresecureService", "paymentService", "borgunPaymentService", "$timeout", "packagesService", "$uibModal", "$http", "currenciesService",
        function (userService, $state, utilsFactory, $element, $scope, shoppingCartService, productsFactory, jwtService, validHelper, customerService, $window, cresecureService, paymentService, borgunPaymentService, $timeout, packagesService, $uibModal, $http, currenciesService) {
            var webUrl = ($("body").data("weburl") ? $("body").data("weburl") : "");
            $scope.labelUtils = utilsFactory;
            $scope.utils = shoppingCartService.utils;
            $scope.dateFormat = shoppingCartService.getDateFormat();
            $scope.validHelper = validHelper;

            $scope.addCartSubmitted = false;
            $scope.hiddenOptionalExtras = Object.create(null);
            $scope.isLoading = true;
            $scope.addonLoading = false;
            $scope.getPackageDurationLabel = packagesService.getPackageDurationLabel;
            $scope.cart = shoppingCartService.getEmptyCart();

            var timeoutID = undefined;

            function resizeSliderPanel(container, refreshAllInputs) {

                window.clearTimeout(timeoutID);

                timeoutID = setTimeout(function () {


                    _.each(jQuery("input"), function (input) {
                        if (jQuery(input).val()) { // trigger "change" event twice for fixing focus issue
                            jQuery(input).change();
                        }
                    });

                    jQuery(window).resize();
                }, 100);
                if (!$scope.hasUpdatePanelEvent && jQuery(".update-collapse-panel").length) {
                    $scope.hasUpdatePanelEvent = true;
                    jQuery(".update-collapse-panel").on("shown.bs.collapse", function () {
                        resizeSliderPanel();
                    });
                    jQuery(".update-collapse-panel").on("hidden.bs.collapse", function () {
                        resizeSliderPanel();
                    });
                }
            }

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            if (jQuery(".update-collapse-panel").length) {
                $scope.hasUpdatePanelEvent = true;
                jQuery(".update-collapse-panel").on("shown.bs.collapse", function () {
                    resizeSliderPanel();
                });
                jQuery(".update-collapse-panel").on("hidden.bs.collapse", function () {
                    resizeSliderPanel();
                });
            }

            $scope.isSkylagoon = function () {
                return ($scope.selectedGeographyCode || "").toLowerCase().indexOf("skl") >= 0;
            };


            $scope.getCurrency = function () {
                //jwtService.getPrincipalTokenCurrency();
                if ($scope.currency) return $scope.currency;

                if ($scope.cart && $scope.cart.Quote) {
                    $scope.currency = $scope.cart.Quote.Currency;
                }
                return $scope.currency || "USD";
            };

            $scope.getItemPrice = function (opItem, dontUseProductPrice) {
                if (!opItem) return 0;

                // TODO: check for FOI
                if (($scope.selectedGeographyCode || "").toLowerCase().indexOf("foi") >= 0 && opItem.unit && opItem.unit.ageBasedPriceBreakdown && opItem.unit.ageBasedPriceBreakdown.adultPrice > 0) {
                    return opItem.unit.ageBasedPriceBreakdown.adultPrice;
                }

                return (opItem.unit && opItem.unit.price > 0) ? opItem.unit.price : ((!dontUseProductPrice && opItem.product.price > 0) ? opItem.product.price : 0);
            };

            $scope.getItemTotalPrice = function (opItem, adults, children) {

                if (!opItem) return 0;

                var pricedPerPerson = 0;

                // TODO: check for FOI
                if (opItem.unit && opItem.unit.ageBasedPriceBreakdown && (opItem.unit.ageBasedPriceBreakdown.adultPrice > 0)) {
                    return opItem.unit.ageBasedPriceBreakdown.adultPrice * adults + opItem.unit.ageBasedPriceBreakdown.childPrice * children;
                }

                return 0;

                //pricedPerPerson = (opItem.unit && opItem.unit.price > 0) ? opItem.unit.price : (opItem.product.price > 0 ? opItem.product.price : 0);

                // return pricedPerPerson * adults + pricedPerPerson * children;
            };

            $scope.setAndFlterOptionalExtrasByPrice = function () {
                if (!($scope.cart.optionalExtras || '').length) return;

                _.each($scope.cart.optionalExtras, function (opItem) {
                    if (opItem.product) {
                        opItem._totalPrice = $scope.selectedOption && $scope.getItemTotalPrice(opItem, $scope.selectedOption.numberOfAdults, $scope.selectedOption.numberOfChildren) || 0;
                        opItem._pricePerUnit = $scope.getItemPrice(opItem, true);
                        opItem._sortPrice = opItem._totalPrice || opItem._pricePerUnit || 999999999998;
                    } if (opItem.package) {
                        opItem._totalPrice = opItem.package.price;
                        opItem._sortPrice = opItem.package.price || 999999999999;
                    }
                });

                $scope.cart.optionalExtras = _.sortBy($scope.cart.optionalExtras, function (opItem) { return opItem._sortPrice; });
            };

            $scope.continueShopping = function () {
                window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
            };

            $scope.shouldShowComponent = function (comp) {
                return comp && !comp.isHidden && comp.ProductType != 'PKG-HDR';
            };

            $scope.handleBack = function () {
                var productCategory = jwtService.getProductCategory();
                var redirect = true;

                jwtService.setCheckoutModel($scope.model);
                window.location = utilsFactory.addPersistentQueryStringsParams("/");
                return;
                switch (productCategory) {
                    case "Activities":
                        redirect = false;
                        window.history.go(-1);
                        break;

                }
                if (redirect) {
                    window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
                }
            };

            $scope.getAddonImage = function (opItem, useProductDataOverUnit) {
                var imgSrc = $scope.getAddonImageSrc(opItem, useProductDataOverUnit);

                if ((imgSrc || "").length) {
                    return { 'background-image': 'url(' + imgSrc + ')' };
                }

                return {};
            };

            $scope.getAddonImageSrc = function (opItem, useProductDataOverUnit) {
                if (!opItem || (!opItem.product && !opItem.package)) return;

                var productDescriptions = null;
                if (useProductDataOverUnit) {
                    productDescriptions = opItem.product ? ((opItem.product.productDescriptions) || (opItem.unit && opItem.unit.productDescriptions))
                        : opItem.package.packageDescriptions;
                } else {
                    productDescriptions = opItem.product ? ((opItem.unit && opItem.unit.productDescriptions) || (opItem.product.productDescriptions))
                        : opItem.package.packageDescriptions;
                }


                if (!productDescriptions) {
                    return "";
                }

                if ((productDescriptions.mainImageUrls || "").length) {
                    return productDescriptions.mainImageUrls[0];
                }

                if ((productDescriptions.extraImageUrls || "").length) {
                    return productDescriptions.extraImageUrls[0];
                }

                return "";
            };

            $scope.getAddonsCount = function () {
                var count = 0;
                if (!$scope.cart || !$scope.cart.optionalExtras.length) return;

                for (var i = 0; i < $scope.cart.optionalExtras.length; i++) {
                    var item = $scope.cart.optionalExtras[i];
                    if ($scope.checkOptionalProductVisbility(item) && (item.package || (item.product && (item.product.units || '').length))) {
                        count++;
                    }
                }
                return count;
            };

            $scope.getAddonTitle = function (opItem, useProductDataOverUnit) {
                if (!opItem || (!opItem.product && !opItem.package)) return;
                if (opItem.product) {

                    if (opItem.product.productDescriptions && opItem.product.productDescriptions.webTrayTitle) {
                        return opItem.product.productDescriptions.webTrayTitle;
                    }

                    var productDescriptions = null;
                    if (useProductDataOverUnit) {
                        productDescriptions = (opItem.product.productDescriptions) || (opItem.unit && opItem.unit.productDescriptions);
                    } else {
                        productDescriptions = (opItem.unit && opItem.unit.productDescriptions) || (opItem.product.productDescriptions);
                    }


                    if (!productDescriptions) {
                        return opItem.product.name;
                    }

                    var title = (productDescriptions
                        && (productDescriptions.titles || "").length > 0) ?
                        productDescriptions.titles[0] : opItem.productDescription;

                    return title;
                } if (opItem.package) {
                    var productDescriptions = opItem.package.packageDescriptions;
                    if (!productDescriptions) {
                        return opItem.package.description;
                    }

                    if (productDescriptions.webTrayTitle) {
                        return productDescriptions.webTrayTitle;
                    }

                    var title = (productDescriptions.titles || "").length > 0 ?
                        productDescriptions.titles[0] : opItem.package.description;
                    return title;
                }
            };

            $scope.getSelectedDateLabel = function () {
                if (!$scope.selectedOption) return;
                var selectedAdultsLabel = $scope.selectedOption.numberOfAdults == 1 ? $scope.labelUtils.getLabel("spa.cart.optionalExtras.selected1Adult") : $scope.labelUtils.getLabel("spa.cart.optionalExtras.selectedAdults");
                selectedAdultsLabel = selectedAdultsLabel.replace("{adults}", $scope.selectedOption.numberOfAdults);

                var selectedChildrenLabel = $scope.selectedOption.numberOfChildren == 1 ? $scope.labelUtils.getLabel("spa.cart.optionalExtras.selected1Child") : $scope.labelUtils.getLabel("spa.cart.optionalExtras.selectedChildren");
                if ($scope.selectedOption.numberOfChildren == 0) {
                    selectedChildrenLabel = "";
                } else {
                    selectedChildrenLabel = selectedChildrenLabel.replace("{children}", $scope.selectedOption.numberOfChildren);
                }

                var selectedDateLabel = $scope.labelUtils.getLabel("spa.cart.optionalExtras.selectedOnDate");
                selectedDateLabel = selectedDateLabel.replace("{date}", $scope.selectedOption.formattedDate);

                return selectedAdultsLabel + (selectedChildrenLabel ? " " + selectedChildrenLabel : "") + " " + selectedDateLabel;
            };

            function fillProductDetails(source, index, callback) {
                var item = source[index];
                if (!item) {
                    callback();
                }
                var getProductPromise = null;
                if (item.productCategory == null || item.productCategory == "Package") {
                    //getProductPromise = Promise.resolve({ data: { products: null } });
                    var params = {
                        urlPrefix: webUrl,
                        token: jwtService.getPrincipalToken(),
                        productCode: item.productCode,
                        travelDate: item.date,
                        adults: 1,
                        children: 0,
                        nights: 0
                    };

                    getProductPromise = packagesService.getPackageDetailsPromise(params);;
                }
                else if (item.productCategory == "Hotel") {
                    // productCode, travelDate, nights, adults, children
                    getProductPromise = productsFactory.getHotelProduct(jwtService.getPrincipalToken(), item.productCode, item.date, 1);
                } else {
                    var loadPrices = ($scope.selectedGeographyCode || "").toLowerCase().indexOf("foi") >= 0;
                    getProductPromise = productsFactory.getProduct(jwtService.getPrincipalToken(), item.productCode, item.productCategory, item.date, loadPrices);
                }

                getProductPromise.then(
                    function (result) {
                        item.product = undefined;

                        if ((!result.data.products || result.data.products.length === 0) && (!result.data.packages || result.data.packages.length === 0)) {
                            if (source.length > index + 1) {
                                fillProductDetails(source, index + 1, callback);
                            } else {
                                callback();
                            }
                            return;
                        }

                        if (result.data.products) {
                            item.product = result.data.products[0];

                            var selectedUnitCode = (Array.isArray(item.unitCode) && item.unitCode[0]) || !Array.isArray(item.unitCode) && item.unitCode;
                            item.selectedUnitCode = selectedUnitCode;

                            if (selectedUnitCode && (item.product.units || "").length) {
                                item.unit = _.find(item.product.units, function (un) { return un.unitCode == selectedUnitCode; })
                            }
                            //else if ((item.product.units || "").length) {
                            //    item.unit = item.product.units[0];
                            //}
                        } else if (result.data.packages) {
                            item.package = result.data.packages[0];
                        }

                        if (source.length > index + 1) {
                            fillProductDetails(source, index + 1, callback);
                        }
                        else {
                            callback();
                        }
                    }, function () {
                        if (source.length > index + 1) {
                            fillProductDetails(source, index + 1, callback);
                        }
                        else {
                            callback();
                        }
                    });
            }

            $scope.showOptionalExtras = function () {
                if (!$scope.cart || !($scope.cart.optionalExtras || "").length) {

                    return false;
                }
                var r = _.find($scope.cart.optionalExtras,
                    function (opItem) {
                        return !opItem.hidden &&
                            (opItem.product && (opItem.product.units || "").length || opItem.productCategory == "Package");
                    });
                return r != undefined;
            };

            $scope.checkOptionalProductVisbility = function (val) { return !val.hidden; };

            $scope.hideOptionalProduct = function (oc) {
                oc.hidden = true;
                $scope.hiddenOptionalExtras[oc.productCode + oc.unitCode] = true;
                shoppingCartService.setStorageCart($scope.cart, function () { });
            };

            $scope.reloadCartOptions = function () {
                // reload cart options
                if ($scope.cart.Quote) {
                    $scope.showCanPayAtHotel = $scope.cart.Quote.CanPayAtHotel;
                    $scope.depositAmountDue = parseFloat($scope.cart.Quote.DepositAmountDue);
                    $scope.dueOnArrival = parseFloat($scope.cart.Quote.DueOnArrival);

                    $scope.canChangeConfirmationEmailAddress = $scope.cart.Quote.CanChangeConfirmationEmailAddress;
                    $scope.showCanPayWithAR = $scope.isAgent && $scope.cart.Quote.CanPayWithAccountsReceivable;
                    $scope.model.payWithAR = $scope.showCanPayWithAR;//checked by default
                }

                $scope.skipCC = $scope.cart.Quote && parseInt($scope.cart.Quote.Price) <= 0 && !$scope.showCanPayAtHotel; //(shoppingCart.DiscountCodes || "").length &&


                $scope.showUnaccompaniedChildMessage = canShowUnaccompaniedChildMessage();
                //

                $scope.passengerList = [];

                var custIndex = 1;// main traveler will be passenger#1
                _.each($scope.cart.Items, function (sitem, index) {
                    if (sitem.BookingToQuote) {
                        if (sitem.BookingToQuote.Components) {
                            _.each(sitem.BookingToQuote.Components, function (scomp, index) {
                                if (scomp.NeedFullPassengerList) {
                                    $scope.passengerList.push({
                                        item: sitem,
                                        component: scomp,
                                        adults: [],
                                        children: [],
                                        infants: []
                                    });
                                    for (var i = 0; i < scomp.NumberOfAdults; i++) { // main traveler will be passenger#1
                                        $scope.passengerList[$scope.passengerList.length - 1].adults.push({
                                            id: "IBE" + (i === 0 ? 1 : (custIndex)),
                                            firstName: "",
                                            lastName: ""
                                        });
                                        custIndex++;
                                    }

                                    for (var j = 0; j < scomp.NumberOfChildren; j++) {
                                        $scope.passengerList[$scope.passengerList.length - 1].children.push({
                                            id: "IBE" + (custIndex++),
                                            firstName: "",
                                            lastName: ""
                                        });
                                    }

                                    for (var k = 0; k < scomp.NumberOfInfants; k++) {
                                        $scope.passengerList[$scope.passengerList.length - 1].infants.push({
                                            id: "IBE" + (custIndex++),
                                            firstName: "",
                                            lastName: ""
                                        });
                                    }

                                }
                            }); //end each
                        }

                        if (sitem.BookingToQuote.Packages) {
                            _.each(sitem.BookingToQuote.Packages, function (pck, index) {
                                var pckComp = _.find(pck.Components, function (pckComp) {
                                    return pckComp.ProductCode == pck.pckNeedPassListCompProductCode;
                                });
                                if (pck.NeedFullPassengerList && pckComp) {
                                    $scope.passengerList.push({
                                        item: sitem,
                                        pck: pck,
                                        pckComp: pckComp,
                                        adults: [],
                                        children: [],
                                        infants: []
                                    });
                                    for (var i = 0; i < pck.NumberOfAdults; i++) { // main traveler will be passenger#1
                                        if ((i == 0 && $scope.passengerList[$scope.passengerList.length - 1].adults.length == 0) || i > 0) {
                                            $scope.passengerList[$scope.passengerList.length - 1].adults.push({
                                                id: "IBE" + (i === 0 ? 1 : (custIndex)),
                                                firstName: "",
                                                lastName: ""
                                            });
                                            custIndex++;
                                        }
                                    }

                                    for (var j = 0; j < pck.NumberOfChildren; j++) {
                                        $scope.passengerList[$scope.passengerList.length - 1].children.push({
                                            id: "IBE" + (custIndex++),
                                            firstName: "",
                                            lastName: ""
                                        });
                                    }

                                    for (var k = 0; k < pck.NumberOfInfants; k++) {
                                        $scope.passengerList[$scope.passengerList.length - 1].infants.push({
                                            id: "IBE" + (custIndex++),
                                            firstName: "",
                                            lastName: ""
                                        });
                                    }

                                }
                            }); //end each
                        }//

                    }
                });

                shoppingCartService.getHotelsComponents($scope.cart, function (spComps) {
                    if (spComps && spComps.length > 0) {
                        $scope.hasCartHotels = true;
                        var tempComps = [];
                        _.map(spComps, function (spCmp) {
                            tempComps.push(
                                {
                                    name: spCmp.isPackageComponent ? spCmp.ProductName : spCmp.BookingToQuote.Components[0].Name,
                                    contactName: "",
                                    phoneNumber: "",
                                    specialRequest: "",
                                    roomRequest: "",
                                    origComp: spCmp
                                });
                        });

                        $scope.specReqComps = tempComps;
                        // resizeSliderPanel();
                    } else {
                        $scope.specReqComps = [{
                            name: undefined,
                            isGeneric: true,
                            contactName: "",
                            phoneNumber: "",
                            specialRequest: "",
                            roomRequest: "",
                            origComp: undefined
                        }];
                        // resizeSliderPanel();
                    }
                });
                // end reload cart
            };


            $scope.addOptionalProduct = function (oc) {
                // new logic
                var date = moment(oc.startDate).format("YYYY-MM-DD");
                var region = jwtService.getGeography();
                var productCode = oc.productCode;
                var productCategory = oc.productCategory;
                var relatedProductCode = oc.relatedProductCode;
                var unitCode = oc.unitCode || "";
                var regionParam = (region && ("/" + region) || "");
                if (Array.isArray(unitCode)) {
                    if (unitCode.length && unitCode[0]) {
                        unitCode = unitCode.join("|");
                    } else {
                        unitCode = "";
                    }
                }

                // find the related cart item
                var relatedProductCode = oc.relatedProductCode;
                var relatedComponent = null;
                var cartItem = _.find($scope.cart.Items, function (cartItem) {
                    relatedComponent = _.find(cartItem.BookingToQuote && cartItem.BookingToQuote.Components, function (comp) {
                        return comp.ProductCode == relatedProductCode;
                    });
                    return relatedComponent != null;
                    //return cartItem && cartItem.ProductCode && cartItem.ProductCode.toLowerCase() === relatedProductCode.toLowerCase();
                });
                var adults = 0, children = 0;
                if (cartItem && relatedComponent) {
                    adults = relatedComponent.NumberOfAdults || 0;
                    children = relatedComponent.NumberOfChildren || 0;
                }
                var simpleEnhancement = (oc.product && oc.product.simpleIBEEnhancement);

                var url = undefined;

                var isUpgradeParams = "";
                var paramSeparator = "";
                if (oc.isUpgrade) {
                    isUpgradeParams = "updateCartItem=" + (relatedComponent && relatedComponent.ProductCode) + "&isUpgrade=1";
                    paramSeparator = "&";
                }

                var isAutoSelectUnitParams = "";
                if (oc.autoSelectUnit) {
                    isAutoSelectUnitParams = paramSeparator + "autoSelectUnit=1";
                    paramSeparator = "&";
                }

                var queryStringParams = "?" + isUpgradeParams + isAutoSelectUnitParams + paramSeparator + "fromwebtray=1";

                switch (productCategory) {
                    case "Package":
                        var url = regionParam + "/activities/details/" + productCode + "/Package" + queryStringParams + "#/package-details/" + (date || 'date') + "/" + productCode;
                        break;
                    case "Attraction":
                        if (simpleEnhancement) {
                            var addOnToCartModalInstance = $uibModal.open({
                                animation: true,
                                templateUrl: "addAddOnToCartModal.html",
                                controller: "addAddOnToCartModalCtrl",
                                size: "md",
                                resolve: {
                                    "product": oc, "cart": $scope.cart, "anonymUser": $scope.anonymUser
                                },
                                backdrop: false
                            });

                            addOnToCartModalInstance.result.then(function (result, args) {
                                if (result && result.cart) {
                                    $scope.cart = result.cart;
                                    //initDisclaimersFromCart();
                                    $scope.hideOptionalProduct(oc);
                                    $scope.reloadCartOptions();
                                }
                            }, function (error, args) {

                                //console.log("dismiss");
                            });
                        }
                        else {

                            var url = regionParam + "/activities/details/" + productCode + "/" + productCategory + "/" + date; //
                            if (unitCode) {
                                url = url + "/" + unitCode;
                            }

                            if (adults || children) {
                                var adults = adults;
                                var children = children;
                                url = url + "/" + adults + "/" + children;
                            }
                            url = url + queryStringParams;
                            url = url + "#/select-ticket/book-adventure";

                            window.location = utilsFactory.addPersistentQueryStringsParams(url);
                        }
                        return;
                        break;
                    case "Hotel":
                        url = regionParam + "/hotels/details/" + productCode + "/" + productCategory + "/" + date + queryStringParams + "#/select-booking-type/book-stay";
                        break;
                    case "Tour":
                        var productType = oc.product && oc.product.productType || productCode;
                        url = regionParam + "/activities/details/" + productType + "/" + productCategory + "/" + date; //
                        if (unitCode) {
                            url = url + "/" + unitCode;
                        }
                        url = url + "/" + adults + "/" + children;
                        url = url + queryStringParams;
                        url = url + "#/select-ticket/book-adventure";
                        break;
                    case "Transportation":
                        var productType = oc.product && oc.product.productType || productCode;
                        url = regionParam + "/transportation/details/" + productType + "/" + productCategory + "/" + date + queryStringParams + "#/select-transportation-ticket/book-transportation-adventure";
                        break;
                }

                if (url) {
                    window.location = utilsFactory.addPersistentQueryStringsParams(url);
                }

                return;
            };

            $scope.goToCheckout = function () {
                if ((document.referrer || "").toLowerCase().indexOf((window.location.hostname || "").toLowerCase()) >= 0 && document.referrer.toLowerCase().indexOf("checkout") > 0) {
                    window.history.go(-1);
                    return;
                } else {
                    var generalCtrl = $scope.$parent;
                    window.location = utilsFactory.addPersistentQueryStringsParams((generalCtrl.selectedGeographyCode ? "/" + generalCtrl.selectedGeographyCode : "") + "/checkout");
                }
            };

            $scope.getOptionalExtras = function (callback) {
                if ($scope.addonLoading || !$scope.cart || $scope.cart.isUpdate || !($scope.cart.Items || "").length) { // || $scope.isLoading
                    $scope.goToCheckout();
                    return;
                }
                var productQueries = [];
                var mapUniqueProducts = Object.create(null);
                _.each($scope.cart.Items, function (item) {
                    if (!item) return;

                    if (item.BookingToQuote && (item.BookingToQuote.Packages || "").length) {
                        var pkg = item.BookingToQuote.Packages[0];
                        var pkgStartDate = moment(pkg.StartDate).format("YYYY-MM-DD");
                        var itPkgKey = pkg.PackageCode + pkgStartDate;
                        if (!(itPkgKey in mapUniqueProducts)) {
                            productQueries.push({
                                ProductCode: pkg.PackageCode,
                                TravelDate: pkgStartDate,
                                UnitCode: null
                            });
                            mapUniqueProducts[itPkgKey] = 1;

                            item.StartDate = pkgStartDate;
                            item.ProductCode = pkg.PackageCode;
                        }
                    } else if (item.ProductCode) {
                        var itKey = item.ProductCode
                            + moment(item.StartDate, shoppingCartService.getDateFormat()).format("YYYY-MM-DD")
                            + (item.UnitCode ? item.UnitCode : "");
                        if (!(itKey in mapUniqueProducts)) {
                            productQueries.push({
                                ProductCode: item.ProductCode,
                                TravelDate: moment(item.StartDate, shoppingCartService.getDateFormat()).format("YYYY-MM-DD"),
                                UnitCode: item.UnitCode ? item.UnitCode : null
                            });
                            mapUniqueProducts[itKey] = 1;
                        }
                    }
                });


                if (!productQueries.length) {
                    $scope.goToCheckout();
                    return;
                }



                var dataToPost = { ProductQueries: productQueries };
                var requestParams = {
                    token: jwtService.getPrincipalToken(),
                    data: dataToPost
                };
                $scope.addonLoading = true;
                $scope.cart.optionalExtras = [];

                productsFactory.getEnhanceYourExperience(requestParams, function (relatedProducts) {

                    if (relatedProducts && relatedProducts.data && relatedProducts.data.length) {
                        var result = [];
                        _.each(relatedProducts.data, function (item) {
                            if ((item.ibeCartEnhancements || "").length) {
                                var parentCartItem = _.find($scope.cart.Items, function (cartItem) {
                                    return cartItem && cartItem.ProductCode && cartItem.ProductCode.toLowerCase() === item.relatedProductCode.toLowerCase();
                                });
                                if (!parentCartItem) return;

                                var date = (parentCartItem.StartDate) ? moment(parentCartItem.StartDate).format("YYYY-MM-DD") : undefined;
                                _.each(item.ibeCartEnhancements, function (optionItem) {
                                    optionItem.relatedProductCode = item.relatedProductCode;
                                    optionItem.date = date;
                                    result.push(optionItem);
                                });
                            }
                        });
                        if (result.length) {
                            fillProductDetails(result, 0, function () {
                                $scope.cart.optionalExtras = result;
                                $scope.hideOptionalExtras(); // hide optional products if they were added from the listing page
                                // hide optional extras if they are added directed on the checkout page - old
                                _.each($scope.cart.optionalExtras, function (oc) {
                                    if ($scope.hiddenOptionalExtras[oc.productCode + oc.unitCode]) {
                                        oc.hidden = true;
                                    }
                                });

                                $scope.cart.optionalExtras = $scope.cart.optionalExtras.filter(function (item) {
                                    if (item.hidden) return false;
                                    return item.package || (item.product && (item.selectedUnitCode && item.unit || !item.selectedUnitCode));

                                    //if ($scope.isSkylagoon()) {
                                    //    return item.package || (item.product && item.unit); // && item.product.unit
                                    //} else {
                                    //    return item.package || (item.product && item.product.units || '').length;
                                    //}
                                });

                                shoppingCartService.setStorageCart($scope.cart, function () { });

                                if (!$scope.cart.optionalExtras.length) {
                                    $scope.goToCheckout();
                                    return;
                                }

                                $scope.addonLoading = false;
                                callback && callback();
                            });
                        } else {
                            $scope.goToCheckout();
                            // $scope.addonLoading = false;
                            return;
                        }
                    } else {
                        $scope.goToCheckout();
                        // $scope.addonLoading = false;
                        return;
                    }
                });
            };

            // hide the optional extras
            $scope.hideOptionalExtras = function () {
                var citems = Object.create(null);
                _.each($scope.cart.Items, function (cartItem) {
                    citems[cartItem.ProductCode + cartItem.UnitCode] = true;
                });

                _.each($scope.cart.optionalExtras, function (opExtra) {
                    if (citems[opExtra.productCode + opExtra.unitCode]) {
                        opExtra.hidden = true;
                    }
                });
            };


            $scope.init = function () {
                var customer = jwtService.getCustomer();
                var isEnhanceBookingPageEnabled = ($scope.selectedLanguage && $scope.selectedLanguage.enableEnhanceBookingPage) || ($scope.anonymUser && $scope.anonymUser.enableEnhanceBookingPage);
                if (!isEnhanceBookingPageEnabled || shoppingCartService.utils.getEnhancePageVisited()) {
                    var redirectToUrl = shoppingCartService.utils.getAfterAddToCartPageUrl($scope.$parent.selectedGeographyCode, false);
                    window.location = utilsFactory.addPersistentQueryStringsParams(redirectToUrl);
                    return;
                }
                shoppingCartService.utils.setEnhancePageVisited();

                shoppingCartService.getStorageCart(function (shoppingCart) {
                    $scope.isFOC = $scope.$parent.selectedGeographyCode == "FOC";

                    if (shoppingCart && shoppingCart.Items && shoppingCart.Items.length > 0) {
                        $scope.cart = shoppingCart;
                        //initDisclaimersFromCart();

                        $scope.selectedOption = $scope.cart.lastAddedItemDetails && JSON.parse(JSON.stringify($scope.cart.lastAddedItemDetails));

                        if ($scope.selectedOption && $scope.selectedOption.selectedUnit) {
                            $scope.selectedOption.product = $scope.selectedOption; // to be compatibile with existing helpers
                            $scope.selectedOption.unit = $scope.selectedOption.selectedUnit;

                            $scope.selectedOption.adultPrice = $scope.selectedOption.selectedUnit.ageBasedPriceBreakdown && $scope.selectedOption.selectedUnit.ageBasedPriceBreakdown.adultPrice;
                            $scope.selectedOption.childPrice = $scope.selectedOption.selectedUnit.ageBasedPriceBreakdown && $scope.selectedOption.selectedUnit.ageBasedPriceBreakdown.childPrice;
                            $scope.selectedOption.currency = $scope.selectedOption.selectedUnit.currency;
                            //

                            var found = false;
                            _.each($scope.cart.Items, function (item) {
                                _.each(item.BookingToQuote.Components, function (comp) {
                                    if (comp.ProductCode == $scope.selectedOption.code) {
                                        $scope.selectedOption.numberOfAdults = comp.NumberOfAdults;
                                        $scope.selectedOption.numberOfChildren = comp.NumberOfChildren;


                                        $scope.selectedOption.totalPrice = ($scope.anonymUser && $scope.anonymUser.isTaxInclusive ? (item.totalCalcPriceWithTax || item.totalCalcPrice) : item.totalCalcPrice);
                                        $scope.selectedOption.formattedDate = moment(comp.StartDate).format("MMMM DD, YYYY");

                                        found = true;
                                        return;
                                    }
                                });
                                if (found) return;
                            });
                        } else if ($scope.selectedOption && $scope.selectedOption.productCategory == "Package") {
                            $scope.selectedOption.package = $scope.selectedOption;

                            var found = false;
                            _.each($scope.cart.Items, function (item) {
                                _.each(item.BookingToQuote.Packages, function (pkg) {
                                    if (pkg.PackageCode == $scope.selectedOption.packageCode) {
                                        $scope.selectedOption.numberOfAdults = pkg.NumberOfAdults;
                                        $scope.selectedOption.numberOfChildren = pkg.NumberOfChildren;


                                        $scope.selectedOption.totalPrice = ($scope.anonymUser && $scope.anonymUser.isTaxInclusive ? (item.totalCalcPriceWithTax || item.totalCalcPrice) : item.totalCalcPrice);
                                        $scope.selectedOption.formattedDate = moment(pkg.StartDate).format("MMMM DD, YYYY");

                                        found = true;
                                        return;
                                    }
                                });
                                if (found) return;
                            });
                        }
                        //$scope.selectedO
                        //


                        if (!($scope.cart.optionalExtras || "").length) {
                            $scope.getOptionalExtras($scope.setAndFlterOptionalExtrasByPrice);
                        } else {
                            $scope.setAndFlterOptionalExtrasByPrice();
                        }

                        // only apply if there's a product in the cart and the productCode is found
                        var firstCartItem = $scope.cart && (($scope.cart.Items || "").length == 1 ? $scope.cart.Items[0] : null);
                        var firstComp = firstCartItem && firstCartItem.BookingToQuote
                            && firstCartItem.BookingToQuote.Components && firstCartItem.BookingToQuote.Components[0];

                        firstComp && $scope.checkExitIntentPopup($scope.anonymUser, firstComp.ProductCode);

                    } else {
                        window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
                        return;
                    }
                    $scope.isLoading = false;
                });

            };

            $scope.initCurrentAnonymUser = function (callback) {

                jwtService.getAnonymousUserByGeography($scope.$parent.selectedGeographyCode, function (user) {

                    $scope.anonymUser = user;
                    if ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) {
                        moment.locale($scope.selectedLanguage.languageCode);
                    }

                    callback();
                });
            };

            $scope.prepareData = function () {
                $scope.initCurrentAnonymUser($scope.init);
            };

            var isGeneralCtrlReady = $scope.$parent.generalCtrlReady;
            if (isGeneralCtrlReady) {
                $scope.prepareData();
            } else {
                $scope.$on("generalCtrlReady", function (event, args) {
                    $scope.prepareData();
                });
            }
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("geographiesCtrl", [
        "utilsFactory", "jwtService", "$scope", "$rootScope", "validHelper", "customerService", "$element", "$window", "$http", "activitiesService", "hotelsService", "transportationService",
        function (utilsFactory, jwtService, $scope, $rootScope, validHelper, customerService, $element, $window, $http, activitiesService, hotelsService, transportationService) {
            $scope.utils = utilsFactory;
            var webUrl = ($("body").data("weburl") ? $("body").data("weburl") : "");
            $.material.init();

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            $scope.init = function () {
                $scope.isLoading = true;
                $scope.getGeographiesAsync(function () {
                    $scope.isLoading = false;
                });
            };

            var t = jwtService.getPrincipalToken();

            if (t && t.length > 0) {
                $scope.init();
            } else {
                $scope.isLoading = true;
                $scope.$on("getPrincipalToken", function (event, args) {
                    $scope.isLoading = false;
                    $scope.init();
                });
            };

        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("loginCtrl", [
        "utilsFactory", "jwtService", "$scope", "$rootScope", "validHelper", "customerService", "shoppingCartService","$element", "$window", "$http",
        function (utilsFactory, jwtService, $scope, $rootScope, validHelper, customerService,shoppingCartService, $element, $window, $http) {
            // Controller not used!
            $scope.utils = utilsFactory;
            var webUrl = ($("body").data("weburl") ? $("body").data("weburl") : "");
            $.material.init();

            $scope.loginType = $($element).attr("data-login-type");

            $scope.loginModel = {
                username: "",
                password: "",
                isLoading: false
            };
            $scope.forgotModel = {
                username: ""
            };
            $scope.showLoginFormId = 1;

            function checkIfLogedIn() {
                return false;
                //var token = jwtService.getCustomerToken();
                //if (!token || token.length === 0) {
                //    $window.location.href = "/";
                //    return false;
                //}
                //return true;
            }

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.loginModel.isLoading = false;
            });

      
            //
            $scope.submitForgotPassword = function (isValid, $forgotModel, $loadingModel) {
               
                if ($loadingModel.isLoading) return false;
                // check to make sure the form is completely valid
                $forgotModel.submitted = true;
                if (isValid) {
                    $loadingModel.isLoading = true;
                    $forgotModel.error = null;
                    $forgotModel.response = null;
                    $http({
                        method: "POST",
                        url: $scope.getWebUrl() + "/api/authentication/forgotpassword",
                        headers: {
                            "Authorization": jwtService.getToken(),
                            'Content-Type': "application/json"
                        },
                        data: {
                            "Username": $forgotModel.username
                        }
                    })
                        .then(
                            function (result) {
                                if (result == null) {
                                    $forgotModel.error = utilsFactory.getLabel("general.loginModal.forgotPwd.error");
                                    $loadingModel.isLoading = false;
                                    return false;
                                }

                                if (result.data && result.data.errors != null && result.data.errors.length > 0) {
                                    $forgotModel.error = result.data.errors[0].errorMessage;
                                } else {
                                    $scope.forgotForm.username.activated = false;
                                    $forgotModel.username = "";
                                    $forgotModel.submitted = false;
                                    $forgotModel.response = utilsFactory.getLabel("general.loginModal.forgotPwd.success");
                                }

                                $loadingModel.isLoading = false;
                                //  init();
                                return true;
                            },
                            function (response) {
                                $loadingModel.isLoading = false;
                                $forgotModel.error = utilsFactory.getLabel("general.loginModal.forgotPwd.error");
                                console.log(response);
                            });
                }


                return false;
            };
            //

            $scope.submitLogin = function (isValid) {
                var generalCtrl = $scope.$parent;
                if ($scope.loginModel.isLoading) return false;

                // check to make sure the form is completely valid
                if (isValid) {
                    $scope.loginModel.isLoading = true;
                    $scope.loginModel.errors = [];
                 
                    var hasTracking = $scope.$parent.trackingInfo &&
                       ($scope.$parent.trackingInfo.CRMVisitId || $scope.$parent.trackingInfo.CRMVisitorId);
                    //var crmVisitParams = "";

                    //if (hasTracking) {
                    //    crmVisitParams = $scope.$parent.trackingInfo.CRMVisitorId + "/" + $scope.$parent.trackingInfo.CRMVisitId;
                    //}
                    //$http({
                    //    method: "POST",
                    //    url: webUrl + "/api/authentication/login/" + $scope.loginModel.username + "/" + $scope.loginModel.password + "/" + crmVisitParams

                    //})
                 
                    var dataToPost = {
                        "Username": $scope.loginModel.username,
                        "Password": $scope.loginModel.password
                    };
                    var oldWebLink = jwtService.getWebLink();
                    dataToPost.WebLink =($scope.$parent.trackingInfo && $scope.$parent.trackingInfo.WebLink)||oldWebLink;
                 

                    if (hasTracking) {
                        dataToPost.CRMVisitId = $scope.$parent.trackingInfo.CRMVisitId;
                        dataToPost.CRMVisitorId = $scope.$parent.trackingInfo.CRMVisitorId;
                    }

                    $http({
                        method: "POST",
                        url: $scope.getWebUrl() + "/api/authentication/customerlogin",
                        headers: {
                            "Authorization": jwtService.getToken(),
                            'Content-Type': "application/json"
                        },
                        data: dataToPost
                    })
                        .then(
                            function (result) {
                                if (result == null || result.data == null) {
                                    $scope.loginModel.errors = [{ errorMessage: utilsFactory.getLabel("general.loginModal.login.error") }];
                                    $scope.loginModel.isLoading = false;
                                    return false;
                                }

                                if (result.data.token != null) {
                                    generalCtrl.refreshCart(result.data.token,function() {
                                        result.data.loginType = $scope.loginType;
                                        jwtService.removeGeography();
                                        var customerToken = result.data;
                                        jwtService.setCustomerToken(result.data);
                                        jwtService.setCustomerLogin($scope.loginModel.username);
                                        // jwtService.setToken(result.data, oldRegion);
                                        generalCtrl.initCustomerRecordWithCallback(true, function(data) {
                                            var customer = generalCtrl.getCustomer();
                                            if (customer) {
                                                customer.isAgent = customer.isAgency;
                                                jwtService.setCustomer(customer);
                                              
                                                if ($scope.loginType === "checkout" && ($scope.cart && ($scope.cart.Items || "").length)) {

                                                    return;
                                                }

                                                if (customer.isAgent) {
                                                    customerToken.loginType = "agent";
                                                    jwtService.setCustomerToken(customerToken);
                                                    location.reload();
                                                    return;
                                                    // window.location = "/"; //TODO: /choose-region
                                                }
                                            }
                                            // window.location = "/";

                                        });
                                    });
                                } else {
                                    if (result.data.errors != null && result.data.errors.length > 0) {
                                        $scope.loginModel.errors = result.data.errors;
                                    } else {
                                        $scope.loginModel.errors = [{ errorMessage: utilsFactory.getLabel("general.loginModal.login.error") }];
                                    }
                                    $scope.loginModel.isLoading = false;
                                }

                                return true;
                            },
                            function (response) {
                                if (response && response.data && response.data.errors && response.data.errors.length > 0) {
                                    $scope.loginModel.errors = response.data.errors;
                                } else {
                                    $scope.loginModel.errors = [{ errorMessage: utilsFactory.getLabel("general.loginModal.login.error") }];
                                }
                                $scope.loginModel.isLoading = false;
                                console.log(response);
                            });
                }

                $scope.loginModel.submitted = true;
                return false;
            };

            $scope.init = function () {
                if (!checkIfLogedIn()) {
                    return;
                }
            };


            $scope.init();

        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("membershipCtrl", [
        "utilsFactory", "$scope", "$state", "shoppingCartService", "jwtService", "$timeout",
        function (utilsFactory, $scope, $state, shoppingCartService, jwtService, $timeout) {

            var webUrl = ($("body").data("weburl") ? $("body").data("weburl") : "");
            $scope.labelUtils = utilsFactory;

            $.material.init();

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            $scope.shouldShowComponent = function (comp) {
                return comp && comp.ProductType != 'PKG-HDR';
            };

            $scope.utils = shoppingCartService.utils;
            $scope.dateFormat = shoppingCartService.getDateFormat();

            $scope.model = {
                barcode: undefined,
                barcodes: []
            };
            $scope.errors = [];

            $scope.onBarcodeChange = function () {
                $scope.showBarcodeError && ($scope.showBarcodeError = false);
                $scope.showAddAnotherBarcode = ($scope.model.barcode || "").toString().trim().length > 0;
            };

            $scope.removeBarcode = function (index) {
                $scope.showBarcodeError = false;
                if (index >= ($scope.model.barcodes || '').length || index < 0) return;

                $scope.model.barcodes = _.reject($scope.model.barcodes, function (item, itemIndex) {
                    return itemIndex === index;
                });
            };

            $scope.enterBarcode = function () {
                $scope.showBarcodeError = false;
                if (($scope.model.barcode || "").toString().trim().length == 0) return;

                $scope.model.barcodes.push(($scope.model.barcode || "").toString().trim());
                $scope.model.barcode = "";
                $scope.onBarcodeChange();

                $timeout(function () {
                    jQuery("#barcode").change();
                });
            };

            $scope.applyBarcode = function () {
                if (!($scope.model.barcodes || '').length && !($scope.model.barcode || '').length) {
                    return;
                }

                $scope.isLoading = true;
                $scope.showBarcodeError = false;
                jwtService.membershipLogin({
                    urlPrefix: webUrl,
                    membershipNumbers: ($scope.model.barcodes || '').length ? $scope.model.barcodes : [$scope.model.barcode],
                    token: jwtService.getPrincipalToken(),
                }, function (result) {
                    $scope.isLoading = false;

                    if ((result && result.success && result.data) && !(result.data.errors || "").length && result.data.anonymousTicketRedirectURL) {                     

                        if (result.data.token) {
                            var tokenObj = {
                                "token": result.data.token,
                                "currency": jwtService.getCurrency(),
                                "maxQuantityOfReservedTimes": result.data.maxQuantityOfReservedTimes,
                                "anonymousTicketRedirectURL": result.data.anonymousTicketRedirectURL,
                                "expire": null
                            };

                            var customertoken = jwtService.getCustomerToken();
                            if (customertoken) {
                                tokenObj.loginType = customertoken.loginType;
                                jwtService.setCustomerToken(tokenObj);
                            } else {
                                jwtService.setToken(tokenObj);
                            }                           
                        }
                        window.location.href = result.data.anonymousTicketRedirectURL;
                    } else {
                        $scope.errors = result.error && result.error.errors;
                        $scope.showBarcodeError = true;
                    }
                    console.log(result);
                });
            };


            $scope.init = function () {

            };


            $scope.preinit = function () {
                jwtService.getAnonymousUserByGeography($scope.$parent.selectedGeographyCode, function (user) {
                    $scope.anonymUser = user;
                    if ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) {
                        moment.locale($scope.selectedLanguage.languageCode);
                    }
                    $scope.init();
                });
            };

            // var t = jwtService.getPrincipalToken();
            var isGeneralCtrlReady = $scope.$parent.generalCtrlReady;
            if (isGeneralCtrlReady) {
                $scope.preinit();
            } else {
                $scope.isLoading = true;
                $scope.$on('generalCtrlReady', function (event, args) {
                    $scope.isLoading = false;
                    $scope.preinit();
                });
            };
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("notFoundCtrl", [
       "utilsFactory", "$scope", function (utilsFactory, $scope) {

           $scope.utils = utilsFactory;
           $scope.init = function () {
               var navbarHeight = $(".navbar").height();

               $(".page-content").height($(window).height() - navbarHeight);
           };

           $scope.init();

           $(window).on("resize", function () {
               $scope.init();
           });
       }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("printOrderCtrl", [
        "utilsFactory", "$scope", "$state", "shoppingCartService", "jwtService", "customerService", "trackingService",
        function (utilsFactory, $scope, $state, shoppingCartService, jwtService, customerService, trackingService) {

            var webUrl = ($("body").data("weburl") ? $("body").data("weburl") : "");
            $scope.labelUtils = utilsFactory;
            $scope.model = {};

            $.material.init();

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            $scope.shouldShowComponent = function (comp) {
                return comp && comp.ProductType != 'PKG-HDR';
            };

            $scope.utils = shoppingCartService.utils;
            $scope.dateFormat = shoppingCartService.getDateFormat();

            $scope.handlePrint = function () {
                if (!$scope.model || !$scope.model.bookingNumber) return;

                var requestParams = {
                    // apiUrl: webUrl + "/api/booking/bookinginvoice",
                    apiUrl: webUrl + "/api/booking/alldocuments",
                    token: jwtService.getPrincipalToken(),
                    bookingNumber: $scope.model.bookingNumber
                };
                $scope.isLoading = true;

                //customerService.getBookingInvoice(requestParams, function (result) {
                //    $scope.isLoading = false;
                //});
                customerService.getAllBookingDocuments(requestParams, function (result) {
                    $scope.isLoading = false;
                });

                //$(".print-order:first").print({
                //    globalStyles: true,
                //    mediaPrint: false,
                //    stylesheet: null,
                //    noPrintSelector: ".no-print",
                //    iframe: true,
                //    append: null,
                //    prepend: null,
                //    manuallyCopyFormValues: true,
                //    deferred: $.Deferred(),
                //    timeout: 250,
                //    title: "Booking #" + $scope.model.bookingNumber,
                //    doctype: '<!doctype html>'
                //});
                // window.print();
            };

            $scope.getCurrency = function () {
                //jwtService.getPrincipalTokenCurrency();
                if ($scope.currency) return $scope.currency;
                if ($scope.model && $scope.model.cart && $scope.model.cart.Quote) {
                    $scope.currency = $scope.model.cart.Quote.Currency;
                }
                return $scope.currency || "USD";
            };


            $scope.model = {
                emailAddress: undefined,
                bookingNumber: undefined,
                cart: undefined
            };

            $scope.getCheckmarkImage = function () {
                if (!$scope.geographyCode) {
                    $scope.geographyCode = jwtService.getGeography();
                }
                if (($scope.geographyCode || "").toLowerCase().indexOf("skl") < 0) {
                    return "/Content/images/layout/checkmark.png";
                } else {
                    return "/Content/images/layout/checkmark-gold.png";
                }
            };

            $scope.handleNext = function () {
                var productCategory = jwtService.getProductCategory();
                var geographyCode = jwtService.getGeography();
                var urlToRedirect = "/";
                if ((geographyCode || "").toLowerCase().indexOf("skl") < 0) {
                    switch (productCategory) {
                        case "Activities":
                            urlToRedirect = geographyCode ? "/" + geographyCode + "/activities" : "/activities";
                            break;
                        case "Hotels":
                            urlToRedirect = geographyCode ? "/" + geographyCode + "/hotels" : "/hotels";
                            break;
                        case "Transportation":
                            urlToRedirect = geographyCode ? "/" + geographyCode + "/transportation" : "/transportation";
                            break;

                    }
                }

                window.location.href = utilsFactory.addPersistentQueryStringsParams(urlToRedirect);
            };

            $scope.getQuoteComponentPrice = function (index) {
                var indexes = shoppingCartService.getQuoteIndexes($scope.model.cart, index);
                var quotes = [];

                for (var j = indexes.startIndex; j <= indexes.endIndex; j++) {
                    var quoteObject = $scope.model.cart.Quote.Components[j];
                    if (quoteObject) {
                        quotes.push(quoteObject);
                    }
                }

                if (quotes.length > 0) {
                    var price = 0;

                    _.map(quotes, function (quote) {
                        price += quote.Price;
                    });

                    return parseFloat(price).toFixed(2);
                }

                return "NaN";
            };

            $scope.showPromoCodes = false;
            $scope.getPromoCodes = function () {
                var currentBooking = shoppingCartService.getBooking(null);
                if (currentBooking && currentBooking.shoppingCart) {
                    var promoCodes = shoppingCartService.utils.getPromoCodes(currentBooking.shoppingCart);
                    if (promoCodes !== "") {
                        $scope.showPromoCodes = true;
                    } else {
                        $scope.showPromoCodes = false;
                    }

                    return promoCodes;
                }
                return null;
            };

            function processPrintOrderCrossSell() {
                // TODO: remove 
                //$scope.crossSell = $scope.anonymUser && $scope.anonymUser.printOrderCrossSell;
                //
                if (!$scope.anonymUser || !$scope.anonymUser.printOrderCrossSell || !$scope.model || !$scope.model.cart || !$scope.model.cart.Items) {
                    return;
                }

                var printOrderCrossSell = $scope.anonymUser.printOrderCrossSell;

                if (!printOrderCrossSell.imageUrl) return;

                var includeOnlyProductUnitCodes = (printOrderCrossSell.showForProductUnitCodes
                    && Array.isArray(printOrderCrossSell.showForProductUnitCodes)
                    && printOrderCrossSell.showForProductUnitCodes) || null;

                var excludeProductUnitCodes = (printOrderCrossSell.hideForProductUnitCodes
                    && Array.isArray(printOrderCrossSell.hideForProductUnitCodes)
                    && printOrderCrossSell.hideForProductUnitCodes) || null;


                var hasItemInIncludedList = false;
                var hasItemInExcludedList = false;
                                 
                _.each($scope.model.cart.Items, function (sitem, index) {
                    sitem.BookingToQuote && sitem.BookingToQuote.Components && _.each(sitem.BookingToQuote.Components, function (comp, index) {
                        var key1 = comp.UnitCode;
                        var key2 = comp.ProductCode + comp.UnitCode;

                        if (!hasItemInIncludedList) {
                            hasItemInIncludedList = includeOnlyProductUnitCodes && (_.contains(includeOnlyProductUnitCodes, key1) || _.contains(includeOnlyProductUnitCodes, key2)) || false;
                        }

                        if (!hasItemInExcludedList) {
                            hasItemInExcludedList = excludeProductUnitCodes && (_.contains(excludeProductUnitCodes, key1) || _.contains(excludeProductUnitCodes, key2)) || false;
                        }
                    });
                });

                var showCrossSell = (hasItemInIncludedList && !!(includeOnlyProductUnitCodes || "").length || !(includeOnlyProductUnitCodes || "").length)
                    && (!hasItemInExcludedList && !!(excludeProductUnitCodes || "").length || !(excludeProductUnitCodes || "").length);

                if (showCrossSell) {
                    $scope.crossSell = $scope.anonymUser.printOrderCrossSell;
                }
            }

            $scope.init = function () {
                /*$scope.model = $scope.$parent.getBillingDetails();
                if ($scope.model == null || $scope.model.length === 0 || !$scope.model.ticket) {
                    $scope.handleBack();
                }*/

                // TODO: remove
                //processPrintOrderCrossSell();
                //

                shoppingCartService.getBooking(function (bookingObject) {
                    if (!bookingObject) {                        
                        window.location = utilsFactory.addPersistentQueryStringsParams("/");
                        return;
                    }

                    $scope.model.emailAddress = bookingObject.email || bookingObject.bookings[0].customers[0].email;

                    if (!$scope.model.emailAddress || !$scope.model.emailAddress.length) {
                        $scope.customer = jwtService.getCustomer();

                        if ($scope.customer) {
                            $scope.model.emailAddress = $scope.customer.email;
                        }
                    }

                    $scope.model.bookingNumber = bookingObject.bookings[0].bookingNumber;
                    $scope.model.cart = bookingObject.shoppingCart;
                    processPrintOrderCrossSell();
                    //
                    var rockies2025combosflowpackagecodes = ($("body").attr("data-activity-rockies2025combosflowpackagecodes") || "").split("|");
                    var rockiescombosflowpackagecodes = ($("body").attr("data-activity-rockiescombosflowpackagecodes") || "").split("|");
                    var rockiesvaluecombosflowpackagecodes = ($("body").attr("data-activity-rockiesvaluecombosflowpackagecodes") || "").split("|");
                    var rockieslitecombosflowpackagecodes = ($("body").attr("data-activity-rockieslitecombosflowpackagecodes") || "").split("|");
                    var dateFormat = shoppingCartService.getDateFormat();
                    $scope.model.cart && $scope.model.cart.Items && _.each($scope.model.cart.Items, function (sitem, index) {

                        sitem.BookingToQuote && sitem.BookingToQuote.Packages && _.each(sitem.BookingToQuote.Packages, function (pkg, index) {
                            var packageCode = pkg.PackageCode;
                            var isRockies2025CombosFlow = (rockies2025combosflowpackagecodes || "").length && rockies2025combosflowpackagecodes.indexOf(packageCode) >= 0;
                            var isRockiesCombosFlow = (rockiescombosflowpackagecodes || "").indexOf(packageCode) >= 0;
                            var isRockiesValueCombosFlow = (rockiesvaluecombosflowpackagecodes || "").indexOf(packageCode) >= 0;
                            //var isRockiesLiteCombosFlow = ($scope.rockieslitecombosflowpackagecodes || "").length && $scope.rockieslitecombosflowpackagecodes.indexOf(packageCode) >= 0;

                            pkg._hideValidFromLabel = isRockies2025CombosFlow || isRockiesCombosFlow || isRockiesValueCombosFlow;

                            if (pkg.TravelWindow > 0) {
                                var label = $scope.labelUtils.getLabel("checkout.details.pkg-valid-window").replace("{0}", $scope.utils.formatDate(pkg.StartDate, dateFormat));

                                label = label.replace("{1}", moment(pkg.StartDate).add(6, "days").format(dateFormat));
                                pkg._travelWindowDatesLabel = label;
                            }
                        });
                    });
                    //

                    $scope.isFOLV = $scope.selectedGeographyCode == "FOLV";

                    // trackingService.buildFlowTrackerObjForPrintPage(bookingObject.bookings[0].bookingNumber, bookingObject.bookings[0].bookingId);
                    var trackerReq = {
                        lobTitle: null,
                        packageName: null,
                        searchDate: null,
                        adults: null,
                        children: null,
                        shoppingCart: $scope.model.cart,
                        anonymUser: $scope.anonymUser,
                        bookingNumber: bookingObject.bookings[0].bookingNumber,
                        bookingId: bookingObject.bookings[0].bookingId,
                        email: $scope.model.emailAddress
                    };
                    trackingService.buildFlowTrackerObj(trackerReq);

                    //if ($scope.model.cart) {
                    //    _.find($scope.model.cart.Items, function (cartitem) {
                    //        if (!cartitem.BookingToQuote || !cartitem.BookingToQuote.Components) return false;

                    //        var comp = _.find(cartitem.BookingToQuote.Components, function (comp) {
                    //            return comp.tripTeaseHotelCode;
                    //        });
                    //        if (comp) {
                    //            $scope.tripTreaseComp = comp;
                    //        }
                    //        return comp;
                    //    });
                    //    if ($scope.tripTreaseComp) {
                    //        $scope.initTripTease();
                    //    }
                    //}

                });
            };

            $scope.isSkylagoon = function () {
                return ($scope.selectedGeographyCode || "").toLowerCase().indexOf("skl") >= 0;
            };


            $scope.loadJS = function (url, implementationCode, location) {
                //url is URL of external file, implementationCode is the code
                //to be called from the file, location is the location to 
                //insert the <script> element

                var scriptTag = document.createElement('script');
                scriptTag.src = url;

                scriptTag.onload = implementationCode;
                scriptTag.onreadystatechange = implementationCode;

                location.appendChild(scriptTag);
            };

            $scope.preinit = function () {
                jwtService.getAnonymousUserByGeography($scope.$parent.selectedGeographyCode, function (user) {
                    $scope.anonymUser = user;
                    if ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) {
                        moment.locale($scope.selectedLanguage.languageCode);
                    }
                    $scope.init();
                });
            };

            // var t = jwtService.getPrincipalToken();
            var isGeneralCtrlReady = $scope.$parent.generalCtrlReady;
            if (isGeneralCtrlReady) {
                $scope.preinit();
            } else {
                $scope.isLoading = true;
                $scope.$on('generalCtrlReady', function (event, args) {
                    $scope.isLoading = false;
                    $scope.preinit();
                });
            };
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("redirectBookingCtrl", [
        "utilsFactory", "$scope", "$state", "shoppingCartService", "jwtService", "$element",
        function (utilsFactory, $scope, $state, shoppingCartService, jwtService, $element) {

            var webUrl = ($("body").data("weburl") ? $("body").data("weburl") : "");
            var bookingPostData = $($element).data("postdata");

            $scope.labelUtils = utilsFactory;

            $.material.init();

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            $scope.utils = shoppingCartService.utils;
            $scope.dateFormat = shoppingCartService.getDateFormat();


            $scope.errors = [];

            $scope.init = function () {
                var generalCtrl = $scope.$parent;
                $scope.isError = false;

                shoppingCartService.getStorageCart(function (shoppingCart) {
                    if (shoppingCart && shoppingCart.Items && shoppingCart.Items.length > 0) {
                        $scope.cart = shoppingCart;
                    }

                    if (!bookingPostData) { 
                        if ((document.referrer || "").indexOf(window.location.hostname) >= 0) {
                            if (document.referrer.toLowerCase().indexOf("checkout")) {
                                window.history.go(-1);
                            } else {
                                window.history.go(1);
                            }
                            return false;
                        } else {
                            if (!$scope.cart || !($scope.cart.Items || "").length) {
                                // window.location.href = "/";
                                $scope.isError = true;
                                return false;
                            }
                            window.location = utilsFactory.addPersistentQueryStringsParams((generalCtrl.selectedGeographyCode ? "/" + generalCtrl.selectedGeographyCode : "") + "/checkout");
                        }
                    } else {
                        addUpperCaseProperties(bookingPostData); // to fix the inconsistency
                        shoppingCartService.addQuotedDataToCart(bookingPostData, function () {
                            var isEnhanceBookingPageEnabled = ($scope.selectedLanguage && $scope.selectedLanguage.enableEnhanceBookingPage) || ($scope.anonymUser && $scope.anonymUser.enableEnhanceBookingPage);
                            var redirectToUrl = shoppingCartService.utils.getAfterAddToCartPageUrl(generalCtrl.selectedGeographyCode, isEnhanceBookingPageEnabled);
                            window.location = utilsFactory.addPersistentQueryStringsParams(redirectToUrl);
                        });
                        return true;
                    }
                });
            };

            // the data from pursuit ha all properites starting with lowercase, but on ibe, some properties require to start uppercase
            function addUpperCaseProperties(targetObject) {
                if (!targetObject) return;

                for (var key in targetObject) {
                    if (targetObject.hasOwnProperty(key) && key[0] == key[0].toLowerCase()) {
                        targetObject[key.charAt(0).toUpperCase() + key.slice(1)] = targetObject[key];
                        //delete targetObject[key];
                    }

                    if (typeof targetObject[key] === "object" && targetObject[key] !== null) {
                        addUpperCaseProperties(targetObject[key]);
                    }
                }
            }

            $scope.preinit = function () {
                jwtService.getAnonymousUserByGeography($scope.$parent.selectedGeographyCode, function (user) {
                    $scope.anonymUser = user;
                    if ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) {
                        moment.locale($scope.selectedLanguage.languageCode);
                    }
                    $scope.init();
                });
            };

            // var t = jwtService.getPrincipalToken();
            var isGeneralCtrlReady = $scope.$parent.generalCtrlReady;
            if (isGeneralCtrlReady) {
                $scope.preinit();
            } else {
                $scope.isLoading = true;
                $scope.$on('generalCtrlReady', function (event, args) {
                    $scope.isLoading = false;
                    $scope.preinit();
                });
            };
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("shoppingCartCtrl", [
        "utilsFactory", "$scope", "shoppingCartService", "jwtService", "productsFactory", "$uibModal", "packagesService",
        function (utilsFactory, $scope, shoppingCartService, jwtService, productsFactory, $uibModal, packagesService) {
            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            var timeoutID = undefined;

            function resizeSliderPanel() {
                window.clearTimeout(timeoutID);
                timeoutID = setTimeout(function () {
                    jQuery(window).resize();
                    if (jQuery("#promocode").length)
                        jQuery("#promocode").change();
                }, 100);
            }

            $scope.getPackageDurationLabel = packagesService.getPackageDurationLabel;

            $scope.labelUtils = utilsFactory;
            $scope.utils = shoppingCartService.utils;
            $scope.dateFormat = shoppingCartService.getDateFormat();
            $scope.addonLoading = false;

            $scope.promoCode = "";


            $scope.removeItemFromCart = function (index, ritem) {
                var confirmRemoveModalInstance = $uibModal.open({
                    animation: true,
                    templateUrl: "removeFromCartModal.html",
                    controller: "confirmRemoveFromCartModalCtrl",
                    size: "confirm-remove-cart",
                    resolve: {
                    },
                    backdrop: "true"
                });
                confirmRemoveModalInstance.result.then(function (result) {
                    //relatedProductCode
                    //var relatedItemsToRemove = [];
                    //_.each(cart.Items, function (ci, index) { if (ci.relatedProductCode == ritem.ProductCode) relatedItemsToRemove.push(index); });

                    var requestParams = {
                        apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                        token: jwtService.getPrincipalToken(),
                        index: index,
                        productCode: ritem.ProductCode
                    };
                    $scope.isLoading = true;
                    $scope.cart.optionalExtras = [];
                    shoppingCartService.setStorageCart($scope.cart, function () {
                        shoppingCartService.updateCartComponents(requestParams, function (shoppingCart) {
                            $scope.isLoading = false;
                            if (shoppingCart) {
                                $scope.cart = shoppingCart;
                                resizeSliderPanel();
                                $scope.getOptionalExtras();
                            }
                        });
                    });
                }, function () {
                    //console.log("dismiss");
                });
            };

            $scope.items = [];
            $scope.cart = shoppingCartService.getEmptyCart();
            $scope.isAgent = false;

            $scope.getTaxes = function (bookingQuoteComponent, quoteComponent) {
                var quotePrice = quoteComponent.Price;
                var numberOfAdults = parseInt(bookingQuoteComponent.NumberOfAdults);
                var numberOfChilds = parseInt(bookingQuoteComponent.NumberOfChildren);

                var totalPrice = numberOfAdults * bookingQuoteComponent.Price + numberOfChilds * bookingQuoteComponent.ChildPrice;

                return parseFloat(quotePrice - totalPrice).toFixed(2);
            };

            $scope.getCurrency = function () {
                var currency = jwtService.getPrincipalTokenCurrency();
                if (!currency && $scope.cart && $scope.cart.Quote) {
                    currency = $scope.cart.Quote.Currency;
                }
                return currency;
            };

            $scope.continueToCheckout = function () {
                var customer = jwtService.getCustomer();
                if (!customer) {
                    window.location = "/signin";
                    return;
                }

                window.location.href = "/checkout";
            };

            $scope.continueShopping = function () {
                window.location.href = "/";
            };

            //not using
            $scope.getQuoteComponentPrice = function (index, isPackage) {

                var quotes = [];
                //var indexes = shoppingCartService.getQuoteIndexes($scope.cart, index,isPackage);
                //var quotes = [];
                //debugger;
                //for (var j = indexes.startIndex; j <= indexes.endIndex; j++) {
                //    var quoteObject = $scope.cart.Quote.Components[j];
                //    if (quoteObject) {
                //        quotes.push(quoteObject);
                //    }
                //}

                //if (quotes.length > 0) {
                //    var price = 0;

                //    _.map(quotes, function (quote) {
                //        price += quote.Price;
                //    });

                //    return parseFloat(price).toFixed(2);
                //}

                return "NaN";
            };

            $scope.applyPromoCode = function () {
                if ($scope.promoCode && $scope.promoCode !== "") {
                    $scope.promoCode = $scope.promoCode.toUpperCase();
                    var requestParams = {
                        apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                        token: jwtService.getPrincipalToken(),
                        promoCode: $scope.promoCode
                    };
                    $scope.isLoading = true;
                    shoppingCartService.applyPromoCode(requestParams, function (shoppingCart) {
                        if (shoppingCart) {
                            $scope.cart = shoppingCart;
                            $scope.promoCode = "";
                            resizeSliderPanel();
                            $scope.getOptionalExtras();
                        }
                        $scope.isLoading = false;
                    });
                }
            };

            $scope.showPromoCodes = false;
            $scope.getPromoCodes = function () {
                if ($scope.cart && ($scope.cart.DiscountCodes || "").length) {
                    $scope.showPromoCodes = true;
                    return $scope.cart.DiscountCodes;
                }
                $scope.showPromoCodes = false;
                return [];
            };
            $scope.removePromoCode = function (index) {
                if (!$scope.cart || !($scope.cart.DiscountCodes || "").length) return;

                var rvItem = $scope.cart.DiscountCodes[index];
                if (!rvItem) return;

                var newCodes = _.reject($scope.cart.DiscountCodes, function (item, itemIndex) {
                    return itemIndex === index;
                });
                var requestParams = {
                    apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                    token: jwtService.getPrincipalToken(),
                    promoCodes: newCodes
                };
                $scope.isLoading = true;
                shoppingCartService.refreshPromoCodesQuote(requestParams, function (shoppingCart) {
                    if (shoppingCart) {
                        $scope.cart = shoppingCart;
                        resizeSliderPanel();
                        $scope.getOptionalExtras();
                    }
                    $scope.isLoading = false;
                });
            };

            //$scope.getPromoCodes = function () {
            //    var promoCodes = shoppingCartService.utils.getPromoCodes($scope.cart);
            //    if (promoCodes !== "") {
            //        $scope.showPromoCodes = true;
            //    } else {
            //        $scope.showPromoCodes = false;
            //    }
            //    if (promoCodes) {
            //        setTimeout(function () {
            //            jQuery('[data-toggle="tooltip"]').tooltip();
            //        });
            //    }
            //    return promoCodes;
            //};

            $scope.cart.optionalExtras = [];

            function fillProductDetails(source, index, callback) {
                var item = source[index];
                if (!item) {
                    callback();
                }
                productsFactory.getProduct(jwtService.getPrincipalToken(), item.productCode, item.productCategory, item.date).then(
                    function (result) {
                        item.product = undefined;

                        if (!result.data.products || result.data.products.length === 0) {
                            if (source.length > index + 1) {
                                fillProductDetails(source, index + 1, callback);
                            } else {
                                callback();
                            }
                            return;
                        }

                        item.product = result.data.products[0];

                        if (item.unitCode && (item.product.units || "").length) {
                            item.unit = _.find(item.product.units, function (un) { return un.unitCode == item.unitCode; })
                        }

                        if (source.length > index + 1) {
                            fillProductDetails(source, index + 1, callback);
                        }
                        else {
                            callback();
                        }
                    }, function () {
                        if (source.length > index + 1) {
                            fillProductDetails(source, index + 1, callback);
                        }
                        else {
                            callback();
                        }
                    });
            }

            $scope.addOptionalProduct = function (oc) {
                var product = oc.product;
                if (!product) return;
                var cartItem = _.find($scope.cart.Items, function (it) {
                    return (it.ProductCode || "").toLowerCase() === (oc.relatedProductCode || "").toLowerCase() && it.BookingToQuote && (it.BookingToQuote.Components || "").length;
                });

                if (!cartItem) return;
                var date = moment(product.startDate);
                var dateStr = "";
                if (date.isValid()) {
                    dateStr = date.format("YYYY-MM-DD");
                }

                if (product.productCategory === "Attraction") {
                    window.location.href = "/activities/details/" + product.code + "/Attraction/" + (oc.date || dateStr) + "/" + (oc.unitCode || "") + "/#/select-ticket/book-adventure";
                    return;
                } else if (product.productCategory === "Tour") {
                    window.location.href = "/activities/details/" + product.productType + "/Tour/" + (oc.date || dateStr) + "/" + (oc.unitCode || "") + "/#/select-ticket/book-adventure";
                    return;
                } else if (product.productCategory === "Transportation") {
                    window.location.href = "/transportation/details/" + product.productType + "/Transportation/" + (oc.date || dateStr) + "/" + (oc.unitCode || "") + "/#/select-transportation-ticket/book-transportation-adventure";
                    return;
                }


                //  $scope.cart.optionalExtras=   _.reject($scope.cart.optionalExtras, function (it) { return it. % 2 == 0; });
                //delete optional item from list
                var components = [];
                var bookingComponent = {
                    "Id": oc.productCode + (oc.unit || product.units[0]).unitCode,
                    "ProductCategory": product.productCategory,
                    "ProductType": product.productType,
                    "ProductCode": product.code,
                    "StartDate": product.startDate,
                    "EndDate": product.endDate,
                    "Name": product.name,
                    "Description": product.description,
                    "Price": product.price,
                    "ChildPrice": product.price,
                    "NumberOfAdults": cartItem.BookingToQuote.Components[0].NumberOfAdults,
                    "NumberOfChildren": cartItem.BookingToQuote.Components[0].NumberOfChildren,
                    "NumberOfInfants": 0,
                    "Status": "New",
                    "UnitCode": (oc.unit || product.units[0]).unitCode,
                    "UnitDescription": (oc.unit || product.units[0]).description,
                    "PickupLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                    "DropoffLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                    "StartingLocation": product.startingLocation,
                    "Destination": product.destination,
                    "Remarks": []
                };
                components.push(bookingComponent);

                var bookingToQuote = {
                    "Components": components
                };
                var data = {
                    "BookingToQuote": bookingToQuote
                };

                var requestParams = {
                    apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                    token: jwtService.getPrincipalToken(),
                    dataToPost: data,
                    startDate: cartItem.StartDate,
                    endDate: undefined,
                    startTime: "Any Time",
                    endTime: undefined,
                    relatedProductCode: oc.relatedProductCode

                };
                $scope.isLoading = true;
                var prevOptionalExtras = $scope.cart.optionalExtras;
                shoppingCartService.addComponentsToCart(requestParams, function (result) {
                    if (result) {
                        shoppingCartService.getStorageCart(function (shoppingCart) {
                            $scope.isLoading = false;
                            if (shoppingCart) {
                                $scope.cart = shoppingCart;
                                $scope.cart.optionalExtras = prevOptionalExtras;
                                // $scope.getOptionalExtras();
                                resizeSliderPanel();
                            }
                        });
                    } else {
                        $scope.isLoading = false;
                    }

                });
            };

            $scope.showOptionalExtras = function () {
                if (!$scope.cart || !($scope.cart.optionalExtras || "").length) {

                    return false;
                }
                var r = _.find($scope.cart.optionalExtras,
                    function (opItem) { return opItem.product && (opItem.product.units || "").length; });
                return r != undefined;
            };

            $scope.getOptionalExtras = function () {
                if ($scope.addonLoading || $scope.isLoading || !$scope.cart || !($scope.cart.Items || "").length) {
                    return;
                }
                var productQueries = [];
                var mapUniqueProducts = Object.create(null);
                _.each($scope.cart.Items, function (item) {
                    if (item && item.ProductCode) {
                        var itKey = item.ProductCode
                            + moment(item.StartDate, shoppingCartService.getDateFormat()).format("YYYY-MM-DD")
                            + (item.UnitCode ? item.UnitCode : "");
                        if (!(itKey in mapUniqueProducts)) {
                            productQueries.push({
                                ProductCode: item.ProductCode,
                                TravelDate: moment(item.StartDate, shoppingCartService.getDateFormat()).format("YYYY-MM-DD"),
                                UnitCode: item.UnitCode ? item.UnitCode : null
                            });
                            mapUniqueProducts[itKey] = 1;
                        }
                    }
                });


                if (!productQueries.length) {
                    return;
                }

                var dataToPost = { ProductQueries: productQueries };
                var requestParams = {
                    token: jwtService.getPrincipalToken(),
                    data: dataToPost
                };
                $scope.addonLoading = true;
                $scope.cart.optionalExtras = [];

                productsFactory.getRelatedServicesMulti(requestParams, function (relatedProducts) {

                    if (relatedProducts && relatedProducts.data && relatedProducts.data.length) {
                        var result = [];
                        _.each(relatedProducts.data, function (item) {
                            if ((item.optionalExtras || "").length) {

                                var parentCartItem = _.find($scope.cart.Items, function (cartItem) {
                                    return cartItem && cartItem.ProductCode && cartItem.ProductCode.toLowerCase() === item.relatedProductCode.toLowerCase();
                                });

                                var date = moment(parentCartItem.StartDate).format("YYYY-MM-DD");
                                _.each(item.optionalExtras, function (optionItem) {
                                    optionItem.relatedProductCode = item.relatedProductCode;
                                    optionItem.date = date;
                                    result.push(optionItem);
                                });
                            }
                        });
                        if (result.length) {
                            fillProductDetails(result, 0, function () {
                                $scope.cart.optionalExtras = result;
                                shoppingCartService.setStorageCart($scope.cart, function () { });
                                $scope.addonLoading = false;
                                resizeSliderPanel();
                            });
                        } else {
                            $scope.addonLoading = false;
                            resizeSliderPanel();
                        }
                    } else {
                        $scope.addonLoading = false;
                    }

                    resizeSliderPanel();
                });
            };

            $scope.init = function () {
                $scope.isLoading = true;
                var customerTokenObj = jwtService.getCustomerTokenObj();
                $scope.isAgent = (customerTokenObj && customerTokenObj.loginType && customerTokenObj.loginType === "agent");

                shoppingCartService.getStorageCart(function (shoppingCart) {
                    $scope.isLoading = false;
                    if (shoppingCart) {
                        $scope.cart = shoppingCart;

                        resizeSliderPanel();
                        if (!($scope.cart.optionalExtras || "").length) {
                            $scope.getOptionalExtras();
                        }

                        var externalPromoCode = shoppingCartService.getExternalPromoCode();
                        if (externalPromoCode) {
                            $scope.promoCode = (externalPromoCode || "").trim();
                            $scope.applyPromoCode();
                            shoppingCartService.setExternalPromoCode(null);
                        }
                    }
                });
            };

            var t = jwtService.getPrincipalToken();

            if (t && t.length > 0) {
                $scope.init();
            } else {
                $scope.isLoading = true;
                $scope.$on("getPrincipalToken", function (event, args) {
                    $scope.isLoading = false;
                    $scope.init();
                });
            };
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("updateBookingCtrl", [
        "utilsFactory", "jwtService", "$scope", "$state", "$rootScope", "validHelper", "customerService", "$element", "$window", "shoppingCartService", "productsFactory", "$timeout", "transportationService",
        function (utilsFactory, jwtService, $scope, $state, $rootScope, validHelper, customerService, $element, $window, shoppingCartService, productsFactory, $timeout, transportationService) {


            var webUrl = ($("body").data("weburl") ? $("body").data("weburl") : "");
            $scope.rockies2025combosflowpackagecodes = ($("body").attr("data-activity-rockies2025combosflowpackagecodes") || "").split("|");
            $scope.rockiescombosflowpackagecodes = ($("body").attr("data-activity-rockiescombosflowpackagecodes") || "").split("|");
            $scope.rockiesvaluecombosflowpackagecodes = ($("body").attr("data-activity-rockiesvaluecombosflowpackagecodes") || "").split("|");
            $scope.rockieslitecombosflowpackagecodes = ($("body").attr("data-activity-rockieslitecombosflowpackagecodes") || "").split("|");
            $scope.isPursuitPassFlow = false;
            $scope.isRelatedServicesError = false;

            $.material.init();
            $scope.labelUtils = utilsFactory;
            $scope.utils = shoppingCartService.utils;
            $scope.validHelper = validHelper;
            $scope.bookingNumber = $($element).attr("data-bookingNo");
            $scope.isLoading = false;
            $scope.isCustomer = false;
            $scope.booking = undefined;
            $scope.bookingUpdated = true;
            $scope.showCannotCancelBookingMsg = false;

            $scope.canChangeConfirmationEmailAddress = false;
            $scope.cancelBookingModel = {};
            $scope.timesBtw = null;

            $scope.productLabels = utilsFactory.getLabel("activity.specificProduct", true);
            $scope.getProductLabel = function (productCode, key) {
                var obj = utilsFactory.getProductLabel($scope.productLabels, productCode);
                if (!obj) {
                    var currentRegion = ($scope.selectedGeographyCode || "").toUpperCase();
                    obj = utilsFactory.getProductLabelByRegion($scope.productLabels, currentRegion);
                }
                if (!obj || !key) return obj;
                return obj[key];
            };

            function setIsPursuitPassFlowCheck() {
                $scope.isPursuitPassFlow = false;
                if (!$scope.booking) {
                    return false;
                }

                $scope.booking.packages && _.each($scope.booking.packages, function (pkg) {
                    if ($scope.isPursuitPassFlow) return;

                    var packageCode = pkg.PackageCode;
                    var isRockies2025CombosFlow = ($scope.rockies2025combosflowpackagecodes || "").length && $scope.rockies2025combosflowpackagecodes.indexOf(packageCode) >= 0;
                    var isRockiesCombosFlow = ($scope.rockiescombosflowpackagecodes || "").length && $scope.rockiescombosflowpackagecodes.indexOf(packageCode) >= 0;
                    var isRockiesValueCombosFlow = ($scope.rockiesvaluecombosflowpackagecodes || "").length && $scope.rockiesvaluecombosflowpackagecodes.indexOf(packageCode) >= 0;
                    var isRockiesLiteCombosFlow = ($scope.rockieslitecombosflowpackagecodes || "").length && $scope.rockieslitecombosflowpackagecodes.indexOf(packageCode) >= 0;
                    $scope.isPursuitPassFlow = isRockies2025CombosFlow || isRockiesCombosFlow || isRockiesValueCombosFlow || isRockiesLiteCombosFlow;
                });
            }

            $scope.showModal = {
                "SubmitErrors": false
            };

            $scope.showModal = {
                "UpdateSuccess": false
            };

            $scope.globalErrors = [];

            $scope.model = {
                confirmEmail: undefined
            };
            $scope.$on("customer-changed", function (event, args) {
                //$scope.init();
            });

            function setCheckIfBookingCanBeCancelledMessage() {
                if (!$scope.booking) return;

                $scope.booking.packages && _.each($scope.booking.packages, function (pkg) {
                    // TODO: change to use the .traveWindow field
                    //var packageCode = pkg.PackageCode;
                    //var isRockiesLiteCombosFlow = (rockieslitecombosflowpackagecodes || "").length && rockieslitecombosflowpackagecodes.indexOf(packageCode) >= 0;

                    if (pkg.TravelWindow > 0) {
                        var label = $scope.labelUtils.getLabel("checkout.details.pkg-valid-window").replace("{0}", $scope.utils.formatDate(pkg.StartDate, shoppingCartService.getDateFormat()));

                        label = label.replace("{1}", moment(pkg.StartDate).add(pkg.TravelWindow - 1, "days").format(shoppingCartService.getDateFormat()));
                        pkg._travelWindowDatesLabel = label;
                    }
                });

                var isBJC = ($scope.actionRegionCode || "").toUpperCase().indexOf("RKY") >= 0;
                console.log("check booking if it can be cancelled: ", $scope.booking);

                var hasAttraction = false;
                if (isBJC) {
                    $scope.booking.components && _.each($scope.booking.components, function (component) {
                        if (hasAttraction) return;
                        hasAttraction = component.productCategory == 'Attraction' && component.productType == 'ATTR';
                    });

                    if (!hasAttraction) {
                        $scope.booking.packages && _.each($scope.booking.packages, function (pkg) {
                            if (hasAttraction || pkg.type != "COMBO") return;

                            pkg.Components && _.each(pkg.Components, function (pkgComp) {
                                if (hasAttraction) return;
                                hasAttraction = pkgComp.ProductCategory == 'Attraction' && pkgComp.ProductType == 'ATTR';
                            });
                        });
                    }
                }

                var canCancelBookingLegacy = (isBJC && !hasAttraction) || !isBJC;
                $scope.showCannotCancelBookingMsg = !canCancelBookingLegacy;
            }

            function refreshInputs(container) {
                setTimeout(function () {
                    var inputs = (container + " input");
                    jQuery(inputs).change();
                    var selects = (container + " select, " + container + " md-select");
                    jQuery(selects).blur();

                });
            }

            function checkIfLogedIn() {
                var token = jwtService.getCustomerToken();
                var customer = jwtService.getCustomer();

                $scope.isCustomer = (customer && token && token.length);
                var customerTokenObj = jwtService.getCustomerTokenObj();
                $scope.isAgent = (customerTokenObj && customerTokenObj.loginType && customerTokenObj.loginType === "agent");
                //if ($scope.isCustomer) {
                //    $scope.model.confirmEmail = $scope.model.confirmEmail_c = customer.email;
                //    refreshInputs("#updateConfirmEmail");
                //}
                $scope.canChangeConfirmationEmailAddress = !$scope.isAgent;
            }

            function getDateWithoutTime(date) {
                return !date ? date : (date.toLowerCase().indexOf("t") > 0 ? date.substring(0, date.toLowerCase().indexOf("t")) : date);
            };

            $scope.$on("mergeGlobalErros", function (event, args) {
                // $scope.isLoading = false;
            });



            $scope.appentTitle = function (currentTitle, components, index) {
                var title = "";

                if (components[index].productCategory === "Transportation") {
                    title = shoppingCartService.getTransportationProductName(components[index], components, index);
                } else {
                    title = components[index].description;
                }

                currentTitle = currentTitle.length ? currentTitle + "<br/> " + title : title;

                return currentTitle;
            }

            $scope.mainComponentsFilter = function (item) {
                return (item.isRequired || !item.isAttachedToParent) && !$scope.utils.isFee(item) && !$scope.utils.isTimeComponent(item);
            };

            $scope.getTimeDescription = function (timeUnit, timeProduct) {
                if (timeUnit)
                    return (timeUnit.description || moment(timeUnit.startTime).format("hh:mm A"));
                return "No time unit";
                //switch (timeProduct.productType) {
                //    case "FLT-TIME":
                //        return moment(timeUnit.startTime).format("hh:mm A");
                //    default:
                //        return moment(timeUnit.startTime).format("hh:mm A");
                //}
            };

            $scope.setDownTimes = function (unit) {
                //$scope.submitted = false;
                $scope.errors = [];
                $scope.bookingUpdated = false;
                if (!unit || !unit.upTimeProduct || !unit.downTimeProduct) return;
                if (!unit.upTimeProduct.selectedUnit) {
                    unit.downTimeProduct.selectedUnit = undefined;
                    return;
                }

                var startMin = moment(unit.upTimeProduct.selectedUnit.startTime);
                var startRecomm = moment(unit.upTimeProduct.selectedUnit.startTime);

                var interval = unit.downTimeProduct.minimumIntervalInMinutes
                    ? parseInt(unit.downTimeProduct.minimumIntervalInMinutes) : 0;

                startMin.add(interval, "m");

                unit.downTimeProduct.filteredUnits = _.filter(unit.downTimeProduct.units, function (un) {
                    return startMin <= moment(un.startTime);
                });

                if (!(unit.downTimeProduct.filteredUnits || "").length) {
                    unit.downTimeProduct.selectedUnit = undefined;
                    return;
                }

                if (!unit.downTimeProduct.recommendedIntervalInMinutes) {
                    return;
                }

                interval = parseInt(unit.downTimeProduct.recommendedIntervalInMinutes);
                startRecomm.add(interval, "m");

                unit.downTimeProduct.selectedUnit = _.find(unit.downTimeProduct.units, function (un) {
                    return startRecomm <= moment(un.startTime);
                });

                if (!unit.downTimeProduct.selectedUnit) {
                    unit.downTimeProduct.selectedUnit = unit.downTimeProduct.units[0];
                }
            };

            $scope.getRelatedServicesParams = function (bookingParam) {
                var booking = bookingParam || $scope.booking;
                if (!booking) return "";
                return "agencyKey=" + (booking.Agency && booking.Agency.AgencyNumber || "") + "&brand=" + (booking.brand || "")
                    + "&salesChannel=" + (booking.salesChannel) + "&rateType=" + (booking.rateType || "");
            };


            $scope.changeAttractionTimes = function (targetComp, targetDate, callback) {
                if (!(targetComp.unitCode || targetComp.UnitCode)) {
                    callback && callback();
                    return false;
                }
                var selectedUnitCodeNormalized = (targetComp.unitCode || targetComp.UnitCode);
                var selectedUnit = targetComp.details && (targetComp.details.selectedUnit || _.find((targetComp.details.units || []), function (unit) {
                    return unit.unitCode == selectedUnitCodeNormalized;
                }));

                if (selectedUnit && selectedUnit.loadRelatedServices === false) {
                    callback && callback();
                    return false;
                }

                var productQueries = [];
                productQueries.push({
                    ProductCode: (targetComp.productCode || targetComp.ProductCode),
                    TravelDate: targetDate,
                    UnitCode: (targetComp.unitCode || targetComp.UnitCode),
                    IncludeDeferredProducts: true
                });
                var dataToPost = { ProductQueries: productQueries, QueryParams: $scope.getRelatedServicesParams() };
                var relatedServicesRequestParams = {
                    token: jwtService.getPrincipalToken(),
                    data: dataToPost
                };
                // $scope.isLoading = true;
                return productsFactory.getRelatedServicesMulti(relatedServicesRequestParams, function (relatedProducts) {
                    // $scope.isLoading = false;
                    if ((!relatedProducts || !relatedProducts.data || "").length) {
                        callback();
                        return;
                    }
                    targetComp.hasRelatedProducts = true;
                    var prevSelectedUpTimeUnitCode = targetComp.relatedProducts && targetComp.relatedProducts.upTimeProduct && targetComp.relatedProducts.upTimeProduct.selectedUnit
                        ? targetComp.relatedProducts.upTimeProduct.selectedUnit.unitCode : "";

                    var prevSelectedDownTimeUnitCode = targetComp.relatedProducts && targetComp.relatedProducts.downTimeProduct && targetComp.relatedProducts.downTimeProduct.selectedUnit
                        ? targetComp.relatedProducts.downTimeProduct.selectedUnit.unitCode : "";

                    targetComp.relatedProducts = relatedProducts.data[0];

                    if (targetComp.relatedProducts) {
                        if ((targetComp.relatedProducts.attractionTimes || "").length) {
                            if (targetComp.relatedProducts.attractionTimes[0].isPrimary) {
                                targetComp.relatedProducts.upTimeProduct = targetComp.relatedProducts.attractionTimes[0];
                            } else {
                                targetComp.relatedProducts.downTimeProduct = targetComp.relatedProducts.attractionTimes[0];
                            }

                            if (targetComp.relatedProducts.attractionTimes[1]) {
                                if (targetComp.relatedProducts.attractionTimes[1].isPrimary) {
                                    targetComp.relatedProducts.upTimeProduct = targetComp.relatedProducts.attractionTimes[1];
                                } else {
                                    targetComp.relatedProducts.downTimeProduct = targetComp.relatedProducts.attractionTimes[1];
                                }
                            }
                        }

                        if (prevSelectedUpTimeUnitCode && targetComp.relatedProducts.upTimeProduct) {
                            targetComp.relatedProducts.upTimeProduct.selectedUnit = _.find(targetComp.relatedProducts.upTimeProduct.units,
                                function (upUnit) { return upUnit.unitCode == prevSelectedUpTimeUnitCode; });
                        }
                        if (prevSelectedDownTimeUnitCode && targetComp.relatedProducts.downTimeProduct) {
                            targetComp.relatedProducts.downTimeProduct.selectedUnit = _.find(targetComp.relatedProducts.downTimeProduct.units,
                                function (downUnit) { return downUnit.unitCode == prevSelectedDownTimeUnitCode; });
                        }
                    }

                    $scope.setDownTimes(targetComp.relatedProducts);
                    callback();
                });
            };

            $scope.transportUnitChanged = function (comp) {
                if ($scope.isLoading || !comp || !comp.filter || !comp.filter.selectedUnit || comp.filter.selectedUnit.busStops) return;

                if ((comp.filter.selectedUnit.busStops || "").length) {
                    $scope.filterTransportationUnits(comp);
                    $scope.isLoading = false;
                    return;
                }

                $scope.isLoading = true;
                $scope.errors = [];
                // $scope.submitted = false;
                $scope.bookingUpdated = false;

                comp.filter.selectedUnit = comp.details && _.find(comp.details.units, function (un) { return un.unitCode == comp.filter.selectedUnit.unitCode; });


                $scope.getProductBusStops(comp, comp.filter.selectedUnit.unitCode, function () {
                    $scope.filterTransportationUnits(comp);
                    $scope.isLoading = false;
                });

            };

            $scope.isSkylagoon = function () {
                return ($scope.selectedGeographyCode || "").toLowerCase().indexOf("skl") >= 0;
            };

            $scope.getDynamicPricesKey = function (comp, month, year) {
                var productCode = comp && comp.productCode;
                if (!productCode) return;

                month++; // month start at 0, so we need to increment
                return String(month) + String(year) + productCode.toLowerCase();
            };

            $scope.loadCalendarPrices = function (comp, $inlineDatePicker, month, year) {
                var productCode = (comp && (comp.productCode)); // don't run for packages || comp.productcode
                if (!productCode) return;
                if (!comp.dynamicPrices) {
                    comp.dynamicPrices = Object.create(null);
                }

                var priceObjKey = $scope.getDynamicPricesKey(comp, month, year);

                month++; // month start at 0, so we need to increment              
                if (comp.dynamicPrices[priceObjKey]) return; // if the dynamic prices were already loaded return;

                //$scope.calendarIsLoading = true;
                $inlineDatePicker.toggleLoading(true);

                var req = {
                    token: jwtService.getPrincipalToken(),
                    productCode: productCode,
                    unitCode: comp.unitCode || comp.unitcode,
                    currentComponentPrice: comp.price,
                    numberOfAdults: Number(comp.numberOfAdults || 0),
                    numberOfChildren: Number(comp.numberOfChildren || 0),
                    numberOfSeniors: Number(comp.numberOfSeniors || 0),
                    numberOfStudents: Number(comp.numberOfStudents || 0),
                    month: month,
                    year: year
                };
                productsFactory.getUpgradePrices(req).then(
                    function (result) {
                        var prices = result.data.prices;
                        if ((prices || "").length) {
                            var monthPrices = Object.create(null);
                            $.each(prices, function (key, value) {
                                var vdate = moment(value.date, 'YYYY-MM-DDTHH:mm:ss').date()
                                monthPrices[vdate] = { price: value.price, className: (value.projectedVisitation || "").toLowerCase() };
                            });
                            comp.dynamicPrices[priceObjKey] = monthPrices;
                        }
                        //$scope.calendarIsLoading = false;

                        $inlineDatePicker.toggleLoading(false);
                        $inlineDatePicker.update();
                    },
                    function (response) {
                        //$scope.calendarIsLoading = false;
                        $inlineDatePicker.toggleLoading(false);
                    });
            };


            $scope.initDatePicker = function () {
                if ($scope.booking) {
                    $timeout(function () {
                        var defaultDate = jwtService.getServerMomentDate();
                        defaultDate.add("1", "d");

                        jQuery($element).find(".date-picker:not(.for-display-only)").each(function () {
                            var isCompDisabled = false;

                            //  var dateStr = jQuery(this).attr("data-minDate");
                            var compMinDate = undefined;
                            var compMaxDate = undefined;

                            //
                            var pckIndex = jQuery(this).attr("data-packageindex");
                            pckIndex = isNaN(pckIndex) ? -1 : parseInt(pckIndex);

                            var pckCompIndex = jQuery(this).attr("data-packageCompIndex");
                            pckCompIndex = isNaN(pckCompIndex) ? -1 : parseInt(pckCompIndex);

                            if (($scope.booking.packages || "").length && $scope.booking.packages[pckIndex]) {
                                var selectedDate = undefined;

                                var pck = ($scope.booking.packages[pckIndex]);

                                //
                                var currentDateFallback = jwtService.getServerMomentDate();

                                var availableFrom = pck.AvailableFrom && moment(pck.AvailableFrom) || null;
                                if (!availableFrom || !availableFrom.isValid() || availableFrom.year() < 2000) availableFrom = null;
                                else if (availableFrom.isBefore(currentDateFallback, "day")) {
                                    availableFrom = currentDateFallback;
                                }

                                var availableTo = pck.AvailableUntil && moment(pck.AvailableUntil) || null;
                                if (!availableTo || !availableTo.isValid() || availableTo.year() < 2000) availableTo = null;
                                else if (availableFrom && availableTo.isBefore(availableFrom, "day")) {
                                    availableFrom = null;
                                }
                                //

                                var dateIsSet = false;



                                if ((pck.Components || "").length && pck.Components[pckCompIndex]) {
                                    var comp = pck.Components[pckCompIndex];

                                    isCompDisabled = pck.Components[pckCompIndex].isDisabled;

                                    var upTimeProduct = pck.Components[pckCompIndex].relatedProducts && pck.Components[pckCompIndex].relatedProducts.upTimeProduct;
                                    dateIsSet = upTimeProduct;

                                    if (upTimeProduct) {
                                        selectedDate = moment(upTimeProduct.startDate);
                                        jQuery(this).val(selectedDate.format(shoppingCartService.getDateFormat()));
                                    }
                                    //set datepicker min date

                                    var primaryTimeComp = pck.Components[pckCompIndex].primaryTimeComp;
                                    if (primaryTimeComp && !primaryTimeComp.isDisabled) {
                                        compMinDate = primaryTimeComp.minChangableDate ? moment(primaryTimeComp.minChangableDate) : defaultDate;
                                        compMaxDate = primaryTimeComp.maxChangableDate ? moment(primaryTimeComp.maxChangableDate) : undefined;
                                    }

                                    // travel window
                                    //var packageCode = pck.PackageCode;
                                    //var isRockiesCombosFlow = (rockiescombosflowpackagecodes || "").length && rockiescombosflowpackagecodes.indexOf(packageCode) >= 0;
                                    //var isRockiesValueCombosFlow = (rockiesvaluecombosflowpackagecodes || "").length && rockiesvaluecombosflowpackagecodes.indexOf(packageCode) >= 0;
                                    //var isRockiesLiteCombosFlow = (rockieslitecombosflowpackagecodes || "").length && rockieslitecombosflowpackagecodes.indexOf(packageCode) >= 0;

                                    if (pck.TravelWindow > 0) { // 
                                        var pkgStartDate = moment(pck.StartDate);
                                        //dateConfig.minDate
                                        compMinDate = pkgStartDate;
                                        //dateConfig.maxDate =
                                        compMaxDate = pkgStartDate.clone().add(pck.TravelWindow - 1, "days");
                                        //dateConfig.autoSelectInitialInput = false; // TODO:
                                    } else {
                                        if (availableFrom && availableFrom.isValid()) {
                                            compMinDate = availableFrom;
                                        }
                                        if (availableTo && availableTo.isValid()) {
                                            compMaxDate = availableTo;
                                        }
                                    }
                                    // pck.Travel>0 TODO:

                                }

                                if (!dateIsSet) {
                                    selectedDate = moment($scope.booking.packages[pckIndex].StartDate);
                                    jQuery(this).val(selectedDate.format(shoppingCartService.getDateFormat()));
                                }

                            } else if ($(this).attr("data-compId")) {

                                var compID = $(this).attr("data-compId");
                                var comp = _.find($scope.booking.components, function (c) {
                                    return c.id == compID;
                                });
                                var selectedDate = undefined;

                                if (comp && comp.relatedProducts && comp.relatedProducts.upTimeProduct) {
                                    if (jQuery(this).hasClass("inline-datepicker")) {
                                        selectedDate = moment(comp.relatedProducts.upTimeProduct.startDate);
                                    } else {
                                        selectedDate = moment(comp.relatedProducts.upTimeProduct.startDate);
                                    }
                                } else {
                                    selectedDate = moment(comp.startDate);

                                    if (jQuery(this).hasClass("inline-datepicker")) {
                                        //
                                    } else {
                                        jQuery(this).val(selectedDate.format(shoppingCartService.getDateFormat()));
                                    }
                                }

                                if (comp) {
                                    //set datepicker min date
                                    var primaryTimeComp = comp.primaryTimeComp || comp;
                                    if (primaryTimeComp && !primaryTimeComp.isDisabled) {
                                        compMinDate = primaryTimeComp.minChangableDate ? moment(primaryTimeComp.minChangableDate) : defaultDate;
                                        compMaxDate = primaryTimeComp.maxChangableDate ? moment(primaryTimeComp.maxChangableDate) : undefined;
                                    }
                                    if (comp.isReturnProduct) {
                                        var departureProduct = _.find($scope.booking.components, function (dep) {
                                            return dep.returnProduct && dep.returnProduct.id == comp.id;
                                        });

                                        if (departureProduct) {
                                            compMinDate = moment(departureProduct.startDate);
                                        }
                                    }
                                }
                            }

                            var pickerSettings = {
                                singleDatePicker: true,
                                // minDate: compMinDate, 
                                showDropdowns: true,
                                locale: {
                                    format: shoppingCartService.getDateFormat()
                                }
                            };

                            if (!isCompDisabled) {
                                if (compMinDate && compMinDate.isValid()) {
                                    pickerSettings.minDate = compMinDate;
                                }
                                if (compMaxDate && compMaxDate.isValid() && compMaxDate.year() < 2100) {//for performance
                                    pickerSettings.maxDate = compMaxDate;
                                }
                            }

                            var dateChanged = function (picker, isDynamicPrice) {
                                //do nothing
                                $scope.errors = [];
                                // $scope.submitted = false;
                                $scope.bookingUpdated = false;
                                if ($scope.isLoading) return;

                                var dateFormat = "YYYY-MM-DD";
                                var strDate;
                                if (isDynamicPrice) {
                                    // use the inline picker
                                    strDate = ((picker.selectedDates || "").length ?
                                        moment(picker.selectedDates[0]) : moment()).format(dateFormat);
                                } else {
                                    //var date = $("#daterange").val();
                                    strDate = moment(picker.val(), shoppingCartService.getDateFormat()).format(dateFormat);
                                }

                                //var date = $(this).val();
                                //var strDate = moment(date, shoppingCartService.getDateFormat()).format("YYYY-MM-DD");

                                if (jQuery(this).attr("data-packageindex")) {
                                    var pckIndex = jQuery(this).attr("data-packageindex");
                                    pckIndex = isNaN(pckIndex) ? -1 : parseInt(pckIndex);

                                    var pckCompIndex = jQuery(this).attr("data-packageCompIndex");
                                    pckCompIndex = isNaN(pckCompIndex) ? -1 : parseInt(pckCompIndex);

                                    if (($scope.booking.packages || "").length && $scope.booking.packages[pckIndex]) {
                                        var pck = ($scope.booking.packages[pckIndex]);
                                        if (pck.TourTimesCanBeOnDifferentDates===false) {
                                            ///
                                            var pickerPromises = [];
                                            var selfPicker = jQuery(this).data('daterangepicker');
                                            var selfPickerInline = jQuery(this).data('datepicker');

                                            jQuery($element).find(":not(.for-display-only)[name=daterange][data-packageIndex=" + pckIndex + "]").each(function () {
                                                var dRpck = jQuery(this).data('daterangepicker');

                                                var pckCompIndex = jQuery(this).attr("data-packageCompIndex");
                                                pckCompIndex = isNaN(pckCompIndex) ? -1 : parseInt(pckCompIndex);

                                                var comp = pck.Components[pckCompIndex];
                                                if (comp) {
                                                    dRpck.setStartDate(selfPicker.startDate);
                                                    dRpck.setEndDate(selfPicker.startDate);
                                                    pickerPromises.push($scope.changeAttractionTimes(comp, strDate, function () { }));
                                                }
                                            });

                                            jQuery($element).find(":not(.for-display-only).inline-datepicker[data-packageIndex=" + pckIndex + "]").each(function () {
                                                var dRpck = jQuery(this).data('datepicker');

                                                var pckCompIndex = jQuery(this).attr("data-packageCompIndex");
                                                pckCompIndex = isNaN(pckCompIndex) ? -1 : parseInt(pckCompIndex);

                                                var comp = pck.Components[pckCompIndex];
                                                if (comp) {
                                                    dRpck.selectDate(selfPickerInline.selectedDates && selfPickerInline.selectedDates[0],true);

                                                    //dRpck.setStartDate(selfPicker.startDate);
                                                    //dRpck.setEndDate(selfPicker.startDate);
                                                    pickerPromises.push($scope.changeAttractionTimes(comp, strDate, function () { }));
                                                }
                                            });


                                            $scope.isLoading = true;
                                            Promise.all(pickerPromises).then(function () {
                                                // $scope.setTimeBetweenAttractionsOrder();
                                                // $scope.isLoading = false;
                                                setTimeout(function () {
                                                    $scope.isLoading = false;
                                                    $scope.$apply();
                                                });
                                            });
                                            ///
                                        } else
                                            if ((pck.Components || "").length && pck.Components[pckCompIndex]) {
                                                $scope.isLoading = true;
                                                $scope.changeAttractionTimes(pck.Components[pckCompIndex], strDate, function () {
                                                    $scope.isLoading = false;
                                                });
                                            }
                                    }
                                }
                                else if ($(this).attr("data-isTransport")) {
                                    var compID = $(this).attr("data-compId");
                                    var comp = _.find($scope.booking.components, function (c) {
                                        return c.id == compID;
                                    });
                                    if (!comp) return;
                                    //test test
                                    if ($scope.utils.isTransportation(comp.productCategory)) {
                                        var requestParams = {
                                            urlPrefix: webUrl,
                                            token: jwtService.getPrincipalToken(),
                                            date: strDate,
                                            code: comp.productCode
                                        };
                                        $scope.isLoading = true;
                                        var transportCallBack = undefined;
                                        var returnProduct = comp.isDepartureProduct && comp.returnProduct;
                                        if (returnProduct && !returnProduct.isDisabled) {
                                            var returnDatePicker = jQuery($element).find("#daterange" + returnProduct.id);
                                            var returnDate = undefined;
                                            if (returnDatePicker) {
                                                returnDate = moment(returnDatePicker.val(), shoppingCartService.getDateFormat());
                                            }
                                            var depDate = moment(strDate);
                                            returnDatePicker.data().daterangepicker.minDate = depDate;
                                            if (depDate > returnDate) {
                                                returnDatePicker.val(depDate.format(shoppingCartService.getDateFormat()));
                                                returnDatePicker.data().daterangepicker.startDate = depDate;
                                                returnDatePicker.data().daterangepicker.endDate = depDate;

                                                transportCallBack = function (product) {
                                                    product = product ? JSON.parse(JSON.stringify(product)) : undefined;

                                                    _.each(product.units, function (un) {
                                                        var repr = returnProduct.details && _.find(returnProduct.details.units, function (cUn) { return cUn.unitCode == un.unitCode; });
                                                        if (!repr) {
                                                            return;
                                                        }
                                                        un.busStops = repr.busStops;
                                                    });

                                                    if (returnProduct.filter && returnProduct.filter.selectedUnit) {
                                                        var oldPickUp = returnProduct.filter.selectedUnit.selectedPickUp;
                                                        var oldDropOff = returnProduct.filter.selectedUnit.selectedDropOff;

                                                        returnProduct.filter.selectedUnit = _.find(product.units, function (un) {
                                                            return un.unitCode == returnProduct.filter.selectedUnit.unitCode;
                                                        });

                                                        if (returnProduct.filter.selectedUnit) {
                                                            returnProduct.filter.selectedUnit.selectedPickUp = oldPickUp;
                                                            returnProduct.filter.selectedUnit.selectedDropOff = oldDropOff;
                                                        }
                                                    }
                                                    returnProduct.details = product;
                                                    $scope.isLoading = false;
                                                    $scope.transportUnitChanged(returnProduct);
                                                    $scope.filterTransportationUnits(returnProduct);
                                                };

                                            }
                                        }
                                        transportationService.getTransportationProduct(requestParams, function (dataResult) {
                                            if (!dataResult || !dataResult.data || !(dataResult.data.products || "").length) {

                                                $scope.isLoading = false;
                                                return;
                                            }

                                            //  comp.details = dataResult.data.products[0];
                                            //copy bus stops from old units
                                            //TODO://busstops not applying to units, only to filter.selectedUnit - investigate!
                                            _.each(dataResult.data.products[0].units, function (un) {
                                                var repr = comp.details && _.find(comp.details.units, function (cUn) { return cUn.unitCode == un.unitCode; });
                                                if (!repr) {
                                                    return;
                                                }
                                                un.busStops = repr.busStops;
                                            });

                                            if (comp.filter && comp.filter.selectedUnit) {
                                                var oldPickUp = comp.filter.selectedUnit.selectedPickUp;
                                                var oldDropOff = comp.filter.selectedUnit.selectedDropOff;

                                                comp.filter.selectedUnit = _.find(dataResult.data.products[0].units, function (un) {
                                                    return un.unitCode == comp.filter.selectedUnit.unitCode;
                                                });

                                                if (comp.filter.selectedUnit) {
                                                    comp.filter.selectedUnit.selectedPickUp = oldPickUp;
                                                    comp.filter.selectedUnit.selectedDropOff = oldDropOff;
                                                }
                                            }
                                            comp.details = dataResult.data.products[0];

                                            $scope.transportUnitChanged(comp);
                                            $scope.filterTransportationUnits(comp);
                                            if (transportCallBack) {
                                                transportCallBack(dataResult.data.products[0]);
                                            }
                                            else
                                                $scope.isLoading = false;
                                            //

                                        });
                                    } else {
                                        //is Tour
                                        $scope.isLoading = true;
                                        var token = jwtService.getPrincipalToken();
                                        var travelDate = strDate;
                                        var productCode = comp.productCode;
                                        var productCategory = comp.productCategory;
                                        productsFactory.getProduct(token, productCode, productCategory, travelDate).then(
                                            function (dataResult) {
                                                if (!dataResult.data.products || dataResult.data.products.length === 0) {
                                                    $scope.isLoading = false;
                                                    return;
                                                }

                                                //  comp.details = dataResult.data.products[0];
                                                //copy bus stops from old units
                                                //TODO://busstops not applying to units, only to filter.selectedUnit - investigate!

                                                _.each(dataResult.data.products[0].units, function (un) {
                                                    var repr = comp.details && _.find(comp.details.units, function (cUn) { return cUn.unitCode == un.unitCode; });
                                                    if (!repr) {
                                                        return;
                                                    }
                                                    un.busStops = repr.busStops;
                                                });

                                                if (comp.filter && comp.filter.selectedUnit) {
                                                    var oldPickUp = comp.filter.selectedUnit.selectedPickUp;
                                                    var oldDropOff = comp.filter.selectedUnit.selectedDropOff;

                                                    comp.filter.selectedUnit = _.find(dataResult.data.products[0].units, function (un) {
                                                        return un.unitCode == comp.filter.selectedUnit.unitCode;
                                                    });

                                                    if (comp.filter.selectedUnit) {
                                                        comp.filter.selectedUnit.selectedPickUp = oldPickUp;
                                                        comp.filter.selectedUnit.selectedDropOff = oldDropOff;
                                                    }
                                                }
                                                comp.details = dataResult.data.products[0];

                                                console.log("set the date for the required products here");
                                                if (comp.details) {
                                                    _.each(comp.requiredComps, function (reqComp) {
                                                        reqComp.startDate = comp.details.startDate;
                                                        reqComp.endDate = comp.details.endDate;
                                                    });
                                                }
                                                $scope.isLoading = false;
                                            },
                                            function (response) {
                                                console.log(response);
                                                $scope.isLoading = false;
                                            }
                                        );
                                    }
                                    //date changed for transportation component
                                }
                                else {
                                    var compID = $(this).attr("data-compId");
                                    var comp = _.find($scope.booking.components, function (c) {
                                        return c.id == compID;
                                    });
                                    if (!comp) return;
                                    $scope.isLoading = true;
                                    var token = jwtService.getPrincipalToken();
                                    var travelDate = strDate;
                                    var productCode = comp.productCode;
                                    var productCategory = comp.productCategory;
                                    productsFactory.getProduct(token, productCode, productCategory, travelDate).then(
                                        function (dataResult) {
                                            if ((dataResult.data.products || "").length >= 0) {
                                                comp.details = dataResult.data.products[0];
                                            } else comp.details = { disabled: true };

                                            if (comp.filter && comp.filter.selectedUnit) {
                                                comp.filter.selectedUnit = _.find(comp.details.units, function (un) {
                                                    return un.unitCode == comp.filter.selectedUnit.unitCode;
                                                });
                                            }

                                            console.log("set the date for the required products here");
                                            if (comp && comp.details && comp.requiredComps) {
                                                _.each(comp.requiredComps, function (reqComp) {
                                                    reqComp.startDate = comp.details.startDate;
                                                    reqComp.endDate = comp.details.endDate;
                                                });
                                            }

                                            //$scope.isLoading = true;
                                            $scope.changeAttractionTimes(comp, strDate, function () {
                                                $scope.isLoading = false;
                                            });
                                        }, function (error) {
                                            $scope.isLoading = false;
                                            console.log("Error getting the product: ", error);
                                        });
                                    return; //
                                    //var upTimeProduct = comp.relatedProducts && comp.relatedProducts.upTimeProduct;
                                    //if (upTimeProduct) {
                                    //    var timeStr = upTimeProduct.startDate.substring(upTimeProduct.startDate.toLowerCase().indexOf('t'));
                                    //    var selectedDate = strDate + timeStr;
                                    //    upTimeProduct.startDate = selectedDate;
                                    //    upTimeProduct.endDate = selectedDate;
                                    //    comp.startDate = selectedDate;
                                    //    comp.endDate = selectedDate;
                                    //}
                                    //var downTimeProduct = comp.relatedProducts && comp.relatedProducts.downTimeProduct;
                                    //if (downTimeProduct) {
                                    //    var timeStr = downTimeProduct.startDate.substring(downTimeProduct.startDate.toLowerCase().indexOf('t'));
                                    //    var selectedDate = strDate + timeStr;
                                    //    downTimeProduct.startDate = selectedDate;
                                    //    downTimeProduct.endDate = selectedDate;
                                    //}
                                    //$scope.changeAttractionTimes(comp, strDate, function () { });
                                }
                            };
                            if (jQuery(this).hasClass("inline-datepicker")) {
                                var thisPicker = this;
                                var $inlineDatePicker = jQuery(this).datepicker({

                                    language: 'en',
                                    // startDate: selectedDate.toDate(),
                                    minDate: pickerSettings.minDate && pickerSettings.minDate.toDate(),
                                    maxDate: pickerSettings.maxDate && pickerSettings.maxDate.toDate(),
                                    onSelect: function (formattedDate, date, inst) {
                                        if (inst.stopFirstDateChanged) {
                                            inst.stopFirstDateChanged = false;
                                        } else {
                                            dateChanged.bind(thisPicker, $inlineDatePicker, true)();
                                        }
                                    },
                                    onChangeView: function (view, month, year) {
                                        if (view == "days") {
                                            !!comp && $scope.loadCalendarPrices(comp, $inlineDatePicker, month, year);
                                        }
                                    },
                                    onChangeDecade: function (decade) {
                                    },
                                    onChangeMonth: function (month, year) {
                                        !!comp && $scope.loadCalendarPrices(comp, $inlineDatePicker, month, year);
                                    },
                                    onChangeYear: function (year) {
                                        !!comp && $scope.loadCalendarPrices(comp, $inlineDatePicker, month, year);
                                    },
                                    onRenderCell: function (date, cellType, isOtherMonthCell) {
                                        var currentDate = date.getDate();

                                        if (cellType == 'day') {
                                            var monthPriceKey = !!comp && $scope.getDynamicPricesKey(comp, date.getMonth(), date.getFullYear());
                                            if (!comp.dynamicPrices) {
                                                comp.dynamicPrices = Object.create(null);
                                            }
                                            var monthPrices = comp && comp.dynamicPrices[monthPriceKey];
                                            var dayPrice = !isOtherMonthCell && monthPrices && monthPrices[currentDate]; // don't show prices from other months
                                            var newPrice = 0;

                                            var hasPrice0 = dayPrice && dayPrice.price == 0;
                                            if (dayPrice && dayPrice.price) {
                                                newPrice = dayPrice.price;
                                            }
                                            var priceLabel = ($scope.anonymUser && $scope.anonymUser.labels
                                                && $scope.anonymUser.labels["dynamicPricingCalendarPriceLabel"]) || $scope.labelUtils.getLabel("dynamicPricing.calendarPriceLabel");
                                            return {
                                                classes: (dayPrice && dayPrice.className),
                                                html: '<div class="day-label ' + ((newPrice || hasPrice0) ? "has-price" : "") + '"><span class="date">' + currentDate + '</span><span class="from">' + priceLabel + '</span></div>' + (newPrice || hasPrice0 ? '<div class="from-price"> $' + (newPrice) + '</div>' : '')
                                            }
                                        }
                                    }
                                }).data('datepicker');
                                $inlineDatePicker.stopFirstDateChanged = true; // we already loaded the related services
                                selectedDate && $inlineDatePicker.selectDate(selectedDate.toDate()); // this will trigger date changed event
                                !!comp && !!selectedDate && $scope.loadCalendarPrices(comp, $inlineDatePicker, selectedDate.month(), selectedDate.year());
                            } else {
                                pickerSettings.startDate = selectedDate && selectedDate.toDate();

                                var dPickerObj = jQuery(this).daterangepicker(pickerSettings);


                                dPickerObj.on("apply.daterangepicker", dateChanged.bind(this, jQuery(this), false));

                                if ($scope.isSkylagoon()) {
                                    dPickerObj.trigger("apply.daterangepicker");
                                }
                            }
                        });// end

                    });
                }
            };

            $scope.submitted = false;
            $scope.bookingUpdated = false;
            $scope.hasBooking = function () {
                return $scope.booking && true;
            }

            $scope.lowerCasePackageProperty = function () {
                if (!$scope.booking || !$scope.booking.packages) return;

                _.each($scope.booking.packages, function (pck) {
                    _.each(pck.Components, function (pcomp) {
                        pcomp.isPackageComponent = true;
                        pcomp.name = pcomp.ProductName;
                        for (var key in pcomp) {
                            if (pcomp.hasOwnProperty(key) && key[0] == key[0].toUpperCase()) {
                                pcomp[key.toLowerCase()] = pcomp[key];
                            }
                        }
                    });
                });
            };

            $scope.upperCaseBookingProperty = function (booking) {
                if (!booking) return;
                //for (var key in booking) {
                //    if (booking.hasOwnProperty(key) && key[0] == key[0].toLowerCase()) {
                //        booking[key.charAt(0).toUpperCase() + key.slice(1)] = booking[key];
                //    }
                //}
                var customColNames = ["isPrimary", "isRequired", "isAttachedToParent"];

                _.each(booking.Components, function (pcomp) {
                    for (var key in pcomp) {
                        if (pcomp.hasOwnProperty(key) && key[0] == key[0].toLowerCase()) {
                            pcomp[key.charAt(0).toUpperCase() + key.slice(1)] = pcomp[key];
                            if (customColNames.indexOf(key) < 0) {
                                delete pcomp[key];
                            }
                        }
                    }
                });

                _.each(booking.Packages, function (pck) {
                    for (var key in pck) {
                        if (pck.hasOwnProperty(key) && key[0] == key[0].toLowerCase()) {
                            pck[key.charAt(0).toUpperCase() + key.slice(1)] = pck[key];
                            if (customColNames.indexOf(key) < 0) {
                                delete pck[key];
                            }
                        }
                    }

                    _.each(pck.Components, function (pcomp) {
                        //pcomp.Name = pcomp.ProductName;
                        for (var key in pcomp) {
                            if (pcomp.hasOwnProperty(key) && key[0] == key[0].toLowerCase()) {
                                pcomp[key.charAt(0).toUpperCase() + key.slice(1)] = pcomp[key];
                                if (customColNames.indexOf(key) < 0) {
                                    delete pck[key];
                                }
                            }
                        }
                    });
                });

            };

            $scope.openCancelBookingModal = function () {
                if (!($scope.booking && $scope.booking.canBeCancelledOnIBE)) return;

                $scope.cancelBookingModel = $scope.booking;
                $scope.showModal["CancelBooking"] = true;
            };

            $scope.cancelBooking = function () {
                if (!$scope.cancelBookingModel || !$scope.cancelBookingModel.bookingId || $scope.isCancelItemLoading) return;

                $scope.isCancelItemLoading = true;
                $scope.cancelBookingModel.wasCancelRequested = true;
                var requestParams = {
                    apiUrl: webUrl + "/api/booking/IBECancel",
                    token: jwtService.getPrincipalToken(),
                    bookingNumber: $scope.cancelBookingModel.bookingNumber,
                    bookingId: $scope.cancelBookingModel.bookingId,
                };
                customerService.cancelBooking(requestParams, function (result) {
                    $scope.isCancelItemLoading = false;
                    if (result && result.success) {
                        $scope.cancelBookingModel.isCanceled = true;
                    }
                });
            };

            $scope.setTimeBetweenAttractionsOrderForBookingPackages = function () {
                if (!$scope.timesBtw || !$scope.booking) return; // error!

                _.each($scope.booking.packages, function (pkg) {
                    var sortedComp = _.map(pkg.Components, function (comp, index) {

                        comp.timeRestr = undefined;
                        comp.parentRestr = undefined;

                        //var selectedDate = moment((comp.selectedDate ? comp.selectedDate : comp.StartDate), "YYYY-MM-DD");
                        //var startDate = selectedDate.format("YYYY-MM-DD");
                        var selectedDate = moment(comp.details && comp.details.startDate || comp.StartDate || comp.startDate, "YYYY-MM-DD");

                        var upTime = undefined;
                        var downTime = undefined;

                        if (comp.relatedProducts && comp.relatedProducts.upTimeProduct && comp.relatedProducts.upTimeProduct.selectedUnit && !comp.relatedProducts.upTimeProduct.selectedUnit.isDisabled) {
                            var timeStr = comp.relatedProducts.upTimeProduct.selectedUnit.startTime.substring(comp.relatedProducts.upTimeProduct.selectedUnit.startTime.toLowerCase().indexOf('t'));

                            selectedDate = moment(comp.relatedProducts.upTimeProduct.startDate, "YYYY-MM-DD");

                            upTime = moment(selectedDate.format("YYYY-MM-DD") + timeStr);
                            upTime = upTime.isValid() ? upTime.toDate().getTime() : "";
                        }
                        if (comp.relatedProducts && comp.relatedProducts.downTimeProduct && comp.relatedProducts.downTimeProduct.selectedUnit && !comp.relatedProducts.downTimeProduct.selectedUnit.isDisabled) {
                            var timeStr = comp.relatedProducts.downTimeProduct.selectedUnit.startTime.substring(comp.relatedProducts.downTimeProduct.selectedUnit.startTime.toLowerCase().indexOf('t'));
                            downTime = moment(selectedDate.format("YYYY-MM-DD") + timeStr);
                            downTime = downTime.isValid() ? downTime.toDate().getTime() : "";
                        }

                        var c = {
                            startDate: selectedDate.toDate().getTime(),
                            upTime: upTime,
                            downTime: downTime,
                            code: comp.ProductCode,
                            index: index
                        };
                        return c;
                    });

                    sortedComp = _.sortBy(sortedComp, function (scomp) {
                        return scomp.upTime || scomp.startDate;
                    });

                    _.each(sortedComp, function (scomp, sindex) {
                        var snextComp = sortedComp[sindex + 1];

                        if (snextComp && scomp.startDate == snextComp.startDate && scomp.upTime && snextComp.upTime) {
                            var firstAttr = undefined;
                            if (scomp.upTime <= snextComp.upTime) {

                                firstAttr = _.find($scope.timesBtw, function (t) {
                                    return t.firstAttractionCode === scomp.code
                                        &&
                                        t.secondAttractionCode === snextComp.code;
                                });
                                if (firstAttr && pkg.Components[snextComp.index]) {
                                    pkg.Components[snextComp.index].timeRestr = firstAttr;
                                    pkg.Components[snextComp.index].parentRestr = pkg.Components[scomp.index];
                                }
                            }
                            else {

                                firstAttr = _.find($scope.timesBtw, function (t) {
                                    return t.firstAttractionCode === snextComp.code
                                        &&
                                        t.secondAttractionCode === scomp.code;
                                });
                                if (firstAttr && pkg.Components[scomp.index]) {
                                    pkg.Components[scomp.index].timeRestr = firstAttr;
                                    pkg.Components[scomp.index].parentRestr = pkg.Components[snextComp.index];;
                                }
                            }

                        }
                    });
                });
            };

            function intervalInfoStr(diffHH, diffMM) {
                var hoursIntervalInfo = diffHH > 0 ? (diffHH + " hour" + (diffHH != 1 ? "s" : "")) : "";
                var hSplit = hoursIntervalInfo && diffMM > 0 ? " and " : "";
                var minutesIntervalInfo = diffMM > 0 ? (diffMM + " minute" + (diffMM != 1 ? "s" : "")) : "";

                return hoursIntervalInfo + hSplit + minutesIntervalInfo;
            }

            $scope.isUnitAvailable = function (unit, compOrPackage) {
                if (!unit || !compOrPackage) return true;

                var totalGuests = parseInt(compOrPackage.numberOfAdults || compOrPackage.NumberOfAdults || 0) + parseInt(compOrPackage.numberOfChildren || compOrPackage.NumberOfChildren || 0) + parseInt(compOrPackage.numberOfInfants || compOrPackage.NumberOfInfants || 0);
                return unit.availability >= totalGuests;
            };

            $scope.isUnitLimitedAvailability = function (unit, compOrPackage) {
                if (!unit || !compOrPackage) return true;

                var totalGuests = parseInt(compOrPackage.numberOfAdults || compOrPackage.NumberOfAdults || 0) + parseInt(compOrPackage.numberOfChildren || compOrPackage.NumberOfChildren || 0) + parseInt(compOrPackage.numberOfInfants || compOrPackage.NumberOfInfants || 0);
                return totalGuests > 0 && (unit.availability == totalGuests || unit.availability == (totalGuests + 1));
            };

            $scope.updateBooking = function (isValid) {
                $scope.submitted = true;
                //      debugger;
                if (!$scope.booking) {
                    return;
                }

                $scope.setTimeBetweenAttractionsOrderForBookingPackages();


                //copy the booking object, remove custom fields and update
                var allComponents = [];
                _.each($scope.booking.packages, function (pck) {
                    allComponents = allComponents.concat(pck.Components);
                });
                $scope.globalErrors = [];

                _.each(allComponents.concat($scope.booking.components), function (comp) {
                    if (!comp.isDisabled && !$scope.utils.isTransportation(comp.productCategory)) { // && !$scope.utils.isTour(comp.productCategory)
                        if (!$scope.utils.isTour(comp.productCategory)) {
                            //
                            if (!comp.isGiftTicket) {
                                if (comp.details && !comp.details.disabled) {
                                    comp.startDate = comp.details.startDate;
                                    comp.endDate = comp.details.startDate.endDate ? comp.details.endDate : comp.details.startDate;
                                }
                                else if (comp.details) return;//date was changed and the product was null
                            }
                            // 

                            if (comp.filter && comp.filter.selectedUnit) {
                                if (comp.filter.selectedUnit.isInPast) {
                                    $scope.globalErrors.push("Selected unit is unavailable" + " for \"" + comp.name + "\"");
                                }
                                comp.unitCode = comp.filter.selectedUnit.unitCode;
                                comp.unitDescription = comp.filter.selectedUnit.description;
                            }
                        }

                        if (!comp.hasPastDateSelected && !comp.hasPassed24hLimit) {
                            if (comp.relatedProducts && comp.relatedProducts.upTimeProduct && comp.relatedProducts.upTimeProduct.selectedUnit) {
                                var totalGuests = parseInt(comp.numberOfAdults || 0) + parseInt(comp.numberOfChildren || 0) +
                                    parseInt(comp.numberOfSeniors || 0) + parseInt(comp.numberOfStudents || 0) + parseInt(comp.numberOfInfants || 0);

                                var isAvailable = comp.relatedProducts.upTimeProduct.selectedUnit.availability >= (totalGuests);
                                if (!isAvailable) {
                                    $scope.globalErrors.push("<b>" + comp.relatedProducts.upTimeProduct.name + "</b>: " + utilsFactory.getLabel("activity.error.unitUnavailable").replace("{0}",
                                        comp.relatedProducts.upTimeProduct.selectedUnit.availability));
                                    return;
                                }

                                var timeProduct = comp.relatedProducts.upTimeProduct;
                                var timeUnit = comp.relatedProducts.upTimeProduct.selectedUnit;
                                if (!comp.primaryTimeComp) {

                                    comp.primaryTimeComp = {
                                        "numberOfAdults": comp.numberOfAdults,
                                        "numberOfChildren": comp.numberOfChildren,
                                        "numberOfInfants": comp.numberOfInfants,
                                        "numberOfSeniors": comp.numberOfSeniors,
                                        "numberOfStudents": comp.numberOfStudents,
                                        status: "New"
                                    };

                                    comp.primaryTimeComp.ParentCode = (comp.productCode || comp.ProductCode);
                                    comp.primaryTimeComp.isAttachedToParent = true;
                                    $scope.booking.components.push(comp.primaryTimeComp);
                                }
                                // keep the ids
                                if (!comp.primaryTimeComp.id) {
                                    comp.primaryTimeComp.id = timeProduct.code + timeUnit.unitCode;
                                }
                                comp.primaryTimeComp.productCategory = timeProduct.productCategory;
                                comp.primaryTimeComp.productType = timeProduct.productType;
                                comp.primaryTimeComp.productCode = timeProduct.code;
                                if (!comp.isGiftTicket && comp.StartDate) {
                                    // change startdate for package components
                                    // NOTE: When the guest picks a travel date/time, that date/time should be placed onto the related services only. The date changes should not be applied to the package components. It is important to scope this to attraction products in packages.
                                    if ((comp.ProductCategory || comp.productCategory) != "Attraction" && (comp.ProductCategory || comp.productCategory) != "Tour") {
                                        comp.StartDate = timeProduct.startDate;
                                        comp.EndDate = timeProduct.startDate;
                                        comp.startDate = timeProduct.startDate;
                                        comp.endDate = timeProduct.startDate;
                                    }
                                }
                                comp.primaryTimeComp.startDate = timeProduct.startDate;
                                comp.primaryTimeComp.endDate = timeProduct.startDate;
                                comp.primaryTimeComp.name = timeProduct.name;
                                comp.primaryTimeComp.description = timeProduct.description;

                                //  comp.primaryTimeComp.Status": "New";
                                comp.primaryTimeComp.unitCode = timeUnit.unitCode;
                                comp.primaryTimeComp.unitDescription = timeUnit.description;
                                comp.primaryTimeComp.pickupLocation = { "Code": "", "Name": "", "Time": "00:00:00" };
                                comp.primaryTimeComp.dropoffLocation = { "Code": "", "Name": "", "Time": "00:00:00" };
                                comp.primaryTimeComp.startingLocation = timeProduct.startingLocation;
                                comp.primaryTimeComp.destination = timeProduct.destination;
                                comp.primaryTimeComp.remarks = [];
                                comp.primaryTimeComp.isPrimary = timeProduct.isPrimary;
                            } else if (comp.relatedProducts && comp.relatedProducts.upTimeProduct && comp.relatedProducts.upTimeProduct.isRequiredRelatedProduct && !comp.relatedProducts.upTimeProduct.selectedUnit) {
                                $scope.globalErrors.push($scope.labelUtils.getLabel("general.pick-up-time-" + comp.productCode, "general.pick-time") + " for \"" + comp.name + "\"");
                            }

                            if (comp.relatedProducts && comp.relatedProducts.downTimeProduct && comp.relatedProducts.downTimeProduct.selectedUnit) {
                                var totalGuests = parseInt(comp.numberOfAdults || 0) + parseInt(comp.numberOfChildren || 0) +
                                    parseInt(comp.numberOfSeniors || 0) + parseInt(comp.numberOfStudents || 0) + parseInt(comp.numberOfInfants || 0);

                                var isAvailable = comp.relatedProducts.downTimeProduct.selectedUnit.availability >= (totalGuests);
                                if (!isAvailable) {
                                    $scope.globalErrors.push("<b>" + comp.relatedProducts.downTimeProduct.name + "</b>: " + utilsFactory.getLabel("activity.error.unitUnavailable").replace("{0}",
                                        comp.relatedProducts.downTimeProduct.selectedUnit.availability));
                                    return;
                                }

                                var timeProduct = comp.relatedProducts.downTimeProduct;
                                var timeUnit = comp.relatedProducts.downTimeProduct.selectedUnit;
                                if (!comp.secondaryTimeComp) {

                                    comp.secondaryTimeComp = {
                                        "numberOfAdults": comp.numberOfAdults,
                                        "numberOfChildren": comp.numberOfChildren,
                                        "numberOfInfants": comp.numberOfInfants,
                                        "numberOfSeniors": comp.numberOfSeniors,
                                        "numberOfStudents": comp.numberOfStudents,
                                        status: "New"
                                    };

                                    comp.secondaryTimeComp.ParentCode = (comp.productCode || comp.ProductCode);
                                    comp.secondaryTimeComp.isAttachedToParent = true;

                                    $scope.booking.components.push(comp.secondaryTimeComp);
                                }
                                // keep the ids
                                if (!comp.secondaryTimeComp.id) {
                                    comp.secondaryTimeComp.id = timeProduct.code + timeUnit.unitCode;
                                }

                                comp.secondaryTimeComp.productCategory = timeProduct.productCategory;
                                comp.secondaryTimeComp.productType = timeProduct.productType;
                                comp.secondaryTimeComp.productCode = timeProduct.code;
                                comp.secondaryTimeComp.startDate = timeProduct.startDate;
                                comp.secondaryTimeComp.endDate = timeProduct.endDate;
                                comp.secondaryTimeComp.name = timeProduct.name;
                                comp.secondaryTimeComp.description = timeProduct.description;

                                //  comp.secondaryTimeComp.Status": "New";
                                comp.secondaryTimeComp.unitCode = timeUnit.unitCode;
                                comp.secondaryTimeComp.unitDescription = timeUnit.description;
                                comp.secondaryTimeComp.pickupLocation = { "Code": "", "Name": "", "Time": "00:00:00" };
                                comp.secondaryTimeComp.dropoffLocation = { "Code": "", "Name": "", "Time": "00:00:00" };
                                comp.secondaryTimeComp.startingLocation = timeProduct.startingLocation;
                                comp.secondaryTimeComp.destination = timeProduct.destination;
                                comp.secondaryTimeComp.remarks = [];
                                comp.secondaryTimeComp.isPrimary = timeProduct.isPrimary;
                            }
                            else
                                if (comp.relatedProducts && comp.relatedProducts.downTimeProduct && comp.relatedProducts.downTimeProduct.isRequiredRelatedProduct && !comp.relatedProducts.downTimeProduct.selectedUnit) {
                                    $scope.globalErrors.push($scope.labelUtils.getLabel("general.pick-down-time") + " for \"" + comp.name + "\"");
                                }
                        }
                        // \
                    }

                    if (!comp.isDisabled && $scope.utils.isTransportation(comp.productCategory)) {

                        if (!comp.isGiftTicket && comp.details) {
                            comp.startDate = comp.details.startDate;
                            comp.endDate = comp.details.startDate;
                        }

                        if (comp.filter) {
                            if (comp.filter.selectedUnit) {
                                if (comp.filter.selectedUnit.isInPast ||
                                    (comp.filter.selectedUnit.invalidDep && comp.filter.selectedUnit.returnSameDepart)) {
                                    $scope.globalErrors.push("Selected unit is unavailable" + " for \"" + comp.name + "\"");
                                }
                                comp.unitCode = comp.filter.selectedUnit.unitCode;
                                comp.unitDescription = comp.filter.selectedUnit.description;

                                if (!comp.filter.selectedUnit.selectedPickUp && comp.filter.selectedUnit.pickupLocationRequired) {
                                    $scope.globalErrors.push("Select pickup" + " for \"" + comp.name + "\"");
                                }

                                comp.pickupLocation = comp.filter.selectedUnit.selectedPickUp;
                                comp.dropoffLocation = comp.filter.selectedUnit.selectedDropOff;
                                if (!comp.filter.selectedUnit.selectedDropOff && comp.filter.selectedUnit.dropoffLocationRequired) {
                                    $scope.globalErrors.push("Select dropoff" + " for \"" + comp.name + "\"");
                                }
                            }
                            else {
                                $scope.globalErrors.push("Select unit" + " for \"" + comp.name + "\"");
                            }
                        }
                    }

                    if (!comp.isDisabled && $scope.utils.isTour(comp.productCategory)) {

                        if (!comp.isGiftTicket && comp.details) {
                            comp.startDate = comp.details.startDate;
                            comp.endDate = comp.details.startDate.endDate ? comp.details.endDate : comp.details.startDate;
                        }

                        if (comp.filter) {
                            if (comp.filter.selectedUnit) {
                                if (comp.filter.selectedUnit.isInPast) {
                                    $scope.globalErrors.push("Selected unit is unavailable" + " for \"" + comp.name + "\"");
                                }
                                comp.unitCode = comp.filter.selectedUnit.unitCode;
                                comp.unitDescription = comp.filter.selectedUnit.description;

                                if (!comp.filter.selectedUnit.selectedPickUp && comp.filter.selectedUnit.pickupLocationRequired) {
                                    $scope.globalErrors.push("Select pickup" + " for \"" + comp.name + "\"");
                                }

                                comp.pickupLocation = comp.filter.selectedUnit.selectedPickUp;
                                comp.dropoffLocation = comp.filter.selectedUnit.selectedDropOff;
                                if (!comp.filter.selectedUnit.selectedDropOff && comp.filter.selectedUnit.dropoffLocationRequired) {
                                    $scope.globalErrors.push("Select dropoff" + " for \"" + comp.name + "\"");
                                }
                            }
                            else
                                $scope.globalErrors.push("Select unit" + " for \"" + comp.name + "\"");
                        }
                    }
                    // time restrictions
                    if (!comp.timeRestr || !comp.parentRestr) return;

                    var timeDiffStr = (comp.timeRestr.minimumTimeBetweenBookings || "").split(":");
                    if (timeDiffStr.length != 3) return;
                    var diffHH = parseInt(timeDiffStr[0]);
                    var diffMM = parseInt(timeDiffStr[1]);
                    var diffSS = parseInt(timeDiffStr[3]);

                    var firstTimeVal = undefined;
                    var secondTimeVal = undefined;

                    //var selectedDate = moment(comp.details && comp.details.startDate || comp.StartDate || comp.startDate, "YYYY-MM-DD"); //moment((comp.selectedDate ? comp.selectedDate : comp.product.startDate), "YYYY-MM-DD");
                    //var startDate = selectedDate.format("YYYY-MM-DD");

                    var timeProduct = comp.relatedProducts && comp.relatedProducts.upTimeProduct;
                    if (timeProduct && timeProduct.selectedUnit && !timeProduct.selectedUnit.isDisabled) {
                        var selectedDate = moment(timeProduct.startDate, "YYYY-MM-DD");
                        var startDate = selectedDate.format("YYYY-MM-DD");

                        var timeStr = timeProduct.selectedUnit.startTime.substring(timeProduct.selectedUnit.startTime.toLowerCase().indexOf('t'));
                        secondTimeVal = moment(startDate + timeStr);
                    }
                    if (!secondTimeVal || !secondTimeVal.isValid()) return;


                    //selectedDate = moment(comp.parentRestr.details && comp.parentRestr.details.startDate || comp.parentRestr.StartDate || comp.parentRestr.startDate, "YYYY-MM-DD"); //moment((comp.parentRestr.selectedDate ? comp.parentRestr.selectedDate : comp.parentRestr.product.startDate), "YYYY-MM-DD");
                    //startDate = selectedDate.format("YYYY-MM-DD");

                    timeProduct = comp.parentRestr.relatedProducts && (comp.parentRestr.relatedProducts.downTimeProduct || comp.parentRestr.relatedProducts.upTimeProduct);

                    if (timeProduct && timeProduct.selectedUnit && !timeProduct.selectedUnit.isDisabled) {
                        var timeStr = timeProduct.selectedUnit.startTime.substring(timeProduct.selectedUnit.startTime.toLowerCase().indexOf('t'));

                        var selectedDate = moment(timeProduct.startDate, "YYYY-MM-DD");
                        var startDate = selectedDate.format("YYYY-MM-DD");

                        firstTimeVal = moment(startDate + timeStr);
                    }

                    if (!firstTimeVal || !firstTimeVal.isValid()) return;
                    firstTimeVal.add(diffHH, "h");
                    firstTimeVal.add(diffMM, "m");
                    firstTimeVal.add(diffSS, "s");

                    if (firstTimeVal.isAfter(secondTimeVal)) {
                        var minimumTimeInfo = intervalInfoStr(diffHH, diffMM);
                        var recommendedTimeInfo = "";
                        var timeDiffStr = (comp.timeRestr.recommendedTimeBetweenBookings || "").split(":");
                        if (timeDiffStr.length == 3) {
                            ;
                            var diffHH = parseInt(timeDiffStr[0]);
                            var diffMM = parseInt(timeDiffStr[1]);
                            var diffSS = parseInt(timeDiffStr[3]);
                            var recommendedTimeInfo = intervalInfoStr(diffHH, diffMM);
                            recommendedTimeInfo = recommendedTimeInfo ? " The recommended time between them is " + recommendedTimeInfo : "";
                        }
                        $scope.globalErrors.push("The minimum time between <b>" + comp.timeRestr.firstAttractionName + "</b> and <b>" +
                            comp.timeRestr.secondAttractionName + "</b> is " + minimumTimeInfo + "." + recommendedTimeInfo);
                    }
                    // restriction
                });
                //if (($scope.model.confirmEmail || "").length < 3) {
                //    $scope.globalErrors.push("Enter a valid email address.");
                //}
                if ($scope.globalErrors.length) {
                    $scope.showModal["SubmitErrors"] = true;
                    return;
                }
                if (!isValid) return;

                // process the booking
                $scope.booking.packages && _.each($scope.booking.packages, function (pck) {

                    /* when guests modify their date for Packages with type="ATTRACTION",
                       * the date of the time product and package product need to match. 
                       * While fixing this issue, it is important that the functionality surrounding combo modifications remains unchanged. 
                       * Since combo passes are valid for 1 week, changing visit dates for packages of type "COMBO" should remain the same, ie date changes only affect time products and package dates should remain unmodified.
                       */
                    // If packageType = "FBCOMBO", the date changes SHOULD be applied to the package components
                    var shouldChangePkgStartDate = pck.type == "ATTRACTION" || pck.type == "FBCOMBO";

                    var newStartDate = null;
                    //var newEndDate = null;
                    _.each(pck.Components, function (pComp) {
                        if (!pComp.isAttachedToParent) {
                            if (pComp.primaryTimeComp) {
                                newStartDate = pComp.primaryTimeComp.startDate;
                                if (shouldChangePkgStartDate && newStartDate) {
                                    pComp.StartDate = newStartDate;
                                    pComp.Startdate = newStartDate;
                                    pComp.startdate = newStartDate;
                                    pComp.EndDate = newStartDate;
                                    pComp.Enddate = newStartDate;
                                    pComp.enddate = newStartDate;
                                }
                            }
                        }
                    });

                    if (shouldChangePkgStartDate && newStartDate) {
                        pck.StartDate = newStartDate;
                        pck._changeItemDate = true;
                        //item.StartDate = newStartDate;
                        _.each(pck.Components, function (pComp) {
                            if (!pComp.isAttachedToParent && !pComp.primaryTimeComp && !pComp.secondaryTimeComp) {
                                pComp.StartDate = newStartDate;
                                pComp.Startdate = newStartDate;
                                pComp.startdate = newStartDate;
                                pComp.EndDate = newStartDate;
                                pComp.Enddate = newStartDate;
                                pComp.enddate = newStartDate;

                                if ((pComp.requiredComps || "").length) {
                                    _.each(pComp.requiredComps, function (comp) {
                                        // It will change item.BookingToQuote.Components
                                        comp.startDate = newStartDate;
                                        comp.endDate = newStartDate;
                                    });
                                }
                            }
                        });
                    }
                });
                //

                var bookingObj = JSON.parse(JSON.stringify($scope.booking));

                var cleanBooking = JSON.parse(JSON.stringify($scope.booking));// this will have upperCase properties added, used to build the shopping cart from the booking object


                // NOTE: make the changes to the $scope.booking, not only to the cleanBooking 

                var cartItems = [];
                _.each(cleanBooking.components, function (comp) {
                    // 
                    if (!comp.isAttachedToParent && !$scope.utils.isTimeComponent(comp)) {
                        comp.origPrice = comp.price;
                        var item = {
                            ProductCode: comp.productCode,
                            ProductCategory: comp.productCategory,
                            UnitCode: comp.unitCode,
                            StartDate: moment(comp.startDate).format(shoppingCartService.getDateFormat()),
                            StartTime: undefined,
                            EndDate: undefined,
                            EndTime: undefined,
                            BookingToQuote: {
                                Components: [comp],
                                Packages: []
                            },
                            relatedProductCode: undefined
                        };
                        if (comp.primaryTimeComp) {
                            item.BookingToQuote.Components.push(comp.primaryTimeComp);
                        }
                        if (comp.secondaryTimeComp) {
                            item.BookingToQuote.Components.push(comp.secondaryTimeComp);
                        }
                        if ((comp.requiredComps || "").length) {
                            _.each(comp.requiredComps, function (comp) {
                                comp.origPrice = comp.price;
                                item.BookingToQuote.Components.push(comp);
                            });
                        }
                        //

                        $scope.upperCaseBookingProperty(item.BookingToQuote);
                        cartItems.push(item);
                    }
                });
                _.each(cleanBooking.packages, function (pck) {
                    var item = {
                        ProductCode: undefined,
                        ProductCategory: undefined,
                        UnitCode: undefined,
                        StartDate: pck.StartDate,
                        StartTime: undefined,
                        EndDate: undefined,
                        EndTime: undefined,
                        BookingToQuote: {
                            Components: [],
                            Packages: [pck]
                        },
                        relatedProductCode: undefined
                    };

                    _.each(pck.Components, function (pComp) {
                        if (!pComp.isAttachedToParent) {
                            pComp.ComponentDescription = pComp.ComponentDescription || pComp.ProductDescription;

                            if (pComp.primaryTimeComp) {
                                item.BookingToQuote.Components.push(pComp.primaryTimeComp);
                            }
                            if (pComp.secondaryTimeComp) {
                                item.BookingToQuote.Components.push(pComp.secondaryTimeComp);
                            }
                            if ((pComp.requiredComps || "").length) {
                                _.each(pComp.requiredComps, function (comp) {
                                    comp.origPrice = comp.price;
                                    item.BookingToQuote.Components.push(comp);
                                });
                            }
                            //
                            //_.each(bookingObj.components, function (comp) { });                           
                        }
                    });

                    if (pck._changeItemDate && pck.StartDate) {
                        item.StartDate = pck.StartDate;
                    }

                    $scope.upperCaseBookingProperty(item.BookingToQuote);
                    cartItems.push(item);
                });

                _.each(bookingObj.components, function (comp) {
                    delete comp.primaryTimeComp;
                    delete comp.secondaryTimeComp;
                    delete comp.isAttachedToParent;
                    delete comp.relatedProducts;
                    delete comp.requiredComps;

                    delete comp.details;
                    delete comp.filter;
                    delete comp.Filter;
                    delete comp.returnProduct;
                    delete comp.isDepartureProduct;
                    delete comp.isReturnProduct;
                });
                // $scope.upperCaseBookingProperty(bookingObj);


                //data.ConfirmationEmailOverride = (!customer || $scope.canChangeConfirmationEmailAddress) ? $scope.model.emailAddress : (customer.email || $scope.model.emailAddress);
                $scope.isLoading = true;

                var requestParams = {
                    apiUrl: $scope.$parent.getWebUrl(),
                    token: jwtService.getPrincipalToken(),
                    items: cartItems,
                    booking: bookingObj,
                    updateBookingUrl: (window.location.pathname + window.location.search)
                };

                shoppingCartService.updateNewCart(requestParams, function (result, error) {
                    if (result) {
                        var generalCtrl = $scope.$parent;
                        window.location = utilsFactory.addPersistentQueryStringsParams((generalCtrl.selectedGeographyCode ? "/" + generalCtrl.selectedGeographyCode : "") + "/checkout");
                    } else {
                        $scope.isLoading = false;
                    }
                });

                //shoppingCartService.addComponentsToCart(requestParams, function (result, error) {

                //    if (result) {
                //        var generalCtrl = $scope.$parent;
                //        window.location = (generalCtrl.selectedGeographyCode ? "/" + generalCtrl.selectedGeographyCode : "") + "/checkout";
                //    } else {
                //        $scope.isLoading = false;
                //    }
                //});

                //var requestParams = {
                //    apiUrl: ($("body").data("weburl") ? $("body").data("weburl") : "") + "/api/booking/update/",
                //    token: jwtService.getPrincipalToken(),
                //    bookingToPost: data
                //}
                //$scope.errors = [];

                //shoppingCartService.createBooking(requestParams, function (result) {
                //    if (!result || (result.errors || "").length) {
                //        $scope.errors = result && (result.errors || "").length ? result.errors : [{
                //            "errorMessage": "An error occurred."
                //        }];
                //    }
                //    else
                //        if (result.bookings) {
                //            $scope.showModal["UpdateSuccess"] = true;
                //            $scope.bookingUpdated = true;

                //        }

                //    $scope.isLoading = false;
                //});
            };

            $scope.loadTransportDetailsRecursive = function (comps, index, callback) {
                if (!comps || !comps[index]) {
                    var allDepTransports = _.filter(comps, function (comp) {
                        return comp.isDepartureProduct;
                    });
                    _.each(allDepTransports, function (comp) {
                        $scope.filterTransportationUnits(comp);
                    });

                    callback();
                    return;
                }

                if (!$scope.utils.isTransportation(comps[index].productCategory)) {

                    var token = jwtService.getPrincipalToken();
                    var travelDate = moment(comps[index].startDate).format("YYYY-MM-DD");
                    var productCode = comps[index].productCode || comps[index].ProductCode;
                    var productCategory = comps[index].productCategory || comps[index].ProductCategory;
                    productsFactory.getProduct(token, productCode, productCategory, travelDate).then(
                        function (result) {

                            if (!result.data.products || result.data.products.length === 0) {
                                $scope.loadTransportDetailsRecursive(comps, index + 1, callback);
                                return;
                            }

                            comps[index].details = result.data.products[0];
                            //if($scope.utils.isTour(comps[index].productCategory)
                            var currentUnitCode = (comps[index].unitCode || comps[index].UnitCode);
                            comps[index].filter = {
                                selectedUnit: _.find(comps[index].details.units,
                                    function (un) {
                                        return un.unitCode == currentUnitCode;
                                    })
                            };
                            // }
                            $scope.loadTransportDetailsRecursive(comps, index + 1, callback);
                        },
                        function (response) {
                            console.log(response);
                            $scope.loadTransportDetailsRecursive(comps, index + 1, callback);
                        }
                    );
                } else {
                    var requestParams = {
                        urlPrefix: webUrl,
                        token: jwtService.getPrincipalToken(),
                        date: moment(comps[index].startDate).format("YYYY-MM-DD"),
                        code: comps[index].productCode
                    };
                    transportationService.getTransportationProduct(requestParams, function (dataResult) {
                        if (!dataResult || !dataResult.data || !(dataResult.data.products || "").length) {
                            $scope.loadTransportDetailsRecursive(comps, index + 1, callback);
                            return;
                        }

                        comps[index].details = dataResult.data.products[0];


                        comps[index].filter = {
                            selectedUnit: _.find(comps[index].details.units,
                                function (un) {
                                    return un.unitCode == comps[index].unitCode;
                                })
                        };

                        $scope.loadTransportDetailsRecursive(comps, index + 1, callback);
                    });
                }

            };

            $scope.initTransportationDetails = function ($booking, callback) {
                if (!$booking || !($booking.components || "").length) {
                    callback();
                    return;
                }
                //var packageComponents = [];
                //_.each($booking.packages, function (pck) {
                //    _.each(pck.Components, function (pComp) {
                //        pComp.isPackageComponent = true;
                //        pComp.startDate = pck.StartDate;
                //        packageComponents.push(pComp);
                //    });
                //});

                //var allComponents = $booking.components.concat(packageComponents);
                //var transportComp = _.filter(allComponents, function (comp) {
                //    return !comp.isAttachedToParent && ($scope.utils.isAttraction(comp.productCategory || comp.ProductCategory) || $scope.utils.isTransportation(comp.productCategory)
                //            || $scope.utils.isTour(comp.productCategory));
                //});

                var transportComp = _.filter($booking.components, function (comp) {
                    return $scope.utils.isTransportation(comp.productCategory)
                        || $scope.utils.isTour(comp.productCategory);
                });
                $scope.loadTransportDetailsRecursive(transportComp, 0, callback);
            };


            $scope.getProductBusStops = function (comp, unitCode, callback) {
                var requestParams = {
                    urlPrefix: webUrl,
                    token: jwtService.getPrincipalToken(),
                    productCode: comp.productCode,
                    unitCode: unitCode
                };
                if (!$scope.utils.isTransportation(comp.productCategory) && !$scope.utils.isTour(comp.productCategory)) {
                    callback();
                    return;
                }


                transportationService.getBusStops(requestParams, function (dateResult) {
                    if (comp.details && comp.filter && comp.filter.selectedUnit) {
                        //reassign object reference - bug: for some reason comp.filter.selectedUnit is not a reference to one of comp.details.units
                        comp.filter.selectedUnit = _.find(comp.details.units, function (un) { return un.unitCode == comp.filter.selectedUnit.unitCode; });

                        comp.filter.selectedUnit.busStops = dateResult.data;

                        if (unitCode == comp.unitCode && !comp.filter.selectedUnit.selectedPickUp) {
                            if (comp.pickupLocation && (comp.filter.selectedUnit.busStops.pickups || "").length) {
                                comp.filter.selectedUnit.selectedPickUp = _.find(comp.filter.selectedUnit.busStops.pickups, function (bs) {
                                    return bs.code === comp.pickupLocation.code;
                                });
                            }
                        }
                        else if (comp.filter.selectedUnit.selectedPickUp) {
                            if ((comp.filter.selectedUnit.busStops.pickups || "").length) {
                                //refresh reference to other bus stop with same code
                                comp.filter.selectedUnit.selectedPickUp = _.find(comp.filter.selectedUnit.busStops.pickups, function (bs) {
                                    return bs.code === comp.filter.selectedUnit.selectedPickUp.code;
                                });
                            } else {
                                comp.filter.selectedUnit.selectedPickUp = undefined;
                            }
                        }

                        if (unitCode == comp.unitCode && !comp.filter.selectedUnit.selectedDropOff) {
                            if (comp.dropoffLocation && (comp.filter.selectedUnit.busStops.dropoffs || "").length) {
                                comp.filter.selectedUnit.selectedDropOff = _.find(comp.filter.selectedUnit.busStops.dropoffs, function (df) {
                                    return df.code === comp.dropoffLocation.code;
                                });
                            }
                        }
                        else if (comp.filter.selectedUnit.selectedDropOff) {
                            if ((comp.filter.selectedUnit.busStops.dropoffs || "").length) {
                                //refresh reference to other bus stop with same code
                                comp.filter.selectedUnit.selectedDropOff = _.find(comp.filter.selectedUnit.busStops.dropoffs, function (bs) {
                                    return bs.code === comp.filter.selectedUnit.selectedDropOff.code;
                                });
                            } else {
                                comp.filter.selectedUnit.selectedDropOff = undefined;
                            }
                        }
                    }
                    callback();
                });
            };

            $scope.initDefaultBusStops = function ($booking, compIndex, callback) {
                if (!$booking || !($booking.components || "").length || !$booking.components[compIndex]) {
                    callback();
                    return;
                }

                $scope.getProductBusStops($booking.components[compIndex], $booking.components[compIndex].unitCode, function () {
                    $scope.initDefaultBusStops($booking, compIndex + 1, callback);
                });
            };

            $scope.filterTransportationUnits = function (comp) {
                if (!$scope.utils.isTransportation(comp.productCategory) || !comp.details) { return; }

                var isCurrDate = moment(comp.details.startDate).isSame(jwtService.getServerMomentDate());
                var tc = jwtService.getServerMomentDate(true);
                var currHourLimit = moment(tc.format("hh:mm A"), "hh:mm A");
                tc.add(2, "h");
                var twoHourLimit = moment(tc.format("hh:mm A"), "hh:mm A");

                var returnProduct = comp.isDepartureProduct && comp.returnProduct;
                var parentProduct = undefined;

                var returnSameDepart = false;
                if (returnProduct) {
                    var returnProductDate = moment(returnProduct.details ? returnProduct.details.startDate : returnProduct.startDate, "YYYY-MM-DD");
                    var currCompDate = moment(comp.details ? comp.details.startDate : comp.startDate, "YYYY-MM-DD");
                    returnSameDepart = returnProductDate.isSame(currCompDate);
                } else
                    if (!comp.isDepartureProduct) {
                        parentProduct = _.find($scope.booking.components, function (parent) {
                            return parent.returnProduct == comp;
                        });

                        if (parentProduct) {
                            var returnProductDate = moment(comp.details.startDate, "YYYY-MM-DD");
                            var currCompDate = moment(parentProduct.details.startDate, "YYYY-MM-DD");
                            returnSameDepart = returnProductDate.isSame(currCompDate);
                        }

                    }

                // returnSameDepart)
                var departStartDate = undefined;
                if (returnProduct) {
                    if (comp.filter && comp.filter.selectedUnit) { //returnSameDepart
                        var currDepartureUnit = comp.filter.selectedUnit;
                        var timeStr = moment(currDepartureUnit.startTime).format("hh:mm A");
                        departStartDate = moment(timeStr, "hh:mm A");
                    }
                } else
                    if (!comp.isDepartureProduct && parentProduct) {
                        if (parentProduct.filter && parentProduct.filter.selectedUnit) { //returnSameDepart
                            var currDepartureUnit = parentProduct.filter.selectedUnit;
                            var timeStr = moment(currDepartureUnit.startTime).format("hh:mm A");
                            departStartDate = moment(timeStr, "hh:mm A");
                        }
                    }

                _.each(comp.details.units, function (un) {
                    var timeStr = moment(un.startTime).format("hh:mm A");
                    var timeVal = moment(timeStr, "hh:mm A");
                    if (isCurrDate) {
                        un.isInPast = timeVal <= currHourLimit;
                        un.isTimeRestricted = timeVal > currHourLimit && timeVal <= twoHourLimit;
                    }
                });

                if (returnProduct && returnProduct.details && departStartDate) {
                    _.each(returnProduct.details.units, function (un) {
                        var timeStr = moment(un.startTime).format("hh:mm A");
                        var timeVal = moment(timeStr, "hh:mm A");

                        un.invalidDep = timeVal <= departStartDate ? true : false;
                        un.returnSameDepart = returnSameDepart;
                    });
                }
                else if (!comp.isDepartureProduct && parentProduct) {
                    _.each(comp.details.units, function (un) {
                        var timeStr = moment(un.startTime).format("hh:mm A");
                        var timeVal = moment(timeStr, "hh:mm A");

                        un.invalidDep = timeVal <= departStartDate ? true : false;
                        un.returnSameDepart = returnSameDepart;
                    });
                }

            };

            $scope.editPackageComponent = function (cItem) {
                if (!cItem) return;
                // reset other package components
                _.each($scope.booking && $scope.booking.packages, function (p) {
                    _.each(p.Components, function (comp) {
                        comp.collapsed = false;
                    });
                });

                cItem.collapsed = true;
            };

            $scope.canModifyPackageComponent = function (cItem) {
                if (!cItem || !cItem.relatedProducts || !cItem.relatedProducts.upTimeProduct || !cItem.relatedProducts.upTimeProduct.selectedUnit) return false;
                if (cItem.relatedProducts.downTimeProduct && !cItem.relatedProducts.downTimeProduct.selectedUnit) return false;


                // check if new selected values are not equal with the orignals
                if (cItem.originalRelatedProducts && cItem.originalRelatedProducts.upTimeProduct && cItem.originalRelatedProducts.upTimeProduct.selectedUnit
                    && cItem.relatedProducts.upTimeProduct.startDate == cItem.originalRelatedProducts.upTimeProduct.startDate
                    && cItem.relatedProducts.upTimeProduct.selectedUnit.startTime == cItem.originalRelatedProducts.upTimeProduct.selectedUnit.startTime
                ) {
                    if (!cItem.relatedProducts.downTimeProduct || !cItem.relatedProducts.downTimeProduct.selectedUnit) {
                        return false;
                    }
                    if (!cItem.originalRelatedProducts.downTimeProduct || !cItem.relatedProducts.downTimeProduct.selectedUnit) {
                        return true;
                    }

                    return (cItem.relatedProducts.downTimeProduct.selectedUnit.startTime != cItem.originalRelatedProducts.downTimeProduct.selectedUnit.startTime);
                }

                return true;
            };

            $scope.confirmPackageComponentChanges = function (cItem, pck) {
                cItem.collapsed = false;
                cItem.relatedProducts.wasChanged = true;

                if (pck.TourTimesCanBeOnDifferentDates === false) {
                    pck.Components && _.each(pck.Components, function (otherComp) {
                        otherComp.relatedProducts.wasChanged = true;
                    });
                }
            };

            $scope.revertPackageComponentChanges = function (cItem, pck) {
                cItem.collapsed = false;
                cItem.relatedProducts = cItem.originalRelatedProducts && JSON.parse(JSON.stringify(cItem.originalRelatedProducts));

                if (pck.TourTimesCanBeOnDifferentDates === false) {
                    pck.Components && _.each(pck.Components, function (otherComp) {
                        otherComp.relatedProducts = otherComp.originalRelatedProducts && JSON.parse(JSON.stringify(otherComp.originalRelatedProducts));
                    });
                }
            };

            $scope.getBookingDetails = function () {
                if (!$scope.bookingNumber) {
                    $scope.isLoading = false;
                    return;
                }

                var currServerDate = jwtService.getServerMomentDate();

                var requestParams = {
                    apiUrl: webUrl + ($scope.isCustomer && !isNaN($scope.bookingNumber) ? "/api/booking/customerbooking" : "/api/booking/booking"),
                    token: $scope.isCustomer ? jwtService.getCustomerToken() : jwtService.getPrincipalToken(),
                    bookingNumber: $scope.bookingNumber
                };

                $scope.isLoading = true;
                customerService.customerBooking(requestParams, function (result) {
                    var tempBooking = (result && result.data && result.data.bookings && result.data.bookings.length >= 1) ?
                        result.data.bookings[0] : ((result && result.error && (result.error.bookings || "").length >= 1) ? result.error.bookings[0] : undefined);

                    //
                    // TODO: remove
                    // DEBUG
                    //if (tempBooking) {
                    //    tempBooking.canBeModifiedOnIBE = true;
                    //    _.each(tempBooking.components, function (bcomp) {
                    //        bcomp.startDate = "2025-04-05T00:00:00";
                    //        bcomp.endDate = "2025-04-05T00:00:00";
                    //    });

                    //    _.each(tempBooking.packages, function (pack) {
                    //        pack.StartDate = "2025-04-05T00:00:00";
                    //        _.each(pack.Components, function (pcomp) {
                    //            pcomp.StartDate = "2025-04-05T00:00:00";
                    //            pcomp.EndDate = "2025-04-05T00:00:00";
                    //        });
                    //    });
                    //}
                    //

                    if (tempBooking) {
                        //
                        var productQueries = [];

                        var prevTransp = undefined;
                        var currServerDate = jwtService.getServerMomentDate();
                        var currServerDateTime = jwtService.getServerMomentDate(true);

                        _.each(tempBooking.components, function (bcomp) {
                            var compDateWithoutTime = getDateWithoutTime(bcomp.startDate);

                            bcomp.isDisabled = !bcomp.canModifyServiceOnIBE || !bcomp.isGiftTicket && (!tempBooking.canBeModifiedOnIBE ||
                                (tempBooking.canEditOnIBEDayOf ? (moment(compDateWithoutTime).isBefore(currServerDate))
                                    : (moment(compDateWithoutTime).isSameOrBefore(currServerDate))));

                            if ($scope.utils.isTransportation(bcomp.productCategory)) {
                                if (prevTransp && prevTransp.startingLocation && prevTransp.destination
                                    && bcomp.startingLocation && bcomp.destination) {
                                    if (prevTransp.startingLocation.code === bcomp.destination.code
                                        && prevTransp.destination.code === bcomp.startingLocation.code) {
                                        prevTransp.isDepartureProduct = true;
                                        prevTransp.returnProduct = bcomp;
                                        bcomp.isReturnProduct = true;
                                        //bcomp.isDisabled = prevTransp.isDisabled;
                                    }
                                } else {
                                    bcomp.isDepartureProduct = true;
                                }

                                prevTransp = bcomp;
                            }

                            if (!bcomp.unitCode || bcomp.productType == "FLT-TIME" || bcomp.productType == "FEE" || $scope.utils.isTransportation(bcomp.productCategory)) return;
                            var travelDateComp = moment(bcomp.startDate);

                            if (travelDateComp.isSameOrAfter(currServerDate, "day")) {
                                productQueries.push({
                                    ProductCode: bcomp.productCode,
                                    TravelDate: travelDateComp.format("YYYY-MM-DD"),//bcomp.startDate
                                    UnitCode: bcomp.unitCode,
                                    IncludeDeferredProducts: true
                                });
                            }
                        });

                        _.each(tempBooking.packages, function (pkg) {
                            var isComboType = (pkg.Type || pkg.type) == "COMBO";

                            var pckDateWithoutTime = getDateWithoutTime(pkg.StartDate);
                            var isPkgDisabled = !tempBooking.canBeModifiedOnIBE;
                            if (isComboType) {
                                var pckAvailabeUntilDateWithoutTime = pkg.AvailableUntil && getDateWithoutTime(pkg.AvailableUntil);
                                var pckAvailabeUntilDateWithoutTimeObj = moment(pckAvailabeUntilDateWithoutTime);

                                if (pckAvailabeUntilDateWithoutTimeObj.isValid()) {
                                    isPkgDisabled = isPkgDisabled
                                        || (tempBooking.canEditOnIBEDayOf ? (pckAvailabeUntilDateWithoutTimeObj.isBefore(currServerDate))
                                            : (pckAvailabeUntilDateWithoutTimeObj.isSameOrBefore(currServerDate)));
                                }

                            } else {
                                isPkgDisabled = isPkgDisabled
                                    || (tempBooking.canEditOnIBEDayOf ? (moment(pckDateWithoutTime).isBefore(currServerDate))
                                        : (moment(pckDateWithoutTime).isSameOrBefore(currServerDate)));
                            }



                            _.each(pkg.Components, function (pkgComp) {
                                pkgComp.isDisabled = isPkgDisabled;
                                //if ($scope.utils.isTransportation(pkgComp.productCategory)) return;
                                var compTravelDate = moment(pkgComp.StartDate || pkg.StartDate);

                                pkgComp.isComboType = isComboType;
                                if (isComboType && compTravelDate.isBefore(currServerDate, 'day')) {
                                    compTravelDate = currServerDate;
                                    pkgComp.hasPastDate = true;
                                }

                                productQueries.push({
                                    ProductCode: pkgComp.ProductCode,
                                    TravelDate: compTravelDate.format("YYYY-MM-DD"),//pkgComp.startDate
                                    UnitCode: pkgComp.UnitCode,
                                    IncludeDeferredProducts: true,
                                    WasDateChanged: pkgComp.hasPastDate,
                                    IsComboType: isComboType
                                });
                            });
                        });

                        if (!productQueries.length) {
                            $scope.booking = tempBooking;
                            setCheckIfBookingCanBeCancelledMessage();
                            setIsPursuitPassFlowCheck();
                            //$scope.setTimeBetweenAttractionsOrderForBookingPackages();

                            $scope.lowerCasePackageProperty();
                            $scope.isLoading = true;
                            $scope.initTransportationDetails($scope.booking, function () {
                                $scope.initDefaultBusStops($scope.booking, 0, function () {
                                    $scope.isLoading = false;
                                    //continue flow here
                                    $scope.initDatePicker();
                                });
                            });
                            return;
                        }
                        var dataToPost = { ProductQueries: productQueries, QueryParams: $scope.getRelatedServicesParams(tempBooking) };
                        var relatedServicesRequestParams = {
                            token: jwtService.getPrincipalToken(),
                            data: dataToPost
                        };

                        // the first relatedservicesmulti call should be first used to attach time componentes to the main components,
                        // but because the startDate(mostly for packages) can be different from the existing time component we'll have to make a secondary call with the right date

                        productsFactory.getRelatedServicesMulti(relatedServicesRequestParams, function (relatedProducts) {
                            if (!relatedProducts || !relatedProducts.data || !relatedProducts.data.length) {
                                // call the final callback
                                getRelatedServicesMultiCallback(relatedProducts);
                                return;
                            }
                            var wasRelatedServicesMultiRequestChanged = false;


                            _.each(relatedProducts.data, function (relatedProduct) {
                                if (!(relatedProduct.attractionTimes || "").length) return;

                                var primaryTime = relatedProduct.attractionTimes.find(function (timeComp) { return timeComp.isPrimary; });
                                if (!primaryTime) return;

                                var productQueryItem = productQueries.find(function (qitem) {
                                    return qitem.ProductCode.toLowerCase() === relatedProduct.relatedProductCode.toLowerCase();
                                });

                                var bookingTimeComponent =
                                    _.find(tempBooking.components, function (bcomp) {
                                        return bcomp.productCode && bcomp.productCode.toLowerCase() === primaryTime.code.toLowerCase();
                                    });

                                if (productQueryItem && productQueryItem.IsComboType && bookingTimeComponent) { // && productQueryItem.WasDateChanged

                                    var timeStartDate = moment(bookingTimeComponent.startDate, "YYYY-MM-DD");
                                    var productQueryStartDate = moment(productQueryItem.TravelDate, "YYYY-MM-DD");
                                    if (productQueryStartDate.isBefore(timeStartDate, 'day')) {
                                        productQueryItem.TravelDate = timeStartDate.format("YYYY-MM-DD");
                                        wasRelatedServicesMultiRequestChanged = true;
                                    }
                                }
                            });
                            if (!wasRelatedServicesMultiRequestChanged) {
                                getRelatedServicesMultiCallback(relatedProducts);
                                return;
                            }

                            // make another request with the travel dates corrected
                            productsFactory.getRelatedServicesMulti(relatedServicesRequestParams, getRelatedServicesMultiCallback)
                        });

                        function getRelatedServicesMultiCallback(relatedProducts) {
                            $scope.isLoading = false;
                            var processedGlobalComponents = false;
                            if (!relatedProducts || !relatedProducts.data || !relatedProducts.data.length) {
                                $scope.booking = tempBooking;
                                setCheckIfBookingCanBeCancelledMessage();
                                setIsPursuitPassFlowCheck();
                                $scope.isRelatedServicesError = !relatedProducts || !relatedProducts.success;

                                //$scope.setTimeBetweenAttractionsOrderForBookingPackages();

                                $scope.lowerCasePackageProperty();
                                $scope.isLoading = true;
                                $scope.initTransportationDetails($scope.booking, function () {

                                    $scope.initDefaultBusStops($scope.booking, 0, function () {
                                        $scope.isLoading = false;
                                        //continue flow here
                                        $scope.initDatePicker();
                                    });
                                });

                                return;
                            }

                            _.each(relatedProducts.data, function (relatedProduct) {
                                //add related products for booking.components
                                var compParent = processedGlobalComponents ?
                                    undefined
                                    :
                                    _.find(tempBooking.components, function (bcomp) {
                                        return !bcomp.hasRelatedProducts
                                            && bcomp.productCode && bcomp.productCode.toLowerCase() === relatedProduct.relatedProductCode.toLowerCase();
                                    });

                                if (!compParent) {
                                    processedGlobalComponents = true;  //find only inside package components

                                    //for each package enumerate its components and attach related services
                                    _.each(tempBooking.packages, function (pkg) {
                                        if (compParent) return false;
                                        var result = _.find(pkg.Components, function (pkgComp) {
                                            return !pkgComp.hasRelatedProducts
                                                && pkgComp.ProductCode && pkgComp.ProductCode.toLowerCase() === relatedProduct.relatedProductCode.toLowerCase();
                                        });
                                        if (result) {
                                            compParent = result;
                                            return true;
                                        }
                                        return false;
                                    });
                                }

                                if (compParent) {
                                    compParent.hasRelatedProducts = true;
                                    compParent.relatedProducts = relatedProduct;


                                    if (compParent.relatedProducts) {
                                        if ((compParent.relatedProducts.attractionTimes || "").length) {

                                            if (!compParent.relatedProducts.upTimeProduct && compParent.relatedProducts.attractionTimes[0].isPrimary) {
                                                compParent.relatedProducts.upTimeProduct =
                                                    compParent.relatedProducts.attractionTimes[0];
                                            } else {
                                                compParent.relatedProducts.downTimeProduct = compParent.relatedProducts.attractionTimes[0];
                                            }

                                            if (compParent.relatedProducts.attractionTimes[1]) {
                                                if (!compParent.relatedProducts.upTimeProduct && compParent.relatedProducts.attractionTimes[1].isPrimary) {
                                                    compParent.relatedProducts.upTimeProduct = compParent.relatedProducts.attractionTimes[1];
                                                } else {
                                                    compParent.relatedProducts.downTimeProduct = compParent.relatedProducts.attractionTimes[1];
                                                }
                                            }

                                        }
                                    }
                                }
                            });

                            //attach attraction times to its parent
                            //attractionTimes
                            //tours have optional
                            var packageComponents = [];
                            _.each(tempBooking.packages, function (pck) {
                                _.each(pck.Components, function (pComp) {
                                    pComp.isPackageComponent = true;
                                    pComp.numberOfAdults = pck.NumberOfAdults;
                                    pComp.numberOfChildren = pck.NumberOfChildren;
                                    pComp.numberOfInfants = pck.NumberOfInfants;
                                    pComp.numberOfSeniors = pck.NumberOfSeniors;
                                    pComp.numberOfStudents = pck.NumberOfStudents;
                                    packageComponents.push(pComp);
                                });
                            });
                            var allComponents = tempBooking.components.concat(packageComponents);
                            _.each(allComponents, function (comp) {
                                var hasRelatedProducts = comp.relatedProducts;
                                //  var attractionTimesLen = hasRelatedProducts ? (comp.relatedProducts.attractionTimes || "").length : 0;



                                _.each(tempBooking.components, function (attachComp) {
                                    if (comp == attachComp || attachComp.isAttachedToParent) return;

                                    if (hasRelatedProducts) {
                                        //attach required product to its parent
                                        var findRequiredComp = undefined;

                                        if ((comp.relatedProducts.requiredProducts || "").length) {
                                            findRequiredComp = _.find(comp.relatedProducts.requiredProducts, function (reqProd) {
                                                if (reqProd.productCode == attachComp.productCode && reqProd.unitCode == attachComp.unitCode) {

                                                    attachComp.ParentCode = (comp.productCode || comp.ProductCode);
                                                    attachComp.isAttachedToParent = true;
                                                    attachComp.isRequired = true;
                                                    if (!(comp.requiredComps || "").length)
                                                        comp.requiredComps = [];
                                                    comp.requiredComps.push(attachComp);

                                                    return true;
                                                }
                                                return false;
                                            });
                                        }
                                        if (findRequiredComp) return;
                                        //
                                        var findTimeComp = undefined;
                                        if (comp.relatedProducts.upTimeProduct) {
                                            //primary time
                                            if (!comp.primaryTimeComp && comp.relatedProducts.upTimeProduct.code == attachComp.productCode) {
                                                // probably it's safer to just add first found component
                                                // TODO: check

                                                attachComp.ParentCode = (comp.productCode || comp.ProductCode);
                                                attachComp.isAttachedToParent = true;
                                                comp.primaryTimeComp = attachComp;

                                                //fix the date for the related products, because related services were requested with product start date 
                                                //which can be different from the flight-time date
                                                comp.relatedProducts.upTimeProduct.startDate = comp.primaryTimeComp.startDate;
                                                comp.relatedProducts.upTimeProduct.endDate = comp.primaryTimeComp.endDate ? comp.primaryTimeComp.endDate : comp.primaryTimeComp.startDate;

                                                findTimeComp = _.find(comp.relatedProducts.upTimeProduct.units, function (unit) {
                                                    if (unit.unitCode == attachComp.unitCode) {
                                                        //  unit.isSelected = true;
                                                        comp.relatedProducts.upTimeProduct.selectedUnit = unit;//create a reference

                                                        attachComp.ParentCode = (comp.productCode || comp.ProductCode);
                                                        attachComp.isAttachedToParent = true;
                                                        // if (comp.relatedProducts.upTimeProduct[0].isPrimary)
                                                        comp.primaryTimeComp = attachComp;
                                                        //  else
                                                        //   comp.secondaryTimeComp = attachComp;
                                                        return true;
                                                    }
                                                    return false;
                                                });

                                                if (comp.isComboType) {
                                                    var compTimeDate = moment(comp.primaryTimeComp.startDate, "YYYY-MM-DD");
                                                    comp.primaryTimeComp.displayDate = compTimeDate.format(shoppingCartService.getDateFormat());



                                                    if (compTimeDate.isBefore(currServerDate, 'day')) {
                                                        comp.hasPastDateSelected = true;
                                                        comp.isDisabled = true;
                                                    }
                                                    else {
                                                        var timeDelimiter = comp.primaryTimeComp.startDate.indexOf("T");
                                                        var startDateStr = timeDelimiter > 0 ? comp.primaryTimeComp.startDate.substring(0, timeDelimiter) : comp.primaryTimeComp.startDate;

                                                        var unitTime = moment(startDateStr + " " + comp.primaryTimeComp.unitDescription, "YYYY-MM-DD hh:mm A");

                                                        if (unitTime.isValid()) {
                                                            unitTime.subtract("24", "h");
                                                            comp.hasPassed24hLimit = currServerDateTime.isAfter(unitTime, "minute");
                                                        } else {
                                                            compTimeDate.subtract("1", "d");
                                                            comp.hasPassed24hLimit = currServerDate.isAfter(compTimeDate, "day");
                                                        }
                                                    }
                                                    if (comp.hasPassed24hLimit) {
                                                        comp.isDisabled = true;
                                                    }

                                                }
                                            }

                                            if (findTimeComp) {
                                                //fix the date for the related products, because related services were requested with product start date 
                                                //which can be different from the flight-time date
                                                comp.relatedProducts.upTimeProduct.startDate = comp.primaryTimeComp.startDate;
                                                comp.relatedProducts.upTimeProduct.endDate = comp.primaryTimeComp.endDate ? comp.primaryTimeComp.endDate : comp.primaryTimeComp.startDate;

                                                return; //attachComp is a time component and was attached to parent
                                            }
                                            if (!comp.secondaryTimeComp && comp.relatedProducts.downTimeProduct && comp.relatedProducts.downTimeProduct.code == attachComp.productCode) {
                                                // probably it's safer to just add first found component
                                                // TODO: check                                                
                                                attachComp.ParentCode = (comp.productCode || comp.ProductCode);
                                                attachComp.isAttachedToParent = true;
                                                comp.secondaryTimeComp = attachComp;
                                                //fix the date for the related products, because related services were requested with product start date 
                                                //which can be different from the flight-time date
                                                comp.relatedProducts.downTimeProduct.startDate = comp.secondaryTimeComp.startDate;
                                                comp.relatedProducts.downTimeProduct.endDate = comp.secondaryTimeComp.endDate ? comp.secondaryTimeComp.endDate : comp.secondaryTimeComp.startDate;
                                                //

                                                findTimeComp = _.find(comp.relatedProducts.downTimeProduct.units, function (unit) {
                                                    if (unit.unitCode == attachComp.unitCode) {
                                                        //unit.isSelected = true;
                                                        comp.relatedProducts.downTimeProduct.selectedUnit = unit;//create a reference

                                                        attachComp.ParentCode = (comp.productCode || comp.ProductCode);
                                                        attachComp.isAttachedToParent = true;
                                                        //if (comp.relatedProducts.attractionTimes[1].isPrimary)
                                                        //    comp.primaryTimeComp = attachComp;
                                                        //else
                                                        comp.secondaryTimeComp = attachComp;
                                                        return true;
                                                    }
                                                    return false;
                                                });

                                            }
                                            if (findTimeComp) {
                                                //fix the date for the related products, because related services were requested with product start date 
                                                //which can be different from the flight-time date
                                                comp.relatedProducts.downTimeProduct.startDate = comp.secondaryTimeComp.startDate;
                                                comp.relatedProducts.downTimeProduct.endDate = comp.secondaryTimeComp.endDate ? comp.secondaryTimeComp.endDate : comp.secondaryTimeComp.startDate;

                                                return; //attachComp is a time component and was attached to parent
                                            }
                                        }
                                    }
                                });


                            }); // end which components

                            _.each(allComponents, function (comp) {
                                if (comp.isAttachedToParent || !comp.relatedProducts
                                    || !comp.relatedProducts.downTimeProduct || $scope.utils.isTransportation(comp.productCategory)) {

                                    comp.originalRelatedProducts = comp.relatedProducts && JSON.parse(JSON.stringify(comp.relatedProducts));
                                    return;
                                }
                                $scope.setDownTimes(comp.relatedProducts);

                                comp.originalRelatedProducts = comp.relatedProducts && JSON.parse(JSON.stringify(comp.relatedProducts)); // the original selections
                            });
                            $scope.booking = tempBooking;
                            setCheckIfBookingCanBeCancelledMessage();
                            setIsPursuitPassFlowCheck();
                            //$scope.setTimeBetweenAttractionsOrderForBookingPackages();

                            $scope.lowerCasePackageProperty();
                            $scope.isLoading = true;
                            $scope.initTransportationDetails($scope.booking, function () {
                                //continue flow here
                                $scope.initDefaultBusStops($scope.booking, 0, function () {
                                    $scope.isLoading = false;
                                    $scope.initDatePicker();
                                });

                            });

                        };

                        //--
                    } else {
                        $scope.booking = null;
                        setCheckIfBookingCanBeCancelledMessage();
                        setIsPursuitPassFlowCheck();
                        $scope.isLoading = false;
                    }

                });

            };

            var timeoutID = undefined;
            function resizeSliderPanel() {
                window.clearTimeout(timeoutID);
                timeoutID = setTimeout(function () {
                    jQuery(window).resize();
                }, 100);
            }

            $scope.initCurrentAnonymUser = function (callback) {
                jwtService.getAnonymousUserByGeography($scope.selectedGeographyCode, function (user) {
                    $scope.anonymUser = user;
                    callback();
                });
            };

            $scope.initialized = false;
            $scope.init = function () {
                if ($scope.initialized) return;
                $scope.initialized = true;
                checkIfLogedIn();
                if ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) {
                    moment.locale($scope.selectedLanguage.languageCode);
                }

                productsFactory.getTimeBetweenAttractions({ token: jwtService.getPrincipalToken() }, function (result) {
                    $scope.timesBtw = result.data;

                    $scope.initCurrentAnonymUser($scope.getBookingDetails.bind(this));
                });


            };
            $scope.isLoading = true;

            var isGeneralCtrlReady = $scope.$parent.generalCtrlReady;
            if (isGeneralCtrlReady) {
                $scope.init();
            } else {
                $scope.$on("generalCtrlReady", function (event, args) {
                    $scope.init();
                });
            }

            //var t = jwtService.getPrincipalToken();

            //if (t && t.length > 0) {
            //    $scope.init();
            //} else {
            //    $scope.isLoading = true;
            //    $scope.$on("getPrincipalToken", function (event, args) {
            //        $scope.init();
            //    });
            //};


        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("hotelBookStayCtrl", [
        "utilsFactory", "trackingService", "$scope", "$state", "$http", "$uibModal", "productsFactory", "hotelsService", "$rootScope", "validHelper", "shoppingCartService", "jwtService", "taskFactory", "$timeout", "$element", "$filter",
        function (utilsFactory, trackingService, $scope, $state, $http, $uibModal, productsFactory, hotelsService, $rootScope, validHelper, shoppingCartService, jwtService, taskFactory, $timeout, $element, $filter) {

            //
            $scope.enable2CalendarsDateRange = true;

            $scope.utils = utilsFactory;

            $scope.getAgeRangeInfo = function (secondaryLabel) {
                if (!$scope.anonymUser) return undefined;
                var selectedLanguage = $scope.anonymUser.selectedLanguage;
                return $scope.utils.getAnonymUserLabel((selectedLanguage && selectedLanguage.userlabels) || $scope.anonymUser, "hotels_ageRangesInfo", secondaryLabel) ||
                    $scope.utils.getAnonymUserLabel((selectedLanguage && selectedLanguage.userlabels) || $scope.anonymUser, "ageRangesInfo", secondaryLabel);
            };

            var webUrl = $("body").data("weburl") ? $("body").data("weburl") : "";

            $scope.availableHotelsCountMessage = $scope.utils.getLabel("hotels.available-message");//$("body").attr("data-available-hotels-count-message") ? $("body").attr("data-available-hotels-count-message") : "";
            $scope.maxAdults = $("body").attr("data-max-hotels-available-adults") ? parseInt($("body").attr("data-max-hotels-available-adults")) : 5;
            $scope.maxChildren = $("body").attr("data-max-hotels-available-children") ? parseInt($("body").attr("data-max-hotels-available-children")) : 5;
            $scope.maxNights = $("body").attr("data-max-hotels-available-nights") ? parseInt($("body").attr("data-max-hotels-available-nights")) : 14;
            $scope.showPackageModal = $("body").attr("data-hotels-show-modal") === "1";
            var hotelSelectTicketCtrl = $scope.$parent;
            var hotelDetailsCtrl = hotelSelectTicketCtrl.$parent;
            var generalCtrl = hotelDetailsCtrl.$parent;

            $.material.init();

            $scope.requestArguments = {
                hotelId: $("div[ng-controller='hotelDetailsCtrl']").attr("data-hotel-id"),
                productCode: $("div[ng-controller='hotelDetailsCtrl']").attr("data-hotel-product-code"),
                productCategory: $("div[ng-controller='hotelDetailsCtrl']").attr("data-hotel-product-category"),
                travelDate: $("div[ng-controller='hotelDetailsCtrl']").attr("data-hotel-travel-date"),
                isDefaultDate: $("div[ng-controller='hotelDetailsCtrl']").attr("data-hotel-is-default-date"),
                adults: $("div[ng-controller='hotelDetailsCtrl']").attr("data-hotel-adults"),
                child: $("div[ng-controller='hotelDetailsCtrl']").attr("data-hotel-child"),
                nights: $("div[ng-controller='hotelDetailsCtrl']").attr("data-hotel-nights"),
                productcodeswithexpandeddescriptionbydefault: $("div[ng-controller='hotelDetailsCtrl']").attr("data-productcodeswithexpandeddescriptionbydefault"),
                //expanddescriptionbydefault: ($("div[ng-controller='hotelDetailsCtrl']").attr("data-expanddescriptionbydefault") || "").toLowerCase() == 'true',
                unitcodeswithexpandedtilesdescriptionbydefault: $("div[ng-controller='hotelDetailsCtrl']").data("unitcodeswithexpandedtilesdescriptionbydefault"),
                defaultselectedadultsbyproductcode: $("div[ng-controller='hotelDetailsCtrl']").data("defaultselectedadultsbyproductcode"),
                updateCartItemCode: $("div[ng-controller='hotelDetailsCtrl']").attr("data-hotel-updateCartItem"),
                fromwebtray: ["1", "true"].indexOf(($("div[ng-controller='hotelDetailsCtrl']").attr("data-hotel-fromwebtray") || "").toLowerCase()) >= 0,
                blockId: $("div[ng-controller='hotelDetailsCtrl']").attr("data-hotel-blockId")
            };
            $scope.hotelCheckinInventory = Object.create(null);
            $scope.hotelCheckoutInventory = Object.create(null);

            $scope.requestArguments.expanddescriptionbydefault = ($scope.requestArguments.productcodeswithexpandeddescriptionbydefault || []).indexOf($scope.requestArguments.productCode) >= 0;

            $scope.packageModalLabels = utilsFactory.getModalLabelsObs("activity.packageModals", $scope.requestArguments.productCode);

            $scope.validHelper = validHelper;

            $scope.maxLimitAvailableRooms = $("body").attr("data-max-limit-available-rooms") || 0;;

            if ($scope.maxLimitAvailableRooms) {
                $scope.maxLimitAvailableRooms = parseInt($scope.maxLimitAvailableRooms);
            }

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            $scope.shouldShowBackBtn = function () {
                return !!$scope.mainSectionId && ($scope.selectedGeographyCode || "").toUpperCase().indexOf("WTC") < 0; //
            };

            $scope.search = function () {
                //
                var datepickerData = $("#daterange").data() && $("#daterange").data().daterangepicker;

                var travelDate = datepickerData && datepickerData.startDate.format("YYYY-MM-DD");
                var travelEnd = datepickerData && datepickerData.startDate.clone().add(parseInt($scope.selectedNights), "d").format("YYYY-MM-DD");
                //               

                var trackerReq = {
                    lobTitle: $scope.lobTitle,
                    packageName: null,
                    searchDate: travelDate,
                    checkoutDate: travelEnd,
                    numberOfNights: $scope.selectedNights,
                    adults: parseInt($scope.selectedAdults),
                    children: parseInt($scope.selectedChild),
                    shoppingCart: $scope.cart,
                    anonymUser: $scope.anonymGeneralUser,
                    bookingNumber: null,
                    bookingId: null
                };
                trackingService.buildFlowTrackerObj(trackerReq);

                var date = $scope.daterangepicker.val(); // $(this).val();
                var strDate = moment(date, shoppingCartService.getHotelsDateFormat()).format("YYYY-MM-DD");
                $scope.getProduct(strDate);
            };

            // first state - show all rates
            // first state - show rate hotels when only one rate
            // second state - show rate hotels
            $scope.showStateEnum = { allRates: 1, singleRateDetails: 2, rateDetails: 3 };
            $scope.currentShowState = $scope.showStateEnum.allRates;

            $scope.initState = function (stateName, stateParams) {
                $scope.rateProduct = undefined;

                if (stateName == "select-booking-type.book-stay.rate") {

                    if (!stateParams || !stateParams.rateCode || !($scope.allRates || "").length) {
                        $state.go("select-booking-type.book-stay");
                        $scope.scrollToResults(true);
                        return false;
                    }

                    $scope.selectedRate = $scope.allRates.find(function (item) {
                        return item.id == stateParams.rateCode;
                    });

                    if (!$scope.selectedRate) {
                        $state.go("select-booking-type.book-stay");
                        $scope.scrollToResults(true);
                        return false;
                    }

                    $scope.rateProduct = $scope.selectedRate.product;
                    $scope.rateMainProduct = {
                        id: $scope.selectedRate.rateCode,
                        isRate: true,
                        name: $scope.selectedRate.title || "-",
                        description: $scope.selectedRate.description,
                        productDescriptions: {
                            mainImageUrls: [$scope.selectedRate.imageUrl],
                            descriptions: [],
                            extraImageUrls: []
                        }
                    };
                }

                switch (stateName) {
                    case "select-booking-type.book-stay":
                        if ($scope.updateItem && !$scope.updateItem.isUpdateCompSynced) {

                        }

                        if (!$scope.requestArguments.blockId && ($scope.allRates || "").length == 1 && ($scope.packages || "").length == 0) {
                            $scope.selectedRate = $scope.allRates[0];
                            $scope.rateProduct = $scope.selectedRate.product;
                            $scope.currentShowState = $scope.showStateEnum.singleRateDetails;
                        } else {
                            $scope.currentShowState = $scope.showStateEnum.allRates;
                        }

                        break;
                    case "select-booking-type.book-stay.rate":
                        if (stateParams && stateParams.rateCode) {
                            $scope.currentShowState = $scope.showStateEnum.rateDetails;
                        } else {
                            $scope.currentShowState = $scope.showStateEnum.allRates;
                        }
                        break;
                    default: break;
                }
                return true;
            };

            $scope.handleBackoverridden = function () {

                if ($scope.currentShowState == $scope.showStateEnum.rateDetails) {
                    $state.go("select-booking-type.book-stay");
                } else {
                    $scope.handleBack(); // from parent
                }
            };

            //$scope.changeMainProductTo = function (product) {
            //    $scope.mainProduct.title = product.title;
            //    $scope.mainProduct.productDescriptions.descriptions = product.productDescriptions.descriptions;

            //};


            $scope.initMainProductsByState = function () {
                switch ($scope.currentShowState) {
                    case $scope.showStateEnum.allRates:
                    case $scope.showStateEnum.singleRateDetails:
                        $scope.mainProduct = $scope.hotelMainProduct;

                        //   $scope.changeMainProductTo($scope.hotelMainProduct);
                        break;
                    case $scope.showStateEnum.rateDetails:
                        $scope.mainProduct = $scope.rateMainProduct;
                        window.Paperboy && window.Paperboy.ready(function () {
                            window.Paperboy.PriceCheck && window.Paperboy.PriceCheck.destroy();
                        });

                        $scope.showSoldOutNotice();
                        // $scope.changeMainProductTo($scope.rateMainProduct);
                        break;
                }
                setTimeout(function () {
                    $scope.$apply();
                });
                //$timeout(function () {
                //    $scope.$apply();
                //});

            };

            $scope.isLoading = true;
            // displayed main product
            $scope.mainProduct = Object.create(null);
            $scope.hotelMainProduct = null;
            $scope.rateMainProduct = null;

            $scope.selectedAdults = $scope.requestArguments.adults > 0 ? $scope.requestArguments.adults : "2";
            if (($scope.requestArguments.defaultselectedadultsbyproductcode || '').length > 0 && !($scope.requestArguments.adults > 0)) {
                var defaultSelectedAdultsStr = _.find($scope.requestArguments.defaultselectedadultsbyproductcode, function (item) {
                    var pcode = item.split(' ')[0];
                    return pcode == $scope.requestArguments.productCode;
                });
                if (defaultSelectedAdultsStr) {
                    var defaultSelectedAdults = parseInt(defaultSelectedAdultsStr.split(' ')[1]);
                    if (defaultSelectedAdults > 0) {
                        $scope.selectedAdults = String(defaultSelectedAdults);
                    }
                }
            }

            $scope.selectedChild = $scope.requestArguments.child > 0 ? $scope.requestArguments.child : "0";

            $scope.selectedRoomsNo = "1";
            $scope.selectedNights = $scope.requestArguments.nights > 0 ? $scope.requestArguments.nights : "1";

            $scope.optionalExtras = [];

            $scope.resultfilter = {
                type: null
            };

            $scope.orderByLabels = {
                "all": $scope.utils.getLabel("filters.sortBy"),
                "sortOrder": $scope.utils.getLabel("filters.sortByMostPopular"),
                "priceAsc": $scope.utils.getLabel("filters.sortByPriceASC"),
                "priceDesc": $scope.utils.getLabel("filters.sortByPriceDESC")
            };

            $scope.getOrderByLabel = function (key, reverse) {
                if (!key || key == "all") return $scope.orderByLabels["all"];
                if (key == "sortOrder") {
                    return $scope.orderByLabels[key];
                } else {
                    return $scope.orderByLabels[key + (reverse ? "Desc" : "Asc")];
                }
            };

            $scope.orderBy = {
                predicate: "all",
                reverse: false
            };

            $scope.filterBy = function (type) {
                if ($scope.resultfilter.type == type) {
                    $scope.resultfilter.type = null;
                    $scope.filterItems();
                    return;
                }
                $scope.resultfilter.type = type;
                $scope.filterItems();
            };

            $scope.order = function (predicate, reverse, preventResize) {
                $scope.orderBy.reverse = reverse;
                if (predicate != "all") {
                    $scope.orderBy.predicate = predicate;
                }
                $scope.filteredItems = $filter('orderBy')($scope.filteredItems, predicate == "all" ? "sortOrder" : $scope.orderBy.predicate, $scope.orderBy.reverse);

                if (!preventResize) {
                    setTimeout(function () {
                        jQuery(window).resize();
                    });
                }
            };

            $scope.filterItems = function () {
                $scope.filteredItems = $filter('filterAttractions')($scope.allItems, $scope.resultfilter);
                $scope.order($scope.orderBy.predicate, $scope.orderBy.reverse, true);
                setTimeout(function () {
                    jQuery(window).resize();
                });
            };

            $scope.showSoldOutNotice = function () {
                // show only if rateproduct is selected
                if (!($scope.rateProduct &&
                    ($scope.currentShowState == $scope.showStateEnum.rateDetails || $scope.currentShowState == $scope.showStateEnum.singleRateDetails))) {
                    return;
                }

                setTimeout(function () {
                    if ($scope.rateProduct && $scope.rateProduct.productDescriptions && $scope.rateProduct.productDescriptions.soldOutNotice) {
                        var showSoldOutNotice = true;
                        _.each($scope.rateProduct.units, function (unit) {
                            showSoldOutNotice = showSoldOutNotice && (unit.availability < 1);
                        });
                        if (showSoldOutNotice) {
                            generalCtrl.toggleModalWithData("SoldOutNotice", $scope.rateProduct.productDescriptions.soldOutNotice);
                        }
                    }
                });
            };

            function strRange(min, max) {
                function toString(val) {
                    return val.toString();
                }

                return _.map(_.range(min, max), toString);
            }

            var timeoutID = undefined;

            function resizeSliderPanel() {
                window.clearTimeout(timeoutID);
                timeoutID = setTimeout(function () {
                    jQuery(window).resize();
                }, 100);
            }
            function resizeOnImgLoad() {
                setTimeout(function () {
                    $($element).find("img").each(function () {
                        //check if the image is already on cache
                        if ($(this).prop("complete")) {
                            resizeSliderPanel();
                        } else {
                            /* Call the codes/function after the image is loaded */
                            $(this).on("load", function () {
                                resizeSliderPanel();
                            });
                        }
                    });
                });

            }
            $scope.availableAdults = strRange(1, $scope.maxAdults + 1);
            $scope.availableChild = strRange(0, $scope.maxChildren + 1);
            $scope.availableNights = strRange(1, $scope.maxNights + 1);

            $scope.isTileDescriptionExpandedByDefault = function (unitCode) {

                return unitCode && ($scope.requestArguments.unitcodeswithexpandedtilesdescriptionbydefault || []).indexOf(unitCode) >= 0;
            };

            $scope.scrollToResults = function (onlyMobile) {
                if (!onlyMobile || jQuery(window).width() < 760) {
                    setTimeout(function () {
                        var page = $("html, body");
                        var offSet = $scope.isLoading ? $("#loadingContainer").offset().top : $("#resultsContainer").offset().top;
                        // if is desktop and page scroll is < resultsContainer then break
                        if (jQuery(window).width() > 760 && page.scrollTop < offSet) return;
                        page.animate({ scrollTop: offSet }, 1000, function () {
                            page.off("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove");
                        });

                        page.on("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove", function () {
                            setTimeout(function () {
                                page.stop();
                            });
                        });
                    });
                }
            };

            $scope.getAvailableUnitsNumber = function () {
                var available = 0;
                if (!$scope.rateProduct || !$scope.rateProduct.units) return 0;

                _.each($scope.rateProduct.units, function (unit) {
                    available += $scope.isUnitInvalid(unit) ? 0 : 1;
                });
                return available;
            };

            $scope.isUnitInvalid = function (unit) {
                var adultsValid = $scope.selectedAdults <= unit.maxOccupancyPerUnit;
                var childValid = $scope.selectedChild <= unit.maxOccupancyPerUnit - $scope.selectedAdults + unit.maxAdditionalChildren;
                return unit.availability <= 0 || !adultsValid || !childValid;
            };

            $scope.fillFiltersDropdowns = function () {
                if (!$scope.rateProduct || !$scope.rateProduct.units) {
                    $scope.availableAdults = ["1"];
                    $scope.availableChild = ["0"];
                    $scope.selectedAdults = $scope.availableAdults[0];
                    $scope.selectedChild = $scope.availableChild[0];
                } else {
                    var maxChildUnit =
                        _.max($scope.rateProduct.units, function (unit) {
                            return unit.availability < 1 || unit.maxAdditionalChildren < 1 ? 0 : unit.maxAdditionalChildren;
                        });

                    $scope.maxUnitAdditionalChildren = maxChildUnit ? maxChildUnit.maxAdditionalChildren : 0;

                    var maxOccupUnit =
                        _.max($scope.rateProduct.units, function (unit) {
                            return unit.availability < 1 || unit.maxOccupancyPerUnit < 1 ? 0 : unit.maxOccupancyPerUnit;
                        });
                    $scope.maxUnitOccupancyPerUnit = maxOccupUnit ? maxOccupUnit.maxOccupancyPerUnit : 1;

                    $scope.availableAdults = strRange(1, ($scope.maxUnitOccupancyPerUnit + 1));
                    if ($scope.availableAdults.indexOf(($scope.selectedAdults || "").toString()) < 0) {
                        $scope.selectedAdults = $scope.availableAdults[0];
                    }

                    $scope.availableChild = strRange(0, (($scope.maxUnitOccupancyPerUnit - $scope.selectedAdults + $scope.maxUnitAdditionalChildren) + 1));
                    if ($scope.availableChild.indexOf(($scope.selectedChild || "").toString()) < 0) {
                        $scope.selectedChild = $scope.availableChild[0];
                    }
                    $scope.adultsChanged();
                    $scope.childChanged();
                }
            };

            $scope.getPerTotalPriceLabel = function () {
                if ($scope.selectedNights <= 1) return $scope.utils.getLabel("hotels.per-night");
                return $scope.utils.getLabel("hotels.per-total-nights").replace("{0}",
                    $scope.selectedNights);
            };

            $scope.loadJS = function (url, implementationCode, location) {
                //url is URL of external file, implementationCode is the code
                //to be called from the file, location is the location to 
                //insert the <script> element

                var scriptTag = document.createElement('script');
                scriptTag.src = url;

                scriptTag.onload = implementationCode;
                scriptTag.onreadystatechange = implementationCode;

                location.appendChild(scriptTag);
            };

            $scope.gotoPackageDetails = function (selectedItem) {
                var productSelectTicketCtrl = $scope.$parent;
                if (!productSelectTicketCtrl.$parent) {
                    return;
                }
                var productDetailsCtrl = productSelectTicketCtrl.$parent;
                productDetailsCtrl.setSelectedPackage(selectedItem);
                var packageDetailsParam = {
                    packageCode: selectedItem.code,
                    date: moment($("#daterange").val(), shoppingCartService.getHotelsDateFormat()).format("YYYY-MM-DD")
                };
                var packagesCriteria = productDetailsCtrl.getPackagesSearchCriteria();
                // packagesCriteria.date = $("#daterange").val(),
                packagesCriteria.children = $scope.selectedChild;
                packagesCriteria.adults = $scope.selectedAdults;
                packagesCriteria.infants = $scope.selectedInfants;
                packagesCriteria.seniors = $scope.selectedSeniors;
                packagesCriteria.students = $scope.selectedStudents;
                packagesCriteria.nights = parseInt($scope.selectedNights);

                productDetailsCtrl.savePackagesSearchCriteria(packagesCriteria);

                productDetailsCtrl.next($state.$current.name, packageDetailsParam);
            };


            $scope.getProduct = function (travelDate) {
                if (!$scope.hotelMainProduct) return;
                var productCode = $scope.hotelMainProduct.code;

                $scope.isLoading = true;
                $scope.scrollToResults(true);

                var requestParams = {
                    urlPrefix: webUrl,
                    token: jwtService.getPrincipalToken(),
                    productCode: productCode,
                    travelDate: travelDate,
                    nights: $scope.selectedNights,
                    adults: $scope.selectedAdults,
                    children: $scope.selectedChild,
                    blockId: $scope.requestArguments.blockId
                };

                $scope.product = undefined;
                $scope.packages = undefined;
                $scope.allItems = [];

                $scope.filterItems();

                // hotelsService.getHotelProductWithPackages(requestParams, function (result) {
                $scope.allRates = [];
                hotelsService.getRates(requestParams, function (result) {

                    $scope.isLoading = false;
                    $scope.wasSearch = true; // 
                    $scope.noResultsMessage = result && result.data && result.data.message;

                    if (!result || !result.data || !result.success) {
                        $scope.scrollToResults(true);
                        $scope.persistCriteria();
                        return;
                    }

                    $scope.allRates = result.data.rateCodes || [];

                    var isAnyRateAvailable = ($scope.allRates || '').length ? false : true;

                    var notifyBlockDateInvalid = null;

                    $.each($scope.allRates, function (key, rate) {
                        if (rate && rate.product) {
                            rate.price = parseFloat(rate.fromPricing || 0);
                            if ((rate.product.units || "").length) {
                                rate.currency = rate.product.units[0].currency;
                            }

                            $.each(rate.product.units, function (key, value) {
                                value.name = value.description;
                                value.petFeeOption = (value.options || []).find(function (option) {
                                    return option.code == "PET";
                                });
                            });
                            isAnyRateAvailable = isAnyRateAvailable || rate.isAvailable;

                            //
                            if (rate.blockId && rate.blockStartDate && rate.blockEndDate) {
                                var blockStartDate = moment(rate.blockStartDate);
                                var blockEndDate = moment(rate.blockEndDate);

                                if (blockStartDate.isValid() && blockEndDate.isValid()) {
                                    var blockStartDateFormatted = blockStartDate.format("MMMM DD");
                                    var blockEndDateFormatted = blockEndDate.format("MMMM DD");

                                    rate.blockAvailableMessage = $scope.utils.getLabel("hotels.groupBlock.range-available-message").replace("{0}", blockStartDateFormatted).replace("{1}", blockEndDateFormatted);


                                    var productStartDate = moment(rate.product.startDate);
                                    var productEndDate = moment(rate.product.endDate).subtract(1, 'day');

                                    var isValid = productStartDate.isSameOrAfter(blockStartDate) && productStartDate.isSameOrBefore(blockEndDate)
                                        &&
                                        productEndDate.isSameOrAfter(blockStartDate) && productEndDate.isSameOrBefore(blockEndDate);

                                    if (!isValid && !notifyBlockDateInvalid) {
                                        notifyBlockDateInvalid = function () {
                                            $uibModal.open({
                                                animation: true,
                                                templateUrl: "infoModal.html",
                                                controller: "infoModalCtrl",
                                                size: "book-required-products",
                                                resolve: {
                                                    "info": {
                                                        title: $scope.utils.getLabel("hotels.groupBlock.modal-title").replace("{0}", blockStartDateFormatted).replace("{1}", blockEndDateFormatted),
                                                        message: $scope.utils.getLabel("hotels.groupBlock.modal-message").replace(new RegExp("\\{0\\}", 'g'), $scope.customprodphone || $scope.phone || "1.888.852.7737")//utilsFactory.getLabel("general.expressConsent.ConfirmModalMessage")
                                                    }
                                                },
                                                backdrop: "true"
                                            });
                                        }
                                    }
                                }
                            }
                        }
                    });

                    // block id
                    notifyBlockDateInvalid && notifyBlockDateInvalid();
                    //

                    //if (!($scope.allRates || "").length) {
                    //    $scope.scrollToResults();
                    //    $scope.persistCriteria();
                    //    return;
                    //}

                    //$scope.product = result.data.products[0];

                    // exception for this hotel
                    var hotelProductCodeWithException = "WEG-BC";
                    $scope.packages = result.data.packages || [];
                    _.each($scope.packages, function (el) {
                        el.isPackage = true; el.sortOrder = el.ibeSortOrder;
                        el.isDisabled = !isAnyRateAvailable; // (productCode != hotelProductCodeWithException) &&

                        el.isException = false; // (productCode == hotelProductCodeWithException);
                    });


                    $scope.allItems = $scope.allRates
                        .concat($scope.packages || []);
                    $scope.filterItems();
                    $scope.persistCriteria();
                    $scope.filterItems();

                    if ($scope.updateItem && !$scope.updateItem.isUpdateCompSynced) {
                        $scope.updateItem.isUpdateCompSynced = true;
                        var firstComp = $scope.updateItem.BookingToQuote.Components[0];
                        $scope.goToRateHotels({ id: firstComp.rateID });
                    }
                    else {
                        $scope.initState($state.$current.name, $state.params);

                        resizeOnImgLoad();
                        resizeSliderPanel();
                        $scope.scrollToResults(true);
                        $scope.showSoldOutNotice();
                    }
                });

                //  }); // old request
            };

            $scope.nightsChanged = function (nights) {
                //  $scope.selectedNights = nights;
                $scope.persistCriteria();
                $scope.wasSearch = false;
                // $scope.daterangepicker.trigger("apply.daterangepicker");
            };
            $scope.triggerRefreshInventory = function (clear) {

                if (!$scope.enable2CalendarsDateRange || $scope.isCalendarLoading) return;

                if (clear) {
                    $scope.hotelCheckinInventory = Object.create(null);
                    $scope.hotelCheckoutInventory = Object.create(null);
                }
                jQuery("#daterange").data('daterangepicker').setValidStartDate();
                jQuery("#daterange").data('daterangepicker').triggerRefreshInventory();
            };

            $scope.adultsChanged = function (doTrigger) {
                //var maxChildren =$scope.maxUnitOccupancyPerUnit?($scope.maxUnitOccupancyPerUnit - $scope.selectedAdults + $scope.maxUnitAdditionalChildren):0;
                //$scope.availableChild = strRange(0, maxChildren + 1);
                //if ($scope.availableChild.indexOf($scope.selectedChild.toString()) < 0) {
                //    $scope.selectedChild = $scope.availableChild[0];
                //}

                $scope.persistCriteria();

                if (doTrigger) $scope.wasSearch = false;

                $scope.triggerRefreshInventory(true);
                //    $scope.daterangepicker.trigger("apply.daterangepicker");
            };

            $scope.childChanged = function (doTrigger) {
                //var diffChild = $scope.maxUnitAdditionalChildren - $scope.selectedChild >= 0 ? 0 : $scope.selectedChild - $scope.maxUnitAdditionalChildren;
                //var maxAdults =$scope.maxUnitOccupancyPerUnit?($scope.maxUnitOccupancyPerUnit - diffChild):0;
                //$scope.availableAdults = strRange(1, maxAdults + 1);
                //if ($scope.availableAdults.indexOf($scope.selectedAdults.toString()) < 0) {
                //    $scope.selectedAdults = $scope.availableAdults[0];
                //}
                $scope.persistCriteria();

                if (doTrigger) $scope.wasSearch = false;

                $scope.triggerRefreshInventory(true);
                //    $scope.daterangepicker.trigger("apply.daterangepicker");
            };

            $scope.getUnitDescription = function (unit) {
                if (!unit || !unit.productDescriptions || !unit.productDescriptions.descriptions.length) return null;
                if (unit.productDescriptions.descriptions.length >= 2) {
                    return unit.productDescriptions.descriptions[1];
                }
                return unit.productDescriptions.descriptions[0];
            };

            $scope.fillProductDetailsRecursive = function (parentProduct, products, index, callback) {
                if (index === products.length || !products[index]) {
                    callback();
                    return;
                }
                var travelDate = products[index].startDate ? moment(products[index].startDate) : $("#daterange").data().daterangepicker.startDate;
                var travelDateStr = (travelDate.isValid() ? travelDate : $("#daterange").data().daterangepicker.startDate).format("YYYY-MM-DD");

                var params = {
                    token: jwtService.getPrincipalToken(),
                    productCode: products[index].productCode,
                    productCategory: products[index].productCategory,
                    travelDate: travelDateStr
                };
                productsFactory.getProductWithHiddenUnitsWithCallback(params, function (result) {
                    if (result && result.success && (result.data || "").length) {
                        products[index].product = result.data[0];
                        //
                        if (products[index].startDate) {
                            products[index].product.startDate = products[index].startDate;
                        }
                        if (products[index].endDate) {
                            products[index].product.endDate = products[index].endDate;
                        }
                        //
                        products[index].product.selectedUnit = _.find(products[index].product.units, function (u) {
                            return products[index].unitCode === u.unitCode;
                        });
                        if (products[index].product.selectedUnit) {
                            products[index].product.selectedUnit.selectedPickUp = (products[index].product.selectedUnit.pickups || "").length == 1 ? products[index].product.selectedUnit.pickups[0] : {};
                            products[index].product.selectedUnit.selectedDropOff = (products[index].product.selectedUnit.dropoffs || "").length == 1 ? products[index].product.selectedUnit.dropoffs[0] : {};
                        }

                        if (!parentProduct.requiredProducts) {
                            parentProduct.requiredProducts = [];
                        }
                        parentProduct.requiredProducts.push(products[index]);
                    }
                    $scope.fillProductDetailsRecursive(parentProduct, products, index + 1, callback);
                });

            };

            $scope.getBookingQuoteObj = function () {
                $scope.isLoading = true;
                var removeExistingCartItemPromise = undefined;

                if ($scope.updateItem) {
                    removeExistingCartItemPromise = new Promise(function (resolve, reject) {
                        var requestParams = {
                            apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                            token: jwtService.getPrincipalToken(),
                            index: $scope.updateIndex,
                            productCode: $scope.updateItem.ProductCode
                        };

                        shoppingCartService.setStorageCart($scope.cart, function () {
                            shoppingCartService.updateCartComponents(requestParams, function (shoppingCart) {
                                if (shoppingCart && (shoppingCart.Items || '').length) {
                                    $scope.cart = shoppingCart;
                                } else {
                                    // window.location = "/";
                                }
                                resolve(1);
                            });
                        });
                    }); // Promise
                } else {
                    removeExistingCartItemPromise = Promise.resolve(1);
                }
                removeExistingCartItemPromise.then(function () {

                    $scope.lobTitle = $scope.hotelMainProduct && $scope.hotelMainProduct.productDescriptions
                        && (
                            $scope.hotelMainProduct.productDescriptions.genericTitle || ($scope.hotelMainProduct.productDescriptions.titles && $scope.hotelMainProduct.productDescriptions.titles.length > 0 ? $scope.hotelMainProduct.productDescriptions.titles[0] : $scope.hotelMainProduct.name));


                    var components = [];
                    var bookingComponent = {
                        "Id": $scope.rateProduct.code + $scope.rateProduct.selectedUnit.unitCode,
                        "ProductCategory": $scope.rateProduct.productCategory,
                        "ProductType": $scope.rateProduct.productType,
                        "ProductCode": $scope.rateProduct.code,
                        "StartDate": $scope.rateProduct.startDate,
                        "EndDate": $scope.rateProduct.endDate,
                        "Name": $scope.rateProduct.name,
                        "Description": $scope.rateProduct.description,
                        "Price": $scope.rateProduct.selectedUnit.price,
                        "ChildPrice": $scope.rateProduct.selectedUnit.price,
                        "NumberOfAdults": $scope.selectedAdults,
                        "NumberOfChildren": $scope.selectedChild,
                        "NumberOfInfants": 0,
                        "Status": "New",
                        "UnitCode": $scope.rateProduct.selectedUnit.unitCode,
                        "UnitDescription": $scope.rateProduct.selectedUnit.description,
                        "PickupLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                        "DropoffLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                        "StartingLocation": $scope.rateProduct.startingLocation,
                        "Destination": $scope.rateProduct.destination,
                        "Remarks": [],
                        "RequestedRateCode": $scope.selectedRate && $scope.selectedRate.rateCode,
                        "tripTeaseHotelCode": $scope.rateProduct.tripTeaseHotelCode,
                        "tripTeaseCurrency": $scope.rateProduct.selectedUnit.currency,
                        "rateID": $scope.selectedRate.id,
                        "nights": $scope.selectedNights,
                        "disclaimers": $scope.rateProduct.productDescriptions && $scope.rateProduct.productDescriptions.disclaimers,
                        "AddedFromWebTray": $scope.requestArguments.fromwebtray,
                        "ProductUnitOption": $scope.rateProduct.selectedUnit.bringPet ? $scope.rateProduct.selectedUnit.petFeeOption : null,
                        "HotelGroupBlockEventCode": $scope.rateProduct.blockId,
                        "ExtendedCoverageSelected": $scope.rateProduct.selectedUnit._extendedCoverageSelected || false,
                        "_trackingLob": $scope.lobTitle,
                    };
                    components.push(bookingComponent);

                    if ($scope.rateProduct.requiredProducts) {

                        _.each($scope.rateProduct.requiredProducts, function (reqProd) {

                            components.push({
                                "Id": reqProd.product.id,
                                "ProductCategory": reqProd.product.productCategory,
                                "ProductType": reqProd.product.productType,
                                "ProductCode": reqProd.product.code,
                                "StartDate": reqProd.product.startDate,
                                "EndDate": reqProd.product.endDate,
                                "Name": reqProd.product.name,
                                "Description": reqProd.product.description,
                                "ProductDescriptions": reqProd.product.productDescriptions,
                                "Price": reqProd.product.price,
                                "ChildPrice": reqProd.product.price,
                                "NumberOfAdults": $scope.selectedAdults,
                                "NumberOfChildren": $scope.selectedChild,
                                "NumberOfInfants": 0,
                                "Status": "New",
                                "UnitCode": reqProd.product.selectedUnit ? reqProd.product.selectedUnit.unitCode : reqProd.unitCode,
                                "UnitDescription": reqProd.product.selectedUnit ? reqProd.product.selectedUnit.description : reqProd.product.description,
                                "PickupLocation": reqProd.product.selectedUnit ? reqProd.product.selectedUnit.selectedPickUp : undefined,
                                "DropoffLocation": reqProd.product.selectedUnit ? reqProd.product.selectedUnit.selectedDropOff : undefined,
                                "StartingLocation": reqProd.product.startingLocation,
                                "Destination": undefined,
                                "Remarks": [],
                                "IsFee": reqProd.product.isFee,
                                "ShowInCart": reqProd.showInCart,
                                "_trackingLob": $scope.lobTitle,
                            });
                        });
                    }

                    var bookingToQuote = {
                        "Components": components
                    };
                    var data = {
                        "BookingToQuote": bookingToQuote
                    };

                    var requestParams = {
                        apiUrl: webUrl,
                        token: jwtService.getPrincipalToken(),
                        dataToPost: data,
                        startDate: $("#daterange").val(),
                        endDate: undefined,
                        startTime: undefined,
                        endTime: undefined
                    };

                    shoppingCartService.addComponentsToCart(requestParams, function (result) {
                        //delete the item from cart

                        //var modalInstance = $uibModal.open({
                        //    animation: true,
                        //    templateUrl: "cartInfoModal.html",
                        //    controller: "cartInfoModalCtrl",
                        //    size: "add-to-cart",
                        //    resolve: {
                        //        count: result,
                        //        isHotel: true
                        //    },
                        //    backdrop: "static"
                        //});
                        if (result) {
                            var isEnhanceBookingPageEnabled = ($scope.selectedLanguage && $scope.selectedLanguage.enableEnhanceBookingPage) || ($scope.anonymUser && $scope.anonymUser.enableEnhanceBookingPage);
                            var redirectToUrl = shoppingCartService.utils.getAfterAddToCartPageUrl(generalCtrl.selectedGeographyCode, isEnhanceBookingPageEnabled);
                            window.location = utilsFactory.addPersistentQueryStringsParams(redirectToUrl);
                        } else {
                            $scope.isLoading = false;
                        }
                    });

                }); // EndPromise resolve     
            };

            $scope.bookHotel = function (ticket) {
                new Promise(function (resolve, reject) {
                    var promiseHandler = { resolve, reject };

                    $scope.rateProduct.selectedUnit = ticket;
                    if (!($scope.rateProduct.requiredProducts || "").length) {
                        $scope.isLoading = true;
                        //get related services - check required additional products to add
                        var productQueries = [];


                        productQueries.push({
                            ProductCode: $scope.rateProduct.code,
                            TravelDate: $("#daterange").data().daterangepicker.startDate.format("YYYY-MM-DD"),
                            TravelEnd: $("#daterange").data().daterangepicker.startDate.clone().add(parseInt($scope.selectedNights), "d").format("YYYY-MM-DD"),
                            UnitCode: ticket ?
                                ticket.unitCode : null
                        });

                        var dataToPost = { ProductQueries: productQueries };
                        var relatedServicesRequestParams = {
                            token: jwtService.getPrincipalToken(),
                            data: dataToPost
                        };

                        productsFactory.getRelatedServicesMulti(relatedServicesRequestParams, function (relatedProducts) {

                            if (relatedProducts && (relatedProducts.data || "").length && (relatedProducts.data[0].requiredProducts || "").length) {
                                //get product details for each additional required product
                                if (!($scope.rateProduct.requiredProducts || "").length) {
                                    $scope.fillProductDetailsRecursive($scope.rateProduct, relatedProducts.data[0].requiredProducts, 0, function () {
                                        $scope.isLoading = false;

                                        if (($scope.rateProduct.requiredProducts || "").length) {
                                            $scope.showRequiredProductsModal(promiseHandler);
                                        } else {
                                            resolve(true);
                                            //$scope.getBookingQuoteObj();
                                        }
                                    });
                                } else {
                                    $scope.isLoading = false;
                                    $scope.showRequiredProductsModal(promiseHandler);
                                }

                            } else {
                                //call the callback
                                //$scope.getBookingQuoteObj();
                                resolve(true);
                            }
                        });
                    } else {
                        $scope.showRequiredProductsModal(promiseHandler);
                    }
                }).then(function (result) {
                    return new Promise(function (resolve, reject) {
                        if (ticket.extendedCoveragePrice > 0) {
                            //
                            var tripCoverageModalLabels = utilsFactory.getLabel("hotels.tripCoverageModal", true);
                            var hotelProductCode = $scope.hotelMainProduct && $scope.hotelMainProduct.code;
                            console.log("trip coverage modal: ", tripCoverageModalLabels, hotelProductCode, $scope.actionRegionCode);


                            var defaultLabels = tripCoverageModalLabels && _.find(tripCoverageModalLabels, function (item) {
                                return item.isDefault;
                            });

                            // first search by hotel product code, then by region code
                            var targetLabels = tripCoverageModalLabels && _.find(tripCoverageModalLabels, function (m) {
                                return m.codes && m.codes.indexOf(hotelProductCode) > -1;
                            });

                            if (!targetLabels && $scope.actionRegionCode) {
                                targetLabels = tripCoverageModalLabels && _.find(tripCoverageModalLabels, function (m) {
                                    return m.geographyCode == $scope.actionRegionCode;
                                });
                            }

                            if (!targetLabels) {
                                targetLabels = defaultLabels;
                            } else {
                                if (targetLabels.inheritEmptyFieldsFromDefault && defaultLabels) {
                                    for (var key in defaultLabels) {
                                        if (!targetLabels.hasOwnProperty(key)) {
                                            targetLabels[key] = defaultLabels[key];
                                        }
                                    }
                                }
                            }

                            if (!targetLabels) {
                                console.log("Can't display the trip coverage modal because the lables are missing!");
                                resolve(false);
                                return;
                            }

                            var formattedPrice = $filter('formatPrice')($scope.getPriceInSelectedCurrency(ticket.extendedCoveragePrice, ticket.currency, $scope.selectedCurrency), $scope.selectedLanguage && $scope.selectedLanguage.languageCode, ($scope.currencyRatesLoaded && $scope.selectedCurrency && $scope.selectedCurrency.code) || ticket.currency);

                            targetLabels.content = targetLabels.content && targetLabels.content.replace('{price}', formattedPrice);
                            targetLabels.priceInfo = targetLabels.priceInfo && targetLabels.priceInfo.replace('{price}', formattedPrice);


                            var tripCoverageModalInstance = $uibModal.open({
                                animation: true,
                                templateUrl: "tripCoverageModal.html",
                                controller: "tripCoverageModalCtrl",
                                size: "trip-coverage",
                                resolve: {
                                    modalInfo: targetLabels
                                },
                                backdrop: "true"
                            });

                            tripCoverageModalInstance.result.then(function (result) {
                                resolve(true);
                            }, function () {
                                resolve(false); // cancel trip coverage but continue booking                                
                            });

                        } else {
                            resolve(false);
                        }
                    });
                }).then(function (addTripCoverage) {
                    // TODO: 

                    ticket._extendedCoverageSelected = addTripCoverage;
                    $scope.getBookingQuoteObj();

                }).catch(function (e) {
                    console.log(e);
                    $scope.isLoading = false;
                });
            };

            $scope.showRequiredProductsModal = function (promiseHandler) {

                var popupProducts = _.filter($scope.rateProduct.requiredProducts, function (reqProd) {

                    if (!reqProd.product) return false;

                    if (reqProd.product.productType === "FEE") {
                        reqProd.product.isFee = true;
                        return false;
                    }
                    return true;
                });
                if (popupProducts.length == 0) {
                    promiseHandler.resolve(true);
                    //$scope.getBookingQuoteObj();
                    return;
                }
                var requiredModalInstance = $uibModal.open({
                    animation: true,
                    templateUrl: "requiredProductsModal.html",
                    controller: "requiredProductsModalCtrl",
                    size: "book-required-products",
                    resolve: {
                        "products": { followingProductSingle: "experience", followingProductMultiple: "experiences", yourProductTitle: "accommodation", data: popupProducts }
                    },
                    backdrop: "true"
                });
                requiredModalInstance.result.then(function (result) {
                    promiseHandler.resolve(true);
                    // $scope.getBookingQuoteObj();
                }, function () {
                    promiseHandler.reject(false);
                    //console.log("dismiss");
                });
            };

            $scope.goToRateHotels = function (rateItem) {
                var doNext = function () {

                    $scope.isLoading = true;
                    $state.go("select-booking-type.book-stay.rate", { rateCode: rateItem.id });
                    $scope.scrollToResults(false);
                };

                if (rateItem && rateItem.expressConsentRequired) {
                    var requiredModalInstance = $uibModal.open({
                        animation: true,
                        templateUrl: "expressConsentModal.html",
                        controller: "expressConsentModalCtrl",
                        size: "book-required-products",
                        resolve: {
                            "expressConsent": {
                                title: utilsFactory.getLabel("general.expressConsent.ConfirmModalTitle"),
                                message: utilsFactory.getLabel("general.expressConsent.ConfirmModalMessage"),
                                components: rateItem
                            }
                        },
                        backdrop: "true"
                    });

                    requiredModalInstance.result.then(function (result) {
                        doNext();
                    }, function (e) {
                        //console.log("dismiss");
                        // debugger;
                    });
                } else {
                    doNext();
                }
            };

            $scope.gotoCheckout = function (ticket) {
                if ($scope.rateProduct.unitCode !== ticket.unitCode) {
                    $scope.rateProduct.requiredProducts = [];
                    $scope.rateProduct.unitCode = ticket.unitCode;
                }

                //show package modal needs to be as for activities
                //if  ($scope.showPackageModal) {
                //    hotelsService.getHotelWizardModel(function (wizardResult) {
                //        if (wizardResult.success && wizardResult.data) {
                //            var ticketTypes = wizardResult.data.ticketTypes;
                //            var containsPackages = false;
                //            if (ticketTypes) {
                //                containsPackages = _.some(ticketTypes, function (val) {
                //                    return val.name && val.name.toLowerCase().indexOf("package") >= 0;
                //                });
                //            }

                //            if (containsPackages && !wizardResult.data.bookedModalShowed) {

                //                var modalInstance = $uibModal.open({
                //                    animation: true,
                //                    templateUrl: "bookModal.html",
                //                    controller: "bookModalCtrl",
                //                    size: "lg",
                //                    resolve: {
                //                        ticket: function () {
                //                            return ticket;
                //                        },
                //                        packageModalLabels: function () {
                //                            return $scope.packageModalLabels;
                //                        }
                //                    }
                //                });

                //                modalInstance.result.then(function (ticket) {
                //                    wizardResult.data.bookedModalShowed = true;
                //                    wizardResult.data.ticket = ticket;

                //                    hotelsService.setHotelWizardModel(wizardResult.data, function () {
                //                        $rootScope.$broadcast("HotelWizardModelChanged", {
                //                            wizardModel: wizardResult.data,
                //                            callback: function () {
                //                                $scope.bookHotel(ticket);
                //                            }
                //                        });
                //                    });
                //                }, function (reason) {
                //                    if (reason && reason.goToPackage) {
                //                        $state.go("select-booking-type.packages");
                //                    } else {
                //                        $scope.bookHotel(ticket);
                //                    }
                //                });

                //            } else {
                //                $scope.bookHotel(ticket);
                //            }
                //        } else {
                //            $scope.bookHotel(ticket);
                //        }
                //    });
                //} else {
                $scope.bookHotel(ticket);
                // }
                // $scope.handleNext(selectedUnit);
            };

            $scope.persistCriteria = function () {
                if ($scope.$parent) {
                    var hotelSelectTicketCtrl = $scope.$parent;
                    if (hotelSelectTicketCtrl.$parent) {
                        var hotelDetailsCtrl = hotelSelectTicketCtrl.$parent;

                        var criteria = {
                            date: $("#daterange").val(),
                            adults: $scope.selectedAdults,
                            child: $scope.selectedChild,
                            nights: $scope.selectedNights,
                            roomsNo: $scope.selectedRoomsNo,
                            rates: $scope.allRates,
                            noResultsMessage: $scope.noResultsMessage,
                            // selectedRate: $scope.selectedRate,
                            //product: $scope.product,
                            packages: $scope.packages
                        };
                        hotelDetailsCtrl.saveSearchCriteria(criteria);
                    }
                }
            };
            $scope.getCriteria = function () {
                if ($scope.$parent) {
                    var hotelSelectTicketCtrl = $scope.$parent;
                    if (hotelSelectTicketCtrl.$parent) {
                        var hotelDetailsCtrl = hotelSelectTicketCtrl.$parent;

                        return hotelDetailsCtrl.getSearchCriteria();
                    }
                }

                return undefined;
            };

            $scope.initCurrentRate = function () {

            };

            $rootScope.$on("$stateChangeSuccess", function (event, toState, toParams, fromState, fromParams) {
                $timeout(function () {
                    $scope.isLoading = false;
                }, 300);
                //

                $scope.initState(toState && toState.name, toParams);
                $scope.initMainProductsByState();
            });

            $scope.onCalendarUpdate = function (isStartDateMode, startDate, endDate, diffDays) {
                if (!$scope.enable2CalendarsDateRange || $scope.calendarLoading) return;

                if (!$("#daterange").data().daterangepicker) {
                    return;
                }

                if ($("#daterange").data().daterangepicker.endDate) {
                    var selectedNights = $("#daterange").data().daterangepicker.endDate.diff($("#daterange").data().daterangepicker.startDate, 'days');
                    if (selectedNights <= 0) {
                        selectedNights = 1;
                    }
                    if (selectedNights != $scope.selectedNights) {
                        $scope.selectedNights = selectedNights;
                        setTimeout(function () {
                            $scope.$apply();
                        });
                    }
                }

                // console.log("onCalendarUpdate", isStartDateMode, startDate, endDate, diffDays);

                // check cached data
                //if (isStartDateMode) {
                //    if ($scope.hotelCheckinInventory && $scope.hotelCheckinInventory[startDate] && $scope.hotelCheckinInventory[endDate]) {
                //        jQuery("#daterange").data('daterangepicker').updateInventory($scope.hotelCheckinInventory, $scope.hotelCheckoutInventory);
                //        return;
                //    }
                //}
                //else {
                //    if ($scope.hotelCheckoutInventory && $scope.hotelCheckoutInventory[startDate]) {
                //        jQuery("#daterange").data('daterangepicker').updateInventory($scope.hotelCheckinInventory, $scope.hotelCheckoutInventory);
                //        return;
                //    }
                //}
                //               

                var rateCode = "BAR";
                var productCode = $scope.requestArguments.productCode;
                var numberOfAdults = $scope.selectedAdults;
                var numberOfChildren = $scope.selectedChild;

                var selectedStartDate = $("#daterange").data().daterangepicker.startDate.format("YYYY-MM-DD");

                // load available start dates and end dates
                // if (isStartDateMode) {
                //

                var promisesResolved = true;

                var startDatePromise = Promise.resolve(1);
                if (!($scope.hotelCheckinInventory && $scope.hotelCheckinInventory[startDate] && $scope.hotelCheckinInventory[endDate])) {
                    promisesResolved = false;
                    startDatePromise = productsFactory.getHotelCheckInCalendar(jwtService.getPrincipalToken(), startDate, productCode, rateCode, numberOfAdults, numberOfChildren, diffDays);
                } else {
                    // load the next month's available start date, if the selected date is the final month
                    // ensure we have the next date inventory as well (when you click on the last day of the month, to be able to click the next btn)
                    var futureDate = moment(selectedStartDate).add(1, 'day').format("YYYY-MM-DD");
                    if (!$scope.hotelCheckinInventory[futureDate]) {
                        promisesResolved = false;
                        startDatePromise = productsFactory.getHotelCheckInCalendar(jwtService.getPrincipalToken(), futureDate, productCode, rateCode, numberOfAdults, numberOfChildren, diffDays);
                    }
                }

                var endDatePromise = Promise.resolve(1);
                if (!($scope.hotelCheckoutInventory && $scope.hotelCheckoutInventory[selectedStartDate])) {
                    promisesResolved = false;
                    endDatePromise = productsFactory.getHotelCheckOutCalendar(jwtService.getPrincipalToken(), selectedStartDate, productCode, rateCode, numberOfAdults, numberOfChildren, diffDays);
                }

                if (promisesResolved) {
                    processInventoryAndShowNoticeModal(selectedStartDate, $scope.hotelCheckinInventory, $scope.hotelCheckoutInventory);
                    jQuery("#daterange").data('daterangepicker').updateInventory($scope.hotelCheckinInventory, $scope.hotelCheckoutInventory);
                    return;
                } else {
                    var prevWasInventoryRequested = $scope.wasInventoryRequested;
                    $scope.wasInventoryRequested = true;

                    jQuery("#daterange").data('daterangepicker').showLoading();
                    $scope.calendarLoading = true;
                    setTimeout(function () {
                        $scope.$apply();
                    });

                    Promise.all([startDatePromise, endDatePromise]).then(
                        function (resultValues) {
                            console.log("getHotelInventory", resultValues);
                            $scope.calendarLoading = false;
                            setTimeout(function () {
                                $scope.$apply();
                            });
                            jQuery("#daterange").data('daterangepicker').hideLoading();

                            var result = resultValues && resultValues[0];
                            var hotelInventory = result && result.data && result.data != 1 && result.data.hotelInventory && result.data.hotelInventory[0];
                            if (hotelInventory && (hotelInventory.dayInventory || "").length) {
                                hotelInventory.dayInventory.forEach(function (val) {
                                    var tcharIndex = val.date.indexOf('T');
                                    var key = tcharIndex > 0 ? val.date.substr(0, tcharIndex) : val.date;

                                    $scope.hotelCheckinInventory[key] = val;

                                });
                            }

                            //
                            result = resultValues && resultValues[1];
                            hotelInventory = result && result.data && result.data != 1 && result.data.hotelInventory && result.data.hotelInventory[0];
                            //var selectedStartDate = $("#daterange").data().daterangepicker.startDate;

                            if (hotelInventory && (hotelInventory.dayInventory || "").length) {
                                $scope.hotelCheckoutInventory[selectedStartDate] = Object.create(null);
                                hotelInventory.dayInventory.forEach(function (val) {
                                    var tcharIndex = val.date.indexOf('T');
                                    var key = tcharIndex > 0 ? val.date.substr(0, tcharIndex) : val.date;
                                    $scope.hotelCheckoutInventory[selectedStartDate][key] = val;
                                });
                            }


                            processInventoryAndShowNoticeModal(selectedStartDate, $scope.hotelCheckinInventory, $scope.hotelCheckoutInventory);
                            jQuery("#daterange").data('daterangepicker').updateInventory($scope.hotelCheckinInventory, $scope.hotelCheckoutInventory);
                            if (!prevWasInventoryRequested) {
                                jQuery("#daterange").data('daterangepicker').setValidStartDate();
                            }
                            //if (isStartDateMode && $("#daterange").data().daterangepicker.startDate && !Object.keys($scope.hotelCheckoutInventory).length) {
                            //    // call checkout inventory for the initial call
                            //    $scope.onCalendarUpdate(false, $("#daterange").data().daterangepicker.startDate.format("YYYY-MM-DD"), null);

                            //} else {
                            //    jQuery("#daterange").data('daterangepicker').hideLoading();
                            //    jQuery("#daterange").data('daterangepicker').updateInventory($scope.hotelCheckinInventory, $scope.hotelCheckoutInventory);
                            //}
                        },
                        function (response) {
                            $scope.calendarLoading = false;
                            jQuery("#daterange").data('daterangepicker').hideLoading();

                            setTimeout(function () {
                                $scope.$apply();
                            });
                        });
                }
                //
                //}
                //else {

                //    if ($scope.hotelCheckoutInventory && $scope.hotelCheckoutInventory[selectedStartDate]) {
                //        jQuery("#daterange").data('daterangepicker').updateInventory($scope.hotelCheckinInventory, $scope.hotelCheckoutInventory);
                //        return;
                //    }

                //    jQuery("#daterange").data('daterangepicker').showLoading();
                //    $scope.calendarLoading = true;
                //    setTimeout(function () {
                //        $scope.$apply();
                //    });
                //    productsFactory.getHotelCheckOutCalendar(jwtService.getPrincipalToken(), startDate, productCode, rateCode, numberOfAdults, numberOfChildren, diffDays).then(
                //        function (result) {
                //            console.log("getHotelInventory", result);
                //            $scope.calendarLoading = false;


                //            var hotelInventory = result && result.data && result.data.hotelInventory && result.data.hotelInventory[0];
                //            if (!hotelInventory || !(hotelInventory.dayInventory || "").length) return;


                //            $scope.hotelCheckoutInventory[startDate] = Object.create(null);


                //            hotelInventory.dayInventory.forEach(function (val) {
                //                var tcharIndex = val.date.indexOf('T');
                //                var key = tcharIndex > 0 ? val.date.substr(0, tcharIndex) : val.date;
                //                //if (isStartDateMode) {
                //                //    $scope.hotelCheckinInventory[key] = val;
                //                //} else {
                //                $scope.hotelCheckoutInventory[startDate][key] = val;
                //                //}
                //            });

                //            //if (isStartDateMode && $("#daterange").data().daterangepicker.startDate && !Object.keys($scope.hotelCheckoutInventory).length) {
                //            //    // call checkout inventory for the initial call
                //            //    $scope.onCalendarUpdate(false, $("#daterange").data().daterangepicker.startDate.format("YYYY-MM-DD"), null);

                //            //} else {
                //            jQuery("#daterange").data('daterangepicker').hideLoading();
                //            jQuery("#daterange").data('daterangepicker').updateInventory($scope.hotelCheckinInventory, $scope.hotelCheckoutInventory);
                //            //}
                //        },
                //        function (response) {
                //            $scope.calendarLoading = false;
                //            setTimeout(function () {
                //                $scope.$apply();
                //            });
                //            jQuery("#daterange").data('daterangepicker').hideLoading();
                //        });
                //}

                // var getHotelInventory = isStartDateMode ? productsFactory.getHotelCheckInCalendar : productsFactory.getHotelCheckOutCalendar;


            };

            function processInventoryAndShowNoticeModal(selectedDate, hotelCheckinInventory, hotelCheckoutInventory) {
                var _this = this;
                var selectedDateModalInfo = jQuery("#daterange").data('daterangepicker').selectedDateModalInfo;
                jQuery("#daterange").data('daterangepicker').selectedDateModalInfo = Object.create(null);

                if (!selectedDate || !hotelCheckinInventory || !hotelCheckoutInventory || !selectedDateModalInfo || !selectedDateModalInfo.selectedDate || selectedDateModalInfo.selectedDate != selectedDate)
                //   console.log("return processInventoryAndShowNoticeModal: ");
                { return; }

                console.log("TBD: Display the modal info here", selectedDateModalInfo, selectedDate, hotelCheckinInventory, hotelCheckoutInventory);

                var checkInDayInventory = hotelCheckinInventory[selectedDate];
                var checkOutInventory = hotelCheckoutInventory[selectedDate];
                var hasAnyCheckoutDaysAvailable = false;

                if (checkOutInventory) {
                    for (var k in checkOutInventory) {
                        var val = checkOutInventory[k];
                        hasAnyCheckoutDaysAvailable = hasAnyCheckoutDaysAvailable || (val.inventory > 0);
                    }
                }
                $('#hotelCheckInLosInfoModal').off('hidden.bs.modal');

                if (checkOutInventory && !hasAnyCheckoutDaysAvailable) {
                    checkInDayInventory.inventory = 0; // because it doesn't have any available checkout dates, overwrite the invetory with 0

                    var $checkinLosMessage = $('#hotelCheckInLosInfoModal').find(".checkin-los-message");
                    $checkinLosMessage.html(($checkinLosMessage.data("checkoutunavailable-title") || ""));
                    $('#hotelCheckInLosInfoModal').modal({ backdrop: 'static' });

                    $('#hotelCheckInLosInfoModal').on('hidden.bs.modal', function (event) {
                        console.log("Revert selected date");
                        jQuery("#daterange").data('daterangepicker').revertSelectedDate();
                        jQuery("#daterange").click();
                        //_this.dateFilter && _this.dateFilter.revertSelectedDate();
                    });

                } else
                    // display the minimum required number of nights modal
                    if (selectedDateModalInfo.isStartDateMode && checkInDayInventory && checkInDayInventory.minLos > 1) {
                        // TODO: change to react modal
                        var $checkinLosMessage = $('#hotelCheckInLosInfoModal').find(".checkin-los-message");
                        $checkinLosMessage.html(($checkinLosMessage.data("checkinlos-title") || "").replace("{0}", checkInDayInventory.minLos));
                        $('#hotelCheckInLosInfoModal').modal({ backdrop: 'static' });
                    }
            }

            $scope.init = function () {

                $scope.checkExitIntentPopup($scope.anonymUser, $scope.requestArguments.productCode);

                $scope.isLoading = false;
                var datepickersettings = {
                    extendedCalendars: $scope.enable2CalendarsDateRange, // custom property added

                    singleDatePicker: $scope.enable2CalendarsDateRange ? false : true,
                    minDate: jwtService.getServerMomentDate(),
                    showDropdowns: $scope.enable2CalendarsDateRange ? false : true,
                    locale: {
                        format: shoppingCartService.getHotelsDateFormat(),//shoppingCartService.getDateFormat(),
                        applyLabel: $scope.utils.getLabel("general.searchbtn"),
                        inventoryAvailable: $scope.utils.getLabel("hotels.calendar.inventoryAvailable"),
                        inventoryFew: $scope.utils.getLabel("hotels.calendar.inventoryFew"),
                        checkoutUnavailableLos: $scope.utils.getLabel("hotels.calendar.checkoutUnavailableLos"),
                        minNightStay: $scope.utils.getLabel("hotels.calendar.minNightStay"),
                    },
                    parentEl: "#daterangecontainer",
                    secondInputEl: $scope.enable2CalendarsDateRange ? "#daterangeCheckout" : null,
                    onCalendarUpdate: $scope.enable2CalendarsDateRange ? $scope.onCalendarUpdate : null
                };

                if ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) {
                    moment.locale($scope.selectedLanguage.languageCode);
                }
                console.log("init: ", $("#daterange"));
                $scope.daterangepicker = $("#daterange").daterangepicker(datepickersettings);

                $("#daterange").on("change.daterangepicker", function (ev, picker) {

                    if (!$scope.enable2CalendarsDateRange || !$("#daterange").data().daterangepicker) {
                        return;
                    }

                    var datepickerData = $("#daterange").data().daterangepicker;
                    if (!datepickerData) return;

                    var oldStartDate = datepickerData.oldStartDate && datepickerData.oldStartDate.format("YYYY-MM-DD");
                    var oldEndDate = datepickerData.oldEndDate && datepickerData.oldEndDate.format("YYYY-MM-DD");
                    var startDate = datepickerData.startDate && datepickerData.startDate.format("YYYY-MM-DD");
                    var endDate = datepickerData.endDate && datepickerData.endDate.format("YYYY-MM-DD");

                    // console.log("date change", oldStartDate, startDate, oldEndDate, endDate);
                    if (oldStartDate == startDate && oldEndDate == endDate) return;

                    if ($("#daterange").data().daterangepicker.endDate) {
                        $scope.selectedNights = $("#daterange").data().daterangepicker.endDate.diff($("#daterange").data().daterangepicker.startDate, 'days');
                        if ($scope.selectedNights <= 0) {
                            $scope.selectedNights = 1;
                        }
                        setTimeout(function () {
                            $scope.wasSearch = false;
                            $scope.$apply();
                        });
                    }
                });

                $scope.daterangepicker.on("search.daterangepicker", function (ev, picker) {
                    $timeout(function () {
                        $scope.wasSearch = false;
                        $scope.search();
                    });
                });

                $scope.daterangepicker.on("apply.daterangepicker", function (ev, picker) {
                    console.log("date apply");
                    $timeout(function () {
                        $scope.wasSearch = false;
                    });
                    //var date = $(this).val();
                    //var strDate = moment(date, shoppingCartService.getDateFormat()).format("YYYY-MM-DD");
                    //$scope.getProduct(strDate);
                });

                var criteria = $scope.getCriteria();

                hotelsService.getSelectedHotel(function (result) {
                    if (result.success && result.data) {
                        //  $scope.mainProduct = result.data;
                        $scope.hotelMainProduct = result.data;

                        $scope.isChildAvailable = $scope.hotelMainProduct.childRatesAvailable;
                        $scope.isSeniorsAvailable = $scope.hotelMainProduct.seniorRateAvailable;
                        $scope.isStudentsAvailable = $scope.hotelMainProduct.studentRateAvailable;
                        $scope.isInfantsAvailable = $scope.hotelMainProduct.infantRateAvailable;
                    }

                    $scope.requestArguments.travelDate = $scope.requestArguments.isDefaultDate !== "1" || (!$scope.hotelMainProduct || !$scope.hotelMainProduct.startDate) ? $scope.requestArguments.travelDate : $scope.$parent.getProductDate($scope.hotelMainProduct.startDate);

                    if (jwtService.getServerMomentDate() > moment($scope.requestArguments.travelDate)) {
                        $scope.requestArguments.travelDate = $scope.hotelMainProduct && $scope.hotelMainProduct.startDate ? $scope.$parent.getProductDate($scope.hotelMainProduct.startDate) : jwtService.getServerStrDate();
                    }

                    if ($scope.updateItem) {
                        $scope.requestArguments.travelDate = jwtService.getServerStrDate();
                        $scope.requestArguments.isDefaultDate = true;

                        $("#daterange").val($scope.updateItem.startDateMoment.format(shoppingCartService.getHotelsDateFormat()));

                        $("#daterange").data().daterangepicker.startDate = $scope.updateItem.startDateMoment;
                        if ($scope.enable2CalendarsDateRange && $scope.updateItem.endDateMoment) {
                            $("#daterangeCheckout").val($scope.updateItem.endDateMoment.format(shoppingCartService.getHotelsDateFormat()));
                            $("#daterange").data().daterangepicker.endDate = $scope.updateItem.endDateMoment;
                        } else {
                            $("#daterange").data().daterangepicker.endDate = $scope.updateItem.startDateMoment;
                        }

                    } else {

                        if (!criteria.date || (moment(criteria.date, shoppingCartService.getHotelsDateFormat()) < jwtService.getServerMomentDate())) {

                            if (jwtService.getServerMomentDate() > moment($scope.requestArguments.travelDate)) {
                                $scope.requestArguments.travelDate = jwtService.getServerStrDate();
                            }
                            criteria.date = $scope.requestArguments.travelDate ? moment($scope.requestArguments.travelDate, "YYYY-MM-DD").format(shoppingCartService.getHotelsDateFormat())
                                : jwtService.getServerMomentDate();
                        }

                        if (criteria.date) {
                            $("#daterange").val(criteria.date);
                            var checkoutDate = null;
                            if ($("#daterangeCheckout").length) {
                                var checkoutDate = moment(criteria.date, shoppingCartService.getHotelsDateFormat()).add(parseInt($scope.selectedNights) || 1, 'days');
                                $("#daterangeCheckout").val(checkoutDate.format(shoppingCartService.getHotelsDateFormat()));
                            }
                            $("#daterange").data().daterangepicker.startDate = moment(criteria.date, shoppingCartService.getHotelsDateFormat());
                            $("#daterange").data().daterangepicker.endDate = checkoutDate || moment(criteria.date, shoppingCartService.getHotelsDateFormat());
                        }
                    }
                    $timeout(function () {
                        $scope.triggerRefreshInventory();
                    });


                });

                if ($scope.updateItem) {
                    var firstComp = $scope.updateItem.BookingToQuote.Components[0];
                    $scope.updateItem.isUpdateCompSynced = false;
                    $scope.selectedAdults = firstComp.NumberOfAdults || 2;
                    $scope.selectedChild = firstComp.NumberOfChildren || 0;
                    $scope.selectedSeniors = firstComp.NumberOfSeniors || 0;
                    $scope.selectedStudents = firstComp.NumberOfStudents || 0;
                    $scope.selectedInfants = firstComp.NumberOfInfants || 0;
                    $scope.selectedNights = firstComp.nights || 1;
                    $scope.wasSearch = false;

                    $scope.initState($state.$current.name, $state.params); // it will redirect if current state is "displaying rate details" and there's no selected rate
                    $scope.initMainProductsByState();

                    $scope.allItems = [].concat($scope.allRates || [])
                        .concat($scope.packages || []);

                    $scope.search();
                } else {
                    $scope.noResultsMessage = criteria.noResultsMessage;

                    if (criteria.adults) {
                        $scope.selectedAdults = criteria.adults;
                    }

                    //if (criteria.roomsNo) {
                    //    $scope.selectedRoomsNo = criteria.roomsNo;
                    //}

                    if (criteria.nights) {
                        $scope.selectedNights = criteria.nights;
                    }

                    if (criteria.child) {
                        $scope.selectedChild = criteria.child;
                    }

                    if (criteria.rates) {
                        $scope.allRates = criteria.rates;
                    }

                    if (criteria.packages) {
                        $scope.packages = criteria.packages;
                    }

                    $scope.initState($state.$current.name, $state.params); // it will redirect if current state is "displaying rate details" and there's no selected rate
                    $scope.initMainProductsByState();

                    $scope.allItems = [].concat($scope.allRates || [])
                        .concat($scope.packages || []);

                    $scope.filterItems();

                    //
                    $scope.lobTitle = $scope.mainProduct && $scope.mainProduct.productDescriptions
                        && (
                            $scope.mainProduct.productDescriptions.genericTitle || ($scope.mainProduct.productDescriptions.titles && $scope.mainProduct.productDescriptions.titles.length > 0 ? $scope.mainProduct.productDescriptions.titles[0] : $scope.mainProduct.name));

                    var trackerReq = {
                        lobTitle: $scope.lobTitle,
                        packageName: null,
                        searchDate: null,
                        adults: null,
                        children: null,
                        shoppingCart: $scope.cart,
                        anonymUser: $scope.anonymGeneralUser,
                        bookingNumber: null,
                        bookingId: null
                    };

                    trackingService.buildFlowTrackerObj(trackerReq); // ($scope.mainProduct && $scope.mainProduct.startDate)
                    //

                    if ($scope.rateProduct &&
                        ($scope.currentShowState == $scope.showStateEnum.rateDetails || $scope.currentShowState == $scope.showStateEnum.singleRateDetails)) {
                        window.Paperboy && window.Paperboy.ready(function () {
                            window.Paperboy.PriceCheck && window.Paperboy.PriceCheck.destroy();
                        });

                        $scope.showSoldOutNotice();
                        $scope.wasSearch = true;
                        resizeSliderPanel();
                        resizeOnImgLoad();
                        return;
                    }

                    if ($scope.allItems.length && $scope.currentShowState == $scope.showStateEnum.allRates) {
                        $scope.wasSearch = true;
                        return;
                    }

                    var triggerAutoSearch = !$scope.requestArguments.isDefaultDate && $scope.requestArguments.nights > 0;
                    if (triggerAutoSearch) {
                        $scope.search();
                    }
                }
              

                $timeout(function () {
                    $scope.triggerRefreshInventory();
                });

                //if (!$scope.product || !$scope.product.units || $scope.product.units.length === 0) {
                //    // $scope.search();
                //    //$scope.daterangepicker.trigger("apply.daterangepicker");
                //} else {
                //    $scope.wasSearch = false;
                //    _.each($scope.packages || [], function (el) { el.isPackage = true; el.sortOrder = el.ibeSortOrder; });

                //    // $scope.fillFiltersDropdowns();
                //    resizeSliderPanel();
                //    resizeOnImgLoad();

                //}

            };

            var initialized = false;

            $scope.anonymUser = undefined;
            $scope.initCurrentAnonymUser = function (callback) {
                //var hotelSelectTicketCtrl = $scope.$parent;
                //var hotelDetailsCtrl = hotelSelectTicketCtrl.$parent;
                //var generalCtrl = hotelDetailsCtrl.$parent;

                jwtService.getAnonymousUserByGeography(generalCtrl.selectedGeographyCode, function (user) {
                    $scope.anonymUser = user;
                    callback();
                });
            };

            $scope.$watch(function () {
                return taskFactory.task;
            },
                function (val) {

                    if (!val || !val.name || initialized) return;
                    initialized = true;

                    //
                    var initShoppingCart = new Promise(function (resolve, reject) {
                        shoppingCartService.getStorageCart(function (shoppingCart) {
                            if (shoppingCart) {
                                $scope.cart = shoppingCart;

                                $scope.updateItem = undefined;
                                $scope.updateIndex = -1;

                                if (($scope.requestArguments.updateCartItemCode || "").length && $scope.cart && $scope.cart.Items) {
                                    $scope.updateItem = _.find($scope.cart.Items, function (cartItem) {
                                        $scope.updateIndex++;
                                        var relatedComponent = _.find(cartItem.BookingToQuote && cartItem.BookingToQuote.Components, function (comp) {
                                            return comp.ProductCode == $scope.requestArguments.updateCartItemCode;
                                        });
                                        return relatedComponent != null;
                                    });

                                    if ($scope.updateItem) {
                                        $scope.updateItem.startDateMoment = moment($scope.updateItem.BookingToQuote.Components[0].StartDate);
                                        $scope.updateItem.endDateMoment = moment($scope.updateItem.BookingToQuote.Components[0].EndDate);
                                        if ($scope.updateItem.endDateMoment.isValid()) {
                                            $scope.selectedNights = $scope.updateItem.endDateMoment.diff($scope.updateItem.startDateMoment, 'days');
                                            if ($scope.selectedNights < 1) {
                                                $scope.selectedNights = 1;
                                            }
                                        }
                                    }
                                }
                            }
                            resolve(1);
                        });
                    });

                    initShoppingCart.then(function () {
                        $timeout($scope.initCurrentAnonymUser.bind(null, $scope.init)); //$scope.init);
                    });
                    //

                }, true);
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("hotelDetailsCtrl", [
       "utilsFactory", "$scope", "$state", "$element", "$http", "localStorageService", "jwtService", "hotelsService", "activitiesService", "taskFactory", "$timeout", "$rootScope",
        function (utilsFactory, $scope, $state, $element, $http, localStorageService, jwtService, hotelsService, activitiesService, taskFactory, $timeout, $rootScope) {

            $scope.$on("HotelWizardModelChanged", function (event, data) {
                $scope.wizardModel = data.wizardModel;

                if (data.callback) {
                    data.callback();
                }
            });

            $.material.init();


            var timeoutID = undefined;

            function resizeSliderPanel() {
                window.clearTimeout(timeoutID);
                timeoutID = setTimeout(function () {
                    jQuery(window).resize();
                }, 100);
            }
            $rootScope.$on("$stateChangeSuccess",
            function (event, toState, toParams, fromState, fromParams) {
                resizeSliderPanel();
                window.Paperboy && window.Paperboy.ready(function () {
                    window.Paperboy.PriceCheck && window.Paperboy.PriceCheck.destroy();
                });
            });


            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            $scope.showModal = {};

            $scope.requestArguments = {
                hotelId: $($element).attr("data-hotel-id"),
                productCode: $($element).attr("data-hotel-product-code"),
                productCategory: $($element).attr("data-hotel-product-category"),
                travelDate: $($element).attr("data-hotel-travel-date"),
                isDefaultDate: $($element).attr("data-hotel-is-default-date"),
                adults: $($element).attr("data-hotel-adults"),
                child: $($element).attr("data-hotel-child"),
                nights: $($element).attr("data-hotel-nights"),
                updateCartItemCode: $($element).attr("data-hotel-updateCartItem"),
                isUpgrade: ["1", "true"].indexOf(($($element).attr("data-hotel-isupgrade") || "").toLowerCase()) >= 0,
                autoSelectUnit: ["1", "true"].indexOf(($($element).attr("data-activity-autoselectunit") || "").toLowerCase()) >= 0,
                fromwebtray: ["1", "true"].indexOf(($($element).attr("data-hotel-fromwebtray") || "").toLowerCase()) >= 0,
                productcodeswithexpandeddescriptionbydefault: $($element).attr("data-productcodeswithexpandeddescriptionbydefault"),
            };

            $scope.billingDetails = {};

            $state.go("select-booking-type", {});

            $scope.wizardModel = {
                hotelId: undefined,
                ticketTypes: undefined,
                ticketType: undefined,
                hotel: undefined,
                roomsCriteria: {
                    date: undefined,
                    nights: undefined,
                    roomsNo: undefined,
                    adults: undefined,
                    child: undefined,
                    rates: undefined,
                    selectedRate: undefined,
                    packages: undefined
                },
                packagesCriteria: {
                    date: undefined,
                    adults: 1,
                    children: 0,
                    packages: undefined,
                    selectedPackage: undefined
                },
                bookedModalShowed: false
            };

            $scope.savePackagesSearchCriteria = function (criteria) {
                $scope.wizardModel.packagesCriteria = criteria;
            };

            $scope.getPackagesSearchCriteria = function () {
                return $scope.wizardModel.packagesCriteria;
            };

            $scope.setSelectedPackage = function (selectedPackage) {
                $scope.wizardModel.packagesCriteria.selectedPackage = selectedPackage;
            };

            $scope.getSelectedPackage = function () {
                return $scope.wizardModel.packagesCriteria.selectedPackage;
            };

            $scope.getPrevHotel = function () {
                if (localStorageService.isSupported) {
                    return localStorageService.get("prevHotel");
                }
                return null;
            };

            $scope.getButtonLabel = function (state, singleTicket) {
                return utilsFactory.getLabel("hotels.go-back");
                //switch (state) {
                //    case "select-booking-type":
                //        return utilsFactory.getLabel("hotels.see-all");
                //    case "select-booking-type.book-stay":
                //        return singleTicket ? utilsFactory.getLabel("hotels.see-all") : utilsFactory.getLabel("hotels.go-back");
                //    default:
                //        return utilsFactory.getLabel("hotels.go-back");
                //};
            };

            $scope.persistWizardModel = function (callback) {
                hotelsService.setHotelWizardModel($scope.wizardModel, callback);
            };

            $scope.back = function (state) {
                hotelsService.setHotelWizardModel($scope.wizardModel, function () { });
                var sectionid = $("[data-sectionid]").data("sectionid") || 0;
                switch (state) {
                    case "select-booking-type.book-stay":
                    case "select-booking-type":
                        hotelsService.setIsFromHotelDetails(1, function () {
                        });
                        window.location.href = utilsFactory.addPersistentQueryStringsParams("/" + jwtService.getGeography() + "/hotels" + (sectionid ? "/" + sectionid : ""));
                        break;
                   
                    case "select-booking-type.packages":
                        $state.go("select-booking-type");
                        break;
                    case "package-details":
                        $state.go("select-booking-type.packages");
                        break;
                };
                $scope.$parent.cleanGlobalErrors();
            };

            $scope.next = function (fromstate, params) {
                hotelsService.setHotelWizardModel($scope.wizardModel, function () { });

                switch (fromstate) {
                    case "select-booking-type":
                        if ($scope.wizardModel.ticketType && $scope.wizardModel.ticketType.name) {

                            if ($scope.wizardModel.ticketType.name.toLowerCase().indexOf("package") >= 0) {
                                $state.go("select-booking-type.packages");
                            } else {
                                $state.go("select-booking-type.book-stay");
                            }
                        }
                        break;
                    case "select-booking-type.book-stay":
                    case "select-booking-type.packages":
                        if (!params) break;
                        $state.go("package-details", params);
                }
                $scope.$parent.cleanGlobalErrors();
            };

            $scope.setTicketType = function (ticketType) {
                $scope.wizardModel.ticketType = ticketType;
            };

            $scope.getTicketTypeByName = function (name) {
                var foundTicketType = undefined;
                angular.forEach($scope.wizardModel.ticketTypes, function (ticketType) {
                    if (ticketType.name === name) {
                        foundTicketType = ticketType;
                    }
                });

                return foundTicketType;
            };

            $scope.setTicket = function (setTicket) {
                $scope.wizardModel.ticket = setTicket;
            };

            $scope.getTicket = function () {
                return $scope.wizardModel.ticket;
            };

            $scope.getProduct = function () {
                return $scope.wizardModel.roomsCriteria.product;
            };

            $scope.getOptionalExtras = function () {
                return $scope.wizardModel.roomsCriteria.optionalExtras;
            };

            $scope.saveSearchCriteria = function (criteria) {
                $scope.wizardModel.roomsCriteria = criteria;
                $scope.persistWizardModel();
            };

            $scope.getSearchCriteria = function () {
                return $scope.wizardModel.roomsCriteria;
            };

            $scope.savePackagesSearchCriteria = function (criteria) {
                $scope.wizardModel.packagesCriteria = criteria;
            };

            $scope.getPackagesSearchCriteria = function () {
                return $scope.wizardModel.packagesCriteria;
            };

            $scope.setSelectedPackage = function (selectedPackage) {
                $scope.wizardModel.packagesCriteria.selectedPackage = selectedPackage;
            };

            $scope.setBillingDetails = function (detail) {
                $scope.billingDetails = detail;
            };

            $scope.getBillingDetails = function () {
                return $scope.billingDetails;
            };

            $scope.getTicketTypes = function (callback) {
                var generalCtrl = $scope.$parent;

                var productCode = $scope.wizardModel.hotel.code ? $scope.wizardModel.hotel.code : $scope.requestArguments.productCode;
                var productCategory = $scope.wizardModel.hotel.productCategory ? $scope.wizardModel.hotel.productCategory : $scope.requestArguments.productCategory;
                var productStartDate = moment($scope.wizardModel.hotel.startDate);
                var travelDate = productStartDate.isValid ? productStartDate.format("YYYY-MM-DD") : $scope.requestArguments.travelDate;

                var params = {
                    urlPrefix: generalCtrl.getWebUrl(),
                    token: jwtService.getPrincipalToken(),
                    productCode: productCode,
                    productCategory: productCategory,
                    travelDate: travelDate
                };
                activitiesService.getTicketTypes(params, function (ticketTypesResult) {
                    if (ticketTypesResult.success) {
                        if (ticketTypesResult.data && ticketTypesResult.data.length > 0) {

                            $scope.wizardModel.ticketTypes = ticketTypesResult.data;
                            $scope.wizardModel.ticketType = $scope.wizardModel.ticketTypes[0];

                            hotelsService.setHotelWizardModel($scope.wizardModel, function () { });
                        }
                    } else {
                        console.log(ticketTypesResult.error);
                    }

                    // $scope.isLoading = false;
                    if (callback)
                        callback();
                });
            };

            $scope.setWizardModel = function (params) {
                $scope.isLoading = true;

                var getProduct = activitiesService.getProductDescriptionByCode; // params.isDefaultDate ?  : hotelsService.getHotelProductWithPackages;

                getProduct(params, function (result) {
                    if (!result || !result.data || !result.success) {
                        $scope.isLoading = false;
                        taskFactory.addTask("SelectedHotelChanged", { name: "No product found" });
                        return;
                    }
                  
                    var hotelResult = result.data;
                    if (!hotelResult.products[0]) {
                        console.log("Error! No product returned.");
                        $scope.isLoading = false;
                        taskFactory.addTask("SelectedHotelChanged", {name:"No product found"});
                        return;
                    }
                    if (hotelResult.products[0].productDescriptions && hotelResult.products[0].productDescriptions.ibePhoneNumberOverride) {
                        $rootScope.customprodphone = hotelResult.products[0].productDescriptions.ibePhoneNumberOverride;
                    }

                    var prodDate = moment(hotelResult.products[0].startDate);
                    var passDate = moment(params.travelDate);
                    var setDate = (params.isDefaultDate && prodDate.isValid() ? (prodDate >= passDate ? prodDate : passDate) : passDate);
                    if (setDate < jwtService.getServerMomentDate()) setDate = jwtService.getServerMomentDate();

                    params.travelDate = setDate.format("YYYY-MM-DD");

                    if (!hotelResult.products[0].startDate) {
                        hotelResult.products[0].startDate = params.travelDate;
                    }
  
                    hotelsService.setSelectedHotel(hotelResult.products[0], function (setHotelResult) {

                        $scope.wizardModel.hotel = hotelResult.products[0];
                        /*$scope.wizardModel.hotel.price = 0;
                        if ($scope.wizardModel.hotel.units && $scope.wizardModel.hotel.units.length > 0) {
                            $scope.wizardModel.hotel.price = _.min($scope.wizardModel.hotel.units, function (unit) {
                                return unit.price;
                            }).price;
                        }*/
                        if (!$scope.wizardModel.roomsCriteria.product) {
                            $scope.wizardModel.roomsCriteria.product = $scope.wizardModel.hotel;
                        }
                        hotelsService.setHotelWizardModel($scope.wizardModel, function () {
                            if (setHotelResult.success) {
                                $scope.getTicketTypes(function () {
                                    taskFactory.addTask("SelectedHotelChanged", $scope.wizardModel.hotel);
                                });
                            } else {
                                taskFactory.addTask("SelectedHotelChanged", $scope.wizardModel.hotel);
                            }
                            setTimeout(function () {
                                $scope.isLoading = false;
                            });
                        });
                    });
                });
            };

            $scope.setTokenAndWizardModel = function (params) {
                if (!params.token) {
                    jwtService.setPrincipalTokenAsync(params.urlPrefix, $scope.$parent.trackingInfo, function (newToken) {
                        params.token = newToken;
                        $scope.setWizardModel(params);
                    });
                } else {
                    $scope.setWizardModel(params);
                }
            };

            $scope.getProductDate = function (date) {
                return !date ? date : (date.toLowerCase().indexOf("t") > 0 ? date.substring(0, date.toLowerCase().indexOf("t")) : date);
            };


            $scope.init = function () {
                $scope.isLoading = true;
                hotelsService.getHotelWizardModel(function (result) {
                    $scope.isLoading = false;
                    var selectedHotel = $scope.getPrevHotel();
                   
                    $scope.requestArguments.travelDate = $scope.requestArguments.isDefaultDate !== "1" || (!selectedHotel || !selectedHotel.startDate) ? $scope.requestArguments.travelDate : $scope.getProductDate(selectedHotel.startDate);
                    if (jwtService.getServerMomentDate() > moment($scope.requestArguments.travelDate)) {
                        $scope.requestArguments.travelDate = (!selectedHotel || !selectedHotel.startDate) ? jwtService.getServerStrDate() : $scope.getProductDate(selectedHotel.startDate);
                    }

                    var params = {
                        urlPrefix: $scope.$parent.getWebUrl(),
                        token: undefined,
                        productCode: $scope.requestArguments.productCode,
                        productCategory: $scope.requestArguments.productCategory ? $scope.requestArguments.productCategory : "",
                        travelDate: $scope.requestArguments.travelDate,
                        nights: "1",
                        adults: "2",
                        isDefaultDate: $scope.requestArguments.isDefaultDate === "1"
                    };
                    var token = jwtService.getPrincipalToken();

                    params.token = token;
                    //check the date
                    var modelStartDate = (result.data && result.data.hotel) ? $scope.getProductDate(result.data.hotel.startDate) : undefined;
                    var sameDate = modelStartDate && $scope.getProductDate($scope.requestArguments.travelDate) === modelStartDate;

                    if (!sameDate||!result.data || !result.data.hotel || !result.data.ticketTypes || !result.data.ticketTypes.length) {
                        hotelsService.removeHotelWizardModel(function () { });
                        $scope.setTokenAndWizardModel(params);
                    }
                    else if (result.data.hotel.code !== $scope.requestArguments.productCode) {
                        hotelsService.removeHotelWizardModel(function () { });
                        $scope.setTokenAndWizardModel(params);
                    }
                    else {
                        $scope.wizardModel = result.data;
                        if ($scope.wizardModel.hotel.productDescriptions && $scope.wizardModel.hotel.productDescriptions.ibePhoneNumberOverride) {
                            $rootScope.customprodphone = $scope.wizardModel.hotel.productDescriptions.ibePhoneNumberOverride;
                        }

                        hotelsService.setSelectedHotel($scope.wizardModel.hotel, function (setHotelResult) {
                            taskFactory.addTask("SelectedHotelChanged", $scope.wizardModel.hotel);
                            //$rootScope.$broadcast("SelectedHotelChanged", $scope.wizardModel.hotel);
                        });
                    }
                });
            };

            $rootScope.$broadcast("hotelDetailsCtrlInitialized");

            $scope.$on("generalControllerInitilized", function (event, data) {
                var t = jwtService.getPrincipalToken();

                if (t && t.length > 0) {
                    $scope.init();
                } else {
                    $scope.isLoading = true;
                    $scope.$on('getPrincipalToken', function (event, args) {
                        $scope.init();
                    });
                };
            });
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("hotelSelectBookingTypeCtrl", [
       "utilsFactory", "hotelsService", "$scope", "$state", "taskFactory", "$rootScope",
       function (utilsFactory,hotelsService, $scope, $state, taskFactory, $rootScope) {
           $.material.init();
           $scope.utils = utilsFactory;
           $scope.mainProduct = {};
           $scope.selectedTicketTypeName = undefined;
           $scope.$on("mergeGlobalErros", function (event, args) {
               $scope.isLoading = false;
           });
           $scope.hideTooltips = function () {
               jQuery("[data-toggle=\"tooltip\"]").tooltip("hide");
           };
           $scope.ticketTypes = function () {
               if ($scope.$parent) {
                   return $scope.$parent.wizardModel.ticketTypes;
               } else {
                   return [];
               }
           };

           $scope.getTicketTypeIfOne = function () {
               var ticketTypes = $scope.ticketTypes();
               return ((ticketTypes || "").length === 1) ? ticketTypes[0] : undefined;
           };

           $scope.getBackButtonLabel = function () {
               var cuurentStateName = $state.$current.name;
               return $scope.$parent.getButtonLabel(cuurentStateName, $scope.getTicketTypeIfOne());
           };
           $scope.backButtonLabel = $scope.getBackButtonLabel();

           $scope.handleBack = function () {
               var singleTicketType = $scope.getTicketTypeIfOne();
               if (singleTicketType) {
                   $scope.$parent.back("select-booking-type");
               } else {
                   if ($scope.$parent) {
                       var cuurentStateName = $state.$current.name;
                       $scope.$parent.back(cuurentStateName);
                       // $scope.backButtonLabel = $scope.getBackButtonLabel();
                   }
               }
           };

           $scope.showNext = false;

           $scope.handleNext = function () {
               if ($scope.$parent) {
                   var getTicket = $scope.$parent.getTicketTypeByName($scope.selectedTicketTypeName);
                   if (getTicket) {
                       $scope.$parent.setTicketType(getTicket);
                   }
                   var cuurentStateName = $state.$current.name;
                   $scope.$parent.next(cuurentStateName);

                   $scope.backButtonLabel = $scope.getBackButtonLabel();
               }
           };



           $scope.selectedTicketTypeName = $scope.$parent && $scope.$parent.wizardModel.ticketType ? $scope.$parent.wizardModel.ticketType.name : undefined;
           $scope.showNext = ($scope.selectedTicketTypeName || "").length;

           $scope.changeSelectedTicket = function (ticketTypeName) {
               $scope.hideTooltips();
               $scope.showNext = true;
               $scope.selectedTicketTypeName = ticketTypeName;
               $scope.handleNext();
           };

           $scope.$watch(function () {
               var tt = $scope.mainProduct;
               return tt ? tt.length : 0;
           }, function () {
               setTimeout(function () {
                   jQuery(window).resize();
               }, 0);
           });

           $scope.$watch(function () {
               var tt = $scope.$parent.wizardModel.ticketTypes;
               return tt ? tt.length : 0;
           }, function () {
               $scope.goNextIfOneSelectTickets();
               setTimeout(function () {
                   jQuery(window).resize();
               }, 0);
           });

           $scope.goNextIfOneSelectTickets = function (stateName,fromstateName) {
               if (!stateName) stateName = $state.$current.name;
              
               if (stateName === "select-booking-type") {
                   if (fromstateName == "select-booking-type.book-stay") {
                       $scope.handleBack();
                   } else {
                       var ticketType = $scope.getTicketTypeIfOne();
                       if (ticketType) {
                           $scope.changeSelectedTicket(ticketType.name);
                           $scope.handleNext();
                       }
                   }
               }
           };
           $rootScope.$on("$stateChangeSuccess",
             function (event, toState, toParams, fromState, fromParams) {
                 $scope.backButtonLabel = $scope.$parent.getButtonLabel(toState.name);
                 
                 $scope.goNextIfOneSelectTickets(toState.name, fromState.name);
             });

           $scope.init = function () {
               $scope.goNextIfOneSelectTickets();
               hotelsService.getSelectedHotel(function (result) {
                   if (result.success && result.data) {
                       $scope.mainProduct = result.data;
                   }
               });
           };
           $scope.init();
           $scope.initialized = false;
           $scope.$watch(function () {
               return taskFactory.task;
           },
           function (val) {
               if (val && val.name) {
                   $scope.mainProduct = val.data;
                   $scope.initialized = true;
               }
           }, true);

       }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("hotelsFilterCtrl", [
       "utilsFactory", "$scope", "$http", "$element", "localStorageService", "jwtService", "hotelsService", "taskFactory", "$timeout", function (utilsFactory, $scope, $http, $element, localStorageService, jwtService, hotelsService, taskFactory, $timeout) {

           $scope.utils = utilsFactory;
           TweenMax.ticker.useRAF(false);
           $scope.hotels = [];
           $scope.categories = [];
           $scope.locations = [];
           $scope.priceRanges = [];
           $scope.detailsUrl = $($element).attr("data-hotel-details") || "";

           $scope.geographyCode = jwtService.getGeography();

           $scope.filter = {
               selectedCategory: null,
               selectedLocation: null,
               selectedPriceRange: null
           };

           $scope.resultfilter = {
               selectedCategory: null,
               selectedLocation: null,
               selectedPriceRange: null
           };

           $scope.orderBy = {
               predicate: "ibeSortOrder",
               reverse: false
           };

           $scope.listIsLoading = false;
           $scope.showNavArrows = false;

           $scope.$on("mergeGlobalErros", function (event, args) {
               $scope.isLoading = false;
               $scope.listIsLoading = false;
           });
           $scope.setHotelsName = function () {
               _.each($scope.hotels, function (hotel) {
                   hotel.name = (hotel.productDescriptions && (hotel.productDescriptions.titles || "").length) ? hotel.productDescriptions.titles[0] : hotel.name;
               });
           };
           $scope.handleFilter = function (e) {
               if ($scope.listIsLoading) return;
               hotelsService.persistHotelsFilters({
                   hotels: $scope.hotels,
                   filters: $scope.filter,
                   locations: $scope.locations,
                   categories: $scope.categories,
                   priceRanges: $scope.priceRanges,
                   orderBy: $scope.orderBy
               }, function (result) {
                   if (e) {
                       //slide up
                       $(e.currentTarget).parent().parent().prev().click();
                   }

                   if (result.success) {
                       $scope.resultfilter.selectedCategory = result.data.filters.selectedCategory;
                       $scope.resultfilter.selectedPriceRange = result.data.filters.selectedPriceRange;
                       $scope.resultfilter.selectedLocation = result.data.filters.selectedLocation;
                   } else {
                       console.log(result.error);
                   }
               });
           };

           $scope.addAvailableStartingDate = function () {
               if (!$scope.hotels) return;
               var currDate = jwtService.getServerMomentDate();

               _.each($scope.hotels, function (hotel) {
                   if (!hotel.startDate) return;

                   var hotelStartDate = moment(hotel.startDate);
                   if (hotelStartDate > currDate) {
                       hotel.availableStartingDate = hotelStartDate.format("DD MMMM YYYY");
                   }
               });
           };

           $scope.goToProductDetailsIfSingle = function () {
               var sectionid = $("[data-sectionid]").data("sectionid") || 0;
               if (($scope.hotels || "").length === 1) {
                   if (hotelsService.getIsFromHotelDetails()) {
                       hotelsService.setIsFromHotelDetails(0, function () {
                           hotelsService.setIsFromFilters(1, function () { });
                           window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
                       });
                       return true;
                   }
                   var firstProduct = $scope.hotels[0];
                   window.location.href = utilsFactory.addPersistentQueryStringsParams( "/" + $scope.geographyCode + $scope.detailsUrl.trim().replace(/[\/\\]$/, "") + "/"
                        + (sectionid ? sectionid + "/" : "")
                     + firstProduct.code + "/" + firstProduct.productCategory);
                   return true;
               }
               hotelsService.setIsFromHotelDetails(0, function () { });
               return false;
           };

           $scope.getHotels = function (e) {
               if ($scope.listIsLoading) return;
               if (e) {
                   $(e.currentTarget).parent().parent().prev().click();
               }
               var sectionid = $("[data-sectionid]").data("sectionid") || 0;
       
               $scope.resultfilter.selectedCategory = $scope.filter.selectedCategory;
               $scope.resultfilter.selectedPriceRange = $scope.filter.selectedPriceRange;

               $scope.resultfilter.selectedLocation = $scope.filter.selectedLocation;

               var token = jwtService.getPrincipalToken();
               //var date = new Date();
               // date.setDate(date.getDate() + 1); //TODO: Remove when fixed
               // var myDate = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
               $scope.listIsLoading = true;

               hotelsService.getPersistedHotelsFilters(sectionid,function (filtersResult) {
                   if (filtersResult.success && filtersResult.data) {
                       $scope.hotels = filtersResult.data.hotels;
                       $scope.addAvailableStartingDate();
                       $scope.setHotelsName();
                       setTimeout(function () {
                           jQuery(".scroll-list[list-scroll]").trigger("checkArrows");
                       }, 0);
                       if (!$scope.goToProductDetailsIfSingle()) {
                           $scope.listIsLoading = false;
                       }
                   } else {
                       hotelsService.getHotelsByDate({id:sectionid, token: token, date: jwtService.getServerStrDate(), urlPrefix: $scope.$parent.getWebUrl() }, function (result) {
                           if (result.success) {
                               $scope.hotels = result.data.products;
                               $scope.setHotelsName();
                               hotelsService.persistHotelsFilters(sectionid,{
                                   hotels: $scope.hotels,
                                   filters: $scope.filter,
                                   locations: $scope.locations,
                                   categories: $scope.categories,
                                   priceRanges: $scope.priceRanges,
                                   orderBy: $scope.orderBy
                               }, function() {
                                   $scope.addAvailableStartingDate();
                               });

                           } else {
                               console.log(result.error);
                           }
                           if (!$scope.goToProductDetailsIfSingle()) {
                               $scope.listIsLoading = false;
                               setTimeout(function () {
                                   jQuery(".scroll-list[list-scroll]").trigger("checkArrows");
                               }, 0);
                           }
                       });
                   }
               });

           };
           $scope.getHotelsFilters = function (callback) {
               $scope.listIsLoading = true;
               var sectionid = $("[data-sectionid]").data("sectionid") || 0;

               hotelsService.getPersistedHotelsFilters(sectionid,function (filtersResult) {
                   if (filtersResult.success && filtersResult.data) {
                       $scope.locations = filtersResult.data.locations;
                       $scope.priceRanges = filtersResult.data.priceRanges;
                       $scope.categories = filtersResult.data.categories;
                       //$scope.orderBy = filtersResult.data.orderBy;

                       // $scope.resultfilter.selectedCategory = $scope.filter.selectedCategory = filtersResult.data.filters.selectedCategory;
                       // $scope.resultfilter.selectedPriceRange = $scope.filter.selectedPriceRange = filtersResult.data.filters.selectedPriceRange;
                       // $scope.resultfilter.selectedLocation = $scope.filter.selectedLocation = filtersResult.data.filters.selectedLocation;
                       $scope.listIsLoading = false;
                       if (callback) {
                           callback();
                       }
                   } else {
                       hotelsService.getHotelsFilters({ urlPrefix: $scope.$parent.getWebUrl(), token: jwtService.getPrincipalToken() }, function (result) {
                           if (result.success) {
                               $.each(result.data, function (key, value) {
                                   if (key.toLowerCase().indexOf("location") >= 0) {
                                       $scope.locations = value;
                                   } else if (key.toLowerCase().indexOf("pricerangefilters") >= 0) {
                                       $scope.priceRanges = value;
                                   } else if (key.toLowerCase().indexOf("marketingtags") >= 0) {
                                       $scope.categories = value;
                                   }
                               });
                           } else {
                               console.log(result.error);
                           }

                           $scope.listIsLoading = false;

                           if (callback) {
                               callback();
                           }
                       });
                   }
               });
           };

           $scope.init = function () {
               $scope.listIsLoading = false;
               $scope.geographyCode = jwtService.getGeography();
               $scope.getHotelsFilters($scope.getHotels);
               jwtService.setProductCategory("Hotels");

               if (!$scope.mainSectionId) {
                   window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
                   return;
               }
           };

           if ($scope.$parent.hasMainSections()) {
               $scope.listIsLoading = true;
               var initialized = false;

               $scope.$watch(function () {
                   return taskFactory.filtersTask;
               },
                   function (val) {
                       if (!val || !val.name || initialized) return;
                       initialized = true;

                       $timeout(function () {
                           $scope.listIsLoading = false;
                           $scope.init();
                       });
                   }, true);
               //$scope.$on("mainSectionReady", function(event, args) {
               //    $scope.listIsLoading = false;
               //    $scope.init();
               //});
           } else {
               var t = jwtService.getPrincipalToken();
               if (t && t.length > 0) {
                   $scope.init();
               } else {
                   $scope.listIsLoading = true;
                   $scope.$on("getPrincipalToken", function (event, args) {
                       $scope.listIsLoading = false;
                       $scope.init();
                   });
               }
           }

           $scope.$on("geographyCodeChanged", function (event, args) {
               jwtService.clearStorage();
               $scope.init();
               $scope.geographyCode = jwtService.getGeography();
           });

           $scope.selectCategory = function (category) {
               $scope.filter.selectedCategory = category;
           };
           $scope.selectLocation = function (location) {
               $scope.filter.selectedLocation = location;
           };
           $scope.selectPriceRange = function (priceRange) {
               $scope.filter.selectedPriceRange = priceRange;
           };

           $scope.selectHotel = function (product, $event) {
               event.preventDefault();
               if (localStorageService.isSupported) {
                   localStorageService.set("prevHotel", product);
               }
               if ($event && $event.currentTarget) {
                   var params = {
                       urlPrefix: ($("body").data("weburl") ? $("body").data("weburl") : ""),
                       productCode: product.code,
                       productTitle: (product.productDescriptions && product.productDescriptions.titles) ? product.productDescriptions.titles[0] : product.name
                   };

                   jwtService.setCurrentProduct(params, function (result) {
                       var urlToRedirect = jQuery($event.currentTarget).attr("href");
                       window.location.href = utilsFactory.addPersistentQueryStringsParams( urlToRedirect);
                   });
               }
           };

           $scope.order = function (predicate) {
               $scope.orderBy.reverse = ($scope.orderBy.predicate === predicate) ? !$scope.orderBy.reverse : false;
               $scope.orderBy.predicate = predicate;

               hotelsService.persistHotelsFilters({
                   hotels: $scope.hotels,
                   filters: $scope.filter,
                   locations: $scope.locations,
                   categories: $scope.categories,
                   priceRanges: $scope.priceRanges,
                   orderBy: $scope.orderBy
               }, function (result) {
                   //do nothing
               });

               //close the sort panel
               setTimeout(function () {
                   $($element).find(".filter-toggle:eq(1)").click();
               }, 300);
           };
       }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("packageHotelBookStayCtrl", [
        "utilsFactory", "$scope", "$state", "$stateParams", "$http", "$uibModal", "productsFactory", "hotelsService", "$rootScope", "validHelper", "shoppingCartService", "jwtService", "taskFactory", "$timeout", "$element",
        function (utilsFactory, $scope, $state, $stateParams, $http, $uibModal, productsFactory, hotelsService, $rootScope, validHelper, shoppingCartService, jwtService, taskFactory, $timeout, $element) {

            var webUrl = $("body").data("weburl") ? $("body").data("weburl") : "";
            $scope.availableHotelsCountMessage = $("body").attr("data-available-hotels-count-message") ? $("body").attr("data-available-hotels-count-message") : "";
            $scope.maxAdults = $("body").attr("data-max-hotels-available-adults") ? parseInt($("body").attr("data-max-hotels-available-adults")) : 5;
            $scope.maxChildren = $("body").attr("data-max-hotels-available-children") ? parseInt($("body").attr("data-max-hotels-available-children")) : 5;
            $scope.maxNights = $("body").attr("data-max-hotels-available-nights") ? parseInt($("body").attr("data-max-hotels-available-nights")) : 14;

            $scope.maxUnitOccupancyPerUnit = 0;
            $scope.maxUnitAdditionalChildren = 0;

            $scope.utils = utilsFactory;
            $scope.getAgeRangeInfo = function (secondaryLabel) {
                if (!$scope.anonymUser) return undefined;
                var selectedLanguage = $scope.anonymUser.selectedLanguage;

                return $scope.utils.getAnonymUserLabel((selectedLanguage && selectedLanguage.userlabels) || $scope.anonymUser, "hotels_ageRangesInfo", secondaryLabel) ||
                $scope.utils.getAnonymUserLabel((selectedLanguage && selectedLanguage.userlabels) || $scope.anonymUser, "ageRangesInfo", secondaryLabel);
            };

            $.material.init();

            $scope.validHelper = validHelper;

            function strRange(min, max) {
                function toString(val) {
                    return val.toString();
                }

                return _.map(_.range(min, max), toString);
            }

            var timeoutID = undefined;

            function resizeSliderPanel() {
                window.clearTimeout(timeoutID);
                timeoutID = setTimeout(function () {
                    jQuery(window).resize();
                }, 100);
            }

            $scope.maxLimitAvailableRooms = $("body").attr("data-max-limit-available-rooms") || 0;

            if ($scope.maxLimitAvailableRooms) {
                $scope.maxLimitAvailableRooms = parseInt($scope.maxLimitAvailableRooms);
            }

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });
            if ($("#daterangeHotel").length) {
                $scope.daterangepicker = $("#daterangeHotel").daterangepicker({
                    singleDatePicker: true,
                    minDate: jwtService.getServerMomentDate(),//.add("days", 1),
                    showDropdowns: true,
                    locale: {
                        format: shoppingCartService.getDateFormat()
                    }
                });

                $scope.daterangepicker.on("apply.daterangepicker", function (ev, picker) {
                    $scope.persistCriteria();

                    $scope.isLoading = true;

                    setTimeout(function () {
                        $scope.$apply();
                    });
                    window.Paperboy && window.Paperboy.ready(function () {
                        window.Paperboy.PriceCheck && window.Paperboy.PriceCheck.destroy();
                    });

                    $scope.$parent.getPackage(function (newPackage) {
                        $scope.isLoading = false;
                        if (newPackage && newPackage.details && (newPackage.details.components || "").length) {
                            for (var i = 0; i < newPackage.details.components.length; i++) {
                                var comp = newPackage.details.components[i];
                                if (comp && comp.product && comp.product.code.toLowerCase().trim() === $stateParams.packageProductCode.toLowerCase().trim()) {
                                    $scope.product = comp.product;
                                    $scope.comp = comp;
                                    $scope.fillFiltersDropdowns();                                    
                                    break;
                                }
                            }
                        }

                        $scope.showAddToCard = !newPackage.showFinal;
                        $scope.package = newPackage;

                        $scope.availableNights = strRange(parseInt($scope.criteria && $scope.criteria.defaultNights) || 1, $scope.maxNights + 1);// $scope.package.details.duration
                        setTimeout(function () {
                            $scope.$apply();
                            resizeSliderPanel();
                        });

                    }, $scope.daterangepicker.val());
                });
            }
            $scope.isLoading = true;

            $scope.citeria = null;

            $scope.selectedAdults = "2";
            $scope.selectedChild = "0";
            $scope.selectedNights = "1";

            $scope.availableAdults = strRange(1, $scope.maxAdults + 1);
            $scope.availableChild = strRange(0, $scope.maxChildren + 1);
            $scope.availableNights = strRange(1, $scope.maxNights + 1);

            $scope.getPerTotalPriceLabel = function () {
                if (!$scope.comp) return "";

                if ($scope.comp.duration <= 1) return $scope.utils.getLabel("hotels.per-night");
                return $scope.utils.getLabel("hotels.per-total-nights").replace("{0}",
                    $scope.comp.duration);
            };

            $scope.getAvailableUnitsNumber = function () {
                var available = 0;

                if (!$scope.product || !$scope.product.units) return 0;

                _.each($scope.product.units, function (unit) {
                    available += $scope.isUnitInvalid(unit) ? 0 : 1;
                });

                return available;
            };
            $scope.isUnitInvalid = function (unit) {
                var adultsValid = $scope.selectedAdults <= unit.maxOccupancyPerUnit;
                var childValid = $scope.selectedChild <= unit.maxOccupancyPerUnit - $scope.selectedAdults + unit.maxAdditionalChildren;
                return unit.availability === 0 || !adultsValid || !childValid;
            };

            $scope.loadJS = function (url, implementationCode, location) {
                //url is URL of external file, implementationCode is the code
                //to be called from the file, location is the location to 
                //insert the <script> element

                var scriptTag = document.createElement('script');
                scriptTag.src = url;

                scriptTag.onload = implementationCode;
                scriptTag.onreadystatechange = implementationCode;

                location.appendChild(scriptTag);
            }; 

            $scope.fillFiltersDropdowns = function () {
                return;
                if (!$scope.product || !$scope.product.units) {
                    $scope.availableAdults = ["1"];
                    $scope.availableChild = ["0"];
                    $scope.selectedAdults = $scope.availableAdults[0];
                    $scope.selectedChild = $scope.availableChild[0];
                } else {
                    var maxChildUnit =
                        _.max($scope.product.units, function (unit) {
                            return unit.availability < 1 || unit.maxAdditionalChildren < 1 ? 0 : unit.maxAdditionalChildren;
                        });

                    $scope.maxUnitAdditionalChildren = maxChildUnit ? maxChildUnit.maxAdditionalChildren : 0;

                    var maxOccupUnit =
                        _.max($scope.product.units, function (unit) {
                            return unit.availability < 1 || unit.maxOccupancyPerUnit < 1 ? 0 : unit.maxOccupancyPerUnit;
                        });
                    $scope.maxUnitOccupancyPerUnit = maxOccupUnit ? maxOccupUnit.maxOccupancyPerUnit : 1;

                    $scope.availableAdults = strRange(1, ($scope.maxUnitOccupancyPerUnit + 1));
                    if ($scope.availableAdults.indexOf($scope.selectedAdults.toString()) < 0) {
                        $scope.selectedAdults = $scope.availableAdults[0];
                    }

                    $scope.availableChild = strRange(0, (($scope.maxUnitOccupancyPerUnit - $scope.selectedAdults + $scope.maxUnitAdditionalChildren) + 1));
                    if ($scope.availableChild.indexOf($scope.selectedChild.toString()) < 0) {
                        $scope.selectedChild = $scope.availableChild[0];
                    }
                    $scope.adultsChanged(true);
                    $scope.childChanged(true);
                }
            };

            $scope.persistCriteria = function () {
                // don't persist because there are no filter on this page anymore
                //$scope.$parent.persistCriteriaParams($("#daterangeHotel").length ? $("#daterangeHotel").val() : undefined, $scope.selectedAdults, $scope.selectedChild, null, $scope.selectedNights);
            };

            $scope.nightsChanged = function (nights) {
                //$scope.selectedNights = nights;
                $scope.persistCriteria();
                $scope.daterangepicker.trigger("apply.daterangepicker");
            };


            $scope.adultsChanged = function (preventRequest) {
                //disabled because of package details conflict
                //var maxChildren = $scope.maxUnitOccupancyPerUnit - $scope.selectedAdults + $scope.maxUnitAdditionalChildren;
                //$scope.availableChild = strRange(0, maxChildren + 1);
                //if ($scope.availableChild.indexOf($scope.selectedChild.toString()) < 0) {
                //    $scope.selectedChild = $scope.availableChild[0];
                //}
                $scope.persistCriteria();
                if (!preventRequest)
                    $scope.daterangepicker.trigger("apply.daterangepicker");
            };

            $scope.childChanged = function (preventRequest) {

                //disabled because of package details conflict
                //var diffChild = $scope.maxUnitAdditionalChildren - $scope.selectedChild >= 0 ? 0 : $scope.selectedChild - $scope.maxUnitAdditionalChildren;
                //var maxAdults = $scope.maxUnitOccupancyPerUnit - diffChild;
                //$scope.availableAdults = strRange(1, maxAdults + 1);
                //if ($scope.availableAdults.indexOf($scope.selectedAdults.toString()) < 0) {
                //    $scope.selectedAdults = $scope.availableAdults[0];
                //}
                $scope.persistCriteria();
                if (!preventRequest)
                    $scope.daterangepicker.trigger("apply.daterangepicker");
            };

            $scope.getUnitDescription = function (unit) {
                if (!unit || !unit.productDescriptions || !unit.productDescriptions.descriptions.length) return null;
                if (unit.productDescriptions.descriptions.length >= 2) {
                    return unit.productDescriptions.descriptions[1];
                }
                return unit.productDescriptions.descriptions[0];
            };

            $scope.goToDetails = function () {
                var param = {
                    packageCode: $scope.package.code ? $scope.package.code : $stateParams.packageCode,
                    date: moment($scope.getCriteria().date, shoppingCartService.getDateFormat()).format("YYYY-MM-DD")
                };

                $state.go("package-details", param);
            };

            $scope.selectUnit = function (selectedUnit) {
                $scope.comp.numberOfNights = $scope.selectedNights;
                var nights = parseInt($scope.selectedNights);
                var dateObj = $("#daterangeHotel").length ? moment($("#daterangeHotel").val(), shoppingCartService.getDateFormat()) :
                    moment($scope.product.startDate);
                if (nights) {
                    dateObj.add(nights, "day");
                }

                $scope.comp.endDate = dateObj.format("YYYY-MM-DD");

                $scope.product.selectedUnit = selectedUnit;
                $scope.product.displayTypeId = 2;
                $scope.$parent.updateSelectedPackage($scope.criteria.selectedPackage);
                $scope.$parent.nextWizard($stateParams.packageProductCode.toLowerCase().trim());
            };

            var initialized = false;
            $scope.anonymUser = undefined;


            $scope.formatDate = function (date, format) {
                return moment(date).format(format ? format : "YYYY-MM-DD");
            };

            $scope.init = function () {
                $scope.anonymUser = $scope.$parent.anonymUser;//packageDetails ctrl

                $scope.criteria = $scope.$parent.getCriteria();

                $scope.isLoading = false;

                if ($("#daterangeHotel").length) {
                    var date = moment($stateParams.date, "YYYY-MM-DD").format(shoppingCartService.getDateFormat());
                    $("#daterangeHotel").val(date);
                    $("#daterangeHotel").data().daterangepicker.startDate = moment(date, shoppingCartService.getDateFormat());
                    $("#daterangeHotel").data().daterangepicker.endDate = moment(date, shoppingCartService.getDateFormat());
                }

                if ($scope.criteria && $scope.criteria.selectedPackage) {

                    $scope.availableNights = strRange(parseInt($scope.criteria.defaultNights) || 1, $scope.maxNights + 1);//$scope.criteria.selectedPackage.details.duration

                    for (var i = 0; i < $scope.criteria.selectedPackage.details.components.length; i++) {
                        var comp = $scope.criteria.selectedPackage.details.components[i];
                        if (comp && comp.product && comp.product.code.toLowerCase().trim() === $stateParams.packageProductCode.toLowerCase().trim()) {
                            $scope.product = comp.product;
                            $scope.comp = comp;
                            resizeSliderPanel();
                            
                            break;
                        }
                    }
                }

                $scope.showAddToCard = !$scope.criteria.selectedPackage.showFinal;

                if ($scope.criteria.adults) {
                    $scope.selectedAdults = $scope.criteria.adults.toString();
                }

                if ($scope.criteria.children) {
                    $scope.selectedChild = $scope.criteria.children.toString();
                }

                if ($scope.criteria.nights) {
                    $scope.selectedNights = $scope.criteria.nights.toString();
                }

                $scope.fillFiltersDropdowns();
                $scope.persistCriteria();
                if (!$scope.product || !$scope.product.units || $scope.product.units.length === 0) {
                    // $scope.daterangepicker.trigger("apply.daterangepicker");
                    //to do go back to the package
                }
                resizeSliderPanel();
                setTimeout(function () {
                    jQuery($element).find("select").change();
                }, 0);
            };



            $scope.$watch(function () {
                return taskFactory.packageTask;
            },
                function (val) {
                    if (!val || initialized) return;
                    initialized = true;
                    $timeout($scope.init);
                }, true);

            //var t = jwtService.getPrincipalToken();

            //if (t && t.length > 0) {
            //    $scope.init();
            //} else {
            //    $scope.isLoading = true;
            //    $scope.$on("getPrincipalToken", function (event, args) {
            //        $scope.init();
            //    });
            //};

        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("packageComponentStepCtrl", [
        "utilsFactory", "currenciesService", "$scope", "$state", "$stateParams", "$http", "$uibModal", "productsFactory", "hotelsService", "$rootScope", "validHelper", "shoppingCartService", "jwtService", "taskFactory", "$timeout", "$element",
        function (utilsFactory, currenciesService, $scope, $state, $stateParams, $http, $uibModal, productsFactory, hotelsService, $rootScope, validHelper, shoppingCartService, jwtService, taskFactory, $timeout, $element) {

            var webUrl = $("body").data("weburl") ? $("body").data("weburl") : "";
            var unitcodeswithexpandedtilesdescriptionbydefault = $("div[ng-controller='activityDetailsCtrl']").data("unitcodeswithexpandedtilesdescriptionbydefault");
            $scope.shouldHideDate = function () {
                // console.log("hide Date picker");
                return $scope.$parent.hideDatePicker;
            };

            $scope.isTileDescriptionExpandedByDefault = function (unitCode) {
                return unitCode && (unitcodeswithexpandedtilesdescriptionbydefault || []).indexOf(unitCode) >= 0;
            };

            $scope.utils = utilsFactory;


            $.material.init();

            $scope.validHelper = validHelper;

            var timeoutID = undefined;

            function resizeSliderPanel() {
                window.clearTimeout(timeoutID);
                timeoutID = setTimeout(function () {
                    jQuery(window).resize();
                }, 100);
            }

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            $scope.isLoading = true;

            $scope.citeria = null;

            $scope.selectedAdults = "2";
            $scope.selectedChild = "0";
            $scope.selectedNights = "1";

            $scope.selectCurrency = function (currency) {
                $scope.selectedCurrency = currency;
                $scope.setSelectedCurrency($scope.selectedCurrency);

                currenciesService.setSelectedCurrencyCode(currency && currency.code);
            };

            $rootScope.$on("$stateChangeSuccess",
                function (event, toState, toParams, fromState, fromParams) {
                    $scope.selectedCurrency = $scope.getCurrencyBySelectedCode();
                    $scope.setSelectedCurrency($scope.selectedCurrency);
                });

            $scope.isUnitAvailable = function (unit) {//checkFlag=1-upload 2-download 3 - both default
                if (!unit) return false;

                var totalGuests = ($scope.criteria.adults || 0) + ($scope.criteria.child || 0) + ($scope.criteria.seniors || 0) + ($scope.criteria.students, 0) + ($scope.criteria.infants, 0);

                return unit.availability >= (totalGuests);
            };


            $scope.persistCriteria = function () {
                // don't persist because there are no filter on this page anymore
                //$scope.$parent.persistCriteriaParams($("#daterangeHotel").length ? $("#daterangeHotel").val() : undefined, $scope.selectedAdults, $scope.selectedChild, null, $scope.selectedNights);
            };

            $scope.getUnitDescription = function (unit) {
                if (!unit || !unit.productDescriptions || !unit.productDescriptions.descriptions.length) return null;
                if (unit.productDescriptions.descriptions.length >= 2) {
                    return unit.productDescriptions.descriptions[1];
                }
                return unit.productDescriptions.descriptions[0];
            };

            $scope.goToDetails = function () {
                var param = {
                    packageCode: $scope.package.code ? $scope.package.code : $stateParams.packageCode,
                    date: moment($scope.getCriteria().date, shoppingCartService.getDateFormat()).format("YYYY-MM-DD")
                };

                $state.go("package-details", param);
            };

            $scope.selectUnit = function (selectedUnit) {
                $scope.product.selectedUnit = selectedUnit;
                $scope.$parent.updateSelectedPackage($scope.criteria.selectedPackage);
                $scope.$parent.nextWizard($stateParams.packageProductCode.toLowerCase().trim());
            };

            var initialized = false;
            $scope.anonymUser = undefined;


            $scope.formatDate = function (date, format) {
                return moment(date).format(format ? format : "YYYY-MM-DD");
            };

            $scope.init = function () {
                $scope.anonymUser = $scope.$parent.anonymUser;//packageDetails ctrl

                $scope.criteria = $scope.$parent.getCriteria();

                $scope.isLoading = false;

                if ($scope.criteria && $scope.criteria.selectedPackage) {

                    for (var i = 0; i < $scope.criteria.selectedPackage.details.components.length; i++) {
                        var comp = $scope.criteria.selectedPackage.details.components[i];
                        if (comp && comp.product && comp.product.code.toLowerCase().trim() === $stateParams.packageProductCode.toLowerCase().trim()) {
                            $scope.product = comp.product;
                            $scope.comp = comp;
                            resizeSliderPanel();

                            break;
                        }
                    }
                }

                $scope.showAddToCard = !$scope.criteria.selectedPackage.showFinal && ($scope.criteria.selectedPackage.type != "CUSTOM");

                if ($scope.criteria.adults) {
                    $scope.selectedAdults = $scope.criteria.adults.toString();
                }

                if ($scope.criteria.children) {
                    $scope.selectedChild = $scope.criteria.children.toString();
                }

                if ($scope.criteria.nights) {
                    $scope.selectedNights = $scope.criteria.nights.toString();
                }


                $scope.persistCriteria();
                if (!$scope.product || !$scope.product.units || $scope.product.units.length === 0) {
                    // $scope.daterangepicker.trigger("apply.daterangepicker");
                    //to do go back to the package
                }
                resizeSliderPanel();
                setTimeout(function () {
                    jQuery($element).find("select").change();
                }, 0);
            };



            $scope.$watch(function () {
                return taskFactory.packageTask;
            },
                function (val) {
                    if (!val || initialized) return;
                    initialized = true;
                    $timeout($scope.init);
                }, true);

            //var t = jwtService.getPrincipalToken();

            //if (t && t.length > 0) {
            //    $scope.init();
            //} else {
            //    $scope.isLoading = true;
            //    $scope.$on("getPrincipalToken", function (event, args) {
            //        $scope.init();
            //    });
            //};

        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("packageDetailsCtrl", [
        "utilsFactory",
        "trackingService",
        "currenciesService",
        "activitiesService", "hotelsService", "transportationService", "$scope", "$state", "$stateParams",
        "$rootScope", "packagesService", "shoppingCartService",
        "jwtService", "$uibModal", "taskFactory", "$timeout", "productsFactory",
        function (utilsFactory, trackingService, currenciesService, activitiesService, hotelsService, transportationService, $scope, $state, $stateParams, $rootScope, packagesService, shoppingCartService, jwtService, $uibModal, taskFactory, $timeout, productsFactory) {

            //function setLocalParamsToFixState(){
            //    $timeout(function () {
            //        var newLocals = $state.$current.locals[localeName];
            //        previousLocals.$stateParams = newLocals.$stateParams;
            //        $state.$current.locals[localeName] = previousLocals;
            //    });
            //}

            //TweenMax.ticker.useRAF(true);
            $scope.utils = utilsFactory;
            $scope.getAgeRangeInfo = function (secondaryLabel) {
                if (!$scope.anonymUser) return undefined;
                var selectedLanguage = $scope.anonymUser.selectedLanguage;
                return ($scope.isHotelPackage() ? $scope.utils.getAnonymUserLabel((selectedLanguage && selectedLanguage.userlabels) || $scope.anonymUser, "hotels_ageRangesInfo", secondaryLabel) : "") ||
                    $scope.utils.getAnonymUserLabel((selectedLanguage && selectedLanguage.userlabels) || $scope.anonymUser, "ageRangesInfo", secondaryLabel);
            };

            var webUrl = $("body").data("weburl") ? $("body").data("weburl") : "";
            var unitcodeswithexpandedtilesdescriptionbydefault = $("div[ng-controller='activityDetailsCtrl']").data("unitcodeswithexpandedtilesdescriptionbydefault");

            $scope.isTileDescriptionExpandedByDefault = function (unitCode) {
                return unitCode && (unitcodeswithexpandedtilesdescriptionbydefault || []).indexOf(unitCode) >= 0;
            };

            $scope.package = undefined;

            //data-autoselectavailabledateforpackagecodes
            $scope.autoSelectAvailableDateForPackageCodes=($("body").attr("data-autoselectavailabledateforpackagecodes") || "").split("|"),
            $scope.autoLoadIndex = 0;
            $scope.topAutoLoadLimit = 3;

            $scope.backButtonLabel = utilsFactory.getLabel("packages.go-back");

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            $scope.noTime = { key: "Any Time", value: null };

            $scope.maxNights = $("body").attr("data-max-hotels-available-nights") ? parseInt($("body").attr("data-max-hotels-available-nights")) : 14;
            $scope.dynamicPrices = Object.create(null);

            $scope.selectedAdults = ($scope.requestArguments && $scope.requestArguments.adults) || "2";
            $scope.selectedChild = ($scope.requestArguments && $scope.requestArguments.child) || "0";
            if ($scope.selectedAdults == 0 && $scope.selectedChild == 0) {
                $scope.selectedAdults = "2";
            }

            $scope.selectedInfants = "0";
            $scope.selectedNights = ($scope.requestArguments && $scope.requestArguments.nights) || undefined;
            $scope.defaultNights = undefined;
            $scope.availableNights = strRange(1, $scope.maxNights + 1);
            $scope.hideDatePicker = false;

            var timeoutID = undefined;

            function resizeSliderPanel() {
                window.clearTimeout(timeoutID);
                timeoutID = setTimeout(function () {
                    jQuery(window).resize();
                }, 100);
            }

            function strRange(min, max) {
                function toString(val) {
                    return val.toString();
                }

                return _.map(_.range(min, max), toString);
            }

            $scope.availableAdults = strRange(1, 5 + 1);
            $scope.availableChild = strRange(0, 5 + 1);
            $scope.availableInfants = strRange(0, 5 + 1);
            $scope.isInfantsAvailable = false;

            $scope.getSelectedProduct = undefined;
            $scope.selectTicketState = "";
            $scope.dateVal = undefined;

            $scope.isMainProductDynamicallyPriced = false;
            $scope.isPackageOnly = ($("div[ng-controller='activityDetailsCtrl']").attr("data-activity-product-category") || "").toLowerCase() == "package";

            $scope.selectCurrency = function (currency) {
                $scope.selectedCurrency = currency;
                $scope.setSelectedCurrency($scope.selectedCurrency);
                currenciesService.setSelectedCurrencyCode(currency && currency.code);
            };

            $scope.initPackageConditionsByPackageCode = function (packageCode) {
                if (!packageCode) return;

                $scope.isRockies2025CombosFlow = ($scope.requestArguments.rockies2025combosflowpackagecodes || "").length && $scope.requestArguments.rockies2025combosflowpackagecodes.indexOf(packageCode) >= 0;
                $scope.isRockiesCombosFlow = ($scope.requestArguments.rockiescombosflowpackagecodes || "").length && $scope.requestArguments.rockiescombosflowpackagecodes.indexOf(packageCode) >= 0;
                $scope.isRockiesValueCombosFlow = ($scope.requestArguments.rockiesvaluecombosflowpackagecodes || "").length && $scope.requestArguments.rockiesvaluecombosflowpackagecodes.indexOf(packageCode) >= 0;
                $scope.isRockiesLiteCombosFlow = ($scope.requestArguments.rockieslitecombosflowpackagecodes || "").length && $scope.requestArguments.rockieslitecombosflowpackagecodes.indexOf(packageCode) >= 0;

                $scope.hideDatePicker = $scope.isRockies2025CombosFlow || $scope.isRockiesCombosFlow || $scope.isRockiesValueCombosFlow || ($scope.requestArguments.productcodeswithhiddendatepicker || "").length && $scope.requestArguments.productcodeswithhiddendatepicker.indexOf(packageCode) >= 0;
            };

            $scope.hasStateArgs = function () {
                return $stateParams.packageCode; // $stateParams.date && 
            };

            $scope.scrollToResultsIfMobile = function () {
                // if (jQuery(window).width() < 760) {
                setTimeout(function () {
                    if (!$("#loadingContainer").length) return;

                    var page = $("html, body");

                    page.animate({ scrollTop: $scope.isLoading ? $("#loadingContainer").offset().top : $("#resultsContainer").offset().top }, 1000, function () {
                        page.off("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove");
                    });

                    page.on("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove", function () {
                        setTimeout(function () {
                            page.stop();
                        });
                    });
                });
                // }
            };

            $scope.shouldShowComponent = function (comp) {
                return comp && comp.product && comp.product && comp.product.productType != 'PKG-HDR';
            };

            $scope.getCurrState = function () {
                return $stateParams.date ? "package-details-withdate" : "package-details";
            };

            $scope.getRequestDate = function () {
                var defaultDate = $scope.package && $scope.package.startDate && moment($scope.package.startDate);
                // package start date can have a min date value
                if (!defaultDate || !defaultDate.isValid() || defaultDate.year() < 2019) {
                    defaultDate = jwtService.getServerMomentDate();
                }

                var defaultDateStr = defaultDate.format("YYYY-MM-DD");
                if (!$stateParams.date) {
                    return defaultDateStr;
                }
                var reqDate = moment($stateParams.date, "YYYY-MM-DD");
                if (!reqDate.isValid() || reqDate.isBefore(defaultDate)) return defaultDateStr;
                return reqDate.format("YYYY-MM-DD");
            };

            $rootScope.$$listeners.$stateChangeStart = [];
            $rootScope.$on("$stateChangeSuccess",
                function (event, toState, toParams, fromState, fromParams) {
                    $scope.selectedCurrency = $scope.getCurrencyBySelectedCode();
                    $scope.setSelectedCurrency($scope.selectedCurrency);

                    $scope.setFiltersFromUrl();

                    //if ((toState.name || "").toLowerCase() == "package-details") {
                    //    taskFactory.packageTask = null;
                    //}
                    //if (toState == "package-details-withdate") { // old url with the date in the urls should go to default                         
                    //    $state.go("package-details", { packageCode: $stateParams.packageCode }, { notify: false });
                    //    return;
                    //}

                    $timeout(function () {

                        resizeSliderPanel();
                        if ((toState.name || "").toLowerCase().indexOf("package") < 0) {
                            // reset window title
                            //console.log("setPackageTitle reset true");
                            $scope.setPackagePageTitle(true);
                            return;
                        }

                        $scope.initPackageConditionsByPackageCode(toParams.packageCode);

                        // the initDatepicker will be called again when $scope.package will be updated if different packagecode
                        var packageIsDifferent = !toParams || !$scope.package || (toParams.packageCode || "").toLowerCase() != ($scope.package.code || "").toLowerCase();
                        if (fromState.name === toState.name) {
                            initDatePicker(null, packageIsDifferent);
                            return;
                        }
                        initDatePicker(function () {
                            var criteria = $scope.getCriteria();

                            if (!criteria || !$scope.hasStateArgs()) {
                                return;
                            }

                            var strDate = $scope.getRequestDate();
                            var formattedStrDate = !criteria.date ? moment(strDate).format(shoppingCartService.getDateFormat()) : criteria.date;

                            // Update the url, disabled for now: 
                            //if ($stateParams.date) {
                            //    $stateParams.date = strDate;
                            //}
                            $scope.setSelectedDate(formattedStrDate);
                            //if ($("#daterangeDetails").length) {
                            //    $("#daterangeDetails").val(formattedStrDate);
                            //    $("#daterangeDetails").data().daterangepicker.startDate = moment(formattedStrDate);
                            //    $("#daterangeDetails").data().daterangepicker.endDate = moment(formattedStrDate);
                            //}

                            //if (criteria.date !== formattedStrDate) {
                            //    criteria.date = formattedStrDate;
                            //    $scope.$parent.savePackagesSearchCriteria(criteria);
                            if ((toState.name || "").toLowerCase() == "package-details") {
                                $scope.isLoading = false;
                            }
                            //    $scope.getPackage();
                            //}

                        }, packageIsDifferent);
                    });//\timeout

                    //
                    //fix weird issue:
                    //NOTE!: weird angularjs issue: Controller is reloaded on $state.go despite notify set to false.
                    // in this case, the next, package-final state will reload package-details
                    if (!$scope.package && initialized) {
                        $scope.init();
                    }
                });


            $scope.getDynamicPricesKey = function (code, month, year) {

                month++; // month start at 0, so we need to increment
                return String(month) + String(year) + code.toLowerCase();
            };

            $scope.loadCalendarPrices = function (month, year) {
                if (!($scope.package && $scope.package.isDynamicallyPrice)) {
                    return;
                }

                var packageCode = $scope.package && $scope.package.code;
                if (!packageCode || !$scope.inlineDatePicker) return;
                var priceObjKey = $scope.getDynamicPricesKey(packageCode, month, year);

                month++; // month start at 0, so we need to increment              
                if ($scope.dynamicPrices[priceObjKey]) return; // if the dynamic prices were already loaded return;

                $scope.calendarIsLoading = true;
                $scope.inlineDatePicker.toggleLoading($scope.calendarIsLoading);

                productsFactory.getDynamicPackagePrices(jwtService.getPrincipalToken(), packageCode, month, year).then(
                    function (result) {
                        var prices = result.data.prices;
                        if ((prices || "").length) {
                            var monthPrices = Object.create(null);
                            $.each(prices, function (key, value) {
                                var vdate = moment(value.date, 'YYYY-MM-DDTHH:mm:ss').date();
                                monthPrices[vdate] = { price: value.price, className: (value.projectedVisitation || "").toLowerCase(), isClosed: value.isClosed, closedReason: value.closedReason };
                            });
                            $scope.dynamicPrices[priceObjKey] = monthPrices;
                        }
                        $scope.calendarIsLoading = false;

                        $scope.inlineDatePicker.toggleLoading($scope.calendarIsLoading);
                        $scope.inlineDatePicker.update();
                    },
                    function (response) {
                        $scope.calendarIsLoading = false;
                        $scope.inlineDatePicker.toggleLoading($scope.calendarIsLoading);
                    });
            };

            $scope.getSelectedDate = function (dateFormat, returnMoment) {
                dateFormat = dateFormat || "YYYY-MM-DD";
                var result = null;
                var momentResult = null;

                if (!$scope.isMonthPicker && $scope.inlineDatePicker) {
                    // use the inline picker
                    momentResult = (($scope.inlineDatePicker.selectedDates || "").length ?
                        moment($scope.inlineDatePicker.selectedDates[0]) : moment());
                    result = momentResult.format(dateFormat);
                }
                else if ($scope.isMonthPicker && $scope.selectedStartDate) {             // $scope.selectedStartDate will always have a value when the datepicker is a dropdown
                    console.log("Selected date: ", $scope.selectedStartDate.format(dateFormat));
                    momentResult = $scope.selectedStartDate;
                    result = momentResult.format(dateFormat);
                }
                else if ($("#daterangeDetails").length) {
                    var date = $("#daterangeDetails").val();
                    momentResult = moment(date, shoppingCartService.getDateFormat());
                    result = momentResult.format(dateFormat);
                }

                if (result) {
                    $scope.dateVal = result;
                }
                return returnMoment ? momentResult : result;
            };

            $scope.selectedStartDateChanged = function () {
                $scope.wasSearch = false;
            };

            $scope.setSelectedDate = function (newDate) {
                var newDateMoment = moment(newDate, shoppingCartService.getDateFormat());

                if (!$scope.isMonthPicker && $scope.inlineDatePicker) {
                    // use the inline picker
                    return $scope.inlineDatePicker.selectDate(newDateMoment.toDate());
                }
                else if ($scope.isMonthPicker && $scope.selectedStartDate) { // $scope.selectedStartDate will always have a value when the datepicker is a dropdown
                    var selectedDate = _.find($scope.availableStartDates, function (val) {
                        return val.month() == newDateMoment.month() && val.year() == newDateMoment.year();
                    });
                    //$scope.selectedStartDate = moment();
                    $scope.selectedStartDate = selectedDate || $scope.availableStartDates[0];
                }
                else if ($("#daterangeDetails").length) {
                    $("#daterangeDetails").val(newDate);

                    $("#daterangeDetails").data().daterangepicker.startDate = newDateMoment;
                    $("#daterangeDetails").data().daterangepicker.endDate = newDateMoment;
                }
            };

            $scope.prevSelectedDate = undefined;
            function initDatePicker(callback, packageIsDifferent) {
                // var defaultDate = (!packageIsDifferent && $scope.package && $scope.package.startDate);
                var travelWindow = $scope.package && $scope.package.travelWindow || 0;

                $scope.isMonthPicker = $scope.package && $scope.package.isDynamicallyPrice && $scope.package.type == "COMBO";


                if ($scope.isRockiesLiteCombosFlow || travelWindow > 0) {
                    $scope.isMonthPicker = false;
                    $scope.isRockiesLiteCombosFlow = true;
                }

                var nextAvailableDate = $scope.package && ($scope.package.nextAvailableDate || $scope.package.packageDescriptions && $scope.package.packageDescriptions.nextAvailableDate);

                //
                // excpetion for nextavailable date for this hotel
                //var hotelProductCodeWithException = "WEG-BC";
                var packageCodeWithException = "PKG-BC-MYS";
                var isPackageWithException = $scope.package && $scope.package.code == packageCodeWithException;
                //var hasHotelWithException = $scope.package && $scope.package.components && $scope.package.components.find(function (pkgComp) {                    
                //    return (pkgComp && pkgComp.product && pkgComp.product.code == hotelProductCodeWithException);
                //});
                if (!!isPackageWithException) {
                    nextAvailableDate = null;
                }
                //

                var startDate = nextAvailableDate ? moment(nextAvailableDate, "YYYY-MM-DD") : jwtService.getServerMomentDate();

                if (!$scope.isMonthPicker && !packageIsDifferent && ($scope.package && $scope.package.isDynamicallyPrice || !!$scope.isRockiesLiteCombosFlow || travelWindow > 0)) {
                    var isMobile = false; //initiate as false
                    // device detection
                    if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
                        || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0, 4))) {
                        isMobile = true;
                    }

                    var popoverTimeout = null;


                    var inlineDatePickerSettings = {
                        language: 'en',
                        minDate: startDate.toDate(),
                        windowRangeDays: travelWindow,
                        autoClose: travelWindow > 0 || $scope.isRockiesLiteCombosFlow,
                        onSelect: function (formattedDate, date, inst) {
                            // the select probably wasn't triggered by user

                            if (!$scope.prevSelectedDate || moment($scope.prevSelectedDate).isSame(moment(date), "day")) {
                                $scope.prevSelectedDate = date;
                                return;
                            }
                            $scope.prevSelectedDate = date;
                            if ($scope.isDisabledAddToCart()) { return; }
                            // $scope.package.details = undefined;
                            $scope.filteredItems = undefined;
                            $scope.wasSearch = false;
                            setTimeout(function () { $scope.$apply(); });
                        },
                        onChangeView: function (view, month, year) {
                            if (view == "days") {
                                $scope.loadCalendarPrices(month, year);
                            }
                        },
                        onChangeDecade: function (decade) {
                        },
                        onChangeMonth: function (month, year) {
                            $scope.loadCalendarPrices(month, year);
                        },
                        onChangeYear: function (year) {
                            var month = new Date().getMonth();

                            var prevDateObj = ($scope.prevSelectedDate && moment($scope.prevSelectedDate));
                            if (prevDateObj) {
                                month = prevDateObj.month();
                            }

                            $scope.loadCalendarPrices(month, year);
                        },
                        onRenderCell: function (date, cellType, isOtherMonthCell) {
                            console.log("render cell");
                            var currentDate = date.getDate();

                            if (cellType == 'day') {
                                var monthPriceKey = $scope.getDynamicPricesKey($scope.package.code, date.getMonth(), date.getFullYear());
                                var monthPrices = $scope.dynamicPrices[monthPriceKey];
                                var dayPrice = !isOtherMonthCell && monthPrices && monthPrices[currentDate]; // don't show prices from other months
                                var priceLabel = ($scope.anonymUser && $scope.anonymUser.labels
                                    && $scope.anonymUser.labels["dynamicPricingCalendarPriceLabel"]) || $scope.labelUtils.getLabel("dynamicPricing.calendarPriceLabel");

                                var closedTooltipHtml = dayPrice && dayPrice.isClosed && dayPrice.closedReason;
                                var closedTooltipClass = "";
                                var closedTooltipAttributes = "";
                                if (closedTooltipHtml) {
                                    closedTooltipClass = "closed-tooltip";
                                    closedTooltipHtml = closedTooltipHtml.replace(/\'/g, '&apos;');

                                    closedTooltipAttributes = 'data-toggle="popover" data-trigger="' + (isMobile ? 'focus' : 'hover focus') + '" data-html="true" data-content="' + closedTooltipHtml + '"';
                                }

                                clearTimeout(popoverTimeout);
                                popoverTimeout = setTimeout(function () {
                                    jQuery('[data-toggle="popover"].closed-tooltip').each(function () {
                                        var $this = $(this);
                                        $this.popover({
                                            container: $this,
                                            delay: { show: isMobile ? 0 : 300, hide: 0 }
                                        });

                                        if ($this.parent().hasClass("-selected-")) {
                                            if (!isMobile) {
                                                setTimeout(function () { $this.popover("show"); }, 50);
                                            } else {
                                                $this.popover("show");
                                            }
                                        }

                                    });//.popover()
                                }, 20);

                                var html = "";
                                if (dayPrice && dayPrice.isClosed) {
                                    html = '<div ' + closedTooltipAttributes + ' class="day-label closed ' + closedTooltipClass + '"><span class="date">' + currentDate + '</span></div>';
                                } else {
                                    html = '<div ' + closedTooltipAttributes + ' class="day-label ' + closedTooltipClass + ' ' + (dayPrice && dayPrice.price ? "has-price" : "") + '"><span class="date">' + currentDate + '</span><span class="from">' + priceLabel + '</span></div>' + (dayPrice && dayPrice.price ? '<div class="from-price"> $' + (dayPrice && dayPrice.price) + '</div>' : '');
                                }
                                var dayPriceClassName = !(travelWindow > 0) && (dayPrice && dayPrice.className) || "";

                                return {
                                    disabled: dayPrice && dayPrice.isClosed,
                                    classes: (dayPrice && dayPrice.isClosed ? "closed-cell" : "") + " " + dayPriceClassName,
                                    html: html
                                }
                            }
                        }
                    };

                    var currentDateFallback = jwtService.getServerMomentDate();

                    var availableFrom = $scope.package.availableFrom && moment($scope.package.availableFrom) || null;
                    if (!availableFrom || !availableFrom.isValid() || availableFrom.year() < 2000) availableFrom = null;
                    else if (availableFrom.isBefore(currentDateFallback, "day")) {
                        availableFrom = currentDateFallback;
                    }

                    var availableTo = $scope.package.availableUntil && moment($scope.package.availableUntil) || null;
                    if (!availableTo || !availableTo.isValid() || availableTo.year() < 2000) availableTo = null;
                    else if (availableFrom && availableTo.isBefore(availableFrom, "day")) {
                        availableFrom = null;
                    }

                    if (availableFrom) {
                        inlineDatePickerSettings.minDate = availableFrom.toDate();
                    }
                    if (availableTo) {
                        inlineDatePickerSettings.maxDate = availableTo.toDate();
                    }

                    $scope.package._adjustedAvailableFromMoment = availableFrom;

                    if (!!$scope.isRockiesLiteCombosFlow || travelWindow > 0) {
                        $scope.inlineDatePicker = $("#inputDatePicker").datepicker(inlineDatePickerSettings).data('datepicker');
                    } else {
                        $scope.inlineDatePicker = $("#inlineDatePicker").datepicker(inlineDatePickerSettings).data('datepicker');
                    }


                    $scope.loadCalendarPrices(startDate.month(), startDate.year());

                } else {

                    if ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) {
                        moment.locale($scope.selectedLanguage.languageCode);
                    }


                    if ($scope.isMonthPicker) {

                        var availableStartDates = [startDate];
                        var indexDate = startDate.clone();
                        for (var i = 0; i < 10; i++) {
                            indexDate = indexDate.add(1, 'M').startOf('month');
                            //console.log("Added: ", indexDate.format());
                            availableStartDates.push(indexDate.clone());
                        }
                        $scope.availableStartDates = availableStartDates;
                        $scope.selectedStartDate = $scope.availableStartDates[0];
                    } else {
                        $scope.availableStartDates = [];
                        $scope.selectedStartDate = undefined;
                        //
                        if (!$("#daterangeDetails").length) {
                            if (callback) callback();
                            return;
                        }
                        var datepickersettings = {
                            singleDatePicker: true,
                            minDate: startDate, //jwtService.getServerMomentDate(),//moment(),//.add("days", 1),
                            showDropdowns: true,
                            locale: {
                                format: shoppingCartService.getDateFormat()
                            },
                            parentEl: "#daterangecontainer"
                        };

                        $scope.daterangepicker = $("#daterangeDetails").daterangepicker(datepickersettings);

                        $scope.daterangepicker.on("apply.daterangepicker", function (ev, picker) {
                            if ($scope.isDisabledAddToCart()) { return; }
                            $scope.package.details = undefined;
                            $scope.filteredItems = undefined;
                            $scope.wasSearch = false;
                            setTimeout(function () { $scope.$apply(); });
                        });
                    }
                }

                if (callback) callback();
            }

            //function dispatchGMTEvent() {
            //    console.log("dispatch ibe_ready");
            //    window.dataLayer = window.dataLayer || [];
            //    window.dataLayer.push({
            //        'event': 'ibe_ready'
            //    });
            //};

            $scope.setPackagePageTitle = function (reset, dontDispatchGMTEvent) {
                if (reset && jQuery("html").data("oldtitle")) {
                    window.document.title = jQuery("html").data("oldtitle");
                    if (!dontDispatchGMTEvent) {
                        //dispatchGMTEvent();
                        trackingService.dispatchIBEReadyGMTEvent();
                    }
                    jQuery("html").data("oldtitle", "");
                    return;
                } else if (reset) {
                    return;
                }

                if (!$scope.package) return;

                var title = $scope.package.packageDescriptions
                    && $scope.package.packageDescriptions.titles
                    && $scope.package.packageDescriptions.titles.length > 0
                    ? $scope.package.packageDescriptions.titles[0] : $scope.package.name;
                if (!title) return;
                if (!jQuery("html").data("oldtitle")) {
                    jQuery("html").data("oldtitle", window.document.title);
                }
                window.document.title = title;
                if (!dontDispatchGMTEvent) {
                    // dispatchGMTEvent();
                    trackingService.dispatchIBEReadyGMTEvent();
                }
            };

            $scope.updateSelectedPackage = function (updPackage) {
                if ($scope.$parent) {
                    var productDetailsCtrl = $scope.$parent;
                    productDetailsCtrl.setSelectedPackage(updPackage);
                }
            };

            $scope.persistCriteriaParams = function (date, adults, children, infants, nights) {
                $scope.selectedAdults = adults;
                $scope.selectedChild = children;

                if (infants) {
                    $scope.selectedInfants = infants;
                }

                if (nights) {
                    $scope.selectedNights = nights;
                }

                $scope.setSelectedDate(date);
                //daterangeDetails
                //if ($("#daterangeDetails").length) {
                //    $("#daterangeDetails").val(date);
                //}
                $scope.dateVal = date;

                $scope.persistCriteria();
            };

            $scope.persistCriteria = function () {

                var packagesCriteria = $scope.getCriteria();
                if (!packagesCriteria) {
                    return;
                }

                var productDetailsCtrl = $scope.$parent;

                if (!productDetailsCtrl) {
                    return;
                }
                //$scope.selectedNights = $scope.selectedNights || ($scope.hasNextElement(null, true) ? 1 : 0);
                if ($scope.selectedNights <= 0) {
                    $scope.selectedNights = ($scope.hasNextElement(null, true) ? 1 : 0);
                }

                packagesCriteria.adults = parseInt($scope.selectedAdults);
                packagesCriteria.children = parseInt($scope.selectedChild);
                packagesCriteria.infants = parseInt($scope.selectedInfants);

                packagesCriteria.nights = parseInt($scope.selectedNights);

                packagesCriteria.date = $scope.getSelectedDate(shoppingCartService.getDateFormat()) || $scope.dateVal;

                //if ($("#daterangeDetails").length) {
                //    packagesCriteria.date = $("#daterangeDetails").val();
                //} else if ($scope.dateVal) {
                //    packagesCriteria.date = $scope.dateVal;
                //}

                packagesCriteria.selectedPackage = $scope.package;
                if (($scope.mainPackages || "").length) {
                    packagesCriteria.packages = $scope.mainPackages;
                }

                packagesCriteria.defaultNights = $scope.defaultNights;

                productDetailsCtrl.savePackagesSearchCriteria(packagesCriteria);
            };

            $scope.fillMainPackage = function (criteriaPackage, callback) {

                if (criteriaPackage
                    &&
                    ((criteriaPackage.code || "").toLowerCase() == ($stateParams.packageCode || "").toLowerCase()
                        || (criteriaPackage.details && criteriaPackage.details.code || "").toLowerCase() == ($stateParams.packageCode || "").toLowerCase())
                ) {
                    $scope.initPackagePrice(criteriaPackage);
                    $scope.package = criteriaPackage;
                    //$scope.setPackageCondtions();
                    $scope.setPackagePageTitle(false, true); // ibe_ready should be triggered after build flow tracker
                    // callback();
                    //return;
                }

                // if this page contains an update package to be updated remove
                if ($scope.updateItem) {
                    var updatepkg = $scope.updateItem.BookingToQuote.Packages[0];
                    var updatecomp = $scope.updateItem.BookingToQuote.Components[0];
                    var startDate = (updatepkg && updatepkg.StartDate) || (updatecomp && updatecomp.StartDate);
                    startDate = (startDate || "").split("T")[0];
                    var params = {
                        urlPrefix: webUrl,
                        token: jwtService.getPrincipalToken(),
                        productCode: (updatepkg && updatepkg.PackageCode) || ($scope.requestArguments && $scope.requestArguments.productCode),
                        travelDate: startDate,
                        adults: 1,
                        children: 0,
                        nights: 0
                    };

                    packagesService.getPackageDetailsPromise(params).then(
                        function (result) {
                            if (result && result.data.packages) {
                                $scope.package = result.data.packages[0];
                                $scope.initPackagePrice($scope.package);
                                //$scope.setPackageCondtions();
                            }
                            callback && callback();
                        });
                }
                else {
                    $scope.getSelectedProduct(function (result) {
                        if (result.success && result.data) {
                            var product = result.data;
                            if ($scope.package) {
                                $scope.package.isMainProductDynamicallyPriced = product && product.isDynamicallyPriced;
                                // 
                                callback();
                                return;
                            }

                            var params = {
                                urlPrefix: webUrl,
                                token: jwtService.getPrincipalToken(),
                                productCode: product.code, // || product.productType,
                                travelDate: $scope.getRequestDate()
                            };
                            $scope.isLoading = true;

                            var getPackageSummariesFunc = undefined;

                            var sectionid = $("[data-sectionid]").data("sectionid") || 0;
                            // check if the package is directly accessed from the listing and not under a product

                            if ($scope.isPackageOnly) {
                                getPackageSummariesFunc = activitiesService.getActivitiesByDate;
                                params = {
                                    token: jwtService.getPrincipalToken(),
                                    id: sectionid,
                                    date: jwtService.getServerStrDate(),
                                    urlPrefix: webUrl
                                };
                            } else {
                                if (!$stateParams.date) {
                                    params.travelDate = null;
                                }

                                if (product.code) {
                                    getPackageSummariesFunc = packagesService.getPackageSummaries;
                                } else {
                                    getPackageSummariesFunc = packagesService.getPackageSummariesByProductType;
                                    params = {
                                        urlPrefix: webUrl,
                                        token: jwtService.getPrincipalToken(),
                                        productCategory: product.productCategory,
                                        productType: product.productType,
                                        travelDate: $stateParams.date ? $scope.getRequestDate() : null
                                    };

                                }
                            }

                            // override for banf gondola that is not available on certain dates                            
                            if ($stateParams.packageCode) { //$stateParams.packageCode == "PKG-BGR-SE") { //
                                params.packageCode = $stateParams.packageCode;
                                getPackageSummariesFunc = packagesService.getPackageDescriptions;
                            }

                            //packagesService.getPackageSummaries
                            getPackageSummariesFunc(params,
                                function (result) {
                                    $scope.isLoading = false;
                                    console.log("getPackageSummariesFunc", result);
                                    if (!result || !result.success || !result.data || !result.data.packages) {
                                        $scope.mainPackages = [];
                                        //$scope.persistCriteria();
                                        callback();
                                        return;
                                    };

                                    var strDate = moment($scope.getRequestDate()).format(shoppingCartService.getDateFormat());

                                    $.each(result.data.packages, function (key, value) {
                                        value.strDate = strDate;
                                        if (value.code.toLowerCase() === $stateParams.packageCode.toLowerCase()) {
                                            $scope.initPackagePrice(value);
                                            $scope.package = value;
                                            //$scope.setPackageCondtions();
                                            $scope.setPackagePageTitle(false, true);  // ibe_ready should be triggered after build flow tracker
                                            $scope.package.isMainProductDynamicallyPriced = product && product.isDynamicallyPriced;

                                        }
                                    });

                                    $scope.mainPackages = result.data.packages;
                                    $scope.persistCriteria();
                                    callback();
                                });

                        } else {
                            callback();
                        }
                    });
                }
            };

            $scope.initPackagePrice = function (packageTo, packageFrom) {
                var packageFromAdjusted = packageFrom || packageTo;

                if (packageTo && packageFromAdjusted && packageFromAdjusted.ageBasedPriceBreakdown) {
                    packageTo.adultPrice = packageFromAdjusted.ageBasedPriceBreakdown.adultPrice;
                    packageTo.childPrice = packageFromAdjusted.ageBasedPriceBreakdown.childPrice;
                    packageTo.additionalChildPrice = packageFromAdjusted.ageBasedPriceBreakdown.additionalChildPrice;
                    packageTo.seniorPrice = packageFromAdjusted.ageBasedPriceBreakdown.seniorPrice;
                    packageTo.studentPrice = packageFromAdjusted.ageBasedPriceBreakdown.studentPrice;
                }
            }

            $scope.isHotelPackage = function () {
                return $scope.requestArguments && $scope.requestArguments.productCategory == "Hotel";
            };

            $scope.fillBussStopsUnits = function (callback) {
                if (!$scope.package || !$scope.package.details) {
                    if (callback) {
                        callback();
                    }
                    return;
                }

                var units = [];
                $.each($scope.package.details.components, function (key, compVal) {
                    if (compVal.product && (compVal.product.productCategory === "Transportation" || compVal.product.productCategory === "Tour")) {
                        $.each(compVal.product.units, function (unitKey, unitVal) {
                            units.push({ unit: unitVal, productCode: compVal.product.code });
                        });
                    }
                });

                var unitParams = {
                    urlPrefix: $("body").data("weburl") ? $("body").data("weburl") : "",
                    token: jwtService.getPrincipalToken()
                };

                function setBusStopForUnit(index) {
                    if (!units[index]) {
                        if (callback) {
                            callback();
                        }
                        return;
                    }
                    unitParams.productCode = units[index].productCode;
                    unitParams.unitCode = units[index].unit.unitCode;
                    transportationService.getBusStops(unitParams, function (dateResult) {
                        units[index].unit.busStops = dateResult.data;
                        //units[index].unit.selectedPickUp = units[index].unit.busStops && units[index].unit.busStops.pickups.length ? units[index].unit.busStops.pickups[0] : undefined;
                        //units[index].unit.selectedDropOff = units[index].unit.busStops && units[index].unit.busStops.dropoffs.length ? units[index].unit.busStops.dropoffs[0] : undefined;
                        setBusStopForUnit(index + 1);
                    });
                };

                setBusStopForUnit(0);
            };

            function fillFilteredComponents(pkgDetails) {
                if (!pkgDetails) {
                    $scope.filteredItems = undefined;
                }

                $scope.filteredItems = _.filter(pkgDetails.components, function (comp) {
                    return comp && !comp.isHidden && comp.product && comp.product && comp.product.productType != 'PKG-HDR';
                });
            }

            $scope.packageHasArrivalTimeSelector = function () {
                return !!$scope.package && ($scope.package.type == "FBCOMBO" && (jwtService.getGeography() || "").toUpperCase().indexOf("SKL") >= 0);
            };

            $scope.getPackage = function (callback, date,autoLoad) {
                if ($scope.isDisabledAddToCart()) { return; }
                if ($scope.isLoading) return;
                var packagesCriteria = $scope.getCriteria();
                var dateval = $scope.getSelectedDate(shoppingCartService.getDateFormat()) || $scope.dateVal;

                if (!packagesCriteria || (!date && !dateval)) {
                    $scope.goBack();
                    return;
                }
                $scope.wasSearch = true;
                $scope.isLoading = true;
                $scope.scrollToResultsIfMobile();
                var dateStr = date || dateval; //$scope.dateVal ? $scope.dateVal : $("#daterangeDetails").val();
                $scope.initPackageConditionsByPackageCode($stateParams.packageCode);
                var params = {
                    urlPrefix: webUrl,
                    token: jwtService.getPrincipalToken(),
                    productCode: $stateParams.packageCode,
                    travelDate: moment(dateStr, shoppingCartService.getDateFormat()).format("YYYY-MM-DD"),
                    adults: packagesCriteria.adults,
                    children: packagesCriteria.children,
                    infants: packagesCriteria.infants || 0,
                    nights: packagesCriteria.nights
                };

                var trackerReq = {
                    lobTitle: $scope.lobTitle,
                    packageName: $scope.packageName,
                    searchDate: params.travelDate,
                    adults: params.adults,
                    children: params.children,
                    shoppingCart: $scope.cart,
                    anonymUser: $scope.anonymGeneralUser,
                    bookingNumber: null,
                    bookingId: null
                };
                trackingService.buildFlowTrackerObj(trackerReq);

                packagesService.getPackageDetails(params,
                    function (result) {
                        
                        if (!result || !result.success || !result.data || !(result.data.packages || "").length) { //
                            // $scope.package = undefined;
                            if (autoLoad && $scope.autoLoadIndex < $scope.topAutoLoadLimit) {
                                $scope.autoLoadIndex++;

                                var newDate = moment(dateStr, shoppingCartService.getDateFormat()).add(1, "d").format(shoppingCartService.getDateFormat());

                                setTimeout(function () {
                                    $scope.isLoading = false;
                                    $scope.setSelectedDate(newDate);
                                    $scope.getPackage(callback, newDate, autoLoad);
                                });
                                return;
                            }

                            $scope.package.details = null;
                            $scope.isLoading = false;
                            // $scope.scrollToResultsIfMobile();
                            if (callback) callback();

                            taskFactory.packageTask = { name: "PackageInit", data: null };
                            return;
                        };

                        var newParams = {
                            date: params.travelDate, packageCode: result.data.packages[0].code
                        };

                        // Disabled for now: $stateParams.date = params.travelDate;
                        //if ($stateParams.date) {
                        //    newParams.date = params.travelDate;
                        //}
                        if ($stateParams.adults != null) {
                            newParams.adults = params.adults;
                        }
                        if ($stateParams.children != null) {
                            newParams.children = params.children;
                        }
                        if ($stateParams.infants != null) {
                            newParams.infants = params.infants || 0;
                        }

                        //adults: (params.adults || 0),
                        //    children: (params.children || 0),
                        //        infants: (params.infants || 0)

                        //NOTE!: weird angularjs issue: Controller is reloaded on $state.go despite notify set to false.
                        // in this case, the next, package-final state will reload package-details

                        $state.go($state.$current.name,
                            newParams,
                            { notify: false });



                        //setLocalParamsToFixState();

                        $scope.package.details = result.data.packages[0];
                        $scope.package.startDate = $scope.package.details && $scope.package.details.startDate || $scope.package.startDate;
                        $scope.package.endDate = $scope.package.details && $scope.package.details.endDate || $scope.package.endDate;

                        //$scope.setPackageCondtions();

                        if ($scope.package.details.bookingCutOffTime) {
                            var currTime = jwtService.getServerMomentDate(true);
                            $scope.package.details.isTimeRestricted = moment($scope.package.details.bookingCutOffTime).isSameOrBefore(currTime);
                        }

                        fillFilteredComponents($scope.package.details);

                        $scope.isInfantsAvailable = $scope.package.details.infantRateAvailable;
                        // fill the price
                        $scope.initPackagePrice($scope.package, $scope.package.details);
                        //if ($scope.package.details.ageBasedPriceBreakdown) {
                        //    $scope.package.adultPrice = $scope.package.details.ageBasedPriceBreakdown.adultPrice;
                        //    $scope.package.childPrice = $scope.package.details.ageBasedPriceBreakdown.childPrice;
                        //    $scope.package.additionalChildPrice = $scope.package.details.ageBasedPriceBreakdown.additionalChildPrice;
                        //    $scope.package.seniorPrice = $scope.package.details.ageBasedPriceBreakdown.seniorPrice;
                        //    $scope.package.studentPrice = $scope.package.details.ageBasedPriceBreakdown.studentPrice;
                        //}
                        $scope.package.currency = $scope.package.details.currency || ((jwtService.getGeography() || "").toUpperCase().indexOf("SKL") >= 0 ? "ISK" : "USD");
                        $scope.package.culture = ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) || "en";

                        $scope.package.strDate = moment(params.travelDate, "YYYY-MM-DD").format(shoppingCartService.getDateFormat());

                        if (!($scope.selectedNights > 0)) {
                            $scope.selectedNights = parseInt($scope.package.details.duration) || $scope.selectedNights || ($scope.hasNextElement(null, true) ? 1 : 0);
                            $scope.defaultNights = $scope.selectedNights;
                            $scope.availableNights = strRange($scope.defaultNights || 1, $scope.maxNights + 1);
                        }

                        var requestParamsMulti = {
                            token: jwtService.getPrincipalToken(),
                            pkg: $scope.package.details,
                            travelDate: moment($scope.package.strDate, shoppingCartService.getDateFormat()).format("YYYY-MM-DD")
                        };

                        var hasArrivalTime = $scope.packageHasArrivalTimeSelector();

                        var hasAnyComponentUnitsToBeSelected = false;

                        $.each($scope.package.details.components, function (key, comp) {
                            if (!comp.product.selectedUnit && ((comp.product.units || '').length == 1)) {
                                comp.product.selectedUnit = comp.product.units[0];
                            }

                            //if ((!hasArrivalTime || (hasArrivalTime && (comp.product.units || '').length == 1)) && !comp.product.selectedUnit) {
                            //    comp.product.selectedUnit = comp.product.units[0];
                            //}
                            hasAnyComponentUnitsToBeSelected = (comp.product.units || '').length > 1 || hasAnyComponentUnitsToBeSelected;
                        });

                        productsFactory.fillPackageRelatedServicesMulti(requestParamsMulti, function () {
                            $scope.package.reqmultidate = requestParamsMulti.travelDate;
                            $scope.fillBussStopsUnits(function () {

                                var hasAnyBussStops = _.find($scope.package.details.components, function (comp) {
                                    return _.find(comp.product.units, function (unit) {
                                        return (unit.busStops || "").length > 0;
                                    });
                                });;
                                var hasAttractionTimes = false;
                                $.each($scope.package.details.components, function (key, compVal) {
                                    if (!compVal.availableHours && compVal.relatedProducts && (compVal.relatedProducts.attractionTimes || "").length) {
                                        var times = compVal.relatedProducts.attractionTimes[0].units;
                                        if (times) {
                                            hasAttractionTimes = true;
                                            var isRequired = compVal.relatedProducts.attractionTimes[0].isRequiredRelatedProduct;

                                            compVal.availableHours = [$scope.noTime]; //isRequired ? [] : [$scope.noTime];

                                            $.each(times, function (timeKey, timeVal) {
                                                compVal.availableHours.push({ key: moment(timeVal.startTime).format("hh:mm A"), value: timeVal });
                                            });
                                            compVal.selectedTime = isRequired ? compVal.availableHours[0] : $scope.noTime;
                                        }
                                    }
                                });
                                // for tours - has pickup location required or dropoff location required
                                var hasTourLocationsRequired = _.find($scope.package.details.components, function (comp) {
                                    if (comp.product.productCategory != "Tour") {
                                        return false;
                                    }
                                    var selectedUnit = comp.product.units && comp.product.units[0];
                                    if (!selectedUnit) return false;
                                    return selectedUnit.dropoffLocationRequired || selectedUnit.pickupLocationRequired;
                                });
                                var hasDateOverwrite = _.find($scope.package.details.components, function (comp) {
                                    // the attraction was changed to not show the date field if it doesn't have attraction times
                                    return comp.product.productCategory != "Hotel" && comp.product.productCategory != "Attraction" && comp.startDateOverwriteable;
                                }) != undefined;


                                // TODO: check if both component products have units > 0
                                $scope.package.showFinal = hasAnyBussStops || hasAttractionTimes || hasTourLocationsRequired || hasDateOverwrite || (hasArrivalTime && hasAnyComponentUnitsToBeSelected);
                                $scope.package.details.showFinal = $scope.package.showFinal;
                                $scope.persistCriteria();
                                taskFactory.packageTask = { name: "PackageInit", data: $scope.wizardModel && $scope.wizardModel.packagesCriteria && $scope.wizardModel.packagesCriteria.selectedPackage };
                                $scope.isLoading = false;
                                $scope.scrollToResultsIfMobile();
                                if (callback) callback($scope.package);
                            });

                        });
                    });
            };
            $scope.isPackageAvailableByAdvancedLimit = function (pkg) {
                if (!pkg || !pkg.advancedBookingDaysLimit) return true;
                var currentDate = jwtService.getServerMomentDate();
                var limitDate = currentDate.add(pkg.advancedBookingDaysLimit, 'days');
                var searchDate = $scope.getSelectedDate(null, true);
                return searchDate.isSameOrBefore(limitDate, 'day');
            };

            $scope.getUnavailablePackageByAdvancedLimit = function (pkg) {
                if (!pkg) return null;
                return utilsFactory.getLabel("packages.unavailableInAdvance").replace("{0}", pkg.advancedBookingDaysLimit);
            }

            $scope.nightsChanged = function () {
                $scope.persistCriteria();
                $scope.wasSearch = false;
                //$scope.daterangepicker.trigger("apply.daterangepicker");
            };

            $scope.adultsChanged = function () {
                //$scope.selectedAdults = adults;
                $scope.persistCriteria();
                $scope.wasSearch = false;
                //$scope.daterangepicker.trigger("apply.daterangepicker");
            };

            $scope.childChanged = function () {
                //$scope.selectedChild = child;
                $scope.persistCriteria();
                $scope.wasSearch = false;
                //$scope.daterangepicker.trigger("apply.daterangepicker");
            };

            //not used
            $scope.infantsChanged = function () {
                //$scope.selectedInfants = infants;
                $scope.persistCriteria();
                //$scope.daterangepicker.trigger("apply.daterangepicker");
            };


            $scope.isDisabledAddToCart = function () {
                return ((parseInt($scope.selectedAdults) || 0) + (parseInt($scope.selectedChild) || 0) + (parseInt($scope.selectedInfants) || 0)) === 0;
            };


            $scope.getCriteria = function () {
                if ($scope.$parent) {
                    var productDetailsCtrl = $scope.$parent;
                    return productDetailsCtrl.getPackagesSearchCriteria();
                }

                return undefined;
            };

            var componentHasForm = function (component) {
                if ($scope.package && $scope.package.type == "CUSTOM" && (component.product.units || "").length > 0) {
                    return true;
                }

                return (component.product.units || "").length > 0 && component.product.productCategory.trim().toLowerCase() === "hotel";
            };
            var componentHasHotelForm = function (component) {
                return (component.product.units || "").length > 0 && component.product.productCategory.trim().toLowerCase() === "hotel";
            };

            $scope.goToComponent = function (component) {
                $scope.$parent.persistWizardModel(function () {
                    $timeout(function () {
                        var param = {
                            packageCode: $scope.package.code ? $scope.package.code : $stateParams.packageCode,
                            packageProductCode: component.product.code,
                            packageProductCategory: component.product.productCategory,
                            date: moment($scope.getCriteria().date, shoppingCartService.getDateFormat()).format("YYYY-MM-DD")
                        };

                        $state.go("package-details.select", param);
                    });
                });
            };

            $scope.hasNextElement = function (packageProductCode, checkHotelComp) {
                var next = undefined;

                if ($scope.package && $scope.package.details && ($scope.package.details.components || "").length > 0) {

                    if (!packageProductCode || !packageProductCode.length) {
                        //package details view
                        next = _.find($scope.package.details.components,
                            function (c) { return checkHotelComp ? componentHasHotelForm(c) : componentHasForm(c); });
                    } else {
                        var isCurrCompFound = false;

                        next = _.find($scope.package.details.components, function (comp) {
                            if (isCurrCompFound && (checkHotelComp ? componentHasHotelForm(comp) : componentHasForm(comp))) {
                                return true;
                            }
                            if (comp && comp.product && comp.product.code.toLowerCase().trim() === packageProductCode.toLowerCase().trim()) {
                                isCurrCompFound = true;
                            }
                            return false;
                        });
                    }
                }
                var hasNextElement = (next && (checkHotelComp ? componentHasHotelForm(next) : componentHasForm(next)));
                if (checkHotelComp && $scope.package && $scope.package.details) {
                    $scope.hadHotelNextElement = hasNextElement;
                }

                return hasNextElement;
            };

            $scope.goBack = function () {

                if ($stateParams.packageProductCode || $state.$current.name === "package-details.final") {
                    $scope.backWizard($stateParams.packageProductCode);
                } else {

                    if ($scope.isPackageOnly) {
                        window.location = $scope.updateItem ? utilsFactory.addPersistentQueryStringsParams("/checkout") : $scope.$parent.back();
                        return;
                    }

                    $scope.persistCriteria();
                    $scope.$parent.persistWizardModel(function () {
                        var parentDetailsCtrl = $scope.$parent;
                        parentDetailsCtrl.back($state.$current.name);
                    });
                }
            };

            $scope.backWizard = function (packageProductCode) {
                $scope.persistCriteria();
                var prev = undefined;

                $scope.$parent.$parent.cleanGlobalErrors();

                if ($scope.package && $scope.package.details && $scope.package.details.components && $scope.package.details.components.length > 0) {
                    var reversedComponents = Array.prototype.slice.call($scope.package.details.components);  //copy
                    reversedComponents.reverse();

                    if (packageProductCode && packageProductCode.length) {
                        var isCurrCompFound = false;
                        prev = _.find(reversedComponents, function (comp) {
                            if (isCurrCompFound && componentHasForm(comp)) {
                                return true;
                            }
                            if (comp && comp.product && comp.product.code.toLowerCase().trim() === packageProductCode.toLowerCase().trim()) {
                                isCurrCompFound = true;
                            }
                            return false;
                        });
                    } else {
                        //it's package final - go back to the last component with details
                        prev = _.find(reversedComponents, function (comp) { return componentHasForm(comp) });
                    }
                }

                if (prev && componentHasForm(prev)) {
                    $scope.goToComponent(prev);
                } else {
                    $scope.$parent.persistWizardModel(function () {
                        $state.go("package-details"); // "package-details"
                    });
                }
            };

            $scope.nextWizard = function (packageProductCode) {
                if ($scope.isDisabledAddToCart()) return;

                $scope.persistCriteria();
                $scope.$parent.persistWizardModel(function () {
                    $scope.$parent.$parent.cleanGlobalErrors();

                    if (!($scope.package && $scope.package.details && $scope.package.details.components && $scope.package.details.components.length > 0)) {
                        //Error:TODO Redirect
                        return;
                    }

                    var doNext = function () {
                        var next = undefined;

                        if ($scope.package && $scope.package.details && ($scope.package.details.components || "").length > 1) {

                            if (!packageProductCode || !packageProductCode.length) {
                                //package details view
                                next = _.find($scope.package.details.components,
                                    function (c) { return componentHasForm(c); });
                            } else {
                                var isCurrCompFound = false;

                                next = _.find($scope.package.details.components, function (comp) {
                                    if (isCurrCompFound && componentHasForm(comp)) {
                                        return true;
                                    }
                                    if (comp && comp.product && comp.product.code.toLowerCase().trim() === packageProductCode.toLowerCase().trim()) {
                                        isCurrCompFound = true;
                                    }
                                    return false;
                                });
                            }
                        }
                        if (next && componentHasForm(next)) {
                            $scope.goToComponent(next);
                        } else {
                            $state.go("package-details.final");
                        }
                    };

                    var expressConsentOptions = $scope.package.details.expressConsentOptions || $scope.package.expressConsentOptions;
                    if (expressConsentOptions && expressConsentOptions.expressConsentRequired) {
                        var requiredModalInstance = $uibModal.open({
                            animation: true,
                            templateUrl: "expressConsentModal.html",
                            controller: "expressConsentModalCtrl",
                            size: "book-required-products",
                            resolve: {
                                "expressConsent": {
                                    title: utilsFactory.getLabel("general.expressConsent.ConfirmModalTitle"),
                                    message: utilsFactory.getLabel("general.expressConsent.ConfirmModalMessage"),
                                    components: $scope.package
                                }
                            },
                            backdrop: "true"
                        });

                        requiredModalInstance.result.then(function (result) {
                            doNext();
                        }, function (e) {
                            //console.log("dismiss");
                            // debugger;
                        });
                    } else {
                        doNext();
                    }
                });
            };

            $scope.initPixelScript = function () {
                if ($scope.package && $scope.package.code == "PKG-CMB-UEB-ADV") {
                    (function () {
                        /* Please fill the following values. */
                        var params = {
                            vd1: "", /* Departure Date */
                            vd2: "", /* Return Date */
                            vf1: "", /* Destination City */
                            vs1: "", /* Destination State or Region */
                            vn1: "", /* Destination Country */
                            t: "" /* Number of Travelers */
                        };
                        /* Please do not modify the below code. */
                        var cid = [];
                        var paramsArr = [];

                        var cidParams = [];
                        var pl = document.createElement('script');
                        var defaultParams = { "vid": "tou", "et": "vs" };
                        for (var key in defaultParams) { params[key] = defaultParams[key]; };
                        for (var key in cidParams) { cid.push(params[cidParams[key]]); };
                        params.cid = cid.join('|');
                        for (var key in params) {
                            paramsArr.push(key + '=' +
                                encodeURIComponent(params[key]))
                        };
                        pl.type = 'text/javascript';
                        pl.async = true;
                        pl.src = 'https://beacon.sojern.com/pixel/p/119397?f_v=v6_js&p_v=1&' + paramsArr.join('&');
                        (document.getElementsByTagName('head')[0] ||
                            document.getElementsByTagName('body')[0]).appendChild(pl);
                    })();
                }
            };

            $scope.setFiltersFromUrl = function () {
                // grab filter values from the url hash
                if ($stateParams.adults != null && $scope.availableAdults && $scope.availableAdults.indexOf(String($stateParams.adults)) >= 0) {
                    $scope.selectedAdults = parseInt($stateParams.adults) || 1;
                }

                if ($stateParams.children != null && $scope.availableChild && $scope.availableChild.indexOf(String($stateParams.children)) >= 0) {
                    $scope.selectedChild = parseInt($stateParams.children) || 0;
                }

                if ($stateParams.infants != null && $scope.availableInfants && $scope.availableInfants.indexOf(String($stateParams.infants)) >= 0) {
                    $scope.selectedInfants = parseInt($stateParams.infants) || 0;
                }

                $scope.persistCriteria();
            };

            $scope.init = function () {
                if ($state.current.name != "package-details" && !!taskFactory.packageTask) {
                    console.log("Package details already initialized");
                    $scope.isLoading = false;
                    return;
                }

                $scope.initPackageConditionsByPackageCode($stateParams.packageCode);

                var productCategory = jwtService.getProductCategory();
                if (!(productCategory || "").length) {
                    productCategory = jQuery("[ng-controller=productDetailsWrapperCtrl]").data("category");
                }

                switch (productCategory.toLowerCase()) {
                    case "activities":
                        $scope.maxAdults = $("body").attr("data-max-attractions-available-adults") ? parseInt($("body").attr("data-max-attractions-available-adults")) : 5;
                        $scope.maxChildren = $("body").attr("data-max-attractions-available-children") ? parseInt($("body").attr("data-max-attractions-available-children")) : 5;

                        $scope.selectTicketState = "select-ticket";
                        $scope.getSelectedProduct = activitiesService.getSelectedActivity; break;
                    case "hotels":
                        $scope.maxAdults = $("body").attr("data-max-hotels-available-adults") ? parseInt($("body").attr("data-max-hotels-available-adults")) : 5;
                        $scope.maxChildren = $("body").attr("data-max-hotels-available-children") ? parseInt($("body").attr("data-max-hotels-available-children")) : 5;

                        $scope.getSelectedProduct = hotelsService.getSelectedHotel;
                        $scope.selectTicketState = "select-booking-type";
                        break;
                    case "transportation":
                        $scope.maxAdults = $("body").attr("data-max-transportations-available-adults") ? parseInt($("body").attr("data-max-transportations-available-adults")) : 5;
                        $scope.maxChildren = $("body").attr("data-max-transportations-available-children") ? parseInt($("body").attr("data-max-transportations-available-children")) : 5;

                        $scope.selectTicketState = "select-transport-ticket";
                        $scope.getSelectedProduct = transportationService.getSelectedTransportation; break;
                    default:
                        $scope.maxAdults = $("body").attr("data-max-attractions-available-adults") ? parseInt($("body").attr("data-max-attractions-available-adults")) : 5;
                        $scope.maxChildren = $("body").attr("data-max-attractions-available-children") ? parseInt($("body").attr("data-max-attractions-available-children")) : 5;

                }
                $scope.availableAdults = strRange(0, $scope.maxAdults + 1);
                $scope.availableChild = strRange(0, $scope.maxChildren + 1);

                if (!$scope.getSelectedProduct) {
                    window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
                    return;
                }

                var criteria = $scope.getCriteria();

                //if ($stateParams.date) { // old url with the date in the urls should go to default
                //    $state.go("package-details", { packageCode: $stateParams.packageCode }, { notify: true });
                //    return;
                //}

                if (!criteria || !$scope.hasStateArgs()) {
                    $state.go($scope.selectTicketState + ".packages");
                    return;
                }

                var autoLoadData = criteria.selectedPackage != null;

                $scope.fillMainPackage(criteria.selectedPackage, function () {
                    var productDetailsCtrl = $scope.$parent;

                    if (!productDetailsCtrl) {
                        window.location = utilsFactory.addPersistentQueryStringsParams("/");
                        return;
                    }

                    if (!$scope.package) {
                        $state.go($scope.selectTicketState + ".packages");
                        return;
                    }

                    $scope.requestArguments.expanddescriptionbydefault = ($scope.requestArguments.productcodeswithexpandeddescriptionbydefault || []).indexOf($scope.package.code) >= 0;

                    initDatePicker();
                    $scope.initPixelScript();

                    var trackedPackageDate = null;

                    if ($scope.updateItem) {
                        var updateItemDateMoment = $scope.updateItem.startDateMoment
                        var strDate = updateItemDateMoment.format("YYYY-MM-DD");
                        trackedPackageDate = strDate;
                        var formattedStrDate = updateItemDateMoment.format(shoppingCartService.getDateFormat());
                        // Disabled for now: 
                        if ($stateParams.date) {
                            // $stateParams.date = strDate;
                            $state.go($state.$current.name, { date: strDate }, { notify: false });
                            // setLocalParamsToFixState();
                        }
                        //

                        $scope.dateVal = formattedStrDate;


                        $scope.setSelectedDate(formattedStrDate);

                        var firstComp = ($scope.updateItem.BookingToQuote.Packages || "").length ? $scope.updateItem.BookingToQuote.Packages[0] : $scope.updateItem.BookingToQuote.Components[0];
                        $scope.updateItem.isUpdateCompSynced = false;
                        $scope.selectedAdults = firstComp.NumberOfAdults || 2;
                        $scope.selectedChild = firstComp.NumberOfChildren || 0;
                        $scope.selectedSeniors = firstComp.NumberOfSeniors || 0;
                        $scope.selectedStudents = firstComp.NumberOfStudents || 0;
                        $scope.selectedInfants = firstComp.NumberOfInfants || 0;


                        if (criteria.nights > 0) {
                            $scope.selectedNights = criteria.nights;

                        }

                        $scope.defaultNights = criteria.defaultNights;
                        $scope.availableNights = strRange($scope.defaultNights || 1, $scope.maxNights + 1);

                        $scope.isLoading = false;
                        $scope.getPackage();

                    } else {
                        var strDate = $scope.getRequestDate();
                        var startDateMoment = moment(strDate);
                        var formattedStrDate = startDateMoment.format(shoppingCartService.getDateFormat());
                        trackedPackageDate = startDateMoment.format("YYYY-MM-DD");

                        // disabled for now: 
                        if ($stateParams.date) {
                            //$stateParams.date = strDate;
                            $state.go($state.$current.name, { date: strDate }, { notify: false });
                            // setLocalParamsToFixState();
                        }

                        //

                        $scope.dateVal = formattedStrDate;


                        $scope.setSelectedDate(formattedStrDate);

                        if (criteria.adults > 0 || criteria.children > 0) { // || $scope.selectedChild > 0 || $scope.selectedInfants > 0
                            $scope.selectedAdults = criteria.adults || 0;
                            $scope.selectedChild = criteria.children || 0;
                            $scope.selectedInfants = criteria.infants || 0;
                        }

                        //
                        if (criteria.nights > 0) {
                            $scope.selectedNights = criteria.nights;

                        }

                        $scope.setFiltersFromUrl();

                        $scope.defaultNights = criteria.defaultNights;
                        $scope.availableNights = strRange($scope.defaultNights || 1, $scope.maxNights + 1);

                        var savedPackageHasDifferentDate = !$scope.package || !moment($scope.package.startDate).isSame(startDateMoment, "day");

                        if (savedPackageHasDifferentDate || criteria.date !== formattedStrDate || (criteria.adults != $scope.selectedAdults || criteria.children != $scope.selectedChild) || !$scope.package.details
                            || (($scope.package.code || "").toLowerCase() !== ($stateParams.packageCode || "").toLowerCase()
                                && ($scope.package.details && $scope.package.details.code || "").toLowerCase() != ($stateParams.packageCode || "").toLowerCase())
                        ) {
                            criteria.date = formattedStrDate;
                            productDetailsCtrl.savePackagesSearchCriteria(criteria);

                            $scope.isLoading = false;

                            // disable autosearch if user didn't come from the previous packages and tickets search screen
                            // or if the user comes from a different site
                            var userComesFromExternalSite = false;
                            try {
                                var docRef = document.referrer.split('/')[2];
                                // remove port number
                                if (docRef && docRef.indexOf(':') > 0) {
                                    docRef = docRef.substr(0, docRef.indexOf(':'));
                                }

                                userComesFromExternalSite = !docRef || docRef != location.hostname;

                            } catch (e) {
                                console.log("userComesFromExternalSite: ", e);
                            }

                            if (userComesFromExternalSite || autoLoadData || $state.$current.name == "package-details.select" || $state.$current.name == "package-details.final") {
                            
                                //
                                var autoSelectData = _.find($scope.autoSelectAvailableDateForPackageCodes, function (item) {
                                    return item && item.split(' ')[0] == $stateParams.packageCode;
                                });
                                if (autoSelectData) {
                                    var autoSelectLimit = parseInt(autoSelectData.split(' ')[1]);
                                    if (autoSelectLimit > 0) {
                                        $scope.topAutoLoadLimit = autoSelectLimit;
                                    }
                                }
                                //
                                $scope.getPackage(null, null, !!autoSelectData);
                            }
                            else {
                                taskFactory.packageTask = { name: "PackageInit", data: {} };
                            }

                            $scope.isInfantsAvailable = $scope.package.infantRateAvailable;
                        }
                        else {
                            $scope.isLoading = false;
                            $scope.isInfantsAvailable = $scope.package.details.infantRateAvailable;
                            taskFactory.packageTask = { name: "PackageInit", data: {} };

                            if (!$scope.filteredItems && $scope.package.details.components) {
                                fillFilteredComponents($scope.package.details);
                                $scope.wasSearch = true;
                            }
                        }
                    } // not update item

                    //  tracking obj
                    if ($scope.isHotelPackage()) {
                        hotelsService.getSelectedHotel(function (result) {
                            var mainProduct = result.success && result.data;

                            $scope.lobTitle = mainProduct && mainProduct.productDescriptions
                                && (
                                    mainProduct.productDescriptions.genericTitle || (mainProduct.productDescriptions.titles && mainProduct.productDescriptions.titles.length > 0 ? mainProduct.productDescriptions.titles[0] : mainProduct.name));

                            $scope.packageName = $scope.package.packageDescriptions
                                && $scope.package.packageDescriptions.titles
                                && $scope.package.packageDescriptions.titles.length > 0 ? $scope.package.packageDescriptions.titles[0] : $scope.package.name;

                            var packageStartDate = ($scope.package && $scope.package.startDate) || "";
                            if (packageStartDate && packageStartDate.indexOf("0001") < 0) {
                                trackedPackageDate = packageStartDate;
                            }

                            var trackerReq = {
                                lobTitle: $scope.lobTitle,
                                packageName: $scope.packageName,
                                searchDate: trackedPackageDate,
                                adults: parseInt($scope.selectedAdults),
                                children: parseInt($scope.selectedChild),
                                shoppingCart: $scope.cart,
                                anonymUser: $scope.anonymGeneralUser,
                                bookingNumber: null,
                                bookingId: null
                            };

                            trackingService.buildFlowTrackerObj(trackerReq);
                            // dispatchGMTEvent();
                        });

                    } else {
                        activitiesService.getSelectedActivity(function (result) {
                            var mainProduct = result.success && result.data;

                            $scope.lobTitle = mainProduct && mainProduct.productDescriptions
                                && (
                                    mainProduct.productDescriptions.genericTitle || (mainProduct.productDescriptions.titles && mainProduct.productDescriptions.titles.length > 0 ? mainProduct.productDescriptions.titles[0] : mainProduct.name));

                            $scope.packageName = $scope.package.packageDescriptions
                                && $scope.package.packageDescriptions.titles
                                && $scope.package.packageDescriptions.titles.length > 0 ? $scope.package.packageDescriptions.titles[0] : $scope.package.name;

                            var packageStartDate = ($scope.package && $scope.package.startDate) || "";
                            if (packageStartDate && packageStartDate.indexOf("0001") < 0) {
                                trackedPackageDate = packageStartDate;
                            }
                            var trackerReq = {
                                lobTitle: $scope.lobTitle,
                                packageName: $scope.packageName,
                                searchDate: trackedPackageDate,
                                adults: parseInt($scope.selectedAdults),
                                children: parseInt($scope.selectedChild),
                                shoppingCart: $scope.cart,
                                anonymUser: $scope.anonymGeneralUser,
                                bookingNumber: null,
                                bookingId: null
                            };
                            trackingService.buildFlowTrackerObj(trackerReq);
                            // dispatchGMTEvent();
                        });
                    }
                    //
                });
            };

            var initialized = false;

            $scope.anonymUser = undefined;
            $scope.initCurrentAnonymUser = function (callback) {
                var detailsCtrl = $scope.$parent;
                var generalCtrl = detailsCtrl.$parent;

                jwtService.getAnonymousUserByGeography(generalCtrl.selectedGeographyCode, function (user) {
                    $scope.anonymUser = user;
                    callback();
                });
            };

            $scope.isLoading = true;
            $scope.$watch(function () {
                return taskFactory.task;
            },
                function (val) {
                    if (!val || !val.name || initialized) return;
                    initialized = true;

                    var initShoppingCart = new Promise(function (resolve, reject) {
                        shoppingCartService.getStorageCart(function (shoppingCart) {
                            if (shoppingCart) {
                                $scope.cart = shoppingCart;

                                $scope.updateItem = undefined;
                                $scope.updateIndex = -1;

                                if (($scope.requestArguments.updateCartItemCode || "").length && $scope.cart && $scope.cart.Items) {
                                    $scope.updateItem = _.find($scope.cart.Items, function (cartItem) {
                                        $scope.updateIndex++;

                                        var relatedComponent = cartItem.BookingToQuote && (cartItem.BookingToQuote.Components || "").length
                                            &&

                                            _.find(cartItem.BookingToQuote && cartItem.BookingToQuote.Components, function (comp) {
                                                return comp.ProductCode == $scope.requestArguments.updateCartItemCode;
                                            });
                                        if (relatedComponent) return true;
                                        var relatedPackage =
                                            _.find(cartItem.BookingToQuote && cartItem.BookingToQuote.Packages, function (pkg) {
                                                return pkg.PackageCode == $scope.requestArguments.updateCartItemCode;
                                            });
                                        return relatedPackage != null;
                                    });

                                    if ($scope.updateItem) {
                                        $scope.updateItem.startDateMoment = ($scope.updateItem.BookingToQuote.Packages || "").length ? moment($scope.updateItem.BookingToQuote.Packages[0].StartDate)
                                            :
                                            moment($scope.updateItem.BookingToQuote.Components[0].StartDate);
                                    }
                                }
                            }
                            resolve(1);
                        });
                    });
                    initShoppingCart.then(function () {
                        $timeout($scope.initCurrentAnonymUser.bind(null, $scope.init)); //$scope.init);
                    });
                    // $timeout($scope.initCurrentAnonymUser.bind(null, $scope.init));

                }, true);
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";


    angular.module("app").controller("packageFinalCtrl", [
        "$scope", "$element", "$state", "$http", "$uibModal", "productsFactory", "hotelsService", "activitiesService", "$rootScope", "validHelper", "shoppingCartService", "jwtService", "taskFactory", "$timeout", "transportationService", "utilsFactory",
        function ($scope, $element, $state, $http, $uibModal, productsFactory, hotelsService, activitiesService, $rootScope, validHelper, shoppingCartService, jwtService, taskFactory, $timeout, transportationService, utilsFactory) {

            var webUrl = $("body").data("weburl") ? $("body").data("weburl") : "";
            $.material.init();
            $scope.utils = utilsFactory;
            $scope.validHelper = validHelper;
            $scope.isLoading = true;
            $scope.timesBtw = undefined;

            var generalCtrl = $scope.$parent.$parent.$parent.$parent;
            $scope.productLabels = utilsFactory.getLabel("activity.specificProduct", true);
            $scope.getProductLabel = function (productCode, key) {
                var obj = utilsFactory.getProductLabel($scope.productLabels, productCode);
                if (!obj) {
                    var currentRegion = (generalCtrl.selectedGeographyCode || "").toUpperCase();
                    obj = utilsFactory.getProductLabelByRegion($scope.productLabels, currentRegion);
                }
                if (!obj || !key) return obj;
                return obj[key];
            };

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
                if (!$scope.criteria || !$scope.criteria.selectedPackage || !$scope.criteria.selectedPackage.showFinal) {
                    $scope.$parent.goBack();
                }
            });

            $scope.getTotalGuests = function () {
                return parseInt($scope.selectedAdults || 0) + parseInt($scope.selectedChild || 0) + parseInt($scope.selectedInfants || 0);
            };

            $scope.isUnitAvailable = function (unit) {//checkFlag=1-upload 2-download 3 - both default
                if (!unit) return false;

                return unit.availability >= ($scope.getTotalGuests() || 0);
            };

            $scope.reloadRelatedServices = function (comp, date, callback) {
                if (!comp || !date) {
                    callback && callback();
                    return;
                }

                var productQueries = [];

                var obj = {
                    ProductCode: comp.product.code,
                    TravelDate: date
                };
                if (comp.product.selectedUnit) {
                    obj.UnitCode = comp.product.selectedUnit.unitCode;
                }
                productQueries.push(obj);

                var dataToPost = { ProductQueries: productQueries };
                var requestParamsMulti = {
                    token: jwtService.getPrincipalToken(),
                    data: dataToPost
                };

                return productsFactory.getRelatedServicesMulti(requestParamsMulti, function (relatedProducts) {

                    if (relatedProducts && relatedProducts.data && relatedProducts.data.length) {
                        comp.relatedProducts = relatedProducts.data[0];
                        if (comp.relatedProducts && (comp.relatedProducts.attractionTimes || '').length) {
                            var prevUnit = comp.upTimeProduct && comp.upTimeProduct.selectedUnit ? comp.upTimeProduct.selectedUnit.unitCode : "";
                            comp.upTimeProduct = _.find(comp.relatedProducts.attractionTimes, function (at) { return at.isPrimary; });
                            if (comp.upTimeProduct) {
                                var isCurrDate = moment(comp.upTimeProduct.startDate).isSame(jwtService.getServerMomentDate());

                                if (isCurrDate && comp.upTimeProduct.bookingRestrictionTime > 0) {
                                    var tc = jwtService.getServerMomentDate(true);

                                    tc.add(parseInt(comp.upTimeProduct.bookingRestrictionTime), "m");
                                    var timeLimit = moment(tc.format("hh:mm A"), "hh:mm A");

                                    comp.upTimeProduct.filteredUnits = _.filter(comp.upTimeProduct.units, function (un) {
                                        var timeStr = moment(un.startTime).format("hh:mm A");
                                        var unitTimeVal = moment(timeStr, "hh:mm A");
                                        return unitTimeVal > timeLimit;
                                    });
                                } else {
                                    comp.upTimeProduct.filteredUnits = comp.upTimeProduct.units;
                                }

                                //remove the “I’ll choose later” option for tour times
                                // From Matt  update our attraction package page to remove the “I’ll choose later” option for tour times:
                                //!comp.upTimeProduct.isRequiredRelatedProduct && ($scope.package.type != "ATTRACTION") &&
                                if ((comp.upTimeProduct.filteredUnits || "").length && ($scope.package && $scope.package.type != "ATTRACTION")) {
                                    comp.upTimeProduct.filteredUnits = [{ isDisabled: true, unitCode: "" }].concat(comp.upTimeProduct.filteredUnits);
                                }

                                var selectedNew = prevUnit ? _.find(comp.upTimeProduct.filteredUnits, function (c) { return c.unitCode == prevUnit; }) :
                                    undefined;
                                comp.upTimeProduct.selectedUnit = selectedNew && $scope.isUnitAvailable(selectedNew) ? selectedNew : comp.upTimeProduct.filteredUnits[0];
                            }

                            comp.downTimeProduct = _.find(comp.relatedProducts.attractionTimes, function (at) { return !at.isPrimary; });
                            if (comp.upTimeProduct && comp.upTimeProduct.selectedUnit && !comp.upTimeProduct.selectedUnit.isDisabled) {
                                $scope.setDownTimes(comp);
                                $scope.setUnitBoardingTime(comp);
                            }
                        }

                    }
                    if (callback)
                        callback();
                });
            }
            function getRockiesModalErrorIfSoldOutOnDate(comp) {
                var isRockies = ($scope.isRockies2025CombosFlow || $scope.isRockiesCombosFlow || $scope.isRockiesValueCombosFlow || $scope.isRockiesLiteCombosFlow);
                if (isRockies && comp.selectedDateFormatted && comp.upTimeProduct && (!(comp.upTimeProduct.filteredUnits || '').length)) {
                    var label = utilsFactory.getLabel("packages.unit.unavailableOnDatePursuitPass").replace("{0}", comp.description);
                    label = label.replace("{1}", comp.selectedDateFormatted);
                    return label;
                }

                return null;
            }

            function displayModalErrorIfSoldOutOnDate(comp) {
                var label = getRockiesModalErrorIfSoldOutOnDate(comp);
                if (!label) return;

                $timeout(function () {
                    generalCtrl.showModalWithData("SubmitActivityErrors", [label]);
                });
            }

            function initDatePicker() {
                if ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) {
                    moment.locale($scope.selectedLanguage.languageCode);
                }

                if ($scope.criteria && $scope.criteria.selectedPackage) {
                    $timeout(function () {

                        var currentDateFallback = jwtService.getServerMomentDate();



                        var availableFrom = $scope.package && $scope.package.availableFrom && moment($scope.package.availableFrom) || null;
                        if (!availableFrom || !availableFrom.isValid() || availableFrom.year() < 2000) availableFrom = null;
                        else if (availableFrom.isBefore(currentDateFallback, "day")) {
                            availableFrom = currentDateFallback;
                        }

                        var availableTo = $scope.package && $scope.package.availableUntil && moment($scope.package.availableUntil) || null;
                        if (!availableTo || !availableTo.isValid() || availableTo.year() < 2000) availableTo = null;
                        else if (availableFrom && availableTo.isBefore(availableFrom, "day")) {
                            availableFrom = null;
                        }
                        if ($scope.package) {
                            $scope.package._adjustedAvailableFromMoment = availableFrom;
                        }

                        $scope.daterangepicker = jQuery($element).find("[name=daterange]").each(function () {
                            var thisDate = moment(jQuery(this).attr("data-min"));
                            var thisCompNr = jQuery(this).attr("data-compNr");
                            var comp = _.find($scope.package.components, function (comp, index) {
                                return comp.componentNumber == thisCompNr;
                            });

                            var prevVal = $(this).val();

                            if (comp && comp.selectedDate) {
                                var dateVal = moment(comp.selectedDate).format(shoppingCartService.getDateFormat());
                                $(this).val(dateVal);

                                //if (comp.selectedDate == thisDate) {
                                //    jQuery(this).css("color", "white");
                                //} else {
                                //    jQuery(this).css("color", "");
                                //}
                            }

                            var dateConfig = {
                                singleDatePicker: true,
                                minDate: thisDate.isValid() ? thisDate : moment($scope.criteria.selectedPackage.strDate, shoppingCartService.getDateFormat()),
                                showDropdowns: true,
                                autoSelectInitialInput: true,
                                locale: {
                                    format: shoppingCartService.getDateFormat()
                                }
                            };

                            if ($scope.criteria.selectedPackage.travelWindow > 0) { //!!$scope.isRockiesLiteCombosFlow) {
                                //$scope.isRockiesLiteCombosFlow = true;

                                var minDateConfig = moment($scope.criteria.selectedPackage.strDate, shoppingCartService.getDateFormat());
                                dateConfig.minDate = minDateConfig;
                                dateConfig.maxDate = minDateConfig.clone().add($scope.criteria.selectedPackage.travelWindow - 1, "days");
                                dateConfig.autoSelectInitialInput = false; // TODO:
                                dateConfig.showDropdowns = false;
                            } else {
                                if (availableFrom && availableFrom.isValid()) {
                                    dateConfig.minDate = availableFrom;
                                    dateConfig.showDropdowns = false;
                                }
                                if (availableTo && availableTo.isValid()) {
                                    dateConfig.maxDate = availableTo;
                                    dateConfig.showDropdowns = false;
                                }
                            }


                            if ($scope.isRockies2025CombosFlow || $scope.isRockiesCombosFlow || $scope.isRockiesValueCombosFlow) {
                                dateConfig.autoSelectInitialInput = false;
                            }

                            // overwrite
                            if (comp && comp.selectedDate) {
                                dateConfig.autoSelectInitialInput = true;
                            }

                            if (dateConfig.autoSelectInitialInput && dateConfig.minDate && dateConfig.minDate.isValid()) {
                                comp.selectedDate = dateConfig.minDate.format("YYYY-MM-DD");
                                comp.selectedDateFormatted = comp.selectedDate && moment(comp.selectedDate).format("MMMM D");
                            }
                            if (!dateConfig.autoSelectInitialInput) {
                                comp.selectedDate = null;
                                comp.selectedDateFormatted = null;
                            }

                            //if ($scope.selectedLanguage && $scope.selectedLanguage.calendar) {
                            //    dateConfig.locale.daysOfWeek = $scope.selectedLanguage.calendar.daysOfWeek;
                            //    dateConfig.locale.monthNames = $scope.selectedLanguage.calendar.monthNames;
                            //    dateConfig.locale.firstday = $scope.selectedLanguage.calendar.firstDay;
                            //}
                            if (comp.startDateOverwriteable) {
                                var hotelComp = _.find($scope.package.components, function (comp, index) {
                                    return $scope.isItemOfType(comp, $scope.itemTypes.hotel);
                                });
                                if (hotelComp && hotelComp.product) {
                                    var endDate = moment(hotelComp.product.endDate);
                                    if (endDate.isValid()) {
                                        dateConfig.maxDate = endDate;
                                    }
                                }

                            }
                            var dPickerObj = jQuery(this).daterangepicker(dateConfig);

                            dPickerObj.on("apply.daterangepicker", function (ev, picker) {
                                var thisDate = jQuery(this).attr("data-min");
                                var selectedDate = moment(jQuery(this).val(), shoppingCartService.getDateFormat());
                                selectedDate = selectedDate.isValid() ? selectedDate.format("YYYY-MM-DD") : "";

                                var thisCompNr = jQuery(this).attr("data-compNr");
                                var comp = _.find($scope.package.components, function (comp, index) {
                                    return comp.componentNumber == thisCompNr;
                                });

                                comp.enabledDate = true;

                                var selfPicker = jQuery(this).data('daterangepicker');
                                var pickerPromises = [];
                                var mobilePickerIdPos = $(this).attr("id").indexOf("Mobile");
                                // update the main picker too
                                if (mobilePickerIdPos > 0) {
                                    var desktopDatePickerId = $(this).attr("id").substring(0, mobilePickerIdPos);
                                    var $datePicker = jQuery($element).find("#" + desktopDatePickerId);
                                    var dRpck = !$datePicker.length ? null : $datePicker.data('daterangepicker');
                                    if (dRpck) {
                                        dRpck.setStartDate(selfPicker.startDate);
                                        dRpck.setEndDate(selfPicker.startDate);
                                    }
                                } else {
                                    var mobilePickerId = $(this).attr("id") + "Mobile";
                                    var $datePicker = jQuery($element).find("#" + mobilePickerId);
                                    var dRpck = !$datePicker.length ? null : $datePicker.data('daterangepicker');
                                    if (dRpck) {
                                        dRpck.setStartDate(selfPicker.startDate);
                                        dRpck.setEndDate(selfPicker.startDate);
                                    }
                                }

                                if ($scope.packageHasArrivalTimeSelector()) {
                                    if (comp && selectedDate) {
                                        comp.selectedDate = selectedDate;
                                        comp.selectedDateFormatted = comp.selectedDate && moment(comp.selectedDate).format("MMMM D");
                                        displayModalErrorIfSoldOutOnDate(comp);
                                    }

                                    return;
                                }

                                if (!$scope.package.tourTimesCanBeOnDifferentDates) {
                                    $scope.isLoading = true;
                                    jQuery($element).find("[name=daterange]").each(function () {
                                        var dRpck = jQuery(this).data('daterangepicker');

                                        var thisCompNr = jQuery(this).attr("data-compNr");
                                        var comp = _.find($scope.package.components, function (comp, index) {
                                            return comp.componentNumber == thisCompNr;
                                        });
                                        // if (comp.enabledDate) {
                                        dRpck.setStartDate(selfPicker.startDate);
                                        dRpck.setEndDate(selfPicker.startDate);

                                        if ($scope.isItemOfType(comp, $scope.itemTypes.tour) && !comp.upTimeProduct) {
                                            if (comp && selectedDate) {
                                                comp.selectedDate = selectedDate;
                                                comp.selectedDateFormatted = comp.selectedDate && moment(comp.selectedDate).format("MMMM D");
                                                displayModalErrorIfSoldOutOnDate(comp);
                                            }
                                            $scope.setTimeBetweenAttractionsOrder();
                                        } else {
                                            pickerPromises.push($scope.reloadRelatedServices(comp, selectedDate, function () {
                                                if (comp && selectedDate) {
                                                    comp.selectedDate = selectedDate;
                                                    comp.selectedDateFormatted = comp.selectedDate && moment(comp.selectedDate).format("MMMM D");
                                                    displayModalErrorIfSoldOutOnDate(comp);
                                                }
                                                $scope.setTimeBetweenAttractionsOrder();
                                            }));
                                        }
                                        //  }
                                    });
                                    Promise.all(pickerPromises).then(function () {
                                        $scope.setTimeBetweenAttractionsOrder();
                                        //$scope.isLoading = false;
                                        setTimeout(function () {
                                            $scope.isLoading = false;
                                            $scope.$apply();
                                        });
                                    });
                                } else {
                                    //

                                    var reloadData = $scope.reloadRelatedServices;
                                    // if ($scope.isItemOfType(comp, $scope.itemTypes.tour) && !comp.upTimeProduct) {
                                    //     reloadData = function (a, b, callback) { callback(); };
                                    // } else {
                                    $scope.isLoading = true;
                                    //}

                                    //$scope.reloadRelatedServices
                                    reloadData(comp, selectedDate, function () {
                                        if (comp && selectedDate) {
                                            comp.selectedDate = selectedDate;
                                            comp.selectedDateFormatted = comp.selectedDate && moment(comp.selectedDate).format("MMMM D");
                                            displayModalErrorIfSoldOutOnDate(comp);
                                        }
                                        $scope.setTimeBetweenAttractionsOrder();
                                        //$scope.isLoading = false;
                                        setTimeout(function () {
                                            $scope.isLoading = false;
                                            $scope.$apply();
                                        });
                                    });
                                    //
                                }
                            });
                        });
                    });
                }
            }

            $rootScope.$$listeners.$stateChangeStart = [];
            $rootScope.$on("$stateChangeSuccess", function (event, toState, toParams, fromState, fromParams) {
                $scope.wasSubmitTriggered = false;
                if (toState && toState.name == "package-details.final") {
                    initDatePicker();
                }
            });

            $scope.formatDate = function (date, format) {
                return moment(date).format(format ? format : "YYYY-MM-DD");
            };

            $scope.itemTypes = {
                attraction: 1,
                hotel: 2,
                transportation: 3,
                tour: 4
            };

            $scope.shouldShowComponent = function (comp) {
                return comp && comp.product && comp.product && comp.product.productType != 'PKG-HDR';
            };

            $scope.goToComponent = function (component) {
                $scope.$parent.goToComponent(component);
            };

            $scope.goToDetails = function (e) {
                e && e.preventDefault();
                var param = {
                    packageCode: $scope.package.code ? $scope.package.code : $stateParams.packageCode,
                    date: moment($scope.getCriteria().date, shoppingCartService.getDateFormat()).format("YYYY-MM-DD")
                };

                $state.go("package-details", param);
            };

            $scope.isItemOfType = function (item, targetType) {
                if (!item) return false;
                var type = $scope.itemTypes.attraction;
                switch (item.product.productCategory.toLowerCase()) {
                    case "attraction":
                        type = $scope.itemTypes.attraction; break;
                    case "hotel":
                        type = $scope.itemTypes.hotel;
                        break;
                    case "transportation":
                        type = $scope.itemTypes.transportation;
                        break;
                    case "tour":
                        type = $scope.itemTypes.tour;
                        break;
                }
                return type === targetType;
            }

            function intervalInfoStr(diffHH, diffMM) {
                var hoursIntervalInfo = diffHH > 0 ? (diffHH + " hour" + (diffHH != 1 ? "s" : "")) : "";
                var hSplit = hoursIntervalInfo && diffMM > 0 ? " and " : "";
                var minutesIntervalInfo = diffMM > 0 ? (diffMM + " minute" + (diffMM != 1 ? "s" : "")) : "";

                return hoursIntervalInfo + hSplit + minutesIntervalInfo;
            }

            function fillFilteredComponents(pkgDetails) {
                if (!pkgDetails) {
                    $scope.filteredItems = undefined;
                }
                var isCombo = (pkgDetails.type || "").toLowerCase().indexOf("combo") >= 0;

                $scope.filteredItems = _.filter(pkgDetails.components, function (comp) {
                    if ($scope.packageHasArrivalTimeSelector()) {
                        return comp && comp.product && (comp.product.units || '').length > 1;
                    }

                    var shouldShowComp = comp && comp.product && comp.product.productType != 'PKG-HDR';

                    if ($scope.isItemOfType(comp, $scope.itemTypes.hotel)) {
                        $scope.filteredHotel = comp;
                        return false;
                    }

                    // For non - combo packages, if there are any selection boxes on the final screen before checkout that have "no selection required", to not show them     
                    // no selection when upTimeProduct is null

                    return shouldShowComp && ((!$scope.isItemOfType(comp, $scope.itemTypes.tour) && !$scope.isItemOfType(comp, $scope.itemTypes.transportation))
                        ?
                        (comp.availableHours || comp.startDateOverwriteable) && (isCombo || comp.upTimeProduct)
                        :
                        true);
                });
            }

            $scope.fillProductDetails = function (parentProduct, reqproduct) {
                var params = {
                    token: jwtService.getPrincipalToken(),
                    productCode: reqproduct.productCode,
                    productCategory: reqproduct.productCategory,
                    travelDate: reqproduct.startDate.split("T")[0]
                };
                return productsFactory.getProductWithHiddenUnitsWithCallback(params, function (result) {
                    if (!parentProduct.requiredProducts) parentProduct.requiredProducts = [];

                    if (result && result.success && (result.data || "").length) {
                        reqproduct.product = result.data[0];
                        reqproduct.product.selectedUnit = _.find(reqproduct.product.units, function (u) {
                            return reqproduct.unitCode === u.unitCode;
                        });

                        parentProduct.requiredProducts.push(reqproduct);
                    }
                });

            };

            $scope.addPackageToCart = function () {
                // for tour components, that have multiple units that user selects, we need to update related services multi - required products
                // by default the related services of the first unit is loaded

                var tourComp = $scope.package.components && _.find($scope.package.components, function (comp) {
                    return $scope.isItemOfType(comp, $scope.itemTypes.tour) && comp.product && comp.product.selectedUnit && (comp.product.units || "").length > 1;
                });

                var requiresRelatedServicesMultiUpdate = tourComp && tourComp.product && tourComp.product.selectedUnit
                    && tourComp.product.selectedUnit.unitCode != tourComp.product.units[0].unitCode;

                console.log("requiresRelatedServicesMultiUpdate:", requiresRelatedServicesMultiUpdate);

                var getReloadRelatedServicesMultiPromise = function () {
                    return !requiresRelatedServicesMultiUpdate
                        ? Promise.resolve(1)
                        : new Promise(function (resolve, reject) {
                            var requestParamsMulti = {
                                token: jwtService.getPrincipalToken(),
                                pkg: $scope.package,
                                travelDate: moment($scope.criteria.selectedPackage.strDate, shoppingCartService.getDateFormat()).format("YYYY-MM-DD")
                            };

                            productsFactory.fillPackageRelatedServicesMulti(requestParamsMulti, function () {
                                var requiredProductsPromises = [];

                                _.each($scope.package.components, function (comp, index) {
                                    comp.requiredProducts = [];
                                    comp.relatedProducts && _.each(comp.relatedProducts.requiredProducts, function (reqProduct) {
                                        requiredProductsPromises.push($scope.fillProductDetails(comp, reqProduct));
                                    });
                                });

                                Promise.all(requiredProductsPromises).then(function (result) {
                                    resolve(1);
                                }).catch(function () {
                                    resolve(0);
                                });
                            });
                        });
                };


                var removeExistingCartItemPromise = undefined;
                var isUpgrade = $scope.requestArguments &&
                    (($scope.requestArguments.fromwebtray && $scope.requestArguments.isUpgrade) || (!$scope.requestArguments.fromwebtray));

                if ($scope.updateItem && isUpgrade) {
                    removeExistingCartItemPromise = new Promise(function (resolve, reject) {
                        var requestParams = {
                            apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                            token: jwtService.getPrincipalToken(),
                            index: $scope.updateIndex,
                            productCode: $scope.updateItem.ProductCode
                        };

                        shoppingCartService.setStorageCart($scope.cart, function () {
                            shoppingCartService.updateCartComponents(requestParams, function (shoppingCart) {
                                if (shoppingCart && (shoppingCart.Items || '').length) {
                                    $scope.cart = shoppingCart;
                                } else {
                                    // window.location = "/";
                                }
                                resolve(1);
                            });
                        });
                    }); // Promise
                } else {
                    removeExistingCartItemPromise = Promise.resolve(1);
                }

                var getLobTitle = new Promise(function (resolve, reject) {
                    if ($scope.isHotelPackage()) {
                        hotelsService.getSelectedHotel(function (result) {
                            var mainProduct = result.success && result.data;

                            var lobTitle = mainProduct && mainProduct.productDescriptions
                                && (
                                    mainProduct.productDescriptions.genericTitle || (mainProduct.productDescriptions.titles && mainProduct.productDescriptions.titles.length > 0 ? mainProduct.productDescriptions.titles[0] : mainProduct.name));

                            resolve(lobTitle);
                        });

                    } else {
                        activitiesService.getSelectedActivity(function (result) {
                            var mainProduct = result.success && result.data;

                            var lobTitle = mainProduct && mainProduct.productDescriptions
                                && (
                                    mainProduct.productDescriptions.genericTitle || (mainProduct.productDescriptions.titles && mainProduct.productDescriptions.titles.length > 0 ? mainProduct.productDescriptions.titles[0] : mainProduct.name));

                            resolve(lobTitle);
                        });
                    }
                });

                Promise.all([getLobTitle, removeExistingCartItemPromise]).then((function (resultVals) {

                    if ($scope.isLoading) return;
                    $scope.wasSubmitTriggered = true;

                    $scope.setTimeBetweenAttractionsOrder();
                    var errors = [];
                    var totalGuests = parseInt($scope.selectedAdults || 0) + parseInt($scope.selectedChild || 0) + parseInt($scope.selectedInfants || 0);

                    _.each($scope.package.components, function (comp, index) {
                        var rockiesSoldoutError = getRockiesModalErrorIfSoldOutOnDate(comp);
                        if (rockiesSoldoutError) {
                            errors.push(rockiesSoldoutError);
                            return;
                        }

                        if (!comp.product.selectedUnit && (comp.product.units || '').length == 1) {
                            comp.product.selectedUnit = comp.product.units[0];
                        }

                        if (!comp.product.selectedUnit) {
                            errors.push((!!comp.description ? ("<b>" + comp.description + "</b>: ") : "") + "Please select the tour");
                            return;
                        }

                        if (comp.product.selectedUnit) {
                            if (comp.product.selectedUnit.pickupLocationRequired && !comp.product.selectedUnit.selectedPickUp) {
                                errors.push((!!comp.description ? ("<b>" + comp.description + "</b>: ") : "") + "Pick-up location is required");
                            }

                            if (comp.product.selectedUnit.dropoffLocationRequired && !comp.product.selectedUnit.selectedDropOff) {
                                errors.push((!!comp.description ? ("<b>" + comp.description + "</b>: ") : "") + "Drop-off location is required");
                            }
                        }

                        if ($scope.isItemOfType(comp, $scope.itemTypes.tour)) {
                            if (comp.product.selectedUnit && !$scope.isUnitAvailable(comp.product.selectedUnit)) {
                                errors.push("<b>" + comp.product.name + "</b>: " + utilsFactory.getLabel("activity.error.unitUnavailable").replace("{0}",
                                    comp.product.selectedUnit.availability));
                                return;
                            }
                        }

                        if ($scope.packageHasArrivalTimeSelector()) {
                            if ((comp.product.units || "").length < 2) {
                                return;
                            }

                            if (!comp.product.selectedUnit) {
                                errors.push("<b>" + comp.product.name + "</b>: " + utilsFactory.getLabel("packages.unit.arrivalTimeRequired"));
                                return;
                            }

                            if (comp.product.selectedUnit && comp.product.selectedUnit.isDisabled) {
                                errors.push("<b>" + comp.product.name + "</b>: " + utilsFactory.getLabel("packages.unit.arrivalTimeUnavailable"));
                                return;
                            }

                            //var isAvailable = comp.product.selectedUnit && comp.product.selectedUnit.availability >= (totalGuests);

                            //if (comp.product.selectedUnit && !isAvailable) {
                            //    errors.push("<b>" + comp.product.name + "</b>: " + utilsFactory.getLabel("activity.error.unitUnavailable").replace("{0}",
                            //        comp.product.selectedUnit.availability));
                            //    return;
                            //}
                            return;
                        }


                        if (comp.upTimeProduct && comp.upTimeProduct.isRequiredRelatedProduct && (!comp.upTimeProduct.selectedUnit || comp.upTimeProduct.selectedUnit.isDisabled)) {
                            errors.push("<b>" + (comp.description || comp.upTimeProduct.name) + "</b>: " + utilsFactory.getLabel("packages.unit.pickTimeRequired"));
                            return;
                        }

                        if (comp.downTimeProduct && comp.downTimeProduct.isRequiredRelatedProduct && (!comp.downTimeProduct.selectedUnit || comp.downTimeProduct.selectedUnit.isDisabled)) {
                            errors.push("<b>" + (comp.description || comp.downTimeProduct.name) + "</b>: " + utilsFactory.getLabel("packages.unit.pickTimeRequired"));
                            return;
                        }

                        if (comp.selectedDate && comp.upTimeProduct && !comp.upTimeProduct.isRequiredRelatedProduct && (!comp.upTimeProduct.selectedUnit || comp.upTimeProduct.selectedUnit.isDisabled)) {
                            errors.push("<b>" + (comp.description || comp.upTimeProduct.name) + "</b>: " + utilsFactory.getLabel("packages.unit.pickTimeRequiredIfDateSelected"));
                            return;
                        }


                        if (!comp.upTimeProduct || !comp.upTimeProduct.selectedUnit || comp.upTimeProduct.selectedUnit.isDisabled) return;

                        var isAvailable = comp.upTimeProduct.selectedUnit.availability >= (totalGuests);
                        if (!isAvailable) {
                            errors.push("<b>" + comp.upTimeProduct.name + "</b>: " + utilsFactory.getLabel("activity.error.unitUnavailable").replace("{0}",
                                comp.upTimeProduct.selectedUnit.availability));
                            return;
                        } else if (comp.downTimeProduct && comp.downTimeProduct.selectedUnit && !comp.downTimeProduct.selectedUnit.isDisabled) {
                            isAvailable = comp.downTimeProduct.selectedUnit.availability >= (totalGuests);
                            if (!isAvailable) {
                                errors.push("<b>" + comp.downTimeProduct.name + "</b>: " + utilsFactory.getLabel("activity.error.unitUnavailable").replace("{0}",
                                    comp.downTimeProduct.selectedUnit.availability));
                                return;
                            }
                        }

                        if (comp.upTimeProduct.selectedUnit._boardingTime && !comp.upTimeProduct._confirmRebookingFeeInfo) {
                            errors.push("<b>" + (comp.description || comp.product && comp.product.name) + "</b>: " + utilsFactory.getLabel("activity.error.confirmBoardingTime"));
                            return;
                        }

                        if (!comp.timeRestr || !comp.parentRestr) return;

                        var timeDiffStr = (comp.timeRestr.minimumTimeBetweenBookings || "").split(":");
                        if (timeDiffStr.length != 3) return;
                        var diffHH = parseInt(timeDiffStr[0]);
                        var diffMM = parseInt(timeDiffStr[1]);
                        var diffSS = parseInt(timeDiffStr[3]);

                        var firstTimeVal = undefined;
                        var secondTimeVal = undefined;

                        var selectedDate = moment((comp.selectedDate ? comp.selectedDate : comp.product.startDate), "YYYY-MM-DD");
                        var startDate = selectedDate.format("YYYY-MM-DD");

                        var timeProduct = comp.upTimeProduct;
                        if (timeProduct && timeProduct.selectedUnit && !timeProduct.selectedUnit.isDisabled) {
                            var timeStr = timeProduct.selectedUnit.startTime.substring(timeProduct.selectedUnit.startTime.toLowerCase().indexOf('t'));
                            secondTimeVal = moment(startDate + timeStr);
                        }
                        if (!secondTimeVal || !secondTimeVal.isValid()) return;

                        selectedDate = moment((comp.parentRestr.selectedDate ? comp.parentRestr.selectedDate : comp.parentRestr.product.startDate), "YYYY-MM-DD");
                        startDate = selectedDate.format("YYYY-MM-DD");

                        timeProduct = comp.parentRestr.downTimeProduct || comp.parentRestr.upTimeProduct;

                        if (timeProduct && timeProduct.selectedUnit && !timeProduct.selectedUnit.isDisabled) {
                            var timeStr = timeProduct.selectedUnit.startTime.substring(timeProduct.selectedUnit.startTime.toLowerCase().indexOf('t'));
                            firstTimeVal = moment(startDate + timeStr);
                        }
                        if (!firstTimeVal || !firstTimeVal.isValid()) return;
                        firstTimeVal.add(diffHH, "h");
                        firstTimeVal.add(diffMM, "m");
                        firstTimeVal.add(diffSS, "s");
                        if (firstTimeVal.isAfter(secondTimeVal)) {
                            var minimumTimeInfo = intervalInfoStr(diffHH, diffMM);
                            var recommendedTimeInfo = "";
                            var timeDiffStr = (comp.timeRestr.recommendedTimeBetweenBookings || "").split(":");
                            if (timeDiffStr.length == 3) {
                                ;
                                var diffHH = parseInt(timeDiffStr[0]);
                                var diffMM = parseInt(timeDiffStr[1]);
                                var diffSS = parseInt(timeDiffStr[3]);
                                var recommendedTimeInfo = intervalInfoStr(diffHH, diffMM);
                                recommendedTimeInfo = recommendedTimeInfo ? " The recommended time between them is " + recommendedTimeInfo : "";
                            }
                            errors.push("The minimum time between <b>" + comp.timeRestr.firstAttractionName + "</b> and <b>" +
                                comp.timeRestr.secondAttractionName + "</b> is " + minimumTimeInfo + "." + recommendedTimeInfo);
                        }
                    });


                    if (errors.length) {
                        $timeout(function () {
                            generalCtrl.showModalWithData("SubmitActivityErrors", errors);
                        });
                        return;
                    }

                    $scope.isLoading = true;

                    //  Promise start
                    getReloadRelatedServicesMultiPromise().then(function () {


                        var pkg = $scope.package;

                        var bookingPackages = [];
                        var globalComponents = [];

                        var selectedPackage = $scope.$parent.getSelectedPackage();
                        var lobTitle = resultVals && resultVals[0];

                        var packageName = $scope.package.packageDescriptions
                            && $scope.package.packageDescriptions.titles
                            && $scope.package.packageDescriptions.titles.length > 0 ? $scope.package.packageDescriptions.titles[0] : $scope.package.name;

                        var setPkgStartDate = (pkg.details && (pkg.details.startDate || "").split("T")[0]) || (moment($scope.criteria.date).format("YYYY-MM-DD"));

                        if ($scope.isRockies2025CombosFlow || $scope.isRockiesCombosFlow || $scope.isRockiesValueCombosFlow) {
                            setPkgStartDate = pkg._adjustedAvailableFromMoment && pkg._adjustedAvailableFromMoment.format("YYYY-MM-DD") || setPkgStartDate;
                        }

                        var bookingPackage = {
                            "Name": pkg.description,
                            "PackageDescriptions": selectedPackage ? selectedPackage.packageDescriptions : pkg.packageDescriptions,
                            "PackageCode": pkg.code,
                            "StartDate": setPkgStartDate,
                            "Duration": pkg.duration,
                            "DurationType": pkg.durationType,
                            "NumberOfAdults": $scope.criteria.adults,
                            "NumberOfChildren": $scope.criteria.children,
                            "NumberOfInfants": $scope.criteria.infants || "0",
                            "Type": pkg.type,
                            "TravelWindow": pkg.travelWindow,
                            "Components": [],
                            "_trackingLob": lobTitle,
                            "_trackingPackage": packageName
                        };
                        bookingPackages.push(bookingPackage);

                        var wasPkgStartDateSetFromComp = false;
                        var earliestComponentDate = null;

                        // There are 3 combo type, since CIA is its own thing
                        // ATTRACTION – is CIA
                        // COMBO – is Pursuit Pass etc
                        // FBCOMBO – attraction + meal combos at Gondola / Flyovers / Canyon

                        // for packages with type='Attraction' we need the dates on the time product and package product to match
                        // If packageType = "FBCOMBO", the date changes SHOULD be applied to the package components
                        

                        var isAttractionPkgType = (bookingPackage.Type || "").toUpperCase() == "ATTRACTION";
                        var isFBCombo = (bookingPackage.Type || "").toUpperCase() == "FBCOMBO";
                        var shouldAppllyDateChangesToPackage = isAttractionPkgType || isFBCombo;

                        $.each(pkg.components, function (key, comp) {
                            var pComp = {
                                "ProductType": comp.product.productType,
                                "ComponentNumber": comp.componentNumber,
                                "ProductCategory": comp.product.productCategory,
                                "ProductCode": comp.product.code,
                                "ProductName": comp.product.name,
                                "ProductDescription": comp.product.description,
                                "ProductDescriptions": comp.product.packageDescriptions,
                                "UnitCode": comp.product.selectedUnit.unitCode,
                                "UnitDescription": comp.product.selectedUnit.description,
                                "ServiceOption": null,
                                "PickupLocation": comp.product.selectedUnit.selectedPickUp,
                                "DropoffLocation": comp.product.selectedUnit.selectedDropOff,
                                "PriceBreakdown": comp.product.selectedUnit.priceBreakdown,
                                //for display only
                                "ComponentDescription": comp.description,
                                "CheckoutDescription": comp.product.selectedUnit.productDescriptions && comp.product.selectedUnit.productDescriptions.checkoutDescription,
                                "PerPerson": comp.perPerson,
                                "isHidden": comp.isHidden,
                                "StartDate": comp.product.startDate,
                                "EndDate": comp.product.endDate
                            };

                            if (comp.numberOfNights) {
                                pComp.NumberOfNights = comp.numberOfNights;
                                pComp.EndDate = comp.endDate;
                            }

                            var canSetPackageStartDateFromComp = false;
                            if (($scope.packageHasArrivalTimeSelector() || comp.startDateOverwriteable) && comp.selectedDate) {

                                // When the guest picks a travel date/time, that date/time should be placed onto the related services only. The date changes should not be applied to the package components. It is important to scope this to attraction products in packages.
                                // exception
                                if (pComp.ProductCategory != "Attraction" && (pComp.ProductCategory == "Tour" && !comp.upTimeProduct || pComp.ProductCategory != "Tour")) {
                                    pComp.StartDate = comp.selectedDate;
                                    canSetPackageStartDateFromComp = true;
                                }


                                //if ($scope.packageHasArrivalTimeSelector()) {
                                if (!$scope.isHotelPackage() && (!$scope.isRockies2025CombosFlow && !$scope.isRockiesCombosFlow && !$scope.isRockiesValueCombosFlow && !$scope.isRockiesLiteCombosFlow && !(pkg.travelWindow > 0))
                                    && canSetPackageStartDateFromComp
                                ) { // && !wasPkgStartDateSetFromComp
                                    // set the package start date to the earlieast component start date
                                    var nextCompDate = moment(comp.selectedDate);
                                    if (!earliestComponentDate || earliestComponentDate.isAfter(nextCompDate)) {
                                        earliestComponentDate = nextCompDate;

                                        bookingPackage.StartDate = comp.selectedDate;
                                    }
                                    // wasPkgStartDateSetFromComp = true; // take the first
                                }

                            } else { //if (!comp.startDateOverwriteable) {
                                pComp.StartDate = comp.startdatestr;
                            }

                            if (comp.stretchable) {
                                var isHotel = (pComp.ProductCategory || '').toLowerCase() == "hotel";
                                var duration = parseInt(pkg.duration) || 0;
                                if (!isHotel) {
                                    duration = duration - 1;
                                }
                                if (duration > 0) {
                                    pComp.EndDate = moment(pComp.StartDate).add(duration, 'd').format("YYYY-MM-DD");
                                } else {
                                    pComp.EndDate = pComp.StartDate;
                                }
                            } else if (!comp.numberOfNights) {
                                pComp.EndDate = (comp.product && comp.product.endDate) || pComp.StartDate;
                            }

                            // make sure the end date is not after start date
                            var pCompStartDate = moment(pComp.StartDate);
                            var pCompEndDate = moment(pComp.EndDate);
                            if (pCompStartDate.isValid() && (!pCompEndDate.isValid() || pCompEndDate.isBefore(pCompStartDate))) {
                                pComp.EndDate = pComp.StartDate;
                            }
                            //

                            bookingPackage.Components.push(pComp);

                            //set required products
                            if ((comp.requiredProducts || "").length) {
                                _.each(comp.requiredProducts, function (reqProd) {
                                    globalComponents.push({
                                        "Id": reqProd.product.id,
                                        "ProductCategory": reqProd.product.productCategory,
                                        "ProductType": reqProd.product.productType,
                                        "ProductCode": reqProd.product.code,
                                        "StartDate": reqProd.product.startDate,
                                        "EndDate": reqProd.product.endDate,
                                        "Name": reqProd.product.name,
                                        "Description": reqProd.product.description,
                                        "ProductDescriptions": reqProd.product.productDescriptions,
                                        "Price": reqProd.product.price,
                                        "ChildPrice": reqProd.product.price,
                                        "NumberOfAdults": $scope.criteria.adults,
                                        "NumberOfChildren": $scope.criteria.children,
                                        "NumberOfSeniors": 0,
                                        "NumberOfStudents": 0,
                                        "NumberOfInfants": $scope.criteria.infants || "0",
                                        "Status": "New",
                                        "UnitCode": reqProd.product.selectedUnit ? reqProd.product.selectedUnit.unitCode : reqProd.unitCode,
                                        "UnitDescription": reqProd.product.selectedUnit ? reqProd.product.selectedUnit.description : reqProd.product.description,
                                        "PickupLocation": undefined,
                                        "DropoffLocation": undefined,
                                        "StartingLocation": reqProd.product.startingLocation,
                                        "Destination": undefined,
                                        "Remarks": [],
                                        "IsFee": reqProd.product.productType === "FEE",
                                        "ShowInCart": reqProd.showInCart
                                    });
                                });
                            }

                            //set selected time

                            if (comp.upTimeProduct &&
                                comp.upTimeProduct.selectedUnit && !comp.upTimeProduct.selectedUnit.isDisabled) {
                                var timeProduct = comp.upTimeProduct;
                                var selectedDate = undefined;
                                var selectedUpDate = undefined;
                                if (jQuery("#daterangeActivity" + comp.componentNumber).length) {
                                    selectedDate = moment(jQuery("#daterangeActivity" + comp.componentNumber).val(),
                                        shoppingCartService.getDateFormat()).format("YYYY-MM-DD");
                                    var timeStr = timeProduct.selectedUnit.startTime.substring(timeProduct.selectedUnit.startTime.toLowerCase().indexOf('t'));
                                    selectedUpDate = selectedDate + timeStr;
                                }
                                var timeComponent = {
                                    "Id": timeProduct.code + timeProduct.selectedUnit.unitCode,
                                    "ProductCategory": timeProduct.productCategory,
                                    "ProductType": timeProduct.productType,
                                    "ProductCode": timeProduct.code,
                                    "StartDate": selectedUpDate ? selectedUpDate : timeProduct.startDate,
                                    "EndDate": selectedUpDate ? selectedUpDate : timeProduct.endDate,
                                    "Name": timeProduct.name,
                                    "Description": timeProduct.description,
                                    "Price": 0.0,
                                    "ChildPrice": 0,
                                    "NumberOfAdults": $scope.criteria.adults,
                                    "NumberOfChildren": $scope.criteria.children,
                                    "NumberOfInfants": $scope.criteria.infants,
                                    "Status": "New",
                                    "UnitCode": timeProduct.selectedUnit.unitCode,
                                    "UnitDescription": timeProduct.selectedUnit.description,
                                    "PickupLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                                    "DropoffLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                                    "StartingLocation": timeProduct.startingLocation,
                                    "Destination": timeProduct.destination,
                                    "Remarks": [],
                                    "ParentCode": comp.product.code
                                };
                                globalComponents.push(timeComponent);

                                if (comp.downTimeProduct &&
                                    comp.downTimeProduct.selectedUnit) {
                                    timeProduct = comp.downTimeProduct;
                                    var selectedDownDate = undefined;
                                    if (selectedDate) {
                                        var timeStr = timeProduct.selectedUnit.startTime.substring(timeProduct.selectedUnit.startTime.toLowerCase().indexOf('t'));
                                        selectedDownDate = selectedDate + timeStr;
                                    }
                                    timeComponent = {
                                        "Id": timeProduct.code + timeProduct.selectedUnit.unitCode,
                                        "ProductCategory": timeProduct.productCategory,
                                        "ProductType": timeProduct.productType,
                                        "ProductCode": timeProduct.code,
                                        "StartDate": selectedDownDate ? selectedDownDate : timeProduct.startDate,
                                        "EndDate": selectedDownDate ? selectedDownDate : timeProduct.endDate,
                                        "Name": timeProduct.name,
                                        "Description": timeProduct.description,
                                        "Price": 0.0,
                                        "ChildPrice": 0,
                                        "NumberOfAdults": $scope.criteria.adults,
                                        "NumberOfChildren": $scope.criteria.children,
                                        "NumberOfInfants": $scope.criteria.infants,
                                        "Status": "New",
                                        "UnitCode": timeProduct.selectedUnit.unitCode,
                                        "UnitDescription": timeProduct.selectedUnit.description,
                                        "PickupLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                                        "DropoffLocation": { "Code": "", "Name": "", "Time": "00:00:00" },
                                        "StartingLocation": timeProduct.startingLocation,
                                        "Destination": timeProduct.destination,
                                        "Remarks": [],
                                        "ParentCode": comp.product.code
                                    };
                                    globalComponents.push(timeComponent);
                                }
                            }

                        });

                        if (shouldAppllyDateChangesToPackage) {
                            var earliestSelectedComponentDate = null;
                            var productCodesWithSelectedDate = [];
                            $.each(pkg.components, function (key, comp) {
                                if (!comp.selectedDate) return;

                                var nextCompDate = moment(comp.selectedDate);
                                if (!earliestSelectedComponentDate || earliestSelectedComponentDate.isAfter(nextCompDate)) {
                                    earliestSelectedComponentDate = nextCompDate;
                                }
                            });

                            // The date change needs to be applied across the whole package.
                            if (earliestSelectedComponentDate) {
                                var earliestSelectedComponentDateFormatted = earliestSelectedComponentDate.format("YYYY-MM-DD");

                                bookingPackage.StartDate = earliestSelectedComponentDateFormatted;
                                $.each(bookingPackage.Components, function (key, comp) {
                                    comp.StartDate = comp.EndDate = earliestSelectedComponentDateFormatted;
                                });

                                globalComponents && $.each(globalComponents, function (key, comp) {
                                    if (comp.ProductType == "FLT-TIME") return;
                                    comp.StartDate = comp.EndDate = earliestSelectedComponentDateFormatted;
                                });
                            }
                        }

                        //if (errors.length) {
                        //    $timeout(function () {
                        //        generalCtrl.showModalWithData("SubmitActivityErrors", errors);
                        //    });
                        //    return;
                        //}

                        // $scope.isLoading = true;

                        var bookingToQuote = {
                            "Packages": bookingPackages,
                            "Components": globalComponents
                        };

                        var specialProductsRequestParams = {
                            apiUrl: $scope.$parent.$parent.getWebUrl(),
                            token: jwtService.getPrincipalToken(),
                            dataToPost: {
                                "Booking": bookingToQuote
                            }
                        };

                        shoppingCartService.handleSpecialProducts(specialProductsRequestParams, function (result) {
                            if (!result) {
                                $scope.isLoading = false;
                                return;
                            }

                            var data = {
                                "BookingToQuote": result
                            };

                            var requestParams = {
                                apiUrl: $scope.$parent.$parent.getWebUrl(),
                                token: jwtService.getPrincipalToken(),
                                dataToPost: data,
                                startDate: $scope.criteria.date,
                                endDate: undefined,
                                startTime: undefined,
                                endTime: undefined
                            };

                            //shoppingCartService.addComponentsToCart(requestParams, function (result, error) {
                            shoppingCartService.quoteComponents(requestParams, function (quoteResult) {
                                if (quoteResult) {
                                    quoteResult.lastAddedItemDetails = $scope.package;
                                    shoppingCartService.addQuotedDataToCart(quoteResult, function () {
                                        var isEnhanceBookingPageEnabled = ($scope.selectedLanguage && $scope.selectedLanguage.enableEnhanceBookingPage) || ($scope.anonymUser && $scope.anonymUser.enableEnhanceBookingPage);
                                        var redirectToUrl = shoppingCartService.utils.getAfterAddToCartPageUrl(generalCtrl.selectedGeographyCode, isEnhanceBookingPageEnabled);
                                        window.location = utilsFactory.addPersistentQueryStringsParams(redirectToUrl);
                                    });
                                } else {
                                    $scope.isLoading = false;
                                }
                                // $scope.isLoading = false;
                            });
                        });
                    });
                }).bind(this)); // EndPromise resolve   

            };

            $scope.pickUpChanged = function (unit, pickUp) {
                unit.selectedPickUp = pickUp;
            };

            $scope.dropOffChanged = function (unit, dropOff) {
                unit.selectedDropOff = dropOff;
            };


            $scope.fillBussStopsUnits = function (callback) {
                var units = [];
                $.each($scope.criteria.selectedPackage.details.components, function (key, compVal) {

                    $.each(compVal.product.units, function (unitKey, unitVal) {
                        if (unitVal.pickupLocationRequired || unitVal.dropoffLocationRequired) {
                            units.push({ unit: unitVal, productCode: compVal.product.code });
                        };
                    });
                });

                var unitParams = {
                    urlPrefix: $("body").data("weburl") ? $("body").data("weburl") : "",
                    token: jwtService.getPrincipalToken()
                };

                function setBusStopForUnit(index) {
                    if (!units[index]) {
                        if (callback) {
                            callback();
                        }
                        return;
                    }
                    if ((units[index].unit.pickups || "").length || (units[index].unit.dropoffs || "").length) {
                        // load pickups from the unit
                        units[index].unit.busStops = { pickups: units[index].unit.pickups, dropoffs: units[index].unit.dropoffs };
                        if (units[index].unit.busStops && units[index].unit.busStops.pickups.length) {
                            units[index].unit.selectedPickUp = units[index].unit.selectedPickUp && _.find(units[index].unit.busStops.pickups, function (pick) {
                                return pick.code == units[index].unit.selectedPickUp.code;
                            });
                            //if (!units[index].unit.selectedPickUp) {
                            //    units[index].unit.selectedPickUp = units[index].unit.busStops.pickups[0];
                            //}
                        } else {
                            units[index].unit.selectedPickUp = undefined;
                        }


                        if (units[index].unit.busStops && units[index].unit.busStops.dropoffs.length) {
                            units[index].unit.selectedDropOff = units[index].unit.selectedDropOff && _.find(units[index].unit.busStops.dropoffs, function (dropoff) {
                                return dropoff.code == units[index].unit.selectedDropOff.code;
                            });
                            //if (!units[index].unit.selectedDropOff) {
                            //    units[index].unit.selectedDropOff = units[index].unit.busStops.dropoffs[0];
                            //}
                        } else {
                            units[index].unit.selectedDropOff = undefined;
                        }

                        setBusStopForUnit(index + 1);
                    } else {
                        unitParams.productCode = units[index].productCode;
                        unitParams.unitCode = units[index].unit.unitCode;
                        transportationService.getBusStops(unitParams, function (dateResult) {
                            units[index].unit.busStops = dateResult.data;
                            //units[index].unit.selectedPickUp = units[index].unit.busStops && units[index].unit.busStops.pickups.length ? units[index].unit.busStops.pickups[0] : undefined;
                            //units[index].unit.selectedDropOff = units[index].unit.busStops && units[index].unit.busStops.dropoffs.length ? units[index].unit.busStops.dropoffs[0] : undefined;
                            if (units[index].unit.selectedPickUp && units[index].unit.busStops && units[index].unit.busStops.pickups.length) {
                                units[index].unit.selectedPickUp = _.find(units[index].unit.busStops.pickups, function (pick) {
                                    return pick.code == units[index].unit.selectedPickUp.code;
                                });
                                //if (!units[index].unit.selectedPickUp) {
                                //    units[index].unit.selectedPickUp = units[index].unit.busStops.pickups[0];
                                //}
                            } else {
                                units[index].unit.selectedPickUp = undefined;
                            }

                            if (units[index].unit.selectedDropOff && units[index].unit.busStops && units[index].unit.busStops.dropoffs.length) {
                                units[index].unit.selectedDropOff = _.find(units[index].unit.busStops.dropoffs, function (dropoff) {
                                    return dropoff.code == units[index].unit.selectedDropOff.code;
                                });
                                //if (!units[index].unit.selectedDropOff) {
                                //    units[index].unit.selectedDropOff = units[index].unit.busStops.dropoffs[0];
                                //}
                            } else {
                                units[index].unit.selectedDropOff = undefined;
                            }
                            setBusStopForUnit(index + 1);
                        });
                    }
                };

                setBusStopForUnit(0);
            };

            $scope.noTime = {
                key: $scope.utils.getLabel("general.chose-later"), //$scope.isRockies2025CombosFlow ? utilsFactory.getLabel("general.pick-time") : $scope.utils.getLabel("general.chose-later"),
                value: null
            };

            $scope.timeChanged = function (item, hour) {
                item.selectedTime = hour;
            };

            $scope.getTimeDescription = function (timeUnit, timeProduct) {
                if (!timeUnit) {
                    return "";
                }
                if (timeUnit.isDisabled) {
                    var hasClearDate = $scope.mainPackage && $scope.mainPackage.travelWindow || $scope.isRockies2025CombosFlow || $scope.isRockiesCombosFlow || $scope.isRockiesValueCombosFlow || $scope.isRockiesLiteCombosFlow;

                    return (hasClearDate||timeProduct && timeProduct.isRequiredRelatedProduct) ? utilsFactory.getLabel("general.pick-time") : utilsFactory.getLabel("general.chose-later"); //$scope.isRockies2025CombosFlow ? utilsFactory.getLabel("general.pick-time") : utilsFactory.getLabel("general.chose-later");
                }
                if (timeUnit.description) return timeUnit.description;
                switch (timeProduct.productType) {
                    case "FLT-TIME":
                        return moment(timeUnit.startTime).format("hh:mm A");
                    default:
                        return moment(timeUnit.startTime).format("hh:mm A");
                }
            };

            $scope.downTimeChanged = function (unit) {
                $scope.setTimeBetweenAttractionsOrder();
            };

            $scope.resetCompDate = function (comp) {
                var selectedTimeUnit = comp && comp.upTimeProduct && comp.upTimeProduct.selectedUnit;
                if (!!selectedTimeUnit) {
                    comp.upTimeProduct.selectedUnit = comp.upTimeProduct.filteredUnits && comp.upTimeProduct.filteredUnits[0];
                }
                if (!!comp.downTimeProduct) {
                    comp.downTimeProduct.selectedUnit = null;
                }
                // to do: change the date\
                var $datePicker = jQuery("#daterangeActivity" + comp.componentNumber);
                if (!$datePicker) return;

                var dRpck = $datePicker.data('daterangepicker');
                if (!dRpck) return;




                //var minDate = moment(dRpck.minDate);
                //var newSelectedDate = (minDate.isValid() && minDate.isSameOrAfter(moment(), 'day')) ? minDate : "";
                //if (newSelectedDate) {
                //    dRpck.setStartDate(newSelectedDate);
                //    dRpck.setEndDate(newSelectedDate);
                //    dRpck.clickApply();
                //}

                $datePicker.val('');
                comp.selectedDate = null;
                comp.selectedDateFormatted = null;
            };

            $scope.setUnitBoardingTime = function (comp) {
                var showBoardingTimeInfo = $scope.requestArguments && ($scope.requestArguments.showboardingtimeforproductcodes || '').indexOf(comp.product && comp.product.code) >= 0;

                if (!showBoardingTimeInfo) return;
                var selectedUnit = comp.product && (comp.product.selectedUnit || comp.product.units[0]);
                var boardingTimeDescription = selectedUnit && selectedUnit.productDescriptions && selectedUnit.productDescriptions.boardingTimeDescription;

                if (!boardingTimeDescription) return;
                //if (!(comp.product && comp.product.productDescriptions && comp.product.productDescriptions.boardingTimeDescription)) return;

                var selectedTimeUnit = comp && comp.upTimeProduct && comp.upTimeProduct.selectedUnit;
                if (!selectedTimeUnit || !selectedTimeUnit.startTime) return;

                var momentObj = moment(selectedTimeUnit.startTime);
                if (!momentObj || !momentObj.isValid()) return;

                var timeStr = momentObj.subtract(15, 'minutes').format("hh:mm A");
                selectedTimeUnit._boardingTime = timeStr;
                selectedTimeUnit._boardingTimeDescription = boardingTimeDescription;
            };

            $scope.adjustSelectedUnit = function (item) {
                // fix angularjs select issue
                item.selectedUnit = item.selectedUnit && item.units && item.units.find(function (it) {
                    return item.selectedUnit.unitCode == it.unitCode;
                }) || item.selectedUnit;
            };

            $scope.setDownTimes = function (unit) {

                if (!unit || !unit.upTimeProduct || !unit.downTimeProduct) {
                    $scope.setTimeBetweenAttractionsOrder();
                    return;
                }
                if (!unit.upTimeProduct.selectedUnit) {
                    unit.downTimeProduct.selectedUnit = undefined;
                    $scope.setTimeBetweenAttractionsOrder();
                    return;
                }

                var startMin = moment(unit.upTimeProduct.selectedUnit.startTime);
                var startRecomm = moment(unit.upTimeProduct.selectedUnit.startTime);

                var interval = unit.downTimeProduct.minimumIntervalInMinutes
                    ? parseInt(unit.downTimeProduct.minimumIntervalInMinutes) : 0;

                startMin.add(interval, "m");

                unit.downTimeProduct.filteredUnits = _.filter(unit.downTimeProduct.units, function (un) {
                    return startMin <= moment(un.startTime);
                });

                if (!(unit.downTimeProduct.filteredUnits || "").length || !unit.downTimeProduct.recommendedIntervalInMinutes) {
                    unit.downTimeProduct.selectedUnit = undefined;
                    return;
                }

                interval = parseInt(unit.downTimeProduct.recommendedIntervalInMinutes);
                startRecomm.add(interval, "m");

                unit.downTimeProduct.selectedUnit = _.find(unit.downTimeProduct.filteredUnits, function (un) {
                    return startRecomm <= moment(un.startTime);
                });

                if (!unit.downTimeProduct.selectedUnit) {
                    unit.downTimeProduct.selectedUnit = unit.downTimeProduct.filteredUnits[0];
                }
                $scope.setTimeBetweenAttractionsOrder();
            };

            $scope.setTimeBetweenAttractionsOrder = function () {

                var sortedComp = _.map($scope.package.components, function (comp, index) {
                    comp.timeRestr = undefined;
                    comp.parentRestr = undefined;

                    var selectedDate = moment((comp.selectedDate ? comp.selectedDate : comp.product.startDate), "YYYY-MM-DD");
                    var startDate = selectedDate.format("YYYY-MM-DD");
                    var upTime = undefined;
                    var downTime = undefined;

                    if (comp.upTimeProduct && comp.upTimeProduct.selectedUnit && !comp.upTimeProduct.selectedUnit.isDisabled) {
                        var timeStr = comp.upTimeProduct.selectedUnit.startTime.substring(comp.upTimeProduct.selectedUnit.startTime.toLowerCase().indexOf('t'));
                        upTime = moment(startDate + timeStr);
                        upTime = upTime.isValid() ? upTime.toDate().getTime() : "";
                    }
                    if (comp.downTimeProduct && comp.downTimeProduct.selectedUnit && !comp.downTimeProduct.selectedUnit.isDisabled) {
                        var timeStr = comp.downTimeProduct.selectedUnit.startTime.substring(comp.downTimeProduct.selectedUnit.startTime.toLowerCase().indexOf('t'));
                        downTime = moment(startDate + timeStr);
                        downTime = downTime.isValid() ? downTime.toDate().getTime() : "";
                    }

                    var c = {
                        startDate: selectedDate.toDate().getTime(),
                        upTime: upTime,
                        downTime: downTime,
                        code: comp.product.code,
                        index: index
                    };
                    return c;
                });

                sortedComp = _.sortBy(sortedComp, function (scomp) {
                    return scomp.upTime || scomp.startDate;
                });

                _.each(sortedComp, function (scomp, sindex) {
                    var snextComp = sortedComp[sindex + 1];

                    if (snextComp && scomp.startDate == snextComp.startDate && scomp.upTime && snextComp.upTime) {
                        var firstAttr = undefined;
                        if (scomp.upTime <= snextComp.upTime) {

                            firstAttr = _.find($scope.timesBtw, function (t) {
                                return t.firstAttractionCode === scomp.code
                                    &&
                                    t.secondAttractionCode === snextComp.code;
                            });
                            if (firstAttr && $scope.package.components[snextComp.index]) {
                                $scope.package.components[snextComp.index].timeRestr = firstAttr;
                                $scope.package.components[snextComp.index].parentRestr = $scope.package.components[scomp.index];
                            }
                        }
                        else {

                            firstAttr = _.find($scope.timesBtw, function (t) {
                                return t.firstAttractionCode === snextComp.code
                                    &&
                                    t.secondAttractionCode === scomp.code;
                            });
                            if (firstAttr && $scope.package.components[scomp.index]) {
                                $scope.package.components[scomp.index].timeRestr = firstAttr;
                                $scope.package.components[scomp.index].parentRestr = $scope.package.components[snextComp.index];;
                            }
                        }

                    }
                });
            };

            $scope.packageHasArrivalTimeSelector = function () {
                return !!$scope.package && ($scope.package.type == "FBCOMBO" && (jwtService.getGeography() || "").toUpperCase().indexOf("SKL") >= 0);
            };

            $scope.updateProductSelectedUnit = function (product) {
                console.log("update selected unit: ", product);
                // fix strange issue where selected unit has different data than it is in the units[] array
                if (product.selectedUnit && product.units) {
                    product.selectedUnit = product.units.find(function (unit) {
                        return unit.unitCode == product.selectedUnit.unitCode;
                    });
                }
            };

            $scope.initLabels = function () {
                if (($scope.criteria && $scope.criteria.selectedPackage) && ($scope.isRockiesLiteCombosFlow == null)) {
                    $scope.$parent.initPackageConditionsByPackageCode($scope.criteria.selectedPackage.code);
                }

                if ($scope.criteria && $scope.criteria.selectedPackage && ($scope.criteria.selectedPackage.travelWindow > 0)) { // $scope.isRockiesLiteCombosFlow ||
                    $scope.isRockiesLiteCombosFlow = true;

                    var startDate = moment($scope.criteria.selectedPackage.strDate, shoppingCartService.getDateFormat());
                    var from = startDate.format("MMMM D");
                    var endDate = startDate.add($scope.criteria.selectedPackage.travelWindow - 1, "days");
                    var to = endDate.format("MMMM D");

                    $scope.reserveTimesBetweenLabel = utilsFactory.getLabel("packages.reserve-attraction-times-between").replace("{0}", from).replace("{1}", to);

                    $scope.selectedTripRange = $scope.criteria.selectedPackage.strDate + " - " + endDate.format(shoppingCartService.getDateFormat());
                }
                return null;
            };

            $scope.init = function () {
                $scope.isLoading = true;
                $scope.criteria = $scope.$parent.getCriteria();

                if (!$scope.criteria || !$scope.criteria.selectedPackage || !$scope.criteria.selectedPackage.details) {
                    window.location = utilsFactory.addPersistentQueryStringsParams("/");
                    return;
                }
                $scope.totalGuests = (parseInt($scope.criteria.adults || 0) + parseInt($scope.criteria.children || 0) +
                    parseInt($scope.criteria.seniors || 0) + parseInt($scope.criteria.students, 0) + parseInt($scope.criteria.infants, 0));

                $scope.mainPackage = $scope.criteria.selectedPackage;
                $scope.package = $scope.criteria.selectedPackage.details;
                fillFilteredComponents($scope.package);
                $scope.initLabels();

                var isFirst = true;
                $.each($scope.package.components, function (key, comp) {
                    if ($scope.updateItem && !$scope.updateItem.wasUnitSelected && ($scope.updateItem.BookingToQuote.Packages || "").length) {
                        var updatepkg = $scope.updateItem.BookingToQuote.Packages[0];
                        var updatepkgComp = _.find(updatepkg.Components, function (updatecomp) {
                            return updatecomp.ProductCode == comp.product.code;
                        });
                        if (updatepkgComp) {
                            comp.product.selectedUnit = _.find(comp.product.units, function (un) {
                                return un.unitCode == updatepkgComp.UnitCode;
                            });
                            comp.selectedDate = updatepkgComp.StartDate;
                            comp.selectedDateFormatted = comp.selectedDate && moment(comp.selectedDate).format("MMMM D");

                            // var compDatePicker = jQuery($element).find("[name=daterange][data-compNr=" + comp.componentNumber + "]");
                            // compDatePicker.val(moment(comp.selectedDate).format(shoppingCartService.getDateFormat()));

                            if (comp.product.selectedUnit) {
                                comp.product.selectedUnit.selectedPickUp = _.find(comp.product.selectedUnit.pickups, function (pick) {
                                    return (pick && pick.code) == (updatepkgComp.PickupLocation && updatepkgComp.PickupLocation.code);
                                });

                                comp.product.selectedUnit.selectedDropOff = _.find(comp.product.selectedUnit.dropoffs, function (dropoff) {
                                    return (dropoff && dropoff.code) == (updatepkgComp.DropoffLocation && updatepkgComp.DropoffLocation.code);
                                });
                            }
                            $scope.updateItem.wasUnitSelected = true;
                        }
                    }

                    //if ((!$scope.packageHasArrivalTimeSelector() || ($scope.packageHasArrivalTimeSelector() && (comp.product.units || '').length == 1)) && !comp.product.selectedUnit) {
                    //    comp.product.selectedUnit = comp.product.units[0];
                    //}
                    if (!comp.product.selectedUnit && ((comp.product.units || '').length == 1)) {
                        comp.product.selectedUnit = comp.product.units[0];
                    }

                    comp.isFirst = isFirst;
                    isFirst = false;
                    var startDate = moment(comp.product.startDate);

                    comp.startdatestr = startDate.isValid() ? startDate.format("YYYY-MM-DD") : "";
                });

                var requestParamsMulti = {
                    token: jwtService.getPrincipalToken(),
                    pkg: $scope.package,
                    travelDate: moment($scope.criteria.selectedPackage.strDate, shoppingCartService.getDateFormat()).format("YYYY-MM-DD")
                };

                var initServicesMulti = $scope.criteria.selectedPackage.reqmultidate == requestParamsMulti.travelDate
                    ? function (a, callback) { callback(); } : productsFactory.fillPackageRelatedServicesMulti;

                productsFactory.getTimeBetweenAttractions({ token: jwtService.getPrincipalToken() }, function (result) {
                    $scope.timesBtw = result.data;

                    initServicesMulti(requestParamsMulti, function () {
                        $scope.fillBussStopsUnits(function () {
                            //$.each($scope.criteria.selectedPackage.details.components, function (key, compVal) {
                            //    if (compVal.relatedProducts && (compVal.relatedProducts.attractionTimes || "").length) {
                            //        var times = compVal.relatedProducts.attractionTimes[0].units;
                            //        if (times) {
                            //            compVal.availableHours = [$scope.noTime];
                            //            compVal.selectedTime = $scope.noTime;
                            //            $.each(times, function (timeKey, timeVal) {
                            //                compVal.availableHours.push({ key: moment(timeVal.startTime).format("hh:mm A"), value: timeVal });
                            //            });
                            //        }
                            //    }
                            //});
                            $scope.setTimeBetweenAttractionsOrder();
                            var requiredProductsPromises = [];
                            if (!$scope.package.hasRequiredProductsInit) {
                                _.each($scope.package.components, function (comp, index) {
                                    comp.requiredProducts = [];
                                    comp.relatedProducts && _.each(comp.relatedProducts.requiredProducts, function (reqProduct) {
                                        requiredProductsPromises.push($scope.fillProductDetails(comp, reqProduct));
                                    });

                                    $scope.setUnitBoardingTime(comp);
                                });
                            }

                            Promise.all(requiredProductsPromises).then(function (result) {
                                $scope.package.hasRequiredProductsInit = true;
                                initDatePicker();
                                var showPage = $scope.criteria.selectedPackage.showFinal;
                                $scope.isLoading = false;

                                if (!showPage) {
                                    $scope.addPackageToCart();
                                }
                            });



                        });
                    });
                });
            };


            var initialized = false;

            $scope.$watch(function () {
                return taskFactory.packageTask;
            },
                function (val) {
                    if (!val || !val.name || initialized) return;
                    initialized = true;

                    $timeout($scope.init);
                }, true);
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("packageSummariesCtrl", [
        "activitiesService", "hotelsService", "transportationService",
        "$scope", "$state", "$rootScope", "packagesService",
        "shoppingCartService", "jwtService", "taskFactory", "$timeout",
        function (activitiesService, hotelsService, transportationService, $scope, $state, $rootScope, packagesService, shoppingCartService, jwtService, taskFactory, $timeout) {
            var webUrl = $("body").data("weburl") ? $("body").data("weburl") : "";
            $scope.packages = [];

            $scope.currentDate = jwtService.getServerMomentDate(); //moment();//.add("days", 1);

            $scope.selectedAdults = "1";
            $scope.selectedChild = "0";

            function strRange(min, max) {
                function toString(val) {
                    return val.toString();
                }

                return _.map(_.range(min, max), toString);
            }

            $scope.availableAdults = strRange(0, 5 + 1);
            $scope.availableChild = strRange(0, 5 + 1);

            $scope.getSelectedProduct = undefined;
            $scope.wasSearch = false;


            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            function initDatePicker(callback) {
                $timeout(function () {
                    if ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) {
                        moment.locale($scope.selectedLanguage.languageCode);
                    }

                    var datepickersettings = {
                        singleDatePicker: true,
                        minDate: $scope.currentDate,
                        showDropdowns: true,
                        locale: {
                            format: shoppingCartService.getDateFormat()
                        },
                        parentEl: "#daterangecontainer"
                    };

                    //if ($scope.selectedLanguage && $scope.selectedLanguage.calendar) {
                    //    datepickersettings.locale.daysOfWeek = $scope.selectedLanguage.calendar.daysOfWeek;
                    //    datepickersettings.locale.monthNames = $scope.selectedLanguage.calendar.monthNames;
                    //    datepickersettings.locale.firstday = $scope.selectedLanguage.calendar.firstDay;
                    //}

                    $scope.daterangepicker = $("#daterange").daterangepicker(datepickersettings);

                    $scope.daterangepicker.on("apply.daterangepicker", function (ev, picker) {
                        //var date = $(this).val();
                        //$scope.currentDate = moment(date, shoppingCartService.getDateFormat());
                        //var strDate = $scope.currentDate.format("YYYY-MM-DD");
                        //$scope.getPackages(strDate);
                        $timeout(function () {
                            $scope.wasSearch = false;
                        });

                    });
                    callback && callback();
                });
            }

            $scope.scrollToResultsIfMobile = function () {
               // if (jQuery(window).width() < 760) {
                    setTimeout(function () {
                        var page = $("html, body");

                        page.animate({ scrollTop: $scope.isLoading ? $("#loadingContainer").offset().top : $("#resultsContainer").offset().top }, 1000, function () {
                            page.off("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove");
                        });

                        page.on("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove", function () {
                            setTimeout(function () {
                                page.stop();
                            });
                        });
                    });
               // }
            };

            $scope.search = function () {
                
                if ($scope.isLoading) return;
                var date = $("#daterange").val();
                $scope.currentDate = moment(date, shoppingCartService.getDateFormat());
                var strDate = $scope.currentDate.format("YYYY-MM-DD");
                $scope.getPackages(strDate);
            };

           

            $scope.adultsChanged = function (adults) {
                $scope.selectedAdults = adults;

                $scope.persistCriteria();
            };

            $scope.childChanged = function (child) {
                $scope.selectedChild = child;

                $scope.persistCriteria();
            };

            $scope.getPackages = function (travelDate) {
                $scope.getSelectedProduct(function (result) {
                  
                    if (result.success && result.data) {
                        var product = result.data;
                        
                        $scope.isLoading = true;
                        $scope.wasSearch = true;
                        $scope.scrollToResultsIfMobile();
                        
                        var params = {
                            urlPrefix: webUrl,
                            token: jwtService.getPrincipalToken(),
                            productCode: product.code || product.productType,
                            travelDate: travelDate
                        }
                        
                        var getPackageSummariesFunc = packagesService.getPackageSummaries;
                        if (!product.code) {
                            getPackageSummariesFunc = packagesService.getPackageSummariesByProductType;
                            params = {
                                urlPrefix: webUrl,
                                token: jwtService.getPrincipalToken(),
                                productCategory: product.productCategory,
                                productType: product.productType,
                                travelDate: travelDate
                            }
                        }
                        getPackageSummariesFunc(params,
                            function (result) {
                                if (!result || !result.success || !result.data || !result.data.packages) {
                                    $scope.packages = [];
                                    $scope.persistCriteria();
                                    $scope.isLoading = false;
                                    $scope.scrollToResultsIfMobile();
                                    return;
                                };

                                var strDate = moment(travelDate).format(shoppingCartService.getDateFormat());
                                $.each(result.data.packages, function (key, value) {
                                    value.strDate = strDate;
                                });

                                $scope.packages = result.data.packages;
                                $scope.persistCriteria();
                                $scope.isLoading = false;
                                $scope.scrollToResultsIfMobile();
                            });
                    }
                });
            };


            $scope.persistCriteria = function () {
                if ($scope.$parent) {
                    var productSelectTicketCtrl = $scope.$parent;
                    if (productSelectTicketCtrl.$parent) {
                        var productDetailsCtrl = productSelectTicketCtrl.$parent;

                        var criteria = {
                            date: $("#daterange").val(),
                            adults: parseInt($scope.selectedAdults),
                            children: parseInt($scope.selectedChild),
                            packages: $scope.packages
                        };
                        productDetailsCtrl.savePackagesSearchCriteria(criteria);
                    }
                }
            };

            $scope.getCriteria = function () {
                if ($scope.$parent) {
                    var productSelectTicketCtrl = $scope.$parent;
                    if (productSelectTicketCtrl.$parent) {
                        var productDetailsCtrl = productSelectTicketCtrl.$parent;

                        return productDetailsCtrl.getPackagesSearchCriteria();
                    }
                }

                return undefined;
            };

            $scope.gotoDetails = function (selectedItem) {
                var productSelectTicketCtrl = $scope.$parent;
                if (!productSelectTicketCtrl.$parent) {
                    return;
                }
                var productDetailsCtrl = productSelectTicketCtrl.$parent;
                productDetailsCtrl.setSelectedPackage(selectedItem);
                var packageDetailsParam = {
                    packageCode: selectedItem.code,
                    date: moment($("#daterange").val(), shoppingCartService.getDateFormat()).format("YYYY-MM-DD")
                };
                productDetailsCtrl.next($state.$current.name, packageDetailsParam);
            };

            $scope.init = function () {
                var productCategory = jwtService.getProductCategory();
                if (!(productCategory || "").length) {
                    productCategory = jQuery("[ng-controller=productDetailsWrapperCtrl]").data("category");
                }
                switch (productCategory.toLowerCase()) {
                    case "activities":
                        $scope.maxAdults = $("body").attr("data-max-attractions-available-adults") ? parseInt($("body").attr("data-max-attractions-available-adults")) : 5;
                        $scope.maxChildren = $("body").attr("data-max-attractions-available-children") ? parseInt($("body").attr("data-max-attractions-available-children")) : 5;

                        $scope.getSelectedProduct = activitiesService.getSelectedActivity; break;
                    case "hotels":
                        $scope.maxAdults = $("body").attr("data-max-hotels-available-adults") ? parseInt($("body").attr("data-max-hotels-available-adults")) : 5;
                        $scope.maxChildren = $("body").attr("data-max-hotels-available-children") ? parseInt($("body").attr("data-max-hotels-available-children")) : 5;

                        $scope.getSelectedProduct = hotelsService.getSelectedHotel; break;
                    case "transportation":
                        $scope.maxAdults = $("body").attr("data-max-transportations-available-adults") ? parseInt($("body").attr("data-max-transportations-available-adults")) : 5;
                        $scope.maxChildren = $("body").attr("data-max-transportations-available-children") ? parseInt($("body").attr("data-max-transportations-available-children")) : 5;

                        $scope.getSelectedProduct = transportationService.getSelectedTransportation; break;
                    default: $scope.maxAdults = $("body").attr("data-max-attractions-available-adults") ? parseInt($("body").attr("data-max-attractions-available-adults")) : 5;
                        $scope.maxChildren = $("body").attr("data-max-attractions-available-children") ? parseInt($("body").attr("data-max-attractions-available-children")) : 5;
                }
                if (!$scope.getSelectedProduct) {
                    window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
                    return;
                }
                $scope.availableAdults = strRange(0, $scope.maxAdults + 1);
                $scope.availableChild = strRange(0, $scope.maxChildren + 1);

                $scope.getSelectedProduct(function (result) {
                    var product = undefined;
                    if (result.success && result.data) {
                        product = result.data;
                    }
                    var isDefaultDate = jQuery("[ng-controller=productDetailsWrapperCtrl]").attr("data-is-default-date");
                    var travelDateRequest = jQuery("[ng-controller=productDetailsWrapperCtrl]").attr("data-travel-date");

                    var travelDate = isDefaultDate !== "1" || (!product || !product.startDate) ?
                        travelDateRequest : $scope.$parent.getProductDate(product.startDate);

                    $scope.isLoading = false;
                
                    var criteria = $scope.getCriteria();
                    var dosearch = criteria && criteria.date;

                    if (criteria) {
                        if (!criteria.date && (travelDate)) {
                            criteria.date = moment(travelDate, "YYYY-MM-DD").format(shoppingCartService.getDateFormat());
                        }
                        if ($("#daterange").length && criteria.date && (moment(criteria.date, shoppingCartService.getDateFormat()) >= jwtService.getServerMomentDate())) {
                            $("#daterange").val(criteria.date);
                            $("#daterange").data().daterangepicker.startDate = moment(criteria.date, shoppingCartService.getDateFormat());
                            $("#daterange").data().daterangepicker.endDate = moment(criteria.date, shoppingCartService.getDateFormat());
                        }
                        if (criteria.packages) {
                            $scope.packages = criteria.packages;
                        }

                        if (criteria.adults) {
                            $scope.selectedAdults = criteria.adults.toString();
                        }

                        if (criteria.children) {
                            $scope.selectedChild = criteria.children.toString();
                        }
                    }

                    if (!$scope.packages ||
                        $scope.packages.length === 0 ||
                        !$scope.packages[0].strDate ||
                        !moment($scope.packages[0].strDate).isSame(moment(criteria.date))) {
                        if (dosearch) {
                            $scope.isLoading = false;
                            $scope.search();
                            // $scope.daterangepicker.trigger("apply.daterangepicker");
                        }

                    } else {
                        $scope.wasSearch = true;
                    }
                });
            };

            var initialized = false;
            $scope.isLoading = true;

            $scope.$watch(function () {
                return taskFactory.task;
            },
                function (val) {
                    if (!val || !val.name || initialized) return;
                    initialized = true;

                    initDatePicker($scope.init);
                }, true);
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    // Setup the filter
    angular.module("app").filter("filterTransportations", function () {

        // Create the return function and set the required parameter as well as an optional paramater
        return function (input, filterObj) {
            if (filterObj && !filterObj.hasTimes) {
                return [];
            }

            if (filterObj && (filterObj.isDeparture || filterObj.isReturn) && (filterObj.selectedDepartureTime || filterObj.selectedReturnTime || filterObj.selectedProductTime)) {
                var out = [];

                var filterProductTimeVal = filterObj.selectedProductTime ? moment(filterObj.selectedProductTime, "hh:mm A") : "";
                var selectedDepartureTimeVal = filterObj.selectedDepartureTime ? moment(filterObj.selectedDepartureTime, "hh:mm A") : "";
                var selectedReturnTimeVal = filterObj.selectedReturnTime ? moment(filterObj.selectedReturnTime, "hh:mm A") : "";
                var isSameDate = filterObj.isSameDate;

                angular.forEach(input, function (value, key) {

                    var currTimeVal = moment(value.timeStr, "hh:mm A");
                    if (filterObj.isDeparture) {
                        if (isSameDate) {
                            if ((filterObj.selectedDepartureTime && value.timeStr === filterObj.selectedDepartureTime)
                                || (!filterObj.selectedDepartureTime && ((filterProductTimeVal && currTimeVal <= filterProductTimeVal) || !filterProductTimeVal))) {
                                if ((selectedReturnTimeVal && currTimeVal < selectedReturnTimeVal) || !selectedReturnTimeVal)
                                    out.push(value);
                            }
                        }
                        else if ((filterObj.selectedDepartureTime && value.timeStr === filterObj.selectedDepartureTime) || !filterObj.selectedDepartureTime) {
                            out.push(value);
                        }
                    }
                    else {
                        if (isSameDate) {
                            if ((filterObj.selectedReturnTime && value.timeStr === filterObj.selectedReturnTime)
                                || (!filterObj.selectedReturnTime && ((filterProductTimeVal && currTimeVal >= filterProductTimeVal) || !filterProductTimeVal))) {
                                if ((selectedDepartureTimeVal && currTimeVal > selectedDepartureTimeVal) || !selectedDepartureTimeVal)
                                    out.push(value);
                            }
                        }
                        else if ((filterObj.selectedReturnTime && value.timeStr === filterObj.selectedReturnTime) || !filterObj.selectedReturnTime) {
                            out.push(value);
                        }
                    }

                }, out);

                return out;

            } else {
                return input;
            }

        };
    });
    // Setup the filter
    angular.module("app").filter("filterTransportationsPickTimes", function () {

        // Create the return function and set the required parameter as well as an optional paramater
        return function (input, filterObj) {

            if (filterObj && filterObj.isSameDate && (filterObj.isDeparture || filterObj.isReturn)) {
                var out = [];

                var filterOtherTimeVal = (filterObj.selectedTime || "").length ? moment(filterObj.selectedTime, "hh:mm A") : "";

                var filterReturnTimeVal = filterObj.selectedReturnProductTime ? moment(filterObj.selectedReturnProductTime, "hh:mm A") : "";
                var filterDepartureTimeVal = filterObj.selectedDepartureProductTime ? moment(filterObj.selectedDepartureProductTime, "hh:mm A") : "";
                if (!filterOtherTimeVal && !filterReturnTimeVal && !filterDepartureTimeVal) {
                    return input;
                }

                angular.forEach(input, function (value, key) {
                    var currTimeVal = moment(value, "hh:mm A");

                    if (filterObj.isDeparture) {

                        if (filterOtherTimeVal) {
                            if (currTimeVal < filterOtherTimeVal && (!filterReturnTimeVal || currTimeVal <= filterReturnTimeVal)) {
                                out.push(value);
                            }
                        }
                        else if (!filterReturnTimeVal || currTimeVal <= filterReturnTimeVal) {
                            out.push(value);
                        }
                    }
                    else {
                        if (filterOtherTimeVal) {
                            if (currTimeVal > filterOtherTimeVal && (!filterDepartureTimeVal || currTimeVal >= filterDepartureTimeVal)) {
                                out.push(value);
                            }
                        }
                        else if (!filterDepartureTimeVal || currTimeVal >= filterDepartureTimeVal) {
                            out.push(value);
                        }
                    }

                }, out);

                return out;

            } else {
                return input;
            }

        };
    });
    angular.module("app").controller("transportationBookAdventureCtrl", [
        "utilsFactory", "trackingService", "$scope", "$state", "$stateParams", "$http", "$uibModal", "activitiesService", "shoppingCartService", "transportationService", "jwtService", "taskFactory", "$timeout", "productsFactory",
        function (utilsFactory, trackingService, $scope, $state, $stateParams, $http, $uibModal, activitiesService, shoppingCartService, transportationService, jwtService, taskFactory, $timeout, productsFactory) {
            $scope.submitted = false;

            var webUrl = $("body").data("weburl") ? $("body").data("weburl") : "";
            $scope.maxAdults = $("body").attr("data-max-transportations-available-adults") ? parseInt($("body").attr("data-max-transportations-available-adults")) : 5;
            $scope.maxChildren = $("body").attr("data-max-transportations-available-children") ? parseInt($("body").attr("data-max-transportations-available-children")) : 5;
            $scope.displayCurrDate = jwtService.getServerMomentDate(true).format("hh:mm A DD-MM-YYYY");
            $scope.utils = utilsFactory;
            $scope.getAgeRangeInfo = function (secondaryLabel) {
                if (!$scope.anonymUser) return undefined;
                var selectedLanguage = $scope.anonymUser.selectedLanguage;
                return $scope.utils.getAnonymUserLabel((selectedLanguage && selectedLanguage.userlabels) || $scope.anonymUser, "ageRangesInfo", secondaryLabel);
            };
            var activitySelectTicketCtrl = $scope.$parent;
            var activityDetailsCtrl = activitySelectTicketCtrl.$parent;
            var generalCtrl = activityDetailsCtrl.$parent;

            $.material.init();
            $scope.initParamsFromUrl = false;
            $scope.wasSearch = false;
            $scope.submittedSearch = false;//for validation only
            $scope.isLoading = true;
            var transportationCtrlDiv = jQuery("div[ng-controller='transportationDetailsCtrl']");
            $scope.requestArguments = {
                productType: transportationCtrlDiv.attr("data-transportation-product-type"),
                productCode: transportationCtrlDiv.attr("data-transportation-product-code"),
                productCategory: transportationCtrlDiv.attr("data-transportation-product-category"),
                travelDate: transportationCtrlDiv.attr("data-transportation-travel-date"),
                unitCode: transportationCtrlDiv.attr("data-transportation-unit-code"),
                isDefaultDate: transportationCtrlDiv.attr("data-transportation-is-default-date") === "1",
                productcodeswithexpandeddescriptionbydefault: transportationCtrlDiv.attr("data-productcodeswithexpandeddescriptionbydefault"),
                defaultselectedadultsbyproductcode: transportationCtrlDiv.data("defaultselectedadultsbyproductcode"),
                updateCartItemCode: transportationCtrlDiv.attr("data-transportation-updateCartItem"),
                fromwebtray: ["1", "true"].indexOf(($("div[ng-controller='transportation']").attr("data-transportation-fromwebtray") || "").toLowerCase()) >= 0
            };
            $scope.requestArguments.expanddescriptionbydefault = ($scope.requestArguments.productcodeswithexpandeddescriptionbydefault || []).indexOf($scope.requestArguments.productCode) >= 0;
            $scope.requestArguments.travelDate = $scope.requestArguments.isDefaultDate ? jwtService.getServerMomentDate() : moment($scope.requestArguments.travelDate);

            if ($scope.requestArguments.updateCartItemCode || jwtService.getServerMomentDate() > moment($scope.requestArguments.travelDate)) {
                $scope.requestArguments.travelDate = jwtService.getServerMomentDate();
                $scope.requestArguments.isDefaultDate = true;
            }


            $scope.serviceType = jQuery("div[ng-controller='transportationDetailsCtrl']").attr("data-transportation-product-type");

            $scope.showLeavingFromCities = false;

            $scope.allLocations = {};
            $scope.departureLocations = [];
            $scope.destinationLocations = [];

            $scope.getDefaultLeavingFromLocation = function () {
                return { value: { code: "" } };
            };
            $scope.selectedLeavingFromCity = undefined;
            $scope.selectedGoingToCity = undefined;

            $scope.showGoingToCities = false;

            $scope.getDefaultGoingToCityLocation = function () {
                return { code: "" };
            };

            $scope.transportationType = 2;

            function strRange(min, max) {
                function toString(val) {
                    return val.toString();
                }

                return _.map(_.range(min, max), toString);
            }


            $scope.selectedAdults = "2";
            if (($scope.requestArguments.defaultselectedadultsbyproductcode || '').length > 0) {
                var defaultSelectedAdultsStr = _.find($scope.requestArguments.defaultselectedadultsbyproductcode, function (item) {
                    var pcode = item.split(' ')[0];
                    return pcode == $scope.requestArguments.productCode;
                });
                if (defaultSelectedAdultsStr) {
                    var defaultSelectedAdults = parseInt(defaultSelectedAdultsStr.split(' ')[1]);
                    if (defaultSelectedAdults > 0) {
                        $scope.selectedAdults = String(defaultSelectedAdults);
                    }
                }
            }
            $scope.selectedChild = "0";

            $scope.availableAdults = strRange(0, $scope.maxAdults + 1);
            $scope.availableChild = strRange(0, $scope.maxChildren + 1);

            $scope.allProducts = [];
            $scope.allReturnProducts = [];
            $scope.availableDepartures = [];
            $scope.availableReturns = [];

            $scope.mapShowDeparureTimes = Object.create(null);
            $scope.availableDepartureTimes = [];
            $scope.mapShowReturnTimes = Object.create(null);
            $scope.availableReturnsTimes = [];

            $scope.selectedDeparturePickTime = "";
            $scope.selectedReturnPickTime = "";

            $scope.showNext = false;
            $scope.selectedPickUp = undefined;
            $scope.selectedDropOff = undefined;

            $scope.selectedDepartureProduct = undefined;
            $scope.selectedReturnProduct = undefined;
            $scope.selectedDeparturePickUp = undefined;
            $scope.selectedDepartureDropOff = undefined;
            $scope.selectedReturnPickUp = undefined;
            $scope.selectedReturnDropOff = undefined;;

            $scope.showModal = {
                "SubmitErrors": false
            };

            $scope.globalErrors = [];

            var timeoutID = undefined;
            function resizeSliderPanel() {
                window.clearTimeout(timeoutID);
                timeoutID = setTimeout(function () {
                    jQuery(window).resize();
                }, 100);
            }

            $scope.isTheSameDate = function () {
                return $scope.transportationType === 2 && $scope.return.data().daterangepicker.startDate
                    .isSame($scope.departure.data().daterangepicker.startDate);
            };

            $scope.scrollToResultsIfMobile = function () {
                // if (jQuery(window).width() < 760) {
                setTimeout(function () {
                    var page = $("html, body");

                    page.animate({ scrollTop: $scope.isLoading ? $("#loadingContainer").offset().top : $("#resultsContainer").offset().top }, 1000, function () {
                        page.off("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove");
                    });

                    page.on("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove", function () {
                        setTimeout(function () {
                            page.stop();
                        });
                    });
                });
                // }
            };

            //$scope.addAvailablePropToProducts = function (date, products) {
            //    if (!moment(date).isSame(jwtService.getServerMomentDate())) {
            //        return;
            //    }
            //    _.each(products, function (product) {
            //        if (product.units && product.units.length > 0) {
            //            var unit = product.units[0];
            //            if (unit) {
            //                product.timeStr = moment(unit.startTime).format("hh:mm A");
            //                product.timeVal = moment(product.timeStr, "hh:mm A");
            //            }
            //        }
            //        moment(unit.startTime).format("hh:mm A");
            //    });
            //};

            $scope.getObjLength = function (obj) {
                return !obj ? 0 : Object.keys(obj).length;
            };

            $scope.isDropoffRequiredForProduct = function (product) {
                var selectedUnit = product && (product.units || "").length ? product.units[0] : undefined;
                return (selectedUnit && (selectedUnit.dropoffLocationRequired));
            };

            $scope.isPickupRequiredForProduct = function (product) {
                var selectedUnit = product && (product.units || "").length ? product.units[0] : undefined;
                return (selectedUnit && (selectedUnit.pickupLocationRequired));
            };

            $scope.setSelectedReturnProduct = function (product, callback) {
                //if ($scope.isLoading) return false;
                if (!product) return;
                if (product.disabled || product.isInPast || product.isTimeRestricted || !$scope.isProductAvailable(product)) {
                    $scope.selectedReturnProduct = undefined;
                    $scope.disableDepartureProducts();
                    $scope.showNext = $scope.canContinue();
                    return false;
                }

                $scope.selectedReturnProduct = product;
                var selectedUnit = (product.units || "").length ? product.units[0] : undefined;
                $scope.disableDepartureProducts();

                if (selectedUnit) {
                    //$scope.selectedReturnPickUp = undefined;//product.busStops && product.busStops.pickups.length ? product.busStops.pickups[0] : undefined;
                    //$scope.selectedReturnDropOff = undefined;//product.busStops && product.busStops.dropoffs.length ? product.busStops.dropoffs[0] : undefined;
                    $scope.showNext = $scope.canContinue();
                    if (callback) {
                        callback();
                    } else {
                        $scope.selectDefaultProducts(1);
                    }
                }
                else {
                    $scope.showNext = $scope.canContinue();
                }
            };

            $scope.resetSelectedProducts = function () {
                $scope.selectedDepartureProduct = undefined;
                $scope.selectedReturnProduct = undefined;
                $scope.showNext = $scope.canContinue();
            };

            $scope.pickUpChanged = function (pickUp) {
                if ($scope.isLoading) return;
                $scope.selectedPickUp = pickUp;
                $scope.wasSearch = false;
                $scope.resetSelectedProducts();
            };

            $scope.dropOffChanged = function (dropOff) {
                if ($scope.isLoading) return;
                $scope.selectedDropOff = dropOff;
                $scope.wasSearch = false;
                $scope.resetSelectedProducts();
            };

            $scope.pickUpChangedReturn = function (pickUp) {
                if ($scope.isLoading) return;
                $scope.selectedPickUpReturn = pickUp;
                $scope.wasSearch = false;
                $scope.resetSelectedProducts();
            };

            $scope.dropOffChangedReturn = function (dropOff) {
                if ($scope.isLoading) return;
                $scope.selectedDropOffReturn = dropOff;
                $scope.wasSearch = false;
                $scope.resetSelectedProducts();
            };
            //-------------------
            $scope.returnPickUpChanged = function (pickUp) {
                if ($scope.isLoading) return false;
                $scope.selectedReturnPickUp = pickUp;
            };

            $scope.returnDropOffChanged = function (dropOff) {
                if ($scope.isLoading) return false;
                $scope.selectedReturnDropOff = dropOff;
            };

            $scope.departurePickUpChanged = function (pickUp) {
                if ($scope.isLoading) return false;
                //  $scope.showNext = true;
                $scope.selectedDeparturePickUp = pickUp;
            };

            $scope.departureDropOffChanged = function (dropOff) {
                if ($scope.isLoading) return false;
                // $scope.showNext = true;
                $scope.selectedDepartureDropOff = dropOff;
            };

            $scope.setSelectedDepartureProduct = function (product, callback) {
                //if ($scope.isLoading) return;
                if (!product) return;
                if (product.isInPast || product.isTimeRestricted || !$scope.isProductAvailable(product)) {
                    $scope.selectedDepartureProduct = undefined;
                    $scope.disableReturnProducts();
                    $scope.showNext = $scope.canContinue();
                    return;
                }
                $scope.disableReturnProducts();
                $scope.selectedDepartureProduct = product;
                var selectedUnit = (product.units || "").length ? product.units[0] : undefined;

                if (selectedUnit) {
                    //      $scope.selectedDeparturePickUp = undefined;//product.busStops && product.busStops.pickups.length ? product.busStops.pickups[0] : undefined;
                    //$scope.selectedDepartureDropOff = undefined;//product.busStops && product.busStops.dropoffs.length ? product.busStops.dropoffs[0] : undefined;
                    $scope.showNext = $scope.canContinue();
                    if (callback) {
                        callback();
                    } else {
                        $scope.selectDefaultProducts(2);
                    }
                    resizeSliderPanel();
                }
                else {
                    $scope.showNext = $scope.canContinue();
                }
            };

            $scope.selectDefaultProducts = function (setId) {
                // if ($scope.isLoading) return false;
                //setId=0-all 1- only departure 2- only return
                setId = setId || 0;

                //   $timeout(function () {
                var firstDeparture = undefined;
                if (($scope.allProducts || "").length) {
                    var availableDepartures = _.filter($scope.allProducts, function (fd) { return !fd.isInPast && $scope.isProductAvailable(fd) && !fd.disabled; });
                    firstDeparture = (availableDepartures || "").length === 1 && $scope.selectedDepartureProduct !== availableDepartures[0] ? availableDepartures[0] : undefined;
                    if ((availableDepartures || "").length > 1 && $scope.updateItem && !$scope.updateItem.wasDepartureProductSelected) {
                        $scope.updateItem.wasDepartureProductSelected = true;
                        var firstUpdateComp = $scope.updateItem.BookingToQuote.Components[0];
                        firstDeparture = _.find(availableDepartures, function (dep) {
                            var depUnit = (dep.units || "").length ? dep.units[0] : undefined;
                            return (depUnit && depUnit.unitCode) == firstUpdateComp.UnitCode;
                        });
                    }
                }


                firstDeparture = firstDeparture && (firstDeparture.isTimeRestricted) ? undefined : firstDeparture;//


                if (firstDeparture && setId <= 1) {
                    $scope.setSelectedDepartureProduct(firstDeparture, function () { });
                }
                //else
                //    if (setId <= 1) { //check if user not clicked the departure product
                //        $scope.selectedDepartureProduct = null;
                //    }

                $scope.disableReturnProducts();

                var firstReturn = undefined;
                if ($scope.transportationType === 2 && ($scope.allReturnProducts || "").length) {
                    var availableReturns = _.filter($scope.allReturnProducts, function (fr) { return !fr.isInPast && $scope.isProductAvailable(fr) && !fr.disabled;; });
                    firstReturn = (availableReturns || "").length === 1 && $scope.selectedReturnProduct !== availableReturns[0] ? availableReturns[0] : undefined;
                    if ((availableReturns || "").length > 1 && $scope.updateItem && !$scope.updateItem.wasReturnProductSelected) {
                        $scope.updateItem.wasReturnProductSelected = true;
                        var secondUpdateComp = $scope.updateItem.BookingToQuote.Components[1];
                        if (secondUpdateComp) {
                            firstReturn = _.find(availableReturns, function (ret) {
                                var retUnit = (ret.units || "").length ? ret.units[0] : undefined;
                                return (retUnit && retUnit.unitCode) == secondUpdateComp.UnitCode;
                            });
                        }
                    }
                }
                firstReturn = firstReturn && (firstReturn.isTimeRestricted || firstReturn.disabled) ? undefined : firstReturn;

                if (firstReturn && (setId == 0 || setId == 2)) {
                    $scope.setSelectedReturnProduct(firstReturn, function () { });
                }
                //else
                //    if (setId == 2 || setId == 0) { //check if user not clicked the return product{
                //        $scope.selectedReturnProduct = undefined;
                //    }

                $scope.disableDepartureProducts();
                $scope.showNext = $scope.canContinue();

                // });
            };


            $scope.returnPickTimeChanged = function (time) {
                if ($scope.isLoading) return false;
                //$scope.selectedReturnPickTime = time;
                $scope.selectedReturnProduct = undefined;
                $scope.selectedDepartureProduct = undefined;
                $scope.showNext = false;

                $scope.selectDefaultProducts();
                resizeSliderPanel();
            };

            $scope.departurePickTimeChanged = function (time) {
                if ($scope.isLoading) return false;
                //  $scope.selectedDeparturePickTime = time;
                $scope.selectedDepartureProduct = undefined;
                $scope.selectedReturnProduct = undefined;
                $scope.showNext = false;

                $scope.selectDefaultProducts();
                resizeSliderPanel();
            };

            $scope.getProductBusStops = function (product, callback, skipLoading) {
                if (!skipLoading && $scope.isLoading) return;

                var requestParams = {
                    urlPrefix: $("body").data("weburl") ? $("body").data("weburl") : "",
                    token: jwtService.getPrincipalToken(),
                    productCode: product.code,
                    unitCode: product.units[0].unitCode
                };

                $scope.isLoading = true;

                transportationService.getBusStops(requestParams, function (dateResult) {
                    product.busStops = dateResult.data;
                    if (callback) {
                        callback();
                    }
                    $scope.isLoading = false;
                });
            };

            $scope.canContinue = function () {
                var selectedDepartureUnit =
                    ($scope.allProducts || "").length && $scope.selectedDepartureProduct && ($scope.selectedDepartureProduct.units || "").length ? $scope.selectedDepartureProduct.units[0] : undefined;

                var selectedReturnUnit =
                    ($scope.allReturnProducts || "").length && $scope.selectedReturnProduct && ($scope.selectedReturnProduct.units || "").length ? $scope.selectedReturnProduct.units[0] : undefined;

                //    var validDeparture = selectedDepartureUnit
                //          && ((selectedDepartureUnit.pickupLocationRequired && $scope.selectedDeparturePickUp)
                //        || !selectedDepartureUnit.pickupLocationRequired)
                //        && ((selectedDepartureUnit.dropoffLocationRequired && $scope.selectedDepartureDropOff)
                //        || !selectedDepartureUnit.dropoffLocationRequired);

                //    var validReturn = selectedReturnUnit
                //  && ((selectedReturnUnit.pickupLocationRequired && $scope.selectedReturnPickUp)
                //|| !selectedReturnUnit.pickupLocationRequired)
                //&& ((selectedReturnUnit.dropoffLocationRequired && $scope.selectedReturnDropOff)
                //|| !selectedReturnUnit.dropoffLocationRequired);


                if (!selectedDepartureUnit || (!selectedReturnUnit && $scope.transportationType === 2)) return false;
                return true;
            }

            $scope.$watch('showNext', function (newVal, oldVal) {
                if (!newVal) {
                    $scope.submitted = false;
                }
            }, true);

            //
            $scope.fillProductDetailsRecursive = function (parentProduct, products, index, callback) {
                if (index === products.length || !products[index]) {
                    callback();
                    return;
                }
                var params = {
                    token: jwtService.getPrincipalToken(),
                    productCode: products[index].productCode,
                    productCategory: products[index].productCategory,
                    travelDate: $("#departure").data().daterangepicker.startDate.format("YYYY-MM-DD")
                };
                productsFactory.getProductWithHiddenUnitsWithCallback(params, function (result) {
                    if (result && result.success && (result.data || "").length) {
                        products[index].product = result.data[0];
                        products[index].product.selectedUnit = _.find(products[index].product.units, function (u) {
                            return products[index].unitCode === u.unitCode;
                        });
                        if (!parentProduct.requiredProducts) {
                            parentProduct.requiredProducts = [];
                        }
                        parentProduct.requiredProducts.push(products[index]);
                    }
                    $scope.fillProductDetailsRecursive(parentProduct, products, index + 1, callback);
                });

            };

            $scope.showRequiredProductsModal = function (callback) {
                var popupProducts = _.filter($scope.selectedDepartureProduct.requiredProducts, function (reqProd) {

                    if (!reqProd.product) return false;

                    if (reqProd.product.productType === "FEE") {
                        reqProd.product.isFee = true;
                        return false;
                    }
                    return true;
                });
                if (popupProducts.length == 0) {
                    callback && callback();
                    return;
                }
                var requiredModalInstance = $uibModal.open({
                    animation: true,
                    templateUrl: "requiredProductsModal.html",
                    controller: "requiredProductsModalCtrl",
                    size: "book-required-products",
                    resolve: {
                        "products": { followingProductSingle: "product", followingProductMultiple: "products", yourProductTitle: "transportation", data: popupProducts }
                    },
                    backdrop: "true"
                });
                requiredModalInstance.result.then(function (result) {
                    callback && callback();
                }, function () {
                    //console.log("dismiss");
                });
            };
            //


            $scope.bookTransportation = function () {
                if ($scope.isLoading) return;
                $scope.submitted = true;

                $scope.globalErrors = [];
                var selectedDepartureUnit =
                    $scope.selectedDepartureProduct && ($scope.selectedDepartureProduct.units || "").length ? $scope.selectedDepartureProduct.units[0] : undefined;

                var selectedReturnUnit =
                    $scope.selectedReturnProduct && ($scope.selectedReturnProduct.units || "").length ? $scope.selectedReturnProduct.units[0] : undefined;

                $scope.selectedDeparturePickUp = selectedDepartureUnit && $scope.selectedPickUp ? _.find(selectedDepartureUnit.pickups, function (pu) {
                    return pu.code == $scope.selectedPickUp.code;
                }) : undefined;

                $scope.selectedReturnPickUp = selectedReturnUnit && $scope.selectedPickUpReturn ? _.find(selectedReturnUnit.pickups, function (pu) {
                    return pu.code == $scope.selectedPickUpReturn.code;
                }) : undefined;

                $scope.selectedDepartureDropOff = selectedDepartureUnit && $scope.selectedDropOff ? _.find(selectedDepartureUnit.dropoffs, function (pu) {
                    return pu.code == $scope.selectedDropOff.code;
                }) : undefined;

                $scope.selectedReturnDropOff = selectedReturnUnit && $scope.selectedDropOffReturn ? _.find(selectedReturnUnit.dropoffs, function (pu) {
                    return pu.code == $scope.selectedDropOffReturn.code;
                }) : undefined;

                var requiredDeparturePickup = selectedDepartureUnit
                    && ((selectedDepartureUnit.pickupLocationRequired && $scope.selectedDeparturePickUp)
                        || !selectedDepartureUnit.pickupLocationRequired);

                var requiredDepartureDropOff = selectedDepartureUnit
                    && ((selectedDepartureUnit.dropoffLocationRequired && $scope.selectedDepartureDropOff)
                        || !selectedDepartureUnit.dropoffLocationRequired);

                var validDeparture = requiredDeparturePickup && requiredDepartureDropOff;

                var requiredReturnPickup = selectedReturnUnit
                    && ((selectedReturnUnit.pickupLocationRequired && $scope.selectedReturnPickUp)
                        || !selectedReturnUnit.pickupLocationRequired);

                var requiredReturnDropOff = selectedReturnUnit && ((selectedReturnUnit.dropoffLocationRequired && $scope.selectedReturnDropOff)
                    || !selectedReturnUnit.dropoffLocationRequired);

                var validReturn = ($scope.transportationType === 2 && requiredReturnPickup && requiredReturnDropOff) || $scope.transportationType != 2;

                if (!requiredDeparturePickup) {
                    $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredDeparturePickup"));
                }
                if (!requiredDepartureDropOff) {
                    $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredDepartureDropOff"));
                }

                if (!validReturn && !requiredReturnPickup) {
                    $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredReturnPickup"));
                }
                if (!validReturn && !requiredReturnDropOff) {
                    $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredReturnDropOff"));
                }
                if ($scope.globalErrors.length) $scope.showModal["SubmitErrors"] = true;
                if (!validDeparture || !validReturn) return;

                $scope.isLoading = true;

                //
                var productQueries = [];
                productQueries.push({
                    ProductCode: $scope.selectedDepartureProduct.code,
                    TravelDate: $("#departure").val(),
                    UnitCode: selectedDepartureUnit ?
                        selectedDepartureUnit.unitCode : null
                });

                if ($scope.transportationType === 2 && $scope.selectedReturnProduct && selectedReturnUnit) {
                    productQueries.push({
                        ProductCode: $scope.selectedReturnProduct.code,
                        TravelDate: $("#return").val(),
                        UnitCode: selectedReturnUnit ?
                            selectedReturnUnit.unitCode : null
                    });
                }

                var dataToPost = { ProductQueries: productQueries };
                var relatedServicesRequestParams = {
                    token: jwtService.getPrincipalToken(),
                    data: dataToPost
                };

                var getRelatedServicesMulti = new Promise(function (resolve, reject) {
                    productsFactory.getRelatedServicesMulti(relatedServicesRequestParams, function (relatedProducts) {

                        console.log("required products: ", relatedProducts && (relatedProducts.data || ""));

                        if (relatedProducts && (relatedProducts.data || "").length) {
                            var departureRequiredProduct = relatedProducts.data.find(function (item) {
                                return item.relatedProductCode == $scope.selectedDepartureProduct.code;
                            });
                            $scope.selectedDepartureProduct.requiredProducts = departureRequiredProduct && departureRequiredProduct.requiredProducts || null;

                            if ($scope.selectedReturnProduct) {
                                var returnRequiredProduct = relatedProducts.data.find(function (item) {
                                    return item.relatedProductCode == $scope.selectedReturnProduct.code;
                                });
                                $scope.selectedReturnProduct.requiredProducts = returnRequiredProduct && returnRequiredProduct.requiredProducts || null;
                            }

                        } else {
                            $scope.selectedDepartureProduct.requiredProducts = null;
                            $scope.selectedReturnProduct && ($scope.selectedReturnProduct.requiredProducts = null);
                        }



                        resolve(1);

                        //if (relatedProducts && (relatedProducts.data || "").length && (relatedProducts.data[0].requiredProducts || "").length) {

                        //    $scope.fillProductDetailsRecursive($scope.selectedDepartureProduct, relatedProducts.data[0].requiredProducts, 0, function () {
                        //        $scope.isLoading = false;

                        //        if (($scope.selectedDepartureProduct.requiredProducts || "").length) {
                        //            $scope.fillProductDetailsRecursive($scope.selectedDepartureProduct, relatedProducts.data[0].requiredProducts, 0, function () {
                        //                $scope.isLoading = false;

                        //                if (($scope.selectedDepartureProduct.requiredProducts || "").length) {
                        //                    $scope.showRequiredProductsModal(function () { resolve(1); });
                        //                } else {
                        //                    resolve(1);
                        //                }
                        //            });
                        //        } else {
                        //            resolve(1);
                        //        }
                        //    });

                        //} else {
                        //resolve(1);
                        //}
                    });
                });
                //

                // remove the item to be updated from the cart
                var removeExistingCartItemPromise = undefined;

                if ($scope.updateItem) {
                    removeExistingCartItemPromise = new Promise(function (resolve, reject) {
                        var requestParams = {
                            apiUrl: $("body").data("weburl") ? $("body").data("weburl") : "",
                            token: jwtService.getPrincipalToken(),
                            index: $scope.updateIndex,
                            productCode: $scope.updateItem.ProductCode
                        };

                        shoppingCartService.setStorageCart($scope.cart, function () {
                            shoppingCartService.updateCartComponents(requestParams, function (shoppingCart) {
                                if (shoppingCart && (shoppingCart.Items || '').length) {
                                    $scope.cart = shoppingCart;
                                } else {
                                    // window.location = "/";
                                }
                                resolve(1);
                            });
                        });
                    }); // Promise
                } else {
                    removeExistingCartItemPromise = Promise.resolve(1);
                }
                //
                getRelatedServicesMulti.then(function () {


                    removeExistingCartItemPromise.then(function () {
                        $scope.lobTitle = $scope.transportation && $scope.transportation.productDescriptions
                            && (
                                $scope.transportation.productDescriptions.genericTitle || ($scope.transportation.productDescriptions.titles && $scope.transportation.productDescriptions.titles.length > 0 ? $scope.transportation.productDescriptions.titles[0] : $scope.transportation.name));


                        var components = [];
                        var departureComponent = {
                            "Id": $scope.selectedDepartureProduct.id,
                            "ProductCategory": $scope.selectedDepartureProduct.productCategory,
                            "ProductType": $scope.selectedDepartureProduct.productType,
                            "ProductCode": $scope.selectedDepartureProduct.code,
                            "StartDate": $scope.selectedDepartureProduct.startDate,
                            "EndDate": $scope.selectedDepartureProduct.endDate,
                            "Name": $scope.selectedDepartureProduct.name,
                            "Description": $scope.selectedDepartureProduct.description,
                            "ProductDescriptions": $scope.selectedDepartureProduct.productDescriptions,
                            "Price": $scope.selectedDepartureProduct.price,
                            "ChildPrice": $scope.selectedDepartureProduct.childPrice,
                            "NumberOfAdults": $scope.selectedAdults,
                            "NumberOfChildren": $scope.selectedChild,
                            "NumberOfInfants": 0,
                            "Status": "New",
                            "UnitCode": selectedDepartureUnit ? selectedDepartureUnit.unitCode : "",
                            "UnitDescription": selectedDepartureUnit ? selectedDepartureUnit.description : "",
                            "PickupLocation": $scope.selectedDeparturePickUp,
                            "DropoffLocation": $scope.selectedDepartureDropOff,
                            "StartingLocation": $scope.selectedDepartureProduct.startingLocation,
                            "Destination": $scope.selectedDepartureProduct.destination,
                            "Remarks": [],
                            "AddedFromWebTray": $scope.requestArguments.fromwebtray,
                            "_trackingLob": $scope.lobTitle
                        };
                        components.push(departureComponent);

                        if ($scope.selectedReturnProduct && $scope.transportationType === 2) {

                            var returnComponent = {
                                "Id": $scope.selectedReturnProduct.id,
                                "ProductCategory": $scope.selectedReturnProduct.productCategory,
                                "ProductType": $scope.selectedReturnProduct.productType,
                                "ProductCode": $scope.selectedReturnProduct.code,
                                "StartDate": $scope.selectedReturnProduct.startDate,
                                "EndDate": $scope.selectedReturnProduct.endDate,
                                "Name": $scope.selectedReturnProduct.name,
                                "Description": $scope.selectedReturnProduct.description,
                                "ProductDescriptions": $scope.selectedReturnProduct.productDescriptions,
                                "Price": $scope.selectedReturnProduct.price,
                                "ChildPrice": $scope.selectedReturnProduct.childPrice,
                                "NumberOfAdults": $scope.selectedAdults,
                                "NumberOfChildren": $scope.selectedChild,
                                "NumberOfInfants": 0,
                                "Status": "New",
                                "UnitCode": selectedReturnUnit ? selectedReturnUnit.unitCode : "",
                                "UnitDescription": selectedReturnUnit ? selectedReturnUnit.description : "",
                                "PickupLocation": $scope.selectedReturnPickUp,
                                "DropoffLocation": $scope.selectedReturnDropOff,
                                "StartingLocation": $scope.selectedReturnProduct.startingLocation,
                                "Destination": $scope.selectedReturnProduct.destination,
                                "Remarks": [],
                                "AddedFromWebTray": $scope.requestArguments.fromwebtray,
                                "_trackingLob": $scope.lobTitle
                            };
                            components.push(returnComponent);
                        };

                        if (($scope.selectedDepartureProduct.requiredProducts || "").length) {
                            _.each($scope.selectedDepartureProduct.requiredProducts, function (reqProd) {
                                components.push({
                                    "Id": null,//reqProd.unitCode,
                                    "ProductCategory": reqProd.productCategory,
                                    "ProductType": reqProd.productType,
                                    "ProductCode": reqProd.productCode,
                                    "StartDate": reqProd.startDate,
                                    "EndDate": reqProd.endDate,
                                    "Name": reqProd.productDescription,
                                    "Description": reqProd.productDescription,
                                    //"ProductDescriptions": reqProd.productDescription, // You’re submitting a string value for productDescriptions on the fuel surcharge components. The ProductDescriptions property is an object, and the request is therefore failing to deserialize on our end. 
                                    "Price": $scope.selectedDepartureProduct.price,
                                    "ChildPrice": $scope.selectedDepartureProduct.childPrice,
                                    "NumberOfAdults": $scope.selectedAdults,
                                    "NumberOfChildren": $scope.selectedChild,
                                    "NumberOfInfants": 0,
                                    "Status": "New",
                                    "UnitCode": reqProd.unitCode,
                                    "UnitDescription": undefined,
                                    "PickupLocation": undefined,
                                    "DropoffLocation": undefined,
                                    "StartingLocation": undefined,
                                    "Destination": undefined,
                                    "Remarks": [],
                                    "IsFee": reqProd.productType == "FEE",
                                    "ShowInCart": reqProd.showInCart,
                                    "ParentCode": $scope.selectedDepartureProduct.code
                                });
                            });
                        }


                        if (($scope.selectedReturnProduct && $scope.transportationType === 2)&&($scope.selectedReturnProduct.requiredProducts || "").length) {
                            _.each($scope.selectedReturnProduct.requiredProducts, function (reqProd) {
                                components.push({
                                    "Id": null,//reqProd.unitCode,
                                    "ProductCategory": reqProd.productCategory,
                                    "ProductType": reqProd.productType,
                                    "ProductCode": reqProd.productCode,
                                    "StartDate": reqProd.startDate,
                                    "EndDate": reqProd.endDate,
                                    "Name": reqProd.productDescription,
                                    "Description": reqProd.productDescription,
                                    // "ProductDescriptions": reqProd.productDescription, // You’re submitting a string value for productDescriptions on the fuel surcharge components. The ProductDescriptions property is an object, and the request is therefore failing to deserialize on our end. 
                                    "Price": $scope.selectedReturnProduct.price,
                                    "ChildPrice": $scope.selectedReturnProduct.childPrice,
                                    "NumberOfAdults": $scope.selectedAdults,
                                    "NumberOfChildren": $scope.selectedChild,
                                    "NumberOfInfants": 0,
                                    "Status": "New",
                                    "UnitCode": reqProd.unitCode,
                                    "UnitDescription": undefined,
                                    "PickupLocation": undefined,
                                    "DropoffLocation": undefined,
                                    "StartingLocation": undefined,
                                    "Destination": undefined,
                                    "Remarks": [],
                                    "IsFee": reqProd.productType == "FEE",
                                    "ShowInCart": reqProd.showInCart,
                                    "ParentCode": $scope.selectedReturnProduct.code
                                });
                            });
                        }

                        var bookingToQuote = {
                            "Components": components
                        };
                        var data = {
                            "BookingToQuote": bookingToQuote
                        };

                        var requestParams = {
                            apiUrl: $scope.$parent.$parent.getWebUrl(),
                            token: jwtService.getPrincipalToken(),
                            dataToPost: data,
                            startDate: $("#departure").val(),
                            endDate: $("#return").val(),
                            startTime: $scope.selectedDeparturePickUp ? $scope.selectedDeparturePickUp.time : undefined,
                            endTime: $scope.selectedReturnPickUp ? $scope.selectedReturnPickUp.time : undefined
                        };

                        shoppingCartService.addComponentsToCart(requestParams, function (result) {

                            //var modalInstance = $uibModal.open({
                            //    animation: true,
                            //    templateUrl: "cartInfoModal.html",
                            //    controller: "cartInfoModalCtrl",
                            //    size: "add-to-cart",
                            //    resolve: {
                            //        count: result,
                            //        isHotel: false
                            //    },
                            //    backdrop: "static"
                            //});

                            //$scope.isLoading = false;
                            if (result) {
                                var isEnhanceBookingPageEnabled = ($scope.selectedLanguage && $scope.selectedLanguage.enableEnhanceBookingPage) || ($scope.anonymUser && $scope.anonymUser.enableEnhanceBookingPage);
                                var redirectToUrl = shoppingCartService.utils.getAfterAddToCartPageUrl(generalCtrl.selectedGeographyCode, isEnhanceBookingPageEnabled);
                                window.location = utilsFactory.addPersistentQueryStringsParams(redirectToUrl);
                            } else {
                                $scope.isLoading = false;
                            }
                        });
                    }); // EndPromise resolve
                });
            };

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            $scope.finalSearch = function () {
                $scope.wasSearch = true;
                $scope.selectDefaultProducts();
                $scope.isLoading = false;
                $scope.scrollToResultsIfMobile();
            };

            $scope.searchProducts = function () {
                if ($scope.isLoading) return false;
                $scope.submittedSearch = true;
                $scope.globalErrors = [];
                if (!$scope.selectedLeavingFromCity) {
                    $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredLeavingFromLocation"));
                }

                if (!$scope.selectedGoingToCity) {
                    $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredGoingToLocation"));
                }
                if (!$scope.selectedPickUp) {
                    $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredPickupLocation"));
                }
                if (!$scope.selectedDropOff) {
                    $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredDropoffLocation"));
                }

                if ($scope.transportationType === 2) {
                    // need change
                    if (!$scope.selectedPickUpReturn) {
                        $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredReturnPickup"));
                    }
                    if (!$scope.selectedDropOffReturn) {
                        $scope.globalErrors.push(utilsFactory.getLabel("transportation.error.requiredReturnDropOff"));
                    }

                }
                if ($scope.globalErrors.length) {
                    $scope.showModal["SubmitErrors"] = true;
                    return false;
                }


                //if ($scope.transportationType === 2) {
                //    if ($scope.return.data().daterangepicker.startDate
                //        .isSame($scope.departure.data().daterangepicker.startDate)) {
                //        $scope.getTransportations();
                //        return true;
                //    } else {
                //        $scope.getTransportations(1, function () { $scope.getTransportations(2) });
                //        return true;
                //    }
                //}   

                $scope.wasSearch = true;
                $scope.allProducts = [];
                $scope.allReturnProducts = [];
                $scope.resetSelectedProducts();
                $scope.isLoading = true;
                $scope.scrollToResultsIfMobile();
                $scope.departureLoading = true;
                $scope.getTransportations(1, function () {
                    $scope.departureLoading = false;
                    if (!$scope.returnLoading) {
                        $scope.finalSearch();
                    }
                });

                if ($scope.transportationType == 2) {
                    $scope.returnLoading = true;
                    $scope.getTransportations(2, function () {
                        $scope.returnLoading = false;
                        if (!$scope.departureLoading) {
                            $scope.finalSearch();
                        }
                    });
                }

                return true;
            };



            $scope.getTotalGuests = function () {
                return parseInt($scope.selectedAdults || 0) + parseInt($scope.selectedChild || 0);
            };

            $scope.getProductAvailability = function (product) {
                var selectedUnit = product && (product.units || "").length ? product.units[0] : undefined;
                if (!selectedUnit) return 0;
                return selectedUnit.availability;
            };

            $scope.isProductAvailable = function (product) {

                return $scope.getProductAvailability(product) >= $scope.getTotalGuests();
            };

            $scope.adultsChanged = function (adults) {
                if (parseInt($scope.selectedAdults) === 0) {
                    $scope.availableChild = strRange(1, $scope.maxAdults + 1);
                    if (parseInt($scope.selectedChild) === 0)
                        $scope.selectedChild = $scope.availableChild[0];
                } else {
                    $scope.availableChild = strRange(0, $scope.maxAdults + 1);
                }

                $scope.setSelectedDepartureProduct($scope.selectedDepartureProduct);
                $scope.setSelectedReturnProduct($scope.selectedReturnProduct);

                $scope.selectDefaultProducts();
            };

            $scope.childChanged = function (child) {
                $scope.setSelectedDepartureProduct($scope.selectedDepartureProduct);
                $scope.setSelectedReturnProduct($scope.selectedReturnProduct);
                $scope.selectDefaultProducts();
            };

            $scope.fillBussStopsForLocation = function (loc, date, callback) {
                if (!loc) {
                    callback();
                    return;
                }
                var requestParams = {
                    urlPrefix: $("body").data("weburl") ? $("body").data("weburl") : "",
                    token: jwtService.getPrincipalToken(),
                    cityCode: loc.code,
                    travelDate: date,
                    serviceType: $scope.serviceType
                };
                $scope.isLoading = true;
                transportationService.getBusStopsByCity(requestParams, function (dateResult) {
                    $scope.isLoading = false;
                    loc.pickups = undefined;
                    loc.dropoffs = undefined;
                    if (dateResult.data) {
                        loc.pickups = (dateResult.data.pickups || "").length ? dateResult.data.pickups : [];
                        loc.dropoffs = (dateResult.data.dropoffs || "").length ? dateResult.data.dropoffs : [];
                    }
                    callback();
                });
            };

            $scope.setSelectedPickUp = function (data) {
                if (!$scope.selectedPickUp) {
                    if ((data || "").length !== 1)
                        return;
                    $scope.selectedPickUp = data[0];
                    return;
                };
                if (!data) {
                    $scope.selectedPickUp = undefined;
                    return;
                }
                $scope.selectedPickUp = _.find(data, function (it) {
                    return it.code == $scope.selectedPickUp.code;
                });
                if (!$scope.selectedPickUp && data.length === 1)
                    $scope.selectedPickUp = data[0];
            };

            $scope.setSelectedDropOff = function (data) {
                if (!$scope.selectedDropOff) {
                    if ((data || "").length !== 1)
                        return;
                    $scope.selectedDropOff = data[0];
                    return;
                };
                if (!data) {
                    $scope.selectedDropOff = undefined;
                    return;
                }
                $scope.selectedDropOff = _.find(data, function (it) {
                    return it.code == $scope.selectedDropOff.code;
                });

                if (!$scope.selectedDropOff && data.length === 1)
                    $scope.selectedDropOff = data[0];
            };

            $scope.setSelectedPickUpReturn = function (data) {
                if (!$scope.selectedPickUpReturn) {
                    if ((data || "").length !== 1)
                        return;
                    $scope.selectedPickUpReturn = data[0];
                    return;
                };
                if (!data) {
                    $scope.selectedPickUpReturn = undefined;
                    return;
                }
                $scope.selectedPickUpReturn = _.find(data, function (it) {
                    return it.code == $scope.selectedPickUpReturn.code;
                });
                if (!$scope.selectedPickUpReturn && data.length === 1)
                    $scope.selectedPickUpReturn = data[0];
            };

            $scope.setSelectedDropOffReturn = function (data) {
                if (!$scope.selectedDropOffReturn) {
                    if ((data || "").length !== 1)
                        return;
                    $scope.selectedDropOffReturn = data[0];
                    return;
                };
                if (!data) {
                    $scope.selectedDropOffReturn = undefined;
                    return;
                }
                $scope.selectedDropOffReturn = _.find(data, function (it) {
                    return it.code == $scope.selectedDropOffReturn.code;
                });

                if (!$scope.selectedDropOffReturn && data.length === 1)
                    $scope.selectedDropOffReturn = data[0];
            };

            $scope.refreshBusStops = function () {

                var travelDate = $("#departure").data().daterangepicker.startDate.format("YYYY-MM-DD");
                if ($scope.selectedLeavingFromCity) {
                    $scope.fillBussStopsForLocation($scope.selectedLeavingFromCity, travelDate, function () {
                        $scope.setSelectedPickUp($scope.selectedLeavingFromCity.pickups);
                        $scope.setSelectedDropOffReturn($scope.selectedLeavingFromCity.dropoffs);
                        if ($scope.selectedGoingToCity) {
                            $scope.fillBussStopsForLocation($scope.selectedGoingToCity, travelDate, function () {
                                $scope.setSelectedDropOff($scope.selectedGoingToCity.dropoffs);
                                $scope.setSelectedPickUpReturn($scope.selectedGoingToCity.pickups);
                            });
                        }
                    });
                } else if ($scope.selectedGoingToCity) {
                    $scope.fillBussStopsForLocation($scope.selectedGoingToCity, travelDate, function () {
                        $scope.setSelectedDropOff($scope.selectedGoingToCity.dropoffs);
                        $scope.setSelectedPickUpReturn($scope.selectedGoingToCity.pickups);
                    });
                }
            };

            $scope.leavingFromCityChanged = function () {
                if (!$scope.selectedLeavingFromCity) return;
                $scope.wasSearch = false;
                $scope.resetSelectedProducts();
                var travelDate = $("#departure").data().daterangepicker.startDate.format("YYYY-MM-DD");
                $scope.fillBussStopsForLocation($scope.selectedLeavingFromCity, travelDate, function () {
                    $scope.setSelectedPickUp($scope.selectedLeavingFromCity.pickups);
                    $scope.setSelectedDropOffReturn($scope.selectedLeavingFromCity.dropoffs);

                    // search automatically if update
                    if ($scope.updateItem && !$scope.updateItem.isUpdateCompSynced
                        && $scope.selectedLeavingFromCity.dropoffs && $scope.selectedLeavingFromCity.pickups
                        && $scope.selectedGoingToCity.dropoffs && $scope.selectedGoingToCity.pickups) {
                        $scope.updateItem.isUpdateCompSynced = true;
                        $scope.searchProducts();
                    }
                });
            };

            $scope.goingToCityChanged = function (callback) {
                if (!$scope.selectedGoingToCity) return;
                $scope.wasSearch = false;
                $scope.resetSelectedProducts();
                var travelDate = $("#departure").data().daterangepicker.startDate.format("YYYY-MM-DD");
                $scope.fillBussStopsForLocation($scope.selectedGoingToCity, travelDate, function () {
                    $scope.setSelectedDropOff($scope.selectedGoingToCity.dropoffs);
                    $scope.setSelectedPickUpReturn($scope.selectedGoingToCity.pickups);

                    // search automatically if update                     
                    if ($scope.updateItem && !$scope.updateItem.isUpdateCompSynced
                        && $scope.selectedLeavingFromCity.dropoffs && $scope.selectedLeavingFromCity.pickups
                        && $scope.selectedGoingToCity.dropoffs && $scope.selectedGoingToCity.pickups) {
                        $scope.updateItem.isUpdateCompSynced = true;
                        $scope.searchProducts();
                    }
                });
            };

            $scope.changeTransportationType = function (type) {
                if ($scope.isLoading) return;
                resizeSliderPanel();
                $scope.wasSearch = false;
                $scope.resetSelectedProducts();
                $scope.showNext = $scope.canContinue();
            };

            //0- all, 1-departure, 2- return
            $scope.getTransportations = function (categ, callback) {
                var isDeparture = !categ || categ <= 1;
                var fromLocation = isDeparture ? $scope.selectedLeavingFromCity : $scope.selectedGoingToCity;
                var toLocation = isDeparture ? $scope.selectedGoingToCity : $scope.selectedLeavingFromCity;

                var pickup = isDeparture ? $scope.selectedPickUp : $scope.selectedPickUpReturn;//isDeparture ? $scope.selectedPickUp : $scope.selectedDropOff;
                var dropoff = isDeparture ? $scope.selectedDropOff : $scope.selectedDropOffReturn;

                var requestParams = {
                    urlPrefix: $("body").data("weburl") ? $("body").data("weburl") : "",
                    token: jwtService.getPrincipalToken(),
                    date: $(isDeparture ? "#departure" : "#return").data().daterangepicker.startDate.format("YYYY-MM-DD"),
                    type: $scope.serviceType,
                    fromLocationCode: fromLocation.code,
                    fromLocationName: fromLocation.name,
                    toLocationCode: toLocation.code,
                    toLocationName: toLocation.name,
                    pickupCode: pickup.code,
                    dropoffCode: dropoff.code
                };

                var trackerReq = {
                    lobTitle: $scope.lobTitle,
                    packageName: null,
                    searchDate: requestParams.date,
                    adults: parseInt($scope.selectedAdults),
                    children: parseInt($scope.selectedChild),
                    shoppingCart: $scope.cart,
                    anonymUser: $scope.anonymGeneralUser,
                    bookingNumber: null,
                    bookingId: null
                };
                trackingService.buildFlowTrackerObj(trackerReq);

                //uncomment if needed
                //$scope.selectedReturnPickTime = "";
                //$scope.selectedDeparturePickTime = "";



                //$scope.isLoading = true;
                //$scope.wasSearch = true;
                //$scope.allProducts = [];
                // $scope.allReturnProducts = [];
                transportationService.getTransportationsByTypeWithPackages(requestParams, function (dateResult) {
                    var isCurrDate = moment(requestParams.date).isSame(jwtService.getServerMomentDate());
                    var currHourLimit = jwtService.getServerMomentDate(true);
                    // moment(tc.format("hh:mm A"), "hh:mm A");

                    if (dateResult && dateResult.data && dateResult.data.products && dateResult.data.products.length > 0) {

                        if ($scope.requestArguments.unitCode) {
                            dateResult.data.products = _.filter(dateResult.data.products, function (product) {
                                if (product.units && product.units.length > 0) {
                                    return product.units[0].unitCode === $scope.requestArguments.unitCode;
                                }
                                return false;
                            });
                        }
                        _.each(dateResult.data.products, function (product) {
                            product.endTimeStr = moment(product.endDate).format("hh:mm A");
                            var productDateStr = product.startDate.substring(0, product.startDate.indexOf("T"));

                            if (product.units && product.units.length > 0) {
                                var unit = product.units[0];
                                if (unit) {
                                    product.timeStr = moment(unit.startTime).format("hh:mm A");

                                    var newDateTime = productDateStr + unit.startTime.substring(unit.startTime.indexOf("T"));
                                    product.timeVal = moment(newDateTime);
                                    // product.timeVal = moment(product.timeStr, "hh:mm A");

                                    // if (isCurrDate) {
                                    product.isInPast = product.timeVal <= currHourLimit;
                                    if (!product.isInPast && product.bookingRestrictionTime > 0) {
                                        var tc = jwtService.getServerMomentDate(true);
                                        tc.add(parseInt(product.bookingRestrictionTime), "m");
                                        // var timeLimit = moment(tc.format("hh:mm A"), "hh:mm A");
                                        product.isTimeRestricted = product.timeVal <= tc;
                                    }
                                    // }
                                }
                            }
                        });
                    }

                    var products = _.sortBy(dateResult.data.products, function (val) {
                        return val.timeVal;
                    });

                    var selectedPickup = isDeparture ? $scope.selectedPickUp : $scope.selectedPickUpReturn;
                    var selectedDropoff = isDeparture ? $scope.selectedDropOff : $scope.selectedDropOffReturn;


                    _.each(products, function (product) {
                        var unit = product.units[0];
                        if (!unit) return;
                        if ((unit.pickups || "").length) {
                            unit.selectedPickup = _.find(unit.pickups, function (pu) {
                                return pu.code == selectedPickup.code;
                            });
                            if (unit.selectedPickup) {
                                unit.selectedPickupTimeMoment = moment(unit.selectedPickup.timeObj, "HH:mm");
                                product.pickupStr = unit.selectedPickupTimeMoment.format("hh:mm A");
                            }
                        }
                        if ((unit.dropoffs || "").length) {
                            unit.selectedDropoff = _.find(unit.dropoffs, function (pu) {
                                return pu.code == selectedDropoff.code;
                            });
                            if (unit.selectedDropoff) {
                                unit.selectedDropoffTimeMoment = moment(unit.selectedDropoff.timeObj, "HH:mm");
                                product.dropoffStr = unit.selectedDropoffTimeMoment.format("hh:mm A");
                            }
                        }
                    });

                    if (isDeparture) {
                        $scope.allProducts = products;
                    } else {
                        $scope.allReturnProducts = products;
                    }
                    $scope.showNext = $scope.canContinue();
                    //$scope.fillTransportations();
                    //$scope.isLoading = false;

                    if (callback) {
                        callback();
                    }

                });
            };

            $scope.disableReturnProducts = function () {
                var isSameDate = $scope.isTheSameDate();

                _.each($scope.allReturnProducts, function (product) {
                    product.disabled = false;

                    if (!isSameDate || !$scope.selectedDepartureProduct) return;
                    product.disabled = (product.timeVal <= $scope.selectedDepartureProduct.timeVal);
                });
                if ($scope.selectedReturnProduct && $scope.selectedReturnProduct.disabled) {
                    $scope.selectedReturnProduct = undefined;
                }
            };

            $scope.disableDepartureProducts = function () {
                var isSameDate = $scope.isTheSameDate();

                _.each($scope.allProducts, function (product) {
                    product.disabled = false;
                    if (!isSameDate || !$scope.selectedReturnProduct) return;
                    product.disabled = (product.timeVal >= $scope.selectedReturnProduct.timeVal);
                });
                if ($scope.selectedDepartureProduct && $scope.selectedDepartureProduct.disabled) {
                    $scope.selectedDepartureProduct = undefined;
                }
            };

            $scope.initLocations = function (callback) {
                var requestParams = {
                    urlPrefix: $("body").data("weburl") ? $("body").data("weburl") : "",
                    token: jwtService.getPrincipalToken(),
                    type: jQuery("div[ng-controller='transportationDetailsCtrl']").attr("data-transportation-product-type")
                };
                $scope.isLoading = true;
                transportationService.getLocationsByServiceType(requestParams, function (dateResult) {
                    $scope.isLoading = false;
                    if (dateResult.data) {
                        var departureLocations = (dateResult.data.departureLocations || "").length ? dateResult.data.departureLocations : [];
                        var destinationLocations = (dateResult.data.destinations || "").length ? dateResult.data.destinations : [];
                        $scope.departureLocations = _.sortBy(departureLocations, function (loc) { return loc.name; });
                        $scope.destinationLocations = _.sortBy(destinationLocations, function (loc) { return loc.name; });
                    }
                    callback();
                });
            };

            $scope.init = function () {
                //console.log($stateParams.ticketType, $stateParams.departure, $stateParams.return, $stateParams.leavingFrom, $stateParams.goingTo, $stateParams.adults, $stateParams.children);
                $scope.isLoading = false;
                var travelDateObj = jwtService.getServerMomentDate();
                var departuredatepickersettings = {
                    singleDatePicker: true,
                    minDate: jwtService.getServerMomentDate(),
                    showDropdowns: true,
                    locale: {
                        format: shoppingCartService.getDateFormat()
                    },
                    parentEl: "#departuredaterangecontainer"
                };
                if ($scope.updateItem) {
                    departuredatepickersettings.startDate = $scope.updateItem.startDateMoment;
                }
                if ($scope.selectedLanguage && $scope.selectedLanguage.languageCode) {
                    moment.locale($scope.selectedLanguage.languageCode);
                }

                //if ($scope.selectedLanguage && $scope.selectedLanguage.calendar) {
                //    departuredatepickersettings.locale.daysOfWeek = $scope.selectedLanguage.calendar.daysOfWeek;
                //    departuredatepickersettings.locale.monthNames = $scope.selectedLanguage.calendar.monthNames;
                //    departuredatepickersettings.locale.firstday = $scope.selectedLanguage.calendar.firstDay;
                //}
                $scope.departure = $("#departure").daterangepicker(departuredatepickersettings);

                $scope.departure.on("apply.daterangepicker", function (ev, picker) {
                    if ($scope.isLoading) return false;
                    $scope.wasSearch = false;
                    $scope.resetSelectedProducts();
                    resizeSliderPanel();
                    if ($scope.return.data().daterangepicker.startDate
                        .isSameOrBefore($scope.departure.data().daterangepicker.startDate)) {
                        $scope.return.data().daterangepicker.setStartDate($scope.departure.data().daterangepicker.startDate);
                        $scope.return.data().daterangepicker.setEndDate($scope.departure.data().daterangepicker.startDate);
                    }
                    $scope.refreshBusStops();
                    // $scope.getTransportations(1);
                    return true;
                });

                var returndatepickersettings = {
                    singleDatePicker: true,
                    minDate: jwtService.getServerMomentDate(),
                    showDropdowns: true,
                    locale: {
                        format: shoppingCartService.getDateFormat()
                    },
                    parentEl: "#returndaterangecontainer"
                };
                if ($scope.updateItem && $scope.updateItem.returnStartDateMoment) {
                    returndatepickersettings.startDate = $scope.updateItem.returnStartDateMoment;
                }
                //if ($scope.selectedLanguage && $scope.selectedLanguage.calendar) {
                //    returndatepickersettings.locale.daysOfWeek = $scope.selectedLanguage.calendar.daysOfWeek;
                //    returndatepickersettings.locale.monthNames = $scope.selectedLanguage.calendar.monthNames;
                //    returndatepickersettings.locale.firstday = $scope.selectedLanguage.calendar.firstDay;
                //}

                $scope.return = $("#return").daterangepicker(returndatepickersettings);


                $scope.return.on("apply.daterangepicker", function (ev, picker) {
                    if ($scope.isLoading) return;
                    $scope.wasSearch = false;
                    $scope.resetSelectedProducts();
                    resizeSliderPanel();

                    if ($scope.return.data().daterangepicker.startDate
                        .isSameOrBefore($scope.departure.data().daterangepicker.startDate)) {
                        $scope.departure.data().daterangepicker.setStartDate($scope.return.data().daterangepicker.startDate);
                        $scope.departure.data().daterangepicker.setEndDate($scope.return.data().daterangepicker.startDate);
                    }
                    $scope.refreshBusStops();
                });

                var result = $scope.$parent.getPrevtransportation();

                $scope.selectedAdults = "2";
                $scope.selectedChild = "0";

                if ($scope.updateItem) {
                    var firstUpdateComp = $scope.updateItem.BookingToQuote.Components[0];
                    $scope.transportationType = $scope.updateItem.BookingToQuote.Components[1] ? 2 : 1;
                    $scope.selectedAdults = firstUpdateComp.NumberOfAdults || 2;
                    $scope.selectedChild = firstUpdateComp.NumberOfChildren || 0;
                    $scope.selectedSeniors = firstUpdateComp.NumberOfSeniors || 0;
                    $scope.selectedStudents = firstUpdateComp.NumberOfStudents || 0;
                    $scope.selectedInfants = firstUpdateComp.NumberOfInfants || 0;
                } else {

                    if ($stateParams.ticketType) {
                        try {
                            $scope.transportationType = parseInt($stateParams.ticketType);
                        } catch (e) {
                            console.log("Invalid ticket type param");
                        }
                    }


                    if ($stateParams.children) {
                        try {
                            var qchild = String(parseInt($stateParams.children));
                            if ($scope.availableChild.indexOf(qchild) >= 0) {
                                $scope.selectedChild = qchild;
                            }
                        } catch (e) {
                            console.log("Invalid children param");
                        }
                    }

                    if ($stateParams.adults) {
                        try {
                            var qadults = String(parseInt($stateParams.adults));
                            if ($scope.availableAdults.indexOf(qadults) >= 0) {
                                $scope.selectedAdults = qadults;
                                $scope.adultsChanged();
                            }
                        } catch (e) {
                            console.log("Invalid adults param");
                        }
                    }




                    //$scope.requestArguments.travelDate = $scope.requestArguments.isDefaultDate ? travelDateObj : moment($scope.requestArguments.travelDate);

                    //if (travelDateObj < $scope.requestArguments.travelDate) {
                    //    travelDateObj = $scope.requestArguments.travelDate;
                    //}

                    var queryDepDate = undefined;
                    var queryRetDate = undefined;

                    if ($stateParams.departure) {
                        try {
                            var pd = $stateParams.departure.split('-');
                            var newDepDate = pd[0] + ((pd[1].length == 1 ? "0" : "") + pd[1]) + ((pd[2].length == 1 ? "0" : "") + pd[2]);
                            queryDepDate = moment(newDepDate, "YYYY-MM-DD");
                            if (!queryDepDate.isValid) queryDepDate = undefined;
                        } catch (e) {
                            console.log("invalid departure date");
                        }
                    }

                    if ($stateParams.return && $scope.transportationType == 2) {
                        try {
                            var pr = $stateParams.return.split('-');
                            var newRetDate = pr[0] + ((pr[1].length == 1 ? "0" : "") + pr[1]) + ((pr[2].length == 1 ? "0" : "") + pr[2]);
                            queryRetDate = moment(newRetDate, "YYYY-MM-DD");
                            if (!queryRetDate.isValid) queryRetDate = undefined;
                        } catch (e) {
                            console.log("invalid return date");
                        }
                    }

                    if (result && result.data && result.data.startDate) {
                        var prodDate = moment(result.data.startDate);
                        if (prodDate < travelDateObj) {
                            travelDateObj = prodDate;
                        }
                    }
                    var startDate = (queryDepDate && queryDepDate >= travelDateObj) ? queryDepDate : travelDateObj;
                    var returnDate = (queryRetDate && queryRetDate >= startDate) ? queryRetDate : startDate;

                    $("#departure").val(startDate.format(shoppingCartService.getDateFormat()));
                    $("#departure").data().daterangepicker.minDate = startDate;
                    $("#departure").data().daterangepicker.startDate = startDate;
                    $("#departure").data().daterangepicker.endDate = startDate;

                    $("#return").val(returnDate.format(shoppingCartService.getDateFormat()));
                    $("#return").data().daterangepicker.minDate = returnDate;
                    $("#return").data().daterangepicker.startDate = returnDate;
                    $("#return").data().daterangepicker.endDate = returnDate;
                } // end else if not updateitem

                $scope.initLocations(function () {
                    //
                    if ($scope.updateItem) {
                        var firstUpdateComp = $scope.updateItem.BookingToQuote.Components[0];
                        if (firstUpdateComp.StartingLocation) {
                            $scope.selectedLeavingFromCity = $scope.departureLocations && _.find($scope.departureLocations, function (city) {
                                return city.code == firstUpdateComp.StartingLocation.code
                            });
                        }

                        if (firstUpdateComp.Destination) {
                            $scope.selectedGoingToCity = $scope.destinationLocations && _.find($scope.destinationLocations, function (city) {
                                return city.code == firstUpdateComp.Destination.code
                            });
                        }

                        $scope.selectedPickUp = firstUpdateComp.PickupLocation;
                        $scope.selectedDropOff = firstUpdateComp.DropoffLocation;

                        var secondUpdateComp = $scope.updateItem.BookingToQuote.Components[1];
                        if (secondUpdateComp) {
                            $scope.selectedPickUpReturn = secondUpdateComp.PickupLocation;
                            $scope.selectedDropOffReturn = secondUpdateComp.DropoffLocation;
                        }

                        //$scope.leavingFromCityChanged(function () {                           
                        //    //$scope.goingToCityChanged(function () {
                        //    //    $scope.searchProducts();
                        //    //});
                        //});
                    }
                });

                $scope.lobTitle = $scope.transportation && $scope.transportation.productDescriptions
                    && (
                        $scope.transportation.productDescriptions.genericTitle || ($scope.transportation.productDescriptions.titles && $scope.transportation.productDescriptions.titles.length > 0 ? $scope.transportation.productDescriptions.titles[0] : $scope.transportation.name));

                var trackerReq = {
                    lobTitle: $scope.lobTitle,
                    packageName: null,
                    searchDate: null,
                    adults: null,
                    children: null,
                    shoppingCart: $scope.cart,
                    anonymUser: $scope.anonymGeneralUser,
                    bookingNumber: null,
                    bookingId: null
                };

                trackingService.buildFlowTrackerObj(trackerReq); // ($scope.transportation && $scope.transportation.startDate)
            };

            var initialized = false;

            $scope.anonymUser = undefined;
            $scope.initCurrentAnonymUser = function (callback) {


                jwtService.getAnonymousUserByGeography(generalCtrl.selectedGeographyCode, function (user) {
                    $scope.anonymUser = user;
                    callback();
                });
            };

            $scope.$watch(function () {
                return taskFactory.task;
            },
                function (val) {
                    if (!val || !val.name || initialized) return;
                    initialized = true;

                    var initShoppingCart = new Promise(function (resolve, reject) {
                        shoppingCartService.getStorageCart(function (shoppingCart) {
                            if (shoppingCart) {
                                $scope.cart = shoppingCart;

                                $scope.updateItem = undefined;
                                $scope.updateIndex = -1;

                                if (($scope.requestArguments.updateCartItemCode || "").length && $scope.cart && $scope.cart.Items) {
                                    $scope.updateItem = _.find($scope.cart.Items, function (cartItem) {
                                        $scope.updateIndex++;
                                        var relatedComponent = _.find(cartItem.BookingToQuote && cartItem.BookingToQuote.Components, function (comp) {
                                            return comp.ProductCode == $scope.requestArguments.updateCartItemCode;
                                        });
                                        return relatedComponent != null;
                                    });
                                    if ($scope.updateItem) {
                                        $scope.updateItem.isUpdateCompSynced = false;

                                        $scope.updateItem.startDateMoment = moment($scope.updateItem.BookingToQuote.Components[0].StartDate);
                                        if ($scope.updateItem.BookingToQuote.Components[1]) {
                                            $scope.updateItem.returnStartDateMoment = moment($scope.updateItem.BookingToQuote.Components[1].StartDate);
                                        }
                                    }
                                }
                            }
                            resolve(1);
                        });
                    }); // init shopping cart update item

                    initShoppingCart.then(function () {
                        $timeout($scope.initCurrentAnonymUser.bind(null, $scope.init)); //$scope.init);
                    });

                }, true);

        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("transportationDetailsCtrl", [
        "utilsFactory", "$scope", "$state", "$element", "$http", "localStorageService", "jwtService", "transportationService", "activitiesService", "$rootScope", "taskFactory", "$timeout", function (utilsFactory, $scope, $state, $element, $http, localStorageService, jwtService, transportationService, activitiesService, $rootScope, taskFactory, $timeout) {

            $.material.init();

            $scope.$on("mergeGlobalErros", function (event, args) {
                $scope.isLoading = false;
            });

            $scope.showModal = {};
            $scope.isLoading = true;

            var timeoutID = undefined;
            function resizeSliderPanel() {
                window.clearTimeout(timeoutID);
                timeoutID = setTimeout(function () {
                    jQuery(window).resize();
                }, 100);
            }
            $rootScope.$on("$stateChangeSuccess",
            function (event, toState, toParams, fromState, fromParams) {
                resizeSliderPanel();
            });

            $scope.requestArguments = {
                transportationId: $($element).attr("data-transportation-id"),
                productType: $($element).attr("data-transportation-product-type"),
                productCategory: $($element).attr("data-transportation-product-category"),
                travelDate: $($element).attr("data-transportation-travel-date"),
                isDefaultDate: $($element).attr("data-transportation-is-default-date")==="1"
            };
            $scope.billingDetails = {};

            $state.go("select-transport-ticket.book-adventure", {});

            $scope.wizardModel = {
                transportationId: undefined,
                ticketTypes: undefined,
                ticketType: undefined,
                transportation: undefined,
                ticketsCriteria: {
                    date: undefined,
                    returningDate: undefined,
                    adults: undefined,
                    child: undefined,
                    product: undefined
                },
                packagesCriteria: {
                    date: undefined,
                    adults: 1,
                    children: 0,
                    packages: undefined,
                    selectedPackage: undefined
                },
                bookedModalShowed: false
            };

            $scope.getPrevtransportation = function () {
                if (localStorageService.isSupported) {
                    return localStorageService.get("prevtransportation");
                }
                return null;
            };

            $scope.getButtonLabel = function (state) {
                return utilsFactory.getLabel("transportation.go-back");
                //switch (state) {
                //    case "select-transport-ticket":
                //        return utilsFactory.getLabel("transportation.go-back");
                //    case "select-transport-ticket.book-adventure":
                //        return utilsFactory.getLabel("transportation.see-all");
                //    default:
                //        return utilsFactory.getLabel("transportation.see-all");
                //};
            };

            $scope.persistWizardModel = function (callback) {
                transportationService.setTransportationWizardModel($scope.wizardModel, callback);
            };
            $scope.back = function (state) {
                var sectionid = $("[data-sectionid]").data("sectionid") || 0;
                transportationService.setTransportationWizardModel($scope.wizardModel, function () { });

                switch (state) {
                    case "select-transport-ticket":
                    case "select-transport-ticket.book-adventure":
                        transportationService.setIsFromTransportationDetails(1, function () {
                        });

                        window.location.href = utilsFactory.addPersistentQueryStringsParams("/" + jwtService.getGeography() + "/transportation" + (sectionid ? "/" + sectionid : ""));
                        break;
                    case "select-transport-ticket.packages":
                        $state.go("select-transport-ticket");
                        break;
                    case "package-details":
                        $state.go("select-transport-ticket.packages");
                        break;
                };
                $scope.$parent.cleanGlobalErrors();
            };

            $scope.next = function (state, params) {
                transportationService.setTransportationWizardModel($scope.wizardModel, function () { });

                switch (state) {
                    case "select-transport-ticket":
                        if ($scope.wizardModel.ticketType && $scope.wizardModel.ticketType.name) {

                            if ($scope.wizardModel.ticketType.name.toLowerCase().indexOf("package") >= 0) {
                                $state.go("select-transport-ticket.packages");
                            } else {
                                $state.go("select-transport-ticket.book-adventure");
                            }
                        }
                        break;
                    case "select-transport-ticket.packages":
                        if (!params) break;
                        $state.go("package-details", params);
                        break;
                }

                $scope.$parent.cleanGlobalErrors();
            };

            $scope.savePackagesSearchCriteria = function (criteria) {
                $scope.wizardModel.packagesCriteria = criteria;
            };

            $scope.getPackagesSearchCriteria = function () {
                return $scope.wizardModel.packagesCriteria;
            };

            $scope.setSelectedPackage = function (selectedPackage) {
                $scope.wizardModel.packagesCriteria.selectedPackage = selectedPackage;
            };

            $scope.setTicketType = function (ticketType) {
                $scope.wizardModel.ticketType = ticketType;
            };

            $scope.getTicketTypeByName = function (name) {
                var foundTicketType = undefined;
                angular.forEach($scope.wizardModel.ticketTypes, function (ticketType) {
                    if (ticketType.name === name) {
                        foundTicketType = ticketType;
                    }
                });

                return foundTicketType;
            };

            $scope.setTicket = function (setTicket) {
                $scope.wizardModel.ticket = setTicket;
            };

            $scope.getTicket = function () {
                return $scope.wizardModel.ticket;
            };

            $scope.getProduct = function () {
                return $scope.wizardModel.roomsCriteria.product;
            };

            $scope.getOptionalExtras = function () {
                return $scope.wizardModel.roomsCriteria.optionalExtras;
            };

            $scope.saveSearchCriteria = function (criteria) {
                $scope.wizardModel.roomsCriteria = criteria;
            };

            $scope.getSearchCriteria = function () {
                return $scope.wizardModel.roomsCriteria;
            };

            $scope.setBillingDetails = function (detail) {
                $scope.billingDetails = detail;
            };

            $scope.getBillingDetails = function () {
                return $scope.billingDetails;
            };

            $scope.getTicketTypes = function (callback) {
                var generalCtrl = $scope.$parent;

                var productId = $scope.wizardModel.transportation.id;
                var productCategory = $scope.wizardModel.transportation.productCategory;

                //$scope.isLoading = true;

                var params = {
                    urlPrefix: generalCtrl.getWebUrl(),
                    token: jwtService.getPrincipalToken(),
                    productId: productId,
                    productCategory: productCategory
                };

                activitiesService.getTicketTypes(params, function (ticketTypesResult) {
                    if (ticketTypesResult.success) {
                        if (ticketTypesResult.data && ticketTypesResult.data.length > 0) {

                            $scope.wizardModel.ticketTypes = ticketTypesResult.data;
                            $scope.wizardModel.ticketType = $scope.wizardModel.ticketTypes[0];

                            transportationService.setTransportationWizardModel($scope.wizardModel, function () { });
                        }
                    } else {
                        console.log(ticketTypesResult.error);
                    }

                    // $scope.isLoading = false;
                    if (callback)
                        callback();
                });
            };

            $scope.setWizardModel = function (params) {

                function setSelectedTransportation(prod, callback) {
                    transportationService.setSelectedTransportation(prod, function (setTransportResult) {

                        $scope.wizardModel.transportation = prod;

                        if (!$scope.wizardModel.ticketsCriteria.product) {
                            $scope.wizardModel.ticketsCriteria.product = $scope.wizardModel.transportation;
                        }

                        transportationService.setTransportationWizardModel($scope.wizardModel, function () {

                            taskFactory.addTask("SelectedTransportationChanged", $scope.wizardModel.transportation);


                            $timeout(function () {
                                if (callback)
                                    callback();
                            });

                        });

                    });
                }
                var sectionid = $("[data-sectionid]").data("sectionid") || 0;
                transportationService.getPersistedTransportationsFilters(sectionid,function (filtersResult) {
                    if (filtersResult.success && filtersResult.data && filtersResult.data.transportations) {
                        var transportations = filtersResult.data.transportations;
                        var prod = _.find(transportations, function (a) {
                            return (a.productType || "").trim().toLowerCase()
                                === (params.productType || "").trim().toLowerCase();
                        });

                        if (prod) {
                            setSelectedTransportation(prod, function () {
                                $scope.isLoading = false;
                            });
                        }
                        else { $scope.isLoading = false; }

                    } else {
                        transportationService.getTransportationsByDate({
                            token: params.token,
                            id: sectionid,
                            date: params.travelDate,
                            urlPrefix: $scope.getWebUrl()
                        }, function (result) {
                            if (result.success && result.data && result.data.products) {
                                var transportations = result.data.products;

                                var prod = _.find(transportations, function (a) {
                                    return (a.productType || "").trim().toLowerCase()
                                        === (params.productType || "").trim().toLowerCase();
                                });

                                if (prod) {
                                    setSelectedTransportation(prod, function () {
                                        $scope.isLoading = false;
                                    });
                                } else {
                                    $scope.isLoading = false;
                                }

                            } else {
                                $scope.isLoading = false;
                                console.log(result.error);
                            }
                        });
                    }
                });

            };


            $scope.setTokenAndWizardModel = function (params) {
                if (!params.token) {
                    jwtService.setPrincipalTokenAsync(params.urlPrefix,$scope.$parent.trackingInfo, function (newToken) {
                        params.token = newToken;
                        $scope.setWizardModel(params);
                    });
                } else {
                    $scope.setWizardModel(params);
                }
            };

            $scope.init = function () {
                //get date
              
                $scope.isLoading = true;
                transportationService.getSelectedTransportation(function (result) {
                    var travelDateObj = jwtService.getServerMomentDate();
                  
                    if (result&&result.data&&result.data.startDate) {
                        var prodDate = moment(result.data.startDate);
                        if (prodDate < travelDateObj) {
                            travelDateObj = prodDate;
                        }
                    }

                    $scope.requestArguments.travelDate = $scope.requestArguments.isDefaultDate ?travelDateObj: moment($scope.requestArguments.travelDate);

                    if (travelDateObj < $scope.requestArguments.travelDate) {
                        travelDateObj= $scope.requestArguments.travelDate;
                    }

                    var params = {
                        urlPrefix: $scope.$parent.getWebUrl(),
                        token: undefined,
                        productType: $scope.requestArguments.productType,
                        productCategory: $scope.requestArguments.productCategory,
                        travelDate:travelDateObj.format("YYYY-MM-DD")
                    };
                    var token = jwtService.getPrincipalToken();

                    params.token = token;

                    if (!result.data || !result.data.transport || !result.data.ticketTypes || !result.data.ticketTypes.length) {
                        $scope.setTokenAndWizardModel(params);
                    } else if (result.data.transportation.code !== $scope.requestArguments.productCode) {
                        $scope.setTokenAndWizardModel(params);
                    } else {
                        $scope.wizardModel = result.data;
                        transportationService.setSelectedTransportation($scope.wizardModel.transportation, function (setTransportationResult) {
                            taskFactory.addTask("SelectedTransportationChanged", $scope.wizardModel.transportation);
                        });

                        $scope.isLoading = false;
                    }
                });
            };

            $rootScope.$broadcast("transportationDetailsCtrlInitialized");

            $scope.$on("generalControllerInitilized", function (event, data) {
                var t = jwtService.getPrincipalToken();

                if (t && t.length > 0) {
                    $scope.init();
                } else {
                    $scope.isLoading = true;
                    $scope.$on("getPrincipalToken", function (event, args) {
                        $scope.init();
                    });
                };
            });


            $scope.$on("transportationWizardModelChanged", function (event, data) {
                $scope.wizardModel = data.wizardModel;

                if (data.callback) {
                    data.callback();
                }
            });
        }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("transportationFilterCtrl", [
       "utilsFactory", "$scope", "$http", "$element", "localStorageService", "jwtService", "transportationService", "taskFactory", "$timeout", function (utilsFactory, $scope, $http, $element, localStorageService, jwtService, transportationService, taskFactory, $timeout) {

           $scope.utils = utilsFactory;
           TweenMax.ticker.useRAF(false);
           $scope.detailsUrl = $($element).attr("data-transportation-details") || "";
           $scope.transportations = [];
           $scope.categories = [];
           $scope.locations = [];
           $scope.priceRanges = [];
           $scope.geographyCode = jwtService.getGeography();

           $scope.filter = {
               selectedCategory: null,
               selectedLocation: null,
               selectedPriceRange: null
           };

           $scope.resultfilter = {
               selectedCategory: null,
               selectedLocation: null,
               selectedPriceRange: null
           };

           $scope.orderBy = {
               predicate: "name",
               reverse: false
           };

           $scope.listIsLoading = false;
           $scope.showNavArrows = false;

           $scope.$on("mergeGlobalErros", function (event, args) {
               $scope.isLoading = false;
               $scope.listIsLoading = false;
           });

           $scope.handleFilter = function (e) {
               if ($scope.listIsLoading) return;
               transportationService.persistTransportationsFilters({
                   transportations: $scope.transportations,
                   filters: $scope.filter,
                   locations: $scope.locations,
                   categories: $scope.categories,
                   priceRanges: $scope.priceRanges,
                   orderBy: $scope.orderBy
               }, function (result) {
                   if (e) {
                       //slide up
                       $(e.currentTarget).parent().parent().prev().click();
                   }

                   if (result.success) {
                       $scope.resultfilter.selectedCategory = result.data.filters.selectedCategory;
                       $scope.resultfilter.selectedPriceRange = result.data.filters.selectedPriceRange;
                       $scope.resultfilter.selectedLocation = result.data.filters.selectedLocation;
                   } else {
                       console.log(result.error);
                   }
               });
           };

           $scope.goToProductDetailsIfSingle = function () {
               var sectionid = $("[data-sectionid]").data("sectionid") || 0;
               if (($scope.transportations || "").length === 1) {
                   if (transportationService.getIsFromTransportationDetails()) {
                       transportationService.setIsFromTransportationDetails(0, function () {
                           transportationService.setIsFromFilters(1, function () { });
                           window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
                       });
                       return true;
                   }
                   window.location.href = utilsFactory.addPersistentQueryStringsParams( "/" + $scope.geographyCode + $scope.detailsUrl.trim().replace(/[\/\\]$/, "") + "/"
                         + (sectionid ? sectionid + "/" : "")
                       + $scope.transportations[0].productType + "/" + $scope.transportations[0].productCategory);
                   return true;
               }
               transportationService.setIsFromTransportationDetails(0, function () { });
               return false;
           };

           $scope.getTransportations = function (e) {
               if ($scope.listIsLoading) return;
               if (e) {
                   $(e.currentTarget).parent().parent().prev().click();
               }
               var sectionid = $("[data-sectionid]").data("sectionid") || 0;
               $scope.resultfilter.selectedCategory = $scope.filter.selectedCategory;
               $scope.resultfilter.selectedPriceRange = $scope.filter.selectedPriceRange;

               $scope.resultfilter.selectedLocation = $scope.filter.selectedLocation;

               var token = jwtService.getPrincipalToken();
               //  var date = new Date();
               //   date.setDate(date.getDate() + 1); //TODO: Remove when fixed
               //     var myDate = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
               $scope.listIsLoading = true;

               transportationService.getPersistedTransportationsFilters(sectionid, function (filtersResult) {
                   if (filtersResult.success && filtersResult.data) {
                       $scope.transportations = filtersResult.data.transportations;
                       setTimeout(function () {
                           jQuery(".scroll-list[list-scroll]").trigger("checkArrows");
                       }, 0);
                       if (!$scope.goToProductDetailsIfSingle()) {
                           $scope.listIsLoading = false;
                       }
                   } else {
                       transportationService.getTransportationsByDate({
                           token: token,
                           id: sectionid,
                           date: jwtService.getServerStrDate(),
                           urlPrefix: $scope.$parent.getWebUrl()
                       }, function (result) {
                           if (result.success) {
                               $scope.transportations = result.data.products;

                               transportationService.persistTransportationsFilters(sectionid, {
                                   transportations: $scope.transportations,
                                   filters: $scope.filter,
                                   locations: $scope.locations,
                                   categories: $scope.categories,
                                   priceRanges: $scope.priceRanges,
                                   orderBy: $scope.orderBy
                               }, function () {

                               });

                           } else {
                               console.log(result.error);
                           }
                           if (!$scope.goToProductDetailsIfSingle()) {
                               $scope.listIsLoading = false;
                               setTimeout(function () {
                                   jQuery(".scroll-list[list-scroll]").trigger("checkArrows");
                               }, 0);
                           }
                       });
                   }
               });

           };
           $scope.getTransportationFilters = function (callback) {
               $scope.listIsLoading = true;
               var sectionid = $("[data-sectionid]").data("sectionid") || 0;
               transportationService.getPersistedTransportationsFilters(sectionid,function (filtersResult) {
                   if (filtersResult.success && filtersResult.data) {
                       $scope.locations = filtersResult.data.locations;
                       $scope.priceRanges = filtersResult.data.priceRanges;
                       $scope.categories = filtersResult.data.categories;
                       $scope.orderBy = filtersResult.data.orderBy;

                       $scope.resultfilter.selectedCategory = $scope.filter.selectedCategory = filtersResult.data.filters.selectedCategory;
                       $scope.resultfilter.selectedPriceRange = $scope.filter.selectedPriceRange = filtersResult.data.filters.selectedPriceRange;
                       $scope.resultfilter.selectedLocation = $scope.filter.selectedLocation = filtersResult.data.filters.selectedLocation;
                       $scope.listIsLoading = false;
                       if (callback) {
                           callback();
                       }
                   } else {
                       transportationService.getTransportationFilters({ urlPrefix: $scope.$parent.getWebUrl(), token: jwtService.getPrincipalToken() }, function (result) {
                           if (result.success) {
                               $.each(result.data, function (key, value) {
                                   if (key.toLowerCase().indexOf("location") >= 0) {
                                       $scope.locations = value;
                                   } else if (key.toLowerCase().indexOf("pricerangefilters") >= 0) {
                                       $scope.priceRanges = value;
                                   } else if (key.toLowerCase().indexOf("marketingtags") >= 0) {
                                       $scope.categories = value;
                                   }
                               });
                           } else {
                               console.log(result.error);
                           }

                           $scope.listIsLoading = false;

                           if (callback) {
                               callback();
                           }
                       });
                   }
               });
           };
           $scope.init = function () {
               $scope.listIsLoading = false;
               $scope.geographyCode = jwtService.getGeography();
               $scope.getTransportationFilters($scope.getTransportations);
               jwtService.setProductCategory("Transportation");

               if (!$scope.mainSectionId) {
                   window.location.href = utilsFactory.addPersistentQueryStringsParams("/");
                   return;
               }
           };

           if ($scope.$parent.hasMainSections()) {
               $scope.listIsLoading = true;
               var initialized = false;

               $scope.$watch(function () {
                   return taskFactory.filtersTask;
               },
                   function (val) {
                       if (!val || !val.name || initialized) return;
                       initialized = true;

                       $timeout(function () {
                           $scope.listIsLoading = false;
                           $scope.init();
                       });
                   }, true);
               //$scope.$on("mainSectionReady", function (event, args) {
               //    $scope.listIsLoading = false;
               //    $scope.init();
               //});
           } else {
               var t = jwtService.getPrincipalToken();
               if (t && t.length > 0) {
                   $scope.init();
               } else {
                   $scope.listIsLoading = true;
                   $scope.$on("getPrincipalToken", function (event, args) {
                       $scope.listIsLoading = false;
                       $scope.init();
                   });
               }
           }

           $scope.$on("geographyCodeChanged", function (event, args) {
               jwtService.clearStorage();
               $scope.init();
               $scope.geographyCode = jwtService.getGeography();
           });


           $scope.selectCategory = function (category) {
               $scope.filter.selectedCategory = category;
           };
           $scope.selectLocation = function (location) {
               $scope.filter.selectedLocation = location;
           };
           $scope.selectPriceRange = function (priceRange) {
               $scope.filter.selectedPriceRange = priceRange;
           };

           $scope.selectTransportation = function (product) {
               if (localStorageService.isSupported) {
                   return localStorageService.set("prevTransportation", product);
               }
           };

           $scope.order = function (predicate) {
               $scope.orderBy.reverse = ($scope.orderBy.predicate === predicate) ? !$scope.orderBy.reverse : false;
               $scope.orderBy.predicate = predicate;

               transportationService.persistTransportationsFilters({
                   transportations: $scope.transportations,
                   filters: $scope.filter,
                   locations: $scope.locations,
                   categories: $scope.categories,
                   priceRanges: $scope.priceRanges,
                   orderBy: $scope.orderBy
               }, function (result) {
                   //do nothing
               });

               //close the sort panel
               setTimeout(function () {
                   $($element).find(".filter-toggle:eq(1)").click();
               }, 300);
           };
       }
    ]);
})(jQuery);;
(function ($) {
    "use strict";

    angular.module("app").controller("transportationSelectTicketCtrl", [
      "utilsFactory", "$scope", "$rootScope", "$state", "taskFactory", "transportationService", function (utilsFactory,$scope, $rootScope, $state, taskFactory, transportationService) {

          $scope.utils = utilsFactory;
          $scope.loadingTickets = true;

           $rootScope.$on("$stateChangeSuccess",
            function (event, toState, toParams, fromState, fromParams) {
                //if (toState.name === "select-transport-ticket") {
                //    $state.go("select-transport-ticket.book-adventure", {});
                //    return;
                //}
            });

           //if ($state.$current.name === "select-transport-ticket") {
           //    $state.go("select-transport-ticket.book-adventure", {});
           //}

           $scope.transportation = {};

           $scope.backButtonLabel = utilsFactory.getLabel("transportation.go-back");

        

           $scope.handleBack = function () {
               if ($scope.$parent) {
                   var cuurentStateName = $state.$current.name;
                   $scope.$parent.back(cuurentStateName);
               }
           };


           $scope.$watch(function () {
               return taskFactory.task;
           },
          function (val) {
              //if (val && val.name) {
             //     $scope.transportation = val.data;
              // }
              if (!val || !val.name) return;

              $scope.init();
          }, true);

           $scope.selectedTicketTypeName = $scope.$parent && $scope.$parent.wizardModel.ticketType ? $scope.$parent.wizardModel.ticketType.name : undefined;
           $scope.showNext = ($scope.selectedTicketTypeName || "").length;
           $scope.init = function () {
               transportationService.getSelectedTransportation(function (result) {
                   if (result.success && result.data) {
                       $scope.transportation = result.data;
                       setTimeout(function () {
                           jQuery(window).resize();
                       }, 0);
                   }
               });
           };
           //$scope.init();
           

       }
    ]);
})(jQuery);;
