package uk.ac.aber.cs31920.assignment.implementation.factories;

import uk.ac.aber.cs31920.assignment.implementation.datastructures.GraphNode;
import uk.ac.aber.cs31920.assignment.implementation.datastructures.MaxFlowGraph;
import uk.ac.aber.cs31920.assignment.implementation.datastructures.ProblemGrid;

import java.util.LinkedList;
import java.util.List;

/**
 * Factory class to generate a graph from a given problem grid.
 */
public class GraphFactory {
    public static MaxFlowGraph createGraphFromProblemGrid(ProblemGrid problemGrid){
        Boolean[][] grid = problemGrid.getContents();
        int size = problemGrid.size;

        GraphNode root = new GraphNode();
        root.setAsSource();
        GraphNode sink = new GraphNode();
        sink.setAsSink();

        GraphNode[][] nodeGrid = new GraphNode[size][size];
        List<GraphNode> allNodes = new LinkedList<GraphNode>(List.of(root, sink)); // linkedlist since we're just gonna be adding or iterating through

        // create nodes linked to source and sink
        for (int i = 0; i < grid.length; i++){
            boolean connectsToSink = !(i % 2 == 0);
            for (int j = 0; j < grid[i].length; j++){
                if (grid[i][j]) {
                    nodeGrid[i][j] = null;
                    connectsToSink = !connectsToSink;
                    continue;
                }

                GraphNode node = new GraphNode();
                node.setId("(" + j + ", " + i + ")"); // (x, y)
                if (connectsToSink){
                    node.addNetworkChild(sink);
                }
                else{
                    root.addNetworkChild(node);
                }
                connectsToSink = !connectsToSink;

                nodeGrid[i][j] = node;
                allNodes.add(node);
            }
        }

        // link nodes together
        for (int i = 0; i < nodeGrid.length; i++){
            for (int j = i%2; j < nodeGrid[i].length; j+=2){
                GraphNode node = nodeGrid[i][j];
                if (node == null)
                    continue;
                if (i != 0) {
                    if (nodeGrid[i-1][j] != null)
                        node.addNetworkChild(nodeGrid[i - 1][j]);
                }
                if (i != nodeGrid.length-1){
                    if (nodeGrid[i+1][j] != null)
                        node.addNetworkChild(nodeGrid[i + 1][j]);
                }
                if (j != 0) {
                    if (nodeGrid[i][j-1] != null)
                        node.addNetworkChild(nodeGrid[i][j - 1]);
                }
                if (j != nodeGrid[i].length-1){
                    if (nodeGrid[i][j+1] != null)
                        node.addNetworkChild(nodeGrid[i][j + 1]);
                }
            }
        }
        return new MaxFlowGraph(root, sink, allNodes);
    }
}
