Function.prototype.Extends = function(base)
{
	for (var prop in base.prototype)
	{
		this.prototype[prop] = base.prototype[prop];
	}
	return this;
};

Function.prototype.Bind = function(object)
{
	var func = this;
	return	function()	{
				func.apply(object, arguments);
			};
};

//////////////////////////////////////////////////////////////
// RadEffect		
RadEffect = {};		

RadEffect.Create = function()
{
	return function() 
	{
		this.Initialize.apply(this, arguments);
	}
};

//////////////////////////////////////////////////////////////
// RadEffect.Base
//	Parameters:
//		- fps - 1-100
//		- duration - effect duration
//		- sync - true for several effects to run synchroniously (driven by RadEffect.Parallel)

RadEffect.Base = function() { };

RadEffect.Base.prototype.Initialize = function()
{
	var params = arguments[0] || {};
	
	params.fps = params.fps || 25;
	params.duration = params.duration || 1;
	
	this.Params = params;
	
	if (!params.sync)
	{	
		this.Start();
	}
};

RadEffect.Base.prototype.Start = function()
{
	var params = this.Params;
	
	if (this.OnStart)
	{
		this.OnStart();
	}
	
	if (params.beforeStart)
	{
		params.beforeStart();
	}
	
	this.Frame = 0;
	this.StartTime = new Date().getTime();	
	this.EndTime = this.StartTime + (params.duration * 1000);
	
	this.Loop();
};

RadEffect.Base.prototype.SetToStop = function()
{
	this.toStop = true;
};

RadEffect.Base.prototype.Loop = function()
{
	var params = this.Params;
	var toStop = this.toStop;
	
	var time = new Date().getTime();
	var frame = Math.round((time - this.StartTime) * params.fps / 1000);
	if (frame > this.Frame && !toStop)
	{
		this.Frame = frame;		
		var pos = Math.min((time - this.StartTime) / (this.EndTime - this.StartTime), 1);
		toStop = this.Update(pos) || (time >= this.EndTime);
	}
	
	if (!toStop)	
	{
		this.Timer = setTimeout(this.Loop.Bind(this), 20);
	}
	else
	{
		this.Stopped();
	}
};

// Return true if you want to stop the effec
RadEffect.Base.prototype.Update = function(pos)
{
	return true;
};

RadEffect.Base.prototype.Stopped = function()
{
	if (this.Params.afterFinish)
	{	
		this.Params.afterFinish();
	}
};

//////////////////////////////////////////////////////////////
// RadEffect.Batch
//	Parameters:
//		- effects - array of effects to run
//
RadEffect.Batch = RadEffect.Create();
RadEffect.Batch.Extends(RadEffect.Base);

RadEffect.Batch.prototype.OnStart = function()
{
	this.Params.duration = 100000;
	
	this.startEffect = true;
	this.effectIndex = 0;
};

RadEffect.Batch.prototype.Update = function(pos)
{
	var effects = this.Params.effects;
	if (this.startEffect)
	{
		effect = effects[this.effectIndex];
		if (effect)
		{
			effect.Start();
			effect.Params.afterFinish = this.StartNext.Bind(this);
			
			this.startEffect = false;
			this.effectIndex++;
		}
	}	
	return (this.startEffect && null == effects[this.effectIndex]);
};

RadEffect.Batch.prototype.StartNext = function()
{
	this.startEffect = true;
};

//////////////////////////////////////////////////////////////
// RadEffect.Parallel
//	Parameters:
//		- effects - array of effects to run
//
RadEffect.Parallel = RadEffect.Create();
RadEffect.Parallel.Extends(RadEffect.Base);

RadEffect.Parallel.prototype.OnStart = function()
{
	var effects = this.Params.effects;
	for (var i = 0; i < effects.length; i++)
	{
		effects[i].OnStart();
	}
};

RadEffect.Parallel.prototype.Update = function(pos)
{
	var effects = this.Params.effects;
	for (var i = 0; i < effects.length; i++)
	{
		effects[i].Update(pos);
	}
};

//////////////////////////////////////////////////////////////
// RadEffect.MoveTo		
RadEffect.MoveTo = RadEffect.Create();
RadEffect.MoveTo.Extends(RadEffect.Base);

RadEffect.MoveTo.prototype.OnStart = function()
{
	var params = this.Params;
	this.object = params.object;
	
	this.object.position = "absolute";
	
	var rect = params.object.GetRect();
	
	this.X = rect.left;
	this.Y = rect.top;
	
	this.destX = (null != params.destX ? params.destX : rect.left);
	this.destY = (null != params.destY ? params.destY : rect.top);
	
	this.diffX = (this.destX - this.X);
	this.diffY = (this.destY - this.Y);
};

RadEffect.MoveTo.prototype.Update = function(pos)
{
	var params = this.Params;
	var object = this.object;
	
	var x = this.X + pos * this.diffX;
	var y = this.Y + pos * this.diffY;
	
	//params.object.MoveTo(x, y);	//params.object.MoveTo(Math.floor(x), Math.floor(y));	 
	
	object.style.left = x + "px";
	object.style.top = y + "px";
	if (object.Overlay) 
	{
		object.Overlay.style.left = object.style.left;
		object.Overlay.style.top = object.style.top;
	}
};

//////////////////////////////////////////////////////////////
//	RadEffect.Resize
//	Params:
//		- object - to resize
//		- width - destination width
//		- height - destination height

RadEffect.Resize = RadEffect.Create();
RadEffect.Resize.Extends(RadEffect.Base);

RadEffect.Resize.prototype.OnStart = function()
{
	var params = this.Params;	
	var object = params.object;

	this.width = parseInt(object.style.width || object.clientWidth);
	this.height = parseInt(object.style.height || object.clientHeight);
	
	params.width = parseInt(null != params.width ? params.width : this.width);
	params.height = parseInt(null != params.height ? params.height : this.height);
	
	if (params.width < 0)
	{
		params.width = 0;
	}
	
	if (params.height < 0)
	{
		params.height = 0;
	}
	
	this.dWidth = (params.width - this.width);
	this.dHeight = (params.height - this.height);
};

RadEffect.Resize.prototype.Update = function(pos)
{
	var params = this.Params;
	var object = params.object;
	
	var w = this.width + pos * this.dWidth;
	var h = this.height + pos * this.dHeight;
	
	object.style.width = Math.floor(w) + "px";
	object.style.height = Math.floor(h) + "px";
	
	if (object.Overlay) 
	{
		object.Overlay.style.width = object.style.width;
		object.Overlay.style.height = object.style.height;
	}

	/*
	
	var node;
	for (var i = 0; i < object.childNodes.length; i++)
	{
		node = object.childNodes[i];
		if (node.style)
		{
			node.style.width = object.style.width;
			node.style.height = object.style.height;
		}
	}*/
};

//BEGIN_ATLAS_NOTIFY
if (typeof(Sys) != "undefined")
{
    if (Sys.Application != null && Sys.Application.notifyScriptLoaded != null)
    {
        Sys.Application.notifyScriptLoaded();
    }
}
//END_ATLAS_NOTIFY
