﻿(function ($) {

    $.fn.dragScroller = function (options) {

        var defaults = {

            containerSelector: '',
            maxOverScroll: 60

        };
        var options = $.extend(defaults, options);

        return this.each(function () {

            var $toDrag = $(this);
            var $container = $toDrag.parent();
            var $dragContainer = $(">.drag-container", $toDrag);
            var $scrollBarContainer = $(">.scroll-bar", $toDrag);

            var maxScroll = function () {

                return $container.height() - $dragContainer.height();

            };

            var positionElements = function (newPos, allowOverflow) {

                var contentHeight = ($dragContainer.length ? $dragContainer : $toDrag.css("height", $toDrag[0]._defaultHeight ? $toDrag[0]._defaultHeight : "")).height();

                if (newPos < maxScroll() - (allowOverflow ? 60 : 0))
                    newPos = maxScroll() - (allowOverflow ? 60 : 0);
                else if (newPos > 0 + (allowOverflow ? 60 : 0))
                    newPos = 0 + (allowOverflow ? 60 : 0);

                $dragContainer.stop(true).css("top", newPos);

                var newBarSpace = $scrollBarContainer.height() - $(".bar", $scrollBarContainer).height();
                var newBarPos = Math.round(newBarSpace * (newPos / maxScroll()));

                if (newBarPos < 0)
                    newBarPos = 0;
                else if (newBarPos > newBarSpace)
                    newBarPos = newBarSpace;

                var realBarHeight = Math.round($scrollBarContainer.height() * ($container.height() / contentHeight));

                if (allowOverflow && (newPos < maxScroll() || newPos > 0)) {

                    var diff = Math.abs(newPos < maxScroll() ? (newPos - maxScroll()) : newPos);
                    var newHeight = Math.round(((60 - diff) / 60) * (realBarHeight));

                    $(".bar", $scrollBarContainer).height(newHeight);

                } else {

                    $(".bar", $scrollBarContainer).height(realBarHeight);

                }

                if (newBarPos >= newBarSpace)
                    $(".bar", $scrollBarContainer).stop(true).css("top", "auto").css("bottom", 0);
                else
                    $(".bar", $scrollBarContainer).stop(true).css("bottom", "auto").css("top", newBarPos);

            };

            var sizeAndSetup = function () {

                var contentHeight = ($dragContainer.length ? $dragContainer : $toDrag.css("height", $toDrag[0]._defaultHeight ? $toDrag[0]._defaultHeight : "")).height();

                if (contentHeight > $container.height() - $toDrag.position().top) {

                    if (!$dragContainer.length) {

                        $toDrag.wrapInner("<div class='drag-container' />");
                        $dragContainer = $(">.drag-container", $toDrag);

                        $dragContainer.bind("mousewheel", function (evt, delta) {

                            evt.preventDefault();

                            positionElements($dragContainer.position().top + (delta * 60));

                        }).bind("dragstart", function (evt) {

                            $dragContainer[0]._startY = $dragContainer.position().top;

                        }).bind("dragmove", function (evt) {

                            positionElements($dragContainer[0]._startY + evt.drag.offsetY, true);

                        }).bind("dragend", function (evt) {

                            if ($dragContainer.position().top < maxScroll() || $dragContainer.position().top > 0) {

                                var css = {};

                                var newTop = $dragContainer.position().top < 0 ? maxScroll() : 0;
                                var topDiff = Math.abs(newTop - $dragContainer.position().top);

                                $dragContainer.stop(true).animate({

                                    top: newTop

                                }, {

                                    duration: topDiff / .2,
                                    easing: "easeOutQuad"

                                });

                                var realBarHeight = Math.round($scrollBarContainer.height() * ($container.height() / contentHeight));

                                $(".bar", $scrollBarContainer).stop(true).animate({

                                    height: realBarHeight

                                }, {

                                    duration: topDiff / .2,
                                    easing: "easeOutQuad"

                                });

                            }

                        });

                        $toDrag.append("<div class='scroll-bar'><div class='bar' /></div>");
                        $scrollBarContainer = $(">.scroll-bar", $toDrag);

                        $scrollBarContainer.css("opacity", .2);

                    }

                    $toDrag.height($container.height()); //.css("overflow", "hidden");
                    $dragContainer.stop(true).height(contentHeight);

                    $(".bar", $scrollBarContainer).stop(true).height(Math.round($scrollBarContainer.height() * ($container.height() / contentHeight)));

                    positionElements($dragContainer.position().top);

                } else {

                    $toDrag.css("height", ""); //.css("overflow", "");
                    $dragContainer.children().unwrap();
                    $dragContainer = $(">.drag-container", $toDrag);
                    $scrollBarContainer.remove();

                }

            };

            if (!$toDrag[0]._dragSetup) {

                $toDrag[0]._defaultHeight = $toDrag.height();

                $(window).resize(function () {

                    if ($toDrag.is(":visible"))
                        sizeAndSetup();

                });

                $toDrag[0]._dragSetup = true;

            }

            sizeAndSetup();

        });

    };

})(jQuery);
