/// <summary>
        /// Initializes a new instance of the QuestionBuilder class according to given values.
        /// </summary>
        /// <param name="oper">The given value of operator.</param>
        /// <param name="value">The given value.</param>
        public QuestionBuilder(QuestionOperator oper, int value)
        {
            if (value < 0)
            {
                throw new ArgumentException("The given integer value shouldn't be less than 0");
            }

            // If the operator is belong to, it can be consider as equal since the value set only have one value.
            if (oper == QuestionOperator.Belong)
            {
                oper = QuestionOperator.Equal;
            }

            // If the operator is greater or equal, it can be consider as less.
            // So, the returned question will be an equalable question with opposite answer.
            // The opposite answer won't impact the decision tree and related logic.
            if (oper == QuestionOperator.GreaterEqual)
            {
                oper = QuestionOperator.Less;
            }

            // If the operator is greater, it can be consider as less or equal.
            // So, the returned question will be an equalable question with opposite answer.
            // The opposite answer won't impact the decision tree and related logic.
            if (oper == QuestionOperator.Greater)
            {
                oper = QuestionOperator.LessEqual;
            }

            Question question = new Question
            {
                Oper = oper,
                ValueSetName = value.ToString(CultureInfo.InvariantCulture),
            };

            switch (oper)
            {
                case QuestionOperator.Equal:
                    question.ValueSet = new List<string> { question.ValueSetName }.AsReadOnly();
                    break;
                case QuestionOperator.Less:
                    question.ValueSet = BuildLessQuestionValueSetStartsWithDigit(value).AsReadOnly();
                    break;
                case QuestionOperator.LessEqual:
                    question.ValueSet = BuildLessQuestionValueSetStartsWithDigit(value + 1).AsReadOnly();
                    break;
                default:
                    throw new NotSupportedException(Helper.NeutralFormat("Unsupported question operator \"{0}\"", oper.ToString()));
            }

            _questionList.Add(question);
        }
        /// <summary>
        /// Build question for not applicable feature value.
        /// </summary>
        /// <param name="featureName">The corresponding feature name.</param>
        /// <param name="leftSeparator">The left separator of this feature.</param>
        /// <param name="rightSeparator">The right separator of this feature.</param>
        /// <returns>The question for not applicable feature value.</returns>
        public static string BuildNotApplicableFeatureQuestion(string featureName, string leftSeparator, string rightSeparator)
        {
            Question question = new Question
            {
                FeatureName = featureName,
                LeftSeparator = leftSeparator,
                RightSeparator = rightSeparator,
                Oper = QuestionOperator.Equal,
                ValueSetName = Label.NotApplicableFeatureValue,
                ValueSet = new List<string> { Label.NotApplicableFeatureValue }.AsReadOnly(),
            };

            return question.Expression;
        }
        /// <summary>
        /// Initializes a new instance of the QuestionBuilder class according to values, range and value type.
        /// </summary>
        /// <param name="values">The valid values.</param>
        /// <param name="minValue">The minimum feature value for generating questions.</param>
        /// <param name="maxValue">The maximum feature value for generating questions.</param>
        /// <param name="valueType">The value type.</param>
        public QuestionBuilder(IEnumerable<int> values, int minValue, int maxValue, LingFeatureValueType valueType)
        {
            List<int> sortedValues = new List<int>(values);
            sortedValues.Sort();

            // Creates the equal questions for enumerable or null type feature.
            if (valueType == LingFeatureValueType.Null || valueType == LingFeatureValueType.Enumerable)
            {
                for (int i = 0; i < sortedValues.Count; i++)
                {
                    if ((minValue > 0 && sortedValues[i] < minValue) || (maxValue > 0 && sortedValues[i] > maxValue))
                    {
                        continue;
                    }

                    string value = sortedValues[i].ToString(CultureInfo.InvariantCulture);
                    List<string> valueSet = new List<string> { value };
                    Question question = new Question
                    {
                        Oper = QuestionOperator.Equal,
                        ValueSetName = value,
                        ValueSet = valueSet.AsReadOnly(),
                    };

                    _questionList.Add(question);
                }
            }

            // Creates the less equal questions for integer or null type feature.
            if (valueType == LingFeatureValueType.Null || valueType == LingFeatureValueType.Integer)
            {
                for (int i = 0; i < sortedValues.Count; i++)
                {
                    if ((minValue > 0 && sortedValues[i] < minValue) || (maxValue > 0 && sortedValues[i] > maxValue))
                    {
                        continue;
                    }

                    string value = sortedValues[i].ToString(CultureInfo.InvariantCulture);
                    List<string> valueSet = new List<string>();
                    for (int j = 0; j <= sortedValues[i]; ++j)
                    {
                        valueSet.Add(j.ToString(CultureInfo.InvariantCulture));
                    }

                    Question question = new Question
                    {
                        Oper = QuestionOperator.LessEqual,
                        ValueSetName = value,
                        ValueSet = valueSet.AsReadOnly(),
                    };

                    _questionList.Add(question);
                }
            }
        }
        /// <summary>
        /// Initializes a new instance of the QuestionBuilder class according to given values.
        /// </summary>
        /// <param name="oper">
        /// The given value of operator.
        /// </param>
        /// <param name="name">
        /// The given name.
        /// </param>
        /// <param name="valueSet">
        /// The given value set.
        /// </param>
        public QuestionBuilder(QuestionOperator oper, string name, List<string> valueSet)
        {
            Question question = new Question
            {
                Oper = oper,
                ValueSetName = name,
                ValueSet = valueSet.AsReadOnly(),
            };

            _questionList.Add(question);
        }
        /// <summary>
        /// Initializes a new instance of the QuestionBuilder class according to integer values.
        /// </summary>
        /// <param name="values">The valid values.</param>
        public QuestionBuilder(IEnumerable<int> values)
        {
            List<int> sortedValues = new List<int>(values);
            sortedValues.Sort();

            // Creates the equal question first.
            for (int i = 0; i < sortedValues.Count; i++)
            {
                string value = sortedValues[i].ToString(CultureInfo.InvariantCulture);
                List<string> valueSet = new List<string> { value };
                Question question = new Question
                {
                    Oper = QuestionOperator.Equal,
                    ValueSetName = value,
                    ValueSet = valueSet.AsReadOnly(),
                };

                _questionList.Add(question);
            }

            // Then the less equal question.
            for (int i = 1; i < sortedValues.Count; i++)
            {
                Question question = new Question
                {
                    Oper = QuestionOperator.LessEqual,
                    ValueSetName = sortedValues[i].ToString(CultureInfo.InvariantCulture),
                    ValueSet = BuildLessQuestionValueSetStartsWithDigit(sortedValues[i] + 1).AsReadOnly(),
                };

                _questionList.Add(question);
            }
        }
        /// <summary>
        /// Initializes a new instance of the QuestionBuilder class according to enum.
        /// </summary>
        /// <param name="enumType">A enum type used to generate questions.</param>
        public QuestionBuilder(Type enumType)
        {
            string[] names = Enum.GetNames(enumType);
            foreach (string name in names)
            {
                Question question = new Question
                {
                    Oper = QuestionOperator.Equal,
                    ValueSetName = name,
                };

                int value = (int)Enum.Parse(enumType, name);
                List<string> valueSet = new List<string> { value.ToString(CultureInfo.InvariantCulture) };

                question.ValueSet = valueSet.AsReadOnly();
                _questionList.Add(question);
            }
        }
        /// <summary>
        /// Initializes a new instance of the QuestionBuilder class according to a name and its value.
        /// </summary>
        /// <param name="namedValues">A dictionary to hold the name and its value.</param>
        public QuestionBuilder(Dictionary<string, object> namedValues)
        {
            foreach (KeyValuePair<string, object> kvp in namedValues)
            {
                List<string> valueSet = new List<string> { kvp.Value.ToString() };
                Question question = new Question
                {
                    Oper = QuestionOperator.Equal,
                    ValueSetName = kvp.Key,
                    ValueSet = valueSet.AsReadOnly(),
                };

                _questionList.Add(question);
            }
        }
        /// <summary>
        /// Initializes a new instance of the QuestionBuilder class according to phonetic question file.
        /// </summary>
        /// <param name="phoneticQuestionFile">The phonetic question file from Hts.</param>
        /// <param name="phonemes">The valid phoneme set, used to validate the phonetic questions.</param>
        public QuestionBuilder(string phoneticQuestionFile, IEnumerable<string> phonemes)
        {
            // Load the all phonetic question firstly.
            PhoneQuestion[] phoneticQuestions = LoadPhoneticQuestions(phoneticQuestionFile, phonemes);

            // For each phonetic question, assign its fields to a Question item.
            foreach (PhoneQuestion phoneQuestion in phoneticQuestions)
            {
                Question question = new Question
                {
                    Oper = QuestionOperator.Belong,
                    ValueSetName = phoneQuestion.Name,
                    ValueSet = phoneQuestion.Phones.AsReadOnly(),
                };

                _questionList.Add(question);
            }
        }
        /// <summary>
        /// Loads the forest from the forest file, for example, .INF file.
        /// </summary>
        /// <param name="forestFileName">The location of the input file.</param>
        /// <returns>DecisionForest.</returns>
        public DecisionForest Load(string forestFileName)
        {
            Helper.ThrowIfNull(forestFileName);
            bool quesSection = true;
            bool treeSection = false;
            Collection<string> treeLines = new Collection<string>();
            foreach (string line in Helper.FileLines(forestFileName, Encoding.ASCII, false))
            {
                // Load question sets and count decision tree
                if (quesSection)
                {
                    if (line.IndexOf(Question.QuestionKeyword, StringComparison.Ordinal) < 0)
                    {
                        quesSection = false;
                    }
                    else
                    {
                        Question question = new Question(line);
                        _nameIndexedQuestions.Add(question.Name, question);
                    }
                }

                if (!quesSection)
                {
                    string trimLine = line.Trim();
                    if (!string.IsNullOrEmpty(trimLine))
                    {
                        // tree start
                        if (!treeSection)
                        {
                            treeSection = true;
                            treeLines.Clear();
                        }

                        treeLines.Add(trimLine);
                    }
                    else
                    {
                        // tree end
                        if (treeSection)
                        {
                            DecisionTree tree = new DecisionTree();
                            tree.Load(treeLines);
                            _treeList.Add(tree);
                            treeSection = false;
                        }
                    }
                }
            }

            if (treeSection)
            {
                throw new InvalidDataException(
                    Helper.NeutralFormat("Invalidate last line for Decision Tree {0}", forestFileName));
            }

            return this;
        }