1 /**
2  * Represents a state for a SystemStateMachine. The state contains any number of SystemProviders which
3  * are used to add Systems to the Engine when this state is entered.
4  */
5 module ashd.fsm.engineState;
6 
7 import std.conv: to;
8 
9 import ashd.core.system                : System;
10 import ashd.fsm.dynamicSystemProvider  : DynamicSystemProvider;
11 import ashd.fsm.ISystemProvider        : ISystemProvider;
12 import ashd.fsm.systemInstanceProvider : SystemInstanceProvider;
13 import ashd.fsm.systemSingletonProvider: SystemSingletonProvider;
14 
15 
16 
17 public class EngineState
18 {
19     private
20     {
21         ISystemProvider[ClassInfo] mProviders;
22     }
23 
24     ISystemProvider[ClassInfo] providers() { return mProviders; }
25 
26     /**
27      * Creates a mapping for the System type to a specific System instance. A
28      * SystemInstanceProvider is used for the mapping.
29      *
30      * @param system The System instance to use for the mapping
31      * @return This StateSystemMapping, so more modifications can be applied
32      */
33     public StateSystemMapping addInstance(T)( T system_a )
34     {
35         return this.addProvider( new SystemInstanceProvider!T( system_a ), T.classinfo );
36     }
37 
38     /**
39      * Creates a mapping for the System type to a single instance of the provided type.
40      * The instance is not created until it is first requested. The type should be the same
41      * as or extend the type for this mapping. A SystemSingletonProvider is used for
42      * the mapping.
43      *
44      * @param type The type of the single instance to be created. If omitted, the type of the
45      * mapping is used.
46      * @return This StateSystemMapping, so more modifications can be applied
47      */
48     public StateSystemMapping addSingleton( ClassInfo type_a )
49     {
50         return addProvider( new SystemSingletonProvider( type_a ), type_a );
51 
52     }
53 
54     /**
55      * Creates a mapping for the System type to a method call.
56      * The method should return a System instance. A DynamicSystemProvider is used for
57      * the mapping.
58      *
59      * @param method The method to provide the System instance.
60      * @return This StateSystemMapping, so more modifications can be applied.
61      */
62     public StateSystemMapping addMethod(T)( T delegate() method_a )
63     {
64         return addProvider( new DynamicSystemProvider( method_a ), T.classinfo );
65     }
66 
67     /**
68      * Adds any SystemProvider.
69      *
70      * @param provider The component provider to use.
71      * @return This StateSystemMapping, so more modifications can be applied.
72      */
73     public StateSystemMapping addProvider( ISystemProvider provider_a, ClassInfo class_a )
74     {
75         StateSystemMapping mapping = new StateSystemMapping( this, provider_a );
76         mProviders[class_a] = provider_a;
77         return mapping;
78     }
79 }
80 
81 
82 
83 class StateSystemMapping
84 {
85     private
86     {
87         EngineState     mCreatingState;
88         ISystemProvider mProvider;
89     }
90 
91     /**
92      * Used internally, the constructor creates a component mapping. The constructor
93      * creates a SystemSingletonProvider as the default mapping, which will be replaced
94      * by more specific mappings if other methods are called.
95      *
96      * @param creatingState The SystemState that the mapping will belong to
97      * @param type The System type for the mapping
98      */
99     private this( EngineState creatingState_a, ISystemProvider provider_a )
100     {
101         mCreatingState = creatingState_a;
102         mProvider = provider_a;
103     }
104 
105     /**
106      * Applies the priority to the provider that the System will be.
107      *
108      * @param priority The component provider to use.
109      * @return This StateSystemMapping, so more modifications can be applied.
110      */
111     public StateSystemMapping withPriority( int priority_a )
112     {
113         mProvider.priority = priority_a;
114         return this;
115     }
116 
117     /**
118      * Creates a mapping for the System type to a specific System instance. A
119      * SystemInstanceProvider is used for the mapping.
120      *
121      * @param system The System instance to use for the mapping
122      * @return This StateSystemMapping, so more modifications can be applied
123      */
124     public StateSystemMapping addInstance(T)( System system_a )
125     {
126         return mCreatingState.addInstance!T( system_a );
127     }
128 
129     /**
130      * Creates a mapping for the System type to a single instance of the provided type.
131      * The instance is not created until it is first requested. The type should be the same
132      * as or extend the type for this mapping. A SystemSingletonProvider is used for
133      * the mapping.
134      *
135      * @param type The type of the single instance to be created. If omitted, the type of the
136      * mapping is used.
137      * @return This StateSystemMapping, so more modifications can be applied
138      */
139     public StateSystemMapping addSingleton( ClassInfo type_a )
140     {
141         return mCreatingState.addSingleton( type_a );
142     }
143 
144     /**
145      * Creates a mapping for the System type to a method call.
146      * The method should return a System instance. A DynamicSystemProvider is used for
147      * the mapping.
148      *
149      * @param method The method to provide the System instance.
150      * @return This StateSystemMapping, so more modifications can be applied.
151      */
152     public StateSystemMapping addMethod( Object delegate() method_a )
153     {
154         return mCreatingState.addMethod( method_a );
155     }
156 
157     /**
158      * Maps through to the addProvider method of the SystemState that this mapping belongs to
159      * so that a fluent interface can be used when configuring entity states.
160      *
161      * @param provider The component provider to use.
162      * @return This StateSystemMapping, so more modifications can be applied.
163      */
164     public StateSystemMapping addProvider( ISystemProvider provider_a, ClassInfo class_a )
165     {
166         return mCreatingState.addProvider( provider_a, class_a );
167     }
168 }
169