2023-01-18 14:22:51 +01:00
|
|
|
using System;
|
2021-05-13 20:03:07 +02:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
using System.Linq;
|
2022-08-30 15:42:25 +02:00
|
|
|
using Serilog;
|
2023-08-31 12:20:06 +02:00
|
|
|
using TINK.Model.Connector;
|
2023-04-19 12:14:14 +02:00
|
|
|
using TINK.Model.Stations.StationNS;
|
2023-08-31 12:20:06 +02:00
|
|
|
using TINK.Services.BluetoothLock;
|
|
|
|
using TINK.Services.Geolocation;
|
|
|
|
using TINK.ViewModel;
|
2022-08-30 15:42:25 +02:00
|
|
|
using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
|
|
|
|
using BikeInfoMutable = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfoMutable;
|
2021-05-13 20:03:07 +02:00
|
|
|
|
2022-08-30 15:42:25 +02:00
|
|
|
namespace TINK.Model.Bikes
|
2021-05-13 20:03:07 +02:00
|
|
|
{
|
2022-09-06 16:08:19 +02:00
|
|
|
/// <summary> Holds entity of bikes. </summary>
|
|
|
|
public class BikeCollectionMutable : ObservableCollection<BikeInfoMutable>, IBikeDictionaryMutable<BikeInfoMutable>
|
|
|
|
{
|
2023-08-31 12:20:06 +02:00
|
|
|
/// <summary> Provides a connector object.</summary>
|
|
|
|
private Func<bool, IConnector> ConnectorFactory { get; }
|
|
|
|
|
|
|
|
/// <summary> Provides geolocation information.</summary>
|
|
|
|
private IGeolocationService GeolocationService { get; }
|
|
|
|
|
|
|
|
/// <summary> Provides a connector object.</summary>
|
|
|
|
private ILocksService LockService { get; }
|
|
|
|
|
|
|
|
/// <summary> Delegate to retrieve connected state. </summary>
|
|
|
|
private Func<bool> IsConnectedDelegate { get; }
|
|
|
|
|
|
|
|
/// <summary>Object to manage update of view model objects from Copri.</summary>
|
|
|
|
protected Func<IPollingUpdateTaskManager> ViewUpdateManager { get; }
|
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
/// <summary> Constructs a mutable bike collection object. </summary>
|
2023-08-31 12:20:06 +02:00
|
|
|
/// <param name="geolocation">Provides geolocation information.</param>
|
|
|
|
/// <param name="lockService">Manages lock.</param>
|
|
|
|
/// <param name="isConnectedDelegate">Delegate to retrieve connected state.</param>
|
|
|
|
/// <param name="connectorFactory">Provides a connector object.</param>
|
|
|
|
public BikeCollectionMutable(
|
|
|
|
IGeolocationService geolocation,
|
|
|
|
ILocksService lockService,
|
|
|
|
Func<bool> isConnectedDelegate,
|
|
|
|
Func<bool, IConnector> connectorFactory,
|
|
|
|
Func<IPollingUpdateTaskManager> viewUpdateManager)
|
2022-09-06 16:08:19 +02:00
|
|
|
{
|
|
|
|
SelectedBike = null;
|
2023-08-31 12:20:06 +02:00
|
|
|
|
|
|
|
GeolocationService = geolocation
|
|
|
|
?? throw new ArgumentException($"Can not instantiate {nameof(BikeCollectionMutable)}- object. No geolocation object available.");
|
|
|
|
|
|
|
|
LockService = lockService
|
|
|
|
?? throw new ArgumentException($"Can not instantiate {nameof(BikeCollectionMutable)}- object. No lock service object available.");
|
|
|
|
|
|
|
|
IsConnectedDelegate = isConnectedDelegate
|
|
|
|
?? throw new ArgumentException($"Can not instantiate {nameof(BikeCollectionMutable)}- object. No is connected delegate available.");
|
|
|
|
|
|
|
|
ConnectorFactory = connectorFactory
|
|
|
|
?? throw new ArgumentException($"Can not instantiate {nameof(BikeCollectionMutable)}- object. No connector available.");
|
|
|
|
|
|
|
|
ViewUpdateManager = viewUpdateManager
|
|
|
|
?? throw new ArgumentException($"Can not instantiate {nameof(BikeCollectionMutable)}- object. No view update manager available.");
|
2022-09-06 16:08:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Updates bikes dictionary from bikes response, i.e.
|
|
|
|
/// - removes bikes which are no more contained in bikes response
|
|
|
|
/// - updates state of all bikes from state contained in bikes response
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="bikesAll"> Object holding bikes info from copri to update from. Holds station id but not station name.</param>
|
|
|
|
/// <param name="stations"> All stations to get station names from.</param>
|
2023-04-19 12:14:14 +02:00
|
|
|
/// <param name="p_oDateTimeProvider">Provides date time information.</param>
|
2023-01-18 14:22:51 +01:00
|
|
|
public void Update(
|
|
|
|
IEnumerable<BikeInfo> bikesAll,
|
2022-09-06 16:08:19 +02:00
|
|
|
IEnumerable<IStation> stations)
|
|
|
|
{
|
|
|
|
// Get list of current bikes by state(s) to update.
|
|
|
|
// Needed to remove bikes which switched state and have to be removed from collection.
|
|
|
|
var bikesToBeRemoved = this.Select(x => x.Id).ToList();
|
|
|
|
|
|
|
|
foreach (var bikeInfo in bikesAll ?? new List<BikeInfo>())
|
|
|
|
{
|
|
|
|
// Get name of station form station id.
|
|
|
|
var stationName = stations?.FirstOrDefault(x => x.Id == bikeInfo.StationId)?.StationName ?? string.Empty;
|
|
|
|
if (string.IsNullOrEmpty(stationName))
|
|
|
|
Log.ForContext<BikeCollectionMutable>().Debug($"No name for station with id {bikeInfo.StationId} found.");
|
|
|
|
|
|
|
|
// Check if bike has to be added to list of existing station.
|
|
|
|
if (ContainsKey(bikeInfo.Id) == false)
|
|
|
|
{
|
2023-08-31 12:20:06 +02:00
|
|
|
var bikeInfoMutable = BikeInfoMutableFactory.Create(
|
|
|
|
GeolocationService,
|
|
|
|
LockService,
|
|
|
|
IsConnectedDelegate,
|
|
|
|
ConnectorFactory,
|
|
|
|
ViewUpdateManager,
|
|
|
|
bikeInfo,
|
|
|
|
stationName);
|
2022-09-06 16:08:19 +02:00
|
|
|
if (bikeInfoMutable != null)
|
|
|
|
{
|
|
|
|
// Bike does not yet exist in list of bikes.
|
|
|
|
Add(bikeInfoMutable);
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update bike.
|
2023-01-18 14:22:51 +01:00
|
|
|
var updateTarget = GetById(bikeInfo.Id);
|
|
|
|
updateTarget.State.Load(bikeInfo.State);
|
|
|
|
updateTarget.DataSource = bikeInfo.DataSource;
|
2022-09-06 16:08:19 +02:00
|
|
|
|
|
|
|
if (bikesToBeRemoved.Contains<string>(bikeInfo.Id))
|
|
|
|
{
|
|
|
|
// Remove list from obsolete list.
|
|
|
|
bikesToBeRemoved.Remove(bikeInfo.Id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove obsolete bikes.
|
|
|
|
foreach (var stationId in bikesToBeRemoved)
|
|
|
|
{
|
|
|
|
RemoveById(stationId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
2023-04-19 12:14:14 +02:00
|
|
|
/// Adds a new bike to collection of bike.
|
2022-09-06 16:08:19 +02:00
|
|
|
/// </summary>
|
|
|
|
/// <param name="newBike">New bike to add.</param>
|
|
|
|
/// <exception cref="Exception">Thrown if bike is not unique.</exception>
|
|
|
|
public new void Add(BikeInfoMutable newBike)
|
|
|
|
{
|
2023-04-19 12:14:14 +02:00
|
|
|
// Ensure that bike id of new bike is unique
|
2022-09-06 16:08:19 +02:00
|
|
|
foreach (BikeInfoMutable bike in Items)
|
|
|
|
{
|
|
|
|
if (bike.Id == newBike.Id)
|
|
|
|
{
|
2023-04-19 12:14:14 +02:00
|
|
|
throw new Exception(string.Format("Can not add bike with {0} to collection ob bike. Id is not unique.", newBike));
|
2022-09-06 16:08:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
base.Add(newBike);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
2023-04-19 12:14:14 +02:00
|
|
|
/// Bike selected by user for reserving or cancel reservation.
|
2022-09-06 16:08:19 +02:00
|
|
|
/// </summary>
|
|
|
|
public BikeInfoMutable SelectedBike
|
|
|
|
{
|
|
|
|
get;
|
|
|
|
private set;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetSelectedBike(string id)
|
|
|
|
{
|
|
|
|
SelectedBike = GetById(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets a bike by its id.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="id"></param>
|
|
|
|
/// <returns></returns>
|
|
|
|
public BikeInfoMutable GetById(string id)
|
2023-01-18 14:22:51 +01:00
|
|
|
=> this.FirstOrDefault(bike => bike.Id == id);
|
2022-09-06 16:08:19 +02:00
|
|
|
|
|
|
|
/// <summary>
|
2023-04-19 12:14:14 +02:00
|
|
|
/// Determines whether a bike by given key exists.
|
2022-09-06 16:08:19 +02:00
|
|
|
/// </summary>
|
|
|
|
/// <param name="p_strKey">Key to check.</param>
|
|
|
|
/// <returns>True if bike exists.</returns>
|
|
|
|
public bool ContainsKey(string id)
|
2023-01-18 14:22:51 +01:00
|
|
|
=> GetById(id) != null;
|
2022-09-06 16:08:19 +02:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Removes a bike by its id.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="id">Id of bike to be removed.</param>
|
|
|
|
public void RemoveById(string id)
|
|
|
|
{
|
|
|
|
var l_oBike = GetById(id);
|
|
|
|
if (l_oBike == null)
|
|
|
|
{
|
|
|
|
// Nothing to do if bike does not exists.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Remove(l_oBike);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Create mutable objects from immutable objects.
|
|
|
|
/// </summary>
|
|
|
|
public static class BikeInfoMutableFactory
|
|
|
|
{
|
2023-08-31 12:20:06 +02:00
|
|
|
/// <param name="viewUpdateManager">Manages update of view model objects from Copri.</param>
|
2022-09-06 16:08:19 +02:00
|
|
|
public static BikeInfoMutable Create(
|
2023-08-31 12:20:06 +02:00
|
|
|
IGeolocationService geolocation,
|
|
|
|
ILocksService lockService,
|
|
|
|
Func<bool> isConnectedDelegate,
|
|
|
|
Func<bool, IConnector> connectorFactory,
|
|
|
|
Func<IPollingUpdateTaskManager> viewUpdateManager,
|
2022-09-06 16:08:19 +02:00
|
|
|
BikeInfo bikeInfo,
|
|
|
|
string stationName)
|
|
|
|
{
|
2023-01-18 14:22:51 +01:00
|
|
|
if (bikeInfo is BikeInfoNS.BluetoothLock.BikeInfo btBikeInfo)
|
2022-09-06 16:08:19 +02:00
|
|
|
{
|
2023-08-31 12:20:06 +02:00
|
|
|
return new BikeInfoNS.BluetoothLock.BikeInfoMutable(
|
|
|
|
geolocation,
|
|
|
|
lockService,
|
|
|
|
isConnectedDelegate,
|
|
|
|
connectorFactory,
|
|
|
|
viewUpdateManager,
|
|
|
|
btBikeInfo,
|
|
|
|
stationName);
|
2022-09-06 16:08:19 +02:00
|
|
|
}
|
|
|
|
else if (bikeInfo is BikeInfoNS.CopriLock.BikeInfo copriBikeInfo)
|
|
|
|
{
|
|
|
|
return new BikeInfoNS.CopriLock.BikeInfoMutable(copriBikeInfo, stationName);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unsupported type detected.
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-05-13 20:03:07 +02:00
|
|
|
}
|