using Adrenak.Unex; using System.Text; using System.Threading.Tasks; using System; using System.Collections.Generic; using RestSharp; using UnityEngine; namespace Adrenak.UniMap { public class FindPlaceRequest { // ================================================ // INNER TYPES // ================================================ /// /// The mode of input for the search query /// public enum InputType { TextQuery, PhoneNumber } /// /// represents the types of fields that the response can contain /// public enum Field { // BASIC FormattedAddress, Geometry, Icon, ID, Name, PermanentlyClosed, Photos, PlaceID, PlusCode, Scope, Types, // CONTACT OpenNow, // ATMOSPHERE PriceLevel, Rating } /// /// Used to prefer results from a specified area /// public enum LocationBias { None, IP, Point, Circular, Rectangular } const string k_BaseURL = "https://maps.googleapis.com/maps/api/place/findplacefromtext/json?"; // ================================================ // PARAMETERS // ================================================ /// /// The Google Maps API key /// public string Key { get; private set; } /// /// The query for the search. Eg. "Eiffel Tower" or "+1 1234567890" /// public string Input { get; private set; } /// /// Input type for the query. Supported: Text and Phone number /// public InputType inputType = InputType.TextQuery; /// /// The language in which the results will be returned /// public string language; /// /// The types of places that can be returned by the response /// public List fields = new List(); /// /// Prefer results in a specified area, by specifying either a radius plus lat/lng, /// or two lat/lng pairs representing the points of a rectangle. /// If this parameter is not specified, the API uses IP address biasing by default. /// public LocationBias locationBias = LocationBias.IP; /// /// (Default:50) The radius of the search circle if the is set to /// public int radius = 50; /// /// (Default:0,0) The co-ordinate of search if the is set to or /// public Location coordinates = new Location(0, 0); /// /// (Default:0,0) The location representing South West of the rectangular search area if is set to /// public Location southWest = new Location(0, 0); /// /// (Default:0,0) The location representing North East of the rectangular search area if is set to /// public Location northEast = new Location(0, 0); /// /// Creates a new request object /// /// The Google Maps API key to use /// The name of the place to be searched for public FindPlaceRequest(string key) { Key = key; } // ================================================ // PUBLIC METHODS // ================================================ /// /// Gets the request URL for the set parameters /// public string GetURL() { // Ensure mandatory parameters if (string.IsNullOrEmpty(Key)) throw new Exception("Key is null or empty"); if (string.IsNullOrEmpty(Input)) throw new Exception("Input is null or empty"); var sb = new StringBuilder(k_BaseURL) .Append("key=").Append(Key) .Append("&input=").Append(Input) .Append("&inputtype=").Append(InputTypeToString(inputType)); if (!string.IsNullOrEmpty(language)) sb.Append("&language=").Append(language); // Add the fields separated by commas if (fields.Count > 0) { sb.Append("&fields="); for (int i = 0; i < fields.Count; i++) { sb.Append(FieldToString(fields[i])); if (i != fields.Count - 1) sb.Append(","); } } // Add the location bias based on the type selected switch (locationBias) { case LocationBias.IP: sb.Append("&locationbias=ipbias"); break; case LocationBias.Point: sb.Append("&point:").Append(coordinates.lat).Append(",").Append(coordinates.lng); break; case LocationBias.Circular: sb.Append("&circle:").Append(radius).Append("@").Append(coordinates.lat).Append(",").Append(coordinates.lng); break; case LocationBias.Rectangular: sb.Append("&rectangular:") .Append(southWest.lat).Append(",").Append(southWest.lng) .Append(northEast.lat).Append(",").Append(northEast.lng); break; } return sb.ToString(); } /// /// Send the API request and returns the response or exception /// /// The name of the place to be searched for /// Action that returns the response as a C# object /// Action that returns the exception encountered in case of an error public void Send(string placeName, Action onResult, Action onException) { Input = placeName; string url = string.Empty; try { url = GetURL(); } catch (Exception e) { onException(e); } var client = new RestClient(); var request = new RestRequest(url, Method.GET); client.ExecuteAsync(request, response => { Dispatcher.Enqueue(() => { if (response.IsSuccessful()) { try { var result = JsonUtility.FromJson(response.Content); onResult?.Invoke(result); } catch (Exception e) { onException?.Invoke(e); } } else onException?.Invoke(response.GetException()); }); }); } /// /// Send the API request and return a task for the response /// /// The name of the place to be searched public Task Send(string placeName){ var source = new TaskCompletionSource(); ; Send(placeName, result => source.SetResult(result), exception => source.SetException(exception) ); return source.Task; } // ================================================ // INNER METHODS // ================================================ string InputTypeToString(InputType type) { switch (type) { case InputType.PhoneNumber: return "phonenumber"; case InputType.TextQuery: return "textquery"; default: return "textquery"; } } string FieldToString(Field field) { switch (field) { case Field.FormattedAddress: return "formatted_address"; case Field.Geometry: return "geometry"; case Field.Icon: return "icon"; case Field.ID: return "id"; case Field.Name: return "name"; case Field.PermanentlyClosed: return "permanently_closed"; case Field.Photos: return "photos"; case Field.PlaceID: return "place_id"; case Field.PlusCode: return "plus_code"; case Field.Scope: return "scope"; case Field.Types: return "types"; case Field.OpenNow: return "open_now"; case Field.PriceLevel: return "price_level"; case Field.Rating: return "rating"; default: return string.Empty; } } } }