(function ($) {
$.fn.jSlide = function(o) {   
    o = $.extend({
        btnPrev: null,
        btnNext: null,
        mouseWheel: true,
        auto: false,
        direction: 'forward',

        speed: 2000,
        easing: 'linear',

        vertical: false,
        circular: true,
        visible: '4',
        start: 0,
        scroll: 1,
        
        step: 50,
        eltByElt: false,
        evtStart : 'mouseover',
		evtStop : 'mouseout',
        beforeStart: null,
        afterEnd: null
    }, o || {});

    return this.each(function() {    
        var running = false, animCss=o.vertical?"top":"left", sizeCss=o.vertical?"height":"width";
        var div = $(this), ul = $("ul", div), tLi = $("li", ul), tl = tLi.size(), v = o.visible;
        var mousewheelN = 0; 
		var defaultBtn = (o.btnNext === null && o.btnPrev === null) ? true : false;
		var cssU = (v.toString().indexOf("%") != -1 ? '%' : (v.toString().indexOf("px") != -1) ? 'px' : 'el');
		var direction = null; 
        
        
        if(o.circular) {
			var imgSet = tLi.clone();
            ul.prepend(imgSet).append(imgSet.clone());
        }
                   
		var li = $("li", ul);								 
        div.css("visibility", "visible");
        li.css("overflow", "hidden")                        
            .css("float", o.vertical ? "none" : "left")     
            .children().css("overflow", "hidden");          
        if(!o.vertical){ li.css("display", "inline"); }		
        if(li.children().get(0).tagName.toLowerCase() == 'a' && !o.vertical){
        	li.children().css('float','left');
        }
        if(o.vertical && jQuery.browser.msie){				
        	li.css('line-height', '4px').children().css('margin-bottom', '-4px');
        }
        

        ul.css("margin", "0")                               
            .css("padding", "0")                            
            .css("position", "relative")                    
            .css("list-style-type", "none")                 
            .css("z-index", "1");                          

        div.css("overflow", "hidden")                       
            .css("position", "relative")                    
            .css("z-index", "2") 
            .css("left", "0px");   
        
        var liSize = o.vertical ? height(li) : width(li);   
        var liSizeV = o.vertical ? elHeight(li) : height(li);	     
        var curr = o.start; 
        var nbAllElts = li.size();
        var ulSize = liSize * nbAllElts;                   	
        var nbElts = tl;	
        var eltsSize = nbElts * liSize;	
        var allEltsSize = nbAllElts * liSize;						
        var step = o.step == 'default' ? liSize : o.step;	
        

  		o.btnPrev = defaultBtn ? $('<input type="button" class="' + (o.vertical ? 'up' : 'prev') + '" />') : $(o.btnPrev);
  		o.btnNext = defaultBtn ? $('<input type="button" class="' + (o.vertical ? 'down' : 'next') + '" />') : $(o.btnNext);
        var prev = o.btnPrev;
        var next = o.btnNext;
        
        if(defaultBtn && o.auto !== true){
	        prev.css({'opacity':'0.6'});
	        next.css({'opacity' :'0.6'});
	        div.prepend(prev);
	        div.prepend(next);
	        o.btnPrev = prev;
	        o.btnNext = next;
        }
        
       
        if(o.eltByElt){ 
        	step = liSize;
        	if(o.start % liSize !== 0){
        		var imgStart = parseInt(o.start / liSize);	
        		curr = o.start = (imgStart * liSize);
        	}
        }
        
      
        if(o.circular){
        	o.start += (liSize * tl);  						
        	curr += (liSize * tl);
        }
        
  
        var divSize, cssSize, cssUnity;
        if(cssU == '%'){
        	divSize = 0;									
        	cssSize = parseInt(v);  
       		cssUnity = "%";
        }
        else if(cssU == 'px'){
        	divSize = parseInt(v);
        	cssSize = parseInt(v);
        	cssUnity = "px";
        }
        else{
        	divSize = liSize * parseInt(v); 
        	cssSize = liSize * parseInt(v);
        	cssUnity = "px";
        }                      								  
          	
        ul.css(sizeCss, ulSize + "px")                       	
            .css(animCss, -(o.start));                  	 	
        div.css(sizeCss, cssSize + cssUnity);                	
        if(o.vertical && cssUnity == '%'){						
        	var pxsize = ((liSize * nbElts) * (parseInt(v) / 100));
        	div.css(sizeCss,  pxsize + 'px');					
        }
        
		if(divSize === 0){										
			divSize = div.width();								
		}
		

		if(o.vertical){											
		    div.css("width" , liSizeV + 'px');
		    ul.css("width", liSizeV + 'px');
		    li.css('margin-bottom', (parseInt(li.css('margin-bottom')) * 2) + 'px');	
		    li.eq(li.size() - 1).css('margin-bottom', li.css('margin-top'));			
		}else{
			div.css('height', liSizeV + 'px');
			ul.css('height', liSizeV + 'px');	
		}
								
					
		if(cssU == '%'){
			v = divSize / li.width();						
			if(v % 1 !== 0){ v +=1; }
			v = parseInt(v);
		}
		
		var divVSize = div.height();	

		if(defaultBtn){
			next.css({'z-index':200, 'position':'absolute'});
	        prev.css({'z-index':200, 'position':'absolute'});

			if(o.vertical){
	        	prev.css({'width': prev.width(), 'height' : prev.height(), 'top' : '0px', 'left': parseInt(liSizeV / 2) - parseInt(prev.width() / 2) + 'px'});
	        	next.css({'width': prev.width(), 'height' : prev.height(), 'top' : (divVSize - prev.height()) + 'px', 'left' : parseInt(liSizeV / 2) - parseInt(prev.width() / 2) + 'px'});
	        	
	        }
	        else{
	        	prev.css({'left':'0px', 'top': parseInt(liSizeV / 2) - parseInt(prev.height() / 2) + 'px'});
	        	next.css({'right':'0px', 'top': parseInt(liSizeV / 2) - parseInt(prev.height() / 2) + 'px'});
	        }
		}


        if(o.btnPrev){            
            $(o.btnPrev).bind(o.evtStart, function() {
                if(defaultBtn){ o.btnPrev.css('opacity',0.9); }
                running = true;
                direction = 'backward';
                return backward(); 
            });
            
            $(o.btnPrev).bind(o.evtStop, function() {
            	if(defaultBtn){ o.btnPrev.css('opacity',0.6); }
            	running = false; 
            	direction = null;
                return stop(); 
            });
        }
        
        

        if(o.btnNext){
			$(o.btnNext).bind(o.evtStart, function() {
				if(defaultBtn){ o.btnNext.css('opacity',0.9); }
				running = true;
				 direction = 'forward';
                return forward(); 
            });
			$(o.btnNext).bind(o.evtStop,function() {
				if(defaultBtn){ o.btnNext.css('opacity',0.6); }
				running = false;
				direction = null;
                return stop(); 
            });
        }
        

	   if(o.auto === true){
	   	 running = true;	
	   	 if(o.direction==='forward'){
            direction = 'forward';
            forward();
         }
         else{
            direction = 'backward';
            backward();
         }
         ul.hover(
            function(){
                running = false;
				direction = null;
                stop();
            },
            function(){
                running = true;
                if(o.direction==='forward'){
                    direction = 'forward';
                    forward();
                }
                else{
                    direction = 'backward';
                    backward();
                }
            }
         );	
	   }		


        if(o.mouseWheel && div.mousewheel){
            div.mousewheel(function(e, d) { 
                if(!o.circular && (d > 0 ? (curr + divSize < ulSize) : (curr > 0)) || o.circular){
	                mousewheelN += 1;
	                if(running === false){
	                	if(d > 0){ forward(step, true); }
	                	else { backward(step, true); }
	                	running = true;
	                }
                }
            });
        }
		

        function forward(stepsize, once){
    		var s = (stepsize ? stepsize : step);

			if(running === true && direction === "backward"){ return; }
			
    		if(!o.circular){
    			if(curr + s + (o.vertical ? divVSize : divSize) > eltsSize){
    				s = eltsSize - (curr + (o.vertical ? divVSize : divSize));
    			}
    		}
    		
    		ul.animate(
                animCss == "left" ? { left: -(curr + s) } : { top: -(curr + s) } , o.speed, o.easing,
                function() {
                	curr += s;
                	if(o.circular){
	                	if(curr + (o.vertical ? divVSize : divSize) + liSize >= allEltsSize){
	                    	ul.css(o.vertical ? 'top' : 'left', -curr + eltsSize);
	                    	curr -= eltsSize;
	                    }
                	}
    				
                    if(!once && running){
                    	 forward();
                    }
                    else if(once){
                    	if(--mousewheelN > 0){
                    		this.forward(step, true);
                    	}
                    	else{
                    		 running = false;
                    		 direction = null;
                    	}
                    }
                }
            );
            
        }

        function backward(stepsize, once){
    		var s = (stepsize ? stepsize : step);
    		
    		if(running === true && direction === "forward"){ return; } 
    		
    		if(!o.circular){
    			if(curr - s  < 0){
    				 s = curr - 0;
    			}
    		}
    		
    		ul.animate(
                animCss == "left" ? { left: -(curr - s) } : { top: -(curr - s) } , o.speed, o.easing,
                function() {
                	curr -= s;
                    if(o.circular){
	                	if(curr <= liSize){
	                    	ul.css(o.vertical ? 'top' : 'left', -(curr + eltsSize));
	                    	curr += eltsSize;
	                    }
                    }
                    
					if(!once  && running){
						backward();
					}
					else if(once){
	                	if(--mousewheelN > 0){
	                		backward(step, true);
	                	}
	                	else{
	                		 running = false;
	                		 direction = null;
	                	}
                	}
                }
            );
        }

        function stop(){
        	if(!o.eltByElt){ 	
        		ul.stop(); 		
        		curr = 0 - parseInt(ul.css(animCss));	
        	}
        	running = false; 	
        	direction = null;
        }

        function imgSize(el, dimension){
			if(dimension == 'width'){
				return el.find('img').width();
			}
			else {
				return el.find('img').height();
			}
		}
		
		function elHeight(el){
			var elImg = el.find('img');
			if(o.vertical){
		    	return parseInt(el.css('margin-left')) + parseInt(el.css('margin-right')) + parseInt(elImg.width()) + parseInt(el.css('border-left-width')) + parseInt(el.css('border-right-width')) + parseInt(el.css('padding-right')) + parseInt(el.css('padding-left'));
			}	
			else{
				return parseInt(el.css('margin-top')) + parseInt(el.css('margin-bottom')) + parseInt(elImg.width()) + parseInt(el.css('border-top-height')) + parseInt(el.css('border-bottom-height')) + parseInt(el.css('padding-top')) + parseInt(el.css('padding-bottom'));
			}
		}
        
        function debug(html){
        	$('#debug').html($('#debug').html() + html + "<br/>");
        } 
        
    });
};

function css(el, prop) {
    return parseInt($.css(el[0], prop)) || 0;
}

function width(el) {
    	return el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');
}

function height(el) {
    return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');
}

})(jQuery);
