sharee.bike-App/TINKLib/Model/State/StateInfoMutable.cs

298 lines
11 KiB
C#
Raw Normal View History

2021-05-13 20:03:07 +02:00
using System;
namespace TINK.Model.State
{
using System.ComponentModel;
using System.Runtime.Serialization;
/// <summary>
/// Manges the state of a bike.
/// </summary>
[DataContract]
public class StateInfoMutable : INotifyPropertyChanged, IStateInfoMutable
{
/// <summary>
/// Provider for current date time to calculate remainig time on demand for state of type reserved.
/// </summary>
2022-08-30 15:42:25 +02:00
private readonly Func<DateTime> _DateTimeNowProvider;
2021-05-13 20:03:07 +02:00
// Holds the current disposable state value
2022-08-30 15:42:25 +02:00
private StateInfo _StateInfo;
2021-05-13 20:03:07 +02:00
/// <summary>
/// Backs up remaining time of child object.
/// </summary>
2022-08-30 15:42:25 +02:00
private TimeSpan? _RemainingTime = null;
2021-05-13 20:03:07 +02:00
/// <summary> Notifies clients about state changes. </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Constructs a state object from source.
/// </summary>
2022-08-30 15:42:25 +02:00
/// <param name="state">State info to load from.</param>
2021-05-13 20:03:07 +02:00
public StateInfoMutable(
2022-08-30 15:42:25 +02:00
Func<DateTime> dateTimeNowProvider = null,
IStateInfo state = null)
2021-05-13 20:03:07 +02:00
{
// Back up date time provider to be able to pass this to requested- object if state changes to requested.
2022-08-30 15:42:25 +02:00
_DateTimeNowProvider = dateTimeNowProvider != null
? dateTimeNowProvider
2021-05-13 20:03:07 +02:00
: () => DateTime.Now;
2022-08-30 15:42:25 +02:00
_StateInfo = Create(state, dateTimeNowProvider);
2021-05-13 20:03:07 +02:00
}
/// <summary>
/// Loads state from immutable source.
/// </summary>
2022-08-30 15:42:25 +02:00
/// <param name="state">State to load from.</param>
public void Load(IStateInfo state)
2021-05-13 20:03:07 +02:00
{
2022-08-30 15:42:25 +02:00
if (state == null)
2021-05-13 20:03:07 +02:00
{
throw new ArgumentException("Can not load state info, object must not be null.");
}
// Back up last state value and remaining time value
// to be able to check whether an event has to be fired or not.
var l_oLastState = Value;
2022-08-30 15:42:25 +02:00
var l_oLastRemainingTime = _RemainingTime;
2021-05-13 20:03:07 +02:00
// Create new state info object from source.
2022-08-30 15:42:25 +02:00
_StateInfo = Create(state, _DateTimeNowProvider);
2021-05-13 20:03:07 +02:00
// Update remaining time value.
2022-08-30 15:42:25 +02:00
_StateInfo.GetIsStillReserved(out _RemainingTime);
2021-05-13 20:03:07 +02:00
2022-08-30 15:42:25 +02:00
if (l_oLastState == _StateInfo.Value
&& l_oLastRemainingTime == _RemainingTime)
2021-05-13 20:03:07 +02:00
{
return;
}
2022-08-30 15:42:25 +02:00
2021-05-13 20:03:07 +02:00
// State has changed, notify clients.
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(State)));
}
/// <summary>
/// Creates a state info object.
/// </summary>
2022-08-30 15:42:25 +02:00
/// <param name="state">State to load from.</param>
2021-05-13 20:03:07 +02:00
private static StateInfo Create(
2022-08-30 15:42:25 +02:00
IStateInfo state,
Func<DateTime> dateTimeNowProvider)
2021-05-13 20:03:07 +02:00
{
2022-08-30 15:42:25 +02:00
switch (state != null ? state.Value : InUseStateEnum.Disposable)
2021-05-13 20:03:07 +02:00
{
case InUseStateEnum.Disposable:
2022-08-30 15:42:25 +02:00
case InUseStateEnum.FeedbackPending:
return new StateInfo(state != null ? state.Value == InUseStateEnum.FeedbackPending : false);
2021-05-13 20:03:07 +02:00
case InUseStateEnum.Reserved:
// Todo: Handle p_oFrom == null here.
// Todo: Handle p_oDuration == null here.
return new StateInfo(
2022-08-30 15:42:25 +02:00
dateTimeNowProvider,
state.From.Value,
state.MailAddress,
state.Code);
2021-05-13 20:03:07 +02:00
case InUseStateEnum.Booked:
// Todo: Handle p_oFrom == null here.
// Todo: Clearify question: What to do if code changes form one value to another? This should never happen.
// Todo: Clearify question: What to do if from time changes form one value to another? This should never happen.
return new StateInfo(
2022-08-30 15:42:25 +02:00
state.From.Value,
state.MailAddress,
state.Code);
2021-05-13 20:03:07 +02:00
default:
// Todo: New state Busy has to be defined.
2022-08-30 15:42:25 +02:00
throw new Exception(string.Format("Can not create new state info object. Unknown state {0} detected.", state.Value));
2021-05-13 20:03:07 +02:00
}
}
/// <summary>
/// Gets the state value of object.
/// </summary>
public InUseStateEnum Value
2022-08-30 15:42:25 +02:00
=> _StateInfo.Value;
2021-05-13 20:03:07 +02:00
/// <summary>
/// Member for serialization purposes.
/// </summary>
[DataMember]
private BaseState StateInfoObject
{
2022-08-30 15:42:25 +02:00
get { return _StateInfo.StateInfoObject; }
2021-05-13 20:03:07 +02:00
set
{
var l_oStateOccupied = value as StateOccupiedInfo;
if (l_oStateOccupied != null)
{
2022-08-30 15:42:25 +02:00
_StateInfo = new StateInfo(l_oStateOccupied.From, l_oStateOccupied.MailAddress, l_oStateOccupied.Code);
2021-05-13 20:03:07 +02:00
return;
}
var l_oStateRequested = value as StateRequestedInfo;
if (l_oStateRequested != null)
{
2022-08-30 15:42:25 +02:00
_StateInfo = new StateInfo(_DateTimeNowProvider, l_oStateRequested.From, l_oStateRequested.MailAddress, l_oStateRequested.Code);
2021-05-13 20:03:07 +02:00
return;
}
2022-08-30 15:42:25 +02:00
_StateInfo = new StateInfo();
2021-05-13 20:03:07 +02:00
}
}
/// Transforms object to string.
/// </summary>
/// <returns></returns>
public new string ToString()
{
2022-08-30 15:42:25 +02:00
return _StateInfo.ToString();
2021-05-13 20:03:07 +02:00
}
/// <summary>
/// Checks and updates state if required.
/// </summary>
/// <returns>Value indicating wheter state has changed</returns>
public void UpdateOnTimeElapsed()
{
2022-08-30 15:42:25 +02:00
switch (_StateInfo.Value)
2021-05-13 20:03:07 +02:00
{
// State is disposable or booked. No need to update "OnTimeElapsed"
case InUseStateEnum.Disposable:
case InUseStateEnum.Booked:
return;
}
// Check if maximum reserved time has elapsed.
2022-08-30 15:42:25 +02:00
if (!_StateInfo.GetIsStillReserved(out _RemainingTime))
2021-05-13 20:03:07 +02:00
{
// Time has elapsed, switch state to disposable and notfiy client
2022-08-30 15:42:25 +02:00
_StateInfo = new StateInfo();
2021-05-13 20:03:07 +02:00
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(State)));
return;
}
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(RemainingTime)));
}
/// <summary> Updates state from webserver. </summary>
2022-08-30 15:42:25 +02:00
/// <param name="state">State of the bike.</param>
/// <param name="from">Date time when bike was reserved/ booked.</param>
/// <param name="mailAddress">Mailaddress of the one which reserved/ booked.</param>
/// <param name="code">Booking code if bike is booked or reserved.</param>
2021-05-13 20:03:07 +02:00
/// <param name="supressNotifyPropertyChanged">Controls whether notify property changed events are fired or not.</param>
public void Load(
2022-08-30 15:42:25 +02:00
InUseStateEnum state,
DateTime? from = null,
string mailAddress = null,
string code = null,
Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel notifyLevel = Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.All)
2021-05-13 20:03:07 +02:00
{
2022-08-30 15:42:25 +02:00
var lastState = _StateInfo.Value;
2021-05-13 20:03:07 +02:00
2022-08-30 15:42:25 +02:00
switch (state)
2021-05-13 20:03:07 +02:00
{
case InUseStateEnum.Disposable:
2022-08-30 15:42:25 +02:00
_StateInfo = new StateInfo();
2021-05-13 20:03:07 +02:00
// Set value to null. Otherwise potentially obsolete value will be taken remaining time.
2022-08-30 15:42:25 +02:00
_RemainingTime = null;
2021-05-13 20:03:07 +02:00
break;
case InUseStateEnum.Reserved:
// Todo: Handle p_oFrom == null here.
// Todo: Handle p_oDuration == null here.
2022-08-30 15:42:25 +02:00
_StateInfo = new StateInfo(
_DateTimeNowProvider,
from.Value,
mailAddress,
code);
2021-05-13 20:03:07 +02:00
// Set value to null. Otherwise potentially obsolete value will be taken remaining time.
2022-08-30 15:42:25 +02:00
_RemainingTime = null;
2021-05-13 20:03:07 +02:00
break;
case InUseStateEnum.Booked:
// Todo: Handle p_oFrom == null here.
// Todo: Clearify question: What to do if code changes form one value to another? This should never happen.
// Todo: Clearify question: What to do if from time changes form one value to another? This should never happen.
2022-08-30 15:42:25 +02:00
_StateInfo = new StateInfo(
from.Value,
mailAddress,
code);
2021-05-13 20:03:07 +02:00
// Set value to null. Otherwise potentially obsolete value will be taken remaining time.
2022-08-30 15:42:25 +02:00
_RemainingTime = null;
2021-05-13 20:03:07 +02:00
break;
default:
// Todo: New state Busy has to be defined.
break;
}
2022-08-30 15:42:25 +02:00
if (lastState != _StateInfo.Value
&& notifyLevel == Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.All)
2021-05-13 20:03:07 +02:00
{
// State has changed, notify clients.
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(State)));
}
}
/// <summary>
/// If bike is reserved time raimaining while bike stays reserved, null otherwise.
/// </summary>
public TimeSpan? RemainingTime
{
get
2022-08-30 15:42:25 +02:00
{
switch (_StateInfo.Value)
2021-05-13 20:03:07 +02:00
{
// State is either available or occupied.
case InUseStateEnum.Disposable:
case InUseStateEnum.Booked:
2022-08-30 15:42:25 +02:00
return null;
2021-05-13 20:03:07 +02:00
}
2022-08-30 15:42:25 +02:00
if (_RemainingTime.HasValue == false)
2021-05-13 20:03:07 +02:00
{
// Value was not yet querried.
// Do querry before returning object.
2022-08-30 15:42:25 +02:00
_StateInfo.GetIsStillReserved(out _RemainingTime);
2021-05-13 20:03:07 +02:00
}
2022-08-30 15:42:25 +02:00
return _RemainingTime;
2021-05-13 20:03:07 +02:00
}
}
public DateTime? From
{
get
{
2022-08-30 15:42:25 +02:00
return _StateInfo.From;
2021-05-13 20:03:07 +02:00
}
}
public string MailAddress
{
get
{
2022-08-30 15:42:25 +02:00
return _StateInfo.MailAddress;
2021-05-13 20:03:07 +02:00
}
}
public string Code
{
get
{
2022-08-30 15:42:25 +02:00
return _StateInfo.Code;
2021-05-13 20:03:07 +02:00
}
}
}
}