using System;
using System.Threading.Tasks;
using Serilog;
using ShareeBike.MultilingualResources;
using ShareeBike.Services.Logging;
using ShareeBike.View;
using static ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.OpenCommand;
using System.ComponentModel;
namespace ShareeBike.ViewModel.Bikes.Bike.BluetoothLock
{
///
/// View model for action open bluetooth lock.
///
///
internal class OpenLockActionViewModel : IOpenCommandListener
{
///
/// View model to be used for progress report and unlocking/ locking view.
///
private IBikesViewModel BikesViewModel { get; set; }
///
/// View service to show modal notifications.
///
private IViewService ViewService { get; }
/// Object to start or stop update of view model objects from Copri.
private Func ViewUpdateManager { get; }
/// Bike open.
private Model.Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable SelectedBike { get; }
///
/// Constructs the object.
///
/// Bike to open.
/// Object to start or stop update of view model objects from Copri.
/// View service to show modal notifications.
/// View model to be used for progress report and unlocking/ locking view.
///
public OpenLockActionViewModel(
Model.Bikes.BikeInfoNS.BluetoothLock.IBikeInfoMutable selectedBike,
Func viewUpdateManager,
IViewService viewService,
IBikesViewModel bikesViewModel)
{
SelectedBike = selectedBike;
ViewUpdateManager = viewUpdateManager;
ViewService = viewService;
BikesViewModel = bikesViewModel
?? throw new ArgumentException($"Can not construct {GetType().Name}-object. {nameof(bikesViewModel)} must not be null.");
}
///
/// Processes the open lock progress.
///
/// Current step to process.
public void ReportStep(Step step)
{
switch (step)
{
case Step.OpeningLock:
// 1a.Step: Open lock
BikesViewModel.ActionText = AppResources.ActivityTextOpeningLock;
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessOpenLockStepOpenLock;
BikesViewModel.RentalProcess.ImportantStepInfoText = AppResources.MarkingRentalProcessOpenLockObserve;
break;
case Step.GetLockInfos:
// 1b.Step: Get lock infos
BikesViewModel.RentalProcess.ImportantStepInfoText = AppResources.MarkingRentalProcessOpenLockWait;
break;
case Step.WaitStopPolling:
// 1c.Step: Wait for polling to be stopped
break;
case Step.UpdateLockingState:
// 1c.Step: Sent info to backend
BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdatingLockingState;
BikesViewModel.RentalProcess.StepInfoText = AppResources.MarkingRentalProcessOpenLockStepUpload;
BikesViewModel.RentalProcess.ImportantStepInfoText = AppResources.MarkingRentalProcessOpenLockWait;
break;
}
}
///
/// Processes the open lock state.
///
/// State to process.
/// Textual details describing current state.
public async Task ReportStateAsync(State state, string details)
{
switch (state)
{
case State.OutOfReachError:
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
BikesViewModel.ActionText = string.Empty;
await ViewService.DisplayAlert(
AppResources.ErrorOpenLockTitle,
AppResources.ErrorLockOutOfReach,
AppResources.MessageAnswerOk);
break;
case State.CouldntOpenBoldStatusIsUnknownError:
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
BikesViewModel.ActionText = string.Empty;
await ViewService.DisplayAlert(
AppResources.ErrorOpenLockTitle,
AppResources.ErrorOpenLockStatusUnknown,
AppResources.MessageAnswerOk);
break;
case State.CouldntOpenBoldIsBlockedError:
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
BikesViewModel.ActionText = string.Empty;
await ViewService.DisplayAlert(
AppResources.ErrorOpenLockTitle,
AppResources.ErrorOpenLockBoldBlocked,
AppResources.MessageAnswerOk);
break;
case State.CouldntOpenInconsistentStateError:
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
BikesViewModel.ActionText = string.Empty;
await ViewService.DisplayAlert(
AppResources.ErrorOpenLockTitle,
AppResources.ErrorOpenLockStillClosed,
AppResources.MessageAnswerOk);
break;
case State.GeneralOpenError:
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
BikesViewModel.ActionText = string.Empty;
await ViewService.DisplayAlert(
AppResources.ErrorOpenLockTitle,
details,
AppResources.MessageAnswerOk);
break;
case State.StopPollingFailed:
break;
case State.WebConnectFailed:
BikesViewModel.ActionText = AppResources.ActivityTextErrorNoWebUpdateingLockstate;
break;
case State.ResponseIsInvalid:
BikesViewModel.ActionText = AppResources.ActivityTextErrorStatusUpdateingLockstate;
break;
case State.BackendUpdateFailed:
BikesViewModel.ActionText = AppResources.ActivityTextErrorConnectionUpdateingLockstate;
break;
}
}
/// Open lock in order to pause ride and update COPRI lock state.
public async Task OpenLockAsync()
{
Log.ForContext().Information("User request to open lock of bike {bikeId}.", SelectedBike.Id);
// lock GUI
BikesViewModel.IsIdle = false;
// Stop Updater
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
var stopPollingTask = ViewUpdateManager().StopAsync();
// Clear logging memory sink to avoid passing log data not related to returning of bike to backend.
// Log data is passed to backend when calling CopriCallsHttps.DoReturn().
MemoryStackSink.ClearMessages();
// 1. Step
// Parameter for RentalProcess View
BikesViewModel.StartRentalProcess(new RentalProcessViewModel(SelectedBike.Id)
{
State = CurrentRentalProcess.OpenLock,
StepIndex = 1,
Result = CurrentStepStatus.None
});
try
{
#if USELOCALINSTANCE
var command = new OpenCommand(SelectedBike, GeolocationService, LockService, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager);
await command.Invoke(this);
#else
await SelectedBike.OpenLockAsync(this, stopPollingTask);
#endif
Log.ForContext().Information("Lock of bike {bikeId} opened successfully.", SelectedBike.Id);
}
catch (Exception exception)
{
Log.ForContext().Information("Lock of bike {bikeId} can not be opened. {@exception}", SelectedBike.Id, exception);
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
await ViewUpdateManager().StartAsync();
BikesViewModel.ActionText = string.Empty;
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
BikesViewModel.IsIdle = true;
return;
}
BikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
await ViewUpdateManager().StartAsync();
BikesViewModel.ActionText = string.Empty;
//Confirmation message
Log.ForContext().Information("User request to park bike {bikeId}.", SelectedBike.Id);
await ViewService.DisplayAlert(
AppResources.MessageRentalProcessOpenLockFinishedTitle,
AppResources.MessageRentalProcessOpenLockFinishedText,
AppResources.MessageAnswerOk);
BikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
BikesViewModel.IsIdle = true;
return;
}
}
}