jQuery.fn.banner = function ( options ) {
	var settings = jQuery.extend({
		sleep: 60,
		path: "/wp-content/plugins/nextgen-gallery/xml/imagerotator.php?gid=",
		gid: 1,
		shuffle: false,
		link: null,
		transition: 1000,
		center: false
	}, options);
	
	// Target
	var target = this;
	var state = 0;
	var timeout;	

	// Images 	
	var imgsSrc = new function ( ) {
			this.ptr = 0;
			this.URLs = [];
			
			this.next = function() {
				var tmp = this.URLs[this.ptr];
				this.ptr = (this.ptr + 1) % this.URLs.length;
				return tmp;
			};
			
			this.shuffle = function() {
				this.URLs.sort(function() {
					return Math.random() - 0.5;
				});
			};
			
			this.add = function( v ) { this.URLs.push(v); };
		};
	
	var images = new function() {
		this.active = 0;
		this.last = 0;
		this.images = new Array();
	
		this.getNext = function() { return (this.active + 1) % this.images.length; };
		
		this.next = function () { this.active = this.getNext(); };
		
		this.load = function ( id, src, callback ) {
			if( this.images[id].src == '' ) {
				this.images[id].onload = function(){ callback(); };
				this.images[id].src = src.url;
				this.images[id].title = src.title;
			} else {
				callback();
			}
		};

		this.loadNext = function ( src, callback ) { this.load( this.getNext(), src, callback ); };

		this.loadActive = function ( src, callback ) { this.load( this.active, src, callback ); };
		
		this.showActive = function ( callback ) {
			this.centerImage( this.images[this.active] );
			jQuery(this.images[this.active]).fadeIn(settings.transition, callback);
			this.updateLink();
		};
				
		this.centerImage = function ( img ) {
			if(settings.center) {
				var left = Math.floor((target.width() - img.width) / 2 );
				var top = Math.floor((target.height() - img.height) / 2 );
				jQuery(img).css({'left': left, 'top': top});
			} 
		};
		
		this.swap = function ( callback ) {
			this.updateLink();
		
			// Center Image
			this.centerImage( this.images[this.getNext()] );
			
			// Fade out last image
			jQuery(this.images[this.active]).fadeOut(settings.transition, callback);
			
			// Fade in next image
			jQuery(this.images[this.getNext()]).fadeIn(settings.transition);
			
			jQuery('div.navi a:eq('+this.active+')', target).toggleClass('active');
			jQuery('div.navi a:eq('+this.getNext()+')', target).toggleClass('active');
		};
		
		this.updateLink = function( id ) {
			id |= this.getNext();
			var url;
					
			if( imgsSrc.URLs[id].link ) {
				url = imgsSrc.URLs[id].link;
			} else {
				url = settings.link;
			}
			
			jQuery('div.image a', target).attr('href', url );
		};
	}
	
	// Load playlist
	jQuery.get( settings.path + settings.gid, {}, function(xml) {
		jQuery("track", xml).each( function(i) { 
			imgsSrc.add( { url: jQuery(this).find("location").text(),
						title: jQuery(this).find('title').text(),
						link: jQuery(this).find('link').text() } ); 
		});
		
		if (settings.shuffle) {
			imgsSrc.shuffle();
		}
				
		buildImageArray();
		createImages();

		var navi;
		if( navi = jQuery('div.navi', target) ) {
			for( var i = 0; i < images.images.length; i++) {
				navi.append('<a></a>');
			}
		}
		jQuery('div.navi a:eq(0)', target).toggleClass('active');
		start();
	});
	
	
	function buildImageArray() { 
		for( i = 0; i < imgsSrc.URLs.length; i++ ) {
			var img = new Image();
			images.images.push( img );
		}
	}
	
	
	function createImages() {
		jQuery.each(images.images, function() {
			jQuery(this).css({ position: "absolute", top: "0px" }).hide();
			jQuery('div.images', target).append(this);
		});
		jQuery('div.images', target).wrapInner('<a href="'+settings.link+'"></a>');
		
	}


	function start() {
		images.loadActive( imgsSrc.next(), function(){images.showActive( dispatch );});
	}
	

	function dispatch ( ) {
		switch( state ) {
			case 0:		// Load Next Image
				state++;
				images.loadNext( imgsSrc.next(), dispatch );
				break;
			case 1: 	// Sleep Timeout
				state++;
				setTimeout( dispatch, settings.sleep * 1000 );
				break;
			case 2:		// Swap Images
				state++;
				images.swap( dispatch );
				break;
			case 3:
				state = 0;
				images.next();
				dispatch();
				break;
		}
	}
};