public FormPrompt NotUnderstood(DialogContext context, T state, FormState form, IMessageActivity input)
        {
            var template = _field.Template(TemplateUsage.NotUnderstood);
            var prompter = new Prompter <T>(template, _field.Form, null);

            return(prompter.Prompt(state, _field, MessageActivityHelper.GetSanitizedTextInput(input)));
        }
        public FormPrompt NotUnderstood(DialogContext context, T state, FormState form, IMessageActivity input)
        {
            var inputText = MessageActivityHelper.GetSanitizedTextInput(input);

            FormPrompt feedback   = null;
            var        iprompt    = _field.Prompt;
            var        fieldState = (FieldStepState)form.StepState;

            if (fieldState.State == FieldStepStates.SentPrompt)
            {
                feedback = Template(TemplateUsage.NotUnderstood).Prompt(state, _field, inputText);
            }
            else if (fieldState.State == FieldStepStates.SentClarify)
            {
                feedback = Template(TemplateUsage.NotUnderstood, ClarifyRecognizer(fieldState, _field.Prompt.Recognizer)).Prompt(state, _field, inputText);
            }
            return(feedback);
        }
        public IEnumerable <TermMatch> Matches(IMessageActivity input, object defaultValue)
        {
            var inputText = MessageActivityHelper.GetSanitizedTextInput(input);

            // if the user hit enter on an optional prompt, then consider taking the current choice as a low confidence option
            bool userSkippedPrompt = string.IsNullOrWhiteSpace(inputText) && (defaultValue != null || _noPreference != null);

            if (userSkippedPrompt)
            {
                yield return(new TermMatch(0, inputText.Length, 1.0, defaultValue));
            }
            inputText = MessageActivityHelper.RemoveDiacritics(inputText);
            foreach (var expression in _expressions)
            {
                double maxWords = expression.MaxWords;
                foreach (Match match in expression.Expression.Matches(inputText))
                {
                    var    group1 = match.Groups[1];
                    var    group2 = match.Groups[2];
                    object newValue;
                    if (group1.Success)
                    {
                        if (ConvertSpecial(expression.Value, defaultValue, out newValue))
                        {
                            yield return(new TermMatch(group1.Index, group1.Length, 1.0, newValue));
                        }
                    }
                    if (group2.Success)
                    {
                        var words      = group2.Value.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Length;
                        var confidence = System.Math.Min(words / maxWords, 1.0);
                        if (ConvertSpecial(expression.Value, defaultValue, out newValue))
                        {
                            yield return(new TermMatch(group2.Index, group2.Length, confidence, newValue));
                        }
                    }
                }
            }
        }
        public virtual IEnumerable <TermMatch> Matches(IMessageActivity input, object defaultValue = null)
        {
            var inputText = MessageActivityHelper.GetSanitizedTextInput(input);

            var matchValue = inputText.Trim().ToLower();

            if (_noPreference != null && _noPreference.Contains(matchValue))
            {
                yield return(new TermMatch(0, inputText.Length, 1.0, null));
            }
            else if ((defaultValue != null || _noPreference != null) && (matchValue == "" || _currentChoices.Contains(matchValue)))
            {
                yield return(new TermMatch(0, inputText.Length, 1.0, defaultValue));
            }
            else
            {
                var result = Parse(inputText);
                if (result != null)
                {
                    yield return(result);
                }
            }
        }
        public async Task <StepResult> ProcessAsync(DialogContext context, T state, FormState form, IMessageActivity input, IEnumerable <TermMatch> matches)
        {
            var inputText = MessageActivityHelper.GetSanitizedTextInput(input);

            ValidateResult feedback = new ValidateResult();

            feedback.IsValid      = true;
            feedback.Feedback     = null;
            feedback.FeedbackCard = null;
            feedback.Choices      = null;
            FormPrompt prompt         = null;
            FormPrompt feedbackPrompt = null;
            var        iprompt        = _field.Prompt;
            var        fieldState     = (FieldStepState)form.StepState;
            object     response       = null;

            if (fieldState.State == FieldStepStates.SentPrompt)
            {
                // Response to prompt
                var firstMatch = matches.FirstOrDefault();
                if (matches.Count() == 1)
                {
                    response = firstMatch.Value;
                    if (_field.AllowsMultiple && response != null &&
                        (response.GetType() == typeof(string) || !response.GetType().IsIEnumerable()))
                    {
                        response = new List <object>()
                        {
                            response
                        };
                    }
                    feedback = await SetValueAsync(state, response, form);

                    if (!feedback.IsValid && feedback.Choices != null)
                    {
                        var choices = new Ambiguous(inputText.Substring(firstMatch.Start, firstMatch.Length), feedback.Choices);
                        fieldState.State          = FieldStepStates.SentClarify;
                        fieldState.Settled        = new List <object>();
                        fieldState.Clarifications = new List <Ambiguous>()
                        {
                            choices
                        };
                        response = SetValue(state, null);
                        prompt   = ClarifyPrompt((FieldStepState)form.StepState, iprompt.Recognizer, state);
                    }
                }
                else if (matches.Count() > 1)
                {
                    // Check multiple matches for ambiguity
                    var groups = MatchAnalyzer.GroupedMatches(matches);
                    // 1) Could be multiple match groups like for ingredients.
                    // 2) Could be overlapping matches like "onion".
                    // 3) Could be multiple matches where only one is expected.

                    if (!_field.AllowsMultiple)
                    {
                        // Create a single group of all possibilities if only want one value
                        var mergedGroup = groups.SelectMany((group) => group).ToList();
                        groups = new List <List <TermMatch> >()
                        {
                            mergedGroup
                        };
                    }
                    var ambiguous = new List <Ambiguous>();
                    var settled   = new List <object>();
                    foreach (var choices in groups)
                    {
                        if (choices.Count > 1)
                        {
                            var unclearResponses = string.Join(" ", (from choice in choices select inputText.Substring(choice.Start, choice.Length)).Distinct());
                            var values           = from match in choices select match.Value;
                            ambiguous.Add(new Ambiguous(unclearResponses, values));
                        }
                        else
                        {
                            var matchValue = choices.First().Value;
                            if (matchValue != null && matchValue.GetType() != typeof(string) && matchValue.GetType().IsIEnumerable())
                            {
                                foreach (var value in (System.Collections.IEnumerable)matchValue)
                                {
                                    settled.Add(value);
                                }
                            }
                            else
                            {
                                settled.Add(choices.First().Value);
                            }
                        }
                    }
                    if (settled.Count > 1)
                    {
                        // Remove no preference if present
                        settled.Remove(null);
                    }

                    if (ambiguous.Count > 0)
                    {
                        // Need 1 or more clarifications
                        fieldState.State          = FieldStepStates.SentClarify;
                        fieldState.Settled        = settled;
                        fieldState.Clarifications = ambiguous;
                        response = SetValue(state, null);
                        prompt   = ClarifyPrompt((FieldStepState)form.StepState, iprompt.Recognizer, state);
                    }
                    else
                    {
                        if (_field.AllowsMultiple)
                        {
                            response = settled;
                            feedback = await SetValueAsync(state, response, form);
                        }
                        else
                        {
                            Debug.Assert(settled.Count == 1);
                            response = settled.First();
                            feedback = await SetValueAsync(state, response, form);
                        }
                    }
                }
                var unmatched      = MatchAnalyzer.Unmatched(inputText, matches);
                var unmatchedWords = string.Join(" ", unmatched);
                var nonNoise       = Language.NonNoiseWords(Language.WordBreak(unmatchedWords)).ToArray();
                fieldState.Unmatched = null;
                if (_field.Prompt.Annotation.Feedback == FeedbackOptions.Always)
                {
                    fieldState.Unmatched = string.Join(" ", nonNoise);
                }
                else if (_field.Prompt.Annotation.Feedback == FeedbackOptions.Auto &&
                         nonNoise.Any() &&
                         unmatched.Any())
                {
                    fieldState.Unmatched = string.Join(" ", nonNoise);
                }
            }
            else if (fieldState.State == FieldStepStates.SentClarify)
            {
                if (matches.Count() == 1)
                {
                    // Clarified ambiguity
                    var clarify = NeedsClarification(fieldState);
                    fieldState.Settled.Add(matches.First().Value);
                    fieldState.Clarifications.Remove(clarify);
                    if (prompt == null)
                    {
                        // No clarification left, so set the field
                        if (_field.AllowsMultiple)
                        {
                            response = fieldState.Settled;
                            feedback = await SetValueAsync(state, response, form);
                        }
                        else
                        {
                            Debug.Assert(fieldState.Settled.Count == 1);
                            response = fieldState.Settled.First();
                            feedback = await SetValueAsync(state, response, form);
                        }
                        form.SetPhase(StepPhase.Completed);
                    }
                }
            }
            if (form.Phase() == StepPhase.Completed)
            {
                form.StepState = null;
                if (fieldState.Unmatched != null)
                {
                    if (feedback.FeedbackCard != null)
                    {
                        feedbackPrompt = feedback.FeedbackCard;
                    }
                    else if (feedback.Feedback != null)
                    {
                        feedbackPrompt = new FormPrompt {
                            Prompt = feedback.Feedback
                        };
                    }
                    else
                    {
                        if (fieldState.Unmatched != "")
                        {
                            feedbackPrompt = new Prompter <T>(_field.Template(TemplateUsage.Feedback), _field.Form, null).Prompt(state, _field, fieldState.Unmatched);
                        }
                        else
                        {
                            feedbackPrompt = new Prompter <T>(_field.Template(TemplateUsage.Feedback), _field.Form, null).Prompt(state, _field);
                        }
                    }
                }
            }
            var next = _field.Next(response, state);

            return(new StepResult(feedback.IsValid, next, feedbackPrompt ?? (feedback.FeedbackCard ?? new FormPrompt {
                Prompt = feedback.Feedback
            }), prompt));
        }
        public IEnumerable <TermMatch> Match(DialogContext context, T state, FormState form, IMessageActivity input)
        {
            IEnumerable <TermMatch> matches = null;

            Debug.Assert(form.Phase() == StepPhase.Responding);
            var stepState = (FieldStepState)form.StepState;

            if (stepState.State == FieldStepStates.SentPrompt)
            {
                matches = _field.Prompt.Recognizer.Matches(input, _field.GetValue(state));
            }
            else if (stepState.State == FieldStepStates.SentClarify)
            {
                var fieldState       = (FieldStepState)form.StepState;
                var iprompt          = _field.Prompt;
                var choiceRecognizer = ClarifyRecognizer(fieldState, iprompt.Recognizer);
                matches = MatchAnalyzer.Coalesce(MatchAnalyzer.HighestConfidence(choiceRecognizer.Matches(input)), MessageActivityHelper.GetSanitizedTextInput(input)).ToArray();
                if (matches.Count() > 1)
                {
                    matches = new TermMatch[0];
                }
            }
#if DEBUG
            if (FormDialog.DebugRecognizers)
            {
                MatchAnalyzer.PrintMatches(matches, 2);
            }
#endif
            return(matches);
        }
        private int AddExpression(int n, object value, IEnumerable <string> terms, bool allowNumbers)
        {
            var orderedTerms = (from term in terms orderby term.Length descending select MessageActivityHelper.RemoveDiacritics(term)).ToArray();
            var words        = new StringBuilder();
            var first        = true;
            int maxWords     = 0;

            if (orderedTerms.Length > 0)
            {
                maxWords = terms.Max(NumberOfWords);
                foreach (var term in orderedTerms)
                {
                    var nterm = term.Trim().Replace(" ", @"\s+");
                    if (nterm != "")
                    {
                        if (first)
                        {
                            first = false;
                            words.Append('(');
                        }
                        else
                        {
                            words.Append('|');
                        }
                        words.Append("(?:");
                        if (_wordStart.Match(nterm).Success&& _wordEnd.Match(nterm).Success)
                        {
                            words.Append($@"\b{nterm}\b");
                        }
                        else
                        {
                            words.Append(nterm);
                        }
                        words.Append(')');
                    }
                }
            }
            if (first)
            {
                words.Append($@"(\b(?:{NOMATCH})");
            }
            words.Append(')');
            var numbers = allowNumbers ? $"(\\b{n}\\b)" : NOMATCH;
            var expr    = $"{numbers}|{words}";

            _expressions.Add(new ValueAndExpression(value, new Regex(expr.ToString(), RegexOptions.IgnoreCase), maxWords));
            ++n;
            return(n);
        }