(function($) {

	$.fn.slider = function(options)
	{
		var defaults =
		{
			speed: 1,																				// speed of animation (scroll * speed) DEFAULT: 1
			gearShift: 0,																			// speed of animation (scroll + gearShift) DEFAULT: 0
			padding: 13, 																			// space between images in px
			startElement: 0,																		// index of element to start on
			fadedOpacity: 0.1,																		// opacity elements when one of them are clicked
			
			autoSlide: false,																		// automaticaly slide elements if true
			autoSlideSpeed: 1,																		// constant speed of autoSlide
			autoSlideMode: 'off',																	// 'always'|'onStart'|'off'
			
			addIndex: false,																		// adds index of sliding element to id (id="slider_[INDEX]")
			
			slidingDirection: 'horizontal',															// 'horizontal'|'vertical'
			
			resize: false,																			// resize elements if true
			resizeWidth: 145,																		// resize element to this width
			resizeHeight: 160,																		// resize element to this height
			
			clickable: false,																		// bind click event on elements
			
			sliderBoxs: false,																		// true if slidingBox are in use else false
			slideLeft: '.slideLeft',																// selector of slide left box
			slideRight: '.slideRight',																// selector of slide right box
			slideClickSpeed: 2,																		// speed of sliding when click on Box
			slideDistance: 0,																		// if > 0 then animation will slide elements untill this distance in px
			
			slideAround: false																		// if true elements will be sliding around infinitly
		};
		
		return this.each(function()
		{
			var opt = $.extend({},defaults, options);												// extend options
			var $this = $(this);
			
			var numSlots, items, rate = contSpeed = btnSpeed = 0;									// initialize variables
			var firstVisible = 0;
			var lastVisible = 0;
			var visible = 0;
			var slider = new Array();
			var left = 0;
			var top = 0;
			var scroll = 0;
			var show = false;
			var startAt = 0;
			var numberOfItems = 0;
			var distance = 0;
			var stopAfterBreak = false;
			var browserSpeed = 0;
			var t1 = '';
			
			left = 0;
			
			$this.css(
			{
				position: 'relative',
				overflow: 'hidden'
			});
			
			//$('body').append('<div id="temp"></div>');
			
			$this.left = Math.ceil($this.position().left + parseInt(isNaN($this.css("marginLeft"))?0:$this.css("marginLeft")));
			$this.right = Math.ceil($this.left + $this.width());
			$this.top = Math.ceil($this.position().top + parseInt(isNaN($this.css("marginTop"))?0:$this.css("marginTop")));
			$this.bottom = Math.ceil($this.top + $this.height());
			
			$this.centerX = ($this.left + parseInt($this.width()/2));
			$this.centerY = ($this.top + parseInt($this.height()/2));
			
			opt.padding = parseInt(opt.padding);
			
			$imgs = $(this).find('.sliderWrapper').children();//$('div', $this);
			numberOfItems = $imgs.size();
			
			if($.browser.msie)
			{
				browserSpeed = 200;
			}
			else if($.browser.webkit)
			{
				browserSpeed = 500;
				opt.autoSlideSpeed = Math.ceil(opt.autoSlideSpeed/2);
				opt.slideClickSpeed = 1;//Math.ceil(opt.slideClickSpeed/2);
			}
			else
			{
				browserSpeed = 200;
			}
			
			if($this.find('.start').index() > 0)												//try to search class="start" in images
			{
				startAt = parseInt($this.find('.start').index());
			}
			
			if(startAt == 0 && opt.startElement > 0)
			{
				startAt = parseInt(opt.startElement-1);
			}
			
			if(numberOfItems > 0)
			{
				 $imgs.each(function(i)
				{
					imageSetUp(this, i);															// setup images
				});
				sliderSetup();																		// setup slider 
			}
			
			function imageSetUp(im, _index)
			{
				im.orig_w = $(im).width();											// save the original dimensions; used when image is clicked
				im.orig_h = $(im).height();
				
				if(opt.resize)
				{
					var w_h = resize( im.orig_w, opt.resizeWidth, im.orig_h, opt.resizeHeight).split('|');			// calculate w/h of images in carousel
					im.w = w_h[0];
					im.h = w_h[1];
				}
				else
				{
					im.w = im.orig_w;
					im.h = im.orig_h;
				}
				
				if(opt.addIndex)
				{
					$(im).attr('id', "slider_"+_index);
				}
				
				$(im).css(																			// set css values for image
				{
					width: parseInt(im.w)+'px',
					height: parseInt(im.h)+'px',
					position: 'absolute',
					zIndex: 100																		// z-index makes front images fully visible
				});
				
				if(opt.slidingDirection == 'vertical')
				{
					// set css values for image
					$(im).css(
					{
						top: Math.ceil(top)+'px',																	// calculate top positioning
						left: Math.ceil(left)+'px'																// calculate left positioning
					});
				}
				else
				{
					// set css values for image
					$(im).css(
					{
						top: Math.ceil(($this.height() - im.h)/2)+'px',
						left: Math.ceil(left)+'px'																// calculate left positioning
					});
				}

				if(opt.clickable)
				{
					$(im).css(																						// set css values for image
					{
						cursor: 'pointer'
					});
					
					im.clicked = {																					// css to animate when image is clicked
						top: parseInt(($this.height() - im.orig_h)/2) + 'px',
						left: parseInt(($this.width() - im.orig_w)/2) + 'px',
						width: im.orig_w + 'px',
						height: im.orig_h + 'px'
					};
					
					im.animateOn = function(el)
					{
						el.css({zIndex: 200});
						elementsVisiblity('fadeOut');																// hide the slider elements
						el.animate( im.clicked, 500 );
					};
					$(im).click(clickOn);																			// bind clickOn to image
				}
				
				if(startAt == _index)
				{
					firstVisible = _index;
					show = true;
				}
				
				if(show)
				{
					if(opt.slidingDirection == 'horizontal')
					{
						if(left < 0 || left > $this.right)
						{
							$(im).addClass('hidden');
						}
						else
						{
							$(im).removeClass('hidden');
							lastVisible = _index;
							visible++;
						}
						left += parseInt(im.w) + opt.padding;
					}
					
					if(opt.slidingDirection == 'vertical')
					{
						if(top < 0 || top > $this.height())
						{
							$(im).addClass('hidden');
						}
						else
						{
							$(im).removeClass('hidden');
							lastVisible = _index;
							visible++;
						}
						top += parseInt(im.h) + opt.padding;
					}
				}
				else
				{
					$(im).addClass('hidden');
				}
				slider[_index] = $(im);
			};
			
			function sliderSetup()
			{
				var im, _t, _s;
				
				if(opt.autoSlide)
				{
					scroll = -opt.autoSlideSpeed;
				}
				
				if(opt.sliderBoxs)
				{
					$(opt.slideLeft).mousedown(function(e)
					{
						scroll = opt.slideClickSpeed;
						t1.start();
					});
					
					$(opt.slideLeft).mouseup(function(e)
					{
						stopAfterBreak = true;
						if(opt.slideDistance == 0)
						{
							t1.stop();
						}
					});
					
					$(opt.slideLeft).mouseleave(function(e)
					{
						stopAfterBreak = true;
						if(opt.slideDistance == 0)
						{
							t1.stop();
						}
					});
					
					$(opt.slideRight).mousedown(function(e)
					{
						scroll = -opt.slideClickSpeed;
						t1.start();
					});
					
					$(opt.slideRight).mouseup(function(e)
					{
						stopAfterBreak = true;
						if(opt.slideDistance == 0)
						{
							t1.stop();
						}
					});
					
					$(opt.slideRight).mouseleave(function(e)
					{
						stopAfterBreak = true;
						if(opt.slideDistance == 0)
						{
							t1.stop();
						}
					});
				}
				else
				{
					if(opt.autoSlideMode != 'always')
					{
						$this.mousemove(function(e)
						{
							if(opt.slidingDirection == 'horizontal')
							{
								if(e.pageX >= $this.left && e.pageX <= ($this.left+($this.width()/3)))
								{
									scroll = Math.ceil(($this.centerX - e.pageX)/(browserSpeed)) + opt.gearShift;
								}
								else if(e.pageX >= $this.right-($this.width()/3) && e.pageX <= $this.right)
								{
									scroll = -(Math.ceil((e.pageX - $this.centerX)/(browserSpeed))) - opt.gearShift;
								}
								else
								{
									scroll = 0;
								}
							}
							
							if(opt.slidingDirection == 'vertical')
							{
								if(e.pageY >= $this.top && e.pageY <= ($this.top + ($this.height()/3)))
								{
									scroll = Math.ceil(($this.centerY - e.pageY)/(browserSpeed)) + opt.gearShift;
								}
								else if(e.pageY >= $this.bottom - ($this.height()/3) && e.pageY <= $this.bottom)
								{
									scroll = -(Math.ceil((e.pageY - $this.centerY)/(browserSpeed))) - opt.gearShift;
								}
								else
								{
									scroll = 0;
								}
							}
							scroll = scroll * opt.speed;
							//$('#temp').text(scroll);
						});
					}
					
					$this.mouseleave(function()
					{
						if(opt.autoSlideMode != 'always')
						{
							t1.stop();
						}
					});
					
					$this.mouseenter(function()
					{
						if (!$this.hasClass('bigshow'))
						{
							if(opt.autoSlideMode != 'always')
							{
								t1.start();
							}
						}
					});
				}
				
				var first = { left: 0, right: 0, top: 0, bottom: 0};
				var last  = { left: 0, right: 0, top: 0, bottom: 0};
				
				// javascript Motion Tween by PHILIPPE MAEGERMAN; very similar to tweening in Flash.
				// check out the full details at his site: http://jstween.blogspot.com/
				
				t1 = new Tween(new Object(), 'xyz', Tween.regularEaseInOut, 0, 10000, 10000);
				
				t1.onMotionChanged = function(event)
				{
					first.left = slider[firstVisible].position().left;
					first.right = slider[firstVisible].position().left + slider[firstVisible].width();
					first.top = slider[firstVisible].position().top;
					first.bottom = slider[firstVisible].position().top + slider[firstVisible].height();
					
					last.left = slider[lastVisible].position().left;
					last.right = slider[lastVisible].position().left + slider[lastVisible].width();
					last.top = slider[lastVisible].position().top;
					last.bottom = slider[lastVisible].position().top + slider[lastVisible].height();
					
					if(!opt.slideAround)
					{
						if(opt.slidingDirection == 'horizontal')
						{
							
							if (
								($(slider[0]).position().left >= 0 && scroll > 0) || 
								($(slider[numberOfItems-1]).position().left + $(slider[numberOfItems-1]).width() + opt.padding <= $this.width() && scroll < 0)
							)
							{
								slide = false;
							}
							else
							{
								slide = true;
							}
						}
						
						if(opt.slidingDirection == 'vertical')
						{
							if (
								($(slider[0]).position().top >= 0 && scroll > 0 && !slider[0].hasClass('hidden'))
								|| ($(slider[numberOfItems-1]).position().top + $(slider[numberOfItems-1]).height() <= $this.height() && scroll < 0 && !slider[numberOfItems-1].hasClass('hidden'))
							)
							{
								slide = false;
							}
							else
							{
								slide = true;
							}
						}
					}
					else
					{
						slide = true;
					}
					
					if(slide)
					{
						if(firstVisible - 1 == -1 && opt.slideAround)
						{
							prev = numberOfItems - 1;
						}
						else
						{
							prev = firstVisible - 1;
						}
						
						if(lastVisible + 1 == numberOfItems && opt.slideAround)
						{
							next = 0;
						}
						else
						{
							next = lastVisible + 1;
						}
						
						if(opt.slidingDirection == 'horizontal')
						{
							if(first.right < 0 && !slider[firstVisible].hasClass('hidden') && opt.slideAround)
							{
								slider[firstVisible].addClass('hidden');
								
								if(firstVisible + 1 == numberOfItems)
								{
									firstVisible = 0;
								}
								else
								{
									firstVisible++;
								}
								visible--;
							}
							
							if(last.left > $this.width() && !slider[lastVisible].hasClass('hidden') && opt.slideAround)
							{
								slider[lastVisible].addClass('hidden');
								
								if(lastVisible - 1 == -1)
								{
									lastVisible = numberOfItems-1;
								}
								else
								{
									lastVisible--;
								}
								visible--;
							}
							
							if(first.left >= 0 && $(slider[prev]).hasClass('hidden') && opt.slideAround && prev >= 0 && prev < numberOfItems)
							{
								slider[prev].removeClass('hidden');
								$(slider[prev]).css(
								{
									left: first.left - opt.padding - slider[prev].width() +'px'
								});
								firstVisible = prev;
								visible++;
							}
							
							if(last.right <= $this.width() && $(slider[next]).hasClass('hidden') && opt.slideAround && next >= 0 && next < numberOfItems)
							{
								slider[next].removeClass('hidden');
								$(slider[next]).css(
								{
									left: last.right + opt.padding+'px'
								});
								lastVisible = next;
								visible++;
							}
						}
						
						if(opt.slidingDirection == 'vertical')
						{
							if(first.bottom <= 0 && !slider[firstVisible].hasClass('hidden'))
							{
								slider[firstVisible].addClass('hidden');
								
								if(firstVisible + 1 == numberOfItems)
								{
									firstVisible = 0;
								}
								else
								{
									firstVisible++;
								}
								visible--;
							}
							
							if(last.top >= $this.height() && !slider[lastVisible].hasClass('hidden'))
							{
								slider[lastVisible].addClass('hidden');
								
								if(lastVisible - 1 == -1)
								{
									lastVisible = numberOfItems-1;
								}
								else
								{
									lastVisible--;
								}
								visible--;
							}
							
							if(first.top > 0 && $(slider[prev]).hasClass('hidden') && prev >= 0 && prev < numberOfItems)
							{
								slider[prev].removeClass('hidden');
								$(slider[prev]).css(
								{
									top: first.top - opt.padding - slider[prev].height() +'px'
								});
								firstVisible = prev;
								visible++;
							}
							
							if(last.bottom < $this.height() && $(slider[next]).hasClass('hidden') && next >= 0 && next < numberOfItems)
							{
								slider[next].removeClass('hidden');
								$(slider[next]).css(
								{
									top: last.bottom + opt.padding+'px'
								});
								lastVisible = next;
								visible++;
							}
						}
						
						index = firstVisible;
						
						for (var j=0; j < visible; j++)
						{
							if(index == numberOfItems && opt.slideAround)
							{
								index = 0;
							}
							
							if(opt.slidingDirection == 'horizontal')
							{
								$(slider[index]).css
								({
									left: Math.ceil($(slider[index]).position().left) + scroll + 'px'
								});
							}
							
							if(opt.slidingDirection == 'vertical')
							{
								$(slider[index]).css
								({
									top: Math.ceil($(slider[index]).position().top) + scroll + 'px'
								});
							}
							index++;
						}
						distance = distance + scroll;
					}
					
					if(stopAfterBreak && Math.abs(distance) >= opt.slideDistance && opt.slideDistance > 0)
					{
						t1.stop();
						distance = 0;
					}
					
					//$("#temp").html(Math.abs(distance) +' s:'+ scroll);
					//$("#temp").html((slide)?'1':'0');
					//$("#temp").html($this.height());
					//$("#temp").html('first.left:'+ first.left + ', first.right:' + first.right + ' first.bottom:' + first.bottom + ' first.top:' + first.top);
					//$("#temp").html('last.left:'+ last.left + ', last.right:' + last.right + ' last.bottom:' + last.bottom + ' last.top:' + last.top);
					//$("#temp").html('start:'+ firstVisible + ', stop:' + lastVisible + ', items:'+numberOfItems+ ', previous: '+prev+ ', next: '+next+ ', visible:'+visible + ', scroll:'+ scroll);
				};
				
				if (!$this.hasClass('bigshow') && opt.autoSlide)
				{
					t1.start();																				// start the motion
				}
			};
			
			function elementsVisiblity(param)
			{
				index = firstVisible;
				
				for (var j=0; j < visible; j++)
				{
					if(index == numberOfItems)
					{
						index = 0;
					}
					
					if(param == 'hide')
					{
						//$(slider[index]).removeClass('hidden');
						$(slider[index]).fadeOut(700);
					}
					
					if(param == 'show')
					{
						//$(slider[index]).addClass('hidden');
						$(slider[index]).fadeIn(700);
					}
					
					if(param == 'fadeOut')
					{
						$(slider[index]).animate
						({
							opacity: opt.fadedOpacity
						}, 500);
					}
					
					if(param == 'fadeIn')
					{
						$(slider[index]).animate
						({
							opacity: 1
						}, 500);
					}
					index++;
				}
			};
			
			function clickOn()																					// actions when element is clicked
			{
				var elem = this;
																												// stop the Tween motion
				if (!$this.hasClass('bigshow'))
				{
					$this.addClass('bigshow');
					t1.stop();
					
					$cloned =																					// clone the image clicked and leave the original in place (this seemed easier than pulling the orig out of place)
					$(this).clone().prependTo($this).click(function()											// add to slider container, when clicked again . . .
					{
						elementsVisiblity('fadeIn');															// show slider elements
						
						$(this).animate(																		// animate back to slider slot
						{
							left: $(elem).position().left + 'px',												// change position
							top: $(elem).position().top + 'px',
							width: $(elem).width() + 'px', 														//  and size
							height: $(elem).height() + 'px',
							opacity: 1
						}, function()
						{
							$(this).remove();																	// remove the cloned image, 
							$(elem).click(clickOn);																// rebind the image click event,
							$this.removeClass('bigshow');
							t1.start();																			// and restart carousel 
						});
						return false;
					});
					(opt.textBox) ? elem.textAnimateOn($cloned) : elem.animateOn($cloned);						// animate the clone; enlarge or position to side of text box
				}
				return false;
			};
			
			function resize(w, max_w, h, max_h)																	// resize elements
			{
				if (w > max_w || h > max_h)
				{
					var x_ratio = max_w / w;
					var y_ratio = max_h / h;
					
					return Math.ceil(y_ratio * w) + '|' + max_h;
				}
				else
					return w + '|' + h;
			};
		});
	};
})(jQuery);
