var BannerPool = function(configParams, callback){
    //default settings for the carousel
    var config = {
        container : null, //html element that contains the banner items
		rotationspeed : 5, //rotation speed in seconds
		animationspeed : 750, //animation speed in  milliseconds
		startindex : 0,	//index to show first
		autostart : true, //determines wheter to autostart animating
		pauseonmouseover : true, //stops the animation while the cursor is over the banner
		allowoverrulesizes : false, //may the banner items stretch the containeritem if they are bigger
		debuglogger : function(){}, //default logging object
        callback    : function(){},
                
        bind : function(params, callback){
            if(params){
                for(param in params){
                    eval("config." + param + " = params." + param);
                }
            }
            if(typeof(callback) == "function"){
                config.callback = callback;
            }
            //config binding done
            config.init = true;
        },
        init : false, //determines if the binding of config is done
        dummy : null //to not forget the appending of the extra , after the last variable
    }; 
    //bind the configuration
    config.bind(configParams, callback);
        
    //private methods and variables for object
    var priv = {
        currentItem : null,
		currentIndex : 0,
		items : new Array(),
		itemHeight : 0,
		itemWidth : 0,
		locked : false,
		rotating : false,
		timer : null,
		timerremain : 0,
		timeToNextStep : config.rotationspeed,
		
        init : function(){
            //test whether we actually have a valid container element, that actually contains items
			if(!config.container && $(config.container).children().length > 0){
				config.debuglogger("Banner: No container element or banner items found.");
				return;
			}
			
			//first determine all the banner items and store them in the array
			priv.items = $(config.container).children();
			
			//make sure the startindex actually exists
			config.startindex = Math.min(config.startindex, priv.items.length-1);
			priv.currentIndex = config.startindex;
			
			//make sure the rotationspeed is >= animationspeed
			config.rotationspeed = Math.max(config.rotationspeed, (config.animationspeed + 100)/1000);
			priv.timeToNextStep = config.rotationspeed*1000;
			
			//now determine the heighest element and set the parent element to this height
			if(config.allowoverrulesizes){
				priv.itemHeight = 0;
				priv.itemWidth = 0;
			
				$(priv.items).each(
					function(index){
						priv.itemHeight = Math.max($(this).height(), priv.itemHeight);
						priv.itemWidth = Math.max($(this).height(), priv.itemHeight);
						config.debuglogger("Banner height: " + priv.itemHeight + "\nWidth: " + priv.itemWidth);
					}
				);
			}
			
			//now set the default styles
			priv.setItemDefaults();
						
			if(config.autostart){
				priv.start();
			}
			
        },
				
		//does the actual animation
		move : function(newIndex){		
			//first test whether the new index actually exists
			if(newIndex >= priv.items.length){
				//non existent item... do nothing
				config.debuglogger("Banner: not moving. Reason: non existing item");
				return;
			}
			//if newIndex is the same as currentIndex do nothing
			if(newIndex == priv.currentIndex){
				config.debuglogger("Banner: not moving. Reason: Same index.");
				return;
			}
			//make sure we are not locked
			if(priv.locked){
				//we are currently locked by another animation, do nothing
				config.debuglogger("Banner: not moving. Reason: locked.");
				return;
			}
			//lock for other moves
			priv.locked = true;
			
			config.debuglogger("Banner: moving. CurrentIndex: " + priv.currentIndex + ", NewIndex: " + newIndex);
			
			//(re)set the time to next step, for continue after mouseover/mouseleave actions
			priv.timerremain = new Date();
			priv.timeToNextStep = config.rotationspeed*1000;
			
			//now make the animation
			//make sure we have the new element starting at top z-index and opacity = 0
			$(priv.items[newIndex]).css({"z-index" : "10"});
			//position the current element at second z-index level
			$(priv.items[priv.currentIndex]).css({"z-index" : "5"});
						
			//now fadeIn the new element
			$(priv.items[newIndex]).fadeIn(config.animationspeed, 
				function(){
					
					//on callback unlock
					priv.locked = false;
					//reset the z-index and opacity to defaults
					$(priv.items[priv.currentIndex]).hide().css({"z-index" : "1"});
					
					//set the new currentIndex
					priv.currentIndex = newIndex;
					priv.currentItem = priv.items[newIndex];
					
					//make the callback after finishing
					config.callback();
				}
			);
		},
		
		start : function(continueAnimating){
			config.debuglogger("Banner: Starting rotation");
			//first clearany existing timer
			priv.clear();
			
			priv.rotating = true;
			priv.timerremain = new Date();
			
			//if we continue from a previous stop, make sure to start from the remaining time first
			if((typeof(continueAnimating) != "undefined" && continueAnimating == true)
				&&
				priv.timeToNextStep > 0){
					//set the action on after first run
					var moveNextAndStart = function(){
						priv.next();
						priv.start();
					}
					
					priv.timer = window.setTimeout(moveNextAndStart, Math.min(priv.timeToNextStep, (config.rotationspeed*1000)));
					config.debuglogger("Banner: Moving next in: " + priv.timeToNextStep + "ms");
					return;
			}
						
			//set the regular timer
			priv.timer = window.setInterval(priv.next, config.rotationspeed*1000);
		},
		
		stop : function(continueAnimating){
			config.debuglogger("Banner: Stopping rotation");
			priv.clear();
			//if continueAnimating is true, make sure it starts up again on mouseleave
			if(typeof(continueAnimating) == "undefined" || continueAnimating == false){
				config.debuglogger("Banner: Stop the rotating, continueAnimating : " + continueAnimating);
				priv.rotating = false;
			}
			else {
				//set the remaining time to the next step if we continue after mouseover/leave events
				var now = new Date();
				priv.timeToNextStep -= (now - priv.timerremain);
				config.debuglogger("Banner: timetonextstep: " + priv.timeToNextStep);
				priv.timerremain = new Date();
			}
		},
		
		//clears  the timer
		clear  : function(){
			try {
                window.clearInterval(priv.timer);
                priv.timer = null;
            }
            catch(err){
                //for IE when timer hsa not been initialized
                priv.timer = null;
            }
			try {
                window.clearTimeout(priv.timer);
                priv.timer = null;
            }
            catch(err){
                //for IE when timer hsa not been initialized
                priv.timer = null;
            }
        },
		
		next : function(){
			var newIndex;
			//determine the next index:
			if(priv.items.length == 0 || priv.items.length == 1){
				//if we have no elements, or but one, do nothing
				return;
			}
			else if(priv.currentIndex + 1 < priv.items.length){
				//if we have a next object, go there
				newIndex = priv.currentIndex + 1;
			}
			else {
				//go to the first item
				newIndex = 0;
			}
			
			priv.move(newIndex);
		},
		
		prev : function(){
			var newIndex;
			//determine the next index:
			if(priv.items.length == 0 || priv.items.length == 1){
				//if we have no elements, or but one, do nothing
				return;
			}
			else if(priv.currentIndex - 1 >= 0){
				//if we have a previous object, go there
				newIndex = priv.currentIndex - 1;
			}
			else {
				//go to the last item
				newIndex = priv.items.length - 1;
			}
			
			priv.move(newIndex);
		},
		
		//sets the styles needed for the banners to function correctly
		setItemDefaults	: function(){			
			//first set the default styles for the container and items, needed to function correclty
			if(priv.itemHeight > 0){
			    $(config.container).height(priv.itemHeight);
			}
			if(priv.itemWidth > 0){
			    $(config.container).width(priv.itemWidth);
			}
			
			$(config.container).css({"overflow" : "hidden", "position" : "relative"});
			priv.items.hide().css({"position" : "absolute", "z-index" : "1"});
			$(priv.items[priv.currentIndex]).show().css({"z-index" : "10"});
			
			//now bind the default events
			//bind pause on mouseover
			$(config.container).hover(
				function(evt){
					if(config.pauseonmouseover && priv.rotating){
						//stop, but make sure we keep priv.rotating set to true so it starts again after mouseleave
						priv.stop(true);
					}
				},
				function(evt){
					if(config.pauseonmouseover && priv.rotating){
						//start, and make sure we we resume were we where at stop
						priv.start(true);
					}
				}
			);
		},
		
		
		
        dummy : null //to not forget the appending of the extra , after the last variable
    };
    priv.init();
   
    //public methods for the object
    return {
        Start : function(){
			priv.start();
		},
		
		Stop : function(){
			priv.stop();
		},
		
		Next : function(){
			priv.next();
		},
		
		Prev : function(){
			priv.prev();
		},
		
		To : function(newIndex){
			priv.move(newIndex);
		},
        
        dummy : null //to not forget the appending of the extra , after the last variable
    }
};

