/**
 * @author Patrick Kopp
 */
function Animator() {

    var strategiesCount = 0;
    
    // hash of strategies
    this.knownStrategies = {};
    
    // array of mutation abjects
    this.mutationsToDo = new Array();
    
    var frameMs = Animator.prototype.NORMAL_FRAME_MS;
    
    var loopInterval = null;
    
    var autoRegisterCount = 0;
    
    this.isRunning = function() {
        return loopInterval != null;
    }
    
    this.setFrameMs = function(ms) {
        var wasStarted = (loopInterval != null);
        if (wasStarted) {
            this.stop();
        }
        if (ms) {
            frameMs = ms;
        }
        else {
            frameMs = Animator.prototype.NORMAL_FRAME_MS;
        }
        if (wasStarted) {
            this.start();
        }
    }
    
    this.getFrameMs = function() {
        return frameMs;
    }
    
    this.addMutation = function(strategyMutation) {
        this.mutationsToDo.push(strategyMutation);
    }
    
    this.removeMutation = function(strategyMutation) {
    
        for (var i = 0; i < this.mutationsToDo.lenght; i++) {
            if (this.mutationsToDo[i] == strategyMutation) {
                this.mutationsToDo.splice(i, 1);
                break;
            }
        }
    }
    
    this.getNamesOfAllStrategies = function() {
    
        var ret = [];
        for (var name in this.knownStrategies) {
            ret.push(name);
        }
        return ret;
    }
    
    this.registerStrategy = function(name, strategy) {
        if (name.constructor != String) {
            throw new Error(" Expected String, got " + name.constructor);
        }
        this.knownStrategies[name] = strategy;
        strategiesCount++;
        return name;
    }
    
    /**
     * Registers a strategy and unregisters it automatically if it is done.
     * @param {Strategy} strategy
     */
    this.registerStrategyAutoUnregister = function(strategy) {
        this.knownStrategies[Animator.prototype.AUTO_REGISTER_PREFIX + autoRegisterCount++] = strategy;
    }
    
    this.isAutoUnregisterStrategy = function(strategyName) {
        return strategyName.indexOf(Animator.prototype.AUTO_REGISTER_PREFIX, 0) == 0;
    }
    
    this.unregisterStrategy = function(name) {
        delete this.knownStrategies[name];
        strategiesCount--;
    }
    
    this.pauseAllStrategies = function() {
        for (var strategyName in this.knownStrategies) {
            var strategy = this.knownStrategies[strategyName];
            strategy.pause();
        }
    }
    
    this.getStrategyById = function(strategyId) {
        return this.knownStrategies[strategyId];
    }
    
    function isRegistered(strategyName) {
        return this.knownStrategies[strategyName] != null;
    }
    
    this.stop = function() {
        clearInterval(loopInterval);
        loopInterval = null;
    }
    
    this.start = function() {
    
        if (loopInterval == null) {
            var anim = this;
            loopInterval = setInterval(function() {
            
                for (var strategyName in anim.knownStrategies) {
                    var strategy = anim.knownStrategies[strategyName];
                    
                    if (strategy.isDone()) {
                        if (anim.isAutoUnregisterStrategy(strategyName)) {
                            anim.unregisterStrategy(strategyName);
                        }
                        var nextStrategy = strategy.getNextStrategy();
                        if (nextStrategy != null && strategy.isItemBased() && nextStrategy.isItemBased()) {
                            nextStrategy.addItems(strategy.removeAllItems());
                        }
                        continue;
                    }
                    
                    if (!strategy.isRunning() || strategy.hasNothingToDo()) {
                        continue;
                    }
                    
                    strategy.perform();
                }
                
                if (anim.mutationsToDo.length > 0) {
                    anim.mutationsToDo.shift().doIt();
                }
                
            }, frameMs);
        }
    }
    
    this.toString = function() {
    
        var str = "";
        for (var strategyName in this.knownStrategies) {
            var strategy = this.knownStrategies[strategyName];
            str += strategyName +
            " => " +
            strategy.STRATEGYNAME +
            strategy.getStringBase() +
            "isAnimated: " +
            !strategy.hasNothingToDo() +
            "items: " +
            !strategy.getAllItems() +
            "\n\n";
        }
        return str;
    }
    
    this.dumpMutations = function() {
        var str = "++DUMP: Mutations to do:\n";
        for (var i = 0; i < this.mutationsToDo.length; i++) {
            str += "\t" + i + ": " + this.mutationsToDo[i].doIt + "\n"
        }
        if (this.mutationsToDo.length > 0) 
            return str + "\tnone!\n"
        else 
            return str + "\n"
    }
}

Animator.prototype.NORMAL_FRAME_MS = 15;

// used for auto-unregistering when finished
Animator.prototype.AUTO_REGISTER_PREFIX = "_@AUTO-REGISTERED@_:";

