/// <summary>
        /// Expects a string similar to:
        /// E={a|O,b|O},true
        /// Indicating that two strings are legal in state E:
        /// a, which maps to O, and b, which maps to O, as well as e being an accepting state.
        ///
        /// Doesn't fully populate the State Object, and instead, returns a partially populated state object, with a list(tuple(string, statename) indicating the mapping states.
        /// </summary>
        /// <param name="s">the string to parse.</param>
        /// <returns>A Tuple representing a <see cref="DeterministicState"/>, and list of tuple(string,string) describing the legal characters and state transformations of the <see cref="DeterministicState"/>, for secondary parsing.</returns>
        private static Tuple <DeterministicState, List <Tuple <string, string> > > ParseStateLine(string s)
        {
            if (!s.Contains("="))
            {
                throw new Exception("Missing a '=' symbol on line '" + s + "'");
            }

            string stateName           = s.Trim().Substring(0, s.Trim().IndexOf("=")).Trim();
            string map                 = s.Substring(s.IndexOf('{') + 1, s.IndexOf('}') - s.IndexOf('{') - 1);
            string isAcceptingUnparsed = s.Substring(s.IndexOf(",", s.IndexOf('}')) + 1).Trim();

            DeterministicState retState = new DeterministicState
            {
                StateName   = stateName,
                IsAccepting = bool.Parse(isAcceptingUnparsed),
            };

            List <Tuple <string, string> > mapDef = new List <Tuple <string, string> >();

            string[] splitMapDefsZero = map.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (string splitMapDef in splitMapDefsZero)
            {
                string trimmedSplitMaPdef = splitMapDef.Trim();
                int    pipeIndex          = trimmedSplitMaPdef.Trim().IndexOf('|');
                string val         = trimmedSplitMaPdef.Substring(0, pipeIndex).Trim();
                string mappedState = trimmedSplitMaPdef.Substring(pipeIndex + 1).Trim();

                mapDef.Add(new Tuple <string, string>(val, mappedState));
            }

            return(new Tuple <DeterministicState, List <Tuple <string, string> > >(retState, mapDef));
        }
        /// <summary>
        /// Evaluates whether two provided <see cref="DeterministicState"/>s are equal by value.
        /// <para>Note: If every <see cref="DeterministicState"/> S in <paramref name="left"/> has a corresponding <see cref="DeterministicState"/> with an identical NAME in <paramref name="right"/>,
        /// they are assumed to be equal, even if the states mapped are not actually the same by ref, or have differing definitions.</para>
        /// </summary>
        /// <param name="left">The left <see cref="DeterministicState"/> to compare.</param>
        /// <param name="right">The right <see cref="DeterministicState"/> to compare.</param>
        /// <returns><see langword="true"/> if <paramref name="left"/> equals <paramref name="right"/>, else, <see langword="false"/>.</returns>
        public static bool ValueEquals(this DeterministicState left, DeterministicState right)
        {
            if (left.AreValueInequalByNullDisparity(right))
            {
                return(false);
            }

            if (object.ReferenceEquals(left, right))
            {
                return(true);
            }

            if (left.StateName != right.StateName ||
                left.IsAccepting != right.IsAccepting ||
                left.AcceptableStrings.AreValueInequalByNullDisparity(right.AcceptableStrings) ||
                left.AcceptableStrings?.Count != right.AcceptableStrings?.Count)
            {
                return(false);
            }

            foreach (var keyPair in left.AcceptableStrings)
            {
                if (!right.AcceptableStrings.ContainsKey(keyPair.Key))
                {
                    return(false);
                }
            }

            return(true);
        }
        private static ParseStringResults EvalDFA(DFA dfa, string data)
        {
            ParseStringResults retVal = new ParseStringResults
            {
                Input = data,
                CorrespondingAutomaton = dfa,
            };

            DeterministicState currState = null;
            int digitsForLengthOfChars   = CalculateDigits(data.Length);

            if (dfa.StateLookup.ContainsKey("E"))
            {
                currState = dfa.DeterministicStateLookup["E"]; // always start with E.
            }
            else if (dfa.StateLookup.ContainsKey("q_0"))
            {
                currState = dfa.DeterministicStateLookup["q_0"]; // else, start with q_0.
            }
            else if (dfa.StateLookup.ContainsKey("Q_0"))
            {
                currState = dfa.DeterministicStateLookup["Q_0"]; // else, start with Q_0.
            }
            else if (dfa.StateLookup.ContainsKey("q0"))
            {
                currState = dfa.DeterministicStateLookup["q0"]; // else, start with q0.
            }
            else if (dfa.StateLookup.ContainsKey("Q0"))
            {
                currState = dfa.DeterministicStateLookup["Q0"]; // else, start with Q0.
            }
            else
            {
                retVal.ErrorMessage = "Please ensure your automaton has a starting edge named, in order, one of (E,q_0,Q_0,q0,Q0). The first edge by a matching name in the aforementioned tuple is assumed to be the starting edge.";
            }

            int idx = 0;

            foreach (char c in data)
            {
                if (currState.AcceptableStrings.ContainsKey(c.ToString()))
                {
                    DeterministicState nextState = currState.AcceptableStrings[c.ToString()];
                    retVal.EvalStatements.Add(string.Format(
                                                  "[{0}]: {1}[{2}] -> {3}",
                                                  idx.ToString().PadLeft(digitsForLengthOfChars, '0'),
                                                  currState.StateName,
                                                  c,
                                                  nextState.StateName));

                    currState = nextState;
                }
                else
                {
                    retVal.ErrorMessage     = string.Format("Illegal character at index {0}", idx);
                    retVal.IllegalCharIndex = idx;
                    retVal.Validated        = false;
                    return(retVal);
                }

                idx++;
            }

            if (currState.IsAccepting)
            {
                retVal.Validated = true;
            }
            else
            {
                retVal.Validated    = false;
                retVal.ErrorMessage = string.Format(
                    "The Automaton did not end in an accepting state. The final state was {0}.",
                    currState.StateName);
                retVal.IllegalCharIndex = retVal.Input.Length - 1;
            }

            return(retVal);
        }