

function Animation()
{
    var self = this;

    self.iTime = 0;
    self.iStep = 80;
    self.bFinish = false;
    self.aEvents = new Array();

    self.addEvent = function(pEvent)
    {
        self.aEvents.push(pEvent)
    };

    self.stop = function()
    {
        self.bFinish = true;
        for (var i = 0; i < self.aEvents.length; i++) self.aEvents[i].finalize();
    }

    self.start = function(iStep)
    {
        for (var i = 0; i < self.aEvents.length; i++) self.aEvents[i].initialize();

        self.bFinish = false;
        self.iStep = iStep;
        self.iTime = 0;
        self.nextStep();
    };

    self.nextStep = function()
    {
        var iEvents = 0;
        var aEvents = self.aEvents;

        if (self.bFinish) self.stop();

        for (var i = 0; i < aEvents.length; i++) if (!aEvents[i].bFinished && aEvents[i].nextStep(self.iTime)) iEvents++;

        self.iTime += self.iStep;

        if (iEvents > 0 && !self.bFinish) window.setTimeout(self.nextStep, self.iStep);
        else self.stop();
    };
}

function AnimationEvent(oObject, sAttribute, iValueStart, iValueEnd, iTimeStart, iTimeEnd, fAlgorithm, fSetter)
{
    var self = this;

    self.oObject = oObject;
    self.sAttribute = sAttribute;

    self.oTime = {start: iTimeStart, end: iTimeEnd, current: 0, duration: iTimeEnd-iTimeStart};
    self.oValue = {start: iValueStart, end: iValueEnd, current: 0};

    self.fSetter = fSetter;
    self.fAlgorithm = fAlgorithm;

    self.bFinished = false;

    self.initialize = function()
    {
        self.bFinished = false;
        self.fSetter(self.oObject, self.sAttribute, self.oValue.start);
    };

    self.finalize = function()
    {
        self.bFinished = true;
        self.fSetter(self.oObject, self.sAttribute, self.oValue.end);

        return false;
    };

    self.nextStep = function(iTime)
    {
        if(iTime < self.oTime.start) return true;
        if(iTime > self.oTime.end  ) return self.finalize();

        self.oTime.current = iTime;
        self.oValue.current = self.fAlgorithm(self.oTime, self.oValue);
        self.fSetter(self.oObject, self.sAttribute, self.oValue.current);

        return true;
    };
}


var AnimationSetters =
{
    attribute: function(oElement, sAttribute, oValue)
    {
        eval("oElement."+sAttribute+"="+oValue+";");
    },

    style: function(oElement, sAttribute, oValue)
    {
        eval("oElement.style."+sAttribute+"="+oValue+";");
    },

    opacity: function(oElement, sAttribute, iValue)
    {
        if (!Utility.isIE())  oElement.style.opacity = iValue;
        else                  oElement.style.filter = "alpha(opacity=" + Math.round(iValue*100) + ")";
    }
}

var AnimationAlgo =
{
    leaner: function(oTime, oValue)
    {
        return oValue.start + ((oValue.end-oValue.start)/(oTime.duration))*(oTime.current-oTime.start);
    },

    expo: function(oTime, oValue)
    {
        var iTimeFraction = 1 - Math.pow((oTime.current-oTime.start)/(oTime.duration)-1, 4);
        return oValue.start + ((oValue.end-oValue.start) * iTimeFraction);
    }
}


