using System; using System.Threading.Tasks; using Serilog; using TINK.Model.Connector; using TINK.Model.Device; using TINK.Model.User; using TINK.MultilingualResources; using TINK.Repository.Exception; using TINK.Services.CopriApi.Exception; using TINK.View; using BikeInfoMutable = TINK.Model.Bikes.BikeInfoNS.BC.BikeInfoMutable; namespace TINK.ViewModel.Bikes.Bike.BC.RequestHandler { public class Reserved : Base, IRequestHandler { /// Provides info about the smart device (phone, tablet, ...) /// View model to be used for progress report and unlocking/ locking view. public Reserved( BikeInfoMutable selectedBike, Func isConnectedDelegate, Func connectorFactory, Func viewUpdateManager, ISmartDevice smartDevice, IViewService viewService, IBikesViewModel bikesViewModel, IUser activeUser) : base(selectedBike, AppResources.ActionCancelRequest, true, isConnectedDelegate, connectorFactory, viewUpdateManager, smartDevice, viewService, bikesViewModel, activeUser) { } /// Executes user request to cancel reservation. public async Task HandleRequest() { // Lock list to avoid multiple taps while copri action is pending. BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease; BikesViewModel.IsIdle = false; BikesViewModel.ActionText = string.Empty; var l_oResult = await ViewService.DisplayAlert( string.Empty, string.Format("Reservierung für Fahrrad {0} aufheben?", SelectedBike.GetFullDisplayName()), "Ja", "Nein"); if (l_oResult == false) { // User aborted cancel process Log.ForContext().Information("User selected reserved bike {l_oId} in order to cancel reservation but action was canceled.", SelectedBike.Id); BikesViewModel.IsIdle = true; return this; } BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease; // Stop polling before cancel request. await ViewUpdateManager().StopUpdatePeridically(); try { IsConnected = IsConnectedDelegate(); await ConnectorFactory(IsConnected).Command.DoCancelReservation(SelectedBike); // If canceling bike succeeds remove bike because it is not ready to be booked again IsRemoveBikeRequired = true; } catch (Exception exception) { if (exception is InvalidAuthorizationResponseException) { // Copri response is invalid. Log.ForContext().Error("User selected reserved bike {l_oId} but canceling reservation failed (Invalid auth. response).", SelectedBike.Id); BikesViewModel.ActionText = String.Empty; await ViewService.DisplayAlert("Fehler beim Stornieren der Buchung!", exception.Message, "OK"); BikesViewModel.IsIdle = true; return this; } else if (exception is WebConnectFailureException || exception is RequestNotCachableException) { // Copri server is not reachable. Log.ForContext().Information("User selected reserved bike {l_oId} but cancel reservation failed (Copri server not reachable).", SelectedBike.Id); BikesViewModel.ActionText = String.Empty; await ViewService.DisplayAlert( "Verbingungsfehler beim Stornieren der Buchung!", string.Format("{0}\r\n{1}", exception.Message, WebConnectFailureException.GetHintToPossibleExceptionsReasons), "OK"); BikesViewModel.IsIdle = true; return this; } else { Log.ForContext().Error("User selected reserved bike {l_oId} but cancel reservation failed. {@l_oException}.", SelectedBike.Id, exception); BikesViewModel.ActionText = String.Empty; await ViewService.DisplayAlert("Fehler beim Stornieren der Buchung!", exception.Message, "OK"); BikesViewModel.IsIdle = true; return this; } } finally { // Restart polling again. await ViewUpdateManager().StartUpdateAyncPeridically(); // 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. } Log.ForContext().Information("User canceled reservation of bike {l_oId} successfully.", SelectedBike.Id); BikesViewModel.IsIdle = true; return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser); } } }