using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using U.ListOperations;
using U.StringOperations;

namespace U.Graph
{
    class GraphValidity
    {
        private static List<string> nodeLabels;
        private static List<string> arcLabels;
        private static List<string> pathLabels;

        internal static void check(Graph graph)
        {
            initializeLists(graph);
            checkUniqueness(graph);
            checkEdges(graph);
            checkPaths(graph);
            clearLists();
        }

        private static void initializeLists(Graph graph)
        {
            if (graph.getNodes() == null) { throw new Graph.InvalidGraphException("graph should include at least two nodes"); }
            if (graph.getArcs() == null) { throw new Graph.InvalidGraphException("graph should include at least one arc"); }
            nodeLabels = new List<string>(); foreach (Node node in graph.getNodes()) { nodeLabels.Add(node.getLabel()); }
            arcLabels = new List<string>(); foreach (Arc arc in graph.getArcs()) { arcLabels.Add(arc.getLabel()); }
            pathLabels = new List<string>(); foreach (Path path in graph.getPaths()) { pathLabels.Add(path.getLabel()); }
        }
        private static void clearLists()
        {
            nodeLabels.Clear(); nodeLabels = null;
            arcLabels.Clear(); arcLabels = null;
            pathLabels.Clear(); pathLabels = null;
        }
        private static void checkUniqueness(Graph graph)
        {
            if (nodeLabels.Count != UList.distinct(nodeLabels).Count) { throw new Graph.InvalidGraphException("at least one node is inserted more than once"); }
            if (arcLabels.Count != UList.distinct(arcLabels).Count) { throw new Graph.InvalidGraphException("at least one arc is inserted more than once"); }
            if (pathLabels.Count != UList.distinct(pathLabels).Count) { throw new Graph.InvalidGraphException("at least one path is inserted more than once"); }
        }

        private static void checkEdges(Graph graph)
        {
            for (int i = 0; i < graph.getArcs().Length; i++)
            {
                Arc arc = graph.getArcs()[i];
                if (nodeLabels.IndexOf(arc.getFromLabel()) == -1) { throw new Graph.InvalidGraphException("from node of arc '" + arc.getLabel() + "' does not exist in the graph"); }
                if (nodeLabels.IndexOf(arc.getToLabel()) == -1) { throw new Graph.InvalidGraphException("to node of arc '" + arc.getLabel() + "' does not exist in the graph"); }
            }
        }

        private static void checkPaths(Graph graph)
        {
            /*
            foreach (Path path in graph.getPaths())
            {
                for (int i = 0; i < path.getNodeLabels().Length - 1; i++)
                {
                    string arcLabel = Str.combine(path.getNodeLabels()[i], path.getNodeLabels()[i + 1], Str.Delimiter.Dash);
                    int arcIndex = arcLabels.IndexOf(arcLabel);
                    if (arcIndex == -1) { throw new Graph.InvalidGraphException("arc '" + arcLabel + "' in path '" + path.getLabel() + "' does not exist in the graph"); }
                }
            }//*/
        }

    }
}
