/*!
 * Name    : Just Another Parallax [Jarallax]
 * Version : 1.8.0
 * Author  : _nK https://nkdev.info
 * GitHub  : https://github.com/nk-o/jarallax
 */
(function (window) {
    'use strict';

    // Adapted from https://gist.github.com/paulirish/1579671
    if(!Date.now) {
        Date.now = function () { return new Date().getTime(); };
    }
    if(!window.requestAnimationFrame) {
        (function () {

            var vendors = ['webkit', 'moz'];
            for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) {
                var vp = vendors[i];
                window.requestAnimationFrame = window[vp+'RequestAnimationFrame'];
                window.cancelAnimationFrame = window[vp+'CancelAnimationFrame']
                                           || window[vp+'CancelRequestAnimationFrame'];
            }
            if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) // iOS6 is buggy
                || !window.requestAnimationFrame || !window.cancelAnimationFrame) {
                var lastTime = 0;
                window.requestAnimationFrame = function (callback) {
                    var now = Date.now();
                    var nextTime = Math.max(lastTime + 16, now);
                    return setTimeout(function () { callback(lastTime = nextTime); },
                                      nextTime - now);
                };
                window.cancelAnimationFrame = clearTimeout;
            }
        }());
    }

    // test if css property supported by browser
    // like "transform"
    var tempDiv = document.createElement('div');
    function isPropertySupported (property) {
        var prefixes = ['O','Moz','ms','Ms','Webkit'];
        var i = prefixes.length;
        if (tempDiv.style[property] !== undefined) {
            return true;
        }
        property = property.charAt(0).toUpperCase() + property.substr(1);
        while (--i > -1 && tempDiv.style[prefixes[i] + property] === undefined) { }
        return i >= 0;
    }

    var supportTransform = isPropertySupported('transform');
    var supportTransform3D = isPropertySupported('perspective');

    var ua = navigator.userAgent;
    var isAndroid = ua.toLowerCase().indexOf('android') > -1;
    var isIOs = /iPad|iPhone|iPod/.test(ua) && !window.MSStream;
    var isFirefox = ua.toLowerCase().indexOf('firefox') > -1;
    var isIE = ua.indexOf('MSIE ') > -1    // IE 10 or older
            || ua.indexOf('Trident/') > -1 // IE 11
            || ua.indexOf('Edge/') > -1;   // Edge
    var isIElt10 = document.all && !window.atob; // IE 9 or older

    var wndW;
    var wndH;
    function updateWndVars () {
        wndW = window.innerWidth || document.documentElement.clientWidth;
        wndH = window.innerHeight || document.documentElement.clientHeight;
    }
    updateWndVars();

    // list with all jarallax instances
    // need to render all in one scroll/resize event
    var jarallaxList = [];

    // Jarallax instance
    var Jarallax = (function () {
        var instanceID = 0;

        function Jarallax_inner (item, userOptions) {
            var _this = this,
                dataOptions;

            _this.$item      = item;

            _this.defaults   = {
                type              : 'scroll', // type of parallax: scroll, scale, opacity, scale-opacity, scroll-opacity
                speed             : 0.5, // supported value from -1 to 2
                imgSrc            : null,
                imgWidth          : null,
                imgHeight         : null,
                elementInViewport : null,
                zIndex            : -100,
                noAndroid         : false,
                noIos             : true,

                // events
                onScroll          : null, // function(calculations) {}
                onInit            : null, // function() {}
                onDestroy         : null, // function() {}
                onCoverImage      : null  // function() {}
            };
            dataOptions      = JSON.parse(_this.$item.getAttribute('data-jarallax') || '{}');
            _this.options    = _this.extend({}, _this.defaults, dataOptions, userOptions);

            // stop init if android or ios
            if(!supportTransform || isAndroid && _this.options.noAndroid || isIOs && _this.options.noIos) {
                return;
            }

            // fix speed option [-1.0, 2.0]
            _this.options.speed = Math.min(2, Math.max(-1, parseFloat(_this.options.speed)));

            // custom element to check if parallax in viewport
            var elementInVP = _this.options.elementInViewport;
            // get first item from array
            if(elementInVP && typeof elementInVP === 'object' && typeof elementInVP.length !== 'undefined') {
                elementInVP = elementInVP[0];
            }
            // check if dom element
            if(!elementInVP instanceof Element) {
                elementInVP = null;
            }
            _this.options.elementInViewport = elementInVP;

            _this.instanceID = instanceID++;

            _this.image      = {
                src        : _this.options.imgSrc || null,
                $container : null,
                $item      : null,
                width      : _this.options.imgWidth || null,
                height     : _this.options.imgHeight || null,
                // fix for some devices
                // use <img> instead of background image - more smoothly
                useImgTag  : isIOs || isAndroid || isIE,

                // position absolute is needed on IE9 and FireFox because fixed position have glitches
                position   : !supportTransform3D || isFirefox ? 'absolute' : 'fixed'
            };

            if(_this.initImg()) {
                _this.init();
            }
        }

        return Jarallax_inner;
    }());

    // add styles to element
    Jarallax.prototype.css = function (el, styles) {
        if(typeof styles === 'string') {
            if(window.getComputedStyle) {
                return window.getComputedStyle(el).getPropertyValue(styles);
            }
            return el.style[styles];
        }

        // add transform property with vendor prefixes
        if(styles.transform) {
            if (supportTransform3D) {
                styles.transform += ' translateZ(0)';
            }
            styles.WebkitTransform = styles.MozTransform = styles.msTransform = styles.OTransform = styles.transform;
        }

        for(var k in styles) {
            el.style[k] = styles[k];
        }
        return el;
    };
    // Extend like jQuery.extend
    Jarallax.prototype.extend = function (out) {
        out = out || {};
        for (var i = 1; i < arguments.length; i++) {
            if (!arguments[i]) {
                continue;
            }
            for (var key in arguments[i]) {
                if (arguments[i].hasOwnProperty(key)) {
                    out[key] = arguments[i][key];
                }
            }
        }
        return out;
    };

    // Jarallax functions
    Jarallax.prototype.initImg = function () {
        var _this = this;

        // get image src
        if(_this.image.src === null) {
            _this.image.src = _this.css(_this.$item, 'background-image').replace(/^url\(['"]?/g,'').replace(/['"]?\)$/g,'');
        }
        return !(!_this.image.src || _this.image.src === 'none');
    };

    Jarallax.prototype.init = function () {
        var _this = this,
            containerStyles = {
                position         : 'absolute',
                top              : 0,
                left             : 0,
                width            : '100%',
                height           : '100%',
                overflow         : 'hidden',
                pointerEvents    : 'none'
            },
            imageStyles = {};

        // save default user styles
        _this.$item.setAttribute('data-jarallax-original-styles', _this.$item.getAttribute('style'));

        // set relative position and z-index to the parent
        if (_this.css(_this.$item, 'position') === 'static') {
            _this.css(_this.$item, {
                position: 'relative'
            });
        }
        if (_this.css(_this.$item, 'z-index') === 'auto') {
            _this.css(_this.$item, {
                zIndex: 0
            });
        }

        // container for parallax image
        _this.image.$container = document.createElement('div');
        _this.css(_this.image.$container, containerStyles);
        _this.css(_this.image.$container, {
            visibility : 'hidden',
            'z-index'  : _this.options.zIndex
        });
        _this.image.$container.setAttribute('id', 'jarallax-container-' + _this.instanceID);
        _this.$item.appendChild(_this.image.$container);

        // use img tag
        if(_this.image.useImgTag) {
            _this.image.$item = document.createElement('img');
            _this.image.$item.setAttribute('src', _this.image.src);
            imageStyles = _this.extend({
                'max-width' : 'none'
            }, containerStyles, imageStyles);
        }

        // use div with background image
        else {
            _this.image.$item = document.createElement('div');
            imageStyles = _this.extend({
                'background-position' : '50% 50%',
                'background-size'     : '100% auto',
                'background-repeat'   : 'no-repeat no-repeat',
                'background-image'    : 'url("' + _this.image.src + '")'
            }, containerStyles, imageStyles);
        }

        // check if one of parents have transform style (without this check, scroll transform will be inverted)
        // discussion - https://github.com/nk-o/jarallax/issues/9
        var parentWithTransform = 0;
        var $itemParents = _this.$item;
        while ($itemParents !== null && $itemParents !== document && parentWithTransform === 0) {
            var parent_transform = _this.css($itemParents, '-webkit-transform') || _this.css($itemParents, '-moz-transform') || _this.css($itemParents, 'transform');
            if(parent_transform && parent_transform !== 'none') {
                parentWithTransform = 1;

                // add transform on parallax container if there is parent with transform
                _this.css(_this.image.$container, {
                    transform: 'translateX(0) translateY(0)'
                });
            }
            $itemParents = $itemParents.parentNode;
        }

        // absolute position if one of parents have transformations or parallax without scroll
        if (parentWithTransform || _this.options.type === 'opacity'|| _this.options.type === 'scale' || _this.options.type === 'scale-opacity') {
            _this.image.position = 'absolute';
        }

        // add position to parallax block
        imageStyles.position = _this.image.position;

        // parallax image
        _this.css(_this.image.$item, imageStyles);
        _this.image.$container.appendChild(_this.image.$item);

        // cover image if width and height is ready
        function initAfterReady () {
            _this.coverImage();
            _this.clipContainer();
            _this.onScroll(true);

            // call onInit event
            if(_this.options.onInit) {
                _this.options.onInit.call(_this);
            }

            // timeout to fix IE blinking
            setTimeout(function () {
                if(_this.$item) {
                    // remove default user background
                    _this.css(_this.$item, {
                        'background-image'      : 'none',
                        'background-attachment' : 'scroll',
                        'background-size'       : 'auto'
                    });
                }
            }, 0);
        }

        if(_this.image.width && _this.image.height) {
            // init if width and height already exists
            initAfterReady();
        } else {
            // load image and get width and height
            _this.getImageSize(_this.image.src, function (width, height) {
                _this.image.width  = width;
                _this.image.height = height;
                initAfterReady();
            });
        }

        jarallaxList.push(_this);
    };

    Jarallax.prototype.destroy = function () {
        var _this = this;

        // remove from instances list
        for(var k = 0, len = jarallaxList.length; k < len; k++) {
            if(jarallaxList[k].instanceID === _this.instanceID) {
                jarallaxList.splice(k, 1);
                break;
            }
        }

        // return styles on container as before jarallax init
        var originalStylesTag = _this.$item.getAttribute('data-jarallax-original-styles');
        _this.$item.removeAttribute('data-jarallax-original-styles');
        // null occurs if there is no style tag before jarallax init
        if(originalStylesTag === 'null') {
            _this.$item.removeAttribute('style');
        } else {
            _this.$item.setAttribute('style', originalStylesTag);
        }

        // remove additional dom elements
        if(_this.$clipStyles) {
            _this.$clipStyles.parentNode.removeChild(_this.$clipStyles);
        }
        _this.image.$container.parentNode.removeChild(_this.image.$container);

        // call onDestroy event
        if(_this.options.onDestroy) {
            _this.options.onDestroy.call(_this);
        }

        // delete jarallax from item
        delete _this.$item.jarallax;

        // delete all variables
        for(var n in _this) {
            delete _this[n];
        }
    };

    Jarallax.prototype.getImageSize = function (src, callback) {
        if(!src || !callback) {
            return;
        }

        var tempImg = new Image();
        tempImg.onload = function () {
            callback(tempImg.width, tempImg.height);
        };
        tempImg.src = src;
    };

    // it will remove some image overlapping
    // overlapping occur due to an image position fixed inside absolute position element (webkit based browsers works without any fix)
    Jarallax.prototype.clipContainer = function () {
        // clip is not working properly on real IE9 and less
        if(isIElt10) {
            return;
        }

        var _this  = this,
            rect   = _this.image.$container.getBoundingClientRect(),
            width  = rect.width,
            height = rect.height;

        if(!_this.$clipStyles) {
            _this.$clipStyles = document.createElement('style');
            _this.$clipStyles.setAttribute('type', 'text/css');
            _this.$clipStyles.setAttribute('id', '#jarallax-clip-' + _this.instanceID);
            var head = document.head || document.getElementsByTagName('head')[0];
            head.appendChild(_this.$clipStyles);
        }

        var styles = [
            '#jarallax-container-' + _this.instanceID + ' {',
            '   clip: rect(0 ' + width + 'px ' + height + 'px 0);',
            '   clip: rect(0, ' + width + 'px, ' + height + 'px, 0);',
            '}'
        ].join('\n');

        // add clip styles inline (this method need for support IE8 and less browsers)
        if (_this.$clipStyles.styleSheet){
            _this.$clipStyles.styleSheet.cssText = styles;
        } else {
            _this.$clipStyles.innerHTML = styles;
        }
    };

    Jarallax.prototype.coverImage = function () {
        var _this = this;

        if(!_this.image.width || !_this.image.height) {
            return;
        }

        var rect       = _this.image.$container.getBoundingClientRect(),
            contW      = rect.width,
            contH      = rect.height,
            contL      = rect.left,
            imgW       = _this.image.width,
            imgH       = _this.image.height,
            speed      = _this.options.speed,
            isScroll   = _this.options.type === 'scroll' || _this.options.type === 'scroll-opacity',
            scrollDist = 0,
            resultW    = 0,
            resultH    = contH,
            resultML   = 0,
            resultMT   = 0;

        // scroll parallax
        if(isScroll) {
            // scroll distance and height for image
            if (speed < 0) {
                scrollDist = speed * Math.max(contH, wndH);
            } else {
                scrollDist = speed * (contH + wndH);
            }

            // size for scroll parallax
            if (speed > 1) {
                resultH = Math.abs(scrollDist - wndH);
            } else if (speed < 0) {
                resultH = scrollDist / speed + Math.abs(scrollDist);
            }  else {
                resultH += Math.abs(wndH - contH) * (1 - speed);
            }

            scrollDist /= 2;
        }

        // calculate width relative to height and image size
        resultW = resultH * imgW / imgH;
        if(resultW < contW) {
            resultW = contW;
            resultH = resultW * imgH / imgW;
        }

        // center parallax image
        if(isScroll) {
            resultML = contL + (contW - resultW) / 2;
            resultMT = (wndH - resultH) / 2;
        } else {
            resultML = (contW - resultW) / 2;
            resultMT = (contH - resultH) / 2;
        }

        // fix if parallax block in absolute position
        if(_this.image.position === 'absolute') {
            resultML -= contL;
        }

        // store scroll distance
        _this.parallaxScrollDistance = scrollDist;

        // apply result to item
        _this.css(_this.image.$item, {
            width: resultW + 'px',
            height: resultH + 'px',
            marginLeft: resultML + 'px',
            marginTop: resultMT + 'px'
        });

        // call onCoverImage event
        if(_this.options.onCoverImage) {
            _this.options.onCoverImage.call(_this);
        }
    };

    Jarallax.prototype.isVisible = function () {
        return this.isElementInViewport || false;
    };

    Jarallax.prototype.onScroll = function (force) {
        var _this = this;

        if(!_this.image.width || !_this.image.height) {
            return;
        }

        var rect   = _this.$item.getBoundingClientRect(),
            contT  = rect.top,
            contH  = rect.height,
            styles = {
                visibility         : 'visible',
                backgroundPosition : '50% 50%'
            };

        // check if in viewport
        var viewportRect = rect;
        if(_this.options.elementInViewport) {
            viewportRect = _this.options.elementInViewport.getBoundingClientRect();
        }
        _this.isElementInViewport =
            viewportRect.bottom >= 0 &&
            viewportRect.right >= 0 &&
            viewportRect.top <= wndH &&
            viewportRect.left <= wndW;

        // stop calculations if item is not in viewport
        if (force ? false : !_this.isElementInViewport) {
            return;
        }

        // calculate parallax helping variables
        var beforeTop = Math.max(0, contT),
            beforeTopEnd = Math.max(0, contH + contT),
            afterTop = Math.max(0, -contT),
            beforeBottom = Math.max(0, contT + contH - wndH),
            beforeBottomEnd = Math.max(0, contH - (contT + contH - wndH)),
            afterBottom = Math.max(0, -contT + wndH - contH),
            fromViewportCenter = 1 - 2 * (wndH - contT) / (wndH + contH);

        // calculate on how percent of section is visible
        var visiblePercent = 1;
        if(contH < wndH) {
            visiblePercent = 1 - (afterTop || beforeBottom) / contH;
        } else {
            if(beforeTopEnd <= wndH) {
                visiblePercent = beforeTopEnd / wndH;
            } else if (beforeBottomEnd <= wndH) {
                visiblePercent = beforeBottomEnd / wndH;
            }
        }

        // opacity
        if(_this.options.type === 'opacity' || _this.options.type === 'scale-opacity' || _this.options.type === 'scroll-opacity') {
            styles.transform = ''; // empty to add translateZ(0) where it is possible
            styles.opacity = visiblePercent;
        }

        // scale
        if(_this.options.type === 'scale' || _this.options.type === 'scale-opacity') {
            var scale = 1;
            if(_this.options.speed < 0) {
                scale -= _this.options.speed * visiblePercent;
            } else {
                scale += _this.options.speed * (1 - visiblePercent);
            }
            styles.transform = 'scale(' + scale + ')';
        }

        // scroll
        if(_this.options.type === 'scroll' || _this.options.type === 'scroll-opacity') {
            var positionY = _this.parallaxScrollDistance * fromViewportCenter;

            // fix if parallax block in absolute position
            if(_this.image.position === 'absolute') {
                positionY -= contT;
            }

            styles.transform = 'translateY(' + positionY + 'px)';
        }

        _this.css(_this.image.$item, styles);

        // call onScroll event
        if(_this.options.onScroll) {
            _this.options.onScroll.call(_this, {
                section: rect,

                beforeTop: beforeTop,
                beforeTopEnd: beforeTopEnd,
                afterTop: afterTop,
                beforeBottom: beforeBottom,
                beforeBottomEnd: beforeBottomEnd,
                afterBottom: afterBottom,

                visiblePercent: visiblePercent,
                fromViewportCenter: fromViewportCenter
            });
        }
    };


    // init events
    function addEventListener (el, eventName, handler) {
        if (el.addEventListener) {
            el.addEventListener(eventName, handler);
        } else {
            el.attachEvent('on' + eventName, function (){
                handler.call(el);
            });
        }
    }

    function update (e) {
        window.requestAnimationFrame(function () {
            if(e.type !== 'scroll') {
                updateWndVars();
            }
            for(var k = 0, len = jarallaxList.length; k < len; k++) {
                // cover image and clip needed only when parallax container was changed
                if(e.type !== 'scroll') {
                    jarallaxList[k].coverImage();
                    jarallaxList[k].clipContainer();
                }
                jarallaxList[k].onScroll();
            }
        });
    }
    addEventListener(window, 'scroll', update);
    addEventListener(window, 'resize', update);
    addEventListener(window, 'orientationchange', update);
    addEventListener(window, 'load', update);


    // global definition
    var plugin = function (items) {
        // check for dom element
        // thanks: http://stackoverflow.com/questions/384286/javascript-isdom-how-do-you-check-if-a-javascript-object-is-a-dom-object
        if(typeof HTMLElement === "object" ? items instanceof HTMLElement : items && typeof items === "object" && items !== null && items.nodeType === 1 && typeof items.nodeName==="string") {
            items = [items];
        }

        var options = arguments[1],
            args = Array.prototype.slice.call(arguments, 2),
            len = items.length,
            k = 0,
            ret;

        for (k; k < len; k++) {
            if (typeof options === 'object' || typeof options === 'undefined') {
                if(!items[k].jarallax) {
                    items[k].jarallax = new Jarallax(items[k], options);
                }
            }
            else if(items[k].jarallax) {
                ret = items[k].jarallax[options].apply(items[k].jarallax, args);
            }
            if (typeof ret !== 'undefined') {
                return ret;
            }
        }

        return items;
    };
    plugin.constructor = Jarallax;

    // no conflict
    var oldPlugin = window.jarallax;
    window.jarallax = plugin;
    window.jarallax.noConflict = function () {
        window.jarallax = oldPlugin;
        return this;
    };

    // jQuery support
    if(typeof jQuery !== 'undefined') {
        var jQueryPlugin = function () {
            var args = arguments || [];
            Array.prototype.unshift.call(args, this);
            var res = plugin.apply(window, args);
            return typeof res !== 'object' ? res : this;
        };
        jQueryPlugin.constructor = Jarallax;

        // no conflict
        var oldJqPlugin = jQuery.fn.jarallax;
        jQuery.fn.jarallax = jQueryPlugin;
        jQuery.fn.jarallax.noConflict = function () {
            jQuery.fn.jarallax = oldJqPlugin;
            return this;
        };
    }

    // data-jarallax initialization
    addEventListener(window, 'DOMContentLoaded', function () {
        plugin(document.querySelectorAll('[data-jarallax], [data-jarallax-video]'));
    });
}(window));
