/*
 * Roar - Notifications (Modified by: Brett)
 *
 * Inspired by Growl
 *
 * @version		1.0.1
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
*/

var Roar = new Class(
	{
		Implements:[Options,Events,Chain],
		options:
			{
				duration:9000,
				position:"upperLeft",
				container:null,
				bodyFx:null,
				itemFx:null,
				margin:{x:10, y:10},
				offset:10,
				className:"roar",
				onShow:$empty,
				onHide:$empty,
				onRender:$empty
			},
		initialize:function(options)
		{
			this.setOptions(options);
			this.items = [];
			this.container = $(this.options.container) || document;
		},
		alert:function(title, message, options)
		{
			var params = Array.link(arguments, {title:String.type, message:String.type, options:Object.type});
			var items = [new Element("h3", {"html":$pick (params.title, '')})];
			if (params.message == null)
				items[0].addClass("roar-no-title");
			if (params.message)
				items.push(new Element('p', {"html":params.message}));
			return this.inject(items, params.options);
		},
		inject:function(elements, options)
		{
			if (!this.body)
				this.render();
			options = options||{};
			this.options.duration = options.duration || this.options.duration;
			this.options.onClicked = options.onClicked || this.options.onClicked;

			var offset = [-this.options.offset, 0];
			var last = this.items.getLast();
			if (last) {
				offset[0] = last.retrieve("roar:offset");
				offset[1] = offset[0] + last.offsetHeight + this.options.offset;
			}
			var to = {};
			to["opacity"] = 1;
			if (!Browser.ie)
				to[this.align.y] = offset;
			else
				to[this.align.y] = offset[1];
			var item = new Element ("div",
				{
					"class":this.options.className,
					"opacity":0
				}).adopt(
					new Element("div",
						{
							"class":"roar-bg",
							"opacity":1
						}), elements);

			item.setStyle(this.align.x, 0).store("roar:offset", offset[1]).set("morph", $merge(
				{
					unit:"px",
					link:"cancel",
					onStart:Chain.prototype.clearChain,
					transition:Fx.Transitions.Back.easeOut
				}, this.options.itemFx));
			var remove = this.remove.create(
				{
					bind:this,
					arguments:[item],
					delay:10
				});
			this.items.push(item.addEvent("click", remove));

			if (this.options.duration && this.options.duration != -1) {
				var over = false;
				var trigger = (function()
					{
						trigger = null;
						if (!over)
							remove ();
					}).delay (this.options.duration);
				item.addEvents(
					{
						mouseover:function()
						{
							over = true;
						},
						mouseout:function()
						{
							over = false;
							if (!trigger)
								remove();
						}
					});
			}
			if (this.options.onClicked != undefined) {
				item.addEvent("click", function()
					{
						this.options.onClicked();
					}.bind(this));
			}
			if (!Browser.ie)
				item.inject(this.body).morph(to);
			else
				item.inject(this.body)
					.setStyles(to);
			return this.fireEvent("onShow", [item, this.items.length]);
		},
		remove:function(item)
		{
			var index = this.items.indexOf(item);
			if (index == -1)
				return this;
			this.items.splice(index, 1);
			item.removeEvents();
			var to = {};
			if (!Browser.ie)
				to["opacity"] = 0;
			to[this.align.y] = item.getStyle(this.align.y).toInt() - item.offsetHeight - this.options.offset;
			if (!Browser.ie)
				item.set("morph", {
					onComplete:function()
					{
						this.element.dispose();
					}}).morph(to);
			else
				item.dispose();
			return this.fireEvent("onHide", [item, this.items.length]).callChain(item);
		},
		empty:function()
		{
			while (this.items.length)
				this.remove(this.items[0]);
			return this;
		},
		render:function()
		{
			this.position = this.options.position;
			if ($type(this.position) == "string") {
				var position = {x:"center", y:"center"};
				this.align = {x:"left", y:"top"};
				if ((/left|west/i).test(this.position)) 
					position.x = "left";
				else if ((/right|east/i).test(this.position))
					this.align.x = position.x = "right";
				if ((/upper|top|north/i).test(this.position))
					position.y = "top";
				else if ((/bottom|lower|south/i).test(this.position))
					this.align.y = position.y = "bottom";
				this.position = position;
			}
			this.body = new Element("div", {"class":"roar-body"}).inject(document.body);
			if (Browser.Engine.trident4)
				this.body.addClass("roar-body-ugly");
			this.moveTo = this.body.setStyles.bind(this.body);
			this.reposition();
			if (this.options.bodyFx) {
				var morph = new Fx.Morph(this.body,
					$merge(
						{
							unit:"px",
							chain:"cancel",
							transition:Fx.Transitions.Circ.easeOut
						}, this.options.bodyFx));
				this.moveTo = morph.start.bind(morph);
			}
			if (!Browser.Engine.webkit && !Browser.Engine.presto && !Browser.Engine.gecko) {
				var repos = this.reposition.bind (this);
				window.addEvents (
					{
						"scroll":repos,
						"resize":repos
					});
			} else {
				this.body.setStyles(
					{
						"position":"fixed",
						"bottom":this.options.margin.y,
						"right":this.options.margin.x,
						"top":"",
						"left":""
					});
			}
			this.fireEvent("onRender", this.body);
		},
		reposition:function()
		{
			var max = document.getCoordinates(),scroll = document.getScroll(), margin = this.options.margin;
			max.left += scroll.x;
			max.right += scroll.x;
			max.top += scroll.y;
			max.bottom += scroll.y;
			var rel = ($type(this.container) == "element") ? this.container.getCoordinates() : max;
			this.moveTo(
				{
					left:(this.position.x == "right")
						? (Math.min(rel.right,max.right) - margin.x)
						: (Math.max(rel.left,max.left) + margin.x),
					top:(this.position.y == "bottom")
						? (Math.min(rel.bottom,max.bottom) - margin.y)
						: (Math.max(rel.top,max.top) + margin.y)
				});
		}
	});
