/*jslint browser:true */
/*global jQuery*/

(function ($, window, undefined) {
    'use strict';

    var pluginName = 'stickySidebar',
        document = window.document,
        defaults = {
            sidebar: '.sidebar',
            content: '.content',
            tolerance: -25
        },
        clearPosition = {
            position: '',
            top: ''
        };

    function Plugin(element, options) {
        this.options = $.extend({}, defaults, options);

        this.defaults = defaults;
        this.name = pluginName;

        this.root = $(element);

        this.init();
    }

    Plugin.prototype.init = function () {
        var self = this;

        this.sidebar = this.root.find(this.options.sidebar);
        this.content = this.root.find(this.options.content);
        this.lastScrollTop = 0;

        if (this.canBeSticky() === true) {
            $(window).bind('scroll.sticky_sidebar', function () {
                self.setScrollDirection()
                    .setBoundaries()
                    .positionSidebar();
            });
        }
    };

    Plugin.prototype.canBeSticky = function () {
        return this.sidebar.height() < this.content.height() &&
               this.sidebar.height() > $(window).height();
    };

    Plugin.prototype.setBoundaries = function () {
        var contentTop = this.content.offset().top,
            contentHeight = this.content.outerHeight();
        this.boundaries = {
            contentTop: contentTop,
            contentBottom: contentTop + contentHeight,
            contentHeight: contentHeight,
            sidebarHeight: this.sidebar.outerHeight(),
            windowHeight: $(window).height()
        };
        return this;
    };

    Plugin.prototype.positionSidebar = function () {
        if (this.lastScrollTop > this.boundaries.contentTop &&
                this.lastScrollTop < this.boundaries.contentBottom) {
            this[this.scrollDirection === 'DOWN' ? 'scrollDown' : 'scrollUp']();
        } else if (this.lastScrollTop < this.boundaries.contentTop) {
            this.sidebar.css('top', '').removeClass('top-fixed');
        }
        return this;
    };

    Plugin.prototype.scrollDown = function () {
        var windowScroll = this.lastScrollTop + this.boundaries.windowHeight,
            sidebarOffsetTop;
        if (this.sidebar.hasClass('scrolling-up')) {
            this.sidebar.removeClass('scrolling-up')
                .addClass('scrolling-down');
        } else if (this.sidebar.hasClass('top-fixed')) {
            sidebarOffsetTop = this.sidebar.offset().top - this.boundaries.contentTop;
            this.sidebar.removeClass('top-fixed')
                .css({
                    position: 'absolute',
                    top: sidebarOffsetTop
                })
                .addClass('scrolling-down');
        }
        if (this.sidebar.hasClass('scrolling-down')) {
            if (windowScroll > this.sidebar.offset().top + this.boundaries.sidebarHeight) {
                this.sidebar.css(clearPosition)
                            .addClass('bottom-fixed')
                            .removeClass('scrolling-down');
            }
        } else {
            if (windowScroll > this.boundaries.contentBottom) {
                this.sidebar.removeClass('bottom-fixed').css({
                    position: 'absolute',
                    top: this.boundaries.contentHeight - this.boundaries.sidebarHeight
                });
            } else if (windowScroll + this.options.tolerance >
                       this.boundaries.sidebarHeight + this.boundaries.contentTop) {
                this.sidebar.css(clearPosition)
                            .removeClass('top-fixed')
                            .addClass('bottom-fixed');
            }
        }
    };

    Plugin.prototype.scrollUp = function () {
        if (this.sidebar.hasClass('scrolling-down')) {
            this.sidebar.removeClass('scrolling-down')
                        .addClass('scrolling-up');
        } else if (this.sidebar.hasClass('bottom-fixed')) {
            this.sidebar.css({
                position: 'absolute',
                top: this.sidebar.offset().top - this.boundaries.contentTop
            }).removeClass('bottom-fixed').addClass('scrolling-up');
        }
        if (this.sidebar.hasClass('scrolling-up')) {
            if (this.lastScrollTop < this.sidebar.offset().top) {
                this.sidebar.css(clearPosition)
                            .addClass('top-fixed')
                            .removeClass('scrolling-up');
            }
        } else {
            if (this.lastScrollTop < this.boundaries.contentTop) {
                this.sidebar.css('position', '').removeClass('top-fixed');
            } else if (this.lastScrollTop - this.options.tolerance <
                       this.boundaries.contentBottom - this.boundaries.sidebarHeight) {
                this.sidebar.css(clearPosition)
                            .removeClass('bottom-fixed')
                            .addClass('top-fixed');
            }
        }
    };

    Plugin.prototype.setScrollDirection = function () {
        var scrollTop = $(window).scrollTop();
        this.scrollDirection = (scrollTop > this.lastScrollTop ? 'DOWN' : 'UP');
        this.lastScrollTop = scrollTop;
        return this;
    };

    $.fn[pluginName] = function (options) {
        return this.each(function () {
            if (!$.data(this, 'plugin_' + pluginName)) {
                $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
            }
        });
    };

}(jQuery, window));
