<commit_before>/*
 * Copyright 2019 <NAME>
 *
 * 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.
 *
 */

package com.pyamsoft.pydroid.ui.arch

import androidx.annotation.CheckResult
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Lifecycle.Event.ON_DESTROY
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProvider.Factory
import androidx.lifecycle.ViewModelProviders
import androidx.lifecycle.ViewModelStore
import com.pyamsoft.pydroid.arch.UiViewModel
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

/**
 * Allow nullable for easier caller API
 */
@CheckResult
inline fun <reified T : UiViewModel<*, *, *>> LifecycleOwner.factory(
  store: ViewModelStore,
  crossinline factoryProvider: () -> Factory?
): ViewModelFactory<T> {
  return lifecycle.factory(store, factoryProvider)
}

/**
 * Allow nullable for easier caller API
 */
@CheckResult
inline fun <reified T : UiViewModel<*, *, *>> Lifecycle.factory(
  store: ViewModelStore,
  crossinline factoryProvider: () -> Factory?
): ViewModelFactory<T> {
  return ViewModelFactory(this, store, T::class.java) { requireNotNull(factoryProvider()) }
}

/**
 * Allow nullable for easier caller API
 */
@CheckResult
inline fun <reified T : UiViewModel<*, *, *>> Fragment.factory(
  crossinline factoryProvider: () -> Factory?
): ViewModelFactory<T> {
  return ViewModelFactory(this, T::class.java) { requireNotNull(factoryProvider()) }
}

/**
 * Allow nullable for easier caller API
 */
@CheckResult
inline fun <reified T : UiViewModel<*, *, *>> FragmentActivity.factory(
  crossinline factoryProvider: () -> Factory?
): ViewModelFactory<T> {
  return ViewModelFactory(this, T::class.java) { requireNotNull(factoryProvider()) }
}

