/**

* Extend jquery with a scrollspy plugin.
* This watches the window scroll and fires events when elements are scrolled into viewport.
*
* throttle() and getTime() taken from Underscore.js
* https://github.com/jashkenas/underscore
*
* @author Copyright 2013 John Smart
* @license https://raw.github.com/thesmart/jquery-scrollspy/master/LICENSE
* @see https://github.com/thesmart
* @version 0.1.2
*/

(function($) {

     var jWindow = $(window);
     var elements = [];
     var elementsInView = [];
     var isSpying = false;
     var ticks = 0;
     var unique_id = 1;
     var offset = {
             top : 0,
             right : 0,
             bottom : 0,
             left : 0,
     }

     /**
      * Find elements that are within the boundary
      * @param {number} top
      * @param {number} right
      * @param {number} bottom
      * @param {number} left
      * @return {jQuery}             A collection of elements
      */
     function findElements(top, right, bottom, left) {
             var hits = $();
             $.each(elements, function(i, element) {
                     if (element.height() > 0) {
                             var elTop = element.offset().top,
                                     elLeft = element.offset().left,
                                     elRight = elLeft + element.width(),
                                     elBottom = elTop + element.height();

                             var isIntersect = !(elLeft > right ||
                                     elRight < left ||
                                     elTop > bottom ||
                                     elBottom < top);

                             if (isIntersect) {
                                     hits.push(element);
                             }
                     }
             });

             return hits;
     }

     /**
      * Called when the user scrolls the window
      */
     function onScroll(scrollOffset) {
             // unique tick id
             ++ticks;

             // viewport rectangle
             var top = jWindow.scrollTop(),
                     left = jWindow.scrollLeft(),
                     right = left + jWindow.width(),
                     bottom = top + jWindow.height();

             // determine which elements are in view
             var intersections = findElements(top+offset.top + scrollOffset || 200, right+offset.right, bottom+offset.bottom, left+offset.left);
             $.each(intersections, function(i, element) {

                     var lastTick = element.data('scrollSpy:ticks');
                     if (typeof lastTick != 'number') {
                             // entered into view
                             element.triggerHandler('scrollSpy:enter');
                     }

                     // update tick id
                     element.data('scrollSpy:ticks', ticks);
             });

             // determine which elements are no longer in view
             $.each(elementsInView, function(i, element) {
                     var lastTick = element.data('scrollSpy:ticks');
                     if (typeof lastTick == 'number' && lastTick !== ticks) {
                             // exited from view
                             element.triggerHandler('scrollSpy:exit');
                             element.data('scrollSpy:ticks', null);
                     }
             });

             // remember elements in view for next tick
             elementsInView = intersections;
     }

     /**
      * Called when window is resized
     */
     function onWinSize() {
             jWindow.trigger('scrollSpy:winSize');
     }

     /**
      * Get time in ms
* @license https://raw.github.com/jashkenas/underscore/master/LICENSE
      * @type {function}
      * @return {number}
      */
     var getTime = (Date.now || function () {
             return new Date().getTime();
     });

     /**
      * Returns a function, that, when invoked, will only be triggered at most once
      * during a given window of time. Normally, the throttled function will run
      * as much as it can, without ever going more than once per `wait` duration;
      * but if you'd like to disable the execution on the leading edge, pass
      * `{leading: false}`. To disable execution on the trailing edge, ditto.
      * @license https://raw.github.com/jashkenas/underscore/master/LICENSE
      * @param {function} func
      * @param {number} wait
      * @param {Object=} options
      * @returns {Function}
      */
     function throttle(func, wait, options) {
             var context, args, result;
             var timeout = null;
             var previous = 0;
             options || (options = {});
             var later = function () {
                     previous = options.leading === false ? 0 : getTime();
                     timeout = null;
                     result = func.apply(context, args);
                     context = args = null;
             };
             return function () {
                     var now = getTime();
                     if (!previous && options.leading === false) previous = now;
                     var remaining = wait - (now - previous);
                     context = this;
                     args = arguments;
                     if (remaining <= 0) {
                             clearTimeout(timeout);
                             timeout = null;
                             previous = now;
                             result = func.apply(context, args);
                             context = args = null;
                     } else if (!timeout && options.trailing !== false) {
                             timeout = setTimeout(later, remaining);
                     }
                     return result;
             };
     };

     /**
      * Enables ScrollSpy using a selector
      * @param {jQuery|string} selector  The elements collection, or a selector
      * @param {Object=} options     Optional.
     throttle : number -> scrollspy throttling. Default: 100 ms
     offsetTop : number -> offset from top. Default: 0
     offsetRight : number -> offset from right. Default: 0
     offsetBottom : number -> offset from bottom. Default: 0
     offsetLeft : number -> offset from left. Default: 0
      * @returns {jQuery}
      */
     $.scrollSpy = function(selector, options) {
       var defaults = {
                     throttle: 100,
                     scrollOffset: 200 // offset - 200 allows elements near bottom of page to scroll
 };
 options = $.extend(defaults, options);

             var visible = [];
             selector = $(selector);
             selector.each(function(i, element) {
                     elements.push($(element));
                     $(element).data("scrollSpy:id", i);
                     // Smooth scroll to section
               $('a[href="#' + $(element).attr('id') + '"]').click(function(e) {
                 e.preventDefault();
                 var offset = $(Materialize.escapeHash(this.hash)).offset().top + 1;
             $('html, body').animate({ scrollTop: offset - options.scrollOffset }, {duration: 400, queue: false, easing: 'easeOutCubic'});
               });
             });

             offset.top = options.offsetTop || 0;
             offset.right = options.offsetRight || 0;
             offset.bottom = options.offsetBottom || 0;
             offset.left = options.offsetLeft || 0;

             var throttledScroll = throttle(function() {
                     onScroll(options.scrollOffset);
             }, options.throttle || 100);
             var readyScroll = function(){
                     $(document).ready(throttledScroll);
             };

             if (!isSpying) {
                     jWindow.on('scroll', readyScroll);
                     jWindow.on('resize', readyScroll);
                     isSpying = true;
             }

             // perform a scan once, after current execution context, and after dom is ready
             setTimeout(readyScroll, 0);

             selector.on('scrollSpy:enter', function() {
                     visible = $.grep(visible, function(value) {
           return value.height() != 0;
         });

                     var $this = $(this);

                     if (visible[0]) {
                             $('a[href="#' + visible[0].attr('id') + '"]').removeClass('active');
                             if ($this.data('scrollSpy:id') < visible[0].data('scrollSpy:id')) {
                                     visible.unshift($(this));
                             }
                             else {
                                     visible.push($(this));
                             }
                     }
                     else {
                             visible.push($(this));
                     }

                     $('a[href="#' + visible[0].attr('id') + '"]').addClass('active');
             });
             selector.on('scrollSpy:exit', function() {
                     visible = $.grep(visible, function(value) {
           return value.height() != 0;
         });

                     if (visible[0]) {
                             $('a[href="#' + visible[0].attr('id') + '"]').removeClass('active');
                             var $this = $(this);
                             visible = $.grep(visible, function(value) {
             return value.attr('id') != $this.attr('id');
           });
           if (visible[0]) { // Check if empty
                                     $('a[href="#' + visible[0].attr('id') + '"]').addClass('active');
           }
                     }
             });

             return selector;
     };

     /**
      * Listen for window resize events
      * @param {Object=} options                                             Optional. Set { throttle: number } to change throttling. Default: 100 ms
      * @returns {jQuery}            $(window)
      */
     $.winSizeSpy = function(options) {
             $.winSizeSpy = function() { return jWindow; }; // lock from multiple calls
             options = options || {
                     throttle: 100
             };
             return jWindow.on('resize', throttle(onWinSize, options.throttle || 100));
     };

     /**
      * Enables ScrollSpy on a collection of elements
      * e.g. $('.scrollSpy').scrollSpy()
      * @param {Object=} options     Optional.
                                                                                     throttle : number -> scrollspy throttling. Default: 100 ms
                                                                                     offsetTop : number -> offset from top. Default: 0
                                                                                     offsetRight : number -> offset from right. Default: 0
                                                                                     offsetBottom : number -> offset from bottom. Default: 0
                                                                                     offsetLeft : number -> offset from left. Default: 0
      * @returns {jQuery}
      */
     $.fn.scrollSpy = function(options) {
             return $.scrollSpy($(this), options);
     };

})(jQuery);