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