/*
* Copyright (c) 2024 Proton AG
*
* This file is part of ProtonVPN.
*
* ProtonVPN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonVPN is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonVPN. If not, see .
*/
using System.Text.RegularExpressions;
using ProtonVPN.Client.Localization.Contracts;
using ProtonVPN.Client.Localization.Extensions;
using ProtonVPN.Client.Logic.Searches.Contracts;
using ProtonVPN.Client.Logic.Servers.Contracts;
using ProtonVPN.Client.Logic.Servers.Contracts.Enums;
using ProtonVPN.Client.Logic.Servers.Contracts.Models;
namespace ProtonVPN.Client.Logic.Searches;
public partial class GlobalSearch : IGlobalSearch
{
[GeneratedRegex(@"^.{2,}(#\d*|\d+)$")]
private static partial Regex GenerateCompileTimeRegex();
private readonly Regex _serverSearchTriggerRegex = GenerateCompileTimeRegex();
private readonly IServersLoader _serversLoader;
//private readonly IProfilesManager _profilesManager;
private readonly ILocalizationProvider _localizer;
public GlobalSearch(IServersLoader serversLoader,
//IProfilesManager profilesManager,
ILocalizationProvider localizer)
{
_serversLoader = serversLoader;
//_profilesManager = profilesManager;
_localizer = localizer;
}
public async Task> SearchAsync(
string? input,
ServerFeatures? serverFeatures = null,
SearchCategory categories = SearchCategory.All)
{
input = input.NormalizeInput();
if (string.IsNullOrWhiteSpace(input))
{
return [];
}
Task> serversTask = categories.HasFlag(SearchCategory.Servers) && _serverSearchTriggerRegex.IsMatch(input)
? Task.Run(() => SearchServers(input, serverFeatures))
: Task.FromResult>([]);
Task> countriesTask = categories.HasFlag(SearchCategory.Countries)
? Task.Run(() => SearchCountries(input, serverFeatures))
: Task.FromResult>([]);
Task> statesTask = categories.HasFlag(SearchCategory.States)
? Task.Run(() => SearchStates(input, serverFeatures))
: Task.FromResult>([]);
Task> citiesTask = categories.HasFlag(SearchCategory.Cities)
? Task.Run(() => SearchCities(input, serverFeatures))
: Task.FromResult>([]);
//Task> gatewaysTask = Task.Run(() => SearchGateways(input));
//Task> profilesTask = Task.Run(() => SearchProfiles(input));
Task.WaitAll(serversTask, citiesTask, statesTask, countriesTask/*, gatewaysTask, profilesTask*/);
IEnumerable servers = await serversTask;
IEnumerable cities = await citiesTask;
IEnumerable states = await statesTask;
IEnumerable countries = await countriesTask;
//IEnumerable gateways = await gatewaysTask;
//IEnumerable profiles = await profilesTask;
//return profiles.Concat(gateways).Concat(countries).Concat(states).Concat(cities).Concat(servers).ToList();
return countries
.Concat(states)
.Concat(cities)
.Concat(servers)
.ToList();
}
private IEnumerable SearchServers(string input, ServerFeatures? serverFeatures)
{
IEnumerable servers = serverFeatures is null
? _serversLoader.GetServers()
: _serversLoader.GetServersByFeatures(serverFeatures.Value);
return servers.Where(s => SearchMatcher.MatchesServer(s, input));
}
private IEnumerable SearchCities(string input, ServerFeatures? serverFeatures)
{
IEnumerable cities = serverFeatures is null
? _serversLoader.GetCities()
: _serversLoader.GetCitiesByFeatures(serverFeatures.Value);
List localizedCities = cities.Select(city => new LocalizedLocation()
{
Location = city,
LocalizedName = _localizer.GetCityName(city.Name, city.CountryCode)
}).ToList();
return localizedCities
.Where(c => SearchMatcher.MatchesCity(c.LocalizedName, input))
.Select(c => c.Location);
}
private IEnumerable SearchStates(string input, ServerFeatures? serverFeatures)
{
IEnumerable states = serverFeatures is null
? _serversLoader.GetStates()
: _serversLoader.GetStatesByFeatures(serverFeatures.Value);
List localizedStates = states.Select(state => new LocalizedLocation()
{
Location = state,
LocalizedName = _localizer.GetStateName(state.Name, state.CountryCode)
}).ToList();
return localizedStates
.Where(s => SearchMatcher.MatchesState(s.LocalizedName, input))
.Select(s => s.Location);
}
private IEnumerable SearchCountries(string input, ServerFeatures? serverFeatures)
{
IEnumerable countries = serverFeatures is null
? _serversLoader.GetCountries()
: _serversLoader.GetCountriesByFeatures(serverFeatures.Value);
List localizedCountries = countries.Select(c => new LocalizedCountry()
{
Country = c,
LocalizedName = _localizer.GetCountryName(c.Code)
}).ToList();
return localizedCountries
.Where(c => SearchMatcher.MatchesCountry(c.Country, c.LocalizedName, input))
.Select(c => c.Country);
}
//private IEnumerable SearchGateways(string input)
//{
// IEnumerable gateways = _serversLoader.GetGateways();
// return gateways.Where(g => IsAMatch(g, input))
// .Select(g => new ConnectionIntent(new GatewayLocationIntent(g)));
//}
//private IEnumerable SearchProfiles(string input)
//{
// IOrderedEnumerable profiles = _profilesManager.GetAll();
// return profiles.Where(p => IsAMatch(p.Name, input));
//}
}