GoogleMap Autocomplete API with Timezone 

##Introductions
Google Place Autocomplete is a service that return the place prediction according to the user's search queries.
<img width="415" alt="screenshot.png" src="https://qiita-image-store.s3.amazonaws.com/0/211892/ff99cebd-98e1-7df7-3638-22d84f607b0a.png">
In this article, I will show on how we can implement this service in iOS
##Tools and Libraries
* Xcode 9+
* Swift 4+
* APIKit
* Himotoki
* GooglePlaces
* RxSwift

##Setup Environment
Now let's go ahead and create a blank single view application in Xcode and name it as what you want. After that install all the required libraries using CocoaPod. I assume you have CocoaPod install in you local machine. If you don't have, I recommend you to check out <a href="https://cocoapods.org">this website</a> before move on to the next step.
In terminal, navigate to the project directory and run

```terminal
pod init
pod install
```
Then, in your pod file, add these following libraries

```swift
  pod "GooglePlaces"
  pod "GooglePlacePicker"
  pod "GoogleMaps"
  pod "RxSwift"
  pod "APIKit"
  pod "Himotoki"
```
and run 

```terminal
pod install
```
##Create project and enable API in Google Developer Console
Now that you have dev-environment setup. Let go and create a new project in <a href="https://console.developers.google.com/">google developer console</a>.
After that go ahead and enable <b>Map SDK for iOS</b> and <b>Time Zone API</b>.
In you dashboard panel, click on <i>credential</i> and create new <b>APIKey</b>
<img width="255" alt="screenshot.png" src="https://qiita-image-store.s3.amazonaws.com/0/211892/202e220f-c9b8-fdcb-1971-d21ff0d4ea3c.png">
You will use this <b>APIKey</b> later in the project.
##Coding part
As We already have environment setup and APIKey, It's time to get our hand dirty. Open the <b>AppDelegate.swift</b> and add

```swift
import GooglePlaces
```
After that in <i>didFinishLaunchingWithOptions</i> callback, add our Google APIKey that we have created in the previous step

```swift
GMSPlacesClient.provideAPIKey("< your-api-key-from-google-developer-console >")
```
In the project directory create new folder call <i>Extensions</i> and in that folder create a new file <b>APIKit+Extension.swift</b> and this following block of code

```swift
import APIKit
import RxSwift

extension Session {
    func sendRequest<T: Request>(request: T) -> Observable<T.Response> {
        return Observable.create { observer in
            let task = self.send(request) { result in
                switch result {
                case .success(let res):
                    observer.on(.next(res))
                    observer.on(.completed)
                case .failure(let err):
                    observer.onError(err)
                }
            }
            return Disposables.create {
                task?.cancel()
            }
        }
    }

    class func sendRequest<T: Request>(request: T) -> Observable<T.Response> {
        return shared.rx_sendRequest(request: request)
    }
}
```
We need to create some request type for <b>APIKit</b>. Now let's go ahead and create <b>RequestType.swift</b> and add this following code to it

```swift
import APIKit
import Himotoki

protocol RequestType: APIKit.Request {}

extension RequestType {
    
    
    var baseURL: URL {
        return URL(string: "https://maps.googleapis.com")!
    }
    
    var headerFields: [String: String] {
        return [
            "Accept": "application/json"
        ]
    }
    
}

// MARK: Decode
extension RequestType where Response: Himotoki.Decodable {
    func response(from object: Any, urlResponse: HTTPURLResponse) throws -> Self.Response {
        return try decodeValue(object)
    }
}
```
We use <b>Himotoki</b> decodable as the response type.
In your root directory of the project create a new file call <b>APIClient.swift</b> and add this block of code

```swift
import RxSwift
import APIKit
import Result

struct APIClient {
    
    struct Timezone {
        static func getTimezone(location: String, timestamp: Double) -> Observable<APIClient.Timezone.ResponseTimezone> {
            return Session.sendRequest(request: TimezoneRequest(location: location, timestamp: timestamp))
        }
    }
    
}
```
We passed <b>TimezoneReqest</b> as the parameter of <b>Session.sendRequest</b> but we didn't have it yet. Let's go and create new file call <b>TimezoneRequest.swift</b> and add this following code

