using System; using System.Linq; using System.Threading.Tasks; using TINK.Model.Bike; using TINK.Model.Services.CopriApi; using TINK.Repository; namespace TINK.Model.Connector { /// Provides query functionality for a logged in user. public class CachedQueryLoggedIn : BaseLoggedIn, IQuery { /// Cached copri server. private readonly ICachedCopriServer server; /// Constructs a copri query object. /// Server which implements communication. public CachedQueryLoggedIn(ICopriServerBase p_oCopriServer, string p_strSessionCookie, string p_strMail, Func p_oDateTimeProvider) : base(p_oCopriServer, p_strSessionCookie, p_strMail, p_oDateTimeProvider) { server = p_oCopriServer as ICachedCopriServer; if (server == null) { throw new ArgumentException($"Copri server is not of expected typ. Type detected is {p_oCopriServer.GetType()}."); } } /// Gets all stations including postions. public async Task> GetBikesAndStationsAsync() { var stationsResponse = await server.GetStations(); if (stationsResponse.Source == typeof(CopriCallsMonkeyStore) || stationsResponse.Exception != null) { // Stations were read from cache ==> get bikes availbalbe and occupied from cache as well to avoid inconsistencies return new Result( stationsResponse.Source, new StationsAndBikesContainer( stationsResponse.Response.GetStationsAllMutable(), UpdaterJSON.GetBikesAll( (await server.GetBikesAvailable(true)).Response, (await server.GetBikesOccupied(true)).Response, Mail, DateTimeProvider)), stationsResponse.Exception); } var bikesAvailableResponse = await server.GetBikesAvailable(); if (bikesAvailableResponse.Source == typeof(CopriCallsMonkeyStore) || bikesAvailableResponse.Exception != null) { // Bikes avilable were read from cache ==> get bikes occupied from cache as well to avoid inconsistencies return new Result( bikesAvailableResponse.Source, new StationsAndBikesContainer( (await server.GetStations(true)).Response.GetStationsAllMutable(), UpdaterJSON.GetBikesAll(bikesAvailableResponse.Response, (await server.GetBikesOccupied(true)).Response, Mail, DateTimeProvider)), bikesAvailableResponse.Exception); } var bikesOccupiedResponse = await server.GetBikesOccupied(); if (bikesOccupiedResponse.Source == typeof(CopriCallsMonkeyStore) || bikesOccupiedResponse.Exception != null) { // Bikes occupied were read from cache ==> get bikes available from cache as well to avoid inconsistencies return new Result( bikesOccupiedResponse.Source, new StationsAndBikesContainer( (await server.GetStations(true)).Response.GetStationsAllMutable(), UpdaterJSON.GetBikesAll( (await server.GetBikesAvailable(true)).Response, bikesOccupiedResponse.Response, Mail, DateTimeProvider)), bikesOccupiedResponse.Exception); } // Both types bikes could read from copri => update cache server.AddToCache(stationsResponse); server.AddToCache(bikesAvailableResponse); server.AddToCache(bikesOccupiedResponse); var exceptions = new[] { stationsResponse?.Exception, bikesAvailableResponse?.Exception, bikesOccupiedResponse?.Exception }.Where(x => x != null).ToArray(); var stationsMutable = stationsResponse.Response.GetStationsAllMutable(); var bikesMutable = UpdaterJSON.GetBikesAll( bikesAvailableResponse.Response, bikesOccupiedResponse.Response, Mail, DateTimeProvider); return new Result( stationsResponse.Source, new StationsAndBikesContainer(stationsMutable, bikesMutable), exceptions.Length > 0 ? new AggregateException(exceptions) : null); } /// Gets bikes occupied. /// Collection of bikes. public async Task> GetBikesOccupiedAsync() { var result = await server.GetBikesOccupied(); server.AddToCache(result); return new Result(result.Source, result.Response.GetBikesOccupied(Mail, DateTimeProvider), result.Exception); } /// Gets bikes available and bikes occupied. /// Collection of bikes. public async Task> GetBikesAsync() { var l_oBikesAvailableResponse = await server.GetBikesAvailable(); if (l_oBikesAvailableResponse.Source == typeof(CopriCallsMonkeyStore) || l_oBikesAvailableResponse.Exception != null) { // Bikes avilable were read from cache ==> get bikes occupied from cache as well to avoid inconsistencies return new Result( l_oBikesAvailableResponse.Source, UpdaterJSON.GetBikesAll( l_oBikesAvailableResponse.Response, (await server.GetBikesOccupied(true)).Response, Mail, DateTimeProvider), l_oBikesAvailableResponse.Exception); } var l_oBikesOccupiedResponse = await server.GetBikesOccupied(); if (l_oBikesOccupiedResponse.Source == typeof(CopriCallsMonkeyStore) || l_oBikesOccupiedResponse.Exception != null) { // Bikes occupied were read from cache ==> get bikes available from cache as well to avoid inconsistencies return new Result( l_oBikesOccupiedResponse.Source, UpdaterJSON.GetBikesAll( (await server.GetBikesAvailable(true)).Response, l_oBikesOccupiedResponse.Response, Mail, DateTimeProvider), l_oBikesOccupiedResponse.Exception); } // Both types bikes could read from copri => update cache server.AddToCache(l_oBikesAvailableResponse); server.AddToCache(l_oBikesOccupiedResponse); return new Result( l_oBikesAvailableResponse.Source, UpdaterJSON.GetBikesAll(l_oBikesAvailableResponse.Response, l_oBikesOccupiedResponse.Response, Mail, DateTimeProvider), l_oBikesAvailableResponse.Exception != null || l_oBikesOccupiedResponse.Exception != null ? new AggregateException(new[] { l_oBikesAvailableResponse.Exception, l_oBikesOccupiedResponse.Exception }) : null); } } }