Metuuu
1/31/2018 - 11:02 AM

PlaceAutocompleteAdapter

package com.bromeco.tolppa.adapters

/**
 * Created by lauri on 12/01/2018.
 */

/*
 * Copyright (C) 2015 Google Inc. All Rights Reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */


import android.content.Context
import android.graphics.Typeface
import android.text.style.StyleSpan
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.Filter
import android.widget.Filterable
import android.widget.TextView
import android.widget.Toast

import com.google.android.gms.common.data.DataBufferUtils
import com.google.android.gms.location.places.AutocompleteFilter
import com.google.android.gms.location.places.AutocompletePrediction
import com.google.android.gms.location.places.GeoDataClient
import com.google.android.gms.maps.model.LatLngBounds
import com.google.android.gms.tasks.RuntimeExecutionException
import com.google.android.gms.tasks.Tasks

import java.util.ArrayList
import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException

/**
 * Adapter that handles Autocomplete requests from the Places Geo Data Client.
 * [AutocompletePrediction] results from the API are frozen and stored directly in this
 * adapter. (See [AutocompletePrediction.freeze].)
 */
class PlaceAutocompleteAdapter
/**
 * Initializes with a resource for text rows and autocomplete query bounds.
 *
 * @see android.widget.ArrayAdapter.ArrayAdapter
 */
(context: Context,
 /**
  * Handles autocomplete requests.
  */
 private val mGeoDataClient: GeoDataClient,
 /**
  * The bounds used for Places Geo Data autocomplete API requests.
  */
 private var mBounds: LatLngBounds?,
 /**
  * The autocomplete filter used to restrict queries to a specific set of place types.
  */
 private val mPlaceFilter: AutocompleteFilter?) : ArrayAdapter<AutocompletePrediction>(context, android.R.layout.simple_expandable_list_item_2, android.R.id.text1), Filterable {
	/**
	 * Current results returned by this adapter.
	 */
	private var mResultList: ArrayList<AutocompletePrediction>? = null

	/**
	 * Sets the bounds for all subsequent queries.
	 */
	fun setBounds(bounds: LatLngBounds) {
		mBounds = bounds
	}

	/**
	 * Returns the number of results received in the last autocomplete query.
	 */
	override fun getCount(): Int {
		return mResultList!!.size
	}

	/**
	 * Returns an item from the last autocomplete query.
	 */
	override fun getItem(position: Int): AutocompletePrediction? {
		try {
			return mResultList!![position]
		} catch (e: Exception) {
			return null
		}

	}

	override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
		val row = super.getView(position, convertView, parent)

		// Sets the primary and secondary text for a row.
		// Note that getPrimaryText() and getSecondaryText() return a CharSequence that may contain
		// styling based on the given CharacterStyle.

		val item = getItem(position)

		val textView1 = row.findViewById<TextView>(android.R.id.text1)
		val textView2 = row.findViewById<TextView>(android.R.id.text2)
		textView1.text = item!!.getPrimaryText(STYLE_BOLD)
		textView2.text = item.getSecondaryText(STYLE_BOLD)

		return row
	}

	/**
	 * Returns the filter for the current set of autocomplete results.
	 */
	override fun getFilter(): Filter {
		return object : Filter() {
			override fun performFiltering(constraint: CharSequence?): Filter.FilterResults {
				val results = Filter.FilterResults()

				// We need a separate list to store the results, since
				// this is run asynchronously.
				var filterData: ArrayList<AutocompletePrediction>? = ArrayList()

				// Skip the autocomplete query if no constraints are given.
				if (constraint != null) filterData = getAutocomplete(constraint) // Query the autocomplete API for the (constraint) search string.

				results.values = filterData
				results.count = if (filterData != null) filterData.size else 0
				return results
			}

			override fun publishResults(constraint: CharSequence?, results: Filter.FilterResults?) {

				if (results != null && results.count > 0) {
					// The API returned at least one result, update the data.
					mResultList = results.values as ArrayList<AutocompletePrediction>
					notifyDataSetChanged()
				} else {
					// The API did not return any results, invalidate the data set.
					notifyDataSetInvalidated()
				}
			}

			override fun convertResultToString(resultValue: Any): CharSequence {
				// Override this method to display a readable result in the AutocompleteTextView
				// when clicked.
				return if (resultValue is AutocompletePrediction) {
					resultValue.getFullText(null)
				} else {
					super.convertResultToString(resultValue)
				}
			}
		}
	}


	fun isThereResultsShowing(parent: ViewGroup): Boolean {
		return try {
			this.getView(0, null, parent)
			true
		} catch (e: NullPointerException) {
			false
		}
	}

	/**
	 * Submits an autocomplete query to the Places Geo Data Autocomplete API.
	 * Results are returned as frozen AutocompletePrediction objects, ready to be cached.
	 * Returns an empty list if no results were found.
	 * Returns null if the API client is not available or the query did not complete
	 * successfully.
	 * This method MUST be called off the main UI thread, as it will block until data is returned
	 * from the API, which may include a network request.
	 *
	 * @param constraint Autocomplete query string
	 * @return Results from the autocomplete API or null if the query was not successful.
	 * @see GeoDataClient.getAutocompletePredictions
	 * @see AutocompletePrediction.freeze
	 */
	private fun getAutocomplete(constraint: CharSequence?): ArrayList<AutocompletePrediction>? {
		Log.i(TAG, "Starting autocomplete query for: " + constraint!!)

		// Submit the query to the autocomplete API and retrieve a PendingResult that will
		// contain the results when the query completes.
		val results = mGeoDataClient.getAutocompletePredictions(constraint.toString(), mBounds, mPlaceFilter)
		try {
			Tasks.await(results, 20, TimeUnit.SECONDS)
		} catch (e: ExecutionException) {
			e.printStackTrace()
		} catch (e: InterruptedException) {
			e.printStackTrace()
		} catch (e: TimeoutException) {
			e.printStackTrace()
		}

		return try {
			val autocompletePredictions = results.result
			DataBufferUtils.freezeAndClose(autocompletePredictions) // Freeze the results immutable representation that can be stored safely.
		} catch (e: RuntimeExecutionException) {
			// If the query did not complete successfully return null
			Toast.makeText(context, "Error contacting API: " + e.toString(), Toast.LENGTH_SHORT).show()
			Log.e(TAG, "Error getting autocomplete prediction API call", e)
			null
		}

	}

	companion object {
		private val TAG = "PlaceAutocompleteAdapt"
		private val STYLE_BOLD = StyleSpan(Typeface.BOLD)
	}
}