```swift
import Foundation
import APIKit
import Himotoki

extension APIClient.Timezone {
    struct TimezoneRequest: RequestType {
        typealias Response = APIClient.Timezone.ResponseTimezone
        
        let location: String
        let timestamp: Double
        
        var path: String {
            return "/maps/api/timezone/json"
        }
        
        var method: HTTPMethod {
            return .get
        }
        
        var parameters: Any? {
            let params = [
                "location": self.location,
                "timestamp": self.timestamp,
                "key": "< your-google-api-key-from-google-developer-console >"
                ] as [String : Any] as [String : Any]
            return params
        }
    }
    
    struct ResponseTimezone: Himotoki.Decodable {
        let dstOffset: Int
        let rawOffset: Int
        let status: String
        let timeZoneId: String
        let timeZoneName: String
        
        static func decode(_ e: Extractor) throws -> APIClient.Timezone.ResponseTimezone{
            return try ResponseTimezone(
                dstOffset: e <| "dstOffset",
                rawOffset: e <| "rawOffset",
                status: e <| "status",
                timeZoneId: e <| "timeZoneId",
                timeZoneName:  e <| "timeZoneName"
            )
        }
    }
}
```
Now we've setup and prepare stuff for the <b>Timezone</b> http request. Let's create the <b>Google Map Autocomplete</b>. Open <b>ViewController.swift</b> and import <i>GooglePlaces</i>

```swift
import GooglePlaces
```
After that add this code to <b>viewDidAppear()</b> callback

```swift
let autocompleteController = GMSAutocompleteViewController()
autocompleteController.delegate = self
present(autocompleteController, animated: true, completion: nil)
```
Now that we have Map Autocomplete setup in the project but we need to do something else when the user select the result location. Now add this code to the end of <b>ViewController.swift</b>

```swift
extension ViewController: GMSAutocompleteViewControllerDelegate {
    
    // Handle the user's selection.
    func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
        print("place name \(place.name)")
    }
    
    func viewController(_ viewController: GMSAutocompleteViewController, didFailAutocompleteWithError error: Error) {
        print("Error: ", error.localizedDescription)
    }
    
    // User canceled the operation.
    func wasCancelled(_ viewController: GMSAutocompleteViewController) {
        print("user cancel search")
    }
    
    // Turn the network activity indicator on and off again.
    func didRequestAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
        UIApplication.shared.isNetworkActivityIndicatorVisible = true
    }
    
    func didUpdateAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
        UIApplication.shared.isNetworkActivityIndicatorVisible = false
    }
    
}
```
<b>GMSAutocompleteViewController</b> has some callback function that we can use to keep track if the user select some location or cancel the search process etc. To have those methods, <b>ViewController</b> has to be conformed to <b>GMSAutocompleteViewControllerDelegate</b> as shown in the code snippet above.
Now, in <b> didAutocompleteWith </b> add this following code to show <b>UIAlertDialog</b> contain location detail including timezone.

```swift
let timestamp = NSDate().timeIntervalSince1970
APIClient.Timezone.getTimezone(location: "\(place.coordinate.latitude),\(place.coordinate.longitude)", timestamp: timestamp).subscribe { event in
   switch event {
     case .next(let resp):
          let timezoneValue = NSTimeZone(name: resp.timeZoneId)
          let info = "latitude: \(place.coordinate.latitude)\n longitude: \(place.coordinate.longitude)\ntimezoneId: \(resp.timeZoneId)\ntimezoneName: \(resp.timeZoneName)\ntimezoneValue: \(timezoneValue?.abbreviation ?? "")"
          let alert = UIAlertController(title: place.name, message: info, preferredStyle: .alert)
                
          alert.addAction(UIAlertAction(title: "Okay", style: .default, handler: nil))
          viewController.present(alert, animated: true)
     case .error(let error): print("error \(error)")
     case .completed: print("completed")
   }
}
```
We need to give two parameters (location and timestamp) for the timezone http request according to the <a href="https://developers.google.com/maps/documentation/timezone/intro">official document</a>. Now let run the application and see how it look.
That's all for this article, I also have sample code in Github where you can check it <a href="https://github.com/phanithken/GoogleMapAutocompleteAPI"> here </a>