Ejemplo n.º 1
0
        public string VoicePhrases(string sep)
        {
            List <Tuple <string, ConditionEntry.MatchType> > ret = actionfiles.ReturnValuesOfSpecificConditions("VoiceInput", new List <ConditionEntry.MatchType>()
            {
                ConditionEntry.MatchType.MatchSemicolonList, ConditionEntry.MatchType.MatchSemicolon
            });                                                                                                                                                                                                                                                   // need these to decide

            string s = "";

            foreach (var vp in ret)
            {
                BaseUtils.StringCombinations sb = new BaseUtils.StringCombinations();
                sb.ParseString(vp.Item1);
                s += String.Join(",", sb.Permutations.ToArray()) + sep;
            }

            return(s);
        }
Ejemplo n.º 2
0
        public string VoicePhrases(string sep)
        {
            var ret = actionfiles.ReturnSpecificConditions(ActionEventEDList.onVoiceInput.TriggerName, "VoiceInput", new List <ConditionEntry.MatchType>()
            {
                ConditionEntry.MatchType.MatchSemicolonList, ConditionEntry.MatchType.MatchSemicolon
            });                                                                                                                                                                                                                                             // need these to decide

            string s = "";

            foreach (var vp in ret)
            {
                BaseUtils.StringCombinations sb = new BaseUtils.StringCombinations();
                sb.ParseString(vp.Item2.MatchString);
                s += String.Join(",", sb.Permutations.ToArray()) + sep;
            }

            return(s);
        }
Ejemplo n.º 3
0
        static public bool?CheckConditions(List <Condition> fel, Variables values, out string errlist, out ErrorClass errclass, List <Condition> passed = null, Functions cf = null)
        {
            errlist  = null;
            errclass = ErrorClass.None;

            bool?outerres = null;

            foreach (Condition fe in fel)        // find all values needed
            {
                bool?innerres = null;

                foreach (ConditionEntry f in fe.fields)
                {
                    bool matched = false;

                    if (f.matchtype == ConditionEntry.MatchType.AlwaysTrue || f.matchtype == ConditionEntry.MatchType.AlwaysFalse)
                    {
                        if (f.itemname.Length == 0 || f.itemname.Equals("Condition", StringComparison.InvariantCultureIgnoreCase))     // empty (legacy) or
                        {
                            if (f.matchtype == ConditionEntry.MatchType.AlwaysTrue)
                            {
                                matched = true;         // matched, else if false, leave as false.
                            }
                        }
                        else
                        {
                            errlist += "AlwaysFalse/True does not have on the left side the word 'Condition'";
                            errclass = ErrorClass.ExprFormatError;
                            innerres = false;
                            break;
                        }
                    }
                    else
                    {
                        string leftside           = null;
                        Functions.ExpandResult er = Functions.ExpandResult.NoExpansion;

                        if (cf != null)     // if we have a string expander, try the left side
                        {
                            er = cf.ExpandString(f.itemname, out leftside);

                            if (er == Functions.ExpandResult.Failed) // stop on error
                            {
                                errlist += leftside;                 // add on errors..
                                innerres = false;                    // stop loop, false
                                break;
                            }
                        }

                        if (f.matchtype == ConditionEntry.MatchType.IsPresent)                // these use f.itemname without any expansion
                        {
                            if (leftside == null || er == Functions.ExpandResult.NoExpansion) // no expansion, must be a variable name
                            {
                                leftside = values.Qualify(f.itemname);                        // its a straight variable name, allow any special formatting
                            }
                            if (values.Exists(leftside) && values[leftside] != null)
                            {
                                matched = true;
                            }
                        }
                        else if (f.matchtype == ConditionEntry.MatchType.IsNotPresent)
                        {
                            if (leftside == null || er == Functions.ExpandResult.NoExpansion) // no expansion, must be a variable name
                            {
                                leftside = values.Qualify(f.itemname);                        // its a straight variable name, allow any special formatting
                            }
                            if (!values.Exists(leftside) || values[leftside] == null)
                            {
                                matched = true;
                            }
                        }
                        else
                        {
                            if (er == Functions.ExpandResult.NoExpansion)     // no expansion, must be a variable name
                            {
                                string qualname = values.Qualify(f.itemname);
                                leftside = values.Exists(qualname) ? values[qualname] : null;   // then lookup.. lookup may also be null if its a pre-def

                                if (leftside == null)
                                {
                                    errlist += "Variable '" + qualname + "' does not exist" + Environment.NewLine;
                                    errclass = ErrorClass.LeftSideVarUndefined;
                                    innerres = false;
                                    break;                       // stop the loop, its a false
                                }
                            }

                            string rightside;

                            if (cf != null)         // if we have a string expander, pass it thru
                            {
                                er = cf.ExpandString(f.matchstring, out rightside);

                                if (er == Functions.ExpandResult.Failed) //  if error, abort
                                {
                                    errlist += rightside;                // add on errors..
                                    innerres = false;                    // stop loop, false
                                    break;
                                }
                            }
                            else
                            {
                                rightside = f.matchstring;
                            }

                            if (f.matchtype == ConditionEntry.MatchType.DateBefore || f.matchtype == ConditionEntry.MatchType.DateAfter)
                            {
                                DateTime tmevalue, tmecontent;
                                if (!DateTime.TryParse(leftside, System.Globalization.CultureInfo.CreateSpecificCulture("en-US"), System.Globalization.DateTimeStyles.None, out tmevalue))
                                {
                                    errlist += "Date time not in correct format on left side" + Environment.NewLine;
                                    errclass = ErrorClass.LeftSideBadFormat;
                                    innerres = false;
                                    break;
                                }
                                else if (!DateTime.TryParse(rightside, System.Globalization.CultureInfo.CreateSpecificCulture("en-US"), System.Globalization.DateTimeStyles.None, out tmecontent))
                                {
                                    errlist += "Date time not in correct format on right side" + Environment.NewLine;
                                    errclass = ErrorClass.RightSideBadFormat;
                                    innerres = false;
                                    break;
                                }
                                else
                                {
                                    if (f.matchtype == ConditionEntry.MatchType.DateBefore)
                                    {
                                        matched = tmevalue.CompareTo(tmecontent) < 0;
                                    }
                                    else
                                    {
                                        matched = tmevalue.CompareTo(tmecontent) >= 0;
                                    }
                                }
                            }
                            else if (f.matchtype == ConditionEntry.MatchType.Equals)
                            {
                                matched = leftside.Equals(rightside, StringComparison.InvariantCultureIgnoreCase);
                            }
                            else if (f.matchtype == ConditionEntry.MatchType.EqualsCaseSensitive)
                            {
                                matched = leftside.Equals(rightside);
                            }

                            else if (f.matchtype == ConditionEntry.MatchType.NotEqual)
                            {
                                matched = !leftside.Equals(rightside, StringComparison.InvariantCultureIgnoreCase);
                            }
                            else if (f.matchtype == ConditionEntry.MatchType.NotEqualCaseSensitive)
                            {
                                matched = !leftside.Equals(rightside);
                            }

                            else if (f.matchtype == ConditionEntry.MatchType.Contains)
                            {
                                matched = leftside.IndexOf(rightside, StringComparison.InvariantCultureIgnoreCase) >= 0;
                            }
                            else if (f.matchtype == ConditionEntry.MatchType.ContainsCaseSensitive)
                            {
                                matched = leftside.Contains(rightside);
                            }

                            else if (f.matchtype == ConditionEntry.MatchType.DoesNotContain)
                            {
                                matched = leftside.IndexOf(rightside, StringComparison.InvariantCultureIgnoreCase) < 0;
                            }
                            else if (f.matchtype == ConditionEntry.MatchType.DoesNotContainCaseSensitive)
                            {
                                matched = !leftside.Contains(rightside);
                            }
                            else if (f.matchtype == ConditionEntry.MatchType.IsOneOf)
                            {
                                StringParser  p   = new StringParser(rightside);
                                List <string> ret = p.NextQuotedWordList();

                                if (ret == null)
                                {
                                    errlist += "IsOneOf value list is not in a optionally quoted comma separated form" + Environment.NewLine;
                                    errclass = ErrorClass.RightSideBadFormat;
                                    innerres = false;
                                    break;                       // stop the loop, its a false
                                }
                                else
                                {
                                    matched = ret.Contains(leftside, StringComparer.InvariantCultureIgnoreCase);
                                }
                            }
                            else if (f.matchtype == ConditionEntry.MatchType.MatchSemicolon)
                            {
                                string[] list = rightside.Split(';').Select(x => x.Trim()).ToArray();                // split and trim
                                matched = list.Contains(leftside.Trim(), StringComparer.InvariantCultureIgnoreCase); // compare, trimmed, case insensitive
                            }
                            else if (f.matchtype == ConditionEntry.MatchType.MatchCommaList)
                            {
                                StringCombinations sc = new StringCombinations(',');
                                sc.ParseString(rightside);                                                                      // parse, give all combinations
                                matched = sc.Permutations.Contains(leftside.Trim(), StringComparer.InvariantCultureIgnoreCase); // compare, trimmed, case insensitive
                            }
                            else if (f.matchtype == ConditionEntry.MatchType.MatchSemicolonList)
                            {
                                StringCombinations sc = new StringCombinations(';');
                                sc.ParseString(rightside);                                                                      // parse, give all combinations
                                matched = sc.Permutations.Contains(leftside.Trim(), StringComparer.InvariantCultureIgnoreCase); // compare, trimmed, case insensitive
                            }
                            else if (f.matchtype == ConditionEntry.MatchType.AnyOfAny)
                            {
                                StringParser  l  = new StringParser(leftside);
                                List <string> ll = l.NextQuotedWordList();

                                StringParser  r  = new StringParser(rightside);
                                List <string> rl = r.NextQuotedWordList();

                                if (ll == null || rl == null)
                                {
                                    errlist += "AnyOfAny value list is not in a optionally quoted comma separated form on both sides" + Environment.NewLine;
                                    errclass = ErrorClass.RightSideBadFormat;
                                    innerres = false;
                                    break;                       // stop the loop, its a false
                                }
                                else
                                {
                                    foreach (string s in ll)                                           // for all left strings
                                    {
                                        if (rl.Contains(s, StringComparer.InvariantCultureIgnoreCase)) // if right has it..
                                        {
                                            matched = true;                                            // matched and break
                                            break;
                                        }
                                    }
                                }
                            }
                            else if (f.matchtype == ConditionEntry.MatchType.IsEmpty)
                            {
                                matched = leftside.Length == 0;
                            }
                            else if (f.matchtype == ConditionEntry.MatchType.IsNotEmpty)
                            {
                                matched = leftside.Length > 0;
                            }
                            else if (f.matchtype == ConditionEntry.MatchType.IsTrue || f.matchtype == ConditionEntry.MatchType.IsFalse)
                            {
                                int inum = 0;

                                if (leftside.InvariantParse(out inum))
                                {
                                    matched = (f.matchtype == ConditionEntry.MatchType.IsTrue) ? (inum != 0) : (inum == 0);
                                }
                                else
                                {
                                    errlist += "True/False value is not an integer on left side" + Environment.NewLine;
                                    errclass = ErrorClass.LeftSideBadFormat;
                                    innerres = false;
                                    break;
                                }
                            }
                            else
                            {
                                double fnum = 0, num = 0;

                                if (!leftside.InvariantParse(out num))
                                {
                                    errlist += "Number not in correct format on left side" + Environment.NewLine;
                                    errclass = ErrorClass.LeftSideBadFormat;
                                    innerres = false;
                                    break;
                                }
                                else if (!rightside.InvariantParse(out fnum))
                                {
                                    errlist += "Number not in correct format on right side" + Environment.NewLine;
                                    errclass = ErrorClass.RightSideBadFormat;
                                    innerres = false;
                                    break;
                                }
                                else
                                {
                                    if (f.matchtype == ConditionEntry.MatchType.NumericEquals)
                                    {
                                        matched = Math.Abs(num - fnum) < 0.0000000001;  // allow for rounding
                                    }
                                    else if (f.matchtype == ConditionEntry.MatchType.NumericNotEquals)
                                    {
                                        matched = Math.Abs(num - fnum) >= 0.0000000001;
                                    }

                                    else if (f.matchtype == ConditionEntry.MatchType.NumericGreater)
                                    {
                                        matched = num > fnum;
                                    }

                                    else if (f.matchtype == ConditionEntry.MatchType.NumericGreaterEqual)
                                    {
                                        matched = num >= fnum;
                                    }

                                    else if (f.matchtype == ConditionEntry.MatchType.NumericLessThan)
                                    {
                                        matched = num < fnum;
                                    }

                                    else if (f.matchtype == ConditionEntry.MatchType.NumericLessThanEqual)
                                    {
                                        matched = num <= fnum;
                                    }
                                    else
                                    {
                                        System.Diagnostics.Debug.Assert(false);
                                    }
                                }
                            }
                        }
                    }

                    //  System.Diagnostics.Debug.WriteLine(fe.eventname + ":Compare " + f.matchtype + " '" + f.contentmatch + "' with '" + vr.value + "' res " + matched + " IC " + fe.innercondition);

                    if (fe.innercondition == ConditionEntry.LogicalCondition.And)       // Short cut, if AND, all must pass, and it did not
                    {
                        if (!matched)
                        {
                            innerres = false;
                            break;
                        }
                    }
                    else if (fe.innercondition == ConditionEntry.LogicalCondition.Nand)  // Short cut, if NAND, and not matched
                    {
                        if (!matched)
                        {
                            innerres = true;                        // positive non match - NAND produces a true
                            break;
                        }
                    }
                    else if (fe.innercondition == ConditionEntry.LogicalCondition.Or)    // Short cut, if OR, and matched
                    {
                        if (matched)
                        {
                            innerres = true;
                            break;
                        }
                    }
                    else
                    {                                               // short cut, if NOR, and matched, its false
                        if (matched)
                        {
                            innerres = false;
                            break;
                        }
                    }
                }

                if (!innerres.HasValue)                                           // All tests executed, without a short cut, we set it to a definitive state
                {
                    if (fe.innercondition == ConditionEntry.LogicalCondition.And) // none did not match, producing a false, so therefore AND is true
                    {
                        innerres = true;
                    }
                    else if (fe.innercondition == ConditionEntry.LogicalCondition.Or)    // none did match, producing a true, so therefore OR must be false
                    {
                        innerres = false;
                    }
                    else if (fe.innercondition == ConditionEntry.LogicalCondition.Nor)   // none did match, producing a false, so therefore NOR must be true
                    {
                        innerres = true;
                    }
                    else                                            // NAND none did match, producing a true, so therefore NAND must be false
                    {
                        innerres = false;
                    }
                }

                if (innerres.Value && passed != null)               // if want a list of passes, do it
                {
                    passed.Add(fe);
                }

                if (!outerres.HasValue)                                 // if first time, its just the value
                {
                    outerres = innerres.Value;
                }
                else if (fe.outercondition == ConditionEntry.LogicalCondition.Or)
                {
                    outerres |= innerres.Value;
                }
                else if (fe.outercondition == ConditionEntry.LogicalCondition.And)
                {
                    outerres &= innerres.Value;
                }
                else if (fe.outercondition == ConditionEntry.LogicalCondition.Nor)
                {
                    outerres = !(outerres | innerres.Value);
                }
                else if (fe.outercondition == ConditionEntry.LogicalCondition.Nand)
                {
                    outerres = !(outerres & innerres.Value);
                }
            }

            return(outerres);
        }
