using gehGassiApp.Core.Interfaces; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using gehGassiApp.Domain.Dogs; using gehGassiApp.Core.Data; using gehGassiApp.Core.Interfaces.Synchronization; namespace gehGassiApp.Core.Services { /// /// Service der die Verwaltung von Hunderassen realisiert /// public class DogRaceService : ServiceBase, IDogRaceService { private readonly ICommunicationService _communicationService; private readonly ISyncInfoPullService _syncInfoPullService; /// /// Erstellt eine Instanz /// /// Instanz eines IUnitOfWork /// Instanz eines ICommunicationService /// Instanz eines ISyncInfoPullService public DogRaceService(IUnitOfWork unitOfWork, ICommunicationService communicationService, ISyncInfoPullService syncInfoPullService) : base(unitOfWork) { _communicationService = communicationService; _syncInfoPullService = syncInfoPullService; } /// /// Gibt eine Entität anhand der eindeutigen Id zurück /// /// Id der Entität /// Gibt an ob NoTRacking verwendet werden soll. Es werden keine Entitäten im EF-Speicher gehalten /// Entität oder null, wenn nicht gefunden public override DogRace Get(object id, bool noTracking = true) { return Repository.SingleOrDefault(c => c.Id == id.ToString(), noTracking); } /// /// Gibt eine Entität anhand der eindeutigen Id zurück /// /// Id der Entität /// Gibt an ob NoTRacking verwendet werden soll. Es werden keine Entitäten im EF-Speicher gehalten /// Entität oder null, wenn nicht gefunden public override async Task GetAsync(object id, bool noTracking = true) { return await Repository.SingleOrDefaultAsync(c => c.Id == id.ToString(), noTracking).ConfigureAwait(false); } /// /// Gibt eine Liste der Hunderassen zurück. /// Entweder von der DB oder vom Server /// /// Aktuelles Accesstoken /// Gewünschte Sprache /// CancellationToken /// Liste der Hunderassen public async Task> GetRacesAsync(string language, string accessToken, CancellationToken token) { //Zuerst DB var localRaces = await Repository.FindAsync(c => c.Deleted == false, noTracking: true).ConfigureAwait(false); if (localRaces != null && localRaces.Any()) return localRaces.Where(c => c.Deleted == false).OrderBy(c => c.Name).ToList(); else { //Dann wenn lokal nicht verfügbar immer online... var isConnected = await _communicationService.IsConnected(); //isConnected = false; if (isConnected) { var racesResult = await _communicationService.GetDogRacesAsync(null, language, accessToken, token); if (racesResult.Success) { var result = await HandleChangesAsync(racesResult.Value); if (result.LastUpdate != null) await _syncInfoPullService.AddOrUpddateAsync(nameof(DogRace), result.LastUpdate.Value).ConfigureAwait(false); return racesResult.Value.Where(c => c.Deleted == false).OrderBy(c => c.Name).ToList(); } } } //Keine Daten online, keine offline return new List(); } /// /// Gibt eine Hunderasse zurück. /// Entweder von der DB oder vom Server /// /// Id der Hunderasse /// Gewünschte Sprache /// Aktuelles Accesstoken /// CancellationToken /// Hunderasse oder null, wenn nicht gefunden public async Task GetRaceAsync(string id, string language, string accessToken, CancellationToken token) { var localRace = await Repository.FirstOrDefaultAsync(c => c.Deleted == false && c.Id == id, noTracking: true).ConfigureAwait(false); if (localRace == null) { //Dann wenn lokal nicht verfügbar immer online... var isConnected = await _communicationService.IsConnected(); //isConnected = false; if (isConnected) { var racesResult = await _communicationService.GetDogRaceAsync(id, language, accessToken, token); if (racesResult.Success) { return racesResult.Value; } } } return localRace; } #region Pull-Push Implementation /// /// Holen der Daten vom lokalen Speicher die noch nicht synchronisiert wurden und senden an den Server /// /// Aktuelles Accesstoken /// CancellationToken /// Task public async Task> PushAsync(string accessToken, CancellationToken token) { var result = new SyncResult(); //Es gibt hier kein Push! await Task.Delay(1); return result; } /// /// Holen der letzten Daten vom Server und Synchronisieren mit den lokalen Daten /// /// Sprache /// Aktuelles Accesstoken /// CancellationToken /// Task public async Task> PullAsync(string language, string accessToken, CancellationToken token) { var result = new SyncResult(); var isConnected = await _communicationService.IsConnected(); if (isConnected) { //Zuerst lezte Aktivität holen... DateTimeOffset? lastUpdate = null; var lastSyncInfo = await _syncInfoPullService.GetAsync(nameof(DogRace)); if (lastSyncInfo != null) lastUpdate = lastSyncInfo.LastUpdate; var ctsQuery = new CancellationTokenSource(Common.Constants.PushPullTimeout); var racesResult = await _communicationService.GetDogRacesAsync(lastUpdate, language, accessToken, token); if (racesResult.Success) { result = await HandleChangesAsync(racesResult.Value); if (result.LastUpdate != null) await _syncInfoPullService.AddOrUpddateAsync(nameof(DogRace), result.LastUpdate.Value).ConfigureAwait(false); } result.LastUpdate ??= lastUpdate; } return result; } #endregion #region Private /// /// Behandeln der Liste von Hunderassen wenn welche vom Online-Store geholt werden. /// /// Liste der Hunderassen /// Task private async Task> HandleChangesAsync(List races) { var result = new SyncResult(); //Je Rasse durchgehen ob was gemacht werden soll foreach (var race in races) { var localRace = await Repository.FirstOrDefaultAsync(c => c.Id == race.Id, false); if (localRace != null && localRace.UpdatedAt < race.UpdatedAt) { if (localRace.UpdatedAt >= race.UpdatedAt) { if (result.LastUpdate == null || result.LastUpdate < localRace.UpdatedAt) result.LastUpdate = localRace.UpdatedAt; continue; } var deleted = localRace.Deleted == false && race.Deleted; localRace.Version = race.Version; localRace.UpdatedAt = race.UpdatedAt; localRace.Deleted = race.Deleted; localRace.Name = race.Name; localRace.Description = race.Description; localRace.Age = race.Age; localRace.SizeAndWeight = race.SizeAndWeight; localRace.Personality = race.Personality; localRace.Coexistence = race.Coexistence; localRace.Care = race.Care; localRace.Decision = race.Decision; localRace.Photo = race.Photo; localRace.Created = race.Created; if (result.LastUpdate == null || result.LastUpdate < localRace.UpdatedAt) result.LastUpdate = localRace.UpdatedAt; if (!deleted) result.Updated.Add(localRace); else result.Deleted.Add(localRace); Repository.Update(localRace); } if (localRace == null) { localRace = new DogRace() { Id = race.Id, Version = race.Version, UpdatedAt = race.UpdatedAt, Deleted = race.Deleted, Name = race.Name, Description = race.Description, Age = race.Age, SizeAndWeight = race.SizeAndWeight, Personality = race.Personality, Coexistence = race.Coexistence, Care = race.Care, Decision = race.Decision, Photo = race.Photo, Created = race.Created }; Repository.Add(localRace); if (result.LastUpdate == null || result.LastUpdate < localRace.UpdatedAt) result.LastUpdate = localRace.UpdatedAt; result.Added.Add(localRace); } } if (result.HasChanges) { try { await CommitAsync().ConfigureAwait(false); } catch (Exception ex) { var err = ex.Message; } } return result; } #endregion } }