ObjectManagerBase.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text.RegularExpressions;
  4. namespace sccdlib
  5. {
  6. public abstract class ObjectManagerBase
  7. {
  8. protected ControllerBase controller;
  9. EventQueue events = new EventQueue();
  10. Dictionary<RuntimeClassBase,InstanceWrapper> instances_map = new Dictionary<RuntimeClassBase,InstanceWrapper> ();
  11. public ObjectManagerBase (ControllerBase controller)
  12. {
  13. this.controller = controller;
  14. }
  15. public void addEvent (Event input_event, double time_offset = 0.0)
  16. {
  17. this.events.Add (input_event, time_offset);
  18. }
  19. public void broadcast (Event new_event)
  20. {
  21. foreach (RuntimeClassBase instance in this.instances_map.Keys)
  22. instance.addEvent(new_event);
  23. }
  24. public double getWaitTime()
  25. {
  26. //first get waiting time of the object manager's events
  27. double smallest_time = this.events.getEarliestTime();
  28. //check all the instances
  29. foreach (RuntimeClassBase instance in this.instances_map.Keys)
  30. smallest_time = Math.Min(smallest_time, instance.getEarliestEventTime());
  31. return smallest_time;
  32. }
  33. public void step (double delta)
  34. {
  35. this.events.decreaseTime(delta);
  36. foreach( Event e in this.events.popDueEvents())
  37. this.handleEvent (e);
  38. }
  39. private void handleEvent (Event handle_event)
  40. {
  41. string event_name = handle_event.getName ();
  42. if (event_name == "narrow_cast") {
  43. this.handleNarrowCastEvent(handle_event.getParameters());
  44. } else if (event_name == "broad_cast") {
  45. this.handleBroadCastEvent(handle_event.getParameters());
  46. } else if (event_name == "create_instance") {
  47. this.handleCreateEvent(handle_event.getParameters());
  48. } else if (event_name == "associate_instance") {
  49. this.handleAssociateEvent(handle_event.getParameters());
  50. } else if (event_name == "start_instance") {
  51. this.handleStartInstanceEvent(handle_event.getParameters());
  52. }
  53. }
  54. public void stepAll (double delta)
  55. {
  56. this.step(delta);
  57. foreach (RuntimeClassBase instance in this.instances_map.Keys)
  58. instance.step(delta);
  59. }
  60. public void start ()
  61. {
  62. foreach (RuntimeClassBase instance in this.instances_map.Keys)
  63. instance.start();
  64. }
  65. /// <summary>
  66. /// Processes the association reference.
  67. /// </summary>
  68. /// <returns>
  69. /// The association reference.
  70. /// </returns>
  71. /// <param name='input_string'>
  72. /// Input_string.
  73. /// </param>
  74. private List<Tuple<string, int>> processAssociationReference (string input_string)
  75. {
  76. if (input_string.Length == 0)
  77. throw new AssociationReferenceException("Empty association reference.");
  78. string[] path_string = input_string.Split (new char[] {'/'});
  79. Regex regex = new Regex(@"^([a-zA-Z_]\w*)(?:\[(\d+)\])?$");
  80. var result = new List<Tuple<string, int>>();
  81. foreach (string string_piece in path_string) {
  82. Match match = regex.Match (string_piece);
  83. if (match.Success ){
  84. string name = match.Groups[1].ToString ();
  85. int index;
  86. if (match.Groups[2].Success)
  87. int.TryParse(match.Groups[2].ToString(), out index);
  88. else
  89. index = -1;
  90. result.Add( new Tuple<string, int>(name,index));
  91. }else{
  92. throw new AssociationReferenceException("Invalid entry in association reference.");
  93. }
  94. }
  95. return result;
  96. }
  97. /// <summary>
  98. /// Gets the instances.
  99. /// </summary>
  100. /// <returns>
  101. /// The instances.
  102. /// </returns>
  103. /// <param name='source'>
  104. /// Source.
  105. /// </param>
  106. /// <param name='traversal_list'>
  107. /// Traversal_list.
  108. /// </param>
  109. private List<InstanceWrapper> getInstances (RuntimeClassBase source, List<Tuple<string, int>> traversal_list)
  110. {
  111. var currents = new List<InstanceWrapper> ();
  112. currents.Add (this.instances_map [source]);
  113. foreach (Tuple<string, int> tuple in traversal_list) {
  114. var nexts = new List<InstanceWrapper> ();
  115. foreach ( InstanceWrapper current in currents ){
  116. Association association = current.getAssociation (tuple.Item1);
  117. if (tuple.Item2 >= 0 )
  118. nexts.Add ( association.getInstance(tuple.Item2) );
  119. else if (tuple.Item2 == -1)
  120. nexts.AddRange ( association.getAllInstances() );
  121. else
  122. throw new AssociationReferenceException("Incorrect index in association reference.");
  123. }
  124. currents = nexts;
  125. }
  126. return currents;
  127. }
  128. /// <summary>
  129. /// Handles the start instance event.
  130. /// </summary>
  131. /// <param name='parameters'>
  132. /// [0] The instance the event originates from.
  133. /// [1] An association reference string targeting the instance to start.
  134. /// </param>
  135. private void handleStartInstanceEvent (object[] parameters)
  136. {
  137. if (parameters.Length != 2) {
  138. throw new ParameterException ("The start instance event needs 2 parameters.");
  139. } else {
  140. RuntimeClassBase source = (RuntimeClassBase) parameters[0];
  141. var traversal_list = this.processAssociationReference((string) parameters [1]);
  142. foreach( InstanceWrapper i in this.getInstances (source, traversal_list)){
  143. i.getInstance().start();
  144. }
  145. }
  146. }
  147. /// <summary>
  148. /// Handles the broad cast event.
  149. /// </summary>
  150. /// <param name='parameters'>
  151. /// [0] The event to be broadcasted.
  152. /// </param>
  153. private void handleBroadCastEvent(object[] parameters)
  154. {
  155. if (parameters.Length != 1 )
  156. throw new ParameterException ("The broadcast event needs 1 parameter.");
  157. this.broadcast((Event)parameters[0]);
  158. }
  159. private void handleCreateEvent (object[] parameters)
  160. {
  161. if (parameters.Length < 2) {
  162. throw new ParameterException ("The create event needs at least 2 parameters.");
  163. } else {
  164. RuntimeClassBase source = (RuntimeClassBase)parameters [0];
  165. string association_name = (string)parameters [1];
  166. Association association = this.instances_map[source].getAssociation (association_name);
  167. if (association.allowedToAdd ()){
  168. int constructor_parameters_length = parameters.Length -2;
  169. object[] constructor_parameters = new object[constructor_parameters_length];
  170. Array.Copy(parameters, 2, constructor_parameters, 0, constructor_parameters_length);
  171. InstanceWrapper new_instance_wrapper = this.createInstance(association.getClassName (), constructor_parameters);
  172. association.addInstance (new_instance_wrapper);
  173. source.addEvent(
  174. new Event(name: "instance_created", parameters : new object[] {association_name})
  175. );
  176. }else{
  177. source.addEvent (
  178. new Event(name: "instance_creation_error", parameters : new object[] {association_name})
  179. );
  180. }
  181. }
  182. }
  183. private void handleAssociateEvent (object[] parameters)
  184. {
  185. if (parameters.Length != 3) {
  186. throw new ParameterException ("The associate_instance event needs 3 parameters.");
  187. } else {
  188. RuntimeClassBase source = (RuntimeClassBase)parameters [0];
  189. List<InstanceWrapper> to_copy_list = this.getInstances (source, this.processAssociationReference ((string)parameters [1]));
  190. if (to_copy_list.Count != 1)
  191. throw new AssociationReferenceException ("Invalid source association reference.");
  192. InstanceWrapper wrapped_to_copy_instance = to_copy_list [0];
  193. List<Tuple<string,int>> dest_list = this.processAssociationReference ((string)parameters [2]);
  194. if (dest_list.Count == 0)
  195. throw new AssociationReferenceException ("Invalid destination association reference.");
  196. Tuple<string,int> last_tuple = dest_list [dest_list.Count - 1];
  197. if (last_tuple.Item2 != -1)
  198. throw new AssociationReferenceException ("Last association name in association reference should not be accompanied by an index.");
  199. dest_list.RemoveAt (dest_list.Count - 1);
  200. foreach (InstanceWrapper i in this.getInstances(source, dest_list)) {
  201. i.getAssociation (last_tuple.Item1).addInstance (wrapped_to_copy_instance);
  202. }
  203. }
  204. }
  205. private void handleNarrowCastEvent(object[] parameters)
  206. {
  207. if (parameters.Length != 3){
  208. throw new ParameterException ("The associate_instance event needs 3 parameters.");
  209. }else{
  210. RuntimeClassBase source = (RuntimeClassBase)parameters [0];
  211. Event cast_event = (Event) parameters[2];
  212. foreach (InstanceWrapper i in this.getInstances(source, this.processAssociationReference( (string) parameters[1])))
  213. i.getInstance ().addEvent(cast_event);
  214. }
  215. }
  216. protected abstract InstanceWrapper instantiate(string class_name, object[] construct_params);
  217. public InstanceWrapper createInstance(string class_name, object[] construct_params)
  218. {
  219. InstanceWrapper iw = this.instantiate(class_name, construct_params);
  220. if (iw != null)
  221. this.instances_map[iw.getInstance ()] = iw;
  222. return iw;
  223. }
  224. }
  225. }