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
origins, IEnumerable
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 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(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}"; } } }