/* TODO: place in a JS file */
var AnimationManager = new Object();
    AnimationManager.frameRate = 60;
    AnimationManager.animations = new Array();
    AnimationManager.timer = null;
    AnimationManager.index = 0;
    AnimationManager.serialID = 0;
    
    
    AnimationManager.everyFrame = function() {
        //Time stamp
        var d = new Date();
        var stamp = d.getTime();
        while (AnimationManager.index < AnimationManager.animations.length) {
            if (AnimationManager.animations[AnimationManager.index].getState()) {
                AnimationManager.animations[AnimationManager.index].execute();
            }
            AnimationManager.index++;
        }
        AnimationManager.index = 0;
        if (AnimationManager.timer != null) {
            var difference = d.getTime() - stamp;
            AnimationManager.start(difference); //Here, if this operation took some time, we minus that from the frameRate Timeout so it happens sooner :D
        }
    };
    
    AnimationManager.start = function(offset) {
        AnimationManager.timer = setTimeout("AnimationManager.everyFrame()", Math.max(0, 1000/AnimationManager.frameRate - offset)); //SetTimeout is recursive... using setInterval just needs to be called once... fool!!
    };
   
    AnimationManager.EveryFrame = function(FN) {
        var home = this;
        var state = "playing";
    
        this.id = AnimationManager.serialID++;
        this.getState = function() {
            return (state == "playing") ? true : false;
        };
        
        this.execute = FN;
        this.play = function() {
            state = "playing";
        };
        this.stop = function() {
            state = "stopped";
        };
        this.clear = function() {
            AnimationManager.clearEveryFrame(home);
        };
        AnimationManager.onEveryFrame(this);
    };
   
    AnimationManager.onEveryFrame = function(newEveryFrame) {
        AnimationManager.animations.push(newEveryFrame);
        if (AnimationManager.timer == null && AnimationManager.animations.length == 1) {
            AnimationManager.start(AnimationManager.frameRate/1000);
        }
    };
   
    AnimationManager.clearEveryFrame = function(oldEveryFrame) {
        for (var i = 0; i < AnimationManager.animations.length; i++) {
            if (AnimationManager.animations[i].id == oldEveryFrame.id) {
                AnimationManager.animations.splice(i, 1);
                if (i < AnimationManager.index) {
                    AnimationManager.index--;
                }
                i = AnimationManager.animations.length + 5;
            }
            if (i == AnimationManager.animations.length - 1) {
                alert("Could not find EveryFrame object reference... why are you clearing an everyFrame event which doesn't exist?");
            }
        }
        if (AnimationManager.animations.length == 0) {
            AnimationManager.serialID = 0;
            AnimationManager.stop();
        }
    };
   
    AnimationManager.stop = function() {
        clearTimeout(AnimationManager.timer);
        AnimationManager.timer = null;
    };
    
    AnimationManager.clear = function() {
        AnimationManager.stop();
        AnimationManager.animations = new Array();
    };
   
    AnimationManager.getSpeed = function(speed) {
        return (((100 - Math.max(0, Math.min(100, speed))) / 100) * 48) + 2;
    };
    
    AnimationManager.inRange = function(curr, last) {
        return (curr <= (last + 1) && curr >= (last - 1));
    };
    
    AnimationManager.move = function(curr, last, increment) {
        return (curr + ((last > curr) ? Math.max(1, increment) : Math.min(-1, increment)));
    };
    
    /* TODO: merge xScale and yScale into one function */
    AnimationManager.xScale = function(obj, finalWidth, speed, onComplete) {
        var animate = null;
        var currWidth = null;
        
        this.setFinalWidth = function(target) {
            finalWidth = target;
        };
        
        this.getCurrentHeight = function() {
            return currWidth;
        };
        
        this.getFinalWidth = function() {
            return finalWidth;
        };
        
        this.stop = function() {
            animate.stop();
        };
        
        this.clear = function() {
            animate.clear();
        };
        
        animate = new AnimationManager.EveryFrame(function() {
            currWidth = obj.clientWidth;
            if (!AnimationManager.inRange(currWidth, finalWidth)) {
                var speeders = AnimationManager.getSpeed(speed);
                var increase = Math.round((finalWidth - currWidth)/speeders);
                obj.style.width = AnimationManager.move(currWidth, finalWidth, increase) + "px";
            } else {
                obj.style.width = finalWidth + "px";
                onComplete();
                AnimationManager.clearEveryFrame(animate);
            }
        });
    };
    
    AnimationManager.yScale = function(obj, finalHeight, speed, onComplete) {
        var animate = null;
        var currHeight;
        
        this.setFinalHeight = function(target) {
            finalHeight = target;
        };
        
        this.getCurrentHeight = function() {
            return currentOpacity;
        };
        
        this.getFinalHeight = function() {
            return finalHeight;
        };
        
        this.stop = function() {
            animate.stop();
        };
        
        this.clear = function() {
            animate.clear();
        };
        
        animate = new AnimationManager.EveryFrame(function() {
            currHeight = obj.clientHeight;
            if (!AnimationManager.inRange(currHeight, finalHeight)) {
                var speeders = AnimationManager.getSpeed(speed);
                var increase = Math.round((finalHeight - currHeight)/speeders);
                obj.style.height = AnimationManager.move(currHeight, finalHeight, increase) + "px";
            } else {
                obj.style.height = finalHeight + "px";
                onComplete();
                AnimationManager.clearEveryFrame(animate);
            }
        });
    };
    
    AnimationManager.fade = function(obj, currentOpacity, targetOpacity, speed, onComplete) {
        var animate = null;
    
        this.setFinalOpacity = function(target) {
            targetOpacity = target;
        };
        
        this.getCurrentOpacity = function() {
            return currentOpacity;
        };
        
        this.getFinalOpacity = function() {
            return targetOpacity;
        };
        
        this.stop = function() {
            animate.stop();
        };
        
        this.clear = function() {
            animate.clear();
        };
        
        //Add transparency for IE
        obj.style.opacity = currentOpacity / 100;
        animate = new AnimationManager.EveryFrame(function() {
            currentOpacity = obj.style.opacity * 100;
            if (!AnimationManager.inRange(currentOpacity, targetOpacity)) {
                var speeders = AnimationManager.getSpeed(speed);
                var increase = Math.round((targetOpacity - currentOpacity)/speeders); /* TODO: create function that includes speeders and returns the increase :D */
                obj.style.opacity = AnimationManager.move(currentOpacity, targetOpacity, increase) / 100;
            } else {
                obj.style.opacity = targetOpacity / 100;
                onComplete();
                AnimationManager.clearEveryFrame(animate);
            }
        });
    };
    
    /* TODO: Re-write tweens, yo! :) */
    AnimationManager.tween = function(type, obj, finalPos, speed, direction, onComplete) {
        var animate = null;
        var currPos = null;
        
        this.setFinalPos = function(newPos) {
            finalPos = newPos;
        };
        
        this.getCurrentPos = function() {
            return currPos;
        };
        
        this.getFinalPos = function() {
            return finalPos;
        };
        if (!obj.style.position) {
            obj.style.position = (type == "absolute") ? "absolute" : "relative";
            obj.style.top = "0px";
        }
        
        this.stop = function() {
            animate.stop();
        };
        
        this.clear = function() {
            animate.clear();
        };
        animate = new AnimationManager.EveryFrame(function() {
            currPos = (direction == "left" || direction == "right") ? obj.style.left.split("px")[0] : obj.style.top.split("px")[0];
            currPos++;
            currPos--;
            if (!AnimationManager.inRange(currPos, finalPos)) {
                var speeders = AnimationManager.getSpeed(speed);
                var newPos = Math.round((finalPos - currPos)/speeders);
                if (direction == "left" || direction == "right") {
                    obj.style.left = AnimationManager.move(currPos, finalPos, newPos) + "px";
                } else {
                    obj.style.top = AnimationManager.move(currPos, finalPos, newPos) + "px";
                }
            } else {
                if (direction == "left" || direction == "right") {
                    obj.style.left = finalPos + "px";
                } else {
                    obj.style.top = finalPos + "px";
                }
                //need to create some kind of event object to pass into here
                onComplete();
                AnimationManager.clearEveryFrame(animate);
            }
        });
    };