Version 3.0.338

This commit is contained in:
Anja Müller-Meißner 2022-09-06 16:08:19 +02:00 committed by Anja
parent 573fe77e12
commit 0468955d49
751 changed files with 62747 additions and 60672 deletions

View file

@ -11,177 +11,177 @@ using TINK.Repository.Response;
namespace TINK.Model.Connector
{
public class Command : Base, ICommand
{
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
public bool IsConnected => CopriServer.IsConnected;
public class Command : Base, ICommand
{
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
public bool IsConnected => CopriServer.IsConnected;
/// <summary> No user is logged in.</summary>
public string SessionCookie => null;
/// <summary> No user is logged in.</summary>
public string SessionCookie => null;
/// <summary> Is raised whenever login state has changed.</summary>
public event LoginStateChangedEventHandler LoginStateChanged;
/// <summary> Is raised whenever login state has changed.</summary>
public event LoginStateChangedEventHandler LoginStateChanged;
/// <summary>Constructs a copri query object.</summary>
/// <param name="p_oCopriServer">Server which implements communication.</param>
public Command(
ICopriServerBase p_oCopriServer) : base(p_oCopriServer)
{
}
/// <summary>Constructs a copri query object.</summary>
/// <param name="p_oCopriServer">Server which implements communication.</param>
public Command(
ICopriServerBase p_oCopriServer) : base(p_oCopriServer)
{
}
/// <summary>
/// Logs user in.
/// If log in succeeds either and session might be updated if it was no more valid (logged in by an different device).
/// If log in fails (password modified) session cookie is set to empty.
/// If communication fails an exception is thrown.
/// </summary>
public async Task<IAccount> DoLogin(
string mail,
string password,
string deviceId)
{
if (string.IsNullOrEmpty(mail))
{
throw new ArgumentNullException("Can not loging user. Mail address must not be null or empty.");
}
/// <summary>
/// Logs user in.
/// If log in succeeds either and session might be updated if it was no more valid (logged in by an different device).
/// If log in fails (password modified) session cookie is set to empty.
/// If communication fails an exception is thrown.
/// </summary>
public async Task<IAccount> DoLogin(
string mail,
string password,
string deviceId)
{
if (string.IsNullOrEmpty(mail))
{
throw new ArgumentNullException("Can not loging user. Mail address must not be null or empty.");
}
if (string.IsNullOrEmpty(password))
{
throw new ArgumentNullException("Can not loging user. Password must not be null or empty.");
}
if (string.IsNullOrEmpty(password))
{
throw new ArgumentNullException("Can not loging user. Password must not be null or empty.");
}
if (string.IsNullOrEmpty(deviceId))
{
throw new ArgumentNullException("Can not loging user. Device not be null or empty.");
}
if (string.IsNullOrEmpty(deviceId))
{
throw new ArgumentNullException("Can not loging user. Device not be null or empty.");
}
AuthorizationResponse response;
try
{
response = (await CopriServer.DoAuthorizationAsync(mail, password, deviceId)).GetIsResponseOk(mail);
}
catch (Exception)
{
throw;
}
AuthorizationResponse response;
try
{
response = (await CopriServer.DoAuthorizationAsync(mail, password, deviceId)).GetIsResponseOk(mail);
}
catch (Exception)
{
throw;
}
var l_oAccount = response.GetAccount(MerchantId, mail, password);
var l_oAccount = response.GetAccount(MerchantId, mail, password);
// Log in state changes. Notify parent object to update.
LoginStateChanged?.Invoke(this, new LoginStateChangedEventArgs(l_oAccount.SessionCookie, l_oAccount.Mail));
// Log in state changes. Notify parent object to update.
LoginStateChanged?.Invoke(this, new LoginStateChangedEventArgs(l_oAccount.SessionCookie, l_oAccount.Mail));
return l_oAccount;
}
return l_oAccount;
}
/// <summary> Logs user out. </summary>
public async Task DoLogout()
{
Log.ForContext<Command>().Error("Unexpected log out request detected. No user logged in.");
await Task.CompletedTask;
}
/// <summary> Logs user out. </summary>
public async Task DoLogout()
{
Log.ForContext<Command>().Error("Unexpected log out request detected. No user logged in.");
await Task.CompletedTask;
}
/// <summary>
/// Request to reserve a bike.
/// </summary>
/// <param name="bike">Bike to book.</param>
public async Task DoReserve(
Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
{
Log.ForContext<Command>().Error("Unexpected booking request detected. No user logged in.");
await Task.CompletedTask;
}
/// <summary>
/// Request to reserve a bike.
/// </summary>
/// <param name="bike">Bike to book.</param>
public async Task DoReserve(
Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
{
Log.ForContext<Command>().Error("Unexpected booking request detected. No user logged in.");
await Task.CompletedTask;
}
/// <summary> Request to cancel a reservation.</summary>
/// <param name="p_oBike">Bike to book.</param>
public async Task DoCancelReservation(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
{
Log.ForContext<Command>().Error("Unexpected cancel reservation request detected. No user logged in.");
await Task.CompletedTask;
}
/// <summary> Request to cancel a reservation.</summary>
/// <param name="p_oBike">Bike to book.</param>
public async Task DoCancelReservation(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
{
Log.ForContext<Command>().Error("Unexpected cancel reservation request detected. No user logged in.");
await Task.CompletedTask;
}
/// <summary> Get authentication keys.</summary>
/// <param name="bike">Bike to book.</param>
public async Task CalculateAuthKeys(Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable bike)
{
Log.ForContext<Command>().Error("Unexpected request to get authenticatin keys detected. No user logged in.");
await Task.CompletedTask;
}
/// <summary> Get authentication keys.</summary>
/// <param name="bike">Bike to book.</param>
public async Task CalculateAuthKeys(Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable bike)
{
Log.ForContext<Command>().Error("Unexpected request to get authenticatin keys detected. No user logged in.");
await Task.CompletedTask;
}
/// <summary> Updates COPRI lock state for a booked bike. </summary>
/// <param name="bike">Bike to update locking state for.</param>
/// <param name="location">Location where lock was opened/ changed.</param>
/// <returns>Response on updating locking state.</returns>
public async Task StartReturningBike(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
{
Log.ForContext<Command>().Error("Unexpected request to notify about start of returning bike. No user logged in.");
await Task.CompletedTask;
}
/// <summary> Updates COPRI lock state for a booked bike. </summary>
/// <param name="bike">Bike to update locking state for.</param>
/// <param name="location">Location where lock was opened/ changed.</param>
/// <returns>Response on updating locking state.</returns>
public async Task StartReturningBike(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
{
Log.ForContext<Command>().Error("Unexpected request to notify about start of returning bike. No user logged in.");
await Task.CompletedTask;
}
/// <summary> Notifies COPRI about start of returning sequence. </summary>
/// <remarks> Operator specific call.</remarks>
/// <param name="bike">Bike to return.</param>
/// <returns>Response on notification about start of returning sequence.</returns>
public async Task UpdateLockingStateAsync(Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable bike, LocationDto location)
{
Log.ForContext<Command>().Error("Unexpected request to update locking state detected. No user logged in.");
await Task.CompletedTask;
}
/// <summary> Notifies COPRI about start of returning sequence. </summary>
/// <remarks> Operator specific call.</remarks>
/// <param name="bike">Bike to return.</param>
/// <returns>Response on notification about start of returning sequence.</returns>
public async Task UpdateLockingStateAsync(Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable bike, LocationDto location)
{
Log.ForContext<Command>().Error("Unexpected request to update locking state detected. No user logged in.");
await Task.CompletedTask;
}
public async Task DoBook(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
{
Log.ForContext<Command>().Error("Unexpected booking request detected. No user logged in.");
await Task.CompletedTask;
}
public async Task DoBook(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
{
Log.ForContext<Command>().Error("Unexpected booking request detected. No user logged in.");
await Task.CompletedTask;
}
public async Task BookAndOpenAync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
{
Log.ForContext<Command>().Error("Unexpected request to book and open bike detected. No user logged in.");
await Task.CompletedTask;
}
public async Task BookAndOpenAync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
{
Log.ForContext<Command>().Error("Unexpected request to book and open bike detected. No user logged in.");
await Task.CompletedTask;
}
public async Task<BookingFinishedModel> DoReturn(
Bikes.BikeInfoNS.BC.IBikeInfoMutable bike,
LocationDto location,
ISmartDevice smartDevice)
{
Log.ForContext<Command>().Error("Unexpected returning request detected. No user logged in.");
return await Task.FromResult(new BookingFinishedModel());
}
public async Task<BookingFinishedModel> DoReturn(
Bikes.BikeInfoNS.BC.IBikeInfoMutable bike,
LocationDto location,
ISmartDevice smartDevice)
{
Log.ForContext<Command>().Error("Unexpected returning request detected. No user logged in.");
return await Task.FromResult(new BookingFinishedModel());
}
public async Task<BookingFinishedModel> ReturnAndCloseAsync(
Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike,
ISmartDevice smartDevice)
{
Log.ForContext<Command>().Error("Unexpected close lock and return request detected. No user logged in.");
return await Task.FromResult(new BookingFinishedModel());
}
public async Task<BookingFinishedModel> ReturnAndCloseAsync(
Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike,
ISmartDevice smartDevice)
{
Log.ForContext<Command>().Error("Unexpected close lock and return request detected. No user logged in.");
return await Task.FromResult(new BookingFinishedModel());
}
/// <summary>
/// Submits feedback to copri server.
/// </summary>
/// <param name="userFeedback">Feedback to submit.</param>
/// <summary>
/// Submits feedback to copri server.
/// </summary>
/// <param name="userFeedback">Feedback to submit.</param>
#if USCSHARP9
public async Task DoSubmitFeedback(ICommand.IUserFeedback userFeedback, Uri opertorUri)
#else
public async Task DoSubmitFeedback(IUserFeedback userFeedback, Uri opertorUri)
public async Task DoSubmitFeedback(IUserFeedback userFeedback, Uri opertorUri)
#endif
{
Log.ForContext<Command>().Error("Unexpected submit feedback request detected. No user logged in.");
await Task.CompletedTask;
}
{
Log.ForContext<Command>().Error("Unexpected submit feedback request detected. No user logged in.");
await Task.CompletedTask;
}
/// <summary> Submits mini survey to copri server. </summary>
/// <param name="answers">Collection of answers.</param>
public async Task DoSubmitMiniSurvey(IDictionary<string, string> answers)
{
Log.ForContext<Command>().Error("Unexpected submit mini survey request detected. No user logged in.");
await Task.CompletedTask;
}
/// <summary> Submits mini survey to copri server. </summary>
/// <param name="answers">Collection of answers.</param>
public async Task DoSubmitMiniSurvey(IDictionary<string, string> answers)
{
Log.ForContext<Command>().Error("Unexpected submit mini survey request detected. No user logged in.");
await Task.CompletedTask;
}
public Task OpenLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
=> throw new NotImplementedException();
public Task OpenLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
=> throw new NotImplementedException();
public Task CloseLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
=> throw new NotImplementedException();
}
public Task CloseLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
=> throw new NotImplementedException();
}
}

View file

@ -13,311 +13,311 @@ using TINK.Services.CopriApi;
namespace TINK.Model.Connector
{
public class CommandLoggedIn : BaseLoggedIn, ICommand
{
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
public bool IsConnected => CopriServer.IsConnected;
public class CommandLoggedIn : BaseLoggedIn, ICommand
{
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
public bool IsConnected => CopriServer.IsConnected;
/// <summary> Is raised whenever login state has changed.</summary>
public event LoginStateChangedEventHandler LoginStateChanged;
/// <summary> Is raised whenever login state has changed.</summary>
public event LoginStateChangedEventHandler LoginStateChanged;
/// <summary>Constructs a copri query object.</summary>
/// <param name="p_oCopriServer">Server which implements communication.</param>
public CommandLoggedIn(ICopriServerBase p_oCopriServer,
string sessionCookie,
string mail,
Func<DateTime> dateTimeProvider) : base(p_oCopriServer, sessionCookie, mail, dateTimeProvider)
{
}
/// <summary>Constructs a copri query object.</summary>
/// <param name="p_oCopriServer">Server which implements communication.</param>
public CommandLoggedIn(ICopriServerBase p_oCopriServer,
string sessionCookie,
string mail,
Func<DateTime> dateTimeProvider) : base(p_oCopriServer, sessionCookie, mail, dateTimeProvider)
{
}
/// <summary>
/// Logs user in.
/// If log in succeeds either and session might be updated if it was no more valid (logged in by an different device).
/// If log in fails (password modified) session cookie is set to empty.
/// If communication fails an TINK.Repository.Exception is thrown.
/// </summary>
/// <param name="p_oAccount">Account to use for login.</param>
public Task<IAccount> DoLogin(string mail, string password, string deviceId)
{
if (string.IsNullOrEmpty(mail))
{
throw new ArgumentNullException("Can not loging user. Mail address must not be null or empty.");
}
/// <summary>
/// Logs user in.
/// If log in succeeds either and session might be updated if it was no more valid (logged in by an different device).
/// If log in fails (password modified) session cookie is set to empty.
/// If communication fails an TINK.Repository.Exception is thrown.
/// </summary>
/// <param name="p_oAccount">Account to use for login.</param>
public Task<IAccount> DoLogin(string mail, string password, string deviceId)
{
if (string.IsNullOrEmpty(mail))
{
throw new ArgumentNullException("Can not loging user. Mail address must not be null or empty.");
}
throw new Exception($"Fehler beim Anmelden von unter {mail}. Benutzer {Mail} ist bereits angemeldet.");
}
throw new Exception($"Fehler beim Anmelden von unter {mail}. Benutzer {Mail} ist bereits angemeldet.");
}
/// <summary> Logs user out. </summary>
public async Task DoLogout()
{
AuthorizationoutResponse l_oResponse = null;
try
{
l_oResponse = (await CopriServer.DoAuthoutAsync()).GetIsResponseOk();
}
catch (AuthcookieNotDefinedException)
{
// Cookie is no more defined, i.e. no need to logout user at copri because user is already logged out.
// Just ignore this error.
// User logged out, log in state changed. Notify parent object to update.
LoginStateChanged?.Invoke(this, new LoginStateChangedEventArgs());
return;
}
catch (Exception)
{
throw;
}
/// <summary> Logs user out. </summary>
public async Task DoLogout()
{
AuthorizationoutResponse l_oResponse = null;
try
{
l_oResponse = (await CopriServer.DoAuthoutAsync()).GetIsResponseOk();
}
catch (AuthcookieNotDefinedException)
{
// Cookie is no more defined, i.e. no need to logout user at copri because user is already logged out.
// Just ignore this error.
// User logged out, log in state changed. Notify parent object to update.
LoginStateChanged?.Invoke(this, new LoginStateChangedEventArgs());
return;
}
catch (Exception)
{
throw;
}
// User logged out, log in state changed. Notify parent object to update.
LoginStateChanged?.Invoke(this, new LoginStateChangedEventArgs());
}
// User logged out, log in state changed. Notify parent object to update.
LoginStateChanged?.Invoke(this, new LoginStateChangedEventArgs());
}
/// <summary>
/// Request to reserve a bike.
/// </summary>
/// <param name="bike">Bike to book.</param>
public async Task DoReserve(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
{
if (bike == null)
{
throw new ArgumentNullException("Can not reserve bike. No bike object available.");
}
/// <summary>
/// Request to reserve a bike.
/// </summary>
/// <param name="bike">Bike to book.</param>
public async Task DoReserve(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
{
if (bike == null)
{
throw new ArgumentNullException("Can not reserve bike. No bike object available.");
}
BikeInfoReservedOrBooked response;
try
{
response = (await CopriServer.DoReserveAsync(bike.Id, bike.OperatorUri)).GetIsReserveResponseOk(bike.Id);
}
catch (Exception)
{
// Exception was not expected or too many subsequent excepitons detected.
throw;
}
BikeInfoReservedOrBooked response;
try
{
response = (await CopriServer.DoReserveAsync(bike.Id, bike.OperatorUri)).GetIsReserveResponseOk(bike.Id);
}
catch (Exception)
{
// Exception was not expected or too many subsequent excepitons detected.
throw;
}
bike.Load(response, Mail, Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None);
}
bike.Load(response, Mail, Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None);
}
/// <summary> Request to cancel a reservation.</summary>
/// <param name="bike">Bike to cancel reservation.</param>
public async Task DoCancelReservation(
Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
{
if (bike == null)
{
throw new ArgumentNullException("Can not cancel reservation of bike. No bike object available.");
}
/// <summary> Request to cancel a reservation.</summary>
/// <param name="bike">Bike to cancel reservation.</param>
public async Task DoCancelReservation(
Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
{
if (bike == null)
{
throw new ArgumentNullException("Can not cancel reservation of bike. No bike object available.");
}
ReservationCancelReturnResponse response;
try
{
response = (await CopriServer.DoCancelReservationAsync(bike.Id, bike.OperatorUri)).GetIsCancelReservationResponseOk(bike.Id);
}
catch (Exception)
{
// Exception was not expected or too many subsequent excepitons detected.
throw;
}
ReservationCancelReturnResponse response;
try
{
response = (await CopriServer.DoCancelReservationAsync(bike.Id, bike.OperatorUri)).GetIsCancelReservationResponseOk(bike.Id);
}
catch (Exception)
{
// Exception was not expected or too many subsequent excepitons detected.
throw;
}
bike.Load(Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None);
}
bike.Load(Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None);
}
/// <summary> Get authentication keys.</summary>
/// <param name="bike">Bike to get new keys for.</param>
public async Task CalculateAuthKeys(Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable bike)
{
if (bike == null)
{
throw new ArgumentNullException("Can not calculate auth keys. No bike object available.");
}
/// <summary> Get authentication keys.</summary>
/// <param name="bike">Bike to get new keys for.</param>
public async Task CalculateAuthKeys(Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable bike)
{
if (bike == null)
{
throw new ArgumentNullException("Can not calculate auth keys. No bike object available.");
}
switch (bike.State.Value)
{
case State.InUseStateEnum.Reserved:
case State.InUseStateEnum.Booked:
break;
switch (bike.State.Value)
{
case State.InUseStateEnum.Reserved:
case State.InUseStateEnum.Booked:
break;
default:
throw new ArgumentNullException($"Can not calculate auth keys. Unexpected bike state {bike.State.Value} detected.");
}
default:
throw new ArgumentNullException($"Can not calculate auth keys. Unexpected bike state {bike.State.Value} detected.");
}
BikeInfoReservedOrBooked response;
Guid guid = (bike is BikeInfoMutable btBike) ? btBike.LockInfo.Guid : new Guid();
try
{
response = (await CopriServer.CalculateAuthKeysAsync(bike.Id, bike.OperatorUri)).GetIsBookingResponseOk(bike.Id);
}
catch (Exception)
{
// Exception was not expected or too many subsequent excepitons detected.
throw;
}
BikeInfoReservedOrBooked response;
Guid guid = (bike is BikeInfoMutable btBike) ? btBike.LockInfo.Guid : new Guid();
try
{
response = (await CopriServer.CalculateAuthKeysAsync(bike.Id, bike.OperatorUri)).GetIsBookingResponseOk(bike.Id);
}
catch (Exception)
{
// Exception was not expected or too many subsequent excepitons detected.
throw;
}
UpdaterJSON.Load(
bike,
response,
Mail,
Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None);
}
UpdaterJSON.Load(
bike,
response,
Mail,
Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None);
}
/// <summary> Notifies COPRI about start of returning sequence. </summary>
/// <remarks> Operator specific call.</remarks>
/// <param name="bike">Bike to return.</param>
/// <returns>Response on notification about start of returning sequence.</returns>
public async Task StartReturningBike(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
{
if (bike == null)
{
throw new ArgumentNullException("Can not notify about start returning bike. No bike object available.");
}
/// <summary> Notifies COPRI about start of returning sequence. </summary>
/// <remarks> Operator specific call.</remarks>
/// <param name="bike">Bike to return.</param>
/// <returns>Response on notification about start of returning sequence.</returns>
public async Task StartReturningBike(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
{
if (bike == null)
{
throw new ArgumentNullException("Can not notify about start returning bike. No bike object available.");
}
try
{
(await CopriServer.StartReturningBike(
bike.Id,
bike.OperatorUri)).GetIsResponseOk("Start returning bike");
}
catch (Exception)
{
// Exception was not expected or too many subsequent excepitons detected.
throw;
}
try
{
(await CopriServer.StartReturningBike(
bike.Id,
bike.OperatorUri)).GetIsResponseOk("Start returning bike");
}
catch (Exception)
{
// Exception was not expected or too many subsequent excepitons detected.
throw;
}
}
}
/// <summary> Updates COPRI lock state for a booked bike. </summary>
/// <param name="bike">Bike to update locking state for.</param>
/// <param name="location">Location of the bike.</param>
/// <returns>Response on updating locking state.</returns>
public async Task UpdateLockingStateAsync(
IBikeInfoMutable bike,
LocationDto location)
{
if (bike == null)
{
throw new ArgumentNullException("Can not update locking state of bike. No bike object available.");
}
/// <summary> Updates COPRI lock state for a booked bike. </summary>
/// <param name="bike">Bike to update locking state for.</param>
/// <param name="location">Location of the bike.</param>
/// <returns>Response on updating locking state.</returns>
public async Task UpdateLockingStateAsync(
IBikeInfoMutable bike,
LocationDto location)
{
if (bike == null)
{
throw new ArgumentNullException("Can not update locking state of bike. No bike object available.");
}
if (bike.State.Value != State.InUseStateEnum.Booked)
{
throw new ArgumentNullException($"Can not update locking state of bike. Unexpected booking state {bike.State} detected.");
}
if (bike.State.Value != State.InUseStateEnum.Booked)
{
throw new ArgumentNullException($"Can not update locking state of bike. Unexpected booking state {bike.State} detected.");
}
lock_state? state = null;
switch (bike.LockInfo.State)
{
case LockingState.Open:
state = lock_state.unlocked;
break;
lock_state? state = null;
switch (bike.LockInfo.State)
{
case LockingState.Open:
state = lock_state.unlocked;
break;
case LockingState.Closed:
state = lock_state.locked;
break;
}
case LockingState.Closed:
state = lock_state.locked;
break;
}
if (!state.HasValue)
{
throw new ArgumentNullException($"Can not update locking state of bike. Unexpected locking state {bike.LockInfo.State} detected.");
}
if (!state.HasValue)
{
throw new ArgumentNullException($"Can not update locking state of bike. Unexpected locking state {bike.LockInfo.State} detected.");
}
try
{
(await CopriServer.UpdateLockingStateAsync(
bike.Id,
state.Value,
bike.OperatorUri,
location,
bike.LockInfo.BatteryPercentage)).GetIsBookingResponseOk(bike.Id);
}
catch (Exception)
{
// Exception was not expected or too many subsequent excepitons detected.
throw;
}
}
try
{
(await CopriServer.UpdateLockingStateAsync(
bike.Id,
state.Value,
bike.OperatorUri,
location,
bike.LockInfo.BatteryPercentage)).GetIsBookingResponseOk(bike.Id);
}
catch (Exception)
{
// Exception was not expected or too many subsequent excepitons detected.
throw;
}
}
/// <summary> Request to book a bike. </summary>
/// <param name="bike">Bike to book.</param>
public async Task DoBook(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
{
if (bike == null)
{
throw new ArgumentNullException(nameof(bike), "Can not book bike. No bike object available.");
}
/// <summary> Request to book a bike. </summary>
/// <param name="bike">Bike to book.</param>
public async Task DoBook(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike)
{
if (bike == null)
{
throw new ArgumentNullException(nameof(bike), "Can not book bike. No bike object available.");
}
BikeInfoReservedOrBooked response;
var btBike = bike as BikeInfoMutable;
Guid guid = btBike != null ? btBike.LockInfo.Guid : new Guid();
double batteryPercentage = btBike != null ? btBike.LockInfo.BatteryPercentage : double.NaN;
BikeInfoReservedOrBooked response;
var btBike = bike as BikeInfoMutable;
Guid guid = btBike != null ? btBike.LockInfo.Guid : new Guid();
double batteryPercentage = btBike != null ? btBike.LockInfo.BatteryPercentage : double.NaN;
response = (await CopriServer.DoBookAsync(
bike.Id,
guid,
batteryPercentage,
bike.OperatorUri)).GetIsBookingResponseOk(bike.Id);
response = (await CopriServer.DoBookAsync(
bike.Id,
guid,
batteryPercentage,
bike.OperatorUri)).GetIsBookingResponseOk(bike.Id);
bike.Load(
response,
Mail,
Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None);
}
bike.Load(
response,
Mail,
Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None);
}
/// <summary>
/// Books a bike and opens the lock.
/// </summary>
/// <param name="bike">Bike to book and open.</param>
public async Task BookAndOpenAync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
=> await Polling.BookAndOpenAync(CopriServer, bike, Mail);
/// <summary>
/// Books a bike and opens the lock.
/// </summary>
/// <param name="bike">Bike to book and open.</param>
public async Task BookAndOpenAync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
=> await Polling.BookAndOpenAync(CopriServer, bike, Mail);
/// <summary> Request to return a bike.</summary>
/// <param name="bike">Bike to return.</param>
/// <param name="locaton">Position of the bike for bluetooth locks.</param>
/// <param name="smartDevice">Provides info about hard and software.</param>
public async Task<BookingFinishedModel> DoReturn(
Bikes.BikeInfoNS.BC.IBikeInfoMutable bike,
LocationDto location = null,
ISmartDevice smartDevice = null)
{
if (bike == null)
{
throw new ArgumentNullException("Can not return bike. No bike object available.");
}
/// <summary> Request to return a bike.</summary>
/// <param name="bike">Bike to return.</param>
/// <param name="locaton">Position of the bike for bluetooth locks.</param>
/// <param name="smartDevice">Provides info about hard and software.</param>
public async Task<BookingFinishedModel> DoReturn(
Bikes.BikeInfoNS.BC.IBikeInfoMutable bike,
LocationDto location = null,
ISmartDevice smartDevice = null)
{
if (bike == null)
{
throw new ArgumentNullException("Can not return bike. No bike object available.");
}
DoReturnResponse response
= (await CopriServer.DoReturn(bike.Id, location, smartDevice, bike.OperatorUri)).GetIsReturnBikeResponseOk(bike.Id);
DoReturnResponse response
= (await CopriServer.DoReturn(bike.Id, location, smartDevice, bike.OperatorUri)).GetIsReturnBikeResponseOk(bike.Id);
bike.Load(Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None);
return response?.Create() ?? new BookingFinishedModel();
}
bike.Load(Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None);
return response?.Create() ?? new BookingFinishedModel();
}
/// <summary> Request to return bike and close the lock.</summary>
/// <param name="bike">Bike to return.</param>
/// <param name="smartDevice">Provides info about hard and software.</param>
public async Task<BookingFinishedModel> ReturnAndCloseAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike, ISmartDevice smartDevice = null)
=> await Polling.ReturnAndCloseAync(CopriServer, smartDevice, bike);
/// <summary> Request to return bike and close the lock.</summary>
/// <param name="bike">Bike to return.</param>
/// <param name="smartDevice">Provides info about hard and software.</param>
public async Task<BookingFinishedModel> ReturnAndCloseAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike, ISmartDevice smartDevice = null)
=> await Polling.ReturnAndCloseAync(CopriServer, smartDevice, bike);
/// <summary>
/// Submits feedback to copri server.
/// </summary>
/// <param name="userFeedback">Feedback to submit.</param>
/// <summary>
/// Submits feedback to copri server.
/// </summary>
/// <param name="userFeedback">Feedback to submit.</param>
#if USCSHARP9
public async Task DoSubmitFeedback(ICommand.IUserFeedback userFeedback, Uri opertorUri)
=> await CopriServer.DoSubmitFeedback(userFeedback.BikeId, userFeedback.Message, userFeedback.IsBikeBroken, opertorUri);
#else
/// <summary> Submits feedback for a renting operation.</summary>
public async Task DoSubmitFeedback(
IUserFeedback userFeedback,
Uri opertorUri)
=> await CopriServer.DoSubmitFeedback(userFeedback.BikeId, userFeedback.CurrentChargeBars, userFeedback.Message, userFeedback.IsBikeBroken, opertorUri);
/// <summary> Submits feedback for a renting operation.</summary>
public async Task DoSubmitFeedback(
IUserFeedback userFeedback,
Uri opertorUri)
=> await CopriServer.DoSubmitFeedback(userFeedback.BikeId, userFeedback.CurrentChargeBars, userFeedback.Message, userFeedback.IsBikeBroken, opertorUri);
#endif
/// <summary> Submits mini survey to copri server. </summary>
/// <param name="answers">Collection of answers.</param>
public async Task DoSubmitMiniSurvey(IDictionary<string, string> answers)
=> await CopriServer.DoSubmitMiniSurvey(answers);
/// <summary> Submits mini survey to copri server. </summary>
/// <param name="answers">Collection of answers.</param>
public async Task DoSubmitMiniSurvey(IDictionary<string, string> answers)
=> await CopriServer.DoSubmitMiniSurvey(answers);
public async Task OpenLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
=> await CopriServer.OpenAync(bike);
public async Task CloseLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
=> await CopriServer.CloseAync(bike);
}
public async Task OpenLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
=> await CopriServer.OpenAync(bike);
public async Task CloseLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike)
=> await CopriServer.CloseAync(bike);
}
}

View file

@ -7,87 +7,87 @@ using TINK.Repository.Request;
namespace TINK.Model.Connector
{
public interface ICommand
{
/// <summary> Is raised whenever login state has changed.</summary>
event LoginStateChangedEventHandler LoginStateChanged;
public interface ICommand
{
/// <summary> Is raised whenever login state has changed.</summary>
event LoginStateChangedEventHandler LoginStateChanged;
/// <summary>
/// Logs user in.
/// If log in succeeds either and session might be updated if it was no more valid (logged in by an different device).
/// If log in fails (password modified) session cookie is set to empty.
/// If communication fails an exception is thrown.
/// </summary>
Task<IAccount> DoLogin(string p_strMail, string p_strPassword, string p_strDeviceId);
/// <summary>
/// Logs user in.
/// If log in succeeds either and session might be updated if it was no more valid (logged in by an different device).
/// If log in fails (password modified) session cookie is set to empty.
/// If communication fails an exception is thrown.
/// </summary>
Task<IAccount> DoLogin(string p_strMail, string p_strPassword, string p_strDeviceId);
/// <summary> Logs user out. </summary>
Task DoLogout();
/// <summary> Logs user out. </summary>
Task DoLogout();
/// <summary> Request to reserve a bike.</summary>
/// <param name="bike">Bike to book.</param>
Task DoReserve(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike);
/// <summary> Request to reserve a bike.</summary>
/// <param name="bike">Bike to book.</param>
Task DoReserve(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike);
/// <summary> Request to cancel a reservation.</summary>
/// <param name="bike">Bike to book.</param>
Task DoCancelReservation(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike);
/// <summary> Request to cancel a reservation.</summary>
/// <param name="bike">Bike to book.</param>
Task DoCancelReservation(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike);
/// <summary> Get authentication keys to connect to lock.</summary>
/// <param name="bike">Bike to book.</param>
Task CalculateAuthKeys(Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable bike);
/// <summary> Get authentication keys to connect to lock.</summary>
/// <param name="bike">Bike to book.</param>
Task CalculateAuthKeys(Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable bike);
/// <summary> Notifies COPRI about start of returning sequence. </summary>
/// <remarks> Operator specific call.</remarks>
/// <param name="bike">Bike to return.</param>
/// <returns>Response on notification about start of returning sequence.</returns>
Task StartReturningBike(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike);
/// <summary> Notifies COPRI about start of returning sequence. </summary>
/// <remarks> Operator specific call.</remarks>
/// <param name="bike">Bike to return.</param>
/// <returns>Response on notification about start of returning sequence.</returns>
Task StartReturningBike(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike);
/// <summary> Updates COPRI lock state for a booked bike. </summary>
/// <param name="bike">Bike to update locking state for.</param>
/// <param name="location">Geolocation of lock when returning bike.</param>
/// <returns>Response on updating locking state.</returns>
Task UpdateLockingStateAsync(Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable bike, LocationDto location = null);
/// <summary> Updates COPRI lock state for a booked bike. </summary>
/// <param name="bike">Bike to update locking state for.</param>
/// <param name="location">Geolocation of lock when returning bike.</param>
/// <returns>Response on updating locking state.</returns>
Task UpdateLockingStateAsync(Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable bike, LocationDto location = null);
/// <summary> Request to book a bike.</summary>
/// <param name="bike">Bike to book.</param>
Task DoBook(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike);
/// <summary> Request to book a bike.</summary>
/// <param name="bike">Bike to book.</param>
Task DoBook(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike);
/// <summary> Request to book a bike and open its lock.</summary>
/// <param name="bike">Bike to book and to open lock for.</param>
Task BookAndOpenAync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike);
/// <summary> Request to book a bike and open its lock.</summary>
/// <param name="bike">Bike to book and to open lock for.</param>
Task BookAndOpenAync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike);
/// <summary> Request to open lock.</summary>
/// <param name="bike">Bike for which lock has to be opened.</param>
Task OpenLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike);
/// <summary> Request to open lock.</summary>
/// <param name="bike">Bike for which lock has to be opened.</param>
Task OpenLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike);
/// <summary> Request to close lock.</summary>
/// <param name="bike">Bike for which lock has to be closed.</param>
Task CloseLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike);
/// <summary> Request to close lock.</summary>
/// <param name="bike">Bike for which lock has to be closed.</param>
Task CloseLockAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike);
/// <summary> Request to return a bike.</summary>
/// <param name="bike">Bike to return.</param>
/// <param name="location">Geolocation of lock when returning bike.</param>
/// <param name="smartDevice">Provides info about hard and software.</param>
Task<BookingFinishedModel> DoReturn(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike, LocationDto geolocation = null, ISmartDevice smartDevice = null);
/// <summary> Request to return a bike.</summary>
/// <param name="bike">Bike to return.</param>
/// <param name="location">Geolocation of lock when returning bike.</param>
/// <param name="smartDevice">Provides info about hard and software.</param>
Task<BookingFinishedModel> DoReturn(Bikes.BikeInfoNS.BC.IBikeInfoMutable bike, LocationDto geolocation = null, ISmartDevice smartDevice = null);
/// <summary> Request to return bike and close the lock.</summary>
/// <param name="bike">Bike to return.</param>
/// <param name="smartDevice">Provides info about hard and software.</param>
Task<BookingFinishedModel> ReturnAndCloseAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike, ISmartDevice smartDevice = null);
/// <summary> Request to return bike and close the lock.</summary>
/// <param name="bike">Bike to return.</param>
/// <param name="smartDevice">Provides info about hard and software.</param>
Task<BookingFinishedModel> ReturnAndCloseAsync(Bikes.BikeInfoNS.CopriLock.IBikeInfoMutable bike, ISmartDevice smartDevice = null);
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
bool IsConnected { get; }
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
bool IsConnected { get; }
/// <summary> True if user is logged in false if not. </summary>
string SessionCookie { get; }
/// <summary> True if user is logged in false if not. </summary>
string SessionCookie { get; }
/// <summary> Submits feedback for a renting operation.</summary>
Task DoSubmitFeedback(
IUserFeedback userFeedback,
Uri opertorUri);
/// <summary> Submits feedback for a renting operation.</summary>
Task DoSubmitFeedback(
IUserFeedback userFeedback,
Uri opertorUri);
/// <summary> Submits mini survey to copri server. </summary>
/// <param name="answers">Collection of answers.</param>
Task DoSubmitMiniSurvey(IDictionary<string, string> answers);
/// <summary> Submits mini survey to copri server. </summary>
/// <param name="answers">Collection of answers.</param>
Task DoSubmitMiniSurvey(IDictionary<string, string> answers);
#if USCSHARP9
/// <summary>
@ -112,55 +112,55 @@ namespace TINK.Model.Connector
string Message { get; }
}
#endif
}
}
/// <summary>Defines delegate to be raised whenever login state changes.</summary>
/// <param name="eventArgs">Holds session cookie and mail address if user logged in successfully.</param>
public delegate void LoginStateChangedEventHandler(object sender, LoginStateChangedEventArgs eventArgs);
/// <summary>Defines delegate to be raised whenever login state changes.</summary>
/// <param name="eventArgs">Holds session cookie and mail address if user logged in successfully.</param>
public delegate void LoginStateChangedEventHandler(object sender, LoginStateChangedEventArgs eventArgs);
#if !USCSHARP9
/// <summary>
/// Feedback given by user when returning bike.
/// </summary>
public interface IUserFeedback
{
/// <summary> Id of the bike to which the feedback is related to.</summary>
string BikeId { get; }
/// <summary>
/// Feedback given by user when returning bike.
/// </summary>
public interface IUserFeedback
{
/// <summary> Id of the bike to which the feedback is related to.</summary>
string BikeId { get; }
/// <summary>
/// Holds the current chargeing level of the battery in bars, null if unkonwn.
/// </summary>
int? CurrentChargeBars { get; set; }
/// <summary>
/// Holds the current chargeing level of the battery in bars, null if unkonwn.
/// </summary>
int? CurrentChargeBars { get; set; }
/// <summary>
/// Holds whether bike is broken or not.
/// </summary>
bool IsBikeBroken { get; }
/// <summary>
/// Holds whether bike is broken or not.
/// </summary>
bool IsBikeBroken { get; }
/// <summary>
/// Holds either
/// - general feedback
/// - error description of broken bike
/// or both.
/// </summary>
string Message { get; }
}
/// <summary>
/// Holds either
/// - general feedback
/// - error description of broken bike
/// or both.
/// </summary>
string Message { get; }
}
#endif
/// <summary> Event arguments to notify about changes of logged in state.</summary>
public class LoginStateChangedEventArgs : EventArgs
{
public LoginStateChangedEventArgs() : this(string.Empty, string.Empty)
{ }
/// <summary> Event arguments to notify about changes of logged in state.</summary>
public class LoginStateChangedEventArgs : EventArgs
{
public LoginStateChangedEventArgs() : this(string.Empty, string.Empty)
{ }
public LoginStateChangedEventArgs(string sessionCookie, string mail)
{
SessionCookie = sessionCookie;
Mail = mail;
}
public LoginStateChangedEventArgs(string sessionCookie, string mail)
{
SessionCookie = sessionCookie;
Mail = mail;
}
public string SessionCookie { get; }
public string SessionCookie { get; }
public string Mail { get; }
}
public string Mail { get; }
}
}

View file

@ -12,21 +12,21 @@ namespace TINK.Model.Connector
#if USCSHARP9
public class UserFeedbackDto : ICommand.IUserFeedback
#else
public class UserFeedbackDto : IUserFeedback
public class UserFeedbackDto : IUserFeedback
#endif
{
public string BikeId { get; set; }
{
public string BikeId { get; set; }
/// <summary>
/// Holds the current chargeing level of the battery in bars, null if unkonwn.
/// </summary>
public int? CurrentChargeBars { get; set; }
/// <summary>
/// Holds the current chargeing level of the battery in bars, null if unkonwn.
/// </summary>
public int? CurrentChargeBars { get; set; }
public bool IsBikeBroken { get; set; }
public bool IsBikeBroken { get; set; }
public string Message { get; set; }
public string Message { get; set; }
}
}
#endif
}

View file

@ -4,67 +4,67 @@ using TINK.Repository;
namespace TINK.Model.Connector
{
/// <summary>
/// Connects app to copri data by getting data from copri.
/// </summary>
public class Connector : IConnector
{
/// <summary>Constructs a copri connector object.</summary>
/// <param name="activeUri"> Uri to connect to.</param>
/// <param name="appContextInfo">Provides app related info (app name and version, merchantid) to pass to COPRI.</param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <param name="sessionCookie"> Holds the session cookie.</param>
/// <param name="mail">Mail of user.</param>
/// <param name="expiresAfter">Timespan which holds value after which cache expires.</param>
/// <param name="server"> Is null in production and migh be a mock in testing context.</param>
public Connector(
Uri activeUri,
AppContextInfo appContextInfo,
string uiIsoLangugageName,
string sessionCookie,
string mail,
TimeSpan? expiresAfter = null,
ICachedCopriServer server = null)
{
Command = GetCommand(
server ?? new CopriProviderHttps(
activeUri,
appContextInfo.MerchantId,
appContextInfo,
uiIsoLangugageName,
sessionCookie),
sessionCookie,
mail);
/// <summary>
/// Connects app to copri data by getting data from copri.
/// </summary>
public class Connector : IConnector
{
/// <summary>Constructs a copri connector object.</summary>
/// <param name="activeUri"> Uri to connect to.</param>
/// <param name="appContextInfo">Provides app related info (app name and version, merchantid) to pass to COPRI.</param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <param name="sessionCookie"> Holds the session cookie.</param>
/// <param name="mail">Mail of user.</param>
/// <param name="expiresAfter">Timespan which holds value after which cache expires.</param>
/// <param name="server"> Is null in production and migh be a mock in testing context.</param>
public Connector(
Uri activeUri,
AppContextInfo appContextInfo,
string uiIsoLangugageName,
string sessionCookie,
string mail,
TimeSpan? expiresAfter = null,
ICachedCopriServer server = null)
{
Command = GetCommand(
server ?? new CopriProviderHttps(
activeUri,
appContextInfo.MerchantId,
appContextInfo,
uiIsoLangugageName,
sessionCookie),
sessionCookie,
mail);
Query = GetQuery(
server ?? new CopriProviderHttps(
activeUri,
appContextInfo.MerchantId,
appContextInfo,
uiIsoLangugageName,
sessionCookie,
expiresAfter),
sessionCookie,
mail);
}
Query = GetQuery(
server ?? new CopriProviderHttps(
activeUri,
appContextInfo.MerchantId,
appContextInfo,
uiIsoLangugageName,
sessionCookie,
expiresAfter),
sessionCookie,
mail);
}
/// <summary> Object for queriying stations and bikes.</summary>
public ICommand Command { get; private set; }
/// <summary> Object for queriying stations and bikes.</summary>
public ICommand Command { get; private set; }
/// <summary> Object for queriying stations and bikes.</summary>
public IQuery Query { get; private set; }
/// <summary> Object for queriying stations and bikes.</summary>
public IQuery Query { get; private set; }
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
public bool IsConnected => Command.IsConnected;
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
public bool IsConnected => Command.IsConnected;
/// <summary> Gets a command object to perform copri commands. </summary>
public static ICommand GetCommand(ICopriServerBase copri, string sessioncookie, string mail) => string.IsNullOrEmpty(sessioncookie)
? new Command(copri)
: new CommandLoggedIn(copri, sessioncookie, mail, () => DateTime.Now) as ICommand;
/// <summary> Gets a command object to perform copri commands. </summary>
public static ICommand GetCommand(ICopriServerBase copri, string sessioncookie, string mail) => string.IsNullOrEmpty(sessioncookie)
? new Command(copri)
: new CommandLoggedIn(copri, sessioncookie, mail, () => DateTime.Now) as ICommand;
/// <summary> Gets a command object to perform copri queries. </summary>
private static IQuery GetQuery(ICachedCopriServer copri, string sessioncookie, string mail) => string.IsNullOrEmpty(sessioncookie)
? new CachedQuery(copri) as IQuery
: new CachedQueryLoggedIn(copri, sessioncookie, mail, () => DateTime.Now);
}
/// <summary> Gets a command object to perform copri queries. </summary>
private static IQuery GetQuery(ICachedCopriServer copri, string sessioncookie, string mail) => string.IsNullOrEmpty(sessioncookie)
? new CachedQuery(copri) as IQuery
: new CachedQueryLoggedIn(copri, sessioncookie, mail, () => DateTime.Now);
}
}

View file

@ -4,47 +4,47 @@ using TINK.Repository;
namespace TINK.Model.Connector
{
/// <summary>
/// Connects app to copri data by getting data from cache.
/// </summary>
public class ConnectorCache : IConnector
{
/// <summary>Constructs a copri connector object.</summary>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <param name="sessionCookie"> Holds the session cookie.</param>
/// <param name="mail">Mail of user.</param>
/// <param name="server"> Is null in production and migh be a mock in testing context.</param>
public ConnectorCache(
AppContextInfo appContextInfo,
string uiIsoLangugageName,
string sessionCookie,
string mail,
ICopriServer server = null)
{
/// <summary>
/// Connects app to copri data by getting data from cache.
/// </summary>
public class ConnectorCache : IConnector
{
/// <summary>Constructs a copri connector object.</summary>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <param name="sessionCookie"> Holds the session cookie.</param>
/// <param name="mail">Mail of user.</param>
/// <param name="server"> Is null in production and migh be a mock in testing context.</param>
public ConnectorCache(
AppContextInfo appContextInfo,
string uiIsoLangugageName,
string sessionCookie,
string mail,
ICopriServer server = null)
{
Command = Connector.GetCommand(
server ?? new CopriProviderMonkeyStore(appContextInfo.MerchantId, uiIsoLangugageName, sessionCookie),
sessionCookie,
mail);
Command = Connector.GetCommand(
server ?? new CopriProviderMonkeyStore(appContextInfo.MerchantId, uiIsoLangugageName, sessionCookie),
sessionCookie,
mail);
Query = GetQuery(
server ?? new CopriProviderMonkeyStore(appContextInfo.MerchantId, uiIsoLangugageName, sessionCookie),
sessionCookie,
mail);
}
Query = GetQuery(
server ?? new CopriProviderMonkeyStore(appContextInfo.MerchantId, uiIsoLangugageName, sessionCookie),
sessionCookie,
mail);
}
/// <summary> Object for queriying stations and bikes.</summary>
public ICommand Command { get; private set; }
/// <summary> Object for queriying stations and bikes.</summary>
public ICommand Command { get; private set; }
/// <summary> Object for queriying stations and bikes.</summary>
public IQuery Query { get; private set; }
/// <summary> Object for queriying stations and bikes.</summary>
public IQuery Query { get; private set; }
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
public bool IsConnected => Command.IsConnected;
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
public bool IsConnected => Command.IsConnected;
/// <summary> Gets a command object to perform copri queries. </summary>
private static IQuery GetQuery(ICopriServer copri, string sessioncookie, string mail) => string.IsNullOrEmpty(sessioncookie)
? new Query(copri) as IQuery
: new QueryLoggedIn(copri, sessioncookie, mail, () => DateTime.Now);
}
/// <summary> Gets a command object to perform copri queries. </summary>
private static IQuery GetQuery(ICopriServer copri, string sessioncookie, string mail) => string.IsNullOrEmpty(sessioncookie)
? new Query(copri) as IQuery
: new QueryLoggedIn(copri, sessioncookie, mail, () => DateTime.Now);
}
}

View file

@ -3,27 +3,27 @@ using TINK.Repository;
namespace TINK.Model.Connector
{
public class ConnectorFactory
{
/// <summary>
/// Gets a connector object depending on whether beein onlin or offline.
/// </summary>
/// <param name="isConnected">True if online, false if offline. If offline cache connector is returned.</param>
/// <param name="appContextInfo">Provides app related info (app name and version, merchantid) to pass to COPRI.</param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <returns></returns>
public static IConnector Create(
bool isConnected,
Uri activeUri,
AppContextInfo appContextInfo,
string uiIsoLangugageName,
string sessionCookie,
string mail,
TimeSpan? expiresAfter = null)
{
return isConnected
? new Connector(activeUri, appContextInfo, uiIsoLangugageName, sessionCookie, mail, expiresAfter: expiresAfter) as IConnector
: new ConnectorCache(appContextInfo, uiIsoLangugageName, sessionCookie, mail);
}
}
public class ConnectorFactory
{
/// <summary>
/// Gets a connector object depending on whether beein onlin or offline.
/// </summary>
/// <param name="isConnected">True if online, false if offline. If offline cache connector is returned.</param>
/// <param name="appContextInfo">Provides app related info (app name and version, merchantid) to pass to COPRI.</param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <returns></returns>
public static IConnector Create(
bool isConnected,
Uri activeUri,
AppContextInfo appContextInfo,
string uiIsoLangugageName,
string sessionCookie,
string mail,
TimeSpan? expiresAfter = null)
{
return isConnected
? new Connector(activeUri, appContextInfo, uiIsoLangugageName, sessionCookie, mail, expiresAfter: expiresAfter) as IConnector
: new ConnectorCache(appContextInfo, uiIsoLangugageName, sessionCookie, mail);
}
}
}

View file

@ -3,23 +3,23 @@ using System.Linq;
namespace TINK.Model.Connector.Filter
{
public static class GroupFilterFactory
{
/// <summary>
/// Creates filter object.
/// </summary>
/// <param name="group">if value consists
/// - list of strings entries are used to filter (intersect) with or if value is
/// - null or an empty list null filter is applied, i.e. filtering is off.</param>
/// <returns>Filtering object.</returns>
/// <remarks>
/// Tread group values of null and empty lists as marker to turn filtering off to handle COPRI responses maximal flexible.
/// </remarks>
public static IGroupFilter Create(IEnumerable<string> group)
{
return group != null && group.Count() > 0
? (IGroupFilter)new IntersectGroupFilter(group) :
new NullGroupFilter();
}
}
public static class GroupFilterFactory
{
/// <summary>
/// Creates filter object.
/// </summary>
/// <param name="group">if value consists
/// - list of strings entries are used to filter (intersect) with or if value is
/// - null or an empty list null filter is applied, i.e. filtering is off.</param>
/// <returns>Filtering object.</returns>
/// <remarks>
/// Tread group values of null and empty lists as marker to turn filtering off to handle COPRI responses maximal flexible.
/// </remarks>
public static IGroupFilter Create(IEnumerable<string> group)
{
return group != null && group.Count() > 0
? (IGroupFilter)new IntersectGroupFilter(group) :
new NullGroupFilter();
}
}
}

View file

@ -2,8 +2,8 @@
namespace TINK.Model.Connector.Filter
{
public interface IGroupFilter
{
IEnumerable<string> DoFilter(IEnumerable<string> filter);
}
public interface IGroupFilter
{
IEnumerable<string> DoFilter(IEnumerable<string> filter);
}
}

View file

@ -2,18 +2,18 @@
namespace TINK.Model.Connector.Filter
{
/// <summary> Filters to enumerations of string by intersecting.</summary>
public class IntersectGroupFilter : IGroupFilter
{
private IEnumerable<string> Group { get; set; }
/// <summary> Filters to enumerations of string by intersecting.</summary>
public class IntersectGroupFilter : IGroupFilter
{
private IEnumerable<string> Group { get; set; }
public IntersectGroupFilter(IEnumerable<string> group) => Group = group ?? new List<string>();
public IntersectGroupFilter(IEnumerable<string> group) => Group = group ?? new List<string>();
/// <summary> Applies filtering. </summary>
/// <param name="filter">Enumeration of filter values to filter with or null if no filtering has to be applied.</param>
/// <returns></returns>
public IEnumerable<string> DoFilter(IEnumerable<string> filter) => filter != null
? Group.IntersectByGoupId(filter)
: Group;
}
/// <summary> Applies filtering. </summary>
/// <param name="filter">Enumeration of filter values to filter with or null if no filtering has to be applied.</param>
/// <returns></returns>
public IEnumerable<string> DoFilter(IEnumerable<string> filter) => filter != null
? Group.IntersectByGoupId(filter)
: Group;
}
}

View file

@ -4,40 +4,40 @@ using System.Text.RegularExpressions;
namespace TINK.Model.Connector.Filter
{
public static class IntersectGroupFilterHelper
{
/// <summary>
/// Transforms a group (each element consists of an operator prefix and a numeric bike category) to bike category enumeration (numeric elements).
/// </summary>
/// <param name="group">Group to transform.</param>
/// <returns>Enumeration of numeric bike categories.</returns>
public static IEnumerable<string> ToBikeCategory(this IEnumerable<string> group)
=> group?.Select(x => x.GetBikeCategory())?.Where(x => !string.IsNullOrEmpty(x))
?? new List<string>();
public static class IntersectGroupFilterHelper
{
/// <summary>
/// Transforms a group (each element consists of an operator prefix and a numeric bike category) to bike category enumeration (numeric elements).
/// </summary>
/// <param name="group">Group to transform.</param>
/// <returns>Enumeration of numeric bike categories.</returns>
public static IEnumerable<string> ToBikeCategory(this IEnumerable<string> group)
=> group?.Select(x => x.GetBikeCategory())?.Where(x => !string.IsNullOrEmpty(x))
?? new List<string>();
/// <summary>
/// Extracts bike group category umber from a group string.
/// </summary>
/// <param name="group">Group to transform. Example KN_300101 (Stadtrad located in Konstanz), FR_300102 (Lastenrad located in Freiburg).</param>
/// <returns>Enumeration of numeric bike categories.</returns>
public static string GetBikeCategory(this string group)
=> Regex.Match(group, "[0-9]+")?.Value ?? string.Empty;
/// <summary>
/// Extracts bike group category umber from a group string.
/// </summary>
/// <param name="group">Group to transform. Example KN_300101 (Stadtrad located in Konstanz), FR_300102 (Lastenrad located in Freiburg).</param>
/// <returns>Enumeration of numeric bike categories.</returns>
public static string GetBikeCategory(this string group)
=> Regex.Match(group, "[0-9]+")?.Value ?? string.Empty;
/// <summary>
/// Intersects two goups only taking into accout the numeric bike group category part.
/// </summary>
/// <param name="group">Group to filter.</param>
/// <param name="filter">Filter to apply</param>
public static IEnumerable<string> IntersectByGoupId(this IEnumerable<string> group, IEnumerable<string> filter)
=> group.Where(x => filter.ContainsGroupId(x));
/// <summary>
/// Intersects two goups only taking into accout the numeric bike group category part.
/// </summary>
/// <param name="group">Group to filter.</param>
/// <param name="filter">Filter to apply</param>
public static IEnumerable<string> IntersectByGoupId(this IEnumerable<string> group, IEnumerable<string> filter)
=> group.Where(x => filter.ContainsGroupId(x));
/// <summary>
/// Gets if group contains a filter element.
/// </summary>
/// <param name="group"></param>
/// <param name="filterElement"></param>
/// <returns></returns>
public static bool ContainsGroupId(this IEnumerable<string> group, string filterElement)
=> group.ToBikeCategory().Contains(filterElement.GetBikeCategory());
}
/// <summary>
/// Gets if group contains a filter element.
/// </summary>
/// <param name="group"></param>
/// <param name="filterElement"></param>
/// <returns></returns>
public static bool ContainsGroupId(this IEnumerable<string> group, string filterElement)
=> group.ToBikeCategory().Contains(filterElement.GetBikeCategory());
}
}

View file

@ -2,8 +2,8 @@
namespace TINK.Model.Connector.Filter
{
public class NullGroupFilter : IGroupFilter
{
public IEnumerable<string> DoFilter(IEnumerable<string> filter) => filter;
}
public class NullGroupFilter : IGroupFilter
{
public IEnumerable<string> DoFilter(IEnumerable<string> filter) => filter;
}
}

View file

@ -1,19 +1,19 @@
namespace TINK.Model.Connector
{
public static class FilterHelper
{
/// <summary> Holds the Konrad group (city bikes).</summary>
/// <remarks>
/// Was "Konrad" up to version 3.0.258.
/// Specified first: "KN300001" (RG).
/// </remarks>
public const string CITYBIKE = "300103";
public static class FilterHelper
{
/// <summary> Holds the Konrad group (city bikes).</summary>
/// <remarks>
/// Was "Konrad" up to version 3.0.258.
/// Specified first: "KN300001" (RG).
/// </remarks>
public const string CITYBIKE = "300103";
/// <summary> Holds the tink group (Lastenräder).</summary>
/// <remarks>
/// Was "TINK" up to version 3.0.258.
/// Specified first: "KN300029" (RG).
/// </remarks>
public const string CARGOBIKE = "300101";
}
/// <summary> Holds the tink group (Lastenräder).</summary>
/// <remarks>
/// Was "TINK" up to version 3.0.258.
/// Specified first: "KN300029" (RG).
/// </remarks>
public const string CARGOBIKE = "300101";
}
}

View file

@ -11,112 +11,112 @@ using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
namespace TINK.Model.Connector
{
/// <summary> Filters connector respones.</summary>
/// <remarks>Former name: Filter</remarks>
public class FilteredConnector : IFilteredConnector
{
/// <summary> Constructs a filter object. </summary>
/// <param name="group">Filter group.</param>
/// <param name="connector">Connector object.</param>
public FilteredConnector(
IEnumerable<string> group,
IConnector connector)
{
Connector = connector;
/// <summary> Filters connector respones.</summary>
/// <remarks>Former name: Filter</remarks>
public class FilteredConnector : IFilteredConnector
{
/// <summary> Constructs a filter object. </summary>
/// <param name="group">Filter group.</param>
/// <param name="connector">Connector object.</param>
public FilteredConnector(
IEnumerable<string> group,
IConnector connector)
{
Connector = connector;
if (Connector == null)
{
throw new ArgumentException("Can not construct filter object. Connector- and command objects must not be null.");
}
if (Connector == null)
{
throw new ArgumentException("Can not construct filter object. Connector- and command objects must not be null.");
}
Query = new QueryProvider(Connector.Query, GroupFilterFactory.Create(group));
}
Query = new QueryProvider(Connector.Query, GroupFilterFactory.Create(group));
}
/// <summary> Inner connector object.</summary>
public IConnector Connector { get; }
/// <summary> Inner connector object.</summary>
public IConnector Connector { get; }
/// <summary> Command object. </summary>
public ICommand Command => Connector.Command;
/// <summary> Command object. </summary>
public ICommand Command => Connector.Command;
/// <summary> Object to query information. </summary>
public IQuery Query { get; }
/// <summary> Object to query information. </summary>
public IQuery Query { get; }
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
public bool IsConnected => Connector.IsConnected;
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
public bool IsConnected => Connector.IsConnected;
/// <summary> Object to perform filtered queries.</summary>
private class QueryProvider : IQuery
{
/// <summary> Holds the filter. </summary>
private IGroupFilter Filter { get; }
/// <summary> Object to perform filtered queries.</summary>
private class QueryProvider : IQuery
{
/// <summary> Holds the filter. </summary>
private IGroupFilter Filter { get; }
/// <summary> Holds the reference to object which performs copry queries.</summary>
private IQuery m_oInnerQuery;
/// <summary> Holds the reference to object which performs copry queries.</summary>
private IQuery m_oInnerQuery;
/// <summary> Constructs a query object.</summary>
/// <param name="innerQuerry"></param>
/// <param name="filter"></param>
public QueryProvider(IQuery innerQuerry, IGroupFilter filter)
{
m_oInnerQuery = innerQuerry;
Filter = filter;
}
/// <summary> Constructs a query object.</summary>
/// <param name="innerQuerry"></param>
/// <param name="filter"></param>
public QueryProvider(IQuery innerQuerry, IGroupFilter filter)
{
m_oInnerQuery = innerQuerry;
Filter = filter;
}
/// <summary> Gets bikes either bikes available if no user is logged in or bikes available and bikes occupied if a user is logged in. </summary>
public async Task<Result<BikeCollection>> GetBikesAsync()
{
var result = await m_oInnerQuery.GetBikesAsync();
return new Result<BikeCollection>(
result.Source,
new BikeCollection(DoFilter(result.Response, Filter)),
result.GeneralData,
result.Exception);
}
/// <summary> Gets bikes either bikes available if no user is logged in or bikes available and bikes occupied if a user is logged in. </summary>
public async Task<Result<BikeCollection>> GetBikesAsync()
{
var result = await m_oInnerQuery.GetBikesAsync();
return new Result<BikeCollection>(
result.Source,
new BikeCollection(DoFilter(result.Response, Filter)),
result.GeneralData,
result.Exception);
}
/// <summary> Gets bikes occupied if a user is logged in. </summary>
public async Task<Result<BikeCollection>> GetBikesOccupiedAsync()
{
var result = await m_oInnerQuery.GetBikesOccupiedAsync();
return new Result<BikeCollection>(
result.Source,
new BikeCollection(result.Response.ToDictionary(x => x.Id)),
result.GeneralData,
result.Exception);
}
/// <summary> Gets bikes occupied if a user is logged in. </summary>
public async Task<Result<BikeCollection>> GetBikesOccupiedAsync()
{
var result = await m_oInnerQuery.GetBikesOccupiedAsync();
return new Result<BikeCollection>(
result.Source,
new BikeCollection(result.Response.ToDictionary(x => x.Id)),
result.GeneralData,
result.Exception);
}
/// <summary> Gets all station applying filter rules. </summary>
/// <returns></returns>
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
{
// Bikes and stations from COPRI or cache
var providerBikesAndStations = await m_oInnerQuery.GetBikesAndStationsAsync();
/// <summary> Gets all station applying filter rules. </summary>
/// <returns></returns>
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
{
// Bikes and stations from COPRI or cache
var providerBikesAndStations = await m_oInnerQuery.GetBikesAndStationsAsync();
// Do filtering.
var filteredStationsDictionary = new StationDictionary(providerBikesAndStations.Response.StationsAll.CopriVersion, DoFilter(providerBikesAndStations.Response.StationsAll, Filter));
var filteredBikesDictionary = new BikeCollection(DoFilter(providerBikesAndStations.Response.Bikes, Filter));
var filteredBikesAndStations = new Result<StationsAndBikesContainer>(
providerBikesAndStations.Source,
new StationsAndBikesContainer(filteredStationsDictionary, filteredBikesDictionary),
providerBikesAndStations.GeneralData,
providerBikesAndStations.Exception);
// Do filtering.
var filteredStationsDictionary = new StationDictionary(providerBikesAndStations.Response.StationsAll.CopriVersion, DoFilter(providerBikesAndStations.Response.StationsAll, Filter));
var filteredBikesDictionary = new BikeCollection(DoFilter(providerBikesAndStations.Response.Bikes, Filter));
var filteredBikesAndStations = new Result<StationsAndBikesContainer>(
providerBikesAndStations.Source,
new StationsAndBikesContainer(filteredStationsDictionary, filteredBikesDictionary),
providerBikesAndStations.GeneralData,
providerBikesAndStations.Exception);
return filteredBikesAndStations;
}
return filteredBikesAndStations;
}
/// <summary> Filter bikes by group. </summary>
/// <param name="bikes">Bikes to filter.</param>
/// <returns>Filtered bikes.</returns>
private static Dictionary<string, BikeInfo> DoFilter(BikeCollection bikes, IGroupFilter filter)
{
return bikes.Where(x => filter.DoFilter(x.Group).Count() > 0).ToDictionary(x => x.Id);
}
/// <summary> Filter bikes by group. </summary>
/// <param name="bikes">Bikes to filter.</param>
/// <returns>Filtered bikes.</returns>
private static Dictionary<string, BikeInfo> DoFilter(BikeCollection bikes, IGroupFilter filter)
{
return bikes.Where(x => filter.DoFilter(x.Group).Count() > 0).ToDictionary(x => x.Id);
}
/// <summary> Filter stations by broup. </summary>
/// <returns></returns>
private static Dictionary<string, IStation> DoFilter(StationDictionary stations, IGroupFilter filter)
{
return stations.Where(x => filter.DoFilter(x.Group).Count() > 0).ToDictionary(x => x.Id);
}
}
}
/// <summary> Filter stations by broup. </summary>
/// <returns></returns>
private static Dictionary<string, IStation> DoFilter(StationDictionary stations, IGroupFilter filter)
{
return stations.Where(x => filter.DoFilter(x.Group).Count() > 0).ToDictionary(x => x.Id);
}
}
}
}

View file

@ -2,16 +2,16 @@
namespace TINK.Model.Connector
{
public static class FilteredConnectorFactory
{
/// <summary> Creates a filter object. </summary>
/// <param name="group">Filter to apply on stations and bikes.</param>
/// <param name="connector">Connector to connect to COPRI.</param>
public static IFilteredConnector Create(IEnumerable<string> group, IConnector connector)
{
return group != null
? (IFilteredConnector)new FilteredConnector(group, connector)
: new NullFilterConnector(connector); // Do not apply filtering.
}
}
public static class FilteredConnectorFactory
{
/// <summary> Creates a filter object. </summary>
/// <param name="group">Filter to apply on stations and bikes.</param>
/// <param name="connector">Connector to connect to COPRI.</param>
public static IFilteredConnector Create(IEnumerable<string> group, IConnector connector)
{
return group != null
? (IFilteredConnector)new FilteredConnector(group, connector)
: new NullFilterConnector(connector); // Do not apply filtering.
}
}
}

View file

@ -1,14 +1,14 @@
namespace TINK.Model.Connector
{
public interface IConnector
{
/// <summary> Object for queriying stations and bikes.</summary>
ICommand Command { get; }
public interface IConnector
{
/// <summary> Object for queriying stations and bikes.</summary>
ICommand Command { get; }
/// <summary> Object for queriying stations and bikes.</summary>
IQuery Query { get; }
/// <summary> Object for queriying stations and bikes.</summary>
IQuery Query { get; }
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
bool IsConnected { get; }
}
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
bool IsConnected { get; }
}
}

View file

@ -1,7 +1,7 @@
namespace TINK.Model.Connector
{
public interface IFilteredConnector : IConnector
{
IConnector Connector { get; }
}
public interface IFilteredConnector : IConnector
{
IConnector Connector { get; }
}
}

View file

@ -10,102 +10,102 @@ using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
namespace TINK.Model.Connector
{
/// <summary> Filters connector respones.</summary>
public class NullFilterConnector : IFilteredConnector
{
/// <summary> Constructs a filter object. </summary>
/// <param name="p_oGroup">Filter group.</param>
/// <param name="connector">Connector object.</param>
public NullFilterConnector(
IConnector connector)
{
Connector = connector;
/// <summary> Filters connector respones.</summary>
public class NullFilterConnector : IFilteredConnector
{
/// <summary> Constructs a filter object. </summary>
/// <param name="p_oGroup">Filter group.</param>
/// <param name="connector">Connector object.</param>
public NullFilterConnector(
IConnector connector)
{
Connector = connector;
if (Connector == null)
{
throw new ArgumentException("Can not construct filter object. Connector- and command objects must not be null.");
}
if (Connector == null)
{
throw new ArgumentException("Can not construct filter object. Connector- and command objects must not be null.");
}
Query = new QueryProvider(Connector.Query);
}
Query = new QueryProvider(Connector.Query);
}
/// <summary> Inner connector object.</summary>
public IConnector Connector { get; }
/// <summary> Inner connector object.</summary>
public IConnector Connector { get; }
/// <summary> Command object. </summary>
public ICommand Command => Connector.Command;
/// <summary> Command object. </summary>
public ICommand Command => Connector.Command;
/// <summary> Object to query information. </summary>
public IQuery Query { get; }
/// <summary> Object to query information. </summary>
public IQuery Query { get; }
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
public bool IsConnected => Connector.IsConnected;
/// <summary> True if connector has access to copri server, false if cached values are used. </summary>
public bool IsConnected => Connector.IsConnected;
/// <summary> Object to perform filtered queries.</summary>
private class QueryProvider : IQuery
{
/// <summary> Holds the reference to object which performs copry queries.</summary>
private IQuery m_oInnerQuery;
/// <summary> Object to perform filtered queries.</summary>
private class QueryProvider : IQuery
{
/// <summary> Holds the reference to object which performs copry queries.</summary>
private IQuery m_oInnerQuery;
/// <summary> Constructs a query object.</summary>
/// <param name="p_oInnerQuery"></param>
/// <param name="p_oFilter"></param>
public QueryProvider(IQuery p_oInnerQuery)
{
m_oInnerQuery = p_oInnerQuery;
}
/// <summary> Constructs a query object.</summary>
/// <param name="p_oInnerQuery"></param>
/// <param name="p_oFilter"></param>
public QueryProvider(IQuery p_oInnerQuery)
{
m_oInnerQuery = p_oInnerQuery;
}
/// <summary> Gets bikes either bikes available if no user is logged in or bikes available and bikes occupied if a user is logged in. </summary>
public async Task<Result<BikeCollection>> GetBikesAsync()
{
var result = await m_oInnerQuery.GetBikesAsync();
return new Result<BikeCollection>(
result.Source,
new BikeCollection(result.Response.ToDictionary(x => x.Id)),
result.GeneralData,
result.Exception);
}
/// <summary> Gets bikes either bikes available if no user is logged in or bikes available and bikes occupied if a user is logged in. </summary>
public async Task<Result<BikeCollection>> GetBikesAsync()
{
var result = await m_oInnerQuery.GetBikesAsync();
return new Result<BikeCollection>(
result.Source,
new BikeCollection(result.Response.ToDictionary(x => x.Id)),
result.GeneralData,
result.Exception);
}
/// <summary> Gets bikes occupied if a user is logged in. </summary>
public async Task<Result<BikeCollection>> GetBikesOccupiedAsync()
{
var result = await m_oInnerQuery.GetBikesOccupiedAsync();
return new Result<BikeCollection>(
result.Source,
new BikeCollection(result.Response.ToDictionary(x => x.Id)),
result.GeneralData,
result.Exception);
}
/// <summary> Gets bikes occupied if a user is logged in. </summary>
public async Task<Result<BikeCollection>> GetBikesOccupiedAsync()
{
var result = await m_oInnerQuery.GetBikesOccupiedAsync();
return new Result<BikeCollection>(
result.Source,
new BikeCollection(result.Response.ToDictionary(x => x.Id)),
result.GeneralData,
result.Exception);
}
/// <summary> Gets all station applying filter rules. </summary>
/// <returns></returns>
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
{
var result = await m_oInnerQuery.GetBikesAndStationsAsync();
/// <summary> Gets all station applying filter rules. </summary>
/// <returns></returns>
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
{
var result = await m_oInnerQuery.GetBikesAndStationsAsync();
return new Result<StationsAndBikesContainer>(
result.Source,
new StationsAndBikesContainer(
new StationDictionary(result.Response.StationsAll.CopriVersion, result.Response.StationsAll.ToDictionary(x => x.Id)),
new BikeCollection(result.Response.Bikes.ToDictionary(x => x.Id))),
result.GeneralData,
result.Exception);
}
return new Result<StationsAndBikesContainer>(
result.Source,
new StationsAndBikesContainer(
new StationDictionary(result.Response.StationsAll.CopriVersion, result.Response.StationsAll.ToDictionary(x => x.Id)),
new BikeCollection(result.Response.Bikes.ToDictionary(x => x.Id))),
result.GeneralData,
result.Exception);
}
/// <summary> Filter bikes by group. </summary>
/// <param name="bikes">Bikes to filter.</param>
/// <returns>Filtered bikes.</returns>
public static Dictionary<string, BikeInfo> DoFilter(BikeCollection bikes, IEnumerable<string> filter)
{
return bikes.Where(x => x.Group.Intersect(filter).Count() > 0).ToDictionary(x => x.Id);
}
/// <summary> Filter bikes by group. </summary>
/// <param name="bikes">Bikes to filter.</param>
/// <returns>Filtered bikes.</returns>
public static Dictionary<string, BikeInfo> DoFilter(BikeCollection bikes, IEnumerable<string> filter)
{
return bikes.Where(x => x.Group.Intersect(filter).Count() > 0).ToDictionary(x => x.Id);
}
/// <summary> Filter stations by broup. </summary>
/// <returns></returns>
public static Dictionary<string, IStation> DoFilter(StationDictionary stations, IEnumerable<string> p_oFilter)
{
return stations.Where(x => x.Group.Intersect(p_oFilter).Count() > 0).ToDictionary(x => x.Id);
}
}
}
/// <summary> Filter stations by broup. </summary>
/// <returns></returns>
public static Dictionary<string, IStation> DoFilter(StationDictionary stations, IEnumerable<string> p_oFilter)
{
return stations.Where(x => x.Group.Intersect(p_oFilter).Count() > 0).ToDictionary(x => x.Id);
}
}
}
}

View file

@ -3,25 +3,25 @@ using TINK.Repository;
namespace TINK.Model.Connector
{
/// <summary>
/// Provides information required for copri commands/ query operations.
/// </summary>
public class Base
{
/// <summary> Reference to object which provides access to copri server. </summary>
protected ICopriServerBase CopriServer { get; }
/// <summary>
/// Provides information required for copri commands/ query operations.
/// </summary>
public class Base
{
/// <summary> Reference to object which provides access to copri server. </summary>
protected ICopriServerBase CopriServer { get; }
/// <summary> Gets the merchant id.</summary>
protected string MerchantId => CopriServer.MerchantId;
/// <summary> Gets the merchant id.</summary>
protected string MerchantId => CopriServer.MerchantId;
/// <summary> Constructs a query base object.</summary>
/// <param name="p_oCopriServer">Server which implements communication.</param>
/// <param name="p_oErrorStack">Object which hold communication objects.</param>
protected Base(
ICopriServerBase p_oCopriServer)
{
CopriServer = p_oCopriServer
?? throw new ArgumentException("Can not instantiate command/ query base- object. Copri server object must never be null or emtpy.");
}
}
/// <summary> Constructs a query base object.</summary>
/// <param name="p_oCopriServer">Server which implements communication.</param>
/// <param name="p_oErrorStack">Object which hold communication objects.</param>
protected Base(
ICopriServerBase p_oCopriServer)
{
CopriServer = p_oCopriServer
?? throw new ArgumentException("Can not instantiate command/ query base- object. Copri server object must never be null or emtpy.");
}
}
}

View file

@ -3,37 +3,37 @@ using TINK.Repository;
namespace TINK.Model.Connector
{
/// <summary>Holds user infromation required for copri related commands/ query operations. </summary>
public class BaseLoggedIn : Base
{
/// <summary>Session cookie used to sign in to copri.</summary>
public string SessionCookie { get; }
/// <summary>Holds user infromation required for copri related commands/ query operations. </summary>
public class BaseLoggedIn : Base
{
/// <summary>Session cookie used to sign in to copri.</summary>
public string SessionCookie { get; }
/// <summary> Mail address of the user. </summary>
protected string Mail { get; }
/// <summary> Mail address of the user. </summary>
protected string Mail { get; }
/// <summary> Object which provides date time info. </summary>
protected readonly Func<DateTime> DateTimeProvider;
/// <summary> Object which provides date time info. </summary>
protected readonly Func<DateTime> DateTimeProvider;
/// <summary>Constructs a copri query object.</summary>
/// <param name="copriServer">Server which implements communication.</param>
public BaseLoggedIn(ICopriServerBase copriServer,
string sessionCookie,
string mail,
Func<DateTime> p_oDateTimeProvider) : base(copriServer)
{
if (string.IsNullOrEmpty(sessionCookie))
throw new ArgumentException("Can not instantiate query object- object. Session cookie must never be null or emtpy.");
/// <summary>Constructs a copri query object.</summary>
/// <param name="copriServer">Server which implements communication.</param>
public BaseLoggedIn(ICopriServerBase copriServer,
string sessionCookie,
string mail,
Func<DateTime> p_oDateTimeProvider) : base(copriServer)
{
if (string.IsNullOrEmpty(sessionCookie))
throw new ArgumentException("Can not instantiate query object- object. Session cookie must never be null or emtpy.");
if (string.IsNullOrEmpty(mail))
throw new ArgumentException("Can not instantiate query object- object. Mail address must never be null or emtpy.");
if (string.IsNullOrEmpty(mail))
throw new ArgumentException("Can not instantiate query object- object. Mail address must never be null or emtpy.");
DateTimeProvider = p_oDateTimeProvider
?? throw new ArgumentException("Can not instantiate connector- object. No date time provider object available.");
DateTimeProvider = p_oDateTimeProvider
?? throw new ArgumentException("Can not instantiate connector- object. No date time provider object available.");
SessionCookie = sessionCookie;
SessionCookie = sessionCookie;
Mail = mail;
}
}
Mail = mail;
}
}
}

View file

@ -11,82 +11,82 @@ using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
namespace TINK.Model.Connector
{
public class CachedQuery : Base, IQuery
{
/// <summary> Cached copri server. </summary>
private readonly ICachedCopriServer server;
public class CachedQuery : Base, IQuery
{
/// <summary> Cached copri server. </summary>
private readonly ICachedCopriServer server;
/// <summary>Constructs a copri query object.</summary>
/// <param name="copriServer">Server which implements communication.</param>
public CachedQuery(
ICopriServerBase copriServer) : base(copriServer)
{
server = copriServer as ICachedCopriServer;
if (server == null)
{
throw new ArgumentException($"Copri server is not of expected typ. Type detected is {copriServer.GetType()}.");
}
}
/// <summary>Constructs a copri query object.</summary>
/// <param name="copriServer">Server which implements communication.</param>
public CachedQuery(
ICopriServerBase copriServer) : base(copriServer)
{
server = copriServer as ICachedCopriServer;
if (server == null)
{
throw new ArgumentException($"Copri server is not of expected typ. Type detected is {copriServer.GetType()}.");
}
}
/// <summary> Gets all stations including postions and bikes.</summary>
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
{
var resultStations = await server.GetStations();
/// <summary> Gets all stations including postions and bikes.</summary>
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
{
var resultStations = await server.GetStations();
if (resultStations.Source == typeof(CopriCallsMonkeyStore))
{
// Communication with copri in order to get stations failed.
return new Result<StationsAndBikesContainer>(
resultStations.Source,
new StationsAndBikesContainer(
resultStations.Response.GetStationsAllMutable(),
(await server.GetBikesAvailable(true)).Response.GetBikesAvailable()),
resultStations.GeneralData,
resultStations.Exception);
}
if (resultStations.Source == typeof(CopriCallsMonkeyStore))
{
// Communication with copri in order to get stations failed.
return new Result<StationsAndBikesContainer>(
resultStations.Source,
new StationsAndBikesContainer(
resultStations.Response.GetStationsAllMutable(),
(await server.GetBikesAvailable(true)).Response.GetBikesAvailable()),
resultStations.GeneralData,
resultStations.Exception);
}
var resultBikes = await server.GetBikesAvailable();
if (resultBikes.Source == typeof(CopriCallsMonkeyStore))
{
// Communication with copri in order to get bikes failed.
return new Result<StationsAndBikesContainer>(
resultBikes.Source,
new StationsAndBikesContainer(
(await server.GetStations(true)).Response.GetStationsAllMutable(),
resultBikes.Response.GetBikesAvailable()),
resultBikes.GeneralData,
resultBikes.Exception);
}
var resultBikes = await server.GetBikesAvailable();
if (resultBikes.Source == typeof(CopriCallsMonkeyStore))
{
// Communication with copri in order to get bikes failed.
return new Result<StationsAndBikesContainer>(
resultBikes.Source,
new StationsAndBikesContainer(
(await server.GetStations(true)).Response.GetStationsAllMutable(),
resultBikes.Response.GetBikesAvailable()),
resultBikes.GeneralData,
resultBikes.Exception);
}
// Communicatin with copri succeeded.
server.AddToCache(resultStations);
server.AddToCache(resultBikes);
// Communicatin with copri succeeded.
server.AddToCache(resultStations);
server.AddToCache(resultBikes);
return new Result<StationsAndBikesContainer>(
resultStations.Source,
new StationsAndBikesContainer(resultStations.Response.GetStationsAllMutable(), resultBikes.Response.GetBikesAvailable()),
resultStations.GeneralData);
}
return new Result<StationsAndBikesContainer>(
resultStations.Source,
new StationsAndBikesContainer(resultStations.Response.GetStationsAllMutable(), resultBikes.Response.GetBikesAvailable()),
resultStations.GeneralData);
}
/// <summary> Gets bikes occupied. </summary>
/// <returns>Collection of bikes.</returns>
public async Task<Result<BikeCollection>> GetBikesOccupiedAsync()
{
Log.ForContext<CachedQuery>().Error("Unexpected call to get be bikes occpied detected. No user is logged in.");
return new Result<BikeCollection>(
typeof(CopriCallsMonkeyStore),
await Task.FromResult(new BikeCollection(new Dictionary<string, BikeInfo>())),
new GeneralData(),
new Exception("Abfrage der reservierten/ gebuchten Räder nicht möglich. Kein Benutzer angemeldet."));
}
/// <summary> Gets bikes occupied. </summary>
/// <returns>Collection of bikes.</returns>
public async Task<Result<BikeCollection>> GetBikesOccupiedAsync()
{
Log.ForContext<CachedQuery>().Error("Unexpected call to get be bikes occpied detected. No user is logged in.");
return new Result<BikeCollection>(
typeof(CopriCallsMonkeyStore),
await Task.FromResult(new BikeCollection(new Dictionary<string, BikeInfo>())),
new GeneralData(),
new Exception("Abfrage der reservierten/ gebuchten Räder nicht möglich. Kein Benutzer angemeldet."));
}
/// <summary> Gets bikes available. </summary>
/// <returns>Collection of bikes.</returns>
public async Task<Result<BikeCollection>> GetBikesAsync()
{
var result = await server.GetBikesAvailable();
server.AddToCache(result);
return new Result<BikeCollection>(result.Source, result.Response.GetBikesAvailable(), result.GeneralData, result.Exception);
}
}
/// <summary> Gets bikes available. </summary>
/// <returns>Collection of bikes.</returns>
public async Task<Result<BikeCollection>> GetBikesAsync()
{
var result = await server.GetBikesAvailable();
server.AddToCache(result);
return new Result<BikeCollection>(result.Source, result.Response.GetBikesAvailable(), result.GeneralData, result.Exception);
}
}
}

View file

@ -9,210 +9,210 @@ using TINK.Repository;
namespace TINK.Model.Connector
{
/// <summary> Provides query functionality for a logged in user. </summary>
public class CachedQueryLoggedIn : BaseLoggedIn, IQuery
{
/// <summary> Cached copri server. </summary>
private ICachedCopriServer Server { get; }
/// <summary> Provides query functionality for a logged in user. </summary>
public class CachedQueryLoggedIn : BaseLoggedIn, IQuery
{
/// <summary> Cached copri server. </summary>
private ICachedCopriServer Server { get; }
/// <summary>Constructs a copri query object.</summary>
/// <param name="copriServer">Server which implements communication.</param>
public CachedQueryLoggedIn(ICopriServerBase copriServer,
string sessionCookie,
string mail,
Func<DateTime> dateTimeProvider) : base(copriServer, sessionCookie, mail, dateTimeProvider)
{
Server = copriServer as ICachedCopriServer;
if (Server == null)
{
throw new ArgumentException($"Copri server is not of expected typ. Type detected is {copriServer.GetType()}.");
}
}
/// <summary>Constructs a copri query object.</summary>
/// <param name="copriServer">Server which implements communication.</param>
public CachedQueryLoggedIn(ICopriServerBase copriServer,
string sessionCookie,
string mail,
Func<DateTime> dateTimeProvider) : base(copriServer, sessionCookie, mail, dateTimeProvider)
{
Server = copriServer as ICachedCopriServer;
if (Server == null)
{
throw new ArgumentException($"Copri server is not of expected typ. Type detected is {copriServer.GetType()}.");
}
}
/// <summary> Gets all stations including postions.</summary>
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
{
var stationsResponse = await Server.GetStations();
/// <summary> Gets all stations including postions.</summary>
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
{
var stationsResponse = await Server.GetStations();
if (stationsResponse.Source == typeof(CopriCallsMonkeyStore)
|| stationsResponse.Exception != null)
{
// Stations were read from cache ==> get bikes availbalbe and occupied from cache as well to avoid inconsistencies
return new Result<StationsAndBikesContainer>(
stationsResponse.Source,
new StationsAndBikesContainer(
stationsResponse.Response.GetStationsAllMutable(),
UpdaterJSON.GetBikesAll(
(await Server.GetBikesAvailable(true)).Response?.bikes?.Values,
(await Server.GetBikesOccupied(true)).Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider)),
stationsResponse.GeneralData,
stationsResponse.Exception);
}
if (stationsResponse.Source == typeof(CopriCallsMonkeyStore)
|| stationsResponse.Exception != null)
{
// Stations were read from cache ==> get bikes availbalbe and occupied from cache as well to avoid inconsistencies
return new Result<StationsAndBikesContainer>(
stationsResponse.Source,
new StationsAndBikesContainer(
stationsResponse.Response.GetStationsAllMutable(),
UpdaterJSON.GetBikesAll(
(await Server.GetBikesAvailable(true)).Response?.bikes?.Values,
(await Server.GetBikesOccupied(true)).Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider)),
stationsResponse.GeneralData,
stationsResponse.Exception);
}
var bikesAvailableResponse = await Server.GetBikesAvailable();
if (bikesAvailableResponse.Source == typeof(CopriCallsMonkeyStore)
|| bikesAvailableResponse.Exception != null)
{
// Bikes avilable were read from cache ==> get bikes occupied from cache as well to avoid inconsistencies
return new Result<StationsAndBikesContainer>(
bikesAvailableResponse.Source,
new StationsAndBikesContainer(
(await Server.GetStations(true)).Response.GetStationsAllMutable(),
UpdaterJSON.GetBikesAll(bikesAvailableResponse.Response?.bikes?.Values,
(await Server.GetBikesOccupied(true)).Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider)),
bikesAvailableResponse.GeneralData,
bikesAvailableResponse.Exception);
}
var bikesAvailableResponse = await Server.GetBikesAvailable();
if (bikesAvailableResponse.Source == typeof(CopriCallsMonkeyStore)
|| bikesAvailableResponse.Exception != null)
{
// Bikes avilable were read from cache ==> get bikes occupied from cache as well to avoid inconsistencies
return new Result<StationsAndBikesContainer>(
bikesAvailableResponse.Source,
new StationsAndBikesContainer(
(await Server.GetStations(true)).Response.GetStationsAllMutable(),
UpdaterJSON.GetBikesAll(bikesAvailableResponse.Response?.bikes?.Values,
(await Server.GetBikesOccupied(true)).Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider)),
bikesAvailableResponse.GeneralData,
bikesAvailableResponse.Exception);
}
var bikesOccupiedResponse = await Server.GetBikesOccupied();
if (bikesOccupiedResponse.Source == typeof(CopriCallsMonkeyStore)
|| bikesOccupiedResponse.Exception != null)
{
// Bikes occupied were read from cache ==> get bikes available from cache as well to avoid inconsistencies
return new Result<StationsAndBikesContainer>(
bikesOccupiedResponse.Source,
new StationsAndBikesContainer(
(await Server.GetStations(true)).Response.GetStationsAllMutable(),
UpdaterJSON.GetBikesAll(
(await Server.GetBikesAvailable(true)).Response?.bikes?.Values,
bikesOccupiedResponse.Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider)),
bikesOccupiedResponse.GeneralData,
bikesOccupiedResponse.Exception);
}
var bikesOccupiedResponse = await Server.GetBikesOccupied();
if (bikesOccupiedResponse.Source == typeof(CopriCallsMonkeyStore)
|| bikesOccupiedResponse.Exception != null)
{
// Bikes occupied were read from cache ==> get bikes available from cache as well to avoid inconsistencies
return new Result<StationsAndBikesContainer>(
bikesOccupiedResponse.Source,
new StationsAndBikesContainer(
(await Server.GetStations(true)).Response.GetStationsAllMutable(),
UpdaterJSON.GetBikesAll(
(await Server.GetBikesAvailable(true)).Response?.bikes?.Values,
bikesOccupiedResponse.Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider)),
bikesOccupiedResponse.GeneralData,
bikesOccupiedResponse.Exception);
}
// Both types bikes could read from copri => update cache
Server.AddToCache(stationsResponse);
Server.AddToCache(bikesAvailableResponse);
Server.AddToCache(bikesOccupiedResponse);
// Both types bikes could read from copri => update cache
Server.AddToCache(stationsResponse);
Server.AddToCache(bikesAvailableResponse);
Server.AddToCache(bikesOccupiedResponse);
var exceptions = new[] { stationsResponse?.Exception, bikesAvailableResponse?.Exception, bikesOccupiedResponse?.Exception }.Where(x => x != null).ToArray();
var exceptions = new[] { stationsResponse?.Exception, bikesAvailableResponse?.Exception, bikesOccupiedResponse?.Exception }.Where(x => x != null).ToArray();
var stationsMutable = stationsResponse.Response.GetStationsAllMutable();
var bikesMutable = UpdaterJSON.GetBikesAll(
bikesAvailableResponse.Response?.bikes?.Values,
bikesOccupiedResponse.Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider);
var stationsMutable = stationsResponse.Response.GetStationsAllMutable();
var bikesMutable = UpdaterJSON.GetBikesAll(
bikesAvailableResponse.Response?.bikes?.Values,
bikesOccupiedResponse.Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider);
return new Result<StationsAndBikesContainer>(
stationsResponse.Source,
new StationsAndBikesContainer(stationsMutable, bikesMutable),
stationsResponse.GeneralData,
exceptions.Length > 0 ? new AggregateException(exceptions) : null);
}
return new Result<StationsAndBikesContainer>(
stationsResponse.Source,
new StationsAndBikesContainer(stationsMutable, bikesMutable),
stationsResponse.GeneralData,
exceptions.Length > 0 ? new AggregateException(exceptions) : null);
}
/// <summary> Gets bikes occupied. </summary>
/// <returns>Collection of bikes.</returns>
public async Task<Result<BikeCollection>> GetBikesOccupiedAsync()
{
var bikesAvailableResponse = await Server.GetBikesAvailable(false);
if (bikesAvailableResponse.Source == typeof(CopriCallsMonkeyStore)
|| bikesAvailableResponse.Exception != null)
{
// Bikes available were read from cache ==> get bikes occupied from cache as well to avoid inconsistencies.
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes available read from cache. Reading bikes occupied from cache as well.");
return new Result<BikeCollection>(
bikesAvailableResponse.Source,
UpdaterJSON.GetBikesAll(
bikesAvailableResponse.Response?.bikes?.Values?.Where(bike => bike.GetState() == State.InUseStateEnum.FeedbackPending),
(await Server.GetBikesOccupied(true))?.Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider),
bikesAvailableResponse.GeneralData,
bikesAvailableResponse.Exception);
}
/// <summary> Gets bikes occupied. </summary>
/// <returns>Collection of bikes.</returns>
public async Task<Result<BikeCollection>> GetBikesOccupiedAsync()
{
var bikesAvailableResponse = await Server.GetBikesAvailable(false);
if (bikesAvailableResponse.Source == typeof(CopriCallsMonkeyStore)
|| bikesAvailableResponse.Exception != null)
{
// Bikes available were read from cache ==> get bikes occupied from cache as well to avoid inconsistencies.
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes available read from cache. Reading bikes occupied from cache as well.");
return new Result<BikeCollection>(
bikesAvailableResponse.Source,
UpdaterJSON.GetBikesAll(
bikesAvailableResponse.Response?.bikes?.Values?.Where(bike => bike.GetState() == State.InUseStateEnum.FeedbackPending),
(await Server.GetBikesOccupied(true))?.Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider),
bikesAvailableResponse.GeneralData,
bikesAvailableResponse.Exception);
}
var bikesOccupiedResponse = await Server.GetBikesOccupied(false);
if (bikesOccupiedResponse.Source == typeof(CopriCallsMonkeyStore)
|| bikesOccupiedResponse.Exception != null)
{
// Bikes occupied were read from cache ==> get bikes available from cache as well to avoid inconsistencies
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes occupied read from cache. Reread bikes available from cache as well.");
return new Result<BikeCollection>(
bikesOccupiedResponse.Source,
UpdaterJSON.GetBikesAll(
(await Server.GetBikesAvailable(true)).Response?.bikes?.Values?.Where(bike => bike.GetState() == State.InUseStateEnum.FeedbackPending),
bikesOccupiedResponse.Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider),
bikesOccupiedResponse.GeneralData,
bikesOccupiedResponse.Exception);
}
var bikesOccupiedResponse = await Server.GetBikesOccupied(false);
if (bikesOccupiedResponse.Source == typeof(CopriCallsMonkeyStore)
|| bikesOccupiedResponse.Exception != null)
{
// Bikes occupied were read from cache ==> get bikes available from cache as well to avoid inconsistencies
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes occupied read from cache. Reread bikes available from cache as well.");
return new Result<BikeCollection>(
bikesOccupiedResponse.Source,
UpdaterJSON.GetBikesAll(
(await Server.GetBikesAvailable(true)).Response?.bikes?.Values?.Where(bike => bike.GetState() == State.InUseStateEnum.FeedbackPending),
bikesOccupiedResponse.Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider),
bikesOccupiedResponse.GeneralData,
bikesOccupiedResponse.Exception);
}
// Both types bikes could read from copri => update bikes occupied cache.
// // Do not add bikes available to cache because this might lead to conflicts calls GetBikesAsync() and bikes with FeedbackPending state are of no use offline.
Server.AddToCache(bikesOccupiedResponse);
// Both types bikes could read from copri => update bikes occupied cache.
// // Do not add bikes available to cache because this might lead to conflicts calls GetBikesAsync() and bikes with FeedbackPending state are of no use offline.
Server.AddToCache(bikesOccupiedResponse);
return new Result<BikeCollection>(
bikesOccupiedResponse.Source,
UpdaterJSON.GetBikesAll(
bikesAvailableResponse?.Response.bikes?.Values?.Select(bike => bike)?.Where(bike => bike.GetState() == State.InUseStateEnum.FeedbackPending),
bikesOccupiedResponse?.Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider),
bikesOccupiedResponse.GeneralData,
bikesOccupiedResponse.Exception);
}
return new Result<BikeCollection>(
bikesOccupiedResponse.Source,
UpdaterJSON.GetBikesAll(
bikesAvailableResponse?.Response.bikes?.Values?.Select(bike => bike)?.Where(bike => bike.GetState() == State.InUseStateEnum.FeedbackPending),
bikesOccupiedResponse?.Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider),
bikesOccupiedResponse.GeneralData,
bikesOccupiedResponse.Exception);
}
/// <summary> Gets bikes available and bikes occupied. </summary>
/// <returns>Collection of bikes.</returns>
public async Task<Result<BikeCollection>> GetBikesAsync()
{
var bikesAvailableResponse = await Server.GetBikesAvailable();
/// <summary> Gets bikes available and bikes occupied. </summary>
/// <returns>Collection of bikes.</returns>
public async Task<Result<BikeCollection>> GetBikesAsync()
{
var bikesAvailableResponse = await Server.GetBikesAvailable();
if (bikesAvailableResponse.Source == typeof(CopriCallsMonkeyStore)
|| bikesAvailableResponse.Exception != null)
{
// Bikes available were read from cache ==> get bikes occupied from cache as well to avoid inconsistencies.
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes available read from cache. Reading bikes occupied from cache as well.");
return new Result<BikeCollection>(
bikesAvailableResponse.Source,
UpdaterJSON.GetBikesAll(
bikesAvailableResponse.Response?.bikes?.Values,
(await Server.GetBikesOccupied(true)).Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider),
bikesAvailableResponse.GeneralData,
bikesAvailableResponse.Exception);
}
if (bikesAvailableResponse.Source == typeof(CopriCallsMonkeyStore)
|| bikesAvailableResponse.Exception != null)
{
// Bikes available were read from cache ==> get bikes occupied from cache as well to avoid inconsistencies.
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes available read from cache. Reading bikes occupied from cache as well.");
return new Result<BikeCollection>(
bikesAvailableResponse.Source,
UpdaterJSON.GetBikesAll(
bikesAvailableResponse.Response?.bikes?.Values,
(await Server.GetBikesOccupied(true)).Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider),
bikesAvailableResponse.GeneralData,
bikesAvailableResponse.Exception);
}
var bikesOccupiedResponse = await Server.GetBikesOccupied();
if (bikesOccupiedResponse.Source == typeof(CopriCallsMonkeyStore)
|| bikesOccupiedResponse.Exception != null)
{
// Bikes occupied were read from cache ==> get bikes available from cache as well to avoid inconsistencies
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes occupied read from cache. Reread bikes available from cache as well.");
return new Result<BikeCollection>(
bikesOccupiedResponse.Source,
UpdaterJSON.GetBikesAll(
(await Server.GetBikesAvailable(true)).Response?.bikes?.Values,
bikesOccupiedResponse.Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider),
bikesOccupiedResponse.GeneralData,
bikesOccupiedResponse.Exception);
}
var bikesOccupiedResponse = await Server.GetBikesOccupied();
if (bikesOccupiedResponse.Source == typeof(CopriCallsMonkeyStore)
|| bikesOccupiedResponse.Exception != null)
{
// Bikes occupied were read from cache ==> get bikes available from cache as well to avoid inconsistencies
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes occupied read from cache. Reread bikes available from cache as well.");
return new Result<BikeCollection>(
bikesOccupiedResponse.Source,
UpdaterJSON.GetBikesAll(
(await Server.GetBikesAvailable(true)).Response?.bikes?.Values,
bikesOccupiedResponse.Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider),
bikesOccupiedResponse.GeneralData,
bikesOccupiedResponse.Exception);
}
// Both types bikes could read from copri => update cache
Server.AddToCache(bikesAvailableResponse);
Server.AddToCache(bikesOccupiedResponse);
// Both types bikes could read from copri => update cache
Server.AddToCache(bikesAvailableResponse);
Server.AddToCache(bikesOccupiedResponse);
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes available and occupied read successfully from server.");
return new Result<BikeCollection>(
bikesAvailableResponse.Source,
UpdaterJSON.GetBikesAll(
bikesAvailableResponse.Response?.bikes?.Values,
bikesOccupiedResponse.Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider),
bikesAvailableResponse.GeneralData,
bikesAvailableResponse.Exception != null || bikesOccupiedResponse.Exception != null ? new AggregateException(new[] { bikesAvailableResponse.Exception, bikesOccupiedResponse.Exception }) : null);
}
}
Log.ForContext<CachedQueryLoggedIn>().Debug("Bikes available and occupied read successfully from server.");
return new Result<BikeCollection>(
bikesAvailableResponse.Source,
UpdaterJSON.GetBikesAll(
bikesAvailableResponse.Response?.bikes?.Values,
bikesOccupiedResponse.Response?.bikes_occupied?.Values,
Mail,
DateTimeProvider),
bikesAvailableResponse.GeneralData,
bikesAvailableResponse.Exception != null || bikesOccupiedResponse.Exception != null ? new AggregateException(new[] { bikesAvailableResponse.Exception, bikesOccupiedResponse.Exception }) : null);
}
}
}

View file

@ -4,17 +4,17 @@ using TINK.Model.Services.CopriApi;
namespace TINK.Model.Connector
{
public interface IQuery
{
/// <summary> Gets all stations including postions.</summary>
Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync();
public interface IQuery
{
/// <summary> Gets all stations including postions.</summary>
Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync();
/// <summary> Gets bikes occupied is a user is logged in. </summary>
/// <returns>Collection of bikes.</returns>
Task<Result<BikeCollection>> GetBikesOccupiedAsync();
/// <summary> Gets bikes occupied is a user is logged in. </summary>
/// <returns>Collection of bikes.</returns>
Task<Result<BikeCollection>> GetBikesOccupiedAsync();
/// <summary> Gets bikes either bikes available if no user is logged in or bikes available and bikes occupied if a user is logged in. </summary>
/// <returns>Collection of bikes.</returns>
Task<Result<BikeCollection>> GetBikesAsync();
}
/// <summary> Gets bikes either bikes available if no user is logged in or bikes available and bikes occupied if a user is logged in. </summary>
/// <returns>Collection of bikes.</returns>
Task<Result<BikeCollection>> GetBikesAsync();
}
}

View file

@ -11,56 +11,56 @@ using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
namespace TINK.Model.Connector
{
/// <summary> Provides query functionality without login. </summary>
public class Query : Base, IQuery
{
/// <summary> Cached copri server. </summary>
private readonly ICopriServer server;
/// <summary> Provides query functionality without login. </summary>
public class Query : Base, IQuery
{
/// <summary> Cached copri server. </summary>
private readonly ICopriServer server;
/// <summary>Constructs a copri query object.</summary>
/// <param name="p_oCopriServer">Server which implements communication.</param>
public Query(ICopriServerBase p_oCopriServer) : base(p_oCopriServer)
{
server = p_oCopriServer as ICopriServer;
if (server == null)
{
throw new ArgumentException($"Copri server is not of expected typ. Type detected is {p_oCopriServer.GetType()}.");
}
}
/// <summary>Constructs a copri query object.</summary>
/// <param name="p_oCopriServer">Server which implements communication.</param>
public Query(ICopriServerBase p_oCopriServer) : base(p_oCopriServer)
{
server = p_oCopriServer as ICopriServer;
if (server == null)
{
throw new ArgumentException($"Copri server is not of expected typ. Type detected is {p_oCopriServer.GetType()}.");
}
}
/// <summary> Gets all stations including postions.</summary>
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
{
var stationsAllResponse = await server.GetStationsAsync();
var bikesAvailableResponse = await server.GetBikesAvailableAsync();
/// <summary> Gets all stations including postions.</summary>
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
{
var stationsAllResponse = await server.GetStationsAsync();
var bikesAvailableResponse = await server.GetBikesAvailableAsync();
return new Result<StationsAndBikesContainer>(
typeof(CopriCallsMonkeyStore),
new StationsAndBikesContainer(stationsAllResponse.GetStationsAllMutable(), bikesAvailableResponse.GetBikesAvailable()),
stationsAllResponse.GetGeneralData());
}
return new Result<StationsAndBikesContainer>(
typeof(CopriCallsMonkeyStore),
new StationsAndBikesContainer(stationsAllResponse.GetStationsAllMutable(), bikesAvailableResponse.GetBikesAvailable()),
stationsAllResponse.GetGeneralData());
}
/// <summary> Gets bikes occupied. </summary>
/// <returns>Collection of bikes.</returns>
public async Task<Result<BikeCollection>> GetBikesOccupiedAsync()
{
Log.ForContext<Query>().Error("Unexpected call to get be bikes occpied detected. No user is logged in.");
return new Result<BikeCollection>(
typeof(CopriCallsMonkeyStore),
await Task.FromResult(new BikeCollection(new Dictionary<string, BikeInfo>())),
new GeneralData(),
new Exception("Abfrage der reservierten/ gebuchten Räder fehlgeschlagen. Kein Benutzer angemeldet."));
}
/// <summary> Gets bikes occupied. </summary>
/// <returns>Collection of bikes.</returns>
public async Task<Result<BikeCollection>> GetBikesOccupiedAsync()
{
Log.ForContext<Query>().Error("Unexpected call to get be bikes occpied detected. No user is logged in.");
return new Result<BikeCollection>(
typeof(CopriCallsMonkeyStore),
await Task.FromResult(new BikeCollection(new Dictionary<string, BikeInfo>())),
new GeneralData(),
new Exception("Abfrage der reservierten/ gebuchten Räder fehlgeschlagen. Kein Benutzer angemeldet."));
}
/// <summary> Gets bikes occupied. </summary>
/// <returns> Collection of bikes. </returns>
public async Task<Result<BikeCollection>> GetBikesAsync()
{
var bikesAvailableResponse = await server.GetBikesAvailableAsync();
return new Result<BikeCollection>(
typeof(CopriCallsMonkeyStore),
bikesAvailableResponse.GetBikesAvailable(),
bikesAvailableResponse.GetGeneralData());
}
}
/// <summary> Gets bikes occupied. </summary>
/// <returns> Collection of bikes. </returns>
public async Task<Result<BikeCollection>> GetBikesAsync()
{
var bikesAvailableResponse = await server.GetBikesAvailableAsync();
return new Result<BikeCollection>(
typeof(CopriCallsMonkeyStore),
bikesAvailableResponse.GetBikesAvailable(),
bikesAvailableResponse.GetGeneralData());
}
}
}

View file

@ -8,79 +8,79 @@ using TINK.Repository;
namespace TINK.Model.Connector
{
/// <summary> Provides query functionality for a logged in user. </summary>
public class QueryLoggedIn : BaseLoggedIn, IQuery
{
/// <summary> Copri server. </summary>
private readonly ICopriServer server;
/// <summary> Provides query functionality for a logged in user. </summary>
public class QueryLoggedIn : BaseLoggedIn, IQuery
{
/// <summary> Copri server. </summary>
private readonly ICopriServer server;
/// <summary>Constructs a copri query object.</summary>
/// <param name="copriServer">Server which implements communication.</param>
public QueryLoggedIn(ICopriServerBase copriServer,
string sessionCookie,
string mail,
Func<DateTime> dateTimeProvider) : base(copriServer, sessionCookie, mail, dateTimeProvider)
{
server = copriServer as ICopriServer;
if (server == null)
{
throw new ArgumentException($"Copri server is not of expected typ. Type detected is {copriServer.GetType()}.");
}
/// <summary>Constructs a copri query object.</summary>
/// <param name="copriServer">Server which implements communication.</param>
public QueryLoggedIn(ICopriServerBase copriServer,
string sessionCookie,
string mail,
Func<DateTime> dateTimeProvider) : base(copriServer, sessionCookie, mail, dateTimeProvider)
{
server = copriServer as ICopriServer;
if (server == null)
{
throw new ArgumentException($"Copri server is not of expected typ. Type detected is {copriServer.GetType()}.");
}
server = copriServer as ICopriServer;
}
server = copriServer as ICopriServer;
}
/// <summary> Gets all stations including postions.</summary>
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
{
var stationResponse = await server.GetStationsAsync();
var bikesAvailableResponse = await server.GetBikesAvailableAsync();
var bikesOccupiedResponse = await server.GetBikesOccupiedAsync();
/// <summary> Gets all stations including postions.</summary>
public async Task<Result<StationsAndBikesContainer>> GetBikesAndStationsAsync()
{
var stationResponse = await server.GetStationsAsync();
var bikesAvailableResponse = await server.GetBikesAvailableAsync();
var bikesOccupiedResponse = await server.GetBikesOccupiedAsync();
return new Result<StationsAndBikesContainer>(
typeof(CopriCallsMonkeyStore),
new StationsAndBikesContainer(
stationResponse.GetStationsAllMutable(),
UpdaterJSON.GetBikesAll(
bikesAvailableResponse?.bikes?.Values,
bikesOccupiedResponse?.bikes_occupied?.Values,
Mail,
DateTimeProvider)),
stationResponse.GetGeneralData());
}
return new Result<StationsAndBikesContainer>(
typeof(CopriCallsMonkeyStore),
new StationsAndBikesContainer(
stationResponse.GetStationsAllMutable(),
UpdaterJSON.GetBikesAll(
bikesAvailableResponse?.bikes?.Values,
bikesOccupiedResponse?.bikes_occupied?.Values,
Mail,
DateTimeProvider)),
stationResponse.GetGeneralData());
}
/// <summary> Gets bikes occupied and bikes for which feedback is required. </summary>
/// <returns>Collection of bikes.</returns>
public async Task<Result<BikeCollection>> GetBikesOccupiedAsync()
{
var bikesFeedbackRequired = await server.GetBikesAvailableAsync();
var bikesOccupiedResponse = await server.GetBikesOccupiedAsync();
/// <summary> Gets bikes occupied and bikes for which feedback is required. </summary>
/// <returns>Collection of bikes.</returns>
public async Task<Result<BikeCollection>> GetBikesOccupiedAsync()
{
var bikesFeedbackRequired = await server.GetBikesAvailableAsync();
var bikesOccupiedResponse = await server.GetBikesOccupiedAsync();
return new Result<BikeCollection>(
typeof(CopriCallsMonkeyStore),
UpdaterJSON.GetBikesAll(
bikesFeedbackRequired.bikes?.Values?.Select(bike => bike)?.Where(bike => bike.GetState() == State.InUseStateEnum.FeedbackPending),
bikesOccupiedResponse?.bikes_occupied?.Values,
Mail,
DateTimeProvider),
bikesOccupiedResponse.GetGeneralData());
}
return new Result<BikeCollection>(
typeof(CopriCallsMonkeyStore),
UpdaterJSON.GetBikesAll(
bikesFeedbackRequired.bikes?.Values?.Select(bike => bike)?.Where(bike => bike.GetState() == State.InUseStateEnum.FeedbackPending),
bikesOccupiedResponse?.bikes_occupied?.Values,
Mail,
DateTimeProvider),
bikesOccupiedResponse.GetGeneralData());
}
/// <summary> Gets bikes available and bikes occupied. </summary>
/// <returns>Collection of bikes.</returns>
public async Task<Result<BikeCollection>> GetBikesAsync()
{
var bikesAvailableResponse = await server.GetBikesAvailableAsync();
var bikesOccupiedResponse = await server.GetBikesOccupiedAsync();
/// <summary> Gets bikes available and bikes occupied. </summary>
/// <returns>Collection of bikes.</returns>
public async Task<Result<BikeCollection>> GetBikesAsync()
{
var bikesAvailableResponse = await server.GetBikesAvailableAsync();
var bikesOccupiedResponse = await server.GetBikesOccupiedAsync();
return new Result<BikeCollection>(
typeof(CopriCallsMonkeyStore),
UpdaterJSON.GetBikesAll(
bikesAvailableResponse?.bikes?.Values,
bikesOccupiedResponse?.bikes_occupied?.Values,
Mail,
DateTimeProvider),
bikesAvailableResponse.GetGeneralData());
}
}
return new Result<BikeCollection>(
typeof(CopriCallsMonkeyStore),
UpdaterJSON.GetBikesAll(
bikesAvailableResponse?.bikes?.Values,
bikesOccupiedResponse?.bikes_occupied?.Values,
Mail,
DateTimeProvider),
bikesAvailableResponse.GetGeneralData());
}
}
}

View file

@ -12,369 +12,369 @@ using TINK.Repository.Response;
namespace TINK.Model.Connector
{
/// <summary>
/// Converts weak typed JSON data (mostly string) to strong typed c# data (base types, enumerations, objects, ...).
/// JSON is received from COPRI and deserialized using Json.NET.
/// </summary>
public static class TextToTypeHelper
{
/// <summary> Holds the text for demo bikes. </summary>
private const string DEMOBIKEMARKER = "DEMO";
/// <summary>
/// Converts weak typed JSON data (mostly string) to strong typed c# data (base types, enumerations, objects, ...).
/// JSON is received from COPRI and deserialized using Json.NET.
/// </summary>
public static class TextToTypeHelper
{
/// <summary> Holds the text for demo bikes. </summary>
private const string DEMOBIKEMARKER = "DEMO";
/// <summary>
/// Gets the position from StationInfo object.
/// </summary>
/// <param name="stationInfo">Object to get information from.</param>
/// <returns>Position information.</returns>
public static IPosition GetPosition(this StationsAvailableResponse.StationInfo stationInfo)
=> GetPosition(stationInfo.gps);
/// <summary>
/// Gets the position from StationInfo object.
/// </summary>
/// <param name="stationInfo">Object to get information from.</param>
/// <returns>Position information.</returns>
public static IPosition GetPosition(this StationsAvailableResponse.StationInfo stationInfo)
=> GetPosition(stationInfo.gps);
/// <summary> Gets the position from StationInfo object. </summary>
/// <param name="authorizationResponse">Object to get information from.</param>
/// <returns>Position information.</returns>
public static IEnumerable<string> GetGroup(this AuthorizationResponse authorizationResponse)
{
try
{
return authorizationResponse.user_group.GetGroup();
}
catch (Exception l_oException)
{
throw new Exception($"Can not get group of user from text \"{authorizationResponse.user_group}\".", l_oException);
}
}
/// <summary> Gets the position from StationInfo object. </summary>
/// <param name="authorizationResponse">Object to get information from.</param>
/// <returns>Position information.</returns>
public static IEnumerable<string> GetGroup(this AuthorizationResponse authorizationResponse)
{
try
{
return authorizationResponse.user_group.GetGroup();
}
catch (Exception l_oException)
{
throw new Exception($"Can not get group of user from text \"{authorizationResponse.user_group}\".", l_oException);
}
}
/// <summary> Gets the position from StationInfo object. </summary>
/// <param name="group">Object to get information from.</param>
/// <returns>Position information.</returns>
public static IEnumerable<string> GetGroup(this string[] group)
{
if (group == null || group.Length == 0)
{
// If not logged in stations groups are empty form COPRI version v4.1.
Log.Debug("Can not get goup form string. Group text can not be null.");
return new List<string>();
}
/// <summary> Gets the position from StationInfo object. </summary>
/// <param name="group">Object to get information from.</param>
/// <returns>Position information.</returns>
public static IEnumerable<string> GetGroup(this string[] group)
{
if (group == null || group.Length == 0)
{
// If not logged in stations groups are empty form COPRI version v4.1.
Log.Debug("Can not get goup form string. Group text can not be null.");
return new List<string>();
}
return new HashSet<string>(group).ToList();
}
return new HashSet<string>(group).ToList();
}
/// <summary> Gets if user acknowldged ags or not. </summary>
/// <param name="authorizationResponse">Object to get information from.</param>
/// <returns>Position information.</returns>
public static bool GetIsAgbAcknowledged(this AuthorizationResponse authorizationResponse)
=> int.TryParse(authorizationResponse?.agb_checked, out int result)
&& result != 0;
/// <summary> Gets if user acknowldged ags or not. </summary>
/// <param name="authorizationResponse">Object to get information from.</param>
/// <returns>Position information.</returns>
public static bool GetIsAgbAcknowledged(this AuthorizationResponse authorizationResponse)
=> int.TryParse(authorizationResponse?.agb_checked, out int result)
&& result != 0;
/// <summary> Gets the position from StationInfo object. </summary>
/// <param name="group">Object to get information from.</param>
/// <returns>Position information.</returns>
public static string GetGroup(this IEnumerable<string> group)
{
return string.Join(",", group);
}
/// <summary> Gets the position from StationInfo object. </summary>
/// <param name="group">Object to get information from.</param>
/// <returns>Position information.</returns>
public static string GetGroup(this IEnumerable<string> group)
{
return string.Join(",", group);
}
/// <summary> Gets the position from StationInfo object. </summary>
/// <param name="stationInfo">Object to get information from.</param>
/// <returns>Position information.</returns>
public static IEnumerable<string> GetGroup(this StationsAvailableResponse.StationInfo stationInfo)
{
try
{
return stationInfo.station_group.GetGroup();
}
catch (Exception l_oException)
{
throw new Exception($"Can not get group of stations from text \"{stationInfo.station_group}\".", l_oException);
}
}
/// <summary> Gets the position from StationInfo object. </summary>
/// <param name="stationInfo">Object to get information from.</param>
/// <returns>Position information.</returns>
public static IEnumerable<string> GetGroup(this StationsAvailableResponse.StationInfo stationInfo)
{
try
{
return stationInfo.station_group.GetGroup();
}
catch (Exception l_oException)
{
throw new Exception($"Can not get group of stations from text \"{stationInfo.station_group}\".", l_oException);
}
}
/// <summary>
/// Gets the position from BikeInfoBase object.
/// </summary>
/// <param name="bikeInfo">Object to get information from.</param>
/// <returns>Rental state.</returns>
public static InUseStateEnum GetState(this BikeInfoBase bikeInfo)
{
var stateText = bikeInfo.state?.ToLower()?.Trim();
/// <summary>
/// Gets the position from BikeInfoBase object.
/// </summary>
/// <param name="bikeInfo">Object to get information from.</param>
/// <returns>Rental state.</returns>
public static InUseStateEnum GetState(this BikeInfoBase bikeInfo)
{
var stateText = bikeInfo.state?.ToLower()?.Trim();
if (string.IsNullOrEmpty(stateText))
{
throw new InvalidResponseException<BikeInfoBase>(
"Bike state must not be empty.",
bikeInfo);
}
if (string.IsNullOrEmpty(stateText))
{
throw new InvalidResponseException<BikeInfoBase>(
"Bike state must not be empty.",
bikeInfo);
}
if (Enum.TryParse(stateText, out InUseStateEnum state))
return state;
if (Enum.TryParse(stateText, out InUseStateEnum state))
return state;
if (stateText == "available")
{
return InUseStateEnum.Disposable;
}
else if (stateText == "reserved" ||
stateText == "requested")
{
return InUseStateEnum.Reserved;
}
else if (stateText == "booked" ||
stateText == "occupied")
{
return InUseStateEnum.Booked;
}
if (stateText == "available")
{
return InUseStateEnum.Disposable;
}
else if (stateText == "reserved" ||
stateText == "requested")
{
return InUseStateEnum.Reserved;
}
else if (stateText == "booked" ||
stateText == "occupied")
{
return InUseStateEnum.Booked;
}
throw new CommunicationException(string.Format("Unknown bike state detected. State is {0}.", stateText));
}
throw new CommunicationException(string.Format("Unknown bike state detected. State is {0}.", stateText));
}
/// <summary>
/// Gets the position from BikeInfoAvailable object.
/// </summary>
/// <param name="bikeInfo">Object to get information from.</param>
/// <returns>Rental state.</returns>
public static InUseStateEnum GetState(this BikeInfoAvailable bikeInfo)
{
var state = GetState((BikeInfoBase)bikeInfo);
/// <summary>
/// Gets the position from BikeInfoAvailable object.
/// </summary>
/// <param name="bikeInfo">Object to get information from.</param>
/// <returns>Rental state.</returns>
public static InUseStateEnum GetState(this BikeInfoAvailable bikeInfo)
{
var state = GetState((BikeInfoBase)bikeInfo);
if (state != InUseStateEnum.Disposable)
return state;
if (state != InUseStateEnum.Disposable)
return state;
return bikeInfo.GetIsFeedbackPending()
? InUseStateEnum.FeedbackPending
: InUseStateEnum.Disposable;
return bikeInfo.GetIsFeedbackPending()
? InUseStateEnum.FeedbackPending
: InUseStateEnum.Disposable;
}
}
/// <summary>
/// Gets the from date information from JSON.
/// </summary>
/// <param name="bikeInfo">JSON to get information from..</param>
/// <returns>From information if bike hold this information 0001-01-01 (DateTime.MinValue) otherwise.</returns>
public static DateTime GetFrom(this BikeInfoReservedOrBooked bikeInfo)
=> DateTime.TryParse(bikeInfo?.start_time, out DateTime dateFrom) ? dateFrom : DateTime.MinValue;
/// <summary>
/// Gets the from date information from JSON.
/// </summary>
/// <param name="bikeInfo">JSON to get information from..</param>
/// <returns>From information if bike hold this information 0001-01-01 (DateTime.MinValue) otherwise.</returns>
public static DateTime GetFrom(this BikeInfoReservedOrBooked bikeInfo)
=> DateTime.TryParse(bikeInfo?.start_time, out DateTime dateFrom) ? dateFrom : DateTime.MinValue;
/// <summary>
/// Gets whether the bike is a trike or not.
/// </summary>
/// <param name="bikeInfo">JSON to get information from..</param>
/// <returns>From information.</returns>
public static bool? GetIsDemo(this BikeInfoBase bikeInfo)
{
return bikeInfo?.description != null
? bikeInfo.description.ToUpper().Contains(DEMOBIKEMARKER)
: (bool?)null;
}
/// <summary>
/// Gets whether the bike is a trike or not.
/// </summary>
/// <param name="bikeInfo">JSON to get information from..</param>
/// <returns>From information.</returns>
public static bool? GetIsDemo(this BikeInfoBase bikeInfo)
{
return bikeInfo?.description != null
? bikeInfo.description.ToUpper().Contains(DEMOBIKEMARKER)
: (bool?)null;
}
/// <summary>
/// Gets whether the bike is a trike or not.
/// </summary>
/// <param name="bikeInfo">JSON to get information from.</param>
/// <returns>From information.</returns>
public static IEnumerable<string> GetGroup(this BikeInfoBase bikeInfo)
{
try
{
return bikeInfo?.bike_group?.GetGroup()?.ToList() ?? new List<string>();
}
catch (Exception l_oException)
{
throw new Exception($"Can not get group of user from text \"{bikeInfo.bike_group}\".", l_oException);
}
}
/// <summary>
/// Gets whether the bike is a trike or not.
/// </summary>
/// <param name="bikeInfo">JSON to get information from.</param>
/// <returns>From information.</returns>
public static IEnumerable<string> GetGroup(this BikeInfoBase bikeInfo)
{
try
{
return bikeInfo?.bike_group?.GetGroup()?.ToList() ?? new List<string>();
}
catch (Exception l_oException)
{
throw new Exception($"Can not get group of user from text \"{bikeInfo.bike_group}\".", l_oException);
}
}
/// <summary> Gets whether the bike has a bord computer or not. </summary>
/// <param name="bikeInfo">JSON to get information from.</param>
/// <returns>From information.</returns>
public static bool GetIsManualLockBike(this BikeInfoBase bikeInfo)
{
return !string.IsNullOrEmpty(bikeInfo.system)
&& bikeInfo.system.ToUpper().StartsWith("LOCK");
}
/// <summary> Gets whether the bike has a bord computer or not. </summary>
/// <param name="bikeInfo">JSON to get information from.</param>
/// <returns>From information.</returns>
public static bool GetIsManualLockBike(this BikeInfoBase bikeInfo)
{
return !string.IsNullOrEmpty(bikeInfo.system)
&& bikeInfo.system.ToUpper().StartsWith("LOCK");
}
/// <summary> Gets whether the bike has a bord computer or not. </summary>
/// <param name="bikeInfo">JSON to get information from..</param>
/// <returns>From information.</returns>
public static bool GetIsBluetoothLockBike(this BikeInfoBase bikeInfo)
{
return !string.IsNullOrEmpty(bikeInfo.system)
&& bikeInfo.system.ToUpper().StartsWith("ILOCKIT");
}
/// <summary> Gets whether the bike has a bord computer or not. </summary>
/// <param name="bikeInfo">JSON to get information from..</param>
/// <returns>From information.</returns>
public static bool GetIsBluetoothLockBike(this BikeInfoBase bikeInfo)
{
return !string.IsNullOrEmpty(bikeInfo.system)
&& bikeInfo.system.ToUpper().StartsWith("ILOCKIT");
}
/// <summary> Gets whether the bike Is a Sigo bike or not. </summary>
/// <param name="bikeInfo">JSON to get information from..</param>
/// <returns>True if bike is a Sigo.</returns>
public static bool GetIsSigoBike(this BikeInfoBase bikeInfo)
{
return !string.IsNullOrEmpty(bikeInfo.system)
&& bikeInfo.system.ToUpper().StartsWith("SIGO");
}
/// <summary> Gets whether the bike Is a Sigo bike or not. </summary>
/// <param name="bikeInfo">JSON to get information from..</param>
/// <returns>True if bike is a Sigo.</returns>
public static bool GetIsSigoBike(this BikeInfoBase bikeInfo)
{
return !string.IsNullOrEmpty(bikeInfo.system)
&& bikeInfo.system.ToUpper().StartsWith("SIGO");
}
public static LockModel? GetLockModel(this BikeInfoBase bikeInfo)
{
if (GetIsBluetoothLockBike(bikeInfo))
return LockModel.ILockIt;
public static LockModel? GetLockModel(this BikeInfoBase bikeInfo)
{
if (GetIsBluetoothLockBike(bikeInfo))
return LockModel.ILockIt;
if (GetIsManualLockBike(bikeInfo))
return LockModel.BordComputer;
if (GetIsManualLockBike(bikeInfo))
return LockModel.BordComputer;
if (GetIsSigoBike(bikeInfo))
return LockModel.Sigo;
if (GetIsSigoBike(bikeInfo))
return LockModel.Sigo;
return null;
}
return null;
}
/// <summary> Gets whether the bike has a bord computer or not. </summary>
/// <param name="bikeInfo">JSON to get information from..</param>
/// <returns>From information.</returns>
public static int GetBluetoothLockId(this BikeInfoBase bikeInfo)
{
return TextToLockItTypeHelper.GetBluetoothLockId(bikeInfo?.Ilockit_ID);
}
/// <summary> Gets whether the bike has a bord computer or not. </summary>
/// <param name="bikeInfo">JSON to get information from..</param>
/// <returns>From information.</returns>
public static int GetBluetoothLockId(this BikeInfoBase bikeInfo)
{
return TextToLockItTypeHelper.GetBluetoothLockId(bikeInfo?.Ilockit_ID);
}
/// <summary> Gets whether the bike has a bord computer or not. </summary>
/// <param name="bikeInfo">JSON to get information from..</param>
/// <returns>From information.</returns>
public static Guid GetBluetoothLockGuid(this BikeInfoBase bikeInfo)
{
// return new Guid("00000000-0000-0000-0000-e57e6b9aee16");
return Guid.TryParse(bikeInfo?.Ilockit_GUID, out Guid lockGuid)
? lockGuid
: TextToLockItTypeHelper.INVALIDLOCKGUID;
}
/// <summary> Gets whether the bike has a bord computer or not. </summary>
/// <param name="bikeInfo">JSON to get information from..</param>
/// <returns>From information.</returns>
public static Guid GetBluetoothLockGuid(this BikeInfoBase bikeInfo)
{
// return new Guid("00000000-0000-0000-0000-e57e6b9aee16");
return Guid.TryParse(bikeInfo?.Ilockit_GUID, out Guid lockGuid)
? lockGuid
: TextToLockItTypeHelper.INVALIDLOCKGUID;
}
public static byte[] GetUserKey(this BikeInfoReservedOrBooked bikeInfo)
{
return GetKey(bikeInfo.K_u);
}
public static byte[] GetUserKey(this BikeInfoReservedOrBooked bikeInfo)
{
return GetKey(bikeInfo.K_u);
}
public static byte[] GetAdminKey(this BikeInfoReservedOrBooked bikeInfo)
{
return GetKey(bikeInfo.K_a);
}
public static byte[] GetAdminKey(this BikeInfoReservedOrBooked bikeInfo)
{
return GetKey(bikeInfo.K_a);
}
public static byte[] GetSeed(this BikeInfoReservedOrBooked bikeInfo)
{
return GetKey(bikeInfo.K_seed);
}
public static byte[] GetSeed(this BikeInfoReservedOrBooked bikeInfo)
{
return GetKey(bikeInfo.K_seed);
}
/// <summary>
/// Get array of keys from string of format "[12, -9, 5]"
/// </summary>
/// <param name="keyArrayText"></param>
/// <returns></returns>
private static byte[] GetKey(string keyArrayText)
{
try
{
if (string.IsNullOrEmpty(keyArrayText))
return new byte[0];
/// <summary>
/// Get array of keys from string of format "[12, -9, 5]"
/// </summary>
/// <param name="keyArrayText"></param>
/// <returns></returns>
private static byte[] GetKey(string keyArrayText)
{
try
{
if (string.IsNullOrEmpty(keyArrayText))
return new byte[0];
return Regex.Replace(keyArrayText, @"\[(.*)\]", "$1").Split(',').Select(x => (byte)sbyte.Parse(x)).ToArray();
}
catch (Exception exception)
{
Log.Error("Can not extract K_u/ K_a/ or K_seed. Key {ArrayText} does not is not of expected format. {Exception}", keyArrayText, exception);
return new byte[0];
}
}
return Regex.Replace(keyArrayText, @"\[(.*)\]", "$1").Split(',').Select(x => (byte)sbyte.Parse(x)).ToArray();
}
catch (Exception exception)
{
Log.Error("Can not extract K_u/ K_a/ or K_seed. Key {ArrayText} does not is not of expected format. {Exception}", keyArrayText, exception);
return new byte[0];
}
}
/// <summary>
/// Gets whether the bike is a trike or not.
/// </summary>
/// <param name="bikeInfo">JSON to get information from..</param>
/// <returns>From information.</returns>
public static WheelType? GetWheelType(this BikeInfoBase bikeInfo)
=> Enum.TryParse(bikeInfo?.bike_type?.wheels, true, out WheelType wheelType)
? wheelType
: (WheelType?)null;
/// <summary>
/// Gets whether the bike is a trike or not.
/// </summary>
/// <param name="bikeInfo">JSON to get information from..</param>
/// <returns>From information.</returns>
public static WheelType? GetWheelType(this BikeInfoBase bikeInfo)
=> Enum.TryParse(bikeInfo?.bike_type?.wheels, true, out WheelType wheelType)
? wheelType
: (WheelType?)null;
/// <summary>
/// Gets the type of bike.
/// </summary>
/// <param name="bikeInfo">Object to get bike type from.</param>
/// <returns>Type of bike.</returns>
public static TypeOfBike? GetTypeOfBike(this BikeInfoBase bikeInfo)
=> Enum.TryParse(bikeInfo?.bike_type?.category, true, out TypeOfBike typeOfBike)
? typeOfBike
: (TypeOfBike?)null;
/// <summary>
/// Gets the type of bike.
/// </summary>
/// <param name="bikeInfo">Object to get bike type from.</param>
/// <returns>Type of bike.</returns>
public static TypeOfBike? GetTypeOfBike(this BikeInfoBase bikeInfo)
=> Enum.TryParse(bikeInfo?.bike_type?.category, true, out TypeOfBike typeOfBike)
? typeOfBike
: (TypeOfBike?)null;
/// <summary> Get position from a ,- separated string. </summary>
/// <param name="gps">Text to extract positon from.</param>
/// <returns>Position object.</returns>
public static IPosition GetPosition(Repository.Response.Position gps)
=> PositionFactory.Create(
double.TryParse(gps?.latitude, NumberStyles.Float, CultureInfo.InvariantCulture, out double latitude) ? latitude : double.NaN,
double.TryParse(gps?.longitude, NumberStyles.Float, CultureInfo.InvariantCulture, out double longitude) ? longitude : double.NaN);
/// <summary> Get position from a ,- separated string. </summary>
/// <param name="gps">Text to extract positon from.</param>
/// <returns>Position object.</returns>
public static IPosition GetPosition(Repository.Response.Position gps)
=> PositionFactory.Create(
double.TryParse(gps?.latitude, NumberStyles.Float, CultureInfo.InvariantCulture, out double latitude) ? latitude : double.NaN,
double.TryParse(gps?.longitude, NumberStyles.Float, CultureInfo.InvariantCulture, out double longitude) ? longitude : double.NaN);
/// <summary> Get position from a ,- separated string. </summary>
/// <param name="gps">Text to extract positon from.</param>
/// <returns>Position object.</returns>
public static Map.IMapSpan GetMapSpan(this MapSpan mapSpan)
=> Map.MapSpanFactory.Create(
GetPosition(mapSpan?.center),
double.TryParse(mapSpan?.radius, NumberStyles.Float, CultureInfo.InvariantCulture, out double radius) ? radius : double.NaN);
/// <summary> Get position from a ,- separated string. </summary>
/// <param name="gps">Text to extract positon from.</param>
/// <returns>Position object.</returns>
public static Map.IMapSpan GetMapSpan(this MapSpan mapSpan)
=> Map.MapSpanFactory.Create(
GetPosition(mapSpan?.center),
double.TryParse(mapSpan?.radius, NumberStyles.Float, CultureInfo.InvariantCulture, out double radius) ? radius : double.NaN);
/// <summary>
/// Gets the locking state from response.
/// </summary>
/// <param name="bikeInfo"> Response locking state from.</param>
/// <returns>Locking state</returns>
public static Bikes.BikeInfoNS.CopriLock.LockingState GetCopriLockingState(this BikeInfoBase bikeInfo)
{
if (string.IsNullOrEmpty(bikeInfo?.lock_state))
return Bikes.BikeInfoNS.CopriLock.LockingState.UnknownDisconnected;
/// <summary>
/// Gets the locking state from response.
/// </summary>
/// <param name="bikeInfo"> Response locking state from.</param>
/// <returns>Locking state</returns>
public static Bikes.BikeInfoNS.CopriLock.LockingState GetCopriLockingState(this BikeInfoBase bikeInfo)
{
if (string.IsNullOrEmpty(bikeInfo?.lock_state))
return Bikes.BikeInfoNS.CopriLock.LockingState.UnknownDisconnected;
if (bikeInfo.lock_state.ToUpper().Trim() == "locked".ToUpper())
return Bikes.BikeInfoNS.CopriLock.LockingState.Closed;
if (bikeInfo.lock_state.ToUpper().Trim() == "locked".ToUpper())
return Bikes.BikeInfoNS.CopriLock.LockingState.Closed;
if (bikeInfo.lock_state.ToUpper().Trim() == "locking".ToUpper())
return Bikes.BikeInfoNS.CopriLock.LockingState.Closing;
if (bikeInfo.lock_state.ToUpper().Trim() == "locking".ToUpper())
return Bikes.BikeInfoNS.CopriLock.LockingState.Closing;
if (bikeInfo.lock_state.ToUpper().Trim() == "unlocked".ToUpper())
return Bikes.BikeInfoNS.CopriLock.LockingState.Open;
if (bikeInfo.lock_state.ToUpper().Trim() == "unlocked".ToUpper())
return Bikes.BikeInfoNS.CopriLock.LockingState.Open;
if (bikeInfo.lock_state.ToUpper().Trim() == "unlocking".ToUpper())
return Bikes.BikeInfoNS.CopriLock.LockingState.Opening;
if (bikeInfo.lock_state.ToUpper().Trim() == "unlocking".ToUpper())
return Bikes.BikeInfoNS.CopriLock.LockingState.Opening;
return Bikes.BikeInfoNS.CopriLock.LockingState.UnknownDisconnected;
}
return Bikes.BikeInfoNS.CopriLock.LockingState.UnknownDisconnected;
}
/// <summary>
/// Gets the operator Uri from response.
/// </summary>
/// <param name="bikeInfo"> Response to get uri from.</param>
/// <returns>Operatore Uri</returns>
public static Uri GetOperatorUri(this BikeInfoBase bikeInfo)
{
return bikeInfo?.uri_operator != null && !string.IsNullOrEmpty(bikeInfo?.uri_operator)
? new Uri($"{bikeInfo.uri_operator}/{CopriServerUriList.REST_RESOURCE_ROOT}")
: null;
}
/// <summary>
/// Gets the operator Uri from response.
/// </summary>
/// <param name="bikeInfo"> Response to get uri from.</param>
/// <returns>Operatore Uri</returns>
public static Uri GetOperatorUri(this BikeInfoBase bikeInfo)
{
return bikeInfo?.uri_operator != null && !string.IsNullOrEmpty(bikeInfo?.uri_operator)
? new Uri($"{bikeInfo.uri_operator}/{CopriServerUriList.REST_RESOURCE_ROOT}")
: null;
}
/// <summary> Tries to get the copriversion from response.</summary>
/// <param name="response">Response to get version info from.</param>
/// <returns>COPRI version</returns>
public static bool TryGetCopriVersion(this CopriVersion response, out Version copriVersion)
{
copriVersion = new Version(0, 0);
return response != null
&& !string.IsNullOrEmpty(response.copri_version)
&& Version.TryParse(response.copri_version, out copriVersion);
}
/// <summary> Tries to get the copriversion from response.</summary>
/// <param name="response">Response to get version info from.</param>
/// <returns>COPRI version</returns>
public static bool TryGetCopriVersion(this CopriVersion response, out Version copriVersion)
{
copriVersion = new Version(0, 0);
return response != null
&& !string.IsNullOrEmpty(response.copri_version)
&& Version.TryParse(response.copri_version, out copriVersion);
}
/// <summary> Gets the copriversion from.</summary>
/// <param name="response">Response to get version info from.</param>
/// <returns>COPRI version</returns>
public static Version GetCopriVersion(this CopriVersion response)
=> response.TryGetCopriVersion(out Version copriVersion)
? copriVersion
: throw new InvalidResponseException($"Can not get version info from copri response {response?.copri_version}.");
/// <summary> Gets the copriversion from.</summary>
/// <param name="response">Response to get version info from.</param>
/// <returns>COPRI version</returns>
public static Version GetCopriVersion(this CopriVersion response)
=> response.TryGetCopriVersion(out Version copriVersion)
? copriVersion
: throw new InvalidResponseException($"Can not get version info from copri response {response?.copri_version}.");
/// <summary>
/// Gets bike advanced bike state. If entry Co2Saving exists feedback is required.
/// </summary>
/// <param name="bike">Bike get to state from.</param>
public static bool GetIsFeedbackPending(this BikeInfoAvailable bike)
=> bike.co2saving != null;
}
/// <summary>
/// Gets bike advanced bike state. If entry Co2Saving exists feedback is required.
/// </summary>
/// <param name="bike">Bike get to state from.</param>
public static bool GetIsFeedbackPending(this BikeInfoAvailable bike)
=> bike.co2saving != null;
}
}

View file

@ -10,321 +10,321 @@ using BikeInfo = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfo;
namespace TINK.Model.Connector.Updater
{
/// <summary>
/// Constructs bike info instances/ bike info derived instances.
/// </summary>
public static class BikeInfoFactory
{
/// <summary> Set default lock type to . </summary>
public static LockModel DEFAULTLOCKMODEL = LockModel.Sigo;
/// <summary>
/// Constructs bike info instances/ bike info derived instances.
/// </summary>
public static class BikeInfoFactory
{
/// <summary> Set default lock type to . </summary>
public static LockModel DEFAULTLOCKMODEL = LockModel.Sigo;
/// <summary> Creates a bike info object from copri response. </summary>
/// <param name="bikeInfo">Copri response for a disposable bike. </param>
public static BikeInfo Create(BikeInfoAvailable bikeInfo)
{
if (bikeInfo == null) throw new ArgumentNullException(nameof(bikeInfo));
/// <summary> Creates a bike info object from copri response. </summary>
/// <param name="bikeInfo">Copri response for a disposable bike. </param>
public static BikeInfo Create(BikeInfoAvailable bikeInfo)
{
if (bikeInfo == null) throw new ArgumentNullException(nameof(bikeInfo));
var lockModel = bikeInfo.GetLockModel();
var lockModel = bikeInfo.GetLockModel();
if (lockModel.HasValue
&& lockModel.Value == LockModel.BordComputer)
{
// Manual lock bikes are no more supported.
Log.Error(
$"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. " +
"Manual lock bikes are no more supported." +
$"Bike number: {bikeInfo.bike}{(bikeInfo.station != null ? $"station number {bikeInfo.station}" : string.Empty)}."
);
if (lockModel.HasValue
&& lockModel.Value == LockModel.BordComputer)
{
// Manual lock bikes are no more supported.
Log.Error(
$"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. " +
"Manual lock bikes are no more supported." +
$"Bike number: {bikeInfo.bike}{(bikeInfo.station != null ? $"station number {bikeInfo.station}" : string.Empty)}."
);
return null;
}
return null;
}
switch (bikeInfo.GetState())
{
case InUseStateEnum.Disposable:
case InUseStateEnum.FeedbackPending:
break;
switch (bikeInfo.GetState())
{
case InUseStateEnum.Disposable:
case InUseStateEnum.FeedbackPending:
break;
default:
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Unexpected state {bikeInfo.GetState()} detected.");
return null;
}
default:
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Unexpected state {bikeInfo.GetState()} detected.");
return null;
}
if (string.IsNullOrEmpty(bikeInfo.station))
{
// Bike available must always have a station id because bikes can only be returned at a station.
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. No station info set.");
return null;
}
if (string.IsNullOrEmpty(bikeInfo.station))
{
// Bike available must always have a station id because bikes can only be returned at a station.
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. No station info set.");
return null;
}
var lockType = lockModel.HasValue
? BikeExtension.GetLockType(lockModel.Value)
: BikeExtension.GetLockType(DEFAULTLOCKMODEL); // Map bikes without "system"- entry in response to backend- locks.
var lockType = lockModel.HasValue
? BikeExtension.GetLockType(lockModel.Value)
: BikeExtension.GetLockType(DEFAULTLOCKMODEL); // Map bikes without "system"- entry in response to backend- locks.
try
{
switch (lockType)
{
case LockType.Backend:
return new Bikes.BikeInfoNS.CopriLock.BikeInfo(
new Bike(
bikeInfo.bike,
LockModel.Sigo,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
bikeInfo.station,
new Bikes.BikeInfoNS.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState() }.Build(),
bikeInfo.GetState() == InUseStateEnum.FeedbackPending,
bikeInfo.GetOperatorUri(),
try
{
switch (lockType)
{
case LockType.Backend:
return new Bikes.BikeInfoNS.CopriLock.BikeInfo(
new Bike(
bikeInfo.bike,
LockModel.Sigo,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
bikeInfo.station,
new Bikes.BikeInfoNS.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState() }.Build(),
bikeInfo.GetState() == InUseStateEnum.FeedbackPending,
bikeInfo.GetOperatorUri(),
#if !NOTARIFFDESCRIPTION
bikeInfo.rental_description != null
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
bikeInfo.rental_description != null
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
#else
Create((TINK.Repository.Response.TariffDescription) null),
#endif
bikeInfo.GetIsDemo(),
bikeInfo.GetGroup(),
miniSurvey: bikeInfo.user_miniquery != null
? new MiniSurveyModel(new Dictionary<string, IQuestionModel> {
{ "q1", new QuestionModel()} // Add a dummy querry. Querries are not yet read from COPRI but compiled into the app.
bikeInfo.GetIsDemo(),
bikeInfo.GetGroup(),
miniSurvey: bikeInfo.user_miniquery != null
? new MiniSurveyModel(new Dictionary<string, IQuestionModel> {
{ "q1", new QuestionModel()} // Add a dummy querry. Querries are not yet read from COPRI but compiled into the app.
})
: new MiniSurveyModel(),
co2Saving: bikeInfo.co2saving);
: new MiniSurveyModel(),
co2Saving: bikeInfo.co2saving);
case LockType.Bluethooth:
return new Bikes.BikeInfoNS.BluetoothLock.BikeInfo(
new Bike(
bikeInfo.bike,
LockModel.ILockIt,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
bikeInfo.GetBluetoothLockId(),
bikeInfo.GetBluetoothLockGuid(),
bikeInfo.station,
bikeInfo.GetOperatorUri(),
case LockType.Bluethooth:
return new Bikes.BikeInfoNS.BluetoothLock.BikeInfo(
new Bike(
bikeInfo.bike,
LockModel.ILockIt,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
bikeInfo.GetBluetoothLockId(),
bikeInfo.GetBluetoothLockGuid(),
bikeInfo.station,
bikeInfo.GetOperatorUri(),
#if !NOTARIFFDESCRIPTION
bikeInfo.rental_description != null
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
bikeInfo.rental_description != null
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
#else
Create((TINK.Repository.Response.TariffDescription)null),
#endif
bikeInfo.GetIsDemo(),
bikeInfo.GetGroup());
bikeInfo.GetIsDemo(),
bikeInfo.GetGroup());
default:
throw new ArgumentException($"Unsupported lock type {lockType} detected.");
}
}
catch (ArgumentException ex)
{
// Contructor reported invalid arguemts (missing lock id, ....).
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Invalid response detected. Available bike with id {bikeInfo.bike} skipped. {ex.Message}");
return null;
}
}
default:
throw new ArgumentException($"Unsupported lock type {lockType} detected.");
}
}
catch (ArgumentException ex)
{
// Contructor reported invalid arguemts (missing lock id, ....).
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Invalid response detected. Available bike with id {bikeInfo.bike} skipped. {ex.Message}");
return null;
}
}
/// <summary> Creates a bike info object from copri response. </summary>
/// <param name="bikeInfo">Copri response. </param>
/// <param name="mailAddress">Mail address of user.</param>
/// <param name="dateTimeProvider">Date and time provider function.</param>
public static BikeInfo Create(
BikeInfoReservedOrBooked bikeInfo,
string mailAddress,
Func<DateTime> dateTimeProvider)
{
if (bikeInfo == null) throw new ArgumentNullException(nameof(bikeInfo));
/// <summary> Creates a bike info object from copri response. </summary>
/// <param name="bikeInfo">Copri response. </param>
/// <param name="mailAddress">Mail address of user.</param>
/// <param name="dateTimeProvider">Date and time provider function.</param>
public static BikeInfo Create(
BikeInfoReservedOrBooked bikeInfo,
string mailAddress,
Func<DateTime> dateTimeProvider)
{
if (bikeInfo == null) throw new ArgumentNullException(nameof(bikeInfo));
var lockModel = bikeInfo.GetLockModel();
var lockModel = bikeInfo.GetLockModel();
if (lockModel.HasValue
&& lockModel.Value == LockModel.BordComputer)
{
// Manual lock bikes are no more supported.
Log.Error(
$"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. " +
"Manual lock bikes are no more supported." +
$"Bike number: {bikeInfo.bike}{(bikeInfo.station != null ? $", station number {bikeInfo.station}" : string.Empty)}."
);
return null;
}
if (lockModel.HasValue
&& lockModel.Value == LockModel.BordComputer)
{
// Manual lock bikes are no more supported.
Log.Error(
$"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. " +
"Manual lock bikes are no more supported." +
$"Bike number: {bikeInfo.bike}{(bikeInfo.station != null ? $", station number {bikeInfo.station}" : string.Empty)}."
);
return null;
}
var lockType = lockModel.HasValue
? BikeExtension.GetLockType(lockModel.Value)
: BikeExtension.GetLockType(DEFAULTLOCKMODEL); // Map bikes without "system"- entry in response to backend- locks.
var lockType = lockModel.HasValue
? BikeExtension.GetLockType(lockModel.Value)
: BikeExtension.GetLockType(DEFAULTLOCKMODEL); // Map bikes without "system"- entry in response to backend- locks.
// Check if bike is a bluetooth lock bike.
int lockSerial = bikeInfo.GetBluetoothLockId();
Guid lockGuid = bikeInfo.GetBluetoothLockGuid();
// Check if bike is a bluetooth lock bike.
int lockSerial = bikeInfo.GetBluetoothLockId();
Guid lockGuid = bikeInfo.GetBluetoothLockGuid();
switch (bikeInfo.GetState())
{
case InUseStateEnum.Reserved:
try
{
switch (lockType)
{
case LockType.Bluethooth:
return new Bikes.BikeInfoNS.BluetoothLock.BikeInfo(
new Bike(
bikeInfo.bike,
LockModel.ILockIt,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
lockSerial,
lockGuid,
bikeInfo.GetUserKey(),
bikeInfo.GetAdminKey(),
bikeInfo.GetSeed(),
bikeInfo.GetFrom(),
mailAddress,
bikeInfo.station,
bikeInfo.GetOperatorUri(),
switch (bikeInfo.GetState())
{
case InUseStateEnum.Reserved:
try
{
switch (lockType)
{
case LockType.Bluethooth:
return new Bikes.BikeInfoNS.BluetoothLock.BikeInfo(
new Bike(
bikeInfo.bike,
LockModel.ILockIt,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
lockSerial,
lockGuid,
bikeInfo.GetUserKey(),
bikeInfo.GetAdminKey(),
bikeInfo.GetSeed(),
bikeInfo.GetFrom(),
mailAddress,
bikeInfo.station,
bikeInfo.GetOperatorUri(),
#if !NOTARIFFDESCRIPTION
bikeInfo.rental_description != null
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
bikeInfo.rental_description != null
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
#else
Create((TINK.Repository.Response.TariffDescription)null),
#endif
dateTimeProvider,
bikeInfo.GetIsDemo(),
bikeInfo.GetGroup());
dateTimeProvider,
bikeInfo.GetIsDemo(),
bikeInfo.GetGroup());
case LockType.Backend:
return new Bikes.BikeInfoNS.CopriLock.BikeInfo(
new Bike(
bikeInfo.bike,
LockModel.Sigo,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
bikeInfo.GetFrom(),
mailAddress,
bikeInfo.station,
new Bikes.BikeInfoNS.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState() }.Build(),
bikeInfo.GetOperatorUri(),
case LockType.Backend:
return new Bikes.BikeInfoNS.CopriLock.BikeInfo(
new Bike(
bikeInfo.bike,
LockModel.Sigo,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
bikeInfo.GetFrom(),
mailAddress,
bikeInfo.station,
new Bikes.BikeInfoNS.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState() }.Build(),
bikeInfo.GetOperatorUri(),
#if !NOTARIFFDESCRIPTION
bikeInfo.rental_description != null
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
bikeInfo.rental_description != null
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
#else
Create((TINK.Repository.Response.TariffDescription)null),
#endif
dateTimeProvider,
bikeInfo.GetIsDemo(),
bikeInfo.GetGroup());
default:
throw new ArgumentException($"Unsupported lock type {lockType} detected.");
}
}
catch (ArgumentException ex)
{
// Contructor reported invalid arguemts (missing lock id, ....).
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoReservedOrBooked)} argument. Invalid response detected. Reserved bike with id {bikeInfo.bike} skipped. {ex.Message}");
return null;
}
dateTimeProvider,
bikeInfo.GetIsDemo(),
bikeInfo.GetGroup());
default:
throw new ArgumentException($"Unsupported lock type {lockType} detected.");
}
}
catch (ArgumentException ex)
{
// Contructor reported invalid arguemts (missing lock id, ....).
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoReservedOrBooked)} argument. Invalid response detected. Reserved bike with id {bikeInfo.bike} skipped. {ex.Message}");
return null;
}
case InUseStateEnum.Booked:
try
{
switch (lockModel)
{
case LockModel.ILockIt:
return new Bikes.BikeInfoNS.BluetoothLock.BikeInfo(
new Bike(
bikeInfo.bike,
LockModel.ILockIt,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
lockSerial,
bikeInfo.GetBluetoothLockGuid(),
bikeInfo.GetUserKey(),
bikeInfo.GetAdminKey(),
bikeInfo.GetSeed(),
bikeInfo.GetFrom(),
mailAddress,
bikeInfo.station,
bikeInfo.GetOperatorUri(),
case InUseStateEnum.Booked:
try
{
switch (lockModel)
{
case LockModel.ILockIt:
return new Bikes.BikeInfoNS.BluetoothLock.BikeInfo(
new Bike(
bikeInfo.bike,
LockModel.ILockIt,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
lockSerial,
bikeInfo.GetBluetoothLockGuid(),
bikeInfo.GetUserKey(),
bikeInfo.GetAdminKey(),
bikeInfo.GetSeed(),
bikeInfo.GetFrom(),
mailAddress,
bikeInfo.station,
bikeInfo.GetOperatorUri(),
#if !NOTARIFFDESCRIPTION
bikeInfo.rental_description != null
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
bikeInfo.rental_description != null
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
#else
Create((TINK.Repository.Response.TariffDescription)null),
#endif
bikeInfo.GetIsDemo(),
bikeInfo.GetGroup());
bikeInfo.GetIsDemo(),
bikeInfo.GetGroup());
case LockModel.BordComputer:
return new BikeInfo(
new Bike(
bikeInfo.bike,
LockModel.BordComputer,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
bikeInfo.GetIsDemo(),
bikeInfo.GetGroup(),
bikeInfo.station,
bikeInfo.GetOperatorUri(),
case LockModel.BordComputer:
return new BikeInfo(
new Bike(
bikeInfo.bike,
LockModel.BordComputer,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
bikeInfo.GetIsDemo(),
bikeInfo.GetGroup(),
bikeInfo.station,
bikeInfo.GetOperatorUri(),
#if !NOTARIFFDESCRIPTION
bikeInfo.rental_description != null
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
bikeInfo.rental_description != null
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
#else
Create((TINK.Repository.Response.TariffDescription)null),
#endif
bikeInfo.GetFrom(),
mailAddress,
bikeInfo.timeCode);
default:
return new Bikes.BikeInfoNS.CopriLock.BikeInfo(
new Bike(
bikeInfo.bike,
LockModel.Sigo,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
bikeInfo.GetFrom(),
mailAddress,
bikeInfo.station,
new Bikes.BikeInfoNS.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState() }.Build(),
bikeInfo.GetOperatorUri(),
bikeInfo.GetFrom(),
mailAddress,
bikeInfo.timeCode);
default:
return new Bikes.BikeInfoNS.CopriLock.BikeInfo(
new Bike(
bikeInfo.bike,
LockModel.Sigo,
bikeInfo.GetWheelType(),
bikeInfo.GetTypeOfBike(),
bikeInfo.description),
DriveFactory.Create(bikeInfo?.bike_type),
bikeInfo.GetFrom(),
mailAddress,
bikeInfo.station,
new Bikes.BikeInfoNS.CopriLock.LockInfo.Builder { State = bikeInfo.GetCopriLockingState() }.Build(),
bikeInfo.GetOperatorUri(),
#if !NOTARIFFDESCRIPTION
bikeInfo.rental_description != null
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
bikeInfo.rental_description != null
? RentalDescriptionFactory.Create(bikeInfo.rental_description)
: TariffDescriptionFactory.Create(bikeInfo.tariff_description),
#else
Create((TINK.Repository.Response.TariffDescription)null),
#endif
bikeInfo.GetIsDemo(),
bikeInfo.GetGroup());
}
}
catch (ArgumentException ex)
{
// Contructor reported invalid arguemts (missing lock id, ....).
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoReservedOrBooked)} argument. Invalid response detected. Booked bike with id {bikeInfo.bike} skipped. {ex.Message}");
return null;
}
bikeInfo.GetIsDemo(),
bikeInfo.GetGroup());
}
}
catch (ArgumentException ex)
{
// Contructor reported invalid arguemts (missing lock id, ....).
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoReservedOrBooked)} argument. Invalid response detected. Booked bike with id {bikeInfo.bike} skipped. {ex.Message}");
return null;
}
default:
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Unexpected state {bikeInfo.GetState()} detected.");
return null;
}
}
}
default:
Log.Error($"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Unexpected state {bikeInfo.GetState()} detected.");
return null;
}
}
}
}

View file

@ -5,46 +5,46 @@ using TINK.Repository.Response;
namespace TINK.Model.Connector.Updater
{
public static class BookingFinishedModelFactory
{
/// <summary> Creates a booking finished object from response.</summary>
/// <param name="response">Response to create survey object from.</param>
public static BookingFinishedModel Create(this DoReturnResponse response)
{
var bookingFinished = new BookingFinishedModel
{
Co2Saving = response?.co2saving
};
public static class BookingFinishedModelFactory
{
/// <summary> Creates a booking finished object from response.</summary>
/// <param name="response">Response to create survey object from.</param>
public static BookingFinishedModel Create(this DoReturnResponse response)
{
var bookingFinished = new BookingFinishedModel
{
Co2Saving = response?.co2saving
};
if (response?.user_miniquery == null)
if (response?.user_miniquery == null)
{
return bookingFinished;
}
{
return bookingFinished;
}
var miniquery = response.user_miniquery;
bookingFinished.MiniSurvey = new MiniSurveyModel
{
Title = miniquery.title,
Subtitle = miniquery.subtitle,
Footer = miniquery.footer
};
var miniquery = response.user_miniquery;
bookingFinished.MiniSurvey = new MiniSurveyModel
{
Title = miniquery.title,
Subtitle = miniquery.subtitle,
Footer = miniquery.footer
};
foreach (var question in miniquery?.questions?.OrderBy(x => x.Key) ?? new Dictionary<string, MiniSurveyResponse.Question>().OrderBy(x => x.Key))
{
if (string.IsNullOrEmpty(question.Key.Trim())
|| question.Value.query == null)
{
// Skip invalid entries.
continue;
}
foreach (var question in miniquery?.questions?.OrderBy(x => x.Key) ?? new Dictionary<string, MiniSurveyResponse.Question>().OrderBy(x => x.Key))
{
if (string.IsNullOrEmpty(question.Key.Trim())
|| question.Value.query == null)
{
// Skip invalid entries.
continue;
}
bookingFinished.MiniSurvey.Questions.Add(
question.Key,
new QuestionModel());
}
bookingFinished.MiniSurvey.Questions.Add(
question.Key,
new QuestionModel());
}
return bookingFinished;
}
}
return bookingFinished;
}
}
}

View file

@ -5,41 +5,41 @@ using TINK.Repository.Response;
namespace TINK.Model.Connector.Updater
{
public static class DriveFactory
{
public static Drive Create(this BikeType bikeType)
{
if (string.IsNullOrEmpty(bikeType?.engine?.manufacturer))
{
// Bike is has no engine
return new Drive();
}
public static class DriveFactory
{
public static Drive Create(this BikeType bikeType)
{
if (string.IsNullOrEmpty(bikeType?.engine?.manufacturer))
{
// Bike is has no engine
return new Drive();
}
// Bike is a pedelec.
return new Drive(
new Engine(bikeType?.engine?.manufacturer),
new Battery.Builder
{
CurrentChargePercent = double.TryParse(bikeType?.battery?.charge_current_percent, out double currentChargePercent)
? currentChargePercent
: double.NaN,
// Bike is a pedelec.
return new Drive(
new Engine(bikeType?.engine?.manufacturer),
new Battery.Builder
{
CurrentChargePercent = double.TryParse(bikeType?.battery?.charge_current_percent, out double currentChargePercent)
? currentChargePercent
: double.NaN,
CurrentChargeBars = int.TryParse(bikeType?.battery?.charge_current_bars, out int currentChargeBars)
? (int?)currentChargeBars
: null,
CurrentChargeBars = int.TryParse(bikeType?.battery?.charge_current_bars, out int currentChargeBars)
? (int?)currentChargeBars
: null,
MaxChargeBars = int.TryParse(bikeType?.battery?.charge_max_bars, out int maxChargeBars)
? (int?)maxChargeBars
: null,
MaxChargeBars = int.TryParse(bikeType?.battery?.charge_max_bars, out int maxChargeBars)
? (int?)maxChargeBars
: null,
IsBackendAccessible = bikeType?.battery?.backend_accessible != null && int.TryParse(bikeType.battery.backend_accessible, out int accessible)
? (bool?)(accessible > 0)
: null,
IsBackendAccessible = bikeType?.battery?.backend_accessible != null && int.TryParse(bikeType.battery.backend_accessible, out int accessible)
? (bool?)(accessible > 0)
: null,
IsHidden = bikeType?.battery?.hidden != null && int.TryParse(bikeType.battery.hidden, out int hidden)
? (bool?)(hidden > 0)
: null
}.Build());
}
}
IsHidden = bikeType?.battery?.hidden != null && int.TryParse(bikeType.battery.hidden, out int hidden)
? (bool?)(hidden > 0)
: null
}.Build());
}
}
}

View file

@ -3,61 +3,61 @@ using System.Linq;
namespace TINK.Model.Connector.Updater
{
public static class RentalDescriptionFactory
{
/// <summary>
/// Creates rental description object from JSON- tarif description object.
/// </summary>
/// <param name="rentalDesciption">Source JSON object.</param>
/// <returns>Tariff description object.</returns>
public static class RentalDescriptionFactory
{
/// <summary>
/// Creates rental description object from JSON- tarif description object.
/// </summary>
/// <param name="rentalDesciption">Source JSON object.</param>
/// <returns>Tariff description object.</returns>
public static Bikes.BikeInfoNS.RentalDescription Create(this Repository.Response.RentalDescription rentalDesciption)
{
Bikes.BikeInfoNS.RentalDescription.TariffElement CreateTarifEntry(string[] elementValue)
{
return new Bikes.BikeInfoNS.RentalDescription.TariffElement
{
Description = elementValue != null && elementValue.Length > 0 ? elementValue[0] : string.Empty,
Value = elementValue != null && elementValue.Length > 1 ? elementValue[1] : string.Empty,
};
}
public static Bikes.BikeInfoNS.RentalDescription Create(this Repository.Response.RentalDescription rentalDesciption)
{
Bikes.BikeInfoNS.RentalDescription.TariffElement CreateTarifEntry(string[] elementValue)
{
return new Bikes.BikeInfoNS.RentalDescription.TariffElement
{
Description = elementValue != null && elementValue.Length > 0 ? elementValue[0] : string.Empty,
Value = elementValue != null && elementValue.Length > 1 ? elementValue[1] : string.Empty,
};
}
Bikes.BikeInfoNS.RentalDescription.InfoElement CreateInfoElement(string[] elementValue)
{
return new Bikes.BikeInfoNS.RentalDescription.InfoElement
{
Key = elementValue != null && elementValue.Length > 0 ? elementValue[0] : string.Empty,
Value = elementValue != null && elementValue.Length > 1 ? elementValue[1] : string.Empty,
};
}
Bikes.BikeInfoNS.RentalDescription.InfoElement CreateInfoElement(string[] elementValue)
{
return new Bikes.BikeInfoNS.RentalDescription.InfoElement
{
Key = elementValue != null && elementValue.Length > 0 ? elementValue[0] : string.Empty,
Value = elementValue != null && elementValue.Length > 1 ? elementValue[1] : string.Empty,
};
}
// Read tariff elements.
var tarifEntries = rentalDesciption?.tarif_elements != null
? rentalDesciption.tarif_elements.Select(x => new
{
Key = x.Key,
Value = CreateTarifEntry(x.Value)
}).ToLookup(x => x.Key, x => x.Value).ToDictionary(x => x.Key, x => x.First())
: new Dictionary<string, Bikes.BikeInfoNS.RentalDescription.TariffElement>();
// Read tariff elements.
var tarifEntries = rentalDesciption?.tarif_elements != null
? rentalDesciption.tarif_elements.Select(x => new
{
Key = x.Key,
Value = CreateTarifEntry(x.Value)
}).ToLookup(x => x.Key, x => x.Value).ToDictionary(x => x.Key, x => x.First())
: new Dictionary<string, Bikes.BikeInfoNS.RentalDescription.TariffElement>();
// Read info elements.
var InfoEntries = rentalDesciption?.rental_info != null
? rentalDesciption.rental_info.Select(x => new
{
Key = x.Key,
Value = CreateInfoElement(x.Value)
}).ToLookup(x => x.Key, x => x.Value).ToDictionary(x => x.Key, x => x.First())
: new Dictionary<string, Bikes.BikeInfoNS.RentalDescription.InfoElement>();
// Read info elements.
var InfoEntries = rentalDesciption?.rental_info != null
? rentalDesciption.rental_info.Select(x => new
{
Key = x.Key,
Value = CreateInfoElement(x.Value)
}).ToLookup(x => x.Key, x => x.Value).ToDictionary(x => x.Key, x => x.First())
: new Dictionary<string, Bikes.BikeInfoNS.RentalDescription.InfoElement>();
var bike = new Bikes.BikeInfoNS.RentalDescription
{
Name = rentalDesciption?.name ?? string.Empty,
Id = int.TryParse(rentalDesciption?.id ?? string.Empty, out int number) ? number : (int?)null,
TariffEntries = tarifEntries,
InfoEntries = InfoEntries
};
var bike = new Bikes.BikeInfoNS.RentalDescription
{
Name = rentalDesciption?.name ?? string.Empty,
Id = int.TryParse(rentalDesciption?.id ?? string.Empty, out int number) ? number : (int?)null,
TariffEntries = tarifEntries,
InfoEntries = InfoEntries
};
return bike;
}
}
return bike;
}
}
}

View file

@ -4,77 +4,77 @@ using TINK.Repository.Response;
namespace TINK.Model.Connector.Updater
{
public static class TariffDescriptionFactory
{
/// <summary>
/// Creates rental description object from JSON- tarif description object.
/// </summary>
/// <param name="tariffDesciption">Source JSON object.</param>
/// <returns>Tariff description object.</returns>
public static Bikes.BikeInfoNS.RentalDescription Create(this TariffDescription tariffDesciption)
{
var bike = new Bikes.BikeInfoNS.RentalDescription
{
Name = tariffDesciption?.name,
public static class TariffDescriptionFactory
{
/// <summary>
/// Creates rental description object from JSON- tarif description object.
/// </summary>
/// <param name="tariffDesciption">Source JSON object.</param>
/// <returns>Tariff description object.</returns>
public static Bikes.BikeInfoNS.RentalDescription Create(this TariffDescription tariffDesciption)
{
var bike = new Bikes.BikeInfoNS.RentalDescription
{
Name = tariffDesciption?.name,
#if USCSHARP9
Number = int.TryParse(tariffDesciption?.number, out int number) ? number : null,
#else
Id = int.TryParse(tariffDesciption?.number, out int number) ? number : (int?)null,
Id = int.TryParse(tariffDesciption?.number, out int number) ? number : (int?)null,
#endif
};
};
if (!string.IsNullOrEmpty(tariffDesciption?.free_hours)
&& double.TryParse(tariffDesciption?.free_hours, NumberStyles.Any, CultureInfo.InvariantCulture, out double freeHours))
{
// Free time. Unit hours,format floating point number.
bike.TariffEntries.Add("1", new Bikes.BikeInfoNS.RentalDescription.TariffElement
{
Description = AppResources.MessageBikesManagementTariffDescriptionFreeTimePerSession,
Value = string.Format("{0} {1}", freeHours.ToString("0.00"), AppResources.MessageBikesManagementTariffDescriptionHour)
});
}
if (!string.IsNullOrEmpty(tariffDesciption?.free_hours)
&& double.TryParse(tariffDesciption?.free_hours, NumberStyles.Any, CultureInfo.InvariantCulture, out double freeHours))
{
// Free time. Unit hours,format floating point number.
bike.TariffEntries.Add("1", new Bikes.BikeInfoNS.RentalDescription.TariffElement
{
Description = AppResources.MessageBikesManagementTariffDescriptionFreeTimePerSession,
Value = string.Format("{0} {1}", freeHours.ToString("0.00"), AppResources.MessageBikesManagementTariffDescriptionHour)
});
}
if (!string.IsNullOrEmpty(tariffDesciption?.eur_per_hour)
&& double.TryParse(tariffDesciption?.eur_per_hour, NumberStyles.Any, CultureInfo.InvariantCulture, out double euroPerHour))
{
// Euro per hour. Format floating point.
bike.TariffEntries.Add("2", new Bikes.BikeInfoNS.RentalDescription.TariffElement
{
Description = AppResources.MessageBikesManagementTariffDescriptionFeeEuroPerHour,
Value = string.Format("{0} {1}", euroPerHour.ToString("0.00"), AppResources.MessageBikesManagementTariffDescriptionEuroPerHour)
});
}
if (!string.IsNullOrEmpty(tariffDesciption?.eur_per_hour)
&& double.TryParse(tariffDesciption?.eur_per_hour, NumberStyles.Any, CultureInfo.InvariantCulture, out double euroPerHour))
{
// Euro per hour. Format floating point.
bike.TariffEntries.Add("2", new Bikes.BikeInfoNS.RentalDescription.TariffElement
{
Description = AppResources.MessageBikesManagementTariffDescriptionFeeEuroPerHour,
Value = string.Format("{0} {1}", euroPerHour.ToString("0.00"), AppResources.MessageBikesManagementTariffDescriptionEuroPerHour)
});
}
if (!string.IsNullOrEmpty(tariffDesciption?.max_eur_per_day)
&& double.TryParse(tariffDesciption.max_eur_per_day, NumberStyles.Any, CultureInfo.InvariantCulture, out double maxEuroPerDay))
{
// Max euro per day. Format floating point.
bike.TariffEntries.Add("3", new Bikes.BikeInfoNS.RentalDescription.TariffElement
{
Description = AppResources.MessageBikesManagementTariffDescriptionMaxFeeEuroPerDay,
Value = string.Format("{0} {1}", maxEuroPerDay.ToString("0.00"), AppResources.MessageBikesManagementMaxFeeEuroPerDay)
});
}
if (!string.IsNullOrEmpty(tariffDesciption?.max_eur_per_day)
&& double.TryParse(tariffDesciption.max_eur_per_day, NumberStyles.Any, CultureInfo.InvariantCulture, out double maxEuroPerDay))
{
// Max euro per day. Format floating point.
bike.TariffEntries.Add("3", new Bikes.BikeInfoNS.RentalDescription.TariffElement
{
Description = AppResources.MessageBikesManagementTariffDescriptionMaxFeeEuroPerDay,
Value = string.Format("{0} {1}", maxEuroPerDay.ToString("0.00"), AppResources.MessageBikesManagementMaxFeeEuroPerDay)
});
}
if (!string.IsNullOrEmpty(tariffDesciption?.abo_eur_per_month)
&& double.TryParse(tariffDesciption.abo_eur_per_month, NumberStyles.Any, CultureInfo.InvariantCulture, out double aboEuroPerMonth))
{
// Abo per month
bike.TariffEntries.Add("4", new Bikes.BikeInfoNS.RentalDescription.TariffElement
{
Description = AppResources.MessageBikesManagementTariffDescriptionAboEuroPerMonth,
Value = string.Format("{0} {1}", aboEuroPerMonth.ToString("0.00"), AppResources.MessageBikesManagementTariffDescriptionEuroPerMonth)
});
}
if (!string.IsNullOrEmpty(tariffDesciption?.abo_eur_per_month)
&& double.TryParse(tariffDesciption.abo_eur_per_month, NumberStyles.Any, CultureInfo.InvariantCulture, out double aboEuroPerMonth))
{
// Abo per month
bike.TariffEntries.Add("4", new Bikes.BikeInfoNS.RentalDescription.TariffElement
{
Description = AppResources.MessageBikesManagementTariffDescriptionAboEuroPerMonth,
Value = string.Format("{0} {1}", aboEuroPerMonth.ToString("0.00"), AppResources.MessageBikesManagementTariffDescriptionEuroPerMonth)
});
}
if (!string.IsNullOrEmpty(tariffDesciption?.operator_agb ?? string.Empty))
{
bike.InfoEntries.Add("1", new Bikes.BikeInfoNS.RentalDescription.InfoElement { Key = "AGB", Value = tariffDesciption.operator_agb });
}
if (!string.IsNullOrEmpty(tariffDesciption?.operator_agb ?? string.Empty))
{
bike.InfoEntries.Add("1", new Bikes.BikeInfoNS.RentalDescription.InfoElement { Key = "AGB", Value = tariffDesciption.operator_agb });
}
return bike;
}
return bike;
}
}
}
}

View file

@ -15,268 +15,268 @@ using IBikeInfoMutable = TINK.Model.Bikes.BikeInfoNS.BC.IBikeInfoMutable;
namespace TINK.Model.Connector.Updater
{
/// <summary>
/// Connects TINK app to copri using JSON as input data format.
/// </summary>
/// <todo>Rename to UpdateFromCopri.</todo>
public static class UpdaterJSON
{
/// <summary> Loads a bike object from copri server cancel reservation/ booking update request.</summary>
/// <param name="bike">Bike object to load response into.</param>
/// <param name="notifyLevel">Controls whether notify property changed events are fired or not.</param>
public static void Load(
this IBikeInfoMutable bike,
Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel notifyLevel)
{
/// <summary>
/// Connects TINK app to copri using JSON as input data format.
/// </summary>
/// <todo>Rename to UpdateFromCopri.</todo>
public static class UpdaterJSON
{
/// <summary> Loads a bike object from copri server cancel reservation/ booking update request.</summary>
/// <param name="bike">Bike object to load response into.</param>
/// <param name="notifyLevel">Controls whether notify property changed events are fired or not.</param>
public static void Load(
this IBikeInfoMutable bike,
Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel notifyLevel)
{
bike.State.Load(InUseStateEnum.Disposable, notifyLevel: notifyLevel);
}
bike.State.Load(InUseStateEnum.Disposable, notifyLevel: notifyLevel);
}
/// <summary>
/// Gets all statsion for station provider and add them into station list.
/// </summary>
/// <param name="p_oStationList">List of stations to update.</param>
public static StationDictionary GetStationsAllMutable(this StationsAvailableResponse stationsAllResponse)
{
// Get stations from Copri/ file/ memory, ....
if (stationsAllResponse == null
|| stationsAllResponse.stations == null)
{
// Latest list of stations could not be retrieved from provider.
return new StationDictionary();
}
/// <summary>
/// Gets all statsion for station provider and add them into station list.
/// </summary>
/// <param name="p_oStationList">List of stations to update.</param>
public static StationDictionary GetStationsAllMutable(this StationsAvailableResponse stationsAllResponse)
{
// Get stations from Copri/ file/ memory, ....
if (stationsAllResponse == null
|| stationsAllResponse.stations == null)
{
// Latest list of stations could not be retrieved from provider.
return new StationDictionary();
}
Version.TryParse(stationsAllResponse.copri_version, out Version copriVersion);
Version.TryParse(stationsAllResponse.copri_version, out Version copriVersion);
var stations = new StationDictionary(p_oVersion: copriVersion);
var stations = new StationDictionary(p_oVersion: copriVersion);
foreach (var station in stationsAllResponse.stations)
{
if (stations.GetById(station.Value.station) != null)
{
// Can not add station to list of station. Id is not unique.
throw new InvalidResponseException<StationsAvailableResponse>(
string.Format("Station id {0} is not unique.", station.Value.station), stationsAllResponse);
}
foreach (var station in stationsAllResponse.stations)
{
if (stations.GetById(station.Value.station) != null)
{
// Can not add station to list of station. Id is not unique.
throw new InvalidResponseException<StationsAvailableResponse>(
string.Format("Station id {0} is not unique.", station.Value.station), stationsAllResponse);
}
stations.Add(new Station.Station(
station.Value.station,
station.Value.GetGroup(),
station.Value.GetPosition(),
station.Value.description,
new Data(station.Value.operator_data?.operator_name,
station.Value.operator_data?.operator_phone,
station.Value.operator_data?.operator_hours,
station.Value.operator_data?.operator_email,
!string.IsNullOrEmpty(station.Value.operator_data?.operator_color)
? Color.FromHex(station.Value.operator_data?.operator_color)
: (Color?)null)));
}
stations.Add(new Station.Station(
station.Value.station,
station.Value.GetGroup(),
station.Value.GetPosition(),
station.Value.description,
new Data(station.Value.operator_data?.operator_name,
station.Value.operator_data?.operator_phone,
station.Value.operator_data?.operator_hours,
station.Value.operator_data?.operator_email,
!string.IsNullOrEmpty(station.Value.operator_data?.operator_color)
? Color.FromHex(station.Value.operator_data?.operator_color)
: (Color?)null)));
}
return stations;
}
return stations;
}
/// <summary>
/// Gets general data from COPRI response.
/// </summary>
/// <param name="response">Response to get data from.</param>
/// <returns>General data object initialized form COPRI response.</returns>
public static GeneralData GetGeneralData(this ResponseBase response)
=> new GeneralData(
response.init_map.GetMapSpan(),
response.merchant_message,
response.TryGetCopriVersion(out Version copriVersion)
? new Version(0, 0)
: copriVersion,
new ResourceUrls(response.tariff_info_html, response.bike_info_html, response.agb_html, response.privacy_html, response.impress_html));
/// <summary>
/// Gets general data from COPRI response.
/// </summary>
/// <param name="response">Response to get data from.</param>
/// <returns>General data object initialized form COPRI response.</returns>
public static GeneralData GetGeneralData(this ResponseBase response)
=> new GeneralData(
response.init_map.GetMapSpan(),
response.merchant_message,
response.TryGetCopriVersion(out Version copriVersion)
? new Version(0, 0)
: copriVersion,
new ResourceUrls(response.tariff_info_html, response.bike_info_html, response.agb_html, response.privacy_html, response.impress_html));
/// <summary> Gets account object from login response.</summary>
/// <param name="merchantId">Needed to extract cookie from autorization response.</param>
/// <param name="loginResponse">Response to get session cookie and debug level from.</param>
/// <param name="mail">Mail address needed to construct a complete account object (is not part of response).</param>
/// <param name="password">Password needed to construct a complete account object (is not part of response).</param>
public static IAccount GetAccount(
this AuthorizationResponse loginResponse,
string merchantId,
string mail,
string password)
{
if (loginResponse == null)
{
throw new ArgumentNullException(nameof(loginResponse));
}
/// <summary> Gets account object from login response.</summary>
/// <param name="merchantId">Needed to extract cookie from autorization response.</param>
/// <param name="loginResponse">Response to get session cookie and debug level from.</param>
/// <param name="mail">Mail address needed to construct a complete account object (is not part of response).</param>
/// <param name="password">Password needed to construct a complete account object (is not part of response).</param>
public static IAccount GetAccount(
this AuthorizationResponse loginResponse,
string merchantId,
string mail,
string password)
{
if (loginResponse == null)
{
throw new ArgumentNullException(nameof(loginResponse));
}
return new Account(
mail,
password,
loginResponse.GetIsAgbAcknowledged(),
loginResponse.authcookie?.Replace(merchantId, ""),
loginResponse.GetGroup(),
loginResponse.debuglevel == 1
? Permissions.All :
(Permissions)loginResponse.debuglevel);
}
return new Account(
mail,
password,
loginResponse.GetIsAgbAcknowledged(),
loginResponse.authcookie?.Replace(merchantId, ""),
loginResponse.GetGroup(),
loginResponse.debuglevel == 1
? Permissions.All :
(Permissions)loginResponse.debuglevel);
}
/// <summary> Load bike object from booking response. </summary>
/// <param name="bike">Bike object to load from response.</param>
/// <param name="bikeInfo">Booking response.</param>
/// <param name="mailAddress">Mail address of user which books bike.</param>
/// <param name="notifyLevel">Controls whether notify property changed events are fired or not.</param>
public static void Load(
this IBikeInfoMutable bike,
BikeInfoReservedOrBooked bikeInfo,
string mailAddress,
Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel notifyLevel = Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.All)
{
if (bike is Bikes.BikeInfoNS.BluetoothLock.BikeInfoMutable btBikeInfo)
{
btBikeInfo.LockInfo.Load(
bikeInfo.GetBluetoothLockId(),
bikeInfo.GetBluetoothLockGuid(),
bikeInfo.GetSeed(),
bikeInfo.GetUserKey(),
bikeInfo.GetAdminKey());
}
/// <summary> Load bike object from booking response. </summary>
/// <param name="bike">Bike object to load from response.</param>
/// <param name="bikeInfo">Booking response.</param>
/// <param name="mailAddress">Mail address of user which books bike.</param>
/// <param name="notifyLevel">Controls whether notify property changed events are fired or not.</param>
public static void Load(
this IBikeInfoMutable bike,
BikeInfoReservedOrBooked bikeInfo,
string mailAddress,
Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel notifyLevel = Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.All)
{
if (bike is Bikes.BikeInfoNS.BluetoothLock.BikeInfoMutable btBikeInfo)
{
btBikeInfo.LockInfo.Load(
bikeInfo.GetBluetoothLockId(),
bikeInfo.GetBluetoothLockGuid(),
bikeInfo.GetSeed(),
bikeInfo.GetUserKey(),
bikeInfo.GetAdminKey());
}
var l_oState = bikeInfo.GetState();
switch (l_oState)
{
case InUseStateEnum.Disposable:
bike.State.Load(
InUseStateEnum.Disposable,
notifyLevel: notifyLevel);
break;
var l_oState = bikeInfo.GetState();
switch (l_oState)
{
case InUseStateEnum.Disposable:
bike.State.Load(
InUseStateEnum.Disposable,
notifyLevel: notifyLevel);
break;
case InUseStateEnum.Reserved:
bike.State.Load(
InUseStateEnum.Reserved,
bikeInfo.GetFrom(),
mailAddress,
bikeInfo.timeCode,
notifyLevel);
break;
case InUseStateEnum.Reserved:
bike.State.Load(
InUseStateEnum.Reserved,
bikeInfo.GetFrom(),
mailAddress,
bikeInfo.timeCode,
notifyLevel);
break;
case InUseStateEnum.Booked:
bike.State.Load(
InUseStateEnum.Booked,
bikeInfo.GetFrom(),
mailAddress,
bikeInfo.timeCode,
notifyLevel);
break;
case InUseStateEnum.Booked:
bike.State.Load(
InUseStateEnum.Booked,
bikeInfo.GetFrom(),
mailAddress,
bikeInfo.timeCode,
notifyLevel);
break;
default:
throw new Exception(string.Format("Unexpected bike state detected. state is {0}.", l_oState));
}
}
default:
throw new Exception(string.Format("Unexpected bike state detected. state is {0}.", l_oState));
}
}
/// <summary> Gets bikes available from copri server response.</summary>
/// <param name="bikesAvailableResponse">Response to create collection from.</param>
/// <returns>New collection of available bikes.</returns>
public static BikeCollection GetBikesAvailable(
this BikesAvailableResponse bikesAvailableResponse)
=> GetBikesAll(
bikesAvailableResponse?.bikes?.Values,
new BikesReservedOccupiedResponse()?.bikes_occupied?.Values, // There are no occupied bikes.
string.Empty,
() => DateTime.Now);
/// <summary> Gets bikes available from copri server response.</summary>
/// <param name="bikesAvailableResponse">Response to create collection from.</param>
/// <returns>New collection of available bikes.</returns>
public static BikeCollection GetBikesAvailable(
this BikesAvailableResponse bikesAvailableResponse)
=> GetBikesAll(
bikesAvailableResponse?.bikes?.Values,
new BikesReservedOccupiedResponse()?.bikes_occupied?.Values, // There are no occupied bikes.
string.Empty,
() => DateTime.Now);
/// <summary> Gets bikes occupied from copri server response. </summary>
/// <param name="p_oBikesAvailable">Response to create bikes from.</param>
/// <returns>New collection of occupied bikes.</returns>
public static BikeCollection GetBikesOccupied(
this BikesReservedOccupiedResponse bikesOccupiedResponse,
string mail,
Func<DateTime> dateTimeProvider)
{
return GetBikesAll(
new BikesAvailableResponse()?.bikes?.Values,
bikesOccupiedResponse?.bikes_occupied?.Values,
mail,
dateTimeProvider);
}
/// <summary> Gets bikes occupied from copri server response. </summary>
/// <param name="p_oBikesAvailable">Response to create bikes from.</param>
/// <returns>New collection of occupied bikes.</returns>
public static BikeCollection GetBikesOccupied(
this BikesReservedOccupiedResponse bikesOccupiedResponse,
string mail,
Func<DateTime> dateTimeProvider)
{
return GetBikesAll(
new BikesAvailableResponse()?.bikes?.Values,
bikesOccupiedResponse?.bikes_occupied?.Values,
mail,
dateTimeProvider);
}
/// <summary> Gets bikes occupied from copri server response. </summary>
/// <param name="bikesAvailable">Response to create bikes available from.</param>
/// <param name="bikesOccupied">Response to create bikes occupied from.</param>
/// <returns>New collection of occupied bikes.</returns>
public static BikeCollection GetBikesAll(
IEnumerable<BikeInfoAvailable> bikesAvailable,
IEnumerable<BikeInfoReservedOrBooked> bikesOccupied,
string mail,
Func<DateTime> dateTimeProvider)
{
var bikesDictionary = new Dictionary<string, BikeInfo>();
var duplicates = new Dictionary<string, BikeInfo>();
/// <summary> Gets bikes occupied from copri server response. </summary>
/// <param name="bikesAvailable">Response to create bikes available from.</param>
/// <param name="bikesOccupied">Response to create bikes occupied from.</param>
/// <returns>New collection of occupied bikes.</returns>
public static BikeCollection GetBikesAll(
IEnumerable<BikeInfoAvailable> bikesAvailable,
IEnumerable<BikeInfoReservedOrBooked> bikesOccupied,
string mail,
Func<DateTime> dateTimeProvider)
{
var bikesDictionary = new Dictionary<string, BikeInfo>();
var duplicates = new Dictionary<string, BikeInfo>();
// Get bikes from Copri/ file/ memory, ....
if (bikesAvailable != null)
{
foreach (var bikeInfoResponse in bikesAvailable)
{
var bikeInfo = BikeInfoFactory.Create(bikeInfoResponse);
if (bikeInfo == null)
{
// Response is not valid.
continue;
}
// Get bikes from Copri/ file/ memory, ....
if (bikesAvailable != null)
{
foreach (var bikeInfoResponse in bikesAvailable)
{
var bikeInfo = BikeInfoFactory.Create(bikeInfoResponse);
if (bikeInfo == null)
{
// Response is not valid.
continue;
}
if (bikesDictionary.ContainsKey(bikeInfo.Id))
{
// Duplicates are not allowed.
Log.Error($"Duplicate bike with id {bikeInfo.Id} detected evaluating bikes available. Bike status is {bikeInfo.State.Value}.");
if (bikesDictionary.ContainsKey(bikeInfo.Id))
{
// Duplicates are not allowed.
Log.Error($"Duplicate bike with id {bikeInfo.Id} detected evaluating bikes available. Bike status is {bikeInfo.State.Value}.");
if (!duplicates.ContainsKey(bikeInfo.Id))
{
duplicates.Add(bikeInfo.Id, bikeInfo);
}
if (!duplicates.ContainsKey(bikeInfo.Id))
{
duplicates.Add(bikeInfo.Id, bikeInfo);
}
continue;
}
continue;
}
bikesDictionary.Add(bikeInfo.Id, bikeInfo);
}
}
bikesDictionary.Add(bikeInfo.Id, bikeInfo);
}
}
// Get bikes from Copri/ file/ memory, ....
if (bikesOccupied != null)
{
foreach (var bikeInfoResponse in bikesOccupied)
{
BikeInfo bikeInfo = BikeInfoFactory.Create(
bikeInfoResponse,
mail,
dateTimeProvider);
// Get bikes from Copri/ file/ memory, ....
if (bikesOccupied != null)
{
foreach (var bikeInfoResponse in bikesOccupied)
{
BikeInfo bikeInfo = BikeInfoFactory.Create(
bikeInfoResponse,
mail,
dateTimeProvider);
if (bikeInfo == null)
{
continue;
}
if (bikeInfo == null)
{
continue;
}
if (bikesDictionary.ContainsKey(bikeInfo.Id))
{
// Duplicates are not allowed.
Log.Error($"Duplicate bike with id {bikeInfo.Id} detected evaluating bikes occupied. Bike status is {bikeInfo.State.Value}.");
if (!duplicates.ContainsKey(bikeInfo.Id))
{
duplicates.Add(bikeInfo.Id, bikeInfo);
}
if (bikesDictionary.ContainsKey(bikeInfo.Id))
{
// Duplicates are not allowed.
Log.Error($"Duplicate bike with id {bikeInfo.Id} detected evaluating bikes occupied. Bike status is {bikeInfo.State.Value}.");
if (!duplicates.ContainsKey(bikeInfo.Id))
{
duplicates.Add(bikeInfo.Id, bikeInfo);
}
continue;
}
continue;
}
bikesDictionary.Add(bikeInfo.Id, bikeInfo);
}
}
bikesDictionary.Add(bikeInfo.Id, bikeInfo);
}
}
// Remove entries which are not unique.
foreach (var l_oDuplicate in duplicates)
{
bikesDictionary.Remove(l_oDuplicate.Key);
}
// Remove entries which are not unique.
foreach (var l_oDuplicate in duplicates)
{
bikesDictionary.Remove(l_oDuplicate.Key);
}
return new BikeCollection(bikesDictionary);
}
}
return new BikeCollection(bikesDictionary);
}
}
}