
/**
 * animOnScroll.js v1.0.0
 * http://www.codrops.com
 *
 * Licensed under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 * 
 * Copyright 2013, Codrops
 * http://www.codrops.com
 */
; (function (window) {

    'use strict';

    var docElem = window.document.documentElement;

    function getViewportH() {
        var client = docElem['clientHeight'],
			inner = window['innerHeight'];

        if (client < inner)
            return inner;
        else
            return client;
    }

    function scrollY() {
        return window.pageYOffset || docElem.scrollTop;
    }

    // http://stackoverflow.com/19451/a/5598797/989439
    function getOffset(el) {
        var offsetTop = 0, offsetLeft = 0;
        do {
            if (!isNaN(el.offsetTop)) {
                offsetTop += el.offsetTop;
            }
            if (!isNaN(el.offsetLeft)) {
                offsetLeft += el.offsetLeft;
            }
        } while (el = el.offsetParent)

        return {
            top: offsetTop,
            left: offsetLeft
        }
    }

    function inViewport(el, h) {
        var elH = el.offsetHeight,
			scrolled = scrollY(),
			viewed = scrolled + getViewportH(),
			elTop = getOffset(el).top,
			elBottom = elTop + elH,
			// if 0, the element is considered in the viewport as soon as it enters.
			// if 1, the element is considered in the viewport only when it's fully inside
			// value in percentage (1 >= h >= 0)
			h = h || 0;

        return (elTop + elH * h) <= viewed && (elBottom - elH * h) >= scrolled;
    }

    function extend(a, b) {
        for (var key in b) {
            if (b.hasOwnProperty(key)) {
                a[key] = b[key];
            }
        }
        return a;
    }

    function AnimOnScroll(el, options) {
        this.el = el;
        this.options = extend(this.defaults, options);
        this._init();
    }

    AnimOnScroll.prototype = {
        defaults: {
            // Minimum and a maximum duration of the animation (random value is chosen)
            minDuration: 0,
            maxDuration: 0,
            // The viewportFactor defines how much of the appearing item has to be visible in order to trigger the animation
            // if we'd use a value of 0, this would mean that it would add the animation class as soon as the item is in the viewport. 
            // If we were to use the value of 1, the animation would only be triggered when we see all of the item in the viewport (100% of it)
            viewportFactor: 0
        },
        _init: function () {
            this.items = Array.prototype.slice.call(document.querySelectorAll('#' + this.el.id + ' > li'));
            this.itemsCount = this.items.length;
            this.itemsRenderedCount = 0;
            this.didScroll = false;

            var self = this;

            imagesLoaded(this.el, function () {

                // initialize masonry
                new Masonry(self.el, {
                    itemSelector: 'li',
                    transitionDuration: 0
                });

                if (Modernizr.cssanimations) {
                    // the items already shown...
                    self.items.forEach(function (el, i) {
                        if (inViewport(el)) {
                            self._checkTotalRendered();
                            classie.add(el, 'shown');
                        }
                    });

                    // animate on scroll the items inside the viewport
                    window.addEventListener('scroll', function () {
                        self._onScrollFn();
                    }, false);
                    window.addEventListener('resize', function () {
                        self._resizeHandler();
                    }, false);
                }

            });
        },
        _onScrollFn: function () {
            var self = this;
            if (!this.didScroll) {
                this.didScroll = true;
                setTimeout(function () { self._scrollPage(); }, 60);
            }
        },
        _scrollPage: function () {
            var self = this;
            this.items.forEach(function (el, i) {
                if (!classie.has(el, 'shown') && !classie.has(el, 'animate') && inViewport(el, self.options.viewportFactor)) {
                    setTimeout(function () {
                        var perspY = scrollY() + getViewportH() / 2;
                        self.el.style.WebkitPerspectiveOrigin = '50% ' + perspY + 'px';
                        self.el.style.MozPerspectiveOrigin = '50% ' + perspY + 'px';
                        self.el.style.perspectiveOrigin = '50% ' + perspY + 'px';

                        self._checkTotalRendered();

                        if (self.options.minDuration && self.options.maxDuration) {
                            var randDuration = (Math.random() * (self.options.maxDuration - self.options.minDuration) + self.options.minDuration) + 's';
                            el.style.WebkitAnimationDuration = randDuration;
                            el.style.MozAnimationDuration = randDuration;
                            el.style.animationDuration = randDuration;
                        }

                        classie.add(el, 'animate');
                    }, 25);
                }
            });
            this.didScroll = false;
        },
        _resizeHandler: function () {
            var self = this;
            function delayed() {
                self._scrollPage();
                self.resizeTimeout = null;
            }
            if (this.resizeTimeout) {
                clearTimeout(this.resizeTimeout);
            }
            this.resizeTimeout = setTimeout(delayed, 1000);
        },
        _checkTotalRendered: function () {
            ++this.itemsRenderedCount;
            if (this.itemsRenderedCount === this.itemsCount) {
                window.removeEventListener('scroll', this._onScrollFn);
            }
        }
    }

    // add to global namespace
    window.AnimOnScroll = AnimOnScroll;

})(window);