package Algorithms;

import Model.LayeredGraphNode;
import Model.LayeredNode;

/**
 * creates random {@link LayeredGraphNode}s for testing purposes
 * @author kolja
 *
 */
public class RandomGraphGenerator {

    private double pSubgraph;
    private double pEdge;
    private int minLayer;
    private int maxLayer;
    private int minNodePerLayer;
    private int maxNodePerLayer;
    private int maxDepth;
    
    /**
     * sets the parameters for the random graph
     * @param pSubgraph the probability that a node contains a graph
     * @param pEdge the probability that there is an edge between two nodes in subsequent layers
     * @param minLayer the minimum number of layers in each graph
     * @param maxLayer the maximum number of layers in each graph
     * @param minNodePerLayer the minimum number of layers in each layer
     * @param maxNodePerLayer the maximum number of layers in each layer
     * @param maxDepth the maximum hierarchy depth
     */
    public RandomGraphGenerator( double pSubgraph, double pEdge, int minLayer, int maxLayer, int minNodePerLayer, int maxNodePerLayer, int maxDepth )
    {
        this.pSubgraph = pSubgraph;
        this.pEdge = pEdge;
        this.minLayer = minLayer;
        this.maxLayer = maxLayer;
        this.minNodePerLayer = minNodePerLayer;
        this.maxNodePerLayer = maxNodePerLayer;
        this.maxDepth = maxDepth;
    }
    
    /**
     * creates a random {@link LayeredGraphNode} using the parameters given to the constructor of the {@link RandomGraphGenerator}
     * @param parent the parent node of the nodes in the graph
     * @param depth the current depth of the graph (used to check if the maximum depth is reached)
     * @return the generated {@link LayeredGraphNode}
     */
    public LayeredGraphNode createRandomNode( LayeredGraphNode parent, int depth )
    {
        LayeredGraphNode node = new LayeredNode( null, null );
        if( parent != null )
            node = parent.createNode( null );
        if( ( Math.random() <= pSubgraph && depth < maxDepth ) || depth == 0 )
        {
            int layer = (int)( Math.random() * ( maxLayer - minLayer ) ) + minLayer;
            for( int i = 0; i < layer; i++ )
            {
                int knoten = (int)( Math.random() * ( maxNodePerLayer - minNodePerLayer ) ) + minNodePerLayer;
                for( int j = 0; j < knoten; j++ )
                {
                    LayeredGraphNode n = createRandomNode( node, depth + 1 );
                    n.setLayer( i );
                    if( i > 0 )
                    {
                        for( LayeredGraphNode n2 : node.getContainedLayers().get( i - 1 ) )
                        {
                            if( Math.random() <= pEdge )
                                node.createSimpleEdge( null, n2, n );
                        }
                    }
                }
            }
        }
        return node;
    }
}
