static internal RuleType Parse(string rule, RuleType emptyRule, List <FuzzyVariable> input, List <OutputVariableType> output)
        {
            if (rule.Length == 0)
            {
                throw new ArgumentException("Rule cannot be empty.");
            }

            //
            // Surround brakes with spaces, remove double spaces
            //
            System.Text.StringBuilder sb = new StringBuilder();
            foreach (char ch in rule)
            {
                if (ch == ')' || ch == '(')
                {
                    if (sb.Length > 0 && sb[sb.Length - 1] == ' ')
                    {
                        // Do not duplicate spaces
                    }
                    else
                    {
                        sb.Append(' ');
                    }

                    sb.Append(ch);
                    sb.Append(' ');
                }
                else
                {
                    if (ch == ' ' && sb.Length > 0 && sb[sb.Length - 1] == ' ')
                    {
                        // Do not duplicate spaces
                    }
                    else
                    {
                        sb.Append(ch);
                    }
                }
            }

            //
            // Remove spaces
            //
            string prepRule = sb.ToString().Trim();

            //
            // Build lexems dictionary
            //
            Dictionary <string, Lexem> lexemsDict = BuildLexemsList(input, output);

            //
            // At first we parse lexems
            //
            List <IExpression> expressions = ParseLexems(prepRule, lexemsDict);

            if (expressions.Count == 0)
            {
                throw new System.Exception("No valid identifiers found.");
            }

            //
            // Find condition & conclusion parts part
            //
            if (expressions[0] != lexemsDict["if"])
            {
                throw new System.Exception("'if' should be the first identifier.");
            }

            int thenIndex = -1;

            for (int i = 1; i < expressions.Count; i++)
            {
                if (expressions[i] == lexemsDict["then"])
                {
                    thenIndex = i;
                    break;
                }
            }

            if (thenIndex == -1)
            {
                throw new System.Exception("'then' identifier not found.");
            }

            int conditionLen = thenIndex - 1;

            if (conditionLen < 1)
            {
                throw new System.Exception("Condition part of the rule not found.");
            }

            int conclusionLen = expressions.Count - thenIndex - 1;

            if (conclusionLen < 1)
            {
                throw new System.Exception("Conclusion part of the rule not found.");
            }

            List <IExpression> conditionExpressions  = expressions.GetRange(1, conditionLen);
            List <IExpression> conclusionExpressions = expressions.GetRange(thenIndex + 1, conclusionLen);

            Conditions conditions = ParseConditions(conditionExpressions, input, lexemsDict);
            SingleCondition <OutputVariableType, OutputValueType> conclusion = ParseConclusion <OutputVariableType, OutputValueType>(conclusionExpressions, output, lexemsDict);

            emptyRule.Condition  = conditions;
            emptyRule.Conclusion = conclusion;
            return(emptyRule);
        }
        static private ICondition ParseConditionsRecurse(List <IExpression> expressions, Dictionary <string, Lexem> lexems)
        {
            if (expressions.Count < 1)
            {
                throw new Exception("Empty condition found.");
            }

            if (expressions[0] == lexems["("] && FindPairBracket(expressions, lexems) == expressions.Count)
            {
                //
                // Remove extra brackets
                //
                return(ParseConditionsRecurse(expressions.GetRange(1, expressions.Count - 2), lexems));
            }
            else if (expressions.Count == 1 && expressions[0] is ConditionExpression)
            {
                //
                // Return single conditions
                //
                return(((ConditionExpression)expressions[0]).Condition);
            }
            else
            {
                //
                // Parse list of one level conditions connected by or/and
                //
                List <IExpression> copyExpressions = expressions.GetRange(0, expressions.Count);
                Conditions         conds           = new Conditions();
                bool setOrAnd = false;
                while (copyExpressions.Count > 0)
                {
                    ICondition cond = null;
                    if (copyExpressions[0] == lexems["("])
                    {
                        //
                        // Find pair bracket
                        //
                        int closeBracket = FindPairBracket(copyExpressions, lexems);
                        if (closeBracket == -1)
                        {
                            throw new Exception("Parenthesis error.");
                        }

                        cond = ParseConditionsRecurse(copyExpressions.GetRange(1, closeBracket - 1), lexems);
                        copyExpressions.RemoveRange(0, closeBracket + 1);
                    }
                    else if (copyExpressions[0] is ConditionExpression)
                    {
                        cond = ((ConditionExpression)copyExpressions[0]).Condition;
                        copyExpressions.RemoveAt(0);
                    }
                    else
                    {
                        throw new ArgumentException(string.Format("Wrong expression in condition part at '{0}'"), copyExpressions[0].Text);
                    }

                    //
                    // And condition to the list
                    //
                    conds.ConditionsList.Add(cond);

                    if (copyExpressions.Count > 0)
                    {
                        if (copyExpressions[0] == lexems["and"] || copyExpressions[0] == lexems["or"])
                        {
                            if (copyExpressions.Count < 2)
                            {
                                throw new Exception(string.Format("Error at {0} in condition part.", copyExpressions[0].Text));
                            }

                            //
                            // Set and/or for conditions list
                            //
                            OperatorType newOp = (copyExpressions[0] == lexems["and"]) ? OperatorType.And : OperatorType.Or;

                            if (setOrAnd)
                            {
                                if (conds.Op != newOp)
                                {
                                    throw new Exception("At the one nesting level cannot be mixed and/or operations.");
                                }
                            }
                            else
                            {
                                conds.Op = newOp;
                                setOrAnd = true;
                            }
                            copyExpressions.RemoveAt(0);
                        }
                        else
                        {
                            throw new Exception(string.Format("{1} cannot goes after {0}", copyExpressions[0].Text, copyExpressions[1].Text));
                        }
                    }
                }

                return(conds);
            }
        }