in CSharp/Library/Microsoft.Bot.Builder/FormFlow/FormDialog.cs [577:774]
private bool MoveToNext(NextStep next)
{
bool found = false;
switch (next.Direction)
{
case StepDirection.Complete:
break;
case StepDirection.Named:
_formState.StepState = null;
if (next.Names.Length == 0)
{
goto case StepDirection.Next;
}
else if (next.Names.Length == 1)
{
var name = next.Names.First();
var nextStep = -1;
for (var i = 0; i < _form.Steps.Count(); ++i)
{
if (_form.Steps[i].Name == name)
{
nextStep = i;
break;
}
}
if (nextStep == -1)
{
throw new ArgumentOutOfRangeException("NextStep", "Does not correspond to a field in the form.");
}
if (_form.Steps[nextStep].Active(_state))
{
var current = _form.Steps[_formState.Step];
_formState.SetPhase(_form.Fields.Field(current.Name).IsUnknown(_state) ? StepPhase.Ready : StepPhase.Completed);
_formState.History.Push(_formState.Step);
_formState.Step = nextStep;
_formState.SetPhase(StepPhase.Ready);
found = true;
}
else
{
// If we went to a state which is not active fall through to the next active if any
goto case StepDirection.Next;
}
}
else
{
// Always mark multiple names as found so we can handle the user navigation
found = true;
}
break;
case StepDirection.Next:
{
var start = _formState.Step;
// Reset any non-optional field step that has been reset to no value
for (var i = 0; i < _form.Steps.Count; ++i)
{
var step = _form.Steps[i];
if (step.Type == StepType.Field && _formState.Phase(i) == StepPhase.Completed && !step.Field.Optional && step.Field.IsUnknown(_state))
{
_formState.SetPhase(i, StepPhase.Ready);
}
}
// Next ready step including current one
for (var offset = 0; offset < _form.Steps.Count; ++offset)
{
var istep = (start + offset) % _form.Steps.Count;
var step = _form.Steps[istep];
_formState.Step = istep;
if (offset > 0)
{
_formState.StepState = null;
_formState.Next = null;
}
if ((_formState.Phase(istep) == StepPhase.Ready || _formState.Phase(istep) == StepPhase.Responding)
&& step.Active(_state))
{
// Ensure all dependencies have values
foreach (var dependency in step.Dependencies)
{
var dstep = _form.Step(dependency);
var dstepi = _form.StepIndex(dstep);
if (dstep.Active(_state) && _formState.Phases[dstepi] != StepPhase.Completed)
{
_formState.Step = dstepi;
break;
}
}
found = true;
break;
}
}
if (!found)
{
next.Direction = StepDirection.Complete;
}
else
{
var normalStep = _formState.Step;
// Process initial messages first, then FieldInputs
if ((_formState.ProcessInputs || _form.Steps[normalStep].Type != StepType.Message) && _formState.FieldInputs != null)
{
// Override normal choice with FieldInputs
Func<bool> NextFieldInput = () =>
{
var foundInput = false;
while (_formState.FieldInputs.Any() && !foundInput)
{
var possible = _formState.FieldInputs.Last().Item1;
if (_form.Steps[possible].Active(_state))
{
_formState.Step = possible;
foundInput = true;
}
else
{
_formState.FieldInputs.Pop();
}
}
if (!_formState.FieldInputs.Any())
{
if (_options.HasFlag(FormOptions.PromptFieldsWithValues))
{
_formState.Reset();
}
else
{
_formState.ProcessInputs = false;
_formState.FieldInputs = null;
_formState.Step = 0;
}
// Skip initial messages since we showed them already
while (_formState.Step < _form.Steps.Count() && _form.Steps[_formState.Step].Type == StepType.Message)
{
_formState.SetPhase(StepPhase.Completed);
++_formState.Step;
}
}
return foundInput;
};
if (!_formState.ProcessInputs)
{
// Start of processing inputs
_formState.ProcessInputs = NextFieldInput();
}
else if (_formState.Phase(start) == StepPhase.Completed || _formState.Phase(start) == StepPhase.Ready)
{
// Reset state of just completed step
if (_options.HasFlag(FormOptions.PromptFieldsWithValues))
{
_formState.SetPhase(StepPhase.Ready);
}
// Move on to next field input if any
_formState.FieldInputs.Pop();
NextFieldInput();
}
}
else
{
if (_formState.Step != start && _form.Steps[start].Type != StepType.Message)
{
_formState.History.Push(start);
}
}
}
}
break;
case StepDirection.Previous:
while (_formState.History.Count() > 0)
{
var lastStepIndex = _formState.History.Pop();
var lastStep = _form.Steps[lastStepIndex];
if (lastStep.Active(_state))
{
var step = _form.Steps[_formState.Step];
_formState.SetPhase(step.Field.IsUnknown(_state) ? StepPhase.Ready : StepPhase.Completed);
_formState.Step = lastStepIndex;
_formState.SetPhase(StepPhase.Ready);
_formState.StepState = null;
_formState.Next = null;
found = true;
break;
}
}
if (!found)
{
next.Direction = StepDirection.Quit;
}
break;
case StepDirection.Quit:
break;
case StepDirection.Reset:
_formState.Reset();
// Because we redo phase they can go through everything again but with defaults.
found = true;
break;
}
return found;
}