import copy
import random


def staticDepthLimit(max_depth):
    """Implement a static limit on the depth of a GP tree, as defined by Koza
    in [Koza1989]. It may be used to decorate both crossover and mutation
    operators. When an invalid (too high) child is generated, it is simply
    replaced by one of its parents.
    
    This operator can be used to avoid memory errors occuring when the tree
    gets higher than 90-95 levels (as Python puts a limit on the call stack
    depth), because it ensures that no tree higher than *max_depth* will ever
    be accepted in the population (except if it was generated at initialization
    time).
    
    :param max_depth: The maximum depth allowed for an individual.
    :returns: A decorator that can be applied to a GP operator using \
    :func:`~deap.base.Toolbox.decorate`

    .. note::
       If you want to reproduce the exact behavior intended by Koza, set
       the *max_depth* param to 17.
    
    .. [Koza1989] J.R. Koza, Genetic Programming - On the Programming of 
        Computers by Means of Natural Selection (MIT Press, 
        Cambridge, MA, 1992)

    """
    def decorator(func):
        def wrapper(*args, **kwargs):
            keep_inds = [copy.deepcopy(ind) for ind in args]
            new_inds = list(func(*args, **kwargs))
            for i, ind in enumerate(new_inds):
                if ind.height > max_depth:
                    new_inds[i] = random.choice(keep_inds)
            return new_inds
        return wrapper
    return decorator