use crate::types::constants::{Language, LocationBias, PlaceSearchPlace, PlaceSearchPlaceFields};
use crate::types::FindPlaceSearchResult;
use reqwest::Client;
use std::collections::HashSet;
pub struct FindPlace<'a> {
input: Option<String>,
input_type: Option<String>,
language: Option<Language>,
fields: Option<HashSet<PlaceSearchPlaceFields>>,
location_bias: Option<LocationBias>,
api_key: String,
client: &'a Client,
result: FindPlaceSearchResult,
}
impl<'a> FindPlace<'a> {
pub fn new(api_key: &str, client: &'a Client) -> Self {
Self {
input: None,
fields: None,
language: None,
location_bias: None,
input_type: None,
api_key: String::from(api_key),
client,
result: Default::default(),
}
}
pub fn with_input(&mut self, input: &str) -> &mut FindPlace<'a> {
self.input = Some(String::from(input));
self
}
pub fn with_fields(&mut self, fields: HashSet<PlaceSearchPlaceFields>) -> &mut FindPlace<'a> {
self.fields = Some(fields);
self
}
pub fn with_language(&mut self, language: Language) -> &mut FindPlace<'a> {
self.language = Some(language);
self
}
pub fn with_location_bias(&mut self, location_bias: LocationBias) -> &mut FindPlace<'a> {
self.location_bias = Some(location_bias);
self
}
pub fn with_input_type(&mut self, input_type: &str) -> &mut FindPlace<'a> {
self.input_type = Some(String::from(input_type));
self
}
fn build_params(&self) -> Vec<(&'static str, String)> {
let mut params = vec![("key", self.api_key.clone())];
if let Some(input) = &self.input {
params.push(("input", input.clone()));
}
if let Some(fields) = &self.fields {
params.push((
"fields",
fields
.iter()
.map(|f| f.to_string())
.collect::<Vec<_>>()
.join(","),
));
}
if let Some(language) = &self.language {
params.push(("language", language.to_string()));
}
if let Some(location_bias) = &self.location_bias {
params.push(("locationbias", location_bias.to_string()));
}
if let Some(input_type) = &self.input_type {
params.push(("inputtype", input_type.clone()));
}
params
}
pub async fn execute(&mut self) -> Option<&mut FindPlace<'a>> {
match (self.input.clone(), self.input_type.clone()) {
(Some(_), Some(_)) => {
let url = "https://maps.googleapis.com/maps/api/place/findplacefromtext/json";
let params = self.build_params();
let resp = self.client.get(url).query(¶ms).send().await.unwrap();
match resp.json::<FindPlaceSearchResult>().await {
Ok(query_result) => {
self.result = query_result;
Some(self)
}
Err(err) => {
println!("Error parsing response: {:?}", err);
None
}
}
}
_ => {panic!("Provide input and inputtype for find_place query!");}
}
}
#[cfg(feature = "blocking")]
pub fn execute_blocking(&mut self) -> Option<&mut FindPlace<'a>> {
tokio::runtime::Runtime::new()
.unwrap()
.block_on(self.execute())
}
pub fn iter(&mut self) -> FindPlaceIterator<'_, 'a> {
FindPlaceIterator {
find_place: self,
current_index: 0,
}
}
pub fn at(&self, index: usize) -> Option<&PlaceSearchPlace> {
self.result.places.get(index)
}
pub fn get_result(&self) -> FindPlaceSearchResult {
self.result.clone()
}
}
pub struct FindPlaceIterator<'a, 'b> {
find_place: &'b mut FindPlace<'a>,
current_index: usize,
}
impl<'a, 'b> Iterator for FindPlaceIterator<'a, 'b> {
type Item = &'b PlaceSearchPlace;
fn next(&mut self) -> Option<Self::Item> {
if self.current_index < self.find_place.result.places.len() {
let place = &self.find_place.result.places[self.current_index];
self.current_index += 1;
Some(unsafe { std::mem::transmute(place) })
} else {
None
}
}
}