sharee.bike-App/SharedBusinessLogic/Model/Bikes/BikeInfoNS/BikeNS/Command/StartReservationCommand.cs
2024-04-09 12:53:23 +02:00

134 lines
3.7 KiB
C#

using System;
using System.Threading.Tasks;
using Serilog;
using ShareeBike.Repository.Exception;
using ShareeBike.Services.CopriApi.Exception;
using ShareeBike.Model.Connector;
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
namespace ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command
{
/// <summary>
/// Provides functionality to get the locked bike location.
/// </summary>
public static class StartReservationCommand
{
/// <summary>
/// Possible steps of requesting a bike.
/// </summary>
public enum Step
{
ReserveBike,
}
/// <summary>
/// Possible steps of requesting a bike.
/// </summary>
public enum State
{
TooManyBikesError,
WebConnectFailed,
GeneralStartReservationError,
}
/// <summary>
/// Interface to notify view model about steps/ state changes of closing process.
/// </summary>
public interface IStartReservationCommandListener
{
/// <summary>
/// Reports current step.
/// </summary>
/// <param name="currentStep">Current step to report.</param>
void ReportStep(Step currentStep);
/// <summary>
/// Reports current state.
/// </summary>
/// <param name="currentState">Current state to report.</param>
/// <param name="message">Message describing the current state.</param>
/// <returns></returns>
Task ReportStateAsync(State currentState, string message);
}
/// <summary>
/// Get current location.
/// </summary>
/// <param name="listener"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static async Task InvokeAsync<T>(
IBikeInfoMutable bike,
Func<bool> isConnectedDelegate,
Func<bool, IConnector> connectorFactory,
IStartReservationCommandListener listener)
{
// Invokes member to notify about step being started.
void InvokeCurrentStep(Step step)
{
if (listener == null)
return;
try
{
listener.ReportStep(step);
}
catch (Exception exception)
{
Log.ForContext<T>().Error("An exception {@exception} was thrown invoking step-action for step {step} ", exception, step);
}
}
// Invokes member to notify about state change.
async Task InvokeCurrentStateAsync(State state, string message)
{
if (listener == null)
return;
try
{
await listener.ReportStateAsync(state, message);
}
catch (Exception exception)
{
Log.ForContext<T>().Error("An exception {@exception} was thrown invoking state-action for state {state} ", exception, state);
}
}
//// Start Action
//// Step: Reserve Bike
InvokeCurrentStep(Step.ReserveBike);
try
{
await connectorFactory(true).Command.DoReserve(bike);
Log.ForContext<T>().Information("User reserved bike {bikeId} successfully.", bike.Id);
}
catch (Exception exception)
{
Log.ForContext<T>().Information("Request to reserve bike {bikeId} declined.", bike.Id);
if (exception is BookingDeclinedException)
{
// Too many bikes booked.
Log.ForContext<T>().Error("Maximum count of bikes {exception.MaxBikesCount} already requested/ booked.", (exception as BookingDeclinedException).MaxBikesCount);
await InvokeCurrentStateAsync(State.TooManyBikesError, (exception as BookingDeclinedException).MaxBikesCount.ToString());
}
else if (exception is WebConnectFailureException
|| exception is RequestNotCachableException)
{
// Copri server is not reachable.
Log.ForContext<T>().Error("Copri server not reachable.");
await InvokeCurrentStateAsync(State.WebConnectFailed, exception.Message);
}
else
{
Log.ForContext<T>().Error("{@exception}", exception);
await InvokeCurrentStateAsync(State.GeneralStartReservationError, exception.Message);
}
throw;
}
}
}
}