Files
BeWoPlaner/Service/ServiceUtils/DistanceCalculator/GoogleDistanceMatrixAPI.cs
2025-06-10 14:29:34 +02:00

156 lines
5.1 KiB
C#

using BeWo.Data.Entities;
using BeWo.Service.Core;
using BS.Shared.DataContracts;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace BeWo.Service.ServiceUtils.DistanceCalculator
{
public class GoogleDistanceMatrixApi : IDistanceAPI
{
public class GoogleDistanceMatrixResponse
{
public string Status { get; set; }
[JsonProperty(PropertyName = "origin_addresses")]
public string[] OriginAddresses { get; set; }
[JsonProperty(PropertyName = "destination_addresses")]
public string[] DestinationAddresses { get; set; }
public Row[] Rows { get; set; }
public class Data
{
public int Value { get; set; }
public string Text { get; set; }
}
public class Element
{
public string Status { get; set; }
public Data Duration { get; set; }
public Data Distance { get; set; }
}
public class Row
{
public Element[] Elements { get; set; }
}
}
private string Key { get; set; }
private string Url { get; set; }
private AddressRouteMatrix Matrix { get; set; }
private Address[] OriginAddresses { get; set; }
private Address[] DestinationAddresses { get; set; }
public GoogleDistanceMatrixApi()
{
var appSettings = ConfigurationManager.AppSettings;
Url = appSettings["GoogleDistanceMatrixApiUrl"];
if (string.IsNullOrEmpty(Url))
{
throw new Exception("GoogleDistanceMatrixApiUrl is not set in AppSettings.");
}
Key = MergedConfig.GetSecretSetting(WebSecretConfigSetting.GoogleDistanceMatrixApiKey);
if (string.IsNullOrEmpty(Key))
{
throw new Exception("GoogleDistanceMatrixApiKey is not set.");
}
}
public void RequestMissingData(ref AddressRouteMatrix matrix, IEnumerable<Address> origins, IEnumerable<Address> destinations)
{
Matrix = matrix;
OriginAddresses = origins.ToArray();
DestinationAddresses = destinations.ToArray();
var task = GetMatrix();
task.Wait();
if (task.Exception is object)
{
throw task.Exception;
}
}
public async Task<AddressRouteMatrix> GetMatrix()
{
using (var client = new HttpClient())
{
var uri = new Uri(GetRequestUrl());
HttpResponseMessage response = await client.GetAsync(uri);
if (!response.IsSuccessStatusCode)
{
throw new Exception("GoogleDistanceMatrixApi failed with status code: " + response.StatusCode);
}
else
{
var content = await response.Content.ReadAsStringAsync();
return FillMatrix(JsonConvert.DeserializeObject<GoogleDistanceMatrixResponse>(content));
}
}
}
public AddressRouteMatrix FillMatrix(GoogleDistanceMatrixResponse response)
{
for (int i = 0; i < response.Rows.Length; i++)
{
var row = response.Rows[i];
var origin = OriginAddresses[i];
for (int j = 0; j < row.Elements.Length; j++)
{
var element = row.Elements[j];
var destination = DestinationAddresses[j];
var route = Matrix.GetRoute(origin, destination);
route.Distance_in_meter = element.Distance.Value;
route.Distance_in_meter_txt = element.Distance.Text;
route.Time_in_seconds = element.Duration.Value;
route.Time_in_seconds_txt = element.Duration.Text;
}
}
return Matrix;
}
public AddressRoute ToAddressRoute(GoogleDistanceMatrixResponse.Element element)
{
var res = new AddressRoute();
res.Distance_in_meter = element.Distance.Value;
res.Distance_in_meter_txt = element.Distance.Text;
res.Time_in_seconds = element.Duration.Value;
res.Time_in_seconds_txt = element.Duration.Text;
return res;
}
private string GetRequestUrl()
{
var originAddresses = OriginAddresses.Select(str => AddressRouteManager.AddressToString(str)).Select(HttpUtility.UrlEncode).ToArray();
var origins = string.Join("|", originAddresses);
var destinationAddresses = DestinationAddresses.Select(str => AddressRouteManager.AddressToString(str)).Select(HttpUtility.UrlEncode).ToArray();
var destinations = string.Join("|", destinationAddresses);
return $"{Url}?origins={origins}&destinations={destinations}&key={Key}";
}
}
}