001/*
002 * Licensed to the author under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package de.cuioss.test.generator.internal.net.java.quickcheck.generator.support;
018
019import static java.lang.String.format;
020
021import java.util.ArrayList;
022import java.util.List;
023
024import de.cuioss.test.generator.internal.net.java.quickcheck.Generator;
025import de.cuioss.test.generator.internal.net.java.quickcheck.GeneratorException;
026
027/**
028 * Base class for tree generators.
029 *
030 * <p>
031 * The callback order is:
032 * </p>
033 * <ul>
034 * <li>{@link AbstractTreeGenerator#createNode()}: create current node</li>
035 * <li>{@link AbstractTreeGenerator#getChildCount(int, int)}: calculate number of child nodes</li>
036 * <li>(create child nodes)</li>
037 * <li>{@link AbstractTreeGenerator#addChildren(Object, List)}: add child nodes to node</li>
038 * </ul>
039 *
040 * @param <T> type of tree node
041 */
042public abstract class AbstractTreeGenerator<T> implements Generator<T> {
043
044    public static final int MAX_TREE_DEPTH = 50;
045
046    /**
047     * Create a node of type T.
048     */
049    protected abstract T createNode();
050
051    /**
052     * Add the created children to the parent node.
053     */
054    protected abstract void addChildren(T node, List<T> children);
055
056    /**
057     * Get the number of children for the current level.
058     *
059     * @param level
060     *            current level starting with 0 for the root level
061     * @param numberOfSiblings
062     *            number of siblings (number of siblings is 1 for the root
063     *            node.)
064     */
065    protected abstract int getChildCount(int level, int numberOfSiblings);
066
067    /**
068     * @return root node of the generated tree
069     */
070    @Override
071    public T next() {
072        return createNodeAndAddChildren(-1, 1);
073    }
074
075    private List<T> down(int level, int numberOfSiblings) {
076        checkDepth(level);
077        List<T> result = new ArrayList<>();
078        int childCount = getChildCount(level, numberOfSiblings);
079        for (int i = 0; i < childCount; i++) {
080            T node = createNodeAndAddChildren(level, childCount);
081            result.add(node);
082        }
083        return result;
084    }
085
086    private void checkDepth(int level) {
087        if (level > MAX_TREE_DEPTH) {
088            throw new GeneratorException(format(
089                    "Max tree depth (%s) exceeded.", MAX_TREE_DEPTH), this);
090        }
091    }
092
093    private T createNodeAndAddChildren(int level, int numberOfSiblings) {
094        T node = createNode();
095        addChildren(node, down(level + 1, numberOfSiblings));
096        return node;
097    }
098
099}