class ViewModelFactory<T : UiViewModel<*, *, *>> private constructor(
  private val lifecycle: Lifecycle,
  private val store: ViewModelStore?,
  private val fragment: Fragment?,
  private val activity: FragmentActivity?,
  private val type: Class<T>,
  private val factoryProvider: () -> Factory
) : ReadOnlyProperty<Any, T> {

  constructor(
    lifecycle: Lifecycle,
    store: ViewModelStore,
    type: Class<T>,
    factoryProvider: () -> Factory
  ) : this(lifecycle, store, null, null, type, factoryProvider)

  constructor(
    fragment: Fragment,
    type: Class<T>,
    factoryProvider: () -> Factory
  ) : this(fragment.viewLifecycleOwner.lifecycle, null, fragment, null, type, factoryProvider)

  constructor(
    activity: FragmentActivity,
    type: Class<T>,
    factoryProvider: () -> Factory
  ) : this(activity.lifecycle, null, null, activity, type, factoryProvider)

  private val lock = Any()
  @Volatile private var value: T? = null

  private fun attachToLifecycle() {
    lifecycle.addObserver(object : LifecycleObserver {

      @Suppress("unused")
      @OnLifecycleEvent(ON_DESTROY)
      fun onDestroy() {
        lifecycle.removeObserver(this)
        value = null
      }

    })
  }

  @CheckResult
  private fun resolveValue(): T {
    attachToLifecycle()
    store?.let { s ->
      return ViewModelProvider(s, factoryProvider())
          .get(type)
    }
    fragment?.let { f ->
      return ViewModelProviders.of(f, factoryProvider())
          .get(type)
    }
    activity?.let { a ->
      return ViewModelProviders.of(a, factoryProvider())
          .get(type)
    }
    throw IllegalStateException("Both Fragment an Activity are null")
  }

  override fun getValue(
    thisRef: Any,
    property: KProperty<*>
  ): T {
    val v = value
    if (v != null) {
      return v
    }

    if (value == null) {
      synchronized(lock) {
        if (value == null) {
          value = resolveValue()<commit_msg>Don't ask for lifecycle until needed<commit_after>/*
 * Copyright 2019 <NAME>
 *
 * 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.
 *
 */

package com.pyamsoft.pydroid.ui.arch

import androidx.annotation.CheckResult
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Lifecycle.Event.ON_DESTROY
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProvider.Factory
import androidx.lifecycle.ViewModelProviders
import androidx.lifecycle.ViewModelStore
import com.pyamsoft.pydroid.arch.UiViewModel
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

/**
 * Allow nullable for easier caller API
 */
@CheckResult
inline fun <reified T : UiViewModel<*, *, *>> LifecycleOwner.factory(
  store: ViewModelStore,
  crossinline factoryProvider: () -> Factory?
): ViewModelFactory<T> {
  return lifecycle.factory(store, factoryProvider)
}

/**
 * Allow nullable for easier caller API
 */
@CheckResult
inline fun <reified T : UiViewModel<*, *, *>> Lifecycle.factory(
  store: ViewModelStore,
  crossinline factoryProvider: () -> Factory?
): ViewModelFactory<T> {
  return ViewModelFactory(this, store, T::class.java) { requireNotNull(factoryProvider()) }
}

/**
 * Allow nullable for easier caller API
 */
@CheckResult
inline fun <reified T : UiViewModel<*, *, *>> Fragment.factory(
  crossinline factoryProvider: () -> Factory?
): ViewModelFactory<T> {
  return ViewModelFactory(this, T::class.java) { requireNotNull(factoryProvider()) }
}

/**
 * Allow nullable for easier caller API
 */
@CheckResult
inline fun <reified T : UiViewModel<*, *, *>> FragmentActivity.factory(
  crossinline factoryProvider: () -> Factory?
): ViewModelFactory<T> {
  return ViewModelFactory(this, T::class.java) { requireNotNull(factoryProvider()) }
}

class ViewModelFactory<T : UiViewModel<*, *, *>> private constructor(
  private val lifecycleProvider: () -> Lifecycle,
  private val store: ViewModelStore?,
  private val fragment: Fragment?,
  private val activity: FragmentActivity?,
  private val type: Class<T>,
  private val factoryProvider: () -> Factory
) : ReadOnlyProperty<Any, T> {

  constructor(
    lifecycle: Lifecycle,
    store: ViewModelStore,
    type: Class<T>,
    factoryProvider: () -> Factory
  ) : this({ lifecycle }, store, null, null, type, factoryProvider)

  constructor(
    fragment: Fragment,
    type: Class<T>,
    factoryProvider: () -> Factory
  ) : this({ fragment.viewLifecycleOwner.lifecycle }, null, fragment, null, type, factoryProvider)

  constructor(
    activity: FragmentActivity,
    type: Class<T>,
    factoryProvider: () -> Factory
  ) : this({ activity.lifecycle }, null, null, activity, type, factoryProvider)

  private val lock = Any()
  @Volatile private var value: T? = null

  private fun attachToLifecycle(lifecycle: Lifecycle) {
    lifecycle.addObserver(object : LifecycleObserver {

      @Suppress("unused")
      @OnLifecycleEvent(ON_DESTROY)
      fun onDestroy() {
        lifecycle.removeObserver(this)
        value = null
      }

    })
  }

  @CheckResult
  private fun resolveValue(): T {
    attachToLifecycle(lifecycleProvider())
    store?.let { s ->
      return ViewModelProvider(s, factoryProvider())
          .get(type)
    }
    fragment?.let { f ->
      return ViewModelProviders.of(f, factoryProvider())
          .get(type)
    }
    activity?.let { a ->
      return ViewModelProviders.of(a, factoryProvider())
          .get(type)
    }
    throw IllegalStateException("Both Fragment an Activity are null")
  }

  override fun getValue(
    thisRef: Any,
    property: KProperty<*>
  ): T {
    val v = value
    if (v != null) {
      return v
    }

    if (value == null) {
      synchronized(lock) {
        if (value == null) {
          value = resolveValue()
{'fraction_non_alphanumeric': 0.11023798832510104, 'fraction_numerical': 0.001796138302649304, 'mean_word_length': 3.9494444444444445, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 68, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '3750562', 'n_tokens_mistral': 2587, 'n_tokens_neox': 2514, 'n_words': 712}