function Scrollpane() {
    this.scrollText = null;
    this.scrollBar = null;
    this.scrollUp = null;
    this.scrollBox = null;
    this.scrollDown = null;

    this.scrollPos = 0;
    this.scrollPosTarget = 0;
    this.scrollHard = false;

    this.dragStartMousePos = 0;
    this.dragStartScrollPos = 0;

    this.scrollBoxInitialTop = 0;
    this.scrollBoxInitialHeight = 0;

    this.scrollerTimeout = null;

    this.startAttempts = 0;
    
    this.start();
}
Scrollpane.prototype = {
    start: function() {
        this.scrollBar = document.getElementById('scrollbar');
        if (this.scrollBar == null) {
            this.deferStart();
            return;
        }
        this.scrollUp = document.getElementById('scrollup');
        this.scrollBox = document.getElementById('scrollbox');
        this.scrollDown = document.getElementById('scrolldown');
        this.scrollText = this.findScrollText();

        var lthis = this;
        this.scrollUp.onclick = function() { lthis.doScrollBy(80); }
        this.scrollDown.onclick = function() { lthis.doScrollBy(-80); }
        this.scrollBar.onclick = function(e) { lthis.scrollBarClicked(e); }

        this.setupDragAndWheel();

        this.updateScrollBox(true);
    },

    findScrollText: function() {
        var tables = document.getElementsByTagName('table');
        if (tables.length < 0) {
            return null;
        }
        var i;
        for (i = 0; i < tables.length; i ++) {
            var table = tables[i];
            if (table.className != 'contentpaneopen') continue;
            var tr = table.getElementsByTagName('tr')[0];
            if (tr == null) continue;
            var td = tr.getElementsByTagName('td')[0];
            if (td == null) continue;
            if (td.className == 'contentheading') continue;
            return this.redesignScrollText(tr);
        }
        return null;
    },

    redesignScrollText: function(tr) {
        tr.className = 'contentmodified';
        var td = tr.getElementsByTagName('td')[0];
        td.style.display = 'block';
        td.style.position = 'absolute';
        td.style.top = '0px';
        td.style.left = '20px';
        td.style.width = '620px';
        td.style.paddingTop = '10px';
        
        return td;
    },

    deferStart: function() {
        var lthis = this;
        this.startAttempts += 1;
        if (this.startAttempts < 80) {
            window.setTimeout(function() {lthis.start();}, 50);
        }
    },

    setupDragAndWheel: function() {
        var lthis = this;

        function wheelEvent(ev) {
            var ev = ev || window.event;
            var amount = ev.wheelDelta ? ev.wheelDelta / 120 : -ev.detail / 3;
            lthis.doScrollBy(amount * 100, true);
            ev = $.event.fix(ev);
            ev.preventDefault();
            return false;
        }
        function dragStart(ev) {
            lthis.dragStartMousePos = ev.pageY;
            lthis.dragStartScrollPos = lthis.scrollPos;

            $(document).bind('mousemove', drag);
            document.ontouchmove = function(ev){
                $(document).unbind('mousemove');
                drag(ev.touches[0]);
            };
            $(document).bind('mouseup', dragEnd);
            $(lthis.scrollBox).bind('mouseup', dragEnd);
            lthis.scrollBox.ontouchend = document.ontouchend = function(ev){
                    $(document).unbind('mouseup');
                    lthis.scrollBox.unbind('mouseup');
                    dragEnd(ev.touches[0]);
            };
            return false;
        }
        function drag(ev) {
            var scale = lthis.scrollBoxInitialHeight / lthis.scrollText.offsetHeight;
            lthis.doScrollTo(lthis.dragStartScrollPos + (lthis.dragStartMousePos - ev.pageY) / scale, true);
        }
        function dragEnd(ev) {
            $(document).unbind('mousemove', drag);
            $(document).unbind('mouseup', dragEnd);
            $(lthis.scrollBox).unbind('mouseup', dragEnd);
            document.ontouchmove = lthis.scrollBox.ontouchend = document.ontouchend = null;
            return false;
        }

        if (this.scrollText.addEventListener) {
            this.scrollText.addEventListener('DOMMouseScroll', wheelEvent, false);
            this.scrollText.addEventListener('mousewheel', wheelEvent, false );
        } else {
            this.scrollText.onmousewheel = wheelEvent;
        }

        $(this.scrollBox).bind('mousedown', dragStart);
        this.scrollBox.ontouchstart = function(ev) {
            ev.preventDefault();
            $(lthis.scrollBox).unbind('mousedown');
            dragStart(ev.touches[0]);
            return false;
        }
    },

    scrollBarClicked: function(e) {
        var y;
        if (e) {
            if (e.target != this.scrollBar) return;
            y = e.layerY;
        } else {
            if (window.event.srcElement != this.scrollBar) return;
            y = window.event.offsetY;
        }
        var scrollBoxHeight = this.scrollBox.offsetHeight;
        var scrollableHeight = this.scrollText.offsetHeight - this.scrollText.parentNode.offsetHeight;
        if (scrollableHeight < 0) scrollableHeight = 0;
        var clickableHeight = this.scrollBoxInitialHeight - scrollBoxHeight;
        var pos = -(y - this.scrollBoxInitialTop - scrollBoxHeight / 2) / clickableHeight * scrollableHeight;
        if (pos > 0) pos = 0;
        if (pos < -scrollableHeight) pos = -scrollableHeight;
        this.doScrollTo(pos);
    },

    doScrollBy: function(amount, hard) {
        var target = this.scrollPosTarget + amount;
        this.doScrollTo(this.scrollPosTarget + amount, hard);
    },
    doScrollTo: function(target, hard) {
        var maxScroll = this.scrollText.offsetHeight - this.scrollText.parentNode.offsetHeight;
        if (maxScroll < 0) maxScroll = 0;
        if (target > 0) target = 0;
        if (target < -maxScroll) target = -maxScroll;
        this.scrollPosTarget = target;
        this.scrollHard = hard;
        this.ensureScrollerRuns();
    },

    ensureScrollerRuns: function() {
        window.clearTimeout(this.scrollerTimeout);
        this.scrollerStep();
    },

    scrollerStep: function() {
        var maxStep = 400;
        var minStep = 1;
        var stepTime = 100;
        
        var distance = this.scrollPosTarget - this.scrollPos;
        
        var amount;
        if (this.scrollHard) {
            this.scrollPos = this.scrollPosTarget;
        } else {
            if (-10 < distance && distance < 10) amount = distance * 0.5;
            else amount = distance * 0.25;
            if (amount > 0) {
                if (amount > maxStep) amount = maxStep;
                else if (amount < minStep) amount = distance;
            } else {
                if (amount < -maxStep) amount = -maxStep;
                else if (amount > -minStep) amount = distance;
            }

            this.scrollPos += amount;
        }

        this.scrollText.style.top = this.scrollPos + 'px';

        this.updateScrollBox();

        if (this.scrollPos != this.scrollPosTarget) {
            var lthis = this;
            this.scrollerTimeout = window.setTimeout(function() {lthis.scrollerStep();}, stepTime);
        }
    },

    updateScrollBox: function(firstTime) {
        if (firstTime) {
            this.scrollBoxInitialTop = this.scrollBox.offsetTop;
            this.scrollBoxInitialHeight = this.scrollBox.offsetHeight;
        }
        var scale = this.scrollBoxInitialHeight / this.scrollText.offsetHeight;
        var top = this.scrollBoxInitialTop - this.scrollPos * scale;
        var height = this.scrollText.parentNode.offsetHeight * scale;
        if (height > this.scrollBoxInitialHeight) {
            top = this.scrollBoxInitialTop;
            height = this.scrollBoxInitialHeight;
        }
        this.scrollBox.style.height = height + 'px';
        this.scrollBox.style.top = top + 'px';
    }
}

