using Serilog; using System; using System.Threading.Tasks; using TINK.Model.Connector; using TINK.Model.Repository.Exception; using TINK.Model.State; using TINK.Model.User; using TINK.MultilingualResources; using TINK.View; using BikeInfoMutable = TINK.Model.Bike.BC.BikeInfoMutable; namespace TINK.ViewModel.Bikes.Bike.BC.RequestHandler { /// View model to be used for progress report and unlocking/ locking view. public class Disposable : Base, IRequestHandler { public Disposable( BikeInfoMutable selectedBike, Func isConnectedDelegate, Func connectorFactory, Func viewUpdateManager, IViewService viewService, IBikesViewModel bikesViewModel, IUser activeUser) : base(selectedBike, selectedBike.State.Value.GetActionText(), true, isConnectedDelegate, connectorFactory, viewUpdateManager, viewService, bikesViewModel, activeUser) { } /// Gets the bike state. public override InUseStateEnum State => InUseStateEnum.Disposable; /// Request bike. public async Task HandleRequest() { // Lock list to avoid multiple taps while copri action is pending. BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease; BikesViewModel.IsIdle = false; var l_oResult = await ViewService.DisplayAlert( string.Empty, string.Format(AppResources.QuestionReserveBike, SelectedBike.GetDisplayName(), StateRequestedInfo.MaximumReserveTime.Minutes), AppResources.MessageAnswerYes, AppResources.MessageAnswerNo); if (l_oResult == false) { // User aborted booking process Log.ForContext().Information("User selected availalbe bike {l_oId} in order to reserve but action was canceled.", SelectedBike.Id); BikesViewModel.IsIdle = true; return this; } BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease; // Stop polling before requesting bike. await ViewUpdateManager().StopUpdatePeridically(); IsConnected = IsConnectedDelegate(); try { await ConnectorFactory(IsConnected).Command.DoReserve(SelectedBike); } catch (Exception l_oException) { if (l_oException is BookingDeclinedException) { // Too many bikes booked. Log.ForContext().Information("Request declined because maximum count of bikes {l_oException.MaxBikesCount} already requested/ booked.", (l_oException as BookingDeclinedException).MaxBikesCount); BikesViewModel.ActionText = string.Empty; await ViewService.DisplayAlert( AppResources.MessageTitleHint, string.Format(AppResources.MessageReservationBikeErrorTooManyReservationsRentals, SelectedBike.Id, (l_oException as BookingDeclinedException).MaxBikesCount), AppResources.MessageAnswerOk); } else if (l_oException is WebConnectFailureException) { // Copri server is not reachable. Log.ForContext().Information("User selected availalbe bike {l_oId} but reserving failed (Copri server not reachable).", SelectedBike.Id); BikesViewModel.ActionText = string.Empty; await ViewService.DisplayAlert( "Verbingungsfehler beim Reservieren des Rads!", string.Format("{0}\r\n{1}", l_oException.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons), "OK"); } else { Log.ForContext().Error("User selected availalbe bike {l_oId} but reserving failed. {@l_oException}", SelectedBike.Id, l_oException); BikesViewModel.ActionText = string.Empty; await ViewService.DisplayAlert("Fehler beim Reservieren des Rads!", l_oException.Message, "OK"); } BikesViewModel.ActionText = string.Empty; // Todo: Remove this statement because in catch block ActionText is already set to empty above. BikesViewModel.IsIdle = true; return this; } finally { // Restart polling again. await ViewUpdateManager().StartUpdateAyncPeridically(); // Update status text and unlock list of bikes because no more action is pending. BikesViewModel.ActionText = string.Empty; // Todo: Move this statement in front of finally block because in catch block ActionText is already set to empty. BikesViewModel.IsIdle = true; } Log.ForContext().Information("User reserved bike {l_oId} successfully.", SelectedBike.Id); return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager, ViewService, BikesViewModel, ActiveUser); } } }