Ejemplo n.º 4
0
        // static
        // Check condition list fel, using the outercondition on each to combine the results
        // values are the set of values to use for variable lookups
        // pass back errlist, errclass
        // optionally pass back conditions which passed
        // optional use the function/macro expander on both sides
        // optionally shortcircuit on outer AND condition
        // obeys disabled

        static public bool?CheckConditions(List <Condition> fel, Variables values, out string errlist, out ErrorClass errclass,
                                           List <Condition> passed         = null,
                                           Functions functionmacroexpander = null,
                                           bool shortcircuitouter          = false,
                                           bool debugit = false)
        {
            errlist  = null;
            errclass = ErrorClass.None;

            bool?outerres = null;

            for (int oc = 0; oc < fel.Count; oc++)
            {
                Condition cond = fel[oc];
                if (cond.Disabled)                // disabled means that its ignored
                {
                    continue;
                }

                bool?innerres = null;

                foreach (ConditionEntry ce in cond.Fields)
                {
                    bool matched = false;

                    if (debugit)
                    {
                        System.Diagnostics.Debug.WriteLine($"CE `{ce.ItemName}`  {ce.MatchCondition} `{ce.MatchString}`");
                    }

                    // these require no left or right

                    if (ce.MatchCondition == ConditionEntry.MatchType.AlwaysTrue || ce.MatchCondition == ConditionEntry.MatchType.AlwaysFalse)
                    {
                        if (ce.ItemName.Length == 0 || ce.ItemName.Equals("Condition", StringComparison.InvariantCultureIgnoreCase))     // empty (legacy) or Condition
                        {
                            if (ce.MatchCondition == ConditionEntry.MatchType.AlwaysTrue)
                            {
                                matched = true;         // matched, else if false, leave as false.
                            }
                        }
                        else
                        {
                            errlist += "AlwaysFalse/True does not have on the left side the word 'Condition'" + Environment.NewLine;
                            errclass = ErrorClass.ExprFormatError;
                            innerres = false;
                            break;
                        }
                    }
                    else
                    {   // at least a left side
                        string leftside = null;
                        Functions.ExpandResult leftexpansionresult = Functions.ExpandResult.NoExpansion;

                        if (functionmacroexpander != null)     // if we have a string expander, try the left side
                        {
                            leftexpansionresult = functionmacroexpander.ExpandString(ce.ItemName, out leftside);

                            if (leftexpansionresult == Functions.ExpandResult.Failed) // stop on error
                            {
                                errlist += leftside;                                  // add on errors..
                                innerres = false;                                     // stop loop, false
                                break;
                            }
                        }

                        // variable names

                        if (ce.MatchCondition == ConditionEntry.MatchType.IsPresent)
                        {
                            if (leftside == null || leftexpansionresult == Functions.ExpandResult.NoExpansion) // no expansion, must be a variable name
                            {
                                leftside = values.Qualify(ce.ItemName);                                        // its a straight variable name, allow any special formatting
                            }
                            if (values.Exists(leftside) && values[leftside] != null)
                            {
                                matched = true;
                            }
                        }
                        else if (ce.MatchCondition == ConditionEntry.MatchType.IsNotPresent)
                        {
                            if (leftside == null || leftexpansionresult == Functions.ExpandResult.NoExpansion) // no expansion, must be a variable name
                            {
                                leftside = values.Qualify(ce.ItemName);                                        // its a straight variable name, allow any special formatting
                            }
                            if (!values.Exists(leftside) || values[leftside] == null)
                            {
                                matched = true;
                            }
                        }
                        else
                        {
                            // if no expansion, then pass thru the eval engine now or its a variable name

                            if (leftexpansionresult == Functions.ExpandResult.NoExpansion)
                            {
                                string qualname = values.Qualify(ce.ItemName);
                                leftside = values.Exists(qualname) ? values[qualname] : null;   // then lookup.. lookup may also be null if its a pre-def

                                if (leftside == null)
                                {
                                    errlist += "Variable '" + qualname + "' does not exist" + Environment.NewLine;
                                    errclass = ErrorClass.LeftSideVarUndefined;
                                    innerres = false;
                                    break;                       // stop the loop, its a false
                                }
                            }

                            //   System.Diagnostics.Debug.WriteLine($".. left side {leftside}");

                            // left side only

                            if (ce.MatchCondition == ConditionEntry.MatchType.IsEmpty)
                            {
                                matched = leftside.Length == 0;
                            }
                            else if (ce.MatchCondition == ConditionEntry.MatchType.IsNotEmpty)
                            {
                                matched = leftside.Length > 0;
                            }
                            else if (ce.MatchCondition == ConditionEntry.MatchType.IsTrue || ce.MatchCondition == ConditionEntry.MatchType.IsFalse)
                            {
                                int inum = 0;

                                if (leftside.InvariantParse(out inum))
                                {
                                    matched = (ce.MatchCondition == ConditionEntry.MatchType.IsTrue) ? (inum != 0) : (inum == 0);
                                }
                                else
                                {
                                    errlist += "True/False value is not an integer on left side" + Environment.NewLine;
                                    errclass = ErrorClass.LeftSideBadFormat;
                                    innerres = false;
                                    break;
                                }
                            }
                            else
                            {
                                // require a right side

                                string rightside = null;
                                Functions.ExpandResult rightexpansionresult = Functions.ExpandResult.NoExpansion;

                                if (functionmacroexpander != null)         // if we have a string expander, pass it thru
                                {
                                    rightexpansionresult = functionmacroexpander.ExpandString(ce.MatchString, out rightside);

                                    if (rightexpansionresult == Functions.ExpandResult.Failed) //  if error, abort
                                    {
                                        errlist += rightside;                                  // add on errors..
                                        innerres = false;                                      // stop loop, false
                                        break;
                                    }
                                }
                                else
                                {
                                    rightside = ce.MatchString;      // no eval, we just use the string
                                }
                                if (debugit)
                                {
                                    System.Diagnostics.Debug.WriteLine($"Condition `{leftside}` {ce.MatchCondition} `{rightside}`");
                                }

                                if (ce.MatchCondition == ConditionEntry.MatchType.DateBefore || ce.MatchCondition == ConditionEntry.MatchType.DateAfter)
                                {
                                    DateTime tmevalue, tmecontent;
                                    if (!DateTime.TryParse(leftside, System.Globalization.CultureInfo.CreateSpecificCulture("en-US"), System.Globalization.DateTimeStyles.None, out tmevalue))
                                    {
                                        errlist += "Date time not in correct format on left side: " + leftside + Environment.NewLine;
                                        errclass = ErrorClass.LeftSideBadFormat;
                                        innerres = false;
                                        break;
                                    }
                                    else if (!DateTime.TryParse(rightside, System.Globalization.CultureInfo.CreateSpecificCulture("en-US"), System.Globalization.DateTimeStyles.None, out tmecontent))
                                    {
                                        errlist += "Date time not in correct format on right side: " + rightside + Environment.NewLine;
                                        errclass = ErrorClass.RightSideBadFormat;
                                        innerres = false;
                                        break;
                                    }
                                    else
                                    {
                                        if (ce.MatchCondition == ConditionEntry.MatchType.DateBefore)
                                        {
                                            matched = tmevalue.CompareTo(tmecontent) < 0;
                                        }
                                        else
                                        {
                                            matched = tmevalue.CompareTo(tmecontent) >= 0;
                                        }
                                    }
                                }
                                else if (ce.MatchCondition == ConditionEntry.MatchType.Equals)
                                {
                                    matched = leftside.Equals(rightside, StringComparison.InvariantCultureIgnoreCase);
                                }
                                else if (ce.MatchCondition == ConditionEntry.MatchType.EqualsCaseSensitive)
                                {
                                    matched = leftside.Equals(rightside);
                                }

                                else if (ce.MatchCondition == ConditionEntry.MatchType.NotEqual)
                                {
                                    matched = !leftside.Equals(rightside, StringComparison.InvariantCultureIgnoreCase);
                                }
                                else if (ce.MatchCondition == ConditionEntry.MatchType.NotEqualCaseSensitive)
                                {
                                    matched = !leftside.Equals(rightside);
                                }

                                else if (ce.MatchCondition == ConditionEntry.MatchType.Contains)
                                {
                                    matched = leftside.IndexOf(rightside, StringComparison.InvariantCultureIgnoreCase) >= 0;
                                }
                                else if (ce.MatchCondition == ConditionEntry.MatchType.ContainsCaseSensitive)
                                {
                                    matched = leftside.Contains(rightside);
                                }

                                else if (ce.MatchCondition == ConditionEntry.MatchType.DoesNotContain)
                                {
                                    matched = leftside.IndexOf(rightside, StringComparison.InvariantCultureIgnoreCase) < 0;
                                }
                                else if (ce.MatchCondition == ConditionEntry.MatchType.DoesNotContainCaseSensitive)
                                {
                                    matched = !leftside.Contains(rightside);
                                }
                                else if (ce.MatchCondition == ConditionEntry.MatchType.IsOneOf)
                                {
                                    StringParser  p   = new StringParser(rightside);
                                    List <string> ret = p.NextQuotedWordList();

                                    if (ret == null)
                                    {
                                        errlist += "IsOneOf value list is not in a optionally quoted comma separated form" + Environment.NewLine;
                                        errclass = ErrorClass.RightSideBadFormat;
                                        innerres = false;
                                        break;                       // stop the loop, its a false
                                    }
                                    else
                                    {
                                        matched = ret.Contains(leftside, StringComparer.InvariantCultureIgnoreCase);
                                    }
                                }
                                else if (ce.MatchCondition == ConditionEntry.MatchType.MatchSemicolon)
                                {
                                    string[] list = rightside.Split(';').Select(x => x.Trim()).ToArray();                // split and trim
                                    matched = list.Contains(leftside.Trim(), StringComparer.InvariantCultureIgnoreCase); // compare, trimmed, case insensitive
                                }
                                else if (ce.MatchCondition == ConditionEntry.MatchType.MatchCommaList)
                                {
                                    StringCombinations sc = new StringCombinations(',');
                                    sc.ParseString(rightside);                                                                      // parse, give all combinations
                                    matched = sc.Permutations.Contains(leftside.Trim(), StringComparer.InvariantCultureIgnoreCase); // compare, trimmed, case insensitive
                                }
                                else if (ce.MatchCondition == ConditionEntry.MatchType.MatchSemicolonList)
                                {
                                    StringCombinations sc = new StringCombinations(';');
                                    sc.ParseString(rightside);                                                                      // parse, give all combinations
                                    matched = sc.Permutations.Contains(leftside.Trim(), StringComparer.InvariantCultureIgnoreCase); // compare, trimmed, case insensitive
                                }
                                else if (ce.MatchCondition == ConditionEntry.MatchType.AnyOfAny)
                                {
                                    StringParser  l  = new StringParser(leftside);
                                    List <string> ll = l.NextQuotedWordList();

                                    StringParser  r  = new StringParser(rightside);
                                    List <string> rl = r.NextQuotedWordList();

                                    if (ll == null || rl == null)
                                    {
                                        errlist += "AnyOfAny value list is not in a optionally quoted comma separated form on both sides" + Environment.NewLine;
                                        errclass = ErrorClass.RightSideBadFormat;
                                        innerres = false;
                                        break;                       // stop the loop, its a false
                                    }
                                    else
                                    {
                                        foreach (string s in ll)                                           // for all left strings
                                        {
                                            if (rl.Contains(s, StringComparer.InvariantCultureIgnoreCase)) // if right has it..
                                            {
                                                matched = true;                                            // matched and break
                                                break;
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    double fnum = 0, num = 0;

                                    if (!leftside.InvariantParse(out num))
                                    {
                                        errlist += "Number not in correct format on left side: " + leftside + Environment.NewLine;
                                        errclass = ErrorClass.LeftSideBadFormat;
                                        innerres = false;
                                        break;
                                    }
                                    else if (!rightside.InvariantParse(out fnum))
                                    {
                                        errlist += "Number not in correct format on right side: " + rightside + Environment.NewLine;
                                        errclass = ErrorClass.RightSideBadFormat;
                                        innerres = false;
                                        break;
                                    }
                                    else
                                    {
                                        if (ce.MatchCondition == ConditionEntry.MatchType.NumericEquals)
                                        {
                                            matched = num.ApproxEquals(fnum);
                                        }

                                        else if (ce.MatchCondition == ConditionEntry.MatchType.NumericNotEquals)
                                        {
                                            matched = !num.ApproxEquals(fnum);
                                        }

                                        else if (ce.MatchCondition == ConditionEntry.MatchType.NumericGreater)
                                        {
                                            matched = num > fnum;
                                        }

                                        else if (ce.MatchCondition == ConditionEntry.MatchType.NumericGreaterEqual)
                                        {
                                            matched = num >= fnum;
                                        }

                                        else if (ce.MatchCondition == ConditionEntry.MatchType.NumericLessThan)
                                        {
                                            matched = num < fnum;
                                        }

                                        else if (ce.MatchCondition == ConditionEntry.MatchType.NumericLessThanEqual)
                                        {
                                            matched = num <= fnum;
                                        }
                                        else
                                        {
                                            System.Diagnostics.Debug.Assert(false);
                                        }
                                    }
                                }
                            }
                        }
                    }

                    //  System.Diagnostics.Debug.WriteLine(fe.eventname + ":Compare " + f.matchtype + " '" + f.contentmatch + "' with '" + vr.value + "' res " + matched + " IC " + fe.innercondition);

                    if (cond.InnerCondition == Condition.LogicalCondition.And)       // Short cut, if AND, all must pass, and it did not
                    {
                        if (!matched)
                        {
                            innerres = false;
                            break;
                        }
                    }
                    else if (cond.InnerCondition == Condition.LogicalCondition.Nand)  // Short cut, if NAND, and not matched
                    {
                        if (!matched)
                        {
                            innerres = true;                        // positive non match - NAND produces a true
                            break;
                        }
                    }
                    else if (cond.InnerCondition == Condition.LogicalCondition.Or)    // Short cut, if OR, and matched
                    {
                        if (matched)
                        {
                            innerres = true;
                            break;
                        }
                    }
                    else
                    {                                               // short cut, if NOR, and matched, its false
                        if (matched)
                        {
                            innerres = false;
                            break;
                        }
                    }
                } // end of inner condition list look

                //   System.Diagnostics.Debug.WriteLine($"Condition list {innerres} {errlist}");

                if (!innerres.HasValue)                                        // if does not have a value
                {
                    if (cond.InnerCondition == Condition.LogicalCondition.And) // none did not matched producing a false, so therefore AND is true
                    {
                        innerres = true;
                    }
                    else if (cond.InnerCondition == Condition.LogicalCondition.Or)    // none did matched producing a true, so therefore OR must be false
                    {
                        innerres = false;
                    }
                    else if (cond.InnerCondition == Condition.LogicalCondition.Nor)   // none did matched producing a false, so therefore NOR must be true
                    {
                        innerres = true;
                    }
                    else                                            // NAND none did matched producing a true, so therefore NAND must be false
                    {
                        innerres = false;
                    }
                }
                else if (innerres == true)
                {
                    passed?.Add(cond);
                }

                if (!outerres.HasValue)                             // if first time, its just the value
                {
                    outerres = innerres.Value;

                    if (shortcircuitouter && oc < fel.Count - 1)       // check short circuits on NEXT ONE! if we have a next one..
                    {
                        // if NEXT outer condition is an OR, and we are true
                        // if NEXT outer condition is an AND, and we are false

                        if ((fel[oc + 1].OuterCondition == Condition.LogicalCondition.Or && outerres == true) ||
                            (fel[oc + 1].OuterCondition == Condition.LogicalCondition.And && outerres == false))
                        {
                            // System.Diagnostics.Debug.WriteLine("Short circuit on {0} cur {1}", fel[oc + 1].OuterCondition, outerres);
                            break;
                        }
                    }
                }
                else if (cond.OuterCondition == Condition.LogicalCondition.Or)
                {
                    outerres |= innerres.Value;

                    if (shortcircuitouter && outerres.Value == true)      // no point continuing, first one true wins
                    {
                        //System.Diagnostics.Debug.WriteLine("Short circuit second on {0} cur {1}", fe.OuterCondition, outerres);
                        break;
                    }
                }
                else if (cond.OuterCondition == Condition.LogicalCondition.And)
                {
                    outerres &= innerres.Value;

                    if (shortcircuitouter && outerres.Value == false)      // no point continuing, first one false wins
                    {
                        //System.Diagnostics.Debug.WriteLine("Short circuit second on {0} cur {1}", fe.OuterCondition, outerres);
                        break;
                    }
                }
                else if (cond.OuterCondition == Condition.LogicalCondition.Nor)
                {
                    outerres = !(outerres | innerres.Value);
                }
                else if (cond.OuterCondition == Condition.LogicalCondition.Nand)
                {
                    outerres = !(outerres & innerres.Value);
                }
                else
                {
                    System.Diagnostics.Debug.Assert(false, "Bad outer condition");
                }
            }

            return(outerres);
        }
        // Check condition list fel, using the outercondition on each to combine the results.
        // Use the eval engine to assemble arguments. Keep arguments as original types (long,double,strings)
        // values are the set of values to use for variable lookups
        // pass back errlist, errclass
        // optionally pass back test executed in order
        // shortcircuit on outer AND condition
        // obeys disabled
        static public bool?CheckConditionsEval(List <Condition> fel, Variables values,
                                               List <ConditionEntry> tests = null, List <string> testerrors = null,
                                               bool debugit = false)
        {
            Eval evl = new Eval(true, true, true, true, true);            // check end, allow fp, allow strings, allow members, allow arrays

            evl.ReturnFunctionValue = BaseFunctionsForEval.BaseFunctions; // allow functions

            evl.ReturnSymbolValue += (str) =>                             // on symbol lookup
            {
                string qualname = values.Qualify(str);

                if (values.Exists(qualname))        //  if we have a variable
                {
                    string text = values[qualname];
                    if (double.TryParse(text, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out double d))
                    {
                        if (long.TryParse(text, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out long v))    // if its a number, return number
                        {
                            return(v);
                        }
                        else
                        {
                            return(d);
                        }
                    }
                    else
                    {
                        return(text);    // else its a string
                    }
                }
                else
                {
                    return(new StringParser.ConvertError("Unknown symbol " + qualname));
                }
            };

            bool?outerres = null;

            for (int oc = 0; oc < fel.Count; oc++)
            {
                Condition cond = fel[oc];
                if (cond.Disabled)                // disabled means that its ignored
                {
                    continue;
                }

                bool?innerres = null;

                foreach (ConditionEntry ce in cond.Fields)
                {
                    bool matched = false;

                    if (debugit)
                    {
                        System.Diagnostics.Debug.WriteLine($"CE `{ce.ItemName}`  {ce.MatchCondition} `{ce.MatchString}`");
                    }

                    tests?.Add(ce);
                    testerrors?.Add(null);

                    // these require no left or right

                    if (ce.MatchCondition == ConditionEntry.MatchType.AlwaysTrue || ce.MatchCondition == ConditionEntry.MatchType.AlwaysFalse)
                    {
                        if (ce.ItemName.Length == 0 || ce.ItemName.Equals("Condition", StringComparison.InvariantCultureIgnoreCase))     // empty (legacy) or Condition
                        {
                            if (ce.MatchCondition == ConditionEntry.MatchType.AlwaysTrue)
                            {
                                matched = true;         // matched, else if false, leave as false.
                            }
                        }
                        else
                        {
                            testerrors[testerrors.Count - 1] = "AlwaysFalse/True does not have on the left side the word 'Condition'";
                            innerres = false;
                            break;
                        }
                    }
                    else
                    {
                        // variable names

                        if (ce.MatchCondition == ConditionEntry.MatchType.IsPresent)
                        {
                            string name = values.Qualify(ce.ItemName);                 // its a straight variable name, allow any special formatting

                            if (values.Exists(name) && values[name] != null)
                            {
                                matched = true;
                            }
                        }
                        else if (ce.MatchCondition == ConditionEntry.MatchType.IsNotPresent)
                        {
                            string name = values.Qualify(ce.ItemName);                 // its a straight variable name, allow any special formatting

                            if (!values.Exists(name) || values[name] == null)
                            {
                                matched = true;
                            }
                        }
                        else
                        {
                            Object leftside;

                            if (values.Contains(ce.ItemName))
                            {
                                string text = values[ce.ItemName];
                                if (double.TryParse(text, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out double d))    // if a double..
                                {
                                    if (long.TryParse(text, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out long v))    // if its a number, return number
                                    {
                                        leftside = v;
                                    }
                                    else
                                    {
                                        leftside = d;
                                    }
                                }
                                else
                                {
                                    leftside = text;    // else its a string
                                }
                            }
                            else
                            {
                                leftside = evl.EvaluateQuickCheck(ce.ItemName);            // evaluate left side

                                if (evl.InError)
                                {
                                    if (debugit)
                                    {
                                        System.Diagnostics.Debug.WriteLine($" .. Left side in error ${((StringParser.ConvertError)leftside).ErrorValue}");
                                    }

                                    testerrors[testerrors.Count - 1] = "Left side did not evaluate: " + ce.ItemName;
                                    leftside = null;        // indicate condition has failed
                                }
                            }

                            string lstring      = leftside as string;   // used below
                            var    clf          = ConditionEntry.Classify(ce.MatchCondition);
                            bool   stringordate = clf == ConditionEntry.Classification.String || clf == ConditionEntry.Classification.Date;

                            if (leftside != null)   // if we have a leftside, check it for stringness
                            {
                                if (stringordate)
                                {
                                    if (lstring == null)
                                    {
                                        if (debugit)
                                        {
                                            System.Diagnostics.Debug.WriteLine(" .. Left side not string");
                                        }
                                        testerrors[testerrors.Count - 1] = "Left side is not a string: " + ce.ItemName;

                                        leftside = null;        // indicate condition has failed
                                    }
                                }
                                else if (!(leftside is double || leftside is long))     // must be long or double
                                {
                                    if (debugit)
                                    {
                                        System.Diagnostics.Debug.WriteLine(" .. Left side not number");
                                    }
                                    testerrors[testerrors.Count - 1] = "Left side is not a number: " + ce.ItemName;

                                    leftside = null;        // indicate condition has failed
                                }
                            }

                            if (leftside != null)       // we have a good left side
                            {
                                //   System.Diagnostics.Debug.WriteLine($".. left side {leftside}");

                                if (ce.MatchCondition == ConditionEntry.MatchType.IsEmpty)
                                {
                                    matched = lstring.Length == 0;
                                }
                                else if (ce.MatchCondition == ConditionEntry.MatchType.IsNotEmpty)
                                {
                                    matched = lstring.Length > 0;
                                }
                                else if (ce.MatchCondition == ConditionEntry.MatchType.IsTrue || ce.MatchCondition == ConditionEntry.MatchType.IsFalse)
                                {
                                    if (leftside is long)       // we already checked about that leftside is double or long
                                    {
                                        matched = (ce.MatchCondition == ConditionEntry.MatchType.IsTrue) ? ((long)leftside != 0) : ((long)leftside == 0);
                                    }
                                    else
                                    {
                                        matched = (ce.MatchCondition == ConditionEntry.MatchType.IsTrue) ? ((double)leftside != 0) : ((double)leftside == 0);
                                    }
                                }
                                else
                                {
                                    // require a right side

                                    Object rightside = evl.EvaluateQuickCheck(ce.MatchString);

                                    if (evl.InError)
                                    {
                                        if (stringordate)            // if in error, and we are doing string date comparisions, allow bare on right
                                        {
                                            rightside = ce.MatchString;
                                        }
                                        else
                                        {
                                            testerrors[testerrors.Count - 1] = "Right side did not evaluate: " + ce.MatchString;

                                            rightside = null;   // indicate bad right side
                                        }
                                    }

                                    string rstring = rightside as string;

                                    if (rightside != null)      // if good right side
                                    {
                                        if (stringordate)
                                        {
                                            if (rstring == null)      // must have a string
                                            {
                                                testerrors[testerrors.Count - 1] = "Right side is not a string: " + ce.ItemName;

                                                innerres  = false;
                                                rightside = null;
                                            }
                                        }
                                        else if (!(rightside is double || rightside is long))
                                        {
                                            testerrors[testerrors.Count - 1] = "Right side is not a number: " + ce.ItemName;

                                            innerres  = false;
                                            rightside = null;
                                        }
                                    }

                                    if (debugit)
                                    {
                                        System.Diagnostics.Debug.WriteLine($" .. `{leftside}` {ce.MatchCondition} `{rightside}`");
                                    }

                                    if (rightside != null)
                                    {
                                        if (ce.MatchCondition == ConditionEntry.MatchType.DateBefore || ce.MatchCondition == ConditionEntry.MatchType.DateAfter)
                                        {
                                            DateTime tmevalue, tmecontent;
                                            if (!DateTime.TryParse(lstring, System.Globalization.CultureInfo.CreateSpecificCulture("en-US"), System.Globalization.DateTimeStyles.None, out tmevalue))
                                            {
                                                testerrors[testerrors.Count - 1] = "Date time not in correct format on left side: " + leftside;

                                                innerres = false;
                                                break;
                                            }
                                            else if (!DateTime.TryParse(rstring, System.Globalization.CultureInfo.CreateSpecificCulture("en-US"), System.Globalization.DateTimeStyles.None, out tmecontent))
                                            {
                                                testerrors[testerrors.Count - 1] = "Date time not in correct format on right side: " + rightside;

                                                innerres = false;
                                                break;
                                            }
                                            else
                                            {
                                                if (ce.MatchCondition == ConditionEntry.MatchType.DateBefore)
                                                {
                                                    matched = tmevalue.CompareTo(tmecontent) < 0;
                                                }
                                                else
                                                {
                                                    matched = tmevalue.CompareTo(tmecontent) >= 0;
                                                }
                                            }
                                        }
                                        else if (ce.MatchCondition == ConditionEntry.MatchType.Equals)
                                        {
                                            matched = lstring.Equals(rstring, StringComparison.InvariantCultureIgnoreCase);
                                        }
                                        else if (ce.MatchCondition == ConditionEntry.MatchType.EqualsCaseSensitive)
                                        {
                                            matched = lstring.Equals(rstring);
                                        }

                                        else if (ce.MatchCondition == ConditionEntry.MatchType.NotEqual)
                                        {
                                            matched = !lstring.Equals(rstring, StringComparison.InvariantCultureIgnoreCase);
                                        }
                                        else if (ce.MatchCondition == ConditionEntry.MatchType.NotEqualCaseSensitive)
                                        {
                                            matched = !lstring.Equals(rstring);
                                        }

                                        else if (ce.MatchCondition == ConditionEntry.MatchType.Contains)
                                        {
                                            matched = lstring.IndexOf(rstring, StringComparison.InvariantCultureIgnoreCase) >= 0;
                                        }
                                        else if (ce.MatchCondition == ConditionEntry.MatchType.ContainsCaseSensitive)
                                        {
                                            matched = lstring.Contains(rstring);
                                        }

                                        else if (ce.MatchCondition == ConditionEntry.MatchType.DoesNotContain)
                                        {
                                            matched = lstring.IndexOf(rstring, StringComparison.InvariantCultureIgnoreCase) < 0;
                                        }
                                        else if (ce.MatchCondition == ConditionEntry.MatchType.DoesNotContainCaseSensitive)
                                        {
                                            matched = !lstring.Contains(rstring);
                                        }
                                        else if (ce.MatchCondition == ConditionEntry.MatchType.IsOneOf)
                                        {
                                            StringParser  p   = new StringParser(rstring);
                                            List <string> ret = p.NextQuotedWordList();

                                            if (ret == null)
                                            {
                                                testerrors[testerrors.Count - 1] = "IsOneOf value list is not in a optionally quoted comma separated form";

                                                innerres = false;
                                                break;                       // stop the loop, its a false
                                            }
                                            else
                                            {
                                                matched = ret.Contains(lstring, StringComparer.InvariantCultureIgnoreCase);
                                            }
                                        }
                                        else if (ce.MatchCondition == ConditionEntry.MatchType.MatchSemicolon)
                                        {
                                            string[] list = rstring.Split(';').Select(x => x.Trim()).ToArray();                 // split and trim
                                            matched = list.Contains(lstring.Trim(), StringComparer.InvariantCultureIgnoreCase); // compare, trimmed, case insensitive
                                        }
                                        else if (ce.MatchCondition == ConditionEntry.MatchType.MatchCommaList)
                                        {
                                            StringCombinations sc = new StringCombinations(',');
                                            sc.ParseString(rstring);                                                                       // parse, give all combinations
                                            matched = sc.Permutations.Contains(lstring.Trim(), StringComparer.InvariantCultureIgnoreCase); // compare, trimmed, case insensitive
                                        }
                                        else if (ce.MatchCondition == ConditionEntry.MatchType.MatchSemicolonList)
                                        {
                                            StringCombinations sc = new StringCombinations(';');
                                            sc.ParseString(rstring);                                                                       // parse, give all combinations
                                            matched = sc.Permutations.Contains(lstring.Trim(), StringComparer.InvariantCultureIgnoreCase); // compare, trimmed, case insensitive
                                        }
                                        else if (ce.MatchCondition == ConditionEntry.MatchType.AnyOfAny)
                                        {
                                            StringParser  l  = new StringParser(lstring);
                                            List <string> ll = l.NextQuotedWordList();

                                            StringParser  r  = new StringParser(rstring);
                                            List <string> rl = r.NextQuotedWordList();

                                            if (ll == null || rl == null)
                                            {
                                                testerrors[testerrors.Count - 1] = "AnyOfAny value list is not in a optionally quoted comma separated form on both sides";

                                                innerres = false;
                                                break;                       // stop the loop, its a false
                                            }
                                            else
                                            {
                                                foreach (string s in ll)                                           // for all left strings
                                                {
                                                    if (rl.Contains(s, StringComparer.InvariantCultureIgnoreCase)) // if right has it..
                                                    {
                                                        matched = true;                                            // matched and break
                                                        break;
                                                    }
                                                }
                                            }
                                        }
                                        else
                                        {
                                            if (leftside is double || rightside is double)
                                            {
                                                double lnum = leftside is long?(double)(long)leftside : (double)leftside;
                                                double rnum = rightside is long?(double)(long)rightside : (double)rightside;

                                                if (ce.MatchCondition == ConditionEntry.MatchType.NumericEquals)
                                                {
                                                    matched = lnum.ApproxEquals(rnum);
                                                }

                                                else if (ce.MatchCondition == ConditionEntry.MatchType.NumericNotEquals)
                                                {
                                                    matched = !lnum.ApproxEquals(rnum);
                                                }

                                                else if (ce.MatchCondition == ConditionEntry.MatchType.NumericGreater)
                                                {
                                                    matched = lnum > rnum;
                                                }

                                                else if (ce.MatchCondition == ConditionEntry.MatchType.NumericGreaterEqual)
                                                {
                                                    matched = lnum >= rnum;
                                                }

                                                else if (ce.MatchCondition == ConditionEntry.MatchType.NumericLessThan)
                                                {
                                                    matched = lnum < rnum;
                                                }

                                                else if (ce.MatchCondition == ConditionEntry.MatchType.NumericLessThanEqual)
                                                {
                                                    matched = lnum <= rnum;
                                                }
                                            }
                                            else
                                            {
                                                long lnum = (long)leftside;
                                                long rnum = (long)rightside;

                                                if (ce.MatchCondition == ConditionEntry.MatchType.NumericEquals)
                                                {
                                                    matched = lnum == rnum;
                                                }

                                                else if (ce.MatchCondition == ConditionEntry.MatchType.NumericNotEquals)
                                                {
                                                    matched = lnum != rnum;
                                                }

                                                else if (ce.MatchCondition == ConditionEntry.MatchType.NumericGreater)
                                                {
                                                    matched = lnum > rnum;
                                                }

                                                else if (ce.MatchCondition == ConditionEntry.MatchType.NumericGreaterEqual)
                                                {
                                                    matched = lnum >= rnum;
                                                }

                                                else if (ce.MatchCondition == ConditionEntry.MatchType.NumericLessThan)
                                                {
                                                    matched = lnum < rnum;
                                                }

                                                else if (ce.MatchCondition == ConditionEntry.MatchType.NumericLessThanEqual)
                                                {
                                                    matched = lnum <= rnum;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    if (debugit)
                    {
                        System.Diagnostics.Debug.WriteLine($" .. match result {matched}");
                    }

                    //  System.Diagnostics.Debug.WriteLine(fe.eventname + ":Compare " + f.matchtype + " '" + f.contentmatch + "' with '" + vr.value + "' res " + matched + " IC " + fe.innercondition);

                    if (cond.InnerCondition == Condition.LogicalCondition.And)       // Short cut, if AND, all must pass, and it did not
                    {
                        if (!matched)
                        {
                            innerres = false;
                            break;
                        }
                    }
                    else if (cond.InnerCondition == Condition.LogicalCondition.Nand)  // Short cut, if NAND, and not matched
                    {
                        if (!matched)
                        {
                            innerres = true;                        // positive non match - NAND produces a true
                            break;
                        }
                    }
                    else if (cond.InnerCondition == Condition.LogicalCondition.Or)    // Short cut, if OR, and matched
                    {
                        if (matched)
                        {
                            innerres = true;
                            break;
                        }
                    }
                    else
                    {                                               // short cut, if NOR, and matched, its false
                        if (matched)
                        {
                            innerres = false;
                            break;
                        }
                    }
                } // end of inner condition list look

                //   System.Diagnostics.Debug.WriteLine($"Condition list {innerres} {errlist}");

                if (!innerres.HasValue)                                        // if does not have a value
                {
                    if (cond.InnerCondition == Condition.LogicalCondition.And) // none did not matched producing a false, so therefore AND is true
                    {
                        innerres = true;
                    }
                    else if (cond.InnerCondition == Condition.LogicalCondition.Or)    // none did matched producing a true, so therefore OR must be false
                    {
                        innerres = false;
                    }
                    else if (cond.InnerCondition == Condition.LogicalCondition.Nor)   // none did matched producing a false, so therefore NOR must be true
                    {
                        innerres = true;
                    }
                    else                                            // NAND none did matched producing a true, so therefore NAND must be false
                    {
                        innerres = false;
                    }
                }

                if (!outerres.HasValue)                             // if first time, its just the value
                {
                    outerres = innerres.Value;

                    if (oc < fel.Count - 1)       // check short circuits on NEXT ONE! if we have a next one..
                    {
                        // if NEXT outer condition is an OR, and we are true
                        // if NEXT outer condition is an AND, and we are false

                        if ((fel[oc + 1].OuterCondition == Condition.LogicalCondition.Or && outerres == true) ||
                            (fel[oc + 1].OuterCondition == Condition.LogicalCondition.And && outerres == false))
                        {
                            // System.Diagnostics.Debug.WriteLine("Short circuit on {0} cur {1}", fel[oc + 1].OuterCondition, outerres);
                            break;
                        }
                    }
                }
                else if (cond.OuterCondition == Condition.LogicalCondition.Or)
                {
                    outerres |= innerres.Value;

                    if (outerres.Value == true)      // no point continuing, first one true wins
                    {
                        //System.Diagnostics.Debug.WriteLine("Short circuit second on {0} cur {1}", fe.OuterCondition, outerres);
                        break;
                    }
                }
                else if (cond.OuterCondition == Condition.LogicalCondition.And)
                {
                    outerres &= innerres.Value;

                    if (outerres.Value == false)      // no point continuing, first one false wins
                    {
                        //System.Diagnostics.Debug.WriteLine("Short circuit second on {0} cur {1}", fe.OuterCondition, outerres);
                        break;
                    }
                }
                else if (cond.OuterCondition == Condition.LogicalCondition.Nor)
                {
                    outerres = !(outerres | innerres.Value);
                }
                else if (cond.OuterCondition == Condition.LogicalCondition.Nand)
                {
                    outerres = !(outerres & innerres.Value);
                }
                else
                {
                    System.Diagnostics.Debug.Assert(false, "Bad outer condition");
                }
            }

            return(outerres);
        }