(function($){
	$.preloadImage = function(image, callback) {
		var self = this;
		this.file = image;
		this.callback = callback;
		this.loaded = false;
		this.aborted = false;
		this.error = false;
		this.image = new Image();
		
		this.cancelEvent = function() {
			if (this.image && this.image.onload) {
				this.image.onload = null;
			}
			if (this.image && this.image.onabort) {
				this.image.onabort = null;
			}
			if (this.image && this.image.onerror) {
				this.image.onerror = null;
			}
		};
		
		this.on_load = function() {
			self.loaded = true;
			if (self.callback && typeof self.callback == "function") {
				self.callback.apply(self, ["loaded"]);
			}
			self.cancelEvent();
		};
		
		this.on_error = function() {
			self.error = true;
			if (self.callback && typeof self.callback == "function") {
				self.callback.apply(self, ["error"]);
			}
			self.cancelEvent();
		};
		
		this.on_abort = function() {
			self.aborted = true;
			if (self.callback && typeof self.callback == "function") {
				self.callback.apply(self, ["aborted"]);
			}
			self.cancelEvent();
		};
		
		this.image.src = this.file;
		
		this.autoCheckIntervalId = 0;
		this.autoCheck = function() {
			if (self.loaded || self.aborted || self.error) {
				window.clearInterval(self.autoCheckIntervalId);
				return;
			}
			
			if (self.image && self.image.complete) {
				window.clearInterval(self.autoCheckIntervalId);
				self.loaded = true;
				if (self.callback && typeof self.callback == "function") {
					self.callback.apply(self, ["loaded"]);
				}
				self.cancelEvent();
				return;
			}
			
			if (self.image && (self.image.width || self.image.height)) {
				window.clearInterval(self.autoCheckIntervalId);
				self.loaded = true;
				if (self.callback && typeof self.callback == "function") {
					self.callback.apply(self, ["loaded"]);
				}
				self.cancelEvent();
				return;
			}
		};
		
		this.autoCheckIntervalId = window.setInterval( self.autoCheck, 500 );
	};
	
	$.fn.carousel = function(options) {
		var isMethodCall = (typeof options == "string") || false;
		var args = arguments;
		
		if (isMethodCall) {
			var carousel = $(this[0]).data("carousel");
			if (carousel) {
				if ( carousel[options] && $.isFunction(carousel[options]) ) {
					return carousel[options].apply(carousel, $.makeArray(args).slice(1));
				}
			}
		}
			
		$(this).each(function() {
			var carousel = $(this).data("carousel");
			
			if (isMethodCall && carousel) {
				if ( carousel[options] && $.isFunction(carousel[options]) ) {
					return carousel[options].apply(carousel, $.makeArray(args).slice(1));
				}
			} else if (!isMethodCall) {
				if ( !carousel ) {
					carousel = new $.carousel(this, options);
					$(this).data("carousel", carousel);
				} else {
					carousel.setOptions(options);
				}
			}
		});
		
		return this;
	}
	
	$.carousel = function(elem, options) {
		this.elem = elem;
		this.options = $.extend( {}, $.carousel.defaults, options );
		this.init();
	};
	
	$.extend( $.carousel, {
		defaults: {
			loadingImage: "images/ajax-loader.gif",
			activeIndex: 0,
			slideDuration: 1200
		},
		prototype: {
			init: function() {
				this.slides_container = $(".carousel_images>ul", this.elem);
				this.slides = $(">li>a", this.slides_container);
				
				if ( this.options.activeIndex < 0 || this.options.activeIndex > this.slides.length-1 ) {
					this.options.activeIndex = 0;
				}
				
				if (this.slides.length > 0) {
					this.nav = $(".carousel_nav", this.elem);
					this.next = $(".carousel_nav a.next", this.elem);
					this.prev = $(".carousel_nav a.prev", this.elem);
					this.legend = $(".carousel_nav .legend", this.elem);
					
					if ( this.next || this.prev ) {
						this.setupNav();
					}
					
					this.nav_height = $(this.nav).innerHeight();
					this.nav.css({bottom:-this.nav_height+"px"});
					
					this.slide_width = $(">li:eq(0)", this.slides_container).outerWidth(true);
					
					this.slides_container.css({
						width: (this.slide_width * this.slides.length)+"px"
					});
					
					this.moveTo(this.options.activeIndex);
				}
			},
			
			setupNav: function(){
				var self = this;
				if ( this.next ) {
					this.next.bind("click", function(){
						this.blur();
						self.moveTo(self.current_index+1);
						return false;
					});
				}
				if ( this.prev ) {
					this.prev.bind("click", function(){
						this.blur();
						self.moveTo(self.current_index-1);
						return false;
					});
				}
				
				$(self.nav).css({display:"block",opacity:0});
				
				$(this.elem).bind("mouseover", function(){
					$(self.nav).stop();
					self.nav.animate({opacity:1}, {queue:false,duration:800,complete:function(){
						$(this).css({display:"block",opacity:""});
					}});
				});
				
				$(this.elem).bind("mouseout", function(){
					$(self.nav).stop();
					self.nav.animate({opacity:0}, {queue:false,duration:800,complete:function(){
					}});
				});
			},
			
			moveTo: function(idx) {
				if ( idx < 0 || idx > this.slides.length-1 ) return;
				
				this.slides_container.stop();
				this.slides_container.animate({left: (-1 * this.slide_width * idx) + "px" }, {
					queue:false,
					easing:"easeInOutExpo",
					duration:this.options.slideDuration
				});
				
				this.current_index = idx;
				
				if ( idx > 0 && this.prev ) {
					this.prev.attr("title", this.slides[idx-1].title).attr("href", "#" + this.slides[idx-1].parentId).removeClass("prev_disabled");
				} else {
					this.prev.attr("title", "").attr("href", "#").addClass("prev_disabled");
				}
				
				if ( idx < this.slides.length-1 && this.next ) {
					this.next.attr("title", this.slides[idx+1].title).attr("href", "#" + this.slides[idx+1].parentId).removeClass("prev_disabled");
				} else {
					this.next.attr("title", "").attr("href", "#").addClass("prev_disabled");
				}
			},
			
			moveNext: function(){
				var idx = this.current_index;
				this.moveTo(++idx);
			},
			
			movePrev: function(){
				var idx = this.current_index;
				this.moveTo(--idx);
			},
			
			isFirst: function(){
				return (this.current_index <= 0);
			},
			
			isLast: function(){
				return (this.current_index >= this.slides.length-1);
			}
		}
	});
	
	$.fn.carousel_thumbs = function(options) {
		var isMethodCall = (typeof options == "string") || false;
		var args = arguments;
			
		$(this).each(function() {
			var carousel_thumbs = $(this).data("carousel_thumbs");
			
			if (isMethodCall && carousel) {
				if ( carousel_thumbs[options] && $.isFunction(carousel_thumbs[options]) ) {
					carousel_thumbs[options].apply(carousel_thumbs, $.makeArray(args).slice(1));
				}
			} else if (!isMethodCall) {
				if ( !carousel_thumbs ) {
					carousel_thumbs = new $.carousel_thumbs(this, options);
					$(this).data("carousel_thumbs", carousel_thumbs);
				} else {
					carousel_thumbs.setOptions(options);
				}
			}
		});
		
		return this;
	}
	
	$.carousel_thumbs = function(elem, options) {
		this.elem = elem;
		this.options = $.extend( {}, $.carousel_thumbs.defaults, options );
		this.init();
	};
	
	$.extend( $.carousel_thumbs, {
		defaults: {
			loadingImage: "images/ajax-loader.gif",
			scrollItems:4,
			scrollPage:0,
			slideDuration: 1200
		},
		prototype: {
			init: function() {
				this.slides_container = $(".carousel_images>ul", this.elem);
				this.slides = $(">li>a", this.slides_container);
				
				this.scrollPageCount = Math.ceil(this.slides.length / this.options.scrollItems);
				
				if ( this.options.scrollPage < 0 || this.options.scrollPage > this.scrollPageCount-1 ) {
					this.options.scrollPage = 0;
				}
				
				if (this.slides.length > 0) {
					this.next = $("a.next", this.elem);
					this.prev = $("a.prev", this.elem);
					
					if ( this.next.length || this.prev.length ) {
						this.setupNav();
					}
					
					this.slide_width = $(">li:eq(0)", this.slides_container).outerWidth(true);
					this.parent_width = $(".carousel_images", this.elem).innerWidth();
					
					this.slides_container.css({
						width: (this.slide_width * this.slides.length)+"px"
					});
					
					this.setupSlides();
					
					this.moveTo(this.options.scrollPage);
					
					this.carousel = $($(".carousel_slideshow")[0]).data('carousel');
					
				}
				
			},
			
			setupNav: function(){
				var self = this;
				if ( this.next.length ) {
					this.next.bind("click", function(){
						this.blur();
						self.moveTo(self.current_index+1);
						return false;
					});
				}
				if ( this.prev.length ) {
					this.prev.bind("click", function(){
						this.blur();
						self.moveTo(self.current_index-1);
						return false;
					});
				}
			},
			
			setupSlides: function(){
				var self = this;
				this.slides.each(function(){
					$(this).bind("click", function(){
						this.blur();
						if ( $(this).is(".selected") ) return false;
						
						self.slides.filter(".selected").removeClass("selected");
						$(this).addClass("selected");
						
						if (self.carousel != undefined) {
							self.carousel['moveTo'].apply(self.carousel, [self.slides.index(this)]);
						}
						
						return false;
					});
				});
			},
			
			moveTo: function(idx) {
				if ( idx < 0 || idx > this.scrollPageCount-1 ) return;
				
				this.slides_container.stop();
				
				var x = 0;
				if (idx == this.scrollPageCount - 1){
					x = -1 * this.slides.length * this.slide_width;
					x += this.parent_width;
				} else if (idx == 0) {
					x = 0;
				} else {
					x = this.options.scrollItems * idx * this.slide_width * -1;
				}
				
				this.slides_container.animate({left: x + "px" }, {
					queue:false,
					easing:"easeInOutExpo",
					duration:this.options.slideDuration
				});
				
				this.current_index = idx;
				
				if ( idx > 0 && this.prev ) {
					this.prev.removeClass("prev_disabled");
					
				} else {
					this.prev.addClass("prev_disabled");
				}
				
				if ( idx < this.slides.length-1 && this.next ) {
					this.next.removeClass("prev_disabled");
				} else {
					this.next.addClass("prev_disabled");
				}
			}
		}
	});
	
	$().ready(function(){
		if ($(".carousel_slideshow").length) {
			$(".carousel_slideshow").carousel();
			$(".charts_thumb").carousel_thumbs();
		}
	});
})(jQuery);