using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ShareeBike.Model.Bikes;
using ShareeBike.Model.Connector.Filter;
using ShareeBike.Model.Services.CopriApi;
using ShareeBike.Model.Stations;
using ShareeBike.Model.Stations.StationNS;
using ShareeBike.Model.Stations.StationNS.Operator;
using BikeInfo = ShareeBike.Model.Bikes.BikeInfoNS.BC.BikeInfo;
namespace ShareeBike.Model.Connector
{
/// Filters connector responses.
/// Former name: Filter
public class FilteredConnector : IFilteredConnector
{
/// Constructs a filter object.
/// Filter group.
/// Connector object.
public FilteredConnector(
IEnumerable group,
IConnector connector)
{
Connector = connector;
if (Connector == null)
{
throw new ArgumentException("Can not construct filter object. Connector- and command objects must not be null.");
}
Query = new QueryProvider(Connector.Query, GroupFilterFactory.Create(group));
}
/// Inner connector object.
public IConnector Connector { get; }
/// Command object.
public ICommand Command => Connector.Command;
/// Object to query information.
public IQuery Query { get; }
/// True if connector has access to copri server, false if cached values are used.
public bool IsConnected => Connector.IsConnected;
/// Object to perform filtered queries.
private class QueryProvider : IQuery
{
/// Holds the filter.
private IGroupFilter Filter { get; }
/// Holds the reference to object which performs copri queries.
private IQuery m_oInnerQuery;
/// Constructs a query object.
///
///
public QueryProvider(IQuery innerQuerry, IGroupFilter filter)
{
m_oInnerQuery = innerQuerry;
Filter = filter;
}
/// Gets bikes either bikes available if no user is logged in or bikes available and bikes occupied if a user is logged in.
/// Uri of the operator host to get bikes from or null if bikes have to be gotten form primary host.
/// Id of station which is used for filtering bikes. Null if no filtering should be applied.
/// Id of bike which is used for filtering bikes. Null if no filtering should be applied.
public async Task> GetBikesAsync(Uri operatorUri = null, string stationId = null, string bikeId = null)
{
var result = await m_oInnerQuery.GetBikesAsync(operatorUri, stationId, bikeId);
if (bikeId == null)
{
// Do filter
return new Result(
result.Source,
new BikeCollection(DoFilter(result.Response, Filter)),
result.GeneralData,
result.Exception);
}
else
{
// Do NOT filter on SelectBikePage = use function from NullFilterConnector: https://dev.azure.com/TeilRad/sharee.bike%20Buchungsplattform/_workitems/edit/904
return new Result(
result.Source,
new BikeCollection(result.Response.ToDictionary(x => x.Id)),
result.GeneralData,
result.Exception);
}
}
/// Gets bikes occupied if a user is logged in.
public async Task> GetBikesOccupiedAsync()
{
var result = await m_oInnerQuery.GetBikesOccupiedAsync();
return new Result(
result.Source,
new BikeCollection(result.Response.ToDictionary(x => x.Id)),
result.GeneralData,
result.Exception);
}
/// Gets all station applying filter rules.
///
public async Task> GetBikesAndStationsAsync()
{
// Bikes and stations from COPRI or cache
var providerBikesAndStations = await m_oInnerQuery.GetBikesAndStationsAsync();
// Do filtering.
var filteredStationsDictionary = new StationDictionary(
providerBikesAndStations.Response.StationsAll.CopriVersion,
DoFilter(providerBikesAndStations.Response.StationsAll, Filter));
var filteredBikesOccupiedDictionary = new BikeCollection(
DoFilter(providerBikesAndStations.Response.BikesOccupied, Filter));
var filteredBikesAndStations = new Result(
providerBikesAndStations.Source,
new StationsAndBikesContainer(
filteredStationsDictionary,
filteredBikesOccupiedDictionary),
providerBikesAndStations.GeneralData,
providerBikesAndStations.Exception);
return filteredBikesAndStations;
}
/// Filter bikes by group.
/// Bikes to filter.
/// Filtered bikes.
private static Dictionary DoFilter(BikeCollection bikes, IGroupFilter filter) =>
bikes
.Where(x => filter.DoFilter(x.Group).Count() > 0)
.ToDictionary(x => x.Id);
/// Filter stations by group and removes bike group collection entries which do not match group filter.
/// Matching stations.
private static Dictionary DoFilter(StationDictionary stations, IGroupFilter filter) =>
stations
.Where(station => filter.DoFilter(station.Group).Count() > 0)
.Select(station => new Station(
station.Id,
station.Group,
station.Position,
station.StationName,
station.OperatorUri,
station.OperatorData,
new BikeGroupCol(station.BikeGroups
.Where(group => filter.DoFilter(new List { group.Group }).Count() > 0))) as IStation)
.ToDictionary(x => x.Id);
}
}
}