/*
Author: jcyuan.space@gmail.com
for the banner in the home page and other places.
@2011 1.13

usage:
	new SlideBox(name).setParent(id).bindData([{title:'', desc:'', image:''}]).draw().start();
*/

var SlideBox = new Class({
	name:'',
	parent:null,
	interval : 3000,
	speed : 1000,
	viewable : 4,
	cursor : 0,
	data : null,
	pairs : null,
	initialize : function(name, parentID)
	{
		this.name = name || ("slidebox_" + (+new Date));
		this.pairs = [];
		this.setParent(parentID);
		return this;
	},
	setParent : function(id)
	{
		this.parent = $(id);
		return this;
	},
	setSpeed : function(speed)
	{
		if(typeOf(speed) == 'number' && speed > 0)
			this.speed = speed;
		return this;
	},
	setSwitchInterval : function(interval)
	{
		if(typeOf(interval) == 'number' && interval > 0)
			this.interval = interval;
		return this;
	},
	setViewableCount : function(count)
	{
		if(typeOf(count) == 'number' && count > 0)
			this.viewable = count;
		return this;
	},
	bindData : function(data)
	{
		var ty = typeOf(data);
		if(ty == 'array')
			this.data = data;
		else if(ty == 'object')
			this.data = [data];
		return this;
	},
	refresh : function()
	{
		this.pairs.empty();
		if(this.cursor > this.data.length - 1)
			this.cursor = this.data.length - 1;
		this.container.dispose();
		
		return this.draw().start();
	},
	draw : function()
	{
		if(typeOf(this.parent) != 'element')
		{
			throw new Error('no parent found, please set one first by calling setParent(id)');
			return;
		}
		this.container = new Element('div', {'id':this.name, 'class':'slidebox_style'});
		this.box = new Element('div', {'class':'container'});
		this.bar = this.__generateSideBar();
		this.loading = new Element('em', {'class':'loading'}).setOpacity(0).setStyle('z-index', 5);
		this.container.appendChild(this.loading);
		this.container.appendChild(this.box);
		this.container.appendChild(this.bar);
		this.container.inject(this.parent, 'top');
		return this;
	},
	start : function()
	{
		if(this.pairs.length <= 0)return;
		this.resetTimer(true);
		this.__autoSlide();
	},
	showImage : function(idx)
	{
		this.busy = true;
		
		//hide the last one
		if(this.lastImage && this.lastImage.status == 'loaded')
			this.lastImage.element.setStyle('z-index', 1);
		
		//show the new one
		var obj = this.pairs[idx].image;
		if(!obj)
		{
			this.resetTimer();
			return;
		}
		this.preloadImage(obj);
	},
	switchImage : function(imgobj)
	{
		imgobj.element.setStyle('z-index', 2);
		new Fx.Tween(imgobj.element, {
			'link':'cancel',
			'duration':this.speed,
			'transition':'quad:in:out',
			'onComplete':this.__imageFadingDone.pass(imgobj, this)
		}).start('opacity', 1);
	},
	resetTimer : function(stop)
	{
		this.timer = clearTimeout(this.timer);
		if(stop !== true)
			this.timer = this.__autoSlide.delay(this.interval, this);
	},
	/*private methods below, do not call them anywhere*/
	__generateSideBar : function()
	{
		var el = new Element('div', {'class':'sidebar'}).setStyle('z-index', 4);
		el.setOpacity(.85);
		var ul = new Element('ul');
		this.data.each(function(o, n)
		{
			if(o.image && o.title)
			{
				var li = new Element('li');
				var icn = new Element('em');
				var pDsc = new Element('p');
				pDsc.appendText(o.desc || "");
				var h1 = new Element('h1');
				h1.appendText(o.title);
				
				li.appendChild(icn);
				li.appendChild(h1);
				li.appendChild(pDsc);
				li.index = n;
				
				li.addEvent('click', function(e)
				{
					var userclicked = false;
					if(e){ e.stop(); userclicked = true; }
					if(this.busy)return;
					this.__mouseevent(li, userclicked);
					
				}.bind(this));
				
				ul.appendChild(li);
				
				this.pairs.push({header:li, image:{addr:o.image, link:o.url, status:'default',element:null}});  //status:'loading', 'loaded', 'default', 'error'
			}
		}, this);
		el.appendChild(ul);
		return el;
	},
	__mouseevent : function(li, userclicked)
	{
		if(li == this.lastActived)
			return;
		
		this.resetTimer(true);
		
		if(this.lastActived)
			this.lastActived.removeClass('active');
			
		this.cursor = (userclicked === true) ? (li.index + 1) : li.index; //+1 for next loop
		
		this.lastActived = li;
		li.addClass('active');
		
		this.showImage(li.index);
	},
	__autoSlide : function()
	{
		if(this.pairs.length < 0)return;
		if(this.cursor > this.pairs.length - 1)
			this.cursor = 0;
		this.pairs[this.cursor].header.fireEvent('click');
		this.cursor++;
	},
	__imageFadingDone : function(cur)
	{
		if(this.lastImage && this.lastImage.status == 'loaded')
			this.lastImage.element.setOpacity(0).setStyle('z-index', '');
		
		this.lastImage = cur;
		this.busy = false;
		
		this.resetTimer();
	},
	/*********image loader**********/
	preloadImage : function(imgobj)
	{
		
		if(imgobj.status == 'loaded')
		{
			this.switchImage(imgobj);
			return;
		}
		else
		{
			this.loading.fade(0.4);
			
			imgobj.status = 'loading';
			imgobj.element = new Asset.image(imgobj.addr, {
				title:'',
				alt:'',
				onload:this.imageloaded.pass(['loaded', imgobj], this),
				onerror:this.imageloaded.pass(['error', imgobj], this),
				onabort:this.imageloaded.pass(['abort', imgobj], this)
			});
		}
	},
	imageloaded : function(status, obj)
	{
		this.loading.fade('out');
		
		obj.status = (status == 'loaded') ? 'loaded' : 'error';
		if(status == 'loaded')
		{
			obj.element.setOpacity(0);
			
			if(typeOf(obj.link) == "string" && obj.link.length > 0)
			{
				var a = new Element("a", {href:obj.link, target:"_blank"});
				obj.element.inject(a);
				a.inject(this.box);
			}
			else
				obj.element.inject(this.box);
		}
		this.switchImage(obj);
	}
});
