﻿/// <reference path="jquery-1.4.2.min.js"/>
/// <reference path="jqueryui/1.8.5/jquery-ui.min.js"/>
/// <reference path="jquery.timers.js"/>
/*
@author Dan Gidman (danatcofo at gmail dot com)
released under GNU General Public License v3
http://www.gnu.org/licenses/gpl.html
version 2.4
*/
(function ($) {

    // #region Constants

    // data keys
    var angles = "$autoscroll", ek = "$tAutoscroll", ik = "$autoscrollInterval", lk = "$edgeAutoscroll", mk = "$lastEdgeAutoscroll",

    // angle enum
    angelenum = {
        up: 90.0,
        left: 180.0,
        right: 360.0,
        upleft: 135.0,
        upright: 45.0,
        downleft: 225.0,
        downright: 315.0,
        leftup: 135.0,
        rightup: 45.0,
        leftdown: 225.0,
        rightdown: 315.0,
        down: 270.0
    },

    // #endregion

    // #region Methods

    // available M defaults to init
    methods = {
        init: function (s) {
            return this.each(function () {
                if (getdata(this)) $(this).data(angles, validation($.extend(getdata(this), s)));
                else {

                    $(this).data(angles, validation($.extend({ e: false, fr: false }, $.fn.autoscroll.defaults.settings, s)));

                    var c = getdata(this);

                    $(this).hover(function () {
                        var c = getdata(this);
                        if (c) {
                            if (c.scroll) {
                                _intervalhandler(this);
                                if (c.stopOn == 'click') {
                                    $(this).click(function () { $(this).stop(true); });
                                }
                                else {
                                    $(this).stop(true);
                                }
                            }
                            c.e = true;
                        }
                    }, function () {
                        var c = getdata(this);
                        if (c && c.e) {
                            if (c.stopOn != 'click') {
                                if (c.scroll) intervalhandler(this);
                            }
                            c.e = false;
                        }
                    });

                    if (c.buttonUp && c.buttonDown) {
                        mouseButtonUp(this);
                        mouseButtonDown(this);
                    }

                    if (c.expandButton) {
                        expand(this);
                    }
                    if (c.mouseWheel) {
                        mouseWheel(this);
                    }

                    if ($.browser.msie && $.browser.version == "6.0") {
                        $(".scrollbarTrack").css({ height: $(this).height() });
                    } else if (c.gradient) {
                        $("#ISIcontainer").prepend($("<img>").attr({ id: 'topGradient', src: c.gradientTop }).css({ height: 0 }));
                        $("<img>").attr({ id: 'bottomGradient', src: c.gradientBottom }).css({ top: c.expandHeight - 50 }).appendTo("#ISIcontainer");
                        $("#ISI").data({'gradientExpand': $('#bottomGradient').height() });
                    }

                    $(".scrollbarContainer").css({ display: 'block' });
                    $(this).css({ 'overflow-x': 'hidden', 'overflow-y': 'hidden' });
                    scrollbarDragger(this);
                    intervalhandler(this);

                }
            });
        },
        destroy: function () {
            return this.each(function () {
                if (getdata(this)) {
                    _intervalhandler(this);
                    $(this).stop(true).data(ik, null).data(angles, null).data(ek, null);
                }
            });
        },
        delay: function (t) {
            return this.each(function () {
                var c = getdata(this);
                if (c && c.scroll) {
                    $(this).autoscroll("pause")
                    $(this).oneTime(t || $.fn.autoscroll.defaults.delay, angles, function () {
                        $(this).autoscroll("resume");
                    });
                }
            });
        },
        fastforward: function (s) { return ffandrewind(this, "f", s); },
        rewind: function (s) { return ffandrewind(this, "r", s); },
        pause: function () {
            return this.each(function () {
                var c = getdata(this);
                if (c && c.scroll) {
                    c.scroll = false;
                    $(this).stop(true);
                    _intervalhandler(this);
                }
            });
        },
        resume: function () {
            return this.each(function () {
                var c = getdata(this);
                if (c) {
                    c.scroll = true;
                    intervalhandler(this);
                }
            });
        },
        reverse: function () {
            return this.each(function () {
                var c = getdata(this);
                if (c && (c.direction += 180.0) > 360.0) c.direction -= 360.0;
                $(this).stop(true);
            });
        },
        toggle: function () {
            return this.each(function () {
                var c = getdata(this);
                if (c)
                    if (c.scroll) $(this).autoscroll("pause");
                    else $(this).autoscroll("resume");
            });
        },
        get: function () {
            return this.each(function () {
                if (getdata(this)) return getdata(this);
            });
        },
        addpausesource: function (e) {
            if (typeof e == "undefined") return this;
            if (!(e instanceof jQuery))
                if ((e = $(e)).length == 0) return this;
            var s = this.selector;
            e.each(function () {
                $(this).hover(function () {
                    $(s).each(function () {
                        var c = getdata(this);
                        if (c) {
                            if (c.scroll) {
                                _intervalhandler(this);
                                if (c.stopOn == 'click') {
                                    $(this).click(function () { $(this).stop(true); });
                                } else {
                                    $(this).stop(true);
                                }
                            }
                            c.e = true;
                        }
                    });
                }, function () {
                    $(s).each(function () {
                        var c = getdata(this);
                        if (c && c.e) {
                            if (c.stopOn != 'click') {
                                if (c.scroll) intervalhandler(this);
                            }
                            c.e = false;
                        }
                    });
                });
            });
            return this;
        }
    },

    // #endregion

    // #region Utilities
    setData = function (e) {

        var c = getdata(e);

        var isiTopPadding = $("#ISI").css("padding-top").replace("px", "");
        isiTopPadding = parseInt(isiTopPadding);

        $("#ISI").data({
            'ISIBodyHeight': $(".ISIbody").height(),
            'dragToControlStop': $("#toControlStop").height(),
            'dragISIcontainer': $("#ISIcontainer").height(),
            'scrollbarTrack': $(".scrollbarTrack").height(),
            'isiTopPadding': isiTopPadding,
            'buttonHeight': $(".scrollbarArrowUp").height() * 2,
            'draggerHeight': $(".scrollbarDrag").height()
        });

    },
    scrollbarDragger = function (e) {
        var c = getdata(e);

        $(c.dragger).draggable(
        {
            axis: 'y',
            containment: 'parent',
            drag: function (event, ui) {
                scrollToDrag(e);
            }
        }).mousedown(function () {
            c.cycleComplete = true;
            $(e).autoscroll("pause");
        });
    },
    gradientControl = function (e, targY) {
        var c = getdata(e);

        //console.log(targY, $("#ISI").data('ISIBodyHeight'), $("#ISI").data('dragISIcontainer'));
        var maxHeight = $("#ISI").data('ISIBodyHeight') - $("#ISI").data('dragISIcontainer');

        //console.log('inside:' + targY + " " + -maxHeight);

        if (targY == 0) {

            $('#topGradient').animate({ height: 0 }, { queue: false });
            $('#ISI').data({ 'gradientOn': false });

        } else if (targY == -maxHeight) {

            $('#bottomGradient').animate({ top: c.expandHeight + $("#ISI").data('gradientExpand') }, { queue: false });
            $('#ISI').data({ 'gradientOn': false });
        } else {
            if ($('#ISI').data('gradientOn') == false) {
                $('#topGradient').animate({ height: 40 }, { queue: false });
                $('#bottomGradient').animate({ top: c.expandHeight - $("#ISI").data('gradientExpand') }, { queue: false });
                $('#ISI').data({ 'gradientOn': true });
            }

        }

    },
    scrollToDrag = function (e) {
        var c = getdata(e);

        if (!$("#ISI").data('ISIBodyHeight')) {
            setData();
        }

        var scrollAmount = ($("#ISI").data('dragToControlStop') - $("#ISI").data('dragISIcontainer')) / ($("#ISI").data('scrollbarTrack') - $("#ISI").data('draggerHeight'));

        var draggerY = $(c.dragger).position().top;
        var targY = Math.floor(-draggerY * scrollAmount);

        if (c.gradient == true) { gradientControl(e, targY); }

        $("#toControlStop").css({ top: targY });

    },
    scrollUp = function (e) {
        var c = getdata(e);

        setTimeout(function () {
            $(e).autoscroll({
                direction: "up",
                step: 400,
                scroll: true
            });
        }, c.cycleDelay);
        c.cycleSetStart = false;
        c.cycleSetEnd = true;
    },
    scrollDown = function (e) {
        var c = getdata(e);

        setTimeout(function () {
            $(e).autoscroll({
                direction: "down",
                step: 20,
                scroll: true
            });
        }, c.cycleDelay);
        c.cycleSetStart = true;
        c.cycleSetEnd = false;
    },
    mouseButtonUp = function (e) {
        var c = getdata(e);
        var that, newPos;

        $(c.buttonUp).mousedown(function () {

            var ISIbody = $('.ISIbody');

            that = setInterval(function () {
                newPos = Math.floor($(".ISIbody").position().top) + 15;

                if (newPos < 0) {
                    //console.log($(e).children(':first').position().top);
                    ISIbody.css({ top: newPos });
                } else {
                    ISIbody.css({ top: '0' });
                }

                if (c.gradient == true) {
                    if (newPos == 0 || newPos == 15) { newPos = 0; }
                    //console.log(newPos, ISIH);             
                    gradientControl(e, newPos);
                }

                moveDragger(e);
            }, 100);

        }).mouseup(function () {
            clearInterval(that);
            $(e).autoscroll("pause");
        }).mouseout(function () {
            clearInterval(that);
            $(e).autoscroll("pause");
        });

    },
    mouseButtonDown = function (e) {
        var c = getdata(e);
        var that;
        var negInt;
        var panelSize;
        var ISI = $(".ISIbody");

        //var padding = $("#ISI").css("padding-top").replace("px", "");
        //$('.ISIbody').height() - $('#ISI').height() - parseInt(padding);

        $(c.buttonDown).mousedown(function () {
            if (!$("#ISI").data('ISIBodyHeight')) {
                scrollToDrag(e);
            }
            var ISIbody = $('.ISIbody');
            that = setInterval(function () {

                var padding = $("#ISI").css("padding-top").replace("px", "");
                var ISIHeight = ISIbody.height() - $('#ISI').height() - parseInt(padding);

                newPos = Math.floor($(".ISIbody").position().top) - 15;

                var ISIH = ISIHeight * -1;

                if (newPos > ISIH) {
                    //console.log($(e).children(':first').position().top);
                    ISIbody.css({ top: newPos });
                } else {
                    ISIbody.css({ top: ISIH });
                }

                if (c.gradient == true) {
                    if (newPos < ISIH) { newPos = ISIH; }
                    //console.log(newPos, ISIH);             
                    gradientControl(e, newPos);
                }

                moveDragger(e);

            }, 100);

        }).mouseup(function () {
            clearInterval(that);
            $(e).autoscroll("pause");
        }).mouseout(function () {
            clearInterval(that);
            $(e).autoscroll("pause");
        });

    },
    mouseWheel = function (e) {
        var c = getdata(e);

        $('#ISIcontainer').bind('mousewheel', function (event, delta) {
            event.preventDefault();
            var ISIbody = $('.ISIbody');

            if (!$("#ISI").data('ISIBodyHeight')) {
                scrollToDrag(e);
            }

            if (delta == -1) {

                var padding = $("#ISI").css("padding-top").replace("px", "");
                var ISIHeight = ISIbody.height() - $('#ISI').height() - parseInt(padding);

                newPos = Math.floor($(".ISIbody").position().top) - c.mouseWheelStep;

                var ISIH = ISIHeight * -1;
                //console.log(newPos, ISIH);
                if (newPos >= ISIH) {
                    ISIbody.css({ top: newPos });
                } else {
                    ISIbody.css({ top: ISIH });
                }
            } else {
                newPos = Math.floor($(".ISIbody").position().top) + c.mouseWheelStep;

                if (newPos <= 0) {
                    //console.log($(e).children(':first').position().top);
                    ISIbody.css({ top: newPos });
                } else {
                    ISIbody.css({ top: '0' });
                }
            }

            if (c.gradient == true) {
                if (newPos == 0 || newPos == c.mouseWheelStep) { newPos = 0; }
                if (newPos < ISIH) { newPos = ISIH; }
                //console.log(newPos, ISIH);             
                gradientControl(e, newPos);
            }
            moveDragger(e);
        });

    },
    moveDragger = function (e) {

        $(e).autoscroll('pause');

        var c = getdata(e);

        if (!$("#ISI").data('ISIBodyHeight')) {
            setData();
        }

        if (c.moveToBottom || c.expandState) {
            var reachBottom = $("#ISI").data('ISIBodyHeight') - $("#ISI").data('isiTopPadding') - 120;
        } else {
            var reachBottom = $("#ISI").data('ISIBodyHeight') - $("#ISI").data('isiTopPadding');
        }

        var realScrollTrack = $(".scrollbarTrack").height() - $("#ISI").data('buttonHeight');
        var dragPos = reachBottom / realScrollTrack;
        var containerPos = Math.abs($(".ISIbody").position().top);

        containerPos = Math.floor(containerPos / dragPos);

        //console.log(reachBottom, realScrollTrack, containerPos, $("#ISI").data('newheight'), $("#ISI").data('ISIBodyHeight'));

        $(c.dragger).css({ top: containerPos });

    },
    expand = function (e) {
        var c = getdata(e);


        //Set the text of the expand/collapse button
        $(c.expandButton).text(c.expandText);

        //Initialize the expand toggle
        $(c.expandButton).toggle(function () {

            $(c.dragger).draggable('disable');
            var that = $(this);

            var ISIcontainer = $("#ISIcontainer");
            var ISI = $("#ISI");
            var ISIcontents = $("#ISIcontents");
            var scrollDrag = $(".scrollbarDragBottom");

            c.expandState = true;
            ISIcontainer.addClass('ISIExpand');
            $(this).text(c.collapseText);

            //If the scroller is moving, pause it
            ISIcontents.autoscroll("pause");

            //Get the padding of the content that represents the headings height
            var ISIPaddingHeight = $("#ISI").css("padding-top").replace("px", "");
            ISIPaddingHeight = parseInt(ISIPaddingHeight);

            //Set all initial values for toggling
            if (!that.data('ISIHeight')) {
                that.data({
                    ISIcontainerHeight: ISIcontainer.outerHeight(),
                    ISIHeight: ISI.height(),
                    ISIContents: ISIcontents.outerHeight(),
                    scrollTrackHeight: $(".scrollbarTrack").height(),
                    scrollbarHeight: $(".scrollbarDrag").height(),
                    scrollbarBottomCapTop: $(".scrollbarDragBottom").position().top
                });
            }

            var expandScroll = Math.floor(($("#ISIcontents").height() / $(".ISIbody").height()) * 100);
            var openScroll = Math.floor((that.data('scrollbarHeight') / expandScroll) * 100);
            var newheight = $(".ISIbody").height() - c.expandHeight;

            $("#ISI").data({ 'newheight': newheight });

            if (!that.data('expandScroll')) {
                that.data({ 'expandScroll': expandScroll, 'openScroll': openScroll });
            }

            //***********************
            // Animate - ISI Container -HEIGHT-
            //***********************

            //Animate the outer ISI container
            $(ISI).stop(0).animate({ height: (c.expandHeight - ISIPaddingHeight) + 'px' }, {
                duration: 1000,
                easing: 'easeOutSine',
                step: function (now, fx) {
                    if ($(".ISIbody").position().top <= -newheight) {
                        c.moveToBottom = true;
                        $(".ISIbody").animate({ top: -newheight }, { duration: 1000, easing: 'easeOutSine', queue: false });
                    }
                    // Move the scoll bar as the ISI expands
                    moveDragger(e);
                }
            });

            //Animate the container Height
            $(ISIcontainer).stop(0).animate({ height: c.expandHeight + 'px' }, { duration: 1000, easing: 'easeOutSine' });
            $(ISIcontents).stop(0).animate({ height: c.expandHeight + 'px' }, { duration: 1000, easing: 'easeOutSine' });

            //***********************
            // Animate Scroll Bar -HEIGHT-
            //***********************

            $(".scrollbarTrack").stop(0).animate({ height: c.expandHeight - ($(c.buttonUp).height() * 2) + 'px' }, {
                duration: 1000,
                easing: 'easeOutSine',
                queue: false
            });

            $(".scrollbarDrag").stop(0).animate({ height: that.data('openScroll') }, {
                duration: 1000,
                easing: 'easeOutSine',
                queue: false,
                complete: function () {
                    setData();
                    $(c.dragger).draggable('enable');
                }
            });

            var dragBottomPos = that.data('openScroll') - ($(".scrollbarDragBottom").height() * 2);

            $(".scrollbarDragBottom").animate({
                top: dragBottomPos
            }, {
                duration: 1000,
                queue: false,
                easing: 'easeOutSine'
            });

        }, function () {

            $(c.dragger).draggable('disable');
            var that = $(this);
            var ISIcontainer = $(this).parent();
            var ISI = $(this).next();
            var ISIcontents = $(this).next().children(":first");
            ISIcontainer.stop(0).animate({ height: that.data('ISIcontainerHeight') }, { duration: 1000, easing: 'easeInSine', queue: false,
                complete: function () { $(this).removeClass('ISIExpand'); }
            });

            $(".scrollbarTrack").stop(0).animate({ height: that.data('scrollTrackHeight') }, {
                duration: 1000,
                easing: 'easeInSine',
                queue: false,
                step: function () {
                    moveDragger(e);
                }
            });

            ISIcontents.stop(0).animate({ height: that.data('ISIcontentsHeight') }, { duration: 1000, easing: 'easeInSine', queue: false });
            $(".scrollbarDrag").stop(0).animate({ height: that.data('scrollbarHeight') }, {
                duration: 1000,
                easing: 'easeInSine',
                queue: false,
                complete: function () {
                    setData();
                    $(c.dragger).draggable('enable');
                }
            });

            var dragBottomPos = that.data('scrollbarHeight') - ($(".scrollbarDragBottom").height() * 2);

            $(".scrollbarDragBottom").animate({
                top: dragBottomPos
            }, {
                duration: 1000,
                queue: false,
                easing: 'easeInSine'
            });

            ISI.stop(0).animate({ height: that.data('ISIHeight') }, { duration: 1000, easing: 'easeInSine', queue: false });
            c.expandState = false;
            $(this).text(c.expandText);
            c.moveToBottom = false;
        });

    },
    // interval handler
    intervalhandler = function (e) {
        $(e).data(ik, setInterval(function () {
            var l, c = getdata(e);
            if (c) {
                if (typeof c.onEvaluate == "function") c.onEvaluate.apply(e);
                if (!edge(e)) {
                    if (c.scroll && !c.e && !c.fr) {
                        if ((l = $(e).data(ek)) && !stepequality(l, c)) $(e).stop(true).animate(step(c.step, c.direction, e), 1000, "linear");
                        else $(e).animate(step(c.step, c.direction), 1000, "linear");
                    }
                }
                $(e).data(ek, $.extend(true, {}, c));

                if (c.cycle) {

                    var isiTopPadding = $("#ISI").css("padding-top").replace("px", "");
                    isiTopPadding = parseFloat(isiTopPadding);
                    var reachBottom = ($(".ISIbody").height() - $(".isiEnd").height() - isiTopPadding) + $(c.buttonDown).height();
                    var realScrollTrack = $(".scrollbarTrack").height() - $(c.dragger).height();
                    var dragPos = reachBottom / realScrollTrack;
                    reachBottom = -reachBottom;

                    var containerPos = Math.abs($(".ISIbody").position().top);
                    containerPos = Math.floor(containerPos / dragPos);

                    if (c.cycleComplete == false) {
                        $(c.dragger).css({ top: containerPos });
                    }

                    if ($(".ISIbody").position().top == reachBottom && !c.cycleSetEnd) {
                        scrollUp(e);
                    } else if ($(".ISIbody").position().top == '0' && !c.cycleStart) {
                        if (c.cycleComplete == false) {
                            scrollDown(e);
                        }
                    }

                }

            }
        }, 50));
    },

    _intervalhandler = function (e) {
        clearInterval($(e).data(ik));
    },

    // get data
    getdata = function (e) { return $(e).data(angles); },

    // step equality
    stepequality = function (a, b) { return a.step === b.step && a.direction === b.direction && a.scroll === b.scroll; },

    // ff and rw handler
    ffandrewind = function (a, r, s) {
        var f = validation($.extend($.fn.autoscroll.defaults.ffrw, s));
        return a.each(function () {
            var c = getdata(this);
            if (c) {
                var scroll = c.scroll, b = c.direction;
                c.fr = true;
                if (r == "r" && (b += 180.0) > 360.0) b -= 360.0;
                if (c.scroll) _intervalhandler(this);
                $(this).stop(true).animate(step(f.step, b), f.speed, "swing", function () { getdata(this).fr = false; if (c.scroll) intervalhandler(this); });
            }
        });
    },

    // validation
    validation = function (s) {
        if ($.inArray(typeof s.scroll, ["undefined", "boolean"]) < 0)
            $.error("scroll is not a boolean");
        if ($.inArray(typeof s.step, ["undefined", "number"]) < 0 && isNaN(s.step = Number(s.step)))
            $.error("step is not a valid number");
        if (s.direction) s.direction = anglehandler(s.direction);
        return s;
    },

    // conversions
    d2r = function (a) { return a * Math.PI / 180.0; },

    // angle handler
    anglehandler = function (a) {
        if (typeof a === "string" && isNaN(Number(a)))
            if (angelenum[a]) a = angelenum[a];
            else if (a.indexOf("rad") == a.length - 3 && !isNaN(a = Number(a.substring(0, a.length - 3)))) a = a * 180.0 / Math.PI;
        if (isNaN(a = Number(a))) $.error("Invalid direction on jQuery.autoscroll");
        while (a < 0.0) a += 360.0;
        return a;
    },

    // step handler
    step = function (s, a) {
        var x = Math.round(s * Math.cos(a = d2r(a))),
            y = Math.round(s * Math.sin(a)) * -1,
            $t = arguments[2];
        return ($t && $($t).length > 0) ?
            { scrollTop: $t.scrollTop + y, scrollLeft: $t.scrollLeft + x} :
            { scrollTop: ((y < 0) ? "-=" : "+=") + Math.abs(y), scrollLeft: ((x < 0) ? "-=" : "+=") + Math.abs(x) };
    },

    // edge handler
    edge = function (e) {
        var c = getdata(e);
        if (c && typeof c.onEdge == "function") {
            var c2 = $(e).data(lk) || { x: null, y: null },
                s = c.step,
                l = e.scrollLeft,
                v = d2r(c.direction),
                x = Math.round(s * Math.cos(v)),
                nl = l + x,
                t = e.scrollTop,
                y = Math.round(s * Math.sin(v)) * -1
            nt = t + y,
                _e = $(e).data(mk);
            // left edge
            if (l > nl && l == 0) {
                if (!c2.x || c2.x != "left") c2.x = "left";
            }
            // right edge
            else if (l < nl && l == e.scrollWidth - e.clientWidth) {
                if (!c2.x || c2.x != "right") c2.x = "right";
            }
            else c2.x = null;

            // top edge
            if (t > nt && t == 0) {

                if (!c2.y || c2.y != "top") c2.y = "top";
            }
            // bottom edge
            else if (t < nt && t == e.scrollHeight - e.clientHeight) {
                if (!c2.y || c2.y != "bottom") c2.y = "bottom";
            }
            else c2.y = null;

            try {
                if (!_e || (c2.x && c2.x != _e.x) || (c2.y && c2.y != _e.y)) {
                    c.onEdge.apply(e, [c2]);
                    return true;
                }
            }
            catch ($e) { throw $e; }
            finally {
                $(e).data(mk, $.extend(true, {}, c2)).data(lk, c2);
            }
        }
        return false;
    };

    // #endregion

    // #region Public

    // main
    $.fn.autoscroll = function (a, b) {

        /// <summary>Autoscroll scrollable elements.</summary>
        if (methods[a]) return methods[a].apply(this, Array.prototype.slice.call(arguments, 1));
        else if (typeof a === 'object' || !a) return methods.init.apply(this, arguments);
        else $.error('Method ' + a + ' does not exist on jQuery.autoscroll');
    };

    // defaults
    $.fn.autoscroll.defaults = {
        settings: {
            step: 50,
            scroll: true,
            direction: "down",
            cycle: false,
            cycleDelay: 5000,
            cycleComplete: false,
            dragger: null,
            buttonUp: null,
            buttonDown: null,
            buttonStep: 10,
            expandState: false,
            moveToBottom: false,
            expandHeight: 400,
            expandButton: null,
            expandText: null,
            collapseText: null,
            mouseWheel: false,
            mouseWheelStep: 10,
            gradients: false,
            gradientTop: null,
            gradientBottom: null
        },
        delay: 5000,
        ffrw: {
            speed: "fast",
            step: 100
        }
    };

    // #endregion

})(jQuery);

