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

import java.util.*;

/**
 * A class representing a single node in a graph. Each has reference to multiple children and no backwards
 * reference to their parent.
 *
 * Nodes hold two types of child, network children and residual children. Network children represent children
 * the graph. Residual children represent children in the most recently calculated residual network.
 */
public class GraphNode {
    private String id;
    static int counter = 0; // to generate id's when none given
    private boolean isSource;
    private boolean isSink;

    private List<GraphNode> networkChildren;
    private List<GraphNode> residualNetworkChildren;


    public void setAsSource() { isSource = true; id = "source";}
    public void setAsSink() { isSink = true; id = "sink";}
    public boolean isSource(){ return isSource; }
    public boolean isSink(){ return isSink; }

    public void setId(String id){this.id = id;}

    public List<GraphNode> getNetworkChildren() { return networkChildren; }
    public void addNetworkChildren(GraphNode[] children) {networkChildren.addAll(List.of(children));}
    public void addNetworkChild(GraphNode child) {networkChildren.add(child);}

    public List<GraphNode> getResidualNetworkChildren() { return residualNetworkChildren; }
    public void addResidualChild(GraphNode child){residualNetworkChildren.add(child);}
    public void removeResidualChildIfExists(GraphNode child){residualNetworkChildren.remove(child);}

    /**
     * Resets a residual network to contain all the regular networks children. This represents the
     * residual network of a node outside of flow. Anything within the flow can be calcualted
     * by removing the child in the flow and adding the parent.
     */
    public void resetResidualNetwork(){
        residualNetworkChildren = new ArrayList<>(networkChildren);
    }


    // constructor with default values
    public GraphNode(){
        this(null, null, counter++) ;
    }
    // constructor with pre-defined networks
    public GraphNode(GraphNode[] networkChildren, GraphNode[] residualNetworkChildren){
        this(networkChildren, residualNetworkChildren, counter++) ;
    }
    // constructor with predefined networks and a custom id
    public GraphNode(GraphNode[] networkChildren, GraphNode[] residualNetworkChildren, int id){
        if (networkChildren != null && networkChildren.length != 0)
            this.networkChildren = new ArrayList<>(List.of(networkChildren));
        else
            this.networkChildren = new ArrayList<>();

        if (residualNetworkChildren != null && residualNetworkChildren.length != 0)
            this.residualNetworkChildren = new ArrayList<>(List.of(residualNetworkChildren));
        else
            this.residualNetworkChildren = new ArrayList<>();


        this.id = Integer.toString(id);
    }

    @Override
    public String toString(){
        return id;
    }
}
