using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using Tango.Core;
using Tango.Logging;
namespace Tango.Transport
{
///
/// Represents an base class.
///
///
public abstract class TransportAdapterBase : ExtendedObject, ITransportAdapter
{
protected long _totalBytes;
private long _transferRateTotalBytes;
private Timer _transferRateTimer;
protected const int MAX_BUFFER_SIZE = 1024; //10 MB.
#region Events
///
/// Occurs when component state changes.
///
public event EventHandler StateChanged;
///
/// Occurs when new data is available.
///
public event EventHandler DataAvailable;
#endregion
#region Properties
private long _totalBytesReceived;
///
/// Gets the total bytes received.
///
public long TotalBytesReceived
{
get { return _totalBytesReceived; }
protected set { _totalBytesReceived = value; RaisePropertyChanged(nameof(TotalBytesReceived)); }
}
private long _totalBytesSent;
///
/// Gets the total bytes sent.
///
public long TotalBytesSent
{
get { return _totalBytesSent; }
protected set { _totalBytesSent = value; RaisePropertyChanged(nameof(TotalBytesSent)); }
}
private long _transferRate;
///
/// Gets the adapter current transfer rate.
///
public long TransferRate
{
get
{
return _transferRate;
}
protected set { _transferRate = value; RaisePropertyChanged(nameof(TransferRate)); }
}
///
/// Gets or sets the channel address.
///
public String Address { get; set; }
private TransportComponentState _state;
///
/// Gets the component state.
///
public TransportComponentState State
{
get { return _state; }
protected set
{
_state = value;
OnStateChanged(_state);
}
}
#endregion
#region Virtual Methods
///
/// Called when the adapter has failed.
///
/// The ex.
protected virtual void OnFailed(Exception ex)
{
Disconnect().Wait();
State = TransportComponentState.Failed;
LogManager.Log(ex, "Adapter failed.");
}
///
/// Called when there is new data available.
///
/// The data.
protected virtual void OnDataAvailable(byte[] data)
{
TotalBytesReceived += data.Length;
_totalBytes += data.Length;
AppendTransferRateBytes(data.Length);
DataAvailable?.Invoke(this, data);
}
///
/// Called when the adapter state has changed.
///
/// The state.
protected virtual void OnStateChanged(TransportComponentState state)
{
StateChanged?.Invoke(this, state);
if (state == TransportComponentState.Connected)
{
_totalBytes = 0;
TransferRate = 0;
if (_transferRateTimer != null)
{
_transferRateTimer.Stop();
_transferRateTimer.Dispose();
}
_transferRateTimer = new Timer(1000);
_transferRateTimer.Elapsed += _transferRateTimer_Elapsed;
_transferRateTimer.Start();
}
else
{
if (_transferRateTimer != null)
{
_transferRateTimer.Stop();
_transferRateTimer.Dispose();
}
}
}
///
/// Throws an exception if adapter is in a failed or disposed state.
///
protected virtual void ThrowIfDisposed()
{
if (State == TransportComponentState.Disposed)
{
throw LogManager.Log(new ObjectDisposedException("The adapter is in a " + State + " state."));
}
}
///
/// Applies any additional headers if required.
///
/// The data.
///
protected virtual byte[] PostProcessBuffer(byte[] data)
{
byte[] postData = data;
postData = BitConverter.GetBytes(data.Length).Concat(data).ToArray();
TotalBytesSent += postData.Length;
_totalBytes += postData.Length;
AppendTransferRateBytes(postData.Length);
return postData;
}
#endregion
#region Private Methods
private void AppendTransferRateBytes(long dataLength)
{
_transferRateTotalBytes += dataLength;
}
#endregion
#region Dispose
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
public virtual void Dispose()
{
Disconnect().Wait();
State = TransportComponentState.Disposed;
}
#endregion
#region Abstract Methods
///
/// Writes the specified data to the stream.
///
/// The data.
public abstract void Write(byte[] data);
///
/// Connects the transport component.
///
///
public abstract Task Connect();
///
/// Disconnects the transport component.
///
///
public abstract Task Disconnect();
#endregion
#region Override Methods
///
/// Returns a that represents this instance.
///
///
/// A that represents this instance.
///
public override string ToString()
{
return this.GetType().Name;
}
#endregion
#region Calculate Transfer Rate
private void _transferRateTimer_Elapsed(object sender, ElapsedEventArgs e)
{
TransferRate = _transferRateTotalBytes;
_transferRateTotalBytes = 0;
}
#endregion
}
}