using gehGassi.Dto.Common;
using gehGassiApp.Core.Common;
using gehGassiApp.Core.Interfaces;
using gehGassiApp.Domain.Common;
namespace gehGassiApp.Core.Services
{
///
/// Hilfs-Service bei der Lokalisierung eines Benutzers
///
public class LocationService : ILocationService
{
private readonly ICountryService _countryService;
private readonly ISettingsService _settingsService;
private readonly IAppReportingService _appReportingService;
private LocationDto _cachedLocation;
private DateTimeOffset? _lastUpdate;
private DateTimeOffset? _lastReceivedNull;
///
/// Erstellt eine Instanz
///
/// Instanz eines ICountryService
/// Instanz eines ISettingsService
/// Instanz eines IAppReportingService
public LocationService(ICountryService countryService, ISettingsService settingsService, IAppReportingService appReportingService)
{
_countryService = countryService;
_settingsService = settingsService;
_appReportingService = appReportingService;
_lastUpdate = null;
_lastReceivedNull = null;
_cachedLocation = null;
}
///
/// Holen der Lat und Lng sowie, wenn möglich Land und Bundesland
///
/// Aktuelle Position des Benutzers, oder null wenn nicht möglich
public async Task GetLocationAsync()
{
if (_cachedLocation != null && _lastUpdate != null && _lastUpdate > DateTimeOffset.UtcNow)
{
return _cachedLocation;
}
var location = new LocationDto();
try
{
var appSettings = _settingsService.GetAppSettings();
if (appSettings.FakeGps)
{
var locationDto = new LocationDto
{
Lat = appSettings.Latitude,
Lng = appSettings.Longitude
};
var placemarks = await Geocoding.Default.GetPlacemarksAsync(locationDto.Lat.Value, locationDto.Lng.Value);
if (placemarks != null && placemarks.Any())
{
var placemark = placemarks.FirstOrDefault();
locationDto.CountryCode = placemark.CountryCode.ToUpper();
var state = await _countryService.GetStateByNameAsync(location.CountryCode, placemark.AdminArea);
if (state != null)
locationDto.StateCode = state.Code;
}
return locationDto;
}
var status = await Permissions.CheckStatusAsync();
if (status == PermissionStatus.Granted)
{
var foundLocation = await Geolocation.Default.GetLastKnownLocationAsync();
if (foundLocation == null && (_lastReceivedNull == null || _lastReceivedNull > DateTimeOffset.UtcNow))
{
//Wenn nichts im Cache, direkt holen. Kann länger dauern
using var cts = new CancellationTokenSource(Constants.GpsRealtimeTimout);
foundLocation = await Geolocation.Default.GetLocationAsync(new GeolocationRequest(GeolocationAccuracy.Medium, Constants.GpsRealtimeTimout), cts.Token);
if (foundLocation == null)
{
_lastReceivedNull = DateTimeOffset.UtcNow.Add(Constants.LocationCacheTimeout);
}
}
if (foundLocation != null)
{
_lastReceivedNull = null;
location.Lat = foundLocation.Latitude;
location.Lng = foundLocation.Longitude;
var placemarks = await Geocoding.Default.GetPlacemarksAsync(foundLocation);
if (placemarks != null && placemarks.Any())
{
var placemark = placemarks.FirstOrDefault();
location.CountryCode = placemark.CountryCode.ToUpper();
var state = await _countryService.GetStateByNameAsync(location.CountryCode, placemark.AdminArea);
if (state != null)
location.StateCode = state.Code;
}
}
}
}
catch
{
location = new LocationDto();
}
_cachedLocation = location;
if (_cachedLocation.Lat == null && _cachedLocation.Lng == null)
_cachedLocation = null;
if (_cachedLocation != null)
_lastUpdate = DateTimeOffset.UtcNow.Add(Constants.LocationCacheTimeout);
else
_lastUpdate = null;
return location;
}
///
/// Gibt Lat und Long anhand einer Adresse zurück, wenn möglich
///
/// Adresse
/// Location mit Lat und Lng oder null wenn nicht möglich
public async Task GetLocationByAddressAsync(Address address)
{
if (address != null)
{
var status = await Permissions.CheckStatusAsync();
if (status == PermissionStatus.Granted)
{
try
{
var locations = await Geocoding.Default.GetLocationsAsync($"{address.AddressLine1} {address.Zip} {address.City} {address.CountryCode}");
var location = locations?.FirstOrDefault();
return location;
}
catch(Exception ex)
{
await _appReportingService.TrackErrorAsync(ex);
}
}
}
return null;
}
///
/// Gibt, wenn möglich, die aktuelle Adresse zu einer Position zurück
///
/// Adresse oder null, wenn keine gefunden
public async Task GetAddressByCurrentLocationAsync()
{
var location = new LocationDto();
try
{
var appSettings = _settingsService.GetAppSettings();
if (appSettings.FakeGps)
{
var locationDto = new LocationDto
{
Lat = appSettings.Latitude,
Lng = appSettings.Longitude
};
var placemarks = await Geocoding.Default.GetPlacemarksAsync(locationDto.Lat.Value, locationDto.Lng.Value);
if (placemarks != null && placemarks.Any())
{
var placemark = placemarks.FirstOrDefault();
var countryCode = placemark.CountryCode.ToUpper();
var stateCode = string.Empty;
var state = await _countryService.GetStateByNameAsync(location.CountryCode, placemark.AdminArea);
if (state != null)
stateCode = state.Code;
var address = new Address
{
AddressLine1 = placemark.Thoroughfare,
AddressLine2 = string.Empty,
Zip = placemark.PostalCode,
City = placemark.Locality,
State = stateCode,
CountryCode = countryCode
};
if (!string.IsNullOrWhiteSpace(placemark.SubThoroughfare))
address.AddressLine1 += $" {placemark.SubThoroughfare}";
if (!string.IsNullOrWhiteSpace(address.AddressLine1) && !string.IsNullOrWhiteSpace(address.Zip) && !string.IsNullOrWhiteSpace(address.City) && !string.IsNullOrWhiteSpace(address.State) && !string.IsNullOrWhiteSpace(address.CountryCode))
return address;
else
return null;
}
return null;
}
var status = await Permissions.CheckStatusAsync();
if (status == PermissionStatus.Granted)
{
var foundLocation = await Geolocation.Default.GetLastKnownLocationAsync();
if (foundLocation == null)
{
//Wenn nichts im Cache, direkt holen. Kann länger dauern
using var cts = new CancellationTokenSource(Constants.GpsRealtimeTimout);
foundLocation = await Geolocation.Default.GetLocationAsync(new GeolocationRequest(GeolocationAccuracy.Medium, Constants.GpsRealtimeTimout), cts.Token);
}
if (foundLocation != null)
{
location.Lat = foundLocation.Latitude;
location.Lng = foundLocation.Longitude;
var placemarks = await Geocoding.Default.GetPlacemarksAsync(foundLocation);
if (placemarks != null && placemarks.Any())
{
var placemark = placemarks.FirstOrDefault();
var countryCode = placemark.CountryCode.ToUpper();
var stateCode = string.Empty;
var state = await _countryService.GetStateByNameAsync(countryCode, placemark.AdminArea);
if (state != null)
stateCode = state.Code;
var address = new Address
{
AddressLine1 = placemark.Thoroughfare,
AddressLine2 = string.Empty,
Zip = placemark.PostalCode,
City = placemark.Locality,
State = stateCode,
CountryCode = countryCode
};
if (!string.IsNullOrWhiteSpace(placemark.SubThoroughfare))
address.AddressLine1 += $" {placemark.SubThoroughfare}";
//return address;
if (!string.IsNullOrWhiteSpace(address.AddressLine1) && !string.IsNullOrWhiteSpace(address.Zip) && !string.IsNullOrWhiteSpace(address.City) && !string.IsNullOrWhiteSpace(address.State) && !string.IsNullOrWhiteSpace(address.CountryCode))
return address;
else
return null;
}
}
}
}
catch(Exception ex)
{
await _appReportingService.TrackErrorAsync(ex);
}
return null;
}
}
}