/*
** Evonux 2005
** evJSAnim
**
** All rights reserved
*/

Evonux.NONE = -1;
Evonux.INFINITY = -2;

Evonux._calcPowerLevel = -1; // 1 to 100%
Evonux._mouseX = 0;
Evonux._mouseY = 0;
Evonux._obj = new Array(); // Associate list for loaded evonux capabilities enabled objects
Evonux._idPrefix = 'evonuxObj';
Evonux._idCnt = 0;
// Clock rythm
Evonux._clockInterval = Math.floor((100 - Evonux.AvailableCalcPower()) * 2);
Evonux._clockPointer = null;

// TODO:
// - IE + SAFARI TESTs !!!
//
// - relative translation : dragging modifies current position then movement resumes from this position
//			     object moves from current position
// - infinite translation
// - multi simultaneous movements, effects
// - sortable lists
// - dropable object (accepts dragged object)
// - effects :	* fading
//		* minimize, maximize
//		* zoom
//		* alpha
// - duplicate object
//
// - creates a new object that takes place of moved object for not modifying page agencement

// ----------------------------------------------------------------------------
// Evonux.Anim
// Allows objects animations (draging,moving,...)

Evonux.Obj = {};
// Wrapper object
// This object allow multiple actions for one object
Evonux.Obj = function(obj)
{
    // Gives this object an id if does not have one
    if (!obj.id)
      obj.id = Evonux._idPrefix + (Evonux._idCnt++);
    this.obj = obj;
    this.id = obj.id;

    // TODO: Object father MUST be root body

    // Animation capabilities
    this.drag = false;
    this.dragObj = null;
    this.translate = false;
    this.translateObj = null;
    this.modify = false;
    this.modifyObj = null;

    // Obj properties backup (TODO: the following is too long !)
    /*
    this.bu_height = Evonux.GetStyleProp(obj, 'heigth');
    this.bu_width = Evonux.GetStyleProp(obj, 'width');
    this.bu_paddingLeft = Evonux.GetStyleProp(obj, 'padding-left');
    this.bu_paddingRight = Evonux.GetStyleProp(obj, 'padding-rigth');
    this.bu_paddingTop = Evonux.GetStyleProp(obj, 'padding-top');
    this.bu_paddingBottom = Evonux.GetStyleProp(obj, 'padding-bottom');
    this.bu_marginLeft = Evonux.GetStyleProp(obj, 'margin-left');
    this.bu_marginRight = Evonux.GetStyleProp(obj, 'margin-rigth');
    this.bu_marginTop = Evonux.GetStyleProp(obj, 'margin-top');
    this.bu_marginBottom = Evonux.GetStyleProp(obj, 'margin-bottom');
    */
    this.backupStyle = (obj.currentStyle
			? obj.currentStyle
			: document.defaultView.getComputedStyle(obj, null));

    // Evonux caugth object properties
    this.cursorFocus = false;
    // -> Set by capabilities objects
    
    this.Register();

    return this;
}

Evonux.Obj.prototype.Register = function()
{
    Evonux._obj[this.id] = this;
    Evonux._obj.length++;
}
// Returns first evonux parent object that has Evonux capabilities
Evonux.Obj.Get = function(objref)
{ // static
    // k prevents infinite loops
    for (var _objref = objref, k = 0;
	 _objref && (_objref.parentNode != _objref ) && (k < 100);
	 _objref = _objref.parentNode, k++)
    {
	if (_objref.id && Evonux._obj[_objref.id])
	  return Evonux._obj[_objref.id];
    }
    return null;
}
Evonux.Obj.prototype.Update = function()
{
    var notFinished = false;
    if (this.drag)
      notFinished = this.dragObj.Update() || notFinished;
    if (this.translate)
      notFinished = this.translateObj.Update() || notFinished;
    if (this.modify)
      notFinished = this.modifyObj.Update() || notFinished;
    return notFinished;
}
Evonux.Obj.prototype.KeyUp = function(keyCode, modifiers)
{
    if (this.drag)
      this.dragObj.KeyUp(keyCode, modifiers);
    if (this.translate)
      this.translateObj.KeyUp(keyCode, modifiers);
}
// Sets cursor focus for object
Evonux.Obj.prototype.SetCursorFocus = function(state)
{
    this.cursorFocus = state;
}
Evonux.Obj.prototype.GetCursorFocus = function()
{
    return this.cursorFocus;
}
Evonux.Obj.prototype.Animable = function()
{
    // Lets object move
    this.originalPosition = this.obj.style.position;
    this.obj.style.position = 'absolute';
}
Evonux.Obj.prototype.Draggable = function(dragObj)
{
    this.drag = true;
    this.dragObj = dragObj;
    dragObj.active = true;
    dragObj.parent = this;
    this.Animable();
}
Evonux.Obj.prototype.Translateable = function(translateObj)
{
    this.translate = true;
    this.translateObj = translateObj;
    translateObj.active = true;
    translateObj.parent = this;
    this.Animable();
}
Evonux.Obj.prototype.Translateunable = function()
{
    if (!this.translate)
      return;
    TO = this.translateObj;
    TO.active = false;
    TO.timeElapsed = 0;
    delete this.path;

    this.translate = false;
    delete TO;
    TO = null;
}
Evonux.Obj.prototype.Modifyable = function(modifyObj)
{
    this.modify = true;
    this.modifyObj = modifyObj;
    modifyObj.active = true;
    modifyObj.parent = this;

    modifyObj.scroll = null;
}
// Removes param action from obj
Evonux.Obj.prototype.Modifyunable = function(param)
{
    var O = this.obj;

    if (!this.modify)
      return;

    if ((param == 'scroll') && (this.modifyObj.scroll != null))
    {
	var MSC = this.modifyObj.scroll.content;
	MSC.parentNode.insertBefore(O, MSC);
	MSC.parentNode.removeChild(MSC);
	delete this.modifyObj.scroll;
	this.modifyObj.scroll = null;
    }

    this.backupStyle = (obj.currentStyle
			? obj.currentStyle
			: document.defaultView.getComputedStyle(obj, null));

    if (O.currentStyle)
      O.currentStyle = this.backupStyle;
    else if (window.getComputedStyle)
    document.defaultView.getComputedStyle();

    // Check for other capabilities !!!
    //    this.modify = false;
}

Evonux.Anim = {};
Evonux.Anim.version = '0.2 (2005/10/13)';

// Handles hitting keys' triggers
Evonux.Anim.HandleKeyUp = function(e)
{
    for (var k in Evonux._obj)
    {
	curobj = Evonux._obj[k];
	curobj.KeyUp(e.keyCode, e.modifiers); // e.keyCode = e.which
    }
}
Evonux.AddEventListener('keyup', Evonux.Anim.HandleKeyUp);

// Returns actual Array(left,top,inherited_margin_left,inherited_margin_top,margin_left,margin_top) position for obj
Evonux.Anim.ActualPos = function(obj)
{
    var res = new Array(0,0,0,0,
			(obj.style && obj.style.marginLeft ? eval(obj.style.marginLeft.substr(0, obj.style.marginLeft.length - 2)) : 0),
			(obj.style && obj.style.marginTop ? eval(obj.style.marginTop.substr(0, obj.style.marginTop.length - 2)) : 0));
    var LEFT = 0, TOP = 1, IM_LEFT = 2, IM_TOP = 3;
    
    if (obj.offsetParent)
	for (curobj = obj; curobj.offsetParent; curobj = curobj.offsetParent)
	    {
		if (obj != curobj)
		    {
			res[IM_LEFT] += curobj.offsetLeft;
			res[IM_TOP] += curobj.offsetTop;
		    }
		res[LEFT] += curobj.offsetLeft;
		res[TOP] += curobj.offsetTop;
	    }
    else if (curobj.x)
	{
	    res[LEFT] += curobj.x;
	    res[TOP] += curobj.y;
	}
    return res;
}

Evonux.Anim.Clock = {};

Evonux.Anim.Clock = function()
{
    // Updates all moving objects
    var clockMustGoOn = false;
    for (var k in Evonux._obj)
    {
	curobj = Evonux._obj[k];
	clockMustGoOn = (curobj.Update() || clockMustGoOn);
    }
    if (clockMustGoOn)
      Evonux._clockPointer = setTimeout('Evonux.Anim.Clock();', Evonux._clockInterval);
    else
    {
	Evonux._clockPointer = null;
    }
}
Evonux.Anim.Clock.Launch = function()
{
    if (!Evonux._clockPointer)
      Evonux.Anim.Clock();
}

Evonux.Anim.Drag = {};
// Asks for dragging object NOW
// TODO:
//   - make it possible to choose an object that moves a parent object
//     instead of parent object itself
Evonux.Anim.Drag = function(obj, xRange, yRange, options)
{
    var evobj = Evonux.Obj.Get(obj);
    if (!evobj)
      evobj = new Evonux.Obj(obj);

    var postmp = Evonux.Anim.ActualPos(obj);
    if (!evobj.drag)
    {
	this.type = 'Evonux.Anim.Drag';

	evobj.Draggable(this);

	// Records its old state to let it recall its initial state
	evobj.originalTop = obj.style.top;
	evobj.originalLeft = obj.style.left;
	evobj.originalBottom = obj.style.bottom;
	evobj.originalRigth = obj.style.right;
	evobj.originalMarginLeft = obj.style.marginLeft;
	evobj.originalMarginTop = obj.style.marginTop;

	// Adjusts object position regarding margins
	evobj.marginTop = evobj.marginLeft = 0;
	if (obj.style.marginLeft)
	    {
		// Actual object LEFT position
		evobj.marginLeft = postmp[2];
		obj.style.marginLeft = '0';
	    }
	obj.style.left = (postmp[0] - postmp[4] - postmp[2]) + 'px';
	curPosLeft = postmp[0];

	if (obj.style.marginTop)
	    {
		// Actual object TOP position
		evobj.marginTop = postmp[3];
		obj.style.marginTop = '0';
	    }
	obj.style.top = (postmp[1] - postmp[5] - postmp[3]) + 'px';
	curPosTop = postmp[1];

	// Sets authorized box for moving
	this.xRange = (xRange
		       ? (Evonux.GetOption(options, 'xRelative')
			  ? [curPosLeft + xRange[0], curPosLeft + xRange[1]]
			  : xRange)
		       : Evonux.INFINITY);
	this.yRange = (yRange
		       ? (Evonux.GetOption(options, 'yRelative')
			  ? [curPosTop + yRange[0], curPosTop + yRange[1]]
			  : yRange)
		       : Evonux.INFINITY);

	Evonux.AddEventListener('mouseout',
				function(e)
				{
				    evobj = Evonux.Obj.Get((e.target ? e.target : e.srcElement));
				    // Cursor may move to fast in this case so clock will check for new position
				    Evonux.Anim.Clock.Launch();
				    evobj.SetCursorFocus(false);
				}, obj);
	Evonux.AddEventListener('mousemove', Evonux.Anim.Drag.SetPosition, obj);
	Evonux.AddEventListener('mouseup',
				function(e)
				{
				    evDO = Evonux.Obj.Get((e.target ? e.target : e.srcElement)).dragObj;
				    evDO.active = false;
				}, obj);
    }
    // Before-dragging position
    evobj.dragObj.startLeft = postmp[0];
    evobj.dragObj.startTop = postmp[1];

    // Object is put on the first visible layer
    obj.style.zIndex = 1000;

    evobj.dragObj.mouseCorrectionX = Evonux._mouseX - obj.offsetLeft;
    evobj.dragObj.mouseCorrectionY = Evonux._mouseY - obj.offsetTop;

    evobj.dragObj.active = true;
    evobj.cursorFocus = true;
}
// Updates dragged object's position
Evonux.Anim.Drag.SetPosition = function(e,evobj)
{ // static
    if (!evobj)
      evobj = Evonux.Obj.Get((e.target ? e.target : e.srcElement));
    if (!evobj || !evobj.dragObj || !evobj.dragObj.active)
      return;
    
    evDO = evobj.dragObj;
    
    // Adjustement for actual position (cursor can be anywhere among object)
    var yPos = Evonux._mouseY - evDO.mouseCorrectionY,
        xPos = Evonux._mouseX - evDO.mouseCorrectionX;

    // If object can move, some correction may be done...
    if (evobj.translate && evobj.translateObj.active)
      evobj.translateObj.ChangeRef(xPos, yPos);

    if ((evDO.xRange == Evonux.INFINITY)
	|| ((evDO.xRange != Evonux.NONE) && (((xPos + evDO.marginLeft) >= evDO.xRange[0]) && ((xPos + evDO.marginLeft) <= evDO.xRange[1]))))
    {
	evobj.obj.style.left = xPos +'px';
	evobj.left = xPos;
    }
    if ((evDO.yRange == Evonux.INFINITY)
	|| ((evDO.yRange != Evonux.NONE) && (((yPos + evDO.marginTop) >= evDO.yRange[0]) && ((yPos + evDO.marginTop) <= evDO.yRange[1]))))
    {
	evobj.obj.style.top = yPos +'px';
	evobj.top = yPos;
    }

    evobj.cursorFocus = true;

    return evobj.obj;
}
Evonux.Anim.Drag.prototype.IsActive = function()
{
    return this.active;
}

Evonux.Anim.Drag.prototype.Update = function()
{
    if (!this.parent.GetCursorFocus() && this.IsActive())
      Evonux.Anim.Drag.SetPosition(null,this);
}
Evonux.Anim.Drag.prototype.KeyUp = function(keyCode, modifiers)
{
    if (this.IsActive())
    switch (keyCode)
    {
      case 27: // ESC
        var postmp = Evonux.Anim.ActualPos(this.parent.obj);
        this.parent.Translateunable(); // Flushes current movement
        new Evonux.Anim.Translate(this.parent.obj, 'path=line:'+ postmp[0] +','+ postmp[1] +','+ this.startLeft +','+ this.startTop +';duration=200');
        this.active = false;
	break;
      default:
	break;
    }
    return 'ou la la';
}

Evonux.Anim.Translate = {};
// options
// -------
// * path=
//     - line:left0,top0,left1,top1,[left2,top2,[...]]
//     - circle:leftCenter,topCenter,horizontalRadius,verticalRadius,angleStart,angleEnd
// * duration=milliseconds (optionnal)
// * infinite (optionnal)
// * loops=[number of iterations] (optionnal)
// * loops-interval=[milliseconds] (optionnal)
// * smoothCycle (optionnal) NB. Makes loops-interval ignored
// * xRelative ; yRelative (optionnal)
// * xOrigin ; yOrigin (optionnal)
//
// E.G. new Evonux.Anim.Translate(this, 'path=line:0,0,50,50,100,0;duration=5000;xRelative');
//
Evonux.Anim.Translate = function(obj, options)
{
    var evobj = Evonux.Obj.Get(obj);
    if (!evobj)
      evobj = new Evonux.Obj(obj);
    if (!evobj.translate)
    {
	this.type = 'Evonux.Anim.Translate';

	var _path, _duration;
	if (!(_path = Evonux.GetOption(options, 'path')))
	    return false;
	// Defines path for movement
	_path = _path.split(':');
	switch (_path[0].toLowerCase())
	    {
	    case 'line':
		this.path = eval('new Evonux.Anim.Lines('+ _path[1] +')');
		break;
	    case 'circle':
		this.path = eval('new Evonux.Anim.Circle('+ _path[1] +')');
		break;
	    default: // No valid path
		return false;
	    }
	evobj.Translateable(this);

	// Duration
	this.duration = ((_duration = Evonux.GetOption(options, 'duration')) != false ? eval(_duration) : 2000);
	// Number of movements
	this.loops = ((_loops = Evonux.GetOption(options, 'loops')) != false ? eval(_loops) : 1);
	this.iterationNb = 0;
	// Time to wait between each iteration
	this.loopsInterval = ((_li = Evonux.GetOption(options, 'loops-interval')) != false ? eval(_li) : 0);
	this.waitTime = 0;
	// Repeat movement forever ? (priority on loops)
	this.infinite = Evonux.GetOption(options, 'infinite');
	// {x,y}Relative ([x,y] is actually first position)
	this.xRelative = Evonux.GetOption(options, 'xRelative');
	this.yRelative = Evonux.GetOption(options, 'yRelative');
	// {x,y}Origin ([x,y] = [0,0] or grid)
	this.xOrigin = Evonux.GetOption(options, 'xOrigin');
	this.yOrigin = Evonux.GetOption(options, 'yOrigin');
	// Treats first position only at first iteration for smooth cycle movement
	this.smoothCycle = Evonux.GetOption(options, 'smoothCycle');

	// Initializes first position
	coordtmp = Evonux.Anim.ActualPos(obj);
	evobj.left = coordtmp[0] - coordtmp[4] - coordtmp[2];
	evobj.top = coordtmp[1] - coordtmp[5] - coordtmp[3];

	this.timeElapsed = 0;
    }
    evTO = evobj.translateObj;

    evTO.active = true;
    // Calculates actual position for ''relative'' movements
    var pos0 = evTO.path.GetPosition(0);
    evTO.xCorrection = (evTO.xRelative ? evobj.left - pos0[0] : 0);
    evTO.yCorrection = (evTO.yRelative ? evobj.top - pos0[1] : 0);
    // Calculates actual position for ''origin'' movements
    evTO.xCorrection += (evTO.xOrigin ? evobj.left : 0);
    evTO.yCorrection += (evTO.yOrigin ? evobj.top : 0);

    // Lauches clock in case no other object is running
    Evonux.Anim.Clock.Launch();

    return true;
}
Evonux.Anim.Translate.prototype.Update = function()
{
    evobj = this.parent;

    // Wait before next iteration
    if ((this.iterationNb > 0) && (this.timeElapsed <= 0))
    {
	this.waitTime += Evonux._clockInterval;
	if (this.waitTime >= this.loopsInterval)
	    this.waitTime = 0;
	else
	    return true;
    }

    if (this.timeElapsed > this.duration)
    {
	// May not have reached last position
	cur_coord = this.path.GetPosition(100);
	evobj.left = cur_coord[0] + this.xCorrection;
	evobj.top = cur_coord[1] + this.yCorrection;
	evobj.obj.style.left = evobj.left +'px';
	evobj.obj.style.top = evobj.top +'px';

	// End of translation
	if (++this.iterationNb >= this.loops)
	    {
		this.iterationNb = 0;
		this.active = false;
	    }
	else
	    this.active = true;
	this.active = this.infinite || this.active;

	if (this.smoothCycle && (this.infinite || ((this.loops > 0) && (this.iterationNb > 0))))
	  this.timeElapsed = Evonux._clockInterval;
	else
	  this.timeElapsed = 0;

	return this.active;
    }
    else if(this.active)
    {
	// Position update
	cur_coord = this.path.GetPosition((this.timeElapsed / this.duration) * 100);
	evobj.left = cur_coord[0] + this.xCorrection;
	evobj.top = cur_coord[1] + this.yCorrection;
	evobj.obj.style.left = evobj.left +'px';
	evobj.obj.style.top = evobj.top +'px';

	this.timeElapsed += Evonux._clockInterval;
	return true;
    }
    return false;
}
// Update reference grid (typically due to dragging action)
Evonux.Anim.Translate.prototype.ChangeRef = function(left, top)
{
    this.xCorrection += left - this.parent.left;
    this.yCorrection += top - this.parent.top;
}
Evonux.Anim.Translate.prototype.KeyUp = function(keyCode, modifiers)
{
    
}

Evonux.Anim.Modify = {};
// options
// -------
// * scroll=[duration:milliseconds,speed:px/second,vectorX:x,vectorY:y,interactive,infinite,donthide]
Evonux.Anim.Modify = function(obj, options)
{
    var evobj = Evonux.Obj.Get(obj);
    if (!evobj)
      evobj = new Evonux.Obj(obj);
    if (!evobj.modify)
    {
	this.type = 'Evonux.Anim.Modify';

	evobj.Modifyable(this);
    }
    if (((_scr = Evonux.GetOption(options, 'scroll')) != false) && (evobj.modifyObj.scroll == null))
      this.scroll = new Evonux.Anim.Modify.Scroll(_scr, evobj.modifyObj);
    if (evobj.modify && evobj.modifyObj.scroll)
      evobj.modifyObj.scroll.active = true;

    // Lauches clock in case no other object is running
    Evonux.Anim.Clock.Launch();

    return evobj.modifyObj;
}
Evonux.Anim.Modify.prototype.Update = function()
{
    var notFinished = false;
    if (this.scroll)
      notFinished = this.scroll.Update() || notFinished;
    return notFinished;
}

Evonux.Anim.Modify.Scroll = {};
Evonux.Anim.Modify.Scroll = function(options, _parent)
{
    options = options.replace(RegExp(':', 'g'), '=').replace(RegExp(',', 'g'), ';');
    if (!(_tmpSpeed = Evonux.GetOption(options, 'speed')))
      this.duration = ((_tmp = Evonux.GetOption(options, 'duration')) != false ? eval(_tmp) : 1);
    this.timeElapsed = 0;
    // Direction for content
    this.vectorX = ((_tmp = Evonux.GetOption(options, 'vectorX')) != false ? eval(_tmp) : 0);
    this.vectorY = ((_tmp = Evonux.GetOption(options, 'vectorY')) != false ? eval(_tmp) : 0);
    if ((this.vectorX == 0) && (this.vectorY == 0))
      this.vectorY = -1;
    this.infinite = Evonux.GetOption(options, 'infinite');
    // Scroll will end when top of content is visible
    this.donthide = Evonux.GetOption(options, 'donthide');
    
    PO = _parent.parent.obj;
    POheight_donttouch = (PO.style.height != '');
    POwidth_donttouch = (PO.style.width != '');
    if (!PO.style.height)
      PO.style.height = (PO.parentNode.style.height ? PO.parentNode.style.height : PO.offsetHeight +'px');
    if (!PO.style.width)
      PO.style.width = (PO.parentNode.style.width ? PO.parentNode.style.width : PO.offsetWidth +'px');

    this.parent = _parent;
    // Builds a DIV wrapper
    this.content = document.createElement('div');
    PO.parentNode.insertBefore(this.content, PO);
    PO.parentNode.removeChild(PO);
    this.content.appendChild(PO);
    // Div wrapper properties for scrolling
    this.content.style.overflow = 'hidden';
    this.content.clip = 'auto';
    this.content.style.width = (!POwidth_donttouch ? PO.style.width : PO.offsetWidth +'px');
    this.content.style.height = (!POheight_donttouch ? PO.style.height : PO.offsetHeight +'px');
    this.content.style.padding = 0;
    this.content.style.margin = 0;

    this.offsetHeight = eval(PO.style.height.substr(0, PO.style.height.length - 2));
    this.offsetWidth = eval(PO.style.width.substr(0, PO.style.width.length - 2));
    
    // Release natural dimensions if they were not forced by user
    if (!POwidth_donttouch)
      PO.style.width = 'auto';
    if (!POheight_donttouch)
      PO.style.height = 'auto';
    
    this.height = PO.offsetHeight;
    this.width = PO.offsetWidth;

    // When cursor moves over object, scrolling pauses. It resumes when cursor leaves area
    if (Evonux.GetOption(options, 'interactive'))
    {
	eval('Evonux.AddEventListener(\'mouseover\', function() {Evonux.Anim.Modify.Scroll.Pause(Evonux.Obj.Get(Evonux.$(\''+ this.parent.parent.id +'\')));}, this.content);');
	eval('Evonux.AddEventListener(\'mouseout\', function() {Evonux.Anim.Modify.Scroll.Play(Evonux.Obj.Get(Evonux.$(\''+ this.parent.parent.id +'\')));}, this.content);');
    }

    if (_tmpSpeed)
    {
	if (this.vectorY < this.vectorX)
	  this.duration = Math.floor(((this.donthide ? this.offsetHeight : this.height) / eval(_tmpSpeed)) * 1000);
	else
	  this.duration = Math.floor(((this.donthide ? this.offsetWidth : this.width) / eval(_tmpSpeed)) * 1000);
    }
    
    // Object is now a child of new wrapper
    // So it may not be position:absolute
    if (Evonux.GetStyleProp(PO, 'position') == 'absolute')
    {
	this.content.style.position = 'absolute';
	this.content.style.left = PO.offsetLeft +'px';
	this.content.style.top = PO.offsetTop +'px';
	
	PO.style.position = 'static';
	PO.style.left = '';
	PO.style.top = '';
    }

    return this;
}
Evonux.Anim.Modify.Scroll.prototype.Update = function()
{
    if (!this.active)
      return false;
    if (this.timeElapsed >= this.duration)
    {
	// Adjustement if 100% has not been reached
	if (this.timeElapsed > this.duration)
	    {
		if (this.vectorY != 0)
		    this.parent.parent.obj.style.marginTop = (this.vectorY < 0 ? 1 : -1) * (this.offsetHeight - Math.floor(((this.donthide ? 0 : this.height) + this.offsetHeight))) + 'px';
		if (this.vectorX != 0)
		    this.parent.parent.obj.style.marginLeft = (this.vectorX < 0 ? 1 : -1) * (this.offsetWidth - Math.floor(((this.donthide ? 0 : this.width) + this.offsetWidth))) + 'px';
	    }
	this.timeElapsed = 0;
	this.active = this.infinite;

	return this.active;
    }
    else
    {
	if (this.vectorY != 0)
	  this.parent.parent.obj.style.marginTop = (this.vectorY < 0 ? 1 : -1) * (this.offsetHeight - Math.floor((this.timeElapsed / this.duration) * ((this.donthide ? 0 : this.height) + this.offsetHeight))) + 'px';
	if (this.vectorX != 0)
	  this.parent.parent.obj.style.marginLeft = (this.vectorX < 0 ? 1 : -1) * (this.offsetWidth - Math.floor((this.timeElapsed / this.duration) * ((this.donthide ? 0 : this.width) + this.offsetWidth))) + 'px';

	this.timeElapsed += Evonux._clockInterval;
	this.active = true;

	return true;
    }
}
Evonux.Anim.Modify.Scroll.Pause = function(evobj)
{ // static
    evobj.modifyObj.scroll.active = false;
}
Evonux.Anim.Modify.Scroll.Play = function(evobj)
{ // static
    evobj.modifyObj.scroll.active = true;
    Evonux.Anim.Clock.Launch();
}

