/* ==========================================
 * JGraphT : a free Java graph-theory library
 * ==========================================
 *
 * Project Info:  http://jgrapht.sourceforge.net/
 * Project Creator:  Barak Naveh (http://sourceforge.net/users/barak_naveh)
 *
 * (C) Copyright 2003-2008, by Barak Naveh and Contributors.
 *
 * This program and the accompanying materials are dual-licensed under
 * either
 *
 * (a) the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation, or (at your option) any
 * later version.
 *
 * or (per the licensee's choosing)
 *
 * (b) the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation.
 */
/* -----------------------
 * GraphGeneratorTest.java
 * -----------------------
 * (C) Copyright 2003-2008, by John V. Sichi and Contributors.
 *
 * Original Author:  John V. Sichi
 * Contributor(s):   -
 *
 * $Id$
 *
 * Changes
 * -------
 * 17-Sep-2003 : Initial revision (JVS);
 * 07-May-2006 : Changed from List<Edge> to Set<Edge> (JVS);
 *
 */
package org.jgrapht.generate;

import java.util.*;

import junit.framework.*;

import org.jgrapht.*;
import org.jgrapht.alg.*;
import org.jgrapht.graph.*;


/**
 * .
 *
 * @author John V. Sichi
 * @since Sep 17, 2003
 */
public class GraphGeneratorTest
    extends TestCase
{
    //~ Static fields/initializers ---------------------------------------------

    private static final int SIZE = 10;

    //~ Instance fields --------------------------------------------------------

    private VertexFactory<Object> vertexFactory =
        new VertexFactory<Object>() {
            private int i;

            public Object createVertex()
            {
                return new Integer(++i);
            }
        };

    //~ Methods ----------------------------------------------------------------

    /**
     * .
     */
    public void testEmptyGraphGenerator()
    {
        GraphGenerator<Object, DefaultEdge, Object> gen =
            new EmptyGraphGenerator<Object, DefaultEdge>(SIZE);
        DirectedGraph<Object, DefaultEdge> g =
            new DefaultDirectedGraph<Object, DefaultEdge>(DefaultEdge.class);
        Map<String, Object> resultMap = new HashMap<String, Object>();
        gen.generateGraph(g, vertexFactory, resultMap);
        assertEquals(SIZE, g.vertexSet().size());
        assertEquals(0, g.edgeSet().size());
        assertTrue(resultMap.isEmpty());
    }

    /**
     * .
     */
    public void testLinearGraphGenerator()
    {
        GraphGenerator<Object, DefaultEdge, Object> gen =
            new LinearGraphGenerator<Object, DefaultEdge>(SIZE);
        DirectedGraph<Object, DefaultEdge> g =
            new DefaultDirectedGraph<Object, DefaultEdge>(DefaultEdge.class);
        Map<String, Object> resultMap = new HashMap<String, Object>();
        gen.generateGraph(g, vertexFactory, resultMap);
        assertEquals(SIZE, g.vertexSet().size());
        assertEquals(SIZE - 1, g.edgeSet().size());

        Object startVertex = resultMap.get(LinearGraphGenerator.START_VERTEX);
        Object endVertex = resultMap.get(LinearGraphGenerator.END_VERTEX);
        Iterator vertexIter = g.vertexSet().iterator();

        while (vertexIter.hasNext()) {
            Object vertex = vertexIter.next();

            if (vertex == startVertex) {
                assertEquals(0, g.inDegreeOf(vertex));
                assertEquals(1, g.outDegreeOf(vertex));

                continue;
            }

            if (vertex == endVertex) {
                assertEquals(1, g.inDegreeOf(vertex));
                assertEquals(0, g.outDegreeOf(vertex));

                continue;
            }

            assertEquals(1, g.inDegreeOf(vertex));
            assertEquals(1, g.outDegreeOf(vertex));
        }
    }

    /**
     * .
     */
    public void testRingGraphGenerator()
    {
        GraphGenerator<Object, DefaultEdge, Object> gen =
            new RingGraphGenerator<Object, DefaultEdge>(SIZE);
        DirectedGraph<Object, DefaultEdge> g =
            new DefaultDirectedGraph<Object, DefaultEdge>(DefaultEdge.class);
        Map<String, Object> resultMap = new HashMap<String, Object>();
        gen.generateGraph(g, vertexFactory, resultMap);
        assertEquals(SIZE, g.vertexSet().size());
        assertEquals(SIZE, g.edgeSet().size());

        Object startVertex = g.vertexSet().iterator().next();
        assertEquals(1, g.outDegreeOf(startVertex));

        Object nextVertex = startVertex;
        Set<Object> seen = new HashSet<Object>();

        for (int i = 0; i < SIZE; ++i) {
            DefaultEdge nextEdge =
                g.outgoingEdgesOf(nextVertex).iterator().next();
            nextVertex = g.getEdgeTarget(nextEdge);
            assertEquals(1, g.inDegreeOf(nextVertex));
            assertEquals(1, g.outDegreeOf(nextVertex));
            assertTrue(!seen.contains(nextVertex));
            seen.add(nextVertex);
        }

        // do you ever get the feeling you're going in circles?
        assertTrue(nextVertex == startVertex);
        assertTrue(resultMap.isEmpty());
    }

    /**
     * .
     */
    public void testCompleteGraphGenerator()
    {
        Graph<Object, DefaultEdge> completeGraph =
            new SimpleGraph<Object, DefaultEdge>(DefaultEdge.class);
        CompleteGraphGenerator<Object, DefaultEdge> completeGenerator =
            new CompleteGraphGenerator<Object, DefaultEdge>(10);
        completeGenerator.generateGraph(
            completeGraph,
            new ClassBasedVertexFactory<Object>(Object.class),
            null);

        // complete graph with 10 vertices has 10*(10-1)/2 = 45 edges
        assertEquals(45, completeGraph.edgeSet().size());
    }

    /**
     * .
     */
    public void testScaleFreeGraphGenerator()
    {
        DirectedGraph<Object, DefaultEdge> graph =
            new DefaultDirectedGraph<Object, DefaultEdge>(DefaultEdge.class);
        ScaleFreeGraphGenerator<Object, DefaultEdge> generator =
            new ScaleFreeGraphGenerator<Object, DefaultEdge>(500);
        generator.generateGraph(graph, vertexFactory, null);
        ConnectivityInspector<Object, DefaultEdge> inspector =
            new ConnectivityInspector<Object, DefaultEdge>(graph);
        assertTrue(
            "generated graph is not connected",
            inspector.isGraphConnected());

        try {
            generator = new ScaleFreeGraphGenerator<Object, DefaultEdge>(-50);
            fail("IllegalArgumentException expected");
        } catch (IllegalArgumentException e) {
        }

        try {
            generator =
                new ScaleFreeGraphGenerator<Object, DefaultEdge>(-50, 31337);
            fail("IllegalArgumentException expected");
        } catch (IllegalArgumentException e) {
        }

        generator = new ScaleFreeGraphGenerator<Object, DefaultEdge>(0);
        DirectedGraph<Object, DefaultEdge> empty =
            new DefaultDirectedGraph<Object, DefaultEdge>(DefaultEdge.class);
        generator.generateGraph(empty, vertexFactory, null);
        assertTrue("non-empty graph generated", empty.vertexSet().size() == 0);
    }

    /**
     * .
     */
    public void testCompleteBipartiteGraphGenerator()
    {
        Graph<Object, DefaultEdge> completeBipartiteGraph =
            new SimpleGraph<Object, DefaultEdge>(
                DefaultEdge.class);
        CompleteBipartiteGraphGenerator<Object, DefaultEdge> completeBipartiteGenerator =
            new CompleteBipartiteGraphGenerator<Object, DefaultEdge>(
                10,
                4);
        completeBipartiteGenerator.generateGraph(
            completeBipartiteGraph,
            new ClassBasedVertexFactory<Object>(Object.class),
            null);

        // Complete bipartite graph with 10 and 4 vertices should have 14
        // total vertices and 4*10=40 total edges
        assertEquals(14, completeBipartiteGraph.vertexSet().size());
        assertEquals(40, completeBipartiteGraph.edgeSet().size());
    }

    /**
     * .
     */
    public void testHyperCubeGraphGenerator()
    {
        Graph<Object, DefaultEdge> hyperCubeGraph =
            new SimpleGraph<Object, DefaultEdge>(
                DefaultEdge.class);
        HyperCubeGraphGenerator<Object, DefaultEdge> hyperCubeGenerator =
            new HyperCubeGraphGenerator<Object, DefaultEdge>(
                4);
        hyperCubeGenerator.generateGraph(
            hyperCubeGraph,
            new ClassBasedVertexFactory<Object>(Object.class),
            null);

        // Hypercube of 4 dimensions should have 2^4=16 vertices and
        // 4*2^(4-1)=32 total edges
        assertEquals(16, hyperCubeGraph.vertexSet().size());
        assertEquals(32, hyperCubeGraph.edgeSet().size());
    }

    /**
     * .
     */
    public void testStarGraphGenerator()
    {
        Map<String, Object> map = new HashMap<String, Object>();
        Graph<Object, DefaultEdge> starGraph =
            new SimpleGraph<Object, DefaultEdge>(
                DefaultEdge.class);
        StarGraphGenerator<Object, DefaultEdge> starGenerator =
            new StarGraphGenerator<Object, DefaultEdge>(
                10);
        starGenerator.generateGraph(
            starGraph,
            new ClassBasedVertexFactory<Object>(Object.class),
            map);

        // Star graph of order 10 should have 10 vertices and 9 edges
        assertEquals(9, starGraph.edgeSet().size());
        assertEquals(10, starGraph.vertexSet().size());
        assertTrue(map.get(StarGraphGenerator.CENTER_VERTEX) != null);
    }

    /**
     * .
     */
    public void testGridGraphGenerator()
    {
        int rows = 3;
        int cols = 4;

        //the form of these two classes helps debugging
        class StringVertexFactory
            implements VertexFactory<String>
        {
            int index = 1;

            @Override public String createVertex()
            {
                return String.valueOf(index++);
            }
        }

        class StringEdgeFactory
            implements EdgeFactory<String, String>
        {
            @Override public String createEdge(
                String sourceVertex,
                String targetVertex)
            {
                return new String(sourceVertex + '-' + targetVertex);
            }
        }

        GridGraphGenerator<String, String> generator =
            new GridGraphGenerator<String, String>(rows, cols);
        Map<String, String> resultMap = new HashMap<String, String>();

        //validating a directed and undirected graph
        Graph<String, String> directedGridGraph =
            new DefaultDirectedGraph<String, String>(new StringEdgeFactory());
        generator.generateGraph(
            directedGridGraph,
            new StringVertexFactory(),
            resultMap);
        validateGridGraphGenerator(rows, cols, directedGridGraph, resultMap);

        resultMap.clear();
        Graph<String, String> undirectedGridGraph =
            new SimpleGraph<String, String>(new StringEdgeFactory());
        generator.generateGraph(
            undirectedGridGraph,
            new StringVertexFactory(),
            resultMap);
        validateGridGraphGenerator(rows, cols, undirectedGridGraph, resultMap);
    }

    public void validateGridGraphGenerator(
        int rows,
        int cols,
        Graph<String, String> gridGraph,
        Map<String, String> resultMap)
    {
        // graph structure validations
        int expectedVerticeNum = rows * cols;
        assertEquals(
            "number of vertices is wrong (" + gridGraph
            .vertexSet().size()
            + "), should be " + expectedVerticeNum,
            expectedVerticeNum,
            gridGraph.vertexSet().size());
        int expectedEdgesNum =
            (((rows - 1) * cols) + ((cols - 1) * rows))
            * ((gridGraph instanceof UndirectedGraph) ? 1 : 2);
        assertEquals(
            "number of edges is wrong (" + gridGraph
            .edgeSet().size()
            + "), should be " + expectedEdgesNum,
            expectedEdgesNum,
            gridGraph.edgeSet().size());

        int cornerVertices = 0, borderVertices = 0, innerVertices = 0,
            neighborsSize;
        int expCornerVertices = 4;
        int expBorderVertices =
            Math.max(((rows - 2) * 2) + ((cols - 2) * 2), 0);
        int expInnerVertices = Math.max((rows - 2) * (cols - 2), 0);
        Set<String> neighbors = new HashSet<String>();

        for (String v : gridGraph.vertexSet()) {
            neighbors.clear();
            neighbors.addAll(Graphs.neighborListOf(gridGraph, v));
            neighborsSize = neighbors.size();
            assertTrue(
                "vertex with illegal number of neighbors (" + neighborsSize
                + ").",
                (neighborsSize == 2)
                || (neighborsSize == 3)
                || (neighborsSize == 4));
            if (neighborsSize == 2) {
                cornerVertices++;
            } else if (neighborsSize == 3) {
                borderVertices++;
            } else if (neighborsSize == 4) {
                innerVertices++;
            }
        }
        assertEquals(
            "there should be exactly " + expCornerVertices
            + " corner (with two neighbors) vertices. "
            + " actual number is " + cornerVertices + ".",
            expCornerVertices,
            cornerVertices);
        assertEquals(
            "there should be exactly " + expBorderVertices
            + " border (with three neighbors) vertices. "
            + " actual number is " + borderVertices + ".",
            expBorderVertices,
            borderVertices);
        assertEquals(
            "there should be exactly " + expInnerVertices
            + " inner (with four neighbors) vertices. "
            + " actual number is " + innerVertices + ".",
            expInnerVertices,
            innerVertices);

        // result map validations
        Set<String> keys = resultMap.keySet();
        assertEquals(
            "result map contains should contains exactly 4 corner verices",
            4,
            keys.size());

        for (String key : keys) {
            neighbors.clear();
            neighbors.addAll(
                Graphs.neighborListOf(gridGraph, resultMap.get(key)));
            neighborsSize = neighbors.size();
            assertEquals(
                "corner vertex should have exactly 2 neighbors",
                2,
                neighborsSize);
        }
    }
}

// End GraphGeneratorTest.java
