/* Some parts in Creative Common License */
/* author : ?? */

/* Smooth scooling */
function smoothScroll(elName, padding) {
	var element = document.getElementById(elName);
	if (!element) var element = elName;
	var paddingTop = 50;
	if (padding) { paddingTop = padding; }
	var windowBottom = window.scrollY + window.innerHeight;
	var offset = getClientOffset(element);
	var elementTop = offset.y - paddingTop;
	var elementBottom = offset.y + element.offsetHeight;
	if (elementTop < window.scrollY || elementBottom > windowBottom) {
		var scrollAmount = (elementBottom - windowBottom) + paddingTop;
		if (elementTop < window.scrollY + scrollAmount)
            scrollAmount = elementTop - window.scrollY;;
		var keyframes = [{
            begin: 0, duration: 400, tween: easeOutQuad,
            onframe: onScrollFrame,
        }];
		Timeline.play(keyframes, 1, { scrollMin: window.scrollY, scrollAmount: scrollAmount });
	}
}
function getClientOffset(elt) {
	function addOffset(elt, coords) {
		if (elt.offsetLeft)
			coords.x += elt.offsetLeft;
		if (elt.offsetTop)
			coords.y += elt.offsetTop;
		if (elt.offsetParent && elt.offsetParent.nodeType == 1)
			addOffset(elt.offsetParent, coords);
	}
	var coords = { x: 0, y: 0 };
	addOffset(elt, coords);
	return coords;
}
function onScrollFrame(keyframe, progress, params) {
    window.scrollTo(0, params.scrollMin + (progress.tweenProgress * params.scrollAmount));
}

function smoothTrans(elName) {
	var element = document.getElementById(elName);
	var keyframes = [{
            begin: 0, duration: 400, tween: tweenTrans,
            onframe: onTransFrame, element: element
        }];
	Timeline.stop();
	Timeline.play(keyframes, 1, {});
}

function onTransFrame(keyframe, progress, params) {
	keyframe.element.style.opacity = progress.tweenProgress;
}

function tweenTrans(t, b, c, d) {
	var o = 0.2 + (t / d);
	if (o >= 1) return 1;
	return o;
}

function easeOutQuad(t, b, c, d) {
	return -c *(t/=d)*(t-2) + b;
}


var Timeline =
{
    currentTimeline: null,
    currentDirection: 1,
    currentParams: null,
    currentProgress: null,
    currentInterval: 0,
    currentBeginTime: 0,
    
    play: function(aTimeline, aDirection, aParams)
    {
        var timeOffset = 0;
        if (this.currentTimeline)
        {
            //if (aTimeline == this.currentTimeline && aDirection != this.currentDirection)
            //{
            //    timeOffset = (new Date()).getTime() - this.currentBeginTime;
            //}
            
            this.stop();
        }
        
        
        this.currentProgress = [];
        for (var i = 0; i < aTimeline.length; ++i)
        {
            this.currentProgress[i] = { playing: false, frame: 0, progress: 0, tweenProgress: 0 };
        }
        
        this.currentTimeline = aTimeline;
        this.currentDirection = aDirection;
        this.currentParams = aParams;
        this.currentBeginTime = (new Date()).getTime() - timeOffset;
        this.currentInterval = window.setInterval(this.intervalCallback, 10);
    },
    
    stop: function()
    {
        // Stop the timer and reset all tracking data
        window.clearInterval(this.currentInterval);
        
        this.currentTimeline = null;
        this.currentParams = null;
        this.currentProgress = null;
        this.currentInterval = 0;
        this.currentBeginTime = 0;
    },
    
    getIsPlaying: function()
    {
        return this.currentTimeline != null;
    },
        dispatchFrameEvent: function(aKeyframe, aData, aName)
    {
        if (aName in aKeyframe)
        {
            try {
                aKeyframe[aName](aKeyframe, aData, this.currentParams);
            } catch (ex)
            {
                this.dumpError(ex);
            }
        }
    },
    
    intervalCallback: function()
    {
        Timeline.tick();
    },
    
    testFrame: function(aKeyFrame, aProgress, aParams)
    {
        throw "UNO " + aProgress.frame + " (" + Math.round(aProgress.tweenProgress*100) + "%)";
    },
    
    dumpError: function(aMessage)
    {
        window.setTimeout("throw '\""+aMessage+"\"'", 0);
    },

    tick: function()
    {
        // Determine how many milliseconds have elapsed since play begain
        var t = (new Date()).getTime() - this.currentBeginTime;
        
        // Use activeCount to count how many keyframes have yet to finish
        var activeCount = 0;
        
        // XXX This currently won't fire any events for keyframes that
        // are completely skipped due to animation lag. Perhaps we should
        // at least fire the first/last frame events for these?
        
        for (var i = 0; i < this.currentTimeline.length; ++i)
        {
            var keyframe = this.currentTimeline[i];
            var progressData = this.currentProgress[i];
            
            // If we have not reached the end of this keyframe...
            if (t < keyframe.begin+keyframe.duration)
            {
                ++activeCount;
            
                // If we are past the beginning of this keyframe
                if (t >= keyframe.begin)
                {
                    ++progressData.frame;
                    if (progressData.frame == 1)
                    {
                        progressData.playing = true;
                        
                        // This is the first tick for this keyframe
                        this.dispatchFrameEvent(keyframe, progressData, "onfirstframe");
                        this.dispatchFrameEvent(keyframe, progressData, "onframe");
                    }
                    else
                    {
                        // Determine how many milliseconds have elapsed in the keyframe duration
                        var kt = t - keyframe.begin;
                        
                          progressData.progress = kt/keyframe.duration;
                        
                        // Determine the percent done, using a tweening function if provided
                        if ("tween" in keyframe)
                        {
                            progressData.tweenProgress = 
                                keyframe.tween(kt, 0, kt, keyframe.duration, 0, 100)/kt;
                        }
                        else
                        {
                            progressData.tweenProgress = progressData.progress;
                        }
                        
                        if (this.currentDirection != 1)
                        {
                            progressData.progress = 1 - progressData.progress;
                            progressData.tweenProgress = 1 - progressData.tweenProgress;
                        }                        
                        
                        this.dispatchFrameEvent(keyframe, progressData, "onframe");
                    }
                }
            }
            // If this keyframe is currently playing, but past the end
            else if (progressData.playing)
            {
                ++progressData.frame;
                progressData.progress = this.currentDirection == 1 ? 1 : 0;
                progressData.tweenProgress = this.currentDirection == 1 ? 1 : 0;
                
                this.dispatchFrameEvent(keyframe, progressData, "onframe");
                this.dispatchFrameEvent(keyframe, progressData, "onlastframe");
                
                progressData.playing = false;
            }
            // If we passed the keyframe without ever playing it
            else if (!progressData.playing && !progressData.frame)
            {
                ++progressData.frame;
                progressData.progress = this.currentDirection == 1 ? 1 : 0;
                progressData.tweenProgress = this.currentDirection == 1 ? 1 : 0;
                
                progressData.playing = true;
                this.dispatchFrameEvent(keyframe, progressData, "onfirstframe");
                this.dispatchFrameEvent(keyframe, progressData, "onframe");
                this.dispatchFrameEvent(keyframe, progressData, "onlastframe");
                progressData.playing = false;
            }
        }
    
        // If there are no more keyframes left to play
        if (activeCount == 0)
        {
            Timeline.stop();
        }
    }
    
};
