-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathStateMachineEngine.cs
144 lines (129 loc) · 6.33 KB
/
StateMachineEngine.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
using System;
using System.Threading.Tasks;
using System.Reflection;
using System.Collections.Generic;
namespace DotStep.Core
{
public class StateMachineEngine<TStateMachine, TContext>
where TStateMachine : IStateMachine
where TContext : IContext
{
TStateMachine stateMachine;
TContext context;
public StateMachineEngine(TContext context)
{
stateMachine = (TStateMachine)Activator.CreateInstance(typeof(TStateMachine));
this.context = context;
}
public async Task Start()
{
await ChangeState(stateMachine.StartAt);
}
private async Task ChangeState(Type type)
{
try {
Console.WriteLine("Changing state to: " + type.Name);
var state = Activator.CreateInstance(type) as IState;
if (state.End)
return;
if (state is ITaskState<TContext>)
{
var taskState = state as ITaskState<TContext>;
context = await taskState.Execute(context);
if (!taskState.End)
await ChangeState(taskState.Next);
}
else if (state is IChoiceState)
{
var choiceState = state as IChoiceState;
var useDefault = true;
foreach (var choice in choiceState.Choices)
{
var useNext = false;
var compairValue = typeof(TContext).GetProperty(choice.Variable).GetValue(context);
var operatorStart = choice.Operator.Substring(0, 2).ToUpper();
switch (operatorStart)
{
case "BO":
if (Convert.ToBoolean(compairValue) == Convert.ToBoolean(choice.Value))
useNext = true;
break;
case "NU":
var numericCompairValue = Convert.ToDecimal(compairValue);
var numericValue = Convert.ToDecimal(choice.Value);
switch (choice.Operator)
{
case Operator.NumericEquals:
if (numericCompairValue == numericValue)
useNext = true;
break;
case Operator.NumericGreaterThan:
if (numericCompairValue > numericValue)
useNext = true;
break;
case Operator.NumericGreaterThanEquals:
if (numericCompairValue >= numericValue)
useNext = true;
break;
case Operator.NumericLessThan:
if (numericCompairValue < numericValue)
useNext = true;
break;
case Operator.NumericLessThanEquals:
if (numericCompairValue <= numericValue)
useNext = true;
break;
default: throw new NotImplementedException("Not implemented: " + choice.Operator);
}
break;
case "ST":
var stringComapirValue = Convert.ToString(compairValue);
var stringValue = Convert.ToString(choice.Value);
switch (choice.Operator)
{
case Operator.StringEquals:
if (stringComapirValue == stringValue)
useNext = true;
break;
default: throw new NotImplementedException("Not implemented: " + choice.Operator);
}
break;
default: throw new NotImplementedException("Operator not supported: " + choice.Operator);
}
if (useNext)
{
useDefault = false;
await ChangeState(choice.Next);
break;
}
}
if (useDefault)
await ChangeState(choiceState.Default);
}
else if (state is IWaitState)
{
var waitState = state as IWaitState;
await Task.Delay(waitState.Seconds * 1000);
await ChangeState(waitState.Next);
}
else if (state is IPassState)
{
// nothing to do here..
var passSate = state as IPassState;
}
else if (state is IParallelState<TContext>) {
var parallelState = state as IParallelState<TContext>;
var tasks = new List<Task>();
foreach (var stateType in parallelState.ParallelStateTypes)
tasks.Add(ChangeState(stateType));
await Task.WhenAll(tasks);
await ChangeState(parallelState.Next);
}
else throw new NotImplementedException("State type not implemented: " + type.Name);
} catch (Exception exception) {
Console.WriteLine(exception.Message);
throw;
}
}
}
}