(function($) {        

    $.fn.scroller = function(opts) {
        
        var defaults = {
            mode : 'horizontal',
            timeout : null,
            scrollAmount : 5,
            scrollAreas: 0,
            calculateDim : false
        }
        
        var o = $.extend(defaults, opts);
        var ul = null;
        
        return this.each(function() {
            
            var obj = $(this);
            var list = obj.children();
            
            obj.append('<div class="moreLeft"><span>more...</span></div>');
            obj.append('<div class="moreRight"><span>more...</span></div>');
            
            if (o.mode == 'horizontal') {
                if (o.calculateDim) {
                    //console.log(list.parents());
                    //console.log(list.parents().reverse());
                    //list.parents().reverse().showButHide();
                    //list.showButHide();
                    w = list.children().outerWidth({ margin: true }) * list.children().length;
                    //list.showButHideRevert();
                    //list.parents().reverse().showButHideRevert();
                }
                else if (list.width() == 0 && list.css('width') == 0) 
                    w = $.hiddenElement.getWidth($(list[0]));
                else 
                    w = (list.width() == 0) ? list.css('width') : list.width();
                list.width(w);
            }
            else if (o.mode == 'vertical') {
                //obj.css('display', 'block');
                
                
                //h = list.children().outerHeight({ margin : true }) * list.children().length;
                //list.height(h);
                //obj.css('display', 'none');
            }
            
            obj.css('position', 'relative');
            list.css('position', 'absolute');
            
            obj.mousemove(function(e) {
                clearTimeout(o.timeout);
                
                //$.scroller.over(this, e, o);
                $.scroller.over(this, e, list, o);
            });
            
            obj.mouseout(function(e) {
                if($(e.relatedTarget).parents().index($(this)) != -1)
                    return false;
            
                clearTimeout(o.timeout);
                o.timeout = null;
            });
            
        });
    }
    
    /**
     * helper functions
     */ 
    
    $.scroller = {
        
        over : function over(el, event, elements, o) {
            if (o.mode == 'horizontal') {
                half = $(el).width() / 2;
                pos = event.pageX - $(el).offset().left;
                amt = $.scroller.getScrollAmount(pos, half, o);
                
                (pos > half) ? $.scroller.scrollLeft(elements, amt) : $.scroller.scrollRight(elements, amt);
            }
            else if (o.mode == 'vertical') {
                half = $(el).height() / 2;
                pos = event.pageY - $(el).offset().top;
                amt = $.scroller.getScrollAmount(pos, half, o);
                
                (pos > half) ? $.scroller.scrollUp(elements, amt) : $.scroller.scrollDown(elements, amt);
            }
            
            o.timeout = setTimeout(function() { over(el, event, elements, o); }, 20);
        },
        
        scrollLeft : function (elements, amt) {
            elements.each(function() {
                oldLeft = parseInt($(this).css('left') == 'auto' ? 0 : $(this).css('left'));
                
                if (Math.abs(oldLeft - amt) > $(this).width() - $(this).parent().width())
                    amt = $(this).width() - $(this).parent().width() -  Math.abs(oldLeft);
                    
                if (Math.abs(oldLeft - amt) <= $(this).width()  - $(this).parent().width())
                    $(this).css('left', oldLeft - amt);
                
                if(oldLeft + amt < 0) 
                    $(this).siblings('.moreLeft').show();
                if (Math.abs(oldLeft - amt) >= $(this).width()  - $(this).parent().width())
                    $(this).siblings('.moreRight').hide();
            });
        },
        
        scrollRight : function (elements, amt) {
            elements.each(function() {
                oldLeft = parseInt($(this).css('left') == 'auto' ? 0 : $(this).css('left'));
                
                if(oldLeft + amt > 0)
                    amt = Math.abs(0 - oldLeft);
                    
                if(oldLeft + amt <= 0)
                    $(this).css('left', oldLeft + amt);
                
                if (Math.abs(oldLeft - amt) < $(this).width()  - $(this).parent().width())
                    $(this).siblings('.moreRight').show();
                if(oldLeft + amt >= 0)
                    $(this).siblings('.moreLeft').hide();
            });
        },
        
        scrollUp : function (elements, amt) {
            elements.each(function() {
                oldTop = parseInt($(this).css('top') == 'auto' ? 0 : $(this).css('top'));
                
                if (Math.abs(oldTop - amt) > $(this).height() - $(this).parent().height())
                    amt = $(this).height() - $(this).parent().height() -  Math.abs(oldTop);
                    
                if (Math.abs(oldTop - amt) <= $(this).height()  - $(this).parent().height())
                    $(this).css('top', oldTop - amt);
                    
                $(this).siblings('.moreLeft').show();
                if (Math.abs(oldTop - amt) >= $(this).height()  - $(this).parent().height())
                    $(this).siblings('.moreRight').hide();
            });
        },
        
        scrollDown : function (elements, amt) {
            elements.each(function() {
                oldTop = parseInt($(this).css('top') == 'auto' ? 0 : $(this).css('top'));
                
                if(oldTop + amt > 0)
                    amt = Math.abs(0 - oldTop);
                    
                if(oldTop + amt <= 0)
                    $(this).css('top', oldTop + amt);
                    
                $(this).siblings('.moreRight').show();
                if(oldTop + amt >= 0)
                    $(this).siblings('.moreLeft').hide();
            });
        },
        
        getScrollAmount : function (pos, half, o) {
            amt = 0;
            
            areas = half / 4;
            actArea = Math.abs(pos - half);
            
            for (i = 0; i < 4; i++) {
                if (i*areas <= actArea && actArea < (i+1)*areas) {
                    break;
                }
            }
            //amt = Math.pow(i, 2) * 5;
            i = i - o.scrollAreas < 0 ? 0 : i - o.scrollAreas;
            amt = i * o.scrollAmount;
            
            return amt;
        }
        
    }
    
    $.fn.showButHide = function() {
        return this.reverse().each(function() {
            var obj = $(this);

            this.oldPos = obj.css('position');
            this.oldVis = obj.css('visibility');
            this.oldDis = obj.css('display');
            
            obj.css('position', 'absolute');
            obj.css('visibility', 'hidden');
            obj.css('display', 'block');
            
        });
        
    }
    
    $.fn.showButHideRevert = function() {
        return this.each(function() {
            var obj = $(this);
            //obj.css('display', this.oldDis);
            //obj.css('visibility', this.oldVis);
            //obj.css('position', this.oldPos);
            obj.css('display', '');
            obj.css('visibility', '');
            obj.css('position', '');
            
        });
    }
    
    $.hiddenElement = {
        
        getHeight : function(element) {
            //element.showButHide();
            //element.parents().showButHide();
            console.log('halllo');
            var height = element.height();
            
            
            //element.parents().reverse().showButHideRevert();
            //element.showButHideRevert();
            
            return height;
        },
        
        getWidth : function(element) {
            //element.showButHide();
            //element.parents().showButHide();
            console.log('halllo2');
            var width = element.width();
            
            //element.parents().reverse().showButHideRevert();
            //element.showButHideRevert();
            
            return width;
        }
        
    }
    
})(jQuery);



