/**
 * @author Patrick Kopp
 */
function StrategyMutator(itsAnimator) {

    var animator = itsAnimator;
    
    this.moveItemToPoint = function(item, point, steps) {
        animator.addMutation(new MutationItemToPoint(animator, item, point, steps));
    }
    
    this.lineUpItems = function(items, lineStart, lineEnd, steps) {
        animator.addMutation(new MutationLineUpItems(animator, items, lineStart, lineEnd, steps));
    }
    
    this.lineUpItemsOfStrategy = function(strategyToTakeItemsFrom, lineStart, lineEnd, steps) {
        animator.addMutation(new MutationLineUpItemsOfStrategy(animator, strategyToTakeItemsFrom, lineStart, lineEnd, steps));
    }
    
    this.fadeItemsToStandingTwisters = function(items, positions, fadeSteps, standSteps) {
        animator.addMutation(new MutationItemsToStandingTwisters(animator, items, positions, fadeSteps, standSteps));
    }
    
    this.doWebJ = function(strategyToMutate, itemsToRemove, itemsToAdd) {
        animator.addMutation(new MutationAddRemoveItems(animator, strategyToMutate, itemsToRemove, itemsToAdd));
    }
}

function MutationItemsToStandingTwisters(mAnimator, mItems, mPoints, mFadeSteps, mStandSteps) {

    var animator = mAnimator;
    var items = mItems;
    var points = mPoints;
    var fadeSteps = mFadeSteps;
    var standSteps = mStandSteps;
    var frameOffset = Math.floor(standSteps / items.length - 1);
    
    this.doIt = function() {
        for (var i = 0; i < items.length; i++) {
            var strategy = new StrategyTwister(standSteps, points[i], standingRadius, standingAngSpeed);
            strategy.setFrame((i + 1) * frameOffset);
            animator.registerStrategyAutoUnregister(strategy);
            new MutationFadeItemToStrategy(animator, items[i], strategy, fadeSteps).doIt();
        }
    }
}

function MutationStrategyToStrategy(mAnimator, mStrategy, mNewStrategy, mSteps) {

    var animator = mAnimator;
    var strategy = mStrategy;
    var newStrategy = mNewStrategy;
    var steps = mSteps;
    
    this.doIt = function() {
    
        if (strategy == newStrategy) {
            return;
        }
        var items = strategy.getAllItems();
        new MutationItemsToStrategy(animator, items, newStrategy, steps).doIt();
    }
}

function MutationItemToPoint(mAnimator, mItem, mPoint, mSteps) {

    if(mItem == null) {
        throw new Error("Item must not be null");
    }
    
    if(mItem.id == null) {
        throw new Error("Null id on " + mItem);
    }
    
    var animator = mAnimator;
    var item = mItem;
    var point = mPoint;
    var steps = mSteps;
    
    this.doIt = function() {
        
        var itemStrategy = item.movementStrategy;
        if (itemStrategy != null) {
            itemStrategy.setNextStrategy(null);
        }
        
        var line = new StrategyLine(item, item.getPosition(), point, steps);
        item.setMovementStrategy(line);
        if (itemStrategy != null) {
            itemStrategy.removeItem(item);
        }
        
        animator.registerStrategyAutoUnregister(line);
    }
}

function MutationLineUpItems(mAnimator, mItems, mLineStart, mLineEnd, mSteps) {
    
    var animator = mAnimator;
    var items = mItems;
    var lineStart = mLineStart;
    var lineEnd = mLineEnd;
    var steps = mSteps;
    
    this.doIt = function() {
        var line = new Line(lineStart, lineEnd);
        var posToMoveTo = line.getPoints(items.length);
        
        for (var i = 0; i < items.length; i++) {
            new MutationItemToPoint(animator, items[i], posToMoveTo[i], steps).doIt();
        }
    }
}

function MutationLineUpItemsOfStrategy(mAnimator, mStrategy, mLineStart, mLineEnd, mSteps) {
    var animator = mAnimator;
    var strategy = mStrategy;
    var lineStart = mLineStart;
    var lineEnd = mLineEnd;
    var steps = mSteps;
    
    this.doIt = function() {
        new MutationLineUpItems(animator, mStrategy.getAllItems(), lineStart, lineEnd, steps);
    }
}

function MutationAddRemoveItems(meAnimator, meStrategyToMutate, mItemsToRemove, mItemsToAdd) {

    var itemsToRemove = mItemsToRemove;
    var itemsToAdd = mItemsToAdd;
    var animator = meAnimator;
    var strategyToMutate = meStrategyToMutate;
    
    var transitionSteps = 50;
    
    this.doIt = function() {
    
        for (var i = 0; i < itemsToRemove.length; i++) {
            if (itemsToRemove[i] != null) {
                var item = itemsToRemove[i];
                if (item.movementStrategy) {
                    item.movementStrategy.removeItem(item);
                }
                item.hide();
                if (item.neighbor && $(item.neighbor.div)) {
                    var elem = $(item.neighbor.div);
                    if (elem.parentNode) {
                        elem.parentNode.removeChild(elem);
                    }
                }
                if ($(item.div)) {
                    var elem = $(item.div);
                    if (elem.parentNode) {
                        elem.parentNode.removeChild(elem);
                    }
                }
                if (DEBUG) 
                    console.debug("webj: destroyed:" + item.id);
                
            }
        }
        
        for (var i = 0; i < itemsToAdd.length; i++) {
        
            var item = itemsToAdd[i];
            var mutator = new MutationFadeItemToStrategy(animator, item, strategyToMutate, transitionSteps);
            mutator.doIt();
            if (DEBUG) 
                console.debug("webj: added:" + item.id);
            
            //            var futurePos = strategyToMutate.getFuturePoints(1, transitionSteps);
            //            var line = new StrategyLine(item, item.getPosition(), futurePos[0], transitionSteps);
            //            line.setNextStrategy(strategyToMutate);
            //	          animator.registerStrategyAutoUnregister(line);
            //            if(DEBUG) console.debug("webj: added:" + item.id);
        }
    }
}

function LetThemHop(animator, items, points, steps) {
    var animator = animator;
    var steps = steps;
    var items = items;
    var computedPoints = [];
    
    items.each(function(item) {
    
        var pointsOfItem = [];
        var pos = item.getPosition();
        //pointsOfItem.push(new StrategyPause(item, 1000));
        points.each(function(point) {
            pointsOfItem.push(point.add(pos));
        });
        computedPoints.push(pointsOfItem);
    }
.bind(this));
    
    this.doIt = function() {
    
        for (var i = 0; i < computedPoints.length; i++) {
        
            var item = items[i];
            var pointsOfItem = computedPoints[i];
            
            var poli = new StrategyPolygon(item, pointsOfItem, false, steps);
            animator.registerStrategyAutoUnregister(poli);
        }
    }
}

function LetThemHop2(animator, items, amplitude, hops, steps, delay) {
    var animator = animator;
    var items = items;
    var amplitude = amplitude;
    var hops = hops;
    var steps = steps;
    var delay = delay;
    var computedPoints = [];
    
    items.each(function(item) {
    
        var pointsOfItem = [];
        //pointsOfItem.push(new StrategyPause(item, Math.round(Math.random() * delay)));
        
        var pos = item.getPosition();
        
        for (var i = 0; i < hops; i++) {
            var x = Math.round(Math.random() * amplitude);
            var y = Math.round(Math.random() * amplitude);
            pointsOfItem.push(pos.add(new Point(x, y)));
        }
        
        pointsOfItem.push(pos.clone());
        
        computedPoints.push(pointsOfItem);
        
    }
.bind(this));
    
    //alert(computedPoints.join("\n"));
    
    this.doIt = function() {
    
        for (var i = 0; i < computedPoints.length; i++) {
        
            var item = items[i];
            var pointsOfItem = computedPoints[i];
            
            var poli = new StrategyPolygon(item, pointsOfItem, false, steps);
            animator.registerStrategyAutoUnregister(poli);
        }
    }
}

