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;
}
}
}
}