/*
         *  1) Check contradiction
         *  2) Alpha rules
         *  3) Delta rules
         *  4) Beta rules
         *  5) Gamma rules
         */
        /// <summary>
        /// Build the Semantic Tableau
        /// </summary>
        /// <returns>True if the formula is Unsatifiable (has contradiction)</returns>
        public bool BuildUtil(TableauNode curNode) // return true if contradiction
        {
            TableauNode newNode = new TableauNode(curNode.SetFormulas, curNode.CurrentVariables);

            if (CheckContradiction(newNode.SetFormulas))
            {
                newNode.SetFormulas = new HashSet <Symbol>()
                {
                    new Constant('0')
                };
                curNode.Childs.Add(newNode);
                return(true);
            }

            HashSet <Symbol> formulas = newNode.SetFormulas;

            //////////////////////////////////////////////////////////////
            // Alpha Rules
            //////////////////////////////////////////////////////////////

            formulas = ExpandAllAnds(newNode, true, false);

            if (!TableauNode.EqualSet(formulas, curNode.SetFormulas)) // successful
            {
                newNode.RuleApplied = TableauRule.ALPHA;
                curNode.Childs.Add(newNode);

                return(BuildUtil(newNode));
            }

            // Haven't applied Alpha rules
            // Continue with

            //////////////////////////////////////////////////////////////
            // Delta rules
            //////////////////////////////////////////////////////////////

            formulas = ExpandAllAnds(newNode, false, true);

            if (!TableauNode.EqualSet(formulas, curNode.SetFormulas)) // successful
            {
                newNode.RuleApplied = TableauRule.DELTA;
                curNode.Childs.Add(newNode);

                return(BuildUtil(newNode));
            }


            //////////////////////////////////////////////////////////////
            // Beta Rules
            //////////////////////////////////////////////////////////////
            bool CurrentlyContradicted = true;

            Symbol        chosenFormula = null;                // The formula that can be applied beta rules
            List <Symbol> expansion     = new List <Symbol>(); // expanded version of the chosen formula

            // Find a subformula that can be applied beta rules
            foreach (Symbol subformula in formulas)
            {
                expansion = ExpandToOr(subformula);

                if (expansion is null)
                {
                    continue;
                }

                chosenFormula = subformula;
                break;
            }

            // There exist a formula expanded.
            if (!(chosenFormula == null))
            {
                formulas.Remove(chosenFormula); // remove the formula

                foreach (Symbol term in expansion)
                {
                    formulas.Add(term); // Add an expanded subformula

                    var newSet = new HashSet <Symbol>(new SymbolComparer());
                    foreach (var item in formulas)
                    {
                        newSet.Add(ObjectExtensions.Copy(item));
                    }

                    TableauNode tmpNode = new TableauNode(newSet, curNode.CurrentVariables);
                    tmpNode.RuleApplied = TableauRule.BETA;

                    curNode.Childs.Add(tmpNode);

                    if (!BuildUtil(tmpNode))
                    {
                        CurrentlyContradicted = false;
                    }

                    formulas.Remove(term);
                }

                return(CurrentlyContradicted); // both childs must be contradition
            }

            //////////////////////////////////////////////////////////////
            // Gamma rules
            //////////////////////////////////////////////////////////////


            var expansionStorage = new HashSet <Symbol>(new SymbolComparer());

            expansion = new List <Symbol>();

            foreach (var subformula in formulas)
            {
                expansion = GammaRules(subformula, newNode);

                if (expansion is null)
                {
                    continue;
                }

                foreach (var expansionTerm in expansion)
                {
                    expansionStorage.Add(expansionTerm);
                }
            }

            if (expansionStorage.Count > 0)
            {
                foreach (var expansionTerm in expansionStorage)
                {
                    formulas.Add(expansionTerm);
                }

                curNode.Childs.Add(newNode);
                newNode.RuleApplied = TableauRule.GAMMA;

                return(BuildUtil(newNode));
            }

            return(false);
        }
        public int GenerateGraphUtil(StreamWriter sw, TableauNode u)
        {
            string content = ""; // text of the Tableau Node (the set of formulas at the current node)

            // Add all formulas to the content
            foreach (var formula in u.SetFormulas)
            {
                content += formula.ToString() + "\n";
            }
            //content = content.Remove(content.Length - 1); // remove last ','
            //content = content.Remove(1, 1); // remove first space
            //content += "]";

            // List active variables
            content += " [";

            foreach (char c in u.ListVariables)
            {
                content += c + ",";
            }

            if (content[content.Length - 1] == ',')
            {
                content = content.Remove(content.Length - 1); // remove last ','
            }
            content += "]";

            int uNum = Counter; // ID of current node

            string fillColor = (u.RuleApplied == TableauRule.ALPHA ? "yellow" :
                                u.RuleApplied == TableauRule.BETA ? "palegreen" :
                                u.RuleApplied == TableauRule.DELTA ? "skyblue" :
                                u.RuleApplied == TableauRule.GAMMA ? "brown1" :
                                "gray88");
            // content of the node
            string graphvizContent = $"\tnode{uNum} [shape=rectangle; style = filled;" +
                                     $"label = \"{content}\"; color = black; fillcolor={fillColor}];";

            // if this node is a contradiction (a node containing only false)
            // then color it red
            if (TableauNode.EqualSet(u.SetFormulas, new HashSet <Symbol>()
            {
                new Constant('0')
            }))
            {
                graphvizContent = $"\tnode{uNum} [shape=rectangle; style=filled;" +
                                  $"label = \"{content}\"; color=crimson fillcolor={fillColor}];";
            }

            // draw current node
            sw.WriteLine(graphvizContent);

            foreach (TableauNode v in u.Childs)
            {
                Counter++;
                int vNum = GenerateGraphUtil(sw, v);
                sw.WriteLine("\tnode{0} -- node{1};", uNum, vNum); // draw edge to child node
            }

            return(uNum); // return ID of current node
        }