using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using RealTimeGraphX.EventArguments;
namespace RealTimeGraphX
{
///
/// Represents an base class.
///
/// The type of the graph data series.
/// The type of the x-axis data point.
/// The type of the y-axis data point.
///
///
public abstract class GraphControllerBase :
GraphOutputComponentBase>,
IGraphController
where XDataPoint : GraphDataPointBase
where YDataPoint : GraphDataPointBase
where TDataSeries : IGraphDataSeries
{
#region Events
///
/// Occurs when one of the properties was modified.
///
public event EventHandler> RangeChanged;
///
/// Occurs when one of the properties was modified.
///
event EventHandler IGraphController.RangeChanged
{
add
{
RangeChanged += new EventHandler>((sender, range) => { value.Invoke(sender, Range); });
}
remove
{
RangeChanged -= new EventHandler>((sender, range) => { value.Invoke(sender, Range); });
}
}
///
/// Occurs when the connected has changed.
///
event EventHandler>> IGraphOutputComponent>.OutputChanged
{
add
{
OutputChanged += new EventHandler>>((sender, output) => { value.Invoke(sender, new OutputChangedEventArgs>(output.Output)); });
}
remove
{
OutputChanged -= new EventHandler>>((sender, output) => { value.Invoke(sender, new OutputChangedEventArgs>(output.Output)); });
}
}
#endregion
#region Properties
///
/// Gets the data series collection.
///
public ReadOnlyObservableCollection DataSeriesCollection { get; private set; }
///
/// Gets the graph range (limits).
///
public GraphRange Range { get; private set; }
///
/// Gets the graph range (limits).
///
IGraphRange IGraphController.Range
{
get
{
return Range;
}
}
///
/// Gets the connected output .
///
IGraphRenderer IGraphOutputComponent>.Output
{
get
{
return Output;
}
}
private bool _isPaused;
///
/// Gets or sets a value indicating whether to pause the graph movement.
///
public bool IsPaused
{
get { return _isPaused; }
set
{
_isPaused = value; RaisePropertyChangedAuto();
if (Output != null)
{
Output.IsPaused = value;
}
}
}
#endregion
#region Constructors
///
/// Initializes a new instance of the class.
///
public GraphControllerBase()
{
DataSeriesCollection = new ReadOnlyObservableCollection(new ObservableCollection());
Range = new GraphRange();
Range.PropertyChanged += (x, e) => OnRangeChanged();
}
#endregion
#region Public Methods
///
/// Clears the graph data.
///
public void Clear()
{
if (Output != null)
{
Output.Clear();
}
}
///
/// Submits a matrix of x and y data points. Meaning each data series should process a single collection of x/y data points.
///
/// X matrix.
/// Y matrix.
public void PushData(IEnumerable> xxxx, IEnumerable> yyyy)
{
if (DataSeriesCollection.Count == 0) return;
Output.Render(DataSeriesCollection, xxxx, yyyy);
}
///
/// Submits the specified collections of x and y data points.
/// If the controller has more than one data series the data points will be distributed evenly.
///
/// X data point collection.
/// Y data point collection.
public void PushData(IEnumerable xx, IEnumerable yy)
{
if (DataSeriesCollection.Count == 0) return;
var xList = xx.ToList();
var yList = yy.ToList();
List> xxList = new List>();
List> yyList = new List>();
foreach (var series in DataSeriesCollection.ToList())
{
xxList.Add(new List());
yyList.Add(new List());
}
int counter = 0;
for (int i = 0; i < xList.Count; i++)
{
xxList[counter].Add(xList[i]);
yyList[counter].Add(yList[i]);
counter++;
if (counter >= xxList.Count)
{
counter = 0;
}
}
Output.Render(DataSeriesCollection, xxList, yyList);
}
///
/// Submits the specified x and y data points the controller.
/// If the controller has more than one data series the data points will be duplicated.
///
/// X data point.
/// Y data point.
public void PushData(XDataPoint x, YDataPoint y)
{
if (DataSeriesCollection.Count == 0) return;
List> xxList = new List>();
List> yyList = new List>();
foreach (var series in DataSeriesCollection.ToList())
{
xxList.Add(new List() { x });
yyList.Add(new List() { y });
}
Output.Render(DataSeriesCollection, xxList, yyList);
}
///
/// Adds a new data series.
///
/// The series.
public void AddDataSeries(TDataSeries series)
{
var current_collection = DataSeriesCollection.ToList();
current_collection.Add(series);
DataSeriesCollection = new ReadOnlyObservableCollection(new ObservableCollection(current_collection));
}
///
/// Removed the specified data series
///
/// The series.
public void RemoveDataSeries(TDataSeries series)
{
var current_collection = DataSeriesCollection.ToList();
current_collection.Remove(series);
DataSeriesCollection = new ReadOnlyObservableCollection(new ObservableCollection(current_collection));
}
///
/// Connects this controller to the specified .
///
/// The renderer.
/// Specifies whether this call was made from an component.
public override void ConnectOutput(IGraphRenderer renderer, bool fromOutput = false)
{
renderer.ThrowIfNull("Cannot connect a null renderer.");
Output = renderer;
if (!fromOutput)
{
Output.ConnectInput(this, true);
}
}
///
/// Disconnects this component from the connected .
///
/// Specifies whether this call was made from an component.
public override void DisconnectOutput(bool fromOutput = false)
{
if (Output != null)
{
if (!fromOutput)
{
(Output as IGraphInputComponent>).DisconnectInput(true);
}
Output = null;
}
}
///
/// Connects this controller to the specified .
///
/// The renderer.
/// Specifies whether this call was made from the output .
void IGraphOutputComponent>.ConnectOutput(IGraphRenderer renderer, bool fromOutput)
{
ConnectOutput(renderer as IGraphRenderer);
}
///
/// Disconnects the current connected output .
///
/// Specifies whether this call was made from the output .
void IGraphOutputComponent>.DisconnectOutput(bool fromOutput)
{
DisconnectOutput();
}
#endregion
#region Protected Methods
///
/// Raises the event.
///
protected virtual void OnRangeChanged()
{
RangeChanged?.Invoke(this, Range);
}
#endregion
}
}