|
using System;
using System.Threading;
namespace RQAssemblies.StateEngine
{
/// <summary>
/// Summary description for Engine.
/// </summary>
public class Engine : System.Collections.IList
{
#region Variables
private System.Collections.ArrayList stateList = new System.Collections.ArrayList();
private System.Xml.XmlDocument stateTable = new System.Xml.XmlDocument();
private object engineMethodsClass = null;
#endregion Variables
#region Threading
#region Thread Variables
private Thread engineThread = null;
private long currentStateNumber = -1;
private bool exitThread = false;
#endregion Thread Variables
#region Public methods
public void LoadStateTable(string fileName)
{
try
{
stateTable.Load(fileName);
PopulateStateEngine();
}
catch(System.Xml.XmlException ex)
{
}
catch(System.IO.FileNotFoundException)
{
}
}
public void Run()
{
if(engineThread == null)
{
engineThread = new Thread(new ThreadStart(EngineThread));
}
engineThread.Start();
}
public void Stop()
{
exitThread = true;
engineThread.Abort();
}
public object EngineMethodsClass
{
get
{
return engineMethodsClass;
}
set
{
engineMethodsClass = value;
}
}
#endregion Public methods
#region Private methods
/// <summary>
/// populates the state list with available states from the xml document
/// </summary>
private void PopulateStateEngine()
{
try
{
System.Xml.XmlNode stateTableNode = stateTable.SelectSingleNode("StateTable");
if(stateTableNode != null)
{
System.Xml.XmlNodeList stateNodeList = stateTableNode.SelectNodes("State");
if(stateNodeList != null)
{
foreach(System.Xml.XmlNode node in stateNodeList)
{
PopulateStateEngine(node);
}
}
}
}
catch(System.Xml.XPath.XPathException ex)
{
}
}
/// <summary>
/// creates a new state and adds it to the state list
/// </summary>
/// <param name="stateNode">the xml node where the state to be added is</param>
private void PopulateStateEngine(System.Xml.XmlNode stateNode)
{
State state = new State();
// state number
System.Xml.XmlAttribute stateNumber = stateNode.Attributes["Number"];
state.StateNumber = System.Convert.ToInt32(stateNumber.Value);
// function
System.Xml.XmlNode exitFunction = stateNode.SelectSingleNode("Function");
string functionName = exitFunction.InnerText;
if(functionName.Length > 0)
{
// get our OnState event, then createand add a new delegate to the event
System.Reflection.EventInfo eventInfo = state.GetType().GetEvent("OnState");
System.Delegate eventDelegate = System.Delegate.CreateDelegate(eventInfo.EventHandlerType, this.engineMethodsClass, functionName);
eventInfo.AddEventHandler(state, eventDelegate);
}
// action
System.Xml.XmlNode actionNode = stateNode.SelectSingleNode("Action");
if(actionNode != null)
{
System.Xml.XmlAttribute actionTypeAttribute = actionNode.Attributes["Type"];
// iterate through the enumeration types and find the one that the state engine references
Type enumType = typeof(RQAssemblies.StateEngine.Action.ActionType);
foreach(System.Reflection.FieldInfo info in enumType.GetFields())
{
if(info.Name == actionTypeAttribute.Value)
{
// now create and add the new action
RQAssemblies.StateEngine.Action.ActionType actionType = (RQAssemblies.StateEngine.Action.ActionType)info.GetValue(null);
Action actionToAdd = new Action(actionType);
switch(actionType)
{
case RQAssemblies.StateEngine.Action.ActionType.SLEEP:
{
System.Xml.XmlNode sleepTime = actionNode.SelectSingleNode("SleepTime");
if(sleepTime != null)
{
actionToAdd.SleepTime = System.Convert.ToInt32(sleepTime.InnerText);
}
break;
}
case RQAssemblies.StateEngine.Action.ActionType.MOVETONEXT:
{
System.Xml.XmlNode sleepTime = actionNode.SelectSingleNode("SleepTime");
if(sleepTime != null)
{
actionToAdd.SleepTime = System.Convert.ToInt32(sleepTime.InnerText);
}
break;
}
}
state.ActionOnExit = actionToAdd;
}
}
}
Add(state);
}
/// <summary>
/// main thread function
/// </summary>
private void EngineThread()
{
do
{
// re-start engine case
if(currentStateNumber == -1)
{
try
{
currentStateNumber = this[0].StateNumber;
}
catch(IndexOutOfRangeException ex)
{
}
}
// if we have a valid state then process it...
if(currentStateNumber != -1)
{
State state = Find(currentStateNumber);
if(state != null)
{
System.Diagnostics.Trace.WriteLine(string.Format("RQAssemblies.StateEngine.Engine - Thread found state ({0})", state.StateNumber));
// a chance for us to do something if we wish
Action actionOnExit = state.Method();
// determine what to do next...
if(actionOnExit != null)
{
switch(actionOnExit.Type)
{
case RQAssemblies.StateEngine.Action.ActionType.MOVETONEXT:
{
System.Threading.Thread.Sleep(System.Convert.ToInt32(actionOnExit.SleepTime));
currentStateNumber = actionOnExit.StateNumberToMoveTo;
break;
}
case RQAssemblies.StateEngine.Action.ActionType.EXIT:
{
exitThread = true;
break;
}
case RQAssemblies.StateEngine.Action.ActionType.SLEEP:
{
System.Threading.Thread.Sleep(System.Convert.ToInt32(actionOnExit.SleepTime));
break;
}
}
}
}
else
{
System.Diagnostics.Trace.WriteLine(string.Format("RQAssemblies.StateEngine.Engine - ERROR STATE ({0}) NOT FOUND", currentStateNumber));
exitThread = true;
}
}
}
while (exitThread == false);
}
/// <summary>
/// finds a state based on its number
/// </summary>
/// <param name="stateNumber">the state number to find</param>
/// <returns></returns>
private State Find(long stateNumber)
{
foreach(State state in stateList)
{
if(state.StateNumber == stateNumber)
{
return state;
}
}
return null;
}
#endregion Private methods
#endregion Threading
#region Collection
// Throw an Exception if object is not an Exception
private void ValidateType(object O)
{
if (O.GetType() != typeof(State))
{
throw new ArgumentException("Value must be of type State");
}
}
public State this[int Index]
{
get
{
return (State)stateList[Index];
}
set
{
// Cannot be null
if (value == null)
{
throw new ArgumentNullException();
}
stateList[Index] = value;
}
}
#region IList methods
object System.Collections.IList.this[int Index]
{
get
{
return this[Index];
}
set
{
ValidateType(value);
stateList[Index] = value as State;
}
}
public bool Contains(object value)
{
ValidateType(value);
return stateList.Contains(value);
}
public void Clear()
{
stateList.Clear();
}
public int Add(object value)
{
ValidateType(value);
return stateList.Add(value);
}
public void RemoveAt(int index)
{
stateList.RemoveAt(index);
}
public void Remove(object value)
{
stateList.Remove(value);
}
bool System.Collections.IList.IsReadOnly
{
get
{
return false;
}
}
public bool IsFixedSize
{
get
{
return false;
}
}
public void Insert(int index, object value)
{
stateList.Insert(index, value);
}
public int IndexOf(object value)
{
ValidateType(value);
return stateList.IndexOf(value);
}
#endregion IList methods
#region IEnumerator methods
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return stateList.GetEnumerator();
}
public object SyncRoot
{
get
{
return stateList.SyncRoot;
}
}
public bool IsSynchronized
{
get
{
return stateList.IsSynchronized;
}
}
public int Count
{
get
{
return stateList.Count;
}
}
public void CopyTo(System.Array array, int index)
{
stateList.CopyTo(array, index);
}
#endregion IEnumerator methods
#endregion Collection
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.