
if(typeof Widget == "undefined") Widget = {};
/**
 * The Widget.Fader class constructor. <br />
 * @constructor Widget.Fader
 * @param {string|img element} img The id of or actual image element to be faded
 * @param {array(string)} list  An array of paths (relative or absolute) of the images
 * @param {object} [options] An object of options.
 */
Widget.LinkedFader = Class.create(/** @scope Widget.LinkedFader **/{
	initialize: function(img, items, options) {
		this.img = $(img);

		var list = new Array();
		var links = new Array();
		items.each(function(e) {
			list.push(e.img);
			links.push({link:e.link, target:e.target});
		});
		this.list = list;
		this.links = links;

/*
		this.list = list;
		this.links = links;
*/
		this.img.observe('click',this.handleClick.bind(this));
		this.img.setStyle({'cursor':'pointer'});
		/**
		 * The default options object.
		 * @class
		 * @param {string} [id] The id used as queue scope. (default: img.id)
		 * @param {float} [fadeInDuration] The time in seconds of the fade in. (default: 2.5)
		 * @param {float} [fadeOutDuration] The time in seconds of the fade out. (default: 1.5)
		 * @param {float} [displayDuration] The time in seconds that the image is not faded out after being faded in. (default: 2.5)
		 * @param {bool} [autoSize] Set true if the image should be sized to it's container. Maintains aspect ratio. (default: false)
		 * @param {bool} [autoStart] If false the Blender will not start until Blender#start is called. (default: true)
		 * @param {object} [attributes] An associative array of attributes given to the image. (default: {})
		 * @param {string} [dir] The directory that all images reside in. Used as a prefix for the image src. (default: null)
		 * @param {function} [beforeFade] A function that is called before the image is faded. 2 parameters are passed: 1. the image; 2. a boolean indicating if the image is being faded in (true) or out (false) (default: null)
		 * @param {int} [startIndex] The index of the first new image to be shown. (default: 0)
		 * @param {function} [builder] The function called to build the items. (default: Widget.Fader.imageBuilder)
		 */
		this.options = Object.extend({
			id: this.img.id,
			fadeInDuration: 2.5,
			fadeOutDuration: 1.5,
			displayDuration: 2.5,
			autoSize: false,
			autoStart: true,
			attributes: {},
			dir: "",
			beforeFade: null,
			startIndex: 0,
			builder: Widget.LinkedFader.imageBuilder
		}, options || {});
		this.options.attributes["id"] = this.options.id;

		this.index = this.options.startIndex;
		this.container = $(this.img.parentNode);
		this.loadedObserver = this.loaded.bind(this);
		this.fadeInObserver = this.fadeIn.bind(this);
		this.nextObserver = this.next.bind(this);

		if(this.options.autoStart) {
			setTimeout(this.start.bind(this), this.options.displayDuration * 1000);
		}
	},
	/**
	 * Starts the fading if the autoStart option was set to false or after a call to stop.
	 * @function
	 */
	start: function() {
		this.stopped = false;
		this.next();
	},
	/**
	 * Stops the fading and sets the opacity of the current image to 100%.
	 * @function
	 */
	stop: function() {
		this.stopped = true;
		try { clearTimeout(this.timeout); } catch(ex) { }
		try { Effect.Queues.get(this.options.id).each(function(effect) { effect.cancel() }) } catch(ex) { }
		if(this.oldImg) {
			this.img = this.oldImg;
			--this.index;
		}
		Element.setOpacity(this.img, 1);
	},
	/**
	 * Loads the next image in list
	 * @private
	 * @function
	 */
	next: function() {
		this.oldImg = this.img;
		if(this.stopped || this.list.length == 0) {
			return;
		}
		++this.index;
		if(this.index >= this.list.length) {
			this.index = 0;
		}
		/*this.img = new Element("img", this.options.attributes);
		Event.observe(this.img, "load", this.loadedObserver);
		this.img.src = this.options.dir + this.list[this.index];*/
		this.img = this.options.builder(this, this.list[this.index], this.loadedObserver);
		this.img.observe('click',this.handleClick.bind(this));
		this.img.setStyle({'cursor':'pointer'});

	},

	handleClick: function() {
		l = this.links[this.index];
		if ((l.link == "") || (l.link == null)) {
			return;
		}
		if ((l.target == "") || (l.target == null)) {
			self.location.href = l.link;
		} else {
			window.open(l.link, l.target);
		}
	},

	/**
	 * Event listener for image loaded
	 * @private
	 * @function
	 */
	loaded: function() {
		Event.stopObserving(this.img, "load", this.loadedObserver);
		if(typeof this.options.beforeFade == "function") {
			this.options.beforeFade(this.oldImg, false);
		}
		new Effect.Opacity(this.oldImg, { duration: this.options.fadeOutDuration, from: 1.0, to: 0.0, queue: { scope: this.options.id } });
		this.timeout = setTimeout(this.fadeInObserver, this.options.fadeOutDuration * 1000);
	},
	/**
	 * Event listener for fadeIn
	 * @private
	 * @function
	 */
	fadeIn: function() {
		if(typeof this.options.beforeFade == "function") {
			this.options.beforeFade(this.img, true);
		}
		this.img.id = this.id;
		Element.setOpacity(this.img, 0);
		if(this.options.autoSize) {
			this.resize(this.img);
		}
		this.container.replaceChild(this.img, this.oldImg);
		this.oldImg = null;
		new Effect.Opacity(this.img, { duration: this.options.fadeInDuration, from: 0.0, to: 1.0, queue: { scope: this.options.id } });
		this.timeout = setTimeout(this.nextObserver, (this.options.fadeInDuration + this.options.displayDuration) * 1000);
	},
	/**
	 * Resize the image to the container while maintaining aspect ratio
	 * @private
	 * @function
	 */
	resize: function(img) {
		var dim = this.container.getDimensions();
		dim.width -= parseInt(this.container.getStyle("padding-left")) +
			parseInt(this.container.getStyle("padding-right")) +
			parseInt(this.container.getStyle("border-left-width")) +
			parseInt(this.container.getStyle("border-right-width"));
		dim.height -= parseInt(this.container.getStyle("padding-top")) +
			parseInt(this.container.getStyle("padding-bottom")) +
			parseInt(this.container.getStyle("border-top-width")) +
			parseInt(this.container.getStyle("border-bottom-width"));

		var dw = dim.width / img.width;
		var dh = dim.height / img.height;
		var w1 = img.width * dh;
		var h1 = img.height * dw;

		if(dw > dh) {
			img.width = w1;
			img.height = dim.height;
		} else {
			img.width = dim.width;
			img.height = h1;
		}
	}
});

/**
 * Builds an image item out the item passed by fader.
 * This is the default builder.
 * @function
 * @param {object} fader The calling Widget.Fader
 * @param {object} item The current item
 * @param {object} loaded A callback bound to the fader for when the item has loaded.
 **/
Widget.LinkedFader.imageBuilder = function(fader, item, loaded) {
	var img = new Element("img", fader.options.attributes);
	img.observe("load", loaded);
	img.src = fader.options.dir + item;
	return img;
};

/**
 * Builds div containing the text from the item passed by fader.
 * The Widget.Fader.options.dir is ignored.
 * @function
 * @param {object} fader The calling Widget.Fader
 * @param {object} item The current item
 * @param {object} loaded A callback bound to the fader for when the item has loaded.
 **/
Widget.LinkedFader.textBuilder = function(fader, item, loaded) {
	var div = new Element("div", fader.options.attributes).update(item);
	loaded.defer();
	return div;
};

/**
 * @class
 * @deprecated
 **/
var LinkedFader = Widget.LinkedFader;
