class DefaultAnimationPlan implements AnimationPlan {

    @Override
    public DefaultAnimationState determineNextState(AnimationState state)
    {
        DefaultAnimationState animationState = getDefaultAnimationState(state);
        validateStepNumber(animationState.getStepNumber());
        int nextIndex;
        Direction nextDirection = animationState.getDirection();
        if (getAnimationSequence().size() > 1)
        {
            if (animationState.getDirection() == Direction.FORWARD)
            {
                nextIndex = animationState.getStepNumber() + 1;
                if (nextIndex >= getAnimationSequence().size())
                {
                    switch (getEndBehavior())
                    {
                        case BOUNCE:
                            nextDirection = animationState.getDirection().opposite();
                            nextIndex = animationState.getStepNumber() - 1;
                            break;
                        case STOP:
                            nextDirection = animationState.getDirection();
                            nextIndex = -1;
                            break;
                        case WRAP:
                            nextDirection = animationState.getDirection();
                            nextIndex = 0;
                            break;
                        default:
                            throw new UnexpectedEnumException(getEndBehavior());
                    }
                }
            }
            else
            {
                nextIndex = animationState.getStepNumber() - 1;
                if (nextIndex < 0)
                {
                    switch (getEndBehavior())
                    {
                        case BOUNCE:
                            nextDirection = animationState.getDirection().opposite();
                            nextIndex = animationState.getStepNumber() + 1;
                            break;
                        case STOP:
                            nextDirection = animationState.getDirection();
                            nextIndex = -1;
                            break;
                        case WRAP:
                            nextDirection = animationState.getDirection();
                            nextIndex = getAnimationSequence().size() - 1;
                            break;
                        default:
                            throw new UnexpectedEnumException(getEndBehavior());
                    }
                }
            }
        }
        else if (getEndBehavior() == EndBehavior.STOP)
        {
            return null;
        }
        else
        {
            nextDirection = getEndBehavior() == EndBehavior.WRAP ? state.getDirection() : state.getDirection().opposite();
            nextIndex = 0;
        }

        return nextIndex >= 0 ? new DefaultAnimationState(nextIndex, nextDirection) : null;
    }

    public  DefaultAnimationPlan(List<? extends TimeSpan> sequence, EndBehavior endBehavior);

}