<commit_before>package jp.toastkid.yobidashi.search.suggestion

import android.support.v7.widget.LinearLayoutManager
import android.view.LayoutInflater
import android.widget.EditText
import io.reactivex.Completable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import io.reactivex.rxkotlin.addTo
import io.reactivex.rxkotlin.toObservable
import io.reactivex.schedulers.Schedulers
import jp.toastkid.yobidashi.R
import jp.toastkid.yobidashi.databinding.ModuleSearchSuggestionBinding
import jp.toastkid.yobidashi.libs.Toaster
import jp.toastkid.yobidashi.libs.WifiConnectionChecker
import jp.toastkid.yobidashi.libs.facade.BaseModule
import jp.toastkid.yobidashi.libs.network.NetworkChecker
import jp.toastkid.yobidashi.libs.preference.PreferenceApplier
import timber.log.Timber
import java.util.*

/**
 * Facade of search suggestion module.
 * Initialize with binding object.
 *
 * @param binding
 * @param searchInput
 *
 * @author toastkidjp
 */
class SuggestionModule(
        binding: ModuleSearchSuggestionBinding,
        searchInput: EditText,
        searchCallback: (String) -> Unit,
        searchBackgroundCallback: (String) -> Unit,
        onClick: () -> Unit
) : BaseModule(binding.root) {

    /**
     * Suggest ModuleAdapter.
     */
    private val adapter: Adapter = Adapter(
            LayoutInflater.from(context()),
            searchInput,
            searchCallback,
            searchBackgroundCallback
    )

    /**
     * Fetcher.
     */
    private val fetcher = SuggestionFetcher()

    /**
     * Cache.
     */
    private val cache = HashMap<String, List<String>>(SUGGESTION_CACHE_CAPACITY)

    /**
     * Last subscription's lastSubscription.
     */
    private var lastSubscription: Disposable? = null

    /**
     * Composite disposables.
     */
    private val disposables: CompositeDisposable = CompositeDisposable()

    init {
        binding.searchSuggestions.layoutManager = LinearLayoutManager(context())
        binding.searchSuggestions.adapter = adapter
        binding.searchSuggestions.setOnTouchListener { _, _ ->
            onClick()
            false
        }
    }

    /**
     * Clear suggestion items.
     */
    fun clear() {
        adapter.clear()
    }

    /**
     * Request web API.
     * @param key
     */
    fun request(key: String) {
        lastSubscription?.dispose()

        if (cache.containsKey(key)) {
            lastSubscription = replace(cache[key]!!).addTo(disposables)
            return
        }

        val context = context()
        if (NetworkChecker.isNotAvailable(context)) {
            return
        }

        if (PreferenceApplier(context).wifiOnly && WifiConnectionChecker.isNotConnecting(context)) {
            Toaster.tShort(context, R.string.message_wifi_not_connecting)
            return
        }

        fetcher.fetchAsync(key) { suggestions ->
            if (suggestions.isEmpty()) {
                Completable.fromAction { hide() }
                        .subscribeOn(AndroidSchedulers.mainThread())
                        .subscribe({}, Timber::e)
                        .addTo(disposables)
                return@fetchAsync
            }
            cache.put(key, suggestions)
            lastSubscription = replace(suggestions).addTo(disposables)
        }
    }

    /**
     * Use for voice search.
     *
     * @param words
     */
    internal fun addAll(words: List<String>) {
        words.toObservable()
                .subscribeOn(Schedulers.computation())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnTerminate { adapter.notifyDataSetChanged() }
                .observeOn(Schedulers.computation())
                .subscribe(adapter::add, Timber::e)
                .addTo(disposables)
    }

    /**
     * Replace suggestions with specified items.
     *
     * @param suggestions
     */
    private fun replace(suggestions: Iterable<String>): Disposable =
            suggestions.toObservable()
                    .doOnNext { adapter.add(it) }
                    .doOnSubscribe { adapter.clear() }<commit_msg>refactor #283 Convert put to assignment in SuggestionModule.<commit_after>package jp.toastkid.yobidashi.search.suggestion

import android.support.v7.widget.LinearLayoutManager
import android.view.LayoutInflater
import android.widget.EditText
import io.reactivex.Completable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import io.reactivex.rxkotlin.addTo
import io.reactivex.rxkotlin.toObservable
import io.reactivex.schedulers.Schedulers
import jp.toastkid.yobidashi.R
import jp.toastkid.yobidashi.databinding.ModuleSearchSuggestionBinding
import jp.toastkid.yobidashi.libs.Toaster
import jp.toastkid.yobidashi.libs.WifiConnectionChecker
import jp.toastkid.yobidashi.libs.facade.BaseModule
import jp.toastkid.yobidashi.libs.network.NetworkChecker
import jp.toastkid.yobidashi.libs.preference.PreferenceApplier
import timber.log.Timber
import java.util.*

/**
 * Facade of search suggestion module.
 * Initialize with binding object.
 *
 * @param binding
 * @param searchInput
 *
 * @author toastkidjp
 */
class SuggestionModule(
        binding: ModuleSearchSuggestionBinding,
        searchInput: EditText,
        searchCallback: (String) -> Unit,
        searchBackgroundCallback: (String) -> Unit,
        onClick: () -> Unit
) : BaseModule(binding.root) {

    /**
     * Suggest ModuleAdapter.
     */
    private val adapter: Adapter = Adapter(
            LayoutInflater.from(context()),
            searchInput,
            searchCallback,
            searchBackgroundCallback
    )

    /**
     * Fetcher.
     */
    private val fetcher = SuggestionFetcher()

    /**
     * Cache.
     */
    private val cache = HashMap<String, List<String>>(SUGGESTION_CACHE_CAPACITY)

    /**
     * Last subscription's lastSubscription.
     */
    private var lastSubscription: Disposable? = null

    /**
     * Composite disposables.
     */
    private val disposables: CompositeDisposable = CompositeDisposable()

    init {
        binding.searchSuggestions.layoutManager = LinearLayoutManager(context())
        binding.searchSuggestions.adapter = adapter
        binding.searchSuggestions.setOnTouchListener { _, _ ->
            onClick()
            false
        }
    }

    /**
     * Clear suggestion items.
     */
    fun clear() {
        adapter.clear()
    }

    /**
     * Request web API.
     * @param key
     */
    fun request(key: String) {
        lastSubscription?.dispose()

        if (cache.containsKey(key)) {
            lastSubscription = replace(cache[key]!!).addTo(disposables)
            return
        }

        val context = context()
        if (NetworkChecker.isNotAvailable(context)) {
            return
        }

        if (PreferenceApplier(context).wifiOnly && WifiConnectionChecker.isNotConnecting(context)) {
            Toaster.tShort(context, R.string.message_wifi_not_connecting)
            return
        }

        fetcher.fetchAsync(key) { suggestions ->
            if (suggestions.isEmpty()) {
                Completable.fromAction { hide() }
                        .subscribeOn(AndroidSchedulers.mainThread())
                        .subscribe({}, Timber::e)
                        .addTo(disposables)
                return@fetchAsync
            }
            cache[key] = suggestions
            lastSubscription = replace(suggestions).addTo(disposables)
        }
    }

    /**
     * Use for voice search.
     *
     * @param words
     */
    internal fun addAll(words: List<String>) {
        words.toObservable()
                .subscribeOn(Schedulers.computation())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnTerminate { adapter.notifyDataSetChanged() }
                .observeOn(Schedulers.computation())
                .subscribe(adapter::add, Timber::e)
                .addTo(disposables)
    }

    /**
     * Replace suggestions with specified items.
     *
     * @param suggestions
     */
    private fun replace(suggestions: Iterable<String>): Disposable =
            suggestions.toObservable()
                    .doOnNext { adapter.add(it) }
                    .doOnSubscribe { adapter.clear() }
{'fraction_non_alphanumeric': 0.09838594825539995, 'fraction_numerical': 0.0005934013766911939, 'mean_word_length': 2.3034104272834184, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '19637', 'n_tokens_mistral': 2475, 'n_tokens_neox': 2344, 'n_words': 403}