/*--------------------------------------------------------------------------*
 * 
 * Copyright (C) 2008-2010 Brand Labs LLC
 * 
 * Sequential Banner
 * 
 * Version 1.4.1
 * 
 *--------------------------------------------------------------------------*/
var EmptyBanner = Class.create({
	getElement: function() {
		return new Element('div');
	}
});

var PlainBanner = Class.create({
	DEFAULT_OPTIONS: {
		preLoadImage: true
	},
	
	/**
	 * 
	 * @param {Object} link
	 * @param {Object} imageSrc
	 */
	initialize: function(imageSrc) {
		this.imageSrc = imageSrc;
		this.imageElement = null;
		this.options = $H(this.DEFAULT_OPTIONS).merge($H(arguments[1] || {}));
		
		//See if need to pre-load image
		if(this.options.get('preLoadImage')) {
			//Immediately create image element
			this.createImageElement();
		}
	},
	
	createImageElement: function() {
		this.imageElement = new Element('img', {
			src: this.imageSrc
		});
	},
	
	/**
	 * 
	 */
	getElement: function() {
		if(this.imageElement == null) {
			this.createImageElement();
		}
		
		return this.imageElement;
	}	
});

var Banner = Class.create(PlainBanner, {
	/**
	 * 
	 * @param {Object} link
	 * @param {Object} imageSrc
	 */
	initialize: function($super, link, imageSrc) {
		$super(imageSrc, arguments[3] || {});
		this.link = link;
	},
	
	/**
	 * 
	 */
	getElement: function($super) {
		var anchorElement = null;		
		
		anchorElement = new Element('a', {href: this.link});		
		
		//Add the image under the anchor
		anchorElement.insert($super());
				
		return anchorElement;
	}
});

var ImageMapBanner = Class.create(PlainBanner, {
	/**
	 * 
	 * @param {Object} imageSrc
	 * @param {Object} useMap
	 */
	initialize: function($super, imageSrc, useMap) {
		$super(imageSrc, arguments[3] || {});
		this.useMap = useMap;
	},
	
	/**
	 * 
	 */
	getElement: function($super) {
		var imageElement = null;
		
		imageElement = $super();
		imageElement.writeAttribute('usemap', this.useMap);
		
		//Return the image element no anchor
		return imageElement;
	}
});

var SingleEventBanner = Class.create(PlainBanner, {
	/**
	 * 
	 * @param {Object} imageSrc
	 * @param {Object} eventName
	 * @param {Function} handler
	 */
	initialize: function($super, imageSrc, eventName, handler) {
		$super(imageSrc, arguments[4] || {});		
		this.eventName = eventName;
		this.handler = handler;
	},
	
	/**
	 * 
	 */
	getElement: function($super) {
		var imageElement = null;
		
		imageElement = $super();
		
		//Add the event handler to the image
		imageElement.observe(this.eventName, this.handler.bind(this));
				
		return imageElement;
	}
});

var AnchorBanner = Class.create(EmptyBanner, {	
	initialize: function(link, id, className, content) {
		this.link = link;
		this.id = id;
		this.className = className;
		this.content = content;
		
		this.element =  new Element('a', {href: this.link, id: this.id});
		this.element.addClassName(this.className);		
		this.element.insert(this.content);
	},
	
	getElement: function() {
		return this.element;
	}
});


var SequentialBanner = Class.create({
	DEFAULT_OPTIONS: {
		immediatelyExecute: false
	},
	
	/**
	 * 
	 * @param {Object} banners
	 * @param {Object} elementName
	 * @param {Object} delay
	 */
	initialize: function(banners, elementName, delay) {
		this.listeners = new Array();
		
		this.element = null;
		this.options = $H(this.DEFAULT_OPTIONS).merge($H(arguments[3] || {}));
		
		this.banners = banners;
		this.delay = delay;
		
		//Sequential, if immediately execute, change position to below first
		if(this.options.get('immediatelyExecute')) {
			this.currentPosition = -1;	
		}
		else {
			this.currentPosition = 0;
		}		
		
		Event.observe(window, 'load', this.load.bind(this, elementName));	
	},
	
	addListener: function(func) {
		//Only add if function
		if (Object.isFunction(func)) {
			//Push onto array
			this.listeners.push(func);
		}
	},
	
	/**
	 * 
	 */
	load: function(elementName) {
		try {
			//Get the element
			this.element = $(elementName);
			
			//Start the executer
			this.start();
			
			//See if requesting immediate execution
			if (this.options.get('immediatelyExecute')) {
				this.execute();
			}
		}
		catch(e){/*Ignore*/}
	},
	
	/**
	 * 
	 */
	start: function() {
		if(this.pe != null) {
			this.stop();				
		}
		this.pe = new PeriodicalExecuter(this.execute.bind(this), this.delay);			
	},
	
	/**
	 * 
	 */
	stop: function() {
		if(this.pe != null) {
			this.pe.stop();
			this.pe = null;
		}
	},
	
	/**
	 * 
	 */
	execute: function() {
		var index = null;
		var args = null;
		
		try {
			args = $A(arguments);
			
			//Check for an index argument
			if (args.size() > 0 && Object.isNumber(args.first())) {
				//Get the argument and set it as the current index
				index = args.first();
				this.currentPosition = index;
				this.stop();
				this.start();
			}
			else {
				this.currentPosition++;
				this.currentPosition = this.currentPosition % this.banners.size();
			}
			
			this.updateElement();
			
			//Inform listeners of change
			this.listeners.each(function(listener){
				try {
					listener(this.currentPosition);
				} 
				catch (e) {/*No-op*/
				}
			}, this);
		}
		catch(e){/*Ignore*/}
	},
	
	/**
	 * 
	 */
	updateElement: function() {
		this.element.update(this.banners[this.currentPosition].getElement());
	}
});

var RandomBanner = Class.create(SequentialBanner, {
	/**
	 * 
	 * @param {Object} banners
	 * @param {Object} elementName
	 * @param {Object} delay
	 */
	initialize: function(banners, elementName) {
		this.listeners = new Array();
		this.currentPosition = 0;
		this.element = null;
		
		this.banners = banners;

		//On window load, display a random image		
		Event.observe(window, 'load', this.load.bind(this, elementName));
	},
	
	/**
	 * 
	 */
	load: function(elementName) {
		//Get the element
		this.element = $(elementName);
		
		//Select random element
		this.currentPosition = Math.floor(Math.random() * this.banners.size());
		
		//Display element 
		this.execute();
	}	
});

var RandomSingleBanner = RandomBanner;

var RandomMultipleBanner = Class.create(SequentialBanner, {
	initialize: function($super, banners, elementName, delay) {
		$super(banners, elementName, delay, arguments[4] || {});
	},
	
	updateToRandomPosition: function() {
		var oldPosition = this.currentPosition;
		var counter = 0;
		
		//See if there is only one or less
		if(this.banners.size() < 2) {
			this.currentPosition = -1; /*Always added after*/
			return;
		}
		
		//Select random element
		while(true) {
			this.currentPosition = Math.floor(Math.random() * this.banners.size());
			if(this.currentPosition != oldPosition || counter >= 10) {
				break;
			}
			counter++;
		} 
		
		this.currentPosition = this.currentPosition - 1 /*Always added after*/;
	},
	
	load: function($super, elementName) {
		this.updateToRandomPosition();
		this.currentPosition++;
		$super(elementName);		
	},
		
	execute: function($super) {
		this.updateToRandomPosition();		
		$super();
	}
});

var MethodsTransitionBanner = {
	TOP_Z_INDEX: 1001,
	BOTTOM_Z_INDEX: 1000,
	
	initialize: function($super, banners, elementName, delay) {
		$super(banners, elementName, delay, arguments[4] || {});
		
		this.lastTransitionElement = null;
	},
	
	updateElement: function() {
		var elementEmpty = false;
		var transitionElement = null;
		var oldTransitionElement = null;

		try {
			elementEmpty = this.element.empty();
			
			//Create new transition element		
			transitionElement = new Element('div');
			transitionElement.setStyle({
				'position': 'absolute',
				'display': 'none',
				'zIndex': this.TOP_Z_INDEX,
				'overflow': 'hidden'
			});
			
			//Add content to element
			transitionElement.insert(this.banners[this.currentPosition].getElement());
			//Add to the main element
			this.element.insert(transitionElement);
			
			//Copy position of main element
			transitionElement.clonePosition(this.element, {
				setTop: false,
				setLeft: false
			});
			
			//See if a previous element exists
			if (this.lastTransitionElement == null) {
				if (elementEmpty) {
					this.lastTransitionElement = new Element('div');
					this.element.insert(this.lastTransitionElement);
				}
				else {
					this.lastTransitionElement = this.element.down();
				}
				//If something is available, put it in a wrapper
				if (this.lastTransitionElement != null) {
					var wrapperElement = new Element('div');
					wrapperElement.setStyle({
						'position': 'absolute',
						'zIndex': this.BOTTOM_Z_INDEX,
						'overflow': 'hidden',
						'width': transitionElement.getWidth() + 'px',
						'height': transitionElement.getHeight() + 'px'
					});
					this.lastTransitionElement.wrap(wrapperElement);
					this.lastTransitionElement = wrapperElement;
				}
			}
			else {
				//Change
				this.lastTransitionElement.setStyle({
					'zIndex': this.BOTTOM_Z_INDEX
				});
			}
			
			//Show the new element and remove the old one
			oldTransitionElement = this.lastTransitionElement;
			this.lastTransitionElement = transitionElement;
			//Show the new element using a transition or not
			this.show(transitionElement, oldTransitionElement);
		}
		catch(e){/*Ignore*/}
	},
	
	show: function(newElement, oldElement) {
		newElement.show();
		if(oldElement != null) {
			oldElement.hide();
			oldElement.remove();
		}
	}
};
var TransitionSequentialBanner = Class.create(SequentialBanner, MethodsTransitionBanner);
var TransitionRandomMultipleBanner = Class.create(RandomMultipleBanner, MethodsTransitionBanner);

var MethodsFadeTransitionSequentialBanner = {
	DELAY: 1.5,
	
	show: function(newElement, oldElement) {
		Effect.Appear(newElement, {
			duration: this.DELAY,
			queue: 'end',
			afterFinish: function() {
				if(oldElement != null) {
					oldElement.hide();
					oldElement.remove();
				}
			}
		});
	}
};
var FadeTransitionSequentialBanner = Class.create(TransitionSequentialBanner, MethodsFadeTransitionSequentialBanner);
var FadeSequentialBanner = FadeTransitionSequentialBanner;
var FadeTransitionRandomMultipleBanner = Class.create(TransitionRandomMultipleBanner, MethodsFadeTransitionSequentialBanner);