Evonux.Anim.Lines = {};
Evonux.Anim.Lines = function()
{
    this.type = 'Evonux.Anim.Lines';

    var argv = Evonux.Anim.Lines.arguments,
        argc = argv.length,
        LEFT = 0, TOP = 1, LG = 2, PERCENT = 3;

    // Array of [left,top,length,%start] positions
    // NB. - length is length of line from [left,top]
    //     - %start is percentage of total lines length where this line starts
    this.coord = new Array(); c = this.coord;
    this.coord_lg = argc / 2;
    this.total_lg = 0; // length of path
    for (var k = 0, i = 0; k < argc; k += 2, i++)
    {
	c.push([argv[k],argv[k+1]]);
	if (k > 0)
	    {
		width = c[i-1][LEFT] - c[i][LEFT];
		height = c[i-1][TOP] - c[i][TOP];
		with (Math)
		    {
			cur_lg = sqrt(pow(width,2) + pow(height,2));
			c[i].push(cur_lg);
			this.total_lg += cur_lg;
		    }
	    }
	else // Length is null at this point
	    c[i].push(0);
    }
    c[0].push(0);
    for (k = 1, lg = argc / 2, cur_lg = 0; k < lg; k++)
    {
	cur_lg += c[k][LG];
	c[k].push((cur_lg / this.total_lg) * 100);
    }
    /*
    // XXX
    output = '';
    for (k = 0, lg = this.coord.length; k < lg; k++)
      output += this.coord[k][LEFT] +','+ this.coord[k][TOP] +' ('+ this.coord[k][LG] +','+ this.coord[k][PERCENT] +')\n';
    alert(output);
    */
    return this;
}
Evonux.Anim.Lines.prototype.GetPosition = function(percent)
{
    var k,
        LEFT = 0, TOP = 1, LG = 2, PERCENT = 3;
    if (percent < 0)
      percent = 0;
    else if (percent > 100)
      percent = 100;
    c = this.coord;
    // Searches for current line
    if (c.length > 1)
    {
	for (k = 0; c[k+1][PERCENT] < percent; k++) ;
	// Position (%) from c[k]
	percent_rel = (percent - c[k][PERCENT]) / (c[k+1][PERCENT] - c[k][PERCENT]);
	// Calculates position
	curleft = Math.floor(c[k][LEFT] + (percent_rel * (c[k+1][LEFT] - c[k][LEFT])));
	curtop = Math.floor(c[k][TOP] + (percent_rel * (c[k+1][TOP] - c[k][TOP])));
	return Array(curleft,curtop);
    }
    else
      return Array(c[0][LEFT],c[0][TOP]);
}

Evonux.Anim.Circle = {};
Evonux.Anim.Circle = function(centerLeft,centerTop,radiusHoriz,radiusVert,angleStart,angleEnd)
{
    this.type = 'Evonux.Anim.Circle';

    this.centerLeft = centerLeft;
    this.centerTop = centerTop;
    this.radiusHoriz = radiusHoriz;
    this.radiusVert = radiusVert;
    this.angleStart = angleStart;
    this.angleEnd = angleEnd;

    return this;
}
Evonux.Anim.Circle.prototype.GetPosition = function(percent)
{
    if (percent < 0)
      percent = 0;
    else if (percent > 100)
      percent = 100;
    var angle = ((this.angleStart + ((percent / 100) * (this.angleEnd - this.angleStart))) / 360) * 2 * Math.PI;

    return Array(Math.floor(this.centerLeft + (Math.cos(angle) * this.radiusHoriz)),
		 Math.floor(this.centerTop + (Math.sin(angle) * this.radiusVert)));
}
