public override string Help(T state, object defaultValue)
        {
            var prompt = new Prompter <T>(_field.Template(TemplateUsage.DateTimeHelp), _field.Form, null);
            var args   = HelpArgs(state, defaultValue);

            return(prompt.Prompt(state, _field, args.ToArray()).Prompt);
        }
        public FormPrompt Start(DialogContext context, T state, FormState form)
        {
            form.SetPhase(StepPhase.Completed);
            var prompt = new Prompter <T>(_promptDefinition, _form, null);

            return(prompt.Prompt(state, null));
        }
        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 Help(T state, FormState form, string commandHelp)
        {
            var recognizer = _field.Prompt.Recognizer;
            var prompt     = new Prompter <T>(_field.Template(TemplateUsage.HelpNavigation), _field.Form, recognizer, _fields);
            var help       = prompt.Prompt(state, _field, "* " + recognizer.Help(state, null), commandHelp);

            return(new FormPrompt {
                Prompt = "* " + help.Prompt, Buttons = help.Buttons
            });
        }
        public FormPrompt Help(T state, FormState form, string commandHelp)
        {
            var template = _field.Template(TemplateUsage.HelpConfirm);
            var prompt   = new Prompter <T>(template, _field.Form, _field.Prompt.Recognizer);
            var help     = prompt.Prompt(state, _field, "* " + prompt.Recognizer.Help(state, null), commandHelp);

            return(new FormPrompt {
                Prompt = "* " + help.Prompt, Buttons = help.Buttons
            });
        }
        public override string Help(T state, object defaultValue)
        {
            var prompt = new Prompter <T>(
                _field.Template(this.multipleAttachments ? TemplateUsage.AttachmentCollectionHelp : TemplateUsage.AttachmentFieldHelp),
                _field.Form,
                null);

            // create instance just to call virtual method
            var awaitableAttachment = Activator.CreateInstance(this.GetAttachmentTypeFromField(), default(Attachment)) as AwaitableAttachment;

            return(prompt.Prompt(state, _field, awaitableAttachment.ProvideHelp(_field)).Prompt);
        }
        public override string Help(T state, object defaultValue)
        {
            var prompt = new Prompter <T>(_field.Template(TemplateUsage.DoubleHelp), _field.Form, null);
            var args   = HelpArgs(state, defaultValue);

            if (_showLimits)
            {
                args.Add(_min);
                args.Add(_max);
            }
            return(prompt.Prompt(state, _field, args.ToArray()).Prompt);
        }
        protected void DefineRecognizer()
        {
            if (_recognizer == null)
            {
                if (_type == null || _type.IsEnum)
                {
                    _recognizer = new RecognizeEnumeration <T>(this);
                }
                else if (_type == typeof(bool))
                {
                    _recognizer = new RecognizeBool <T>(this);
                }
                else if (_type == typeof(string))
                {
                    _recognizer = new RecognizeString <T>(this);
                }
                else if (_type.IsIntegral())
                {
                    _recognizer = new RecognizeNumber <T>(this);
                }
                else if (_type.IsDouble())
                {
                    _recognizer = new RecognizeDouble <T>(this);
                }
                else if (_type == typeof(DateTime))
                {
                    _recognizer = new RecognizeDateTime <T>(this);
                }
                else if (_type.IsAttachmentType() || _type.IsAttachmentCollection())
                {
                    _recognizer = new RecognizeAttachment <T>(this, _type.IsAttachmentCollection());
                }
                else if (_type.IsIEnumerable())
                {
                    var elt = _type.GetGenericElementType();
                    if (elt.IsEnum)
                    {
                        _recognizer = new RecognizeEnumeration <T>(this);
                    }
                }
                _buildPrompts = true;
            }

            if (_buildPrompts)
            {
                var template = Template(TemplateUsage.Help);
                _help = new Prompter <T>(template, _form, _recognizer);
                var prompt = _promptDefinition;
                _prompt       = new Prompter <T>(_promptDefinition, _form, _recognizer);
                _buildPrompts = false;
            }
        }
        private FormPrompt ClarifyPrompt(FieldStepState stepState, IRecognize <T> recognizer, T state)
        {
            var        clarify = NeedsClarification(stepState);
            FormPrompt prompt  = null;

            if (clarify != null)
            {
                var field    = ClarifyField(clarify, recognizer);
                var prompter = new Prompter <T>(field.Template(TemplateUsage.Clarify), field.Form, new RecognizeEnumeration <T>(field));
                prompt = prompter.Prompt(state, field, clarify.Response);
            }
            return(prompt);
        }
        public NavigationField(string name, string startField, IForm <T> form, T state, FormState formState, Fields <T> fields)
            : base(name, FieldRole.Value)
        {
            Form = form;
            var field = form.Fields.Field(startField);

            SetFieldDescription(_form.Configuration.Navigation);
            SetOptional();
            foreach (var value in formState.Next.Names)
            {
                var svalue      = (string)value;
                var sfield      = form.Fields.Field(svalue);
                var fieldPrompt = sfield.Template(TemplateUsage.NavigationFormat);
                var prompter    = new Prompter <T>(fieldPrompt, form, sfield.Prompt.Recognizer);
                AddDescription(value, prompter.Prompt(state, sfield).Prompt, null, sfield.FieldDescription.Message ?? sfield.FieldDescription.Description);
                AddTerms(value, form.Fields.Field(svalue).FieldTerms.ToArray());
            }
            var template = field.Template(TemplateUsage.Navigation);

            SetPrompt(new PromptAttribute(template));
            SetRecognizer(new RecognizeEnumeration <T>(this));
            _prompt = new Prompter <T>(template, form, _recognizer, fields);
        }
        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));
        }
        private string ExpandTemplate(string template, string currentChoice, string noValue, T state, IField <T> field, object[] args, ref IList <DescribeAttribute> buttons)
        {
            bool foundUnspecified = false;
            int  last             = 0;
            int  numeric;
            var  response = new StringBuilder();

            foreach (Match match in _args.Matches(template))
            {
                var expr       = match.Groups[1].Value.Trim();
                var substitute = string.Empty;
                if (expr.StartsWith("&"))
                {
                    var name = expr.Substring(1);
                    if (name == string.Empty && field != null)
                    {
                        name = field.Name;
                    }
                    var pathField = _fields.Field(name);
                    substitute = Language.Normalize(pathField == null ? field.Name : pathField.FieldDescription.Description, _annotation.FieldCase);
                }
                else if (expr == "||")
                {
                    var builder    = new StringBuilder();
                    var values     = _recognizer.ValueDescriptions();
                    var useButtons = !field.AllowsMultiple &&
                                     (_annotation.ChoiceStyle == ChoiceStyleOptions.Auto ||
                                      _annotation.ChoiceStyle == ChoiceStyleOptions.Buttons ||
                                      _annotation.ChoiceStyle == ChoiceStyleOptions.Carousel);
                    if (values.Any() && _annotation.AllowDefault != BoolDefault.False && field.Optional)
                    {
                        values = values.Concat(new DescribeAttribute[] { new DescribeAttribute(Language.Normalize(noValue, _annotation.ChoiceCase)) });
                    }
                    string current = null;
                    if (_annotation.AllowDefault != BoolDefault.False)
                    {
                        if (!field.Optional)
                        {
                            if (!field.IsUnknown(state))
                            {
                                current = ExpandTemplate(currentChoice, null, noValue, state, field, args, ref buttons);
                            }
                        }
                        else
                        {
                            current = ExpandTemplate(currentChoice, null, noValue, state, field, args, ref buttons);
                        }
                    }
                    if (values.Any())
                    {
                        if (useButtons)
                        {
                            foreach (var value in values)
                            {
                                buttons.Add(value);
                            }
                        }
                        else
                        {
                            // Buttons do not support multiple selection so we fall back to text
                            if (((_annotation.ChoiceStyle == ChoiceStyleOptions.Auto || _annotation.ChoiceStyle == ChoiceStyleOptions.AutoText) &&
                                 values.Count() < 4) ||
                                (_annotation.ChoiceStyle == ChoiceStyleOptions.Inline))
                            {
                                // Inline choices
                                if (_annotation.ChoiceParens == BoolDefault.True)
                                {
                                    builder.Append('(');
                                }
                                var choices = new List <string>();
                                var i       = 1;
                                foreach (var value in values)
                                {
                                    choices.Add(string.Format(_annotation.ChoiceFormat, i, Language.Normalize(value.Description, _annotation.ChoiceCase)));
                                    ++i;
                                }
                                builder.Append(Language.BuildList(choices, _annotation.ChoiceSeparator, _annotation.ChoiceLastSeparator));
                                if (_annotation.ChoiceParens == BoolDefault.True)
                                {
                                    builder.Append(')');
                                }
                                if (current != null)
                                {
                                    builder.Append(" ");
                                    builder.Append(current);
                                }
                            }
                            else
                            {
                                // Separate line choices
                                if (current != null)
                                {
                                    builder.Append(current);
                                    builder.Append(" ");
                                }
                                var i = 1;
                                foreach (var value in values)
                                {
                                    builder.AppendLine();
                                    builder.Append("  ");
                                    if (!_annotation.AllowNumbers)
                                    {
                                        builder.Append("* ");
                                    }
                                    builder.AppendFormat(_annotation.ChoiceFormat, i, Language.Normalize(value.Description, _annotation.ChoiceCase));
                                    ++i;
                                }
                            }
                        }
                    }
                    else if (current != null)
                    {
                        builder.Append(" ");
                        builder.Append(current);
                    }
                    substitute = builder.ToString();
                }
                else if (expr.StartsWith("*"))
                {
                    // Status display of active results
                    var filled  = expr.ToLower().Trim().EndsWith("filled");
                    var builder = new StringBuilder();
                    if (match.Index > 0)
                    {
                        builder.AppendLine();
                    }
                    foreach (var entry in (from step in _fields where (!filled || !step.IsUnknown(state)) && step.Role == FieldRole.Value && step.Active(state) select step))
                    {
                        var format = new Prompter <T>(Template(entry, TemplateUsage.StatusFormat), _form, null);
                        builder.Append("* ").AppendLine(format.Prompt(state, entry).Prompt);
                    }
                    substitute = builder.ToString();
                }
                else if (expr.StartsWith("[") && expr.EndsWith("]"))
                {
                    // Generate a list from multiple fields
                    var paths  = expr.Substring(1, expr.Length - 2).Split(' ');
                    var values = new List <Tuple <IField <T>, object, string> >();
                    foreach (var spec in paths)
                    {
                        if (!spec.StartsWith("{") || !spec.EndsWith("}"))
                        {
                            throw new ArgumentException("Only {<field>} references are allowed in lists.");
                        }
                        var formatArgs = spec.Substring(1, spec.Length - 2).Trim().Split(':');
                        var name       = formatArgs[0];
                        if (name == string.Empty && field != null)
                        {
                            name = field.Name;
                        }
                        var format  = (formatArgs.Length > 1 ? "0:" + formatArgs[1] : "0");
                        var eltDesc = _fields.Field(name);
                        if (!eltDesc.IsUnknown(state))
                        {
                            var value = eltDesc.GetValue(state);
                            if (value.GetType() != typeof(string) && value.GetType().IsIEnumerable())
                            {
                                var eltValues = (value as System.Collections.IEnumerable);
                                foreach (var elt in eltValues)
                                {
                                    values.Add(Tuple.Create(eltDesc, elt, format));
                                }
                            }
                            else
                            {
                                values.Add(Tuple.Create(eltDesc, eltDesc.GetValue(state), format));
                            }
                        }
                    }
                    if (values.Count() > 0)
                    {
                        var elements = (from elt in values
                                        select Language.Normalize(ValueDescription(elt.Item1, elt.Item2, elt.Item3), _annotation.ValueCase)).ToArray();
                        substitute = Language.BuildList(elements, _annotation.Separator, _annotation.LastSeparator);
                    }
                }
                else if (expr.StartsWith("?"))
                {
                    // Conditional template
                    var subValue = ExpandTemplate(expr.Substring(1), currentChoice, null, state, field, args, ref buttons);
                    if (subValue == null)
                    {
                        substitute = string.Empty;
                    }
                    else
                    {
                        substitute = subValue;
                    }
                }
                else if (TryParseFormat(expr, out numeric))
                {
                    // Process ad hoc arg
                    if (numeric < args.Length && args[numeric] != null)
                    {
                        substitute = string.Format("{" + expr + "}", args);
                    }
                    else
                    {
                        foundUnspecified = true;
                        break;
                    }
                }
                else
                {
                    var formatArgs = expr.Split(':');
                    var name       = formatArgs[0];
                    if (name == string.Empty && field != null)
                    {
                        name = field.Name;
                    }
                    var pathDesc = _fields.Field(name);
                    if (pathDesc.IsUnknown(state))
                    {
                        if (noValue == null)
                        {
                            foundUnspecified = true;
                            break;
                        }
                        substitute = noValue;
                    }
                    else
                    {
                        var value = pathDesc.GetValue(state);
                        if (value.GetType() != typeof(string) && value.GetType().IsIEnumerable())
                        {
                            if (value.GetType().IsAttachmentCollection())
                            {
                                var locTemplate = this._form.Configuration.Template(TemplateUsage.AttachmentCollectionDescription);
                                substitute = string.Format(locTemplate.Pattern(), (value as IEnumerable <AwaitableAttachment>).Count());
                            }
                            else
                            {
                                var values = (value as System.Collections.IEnumerable);
                                substitute = Language.BuildList(from elt in values.Cast <object>()
                                                                select Language.Normalize(ValueDescription(pathDesc, elt, "0"), _annotation.ValueCase),
                                                                _annotation.Separator, _annotation.LastSeparator);
                            }
                        }
                        else if (value.GetType().IsAttachmentType())
                        {
                            var attachment  = (value as AwaitableAttachment).Attachment;
                            var locTemplate = this._form.Configuration.Template(TemplateUsage.AttachmentFieldDescription);
                            substitute = string.Format(locTemplate.Pattern(), attachment.Name, attachment.ContentType);
                        }
                        else
                        {
                            var format = (formatArgs.Length > 1 ? "0:" + formatArgs[1] : "0");
                            substitute = ValueDescription(pathDesc, value, format);
                        }
                    }
                }
                response.Append(template.Substring(last, match.Index - last)).Append(substitute);
                last = match.Index + match.Length;
            }
            return(foundUnspecified ? null : response.Append(template.Substring(last, template.Length - last)).ToString());
        }