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 { /// /// Provides functionality to get the locked bike location. /// public static class StartReservationCommand { /// /// Possible steps of requesting a bike. /// public enum Step { ReserveBike, } /// /// Possible steps of requesting a bike. /// public enum State { TooManyBikesError, WebConnectFailed, GeneralStartReservationError, } /// /// Interface to notify view model about steps/ state changes of closing process. /// public interface IStartReservationCommandListener { /// /// Reports current step. /// /// Current step to report. void ReportStep(Step currentStep); /// /// Reports current state. /// /// Current state to report. /// Message describing the current state. /// Task ReportStateAsync(State currentState, string message); } /// /// Get current location. /// /// /// /// public static async Task InvokeAsync( IBikeInfoMutable bike, Func isConnectedDelegate, Func 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().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().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().Information("User reserved bike {bikeId} successfully.", bike.Id); } catch (Exception exception) { Log.ForContext().Information("Request to reserve bike {bikeId} declined.", bike.Id); if (exception is BookingDeclinedException) { // Too many bikes booked. Log.ForContext().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().Error("Copri server not reachable."); await InvokeCurrentStateAsync(State.WebConnectFailed, exception.Message); } else { Log.ForContext().Error("{@exception}", exception); await InvokeCurrentStateAsync(State.GeneralStartReservationError, exception.Message); } throw; } } } }