using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace csharp_sccd_compiler
{
public class StateChart : Visitable
{
///
/// The total number of transitions present in this statechart that are trigger by time (AFTER).
///
public int nr_of_after_transitions { get; private set; }
///
/// Root node of the statechart.
///
public StateChartNode root { get; private set; }
///
/// All basic states.
///
public List basics { get; private set; }
///
/// All composite states.
///
public List composites { get; private set; }
///
/// All history states.
///
public List histories { get; private set; }
///
/// All nodes that need their state saved shallow.
///
public List shallow_history_parents { get; private set; }
///
/// All nodes that need their state saved deep.
///
public List deep_history_parents { get; private set; }
///
/// All nodes that need their state saved on leaving
///
public List combined_history_parents { get; private set; }
public StateChart(XElement xml)
{
this.root = new StateChartNode(xml);
this.nr_of_after_transitions = 0;
this.basics = new List();
this.composites = new List();
this.histories = new List();
this.extractFromHierarchy(this.root);
this.shallow_history_parents = new List();
this.deep_history_parents = new List();
this.combined_history_parents = new List();
foreach (StateChartNode node in this.histories)
{
this.calculateHistory(node.parent, node.is_history_deep);
}
}
///
/// Calculates which nodes need their state saved for history purposes.
///
/// The parent node of a history state.
/// If set to true the history type is deep.
private void calculateHistory(StateChartNode parent, bool is_history_deep)
{
if (object.ReferenceEquals(parent, this.root)) //TODO use is_root property?
throw new CompilerException("Root component cannot contain a history state.");
if (!this.combined_history_parents.Contains(parent))
{
this.combined_history_parents.Add(parent);
parent.save_state_on_exit = true;
}
if (is_history_deep)
{
if (! this.deep_history_parents.Contains(parent))
this.deep_history_parents.Add(parent);
}
else
{
if (! this.shallow_history_parents.Contains(parent))
this.shallow_history_parents.Add(parent);
}
if ( parent.is_parallel || is_history_deep)
{
foreach (StateChartNode child in parent.children)
if (child.is_composite)
this.calculateHistory(child, is_history_deep);
}
}
private void extractFromHierarchy(StateChartNode node)
{
foreach (StateChartTransition transition in node.transitions)
{
TriggerEvent trigger = transition.trigger;
if (trigger.is_after)
{
trigger.after_index = this.nr_of_after_transitions;
string event_name = string.Format("_{0}after", trigger.after_index);
trigger.event_name = event_name;
this.nr_of_after_transitions += 1;
}
}
if (node.is_basic)
this.basics.Add(node);
else if (node.is_composite)
this.composites.Add(node);
else if (node.is_history)
this.histories.Add(node);
foreach (StateChartNode child in node.children)
this.extractFromHierarchy(child);
}
public override void accept(Visitor visitor)
{
visitor.visit (this);
}
}
}