package com.ysnows.base.base

import android.app.Application
import android.os.Bundle
import androidx.databinding.Observable
import androidx.databinding.Observable.OnPropertyChangedCallback
import androidx.databinding.PropertyChangeRegistry
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import com.ysnows.base.inter.IViewModel
import com.ysnows.base.utils.Toasts
import com.ysnows.base.utils.UiSwitch
import com.ysnows.base.view.BView

open class BViewModel<BR : BRepository>(application: Application) : AndroidViewModel(application), IViewModel, Observable {

    val refreshing: MutableLiveData<Boolean> = MutableLiveData(false)


    private lateinit var repository: BR

    init {

    }

    protected lateinit var bView: BView


    override fun <T> single(clazz: Class<T>) {
        UiSwitch.single(view()!!.context(), clazz)
    }

    override fun <T> bundle(clazz: Class<T>, bundle: Bundle?) {
        UiSwitch.bundle(view()!!.context(), clazz, bundle)
    }

    override fun <T> singleFromBottom(clazz: Class<T>) {
        UiSwitch.singleFromBottom(view()!!.context(), clazz)
    }

    override fun <T> bundleBottom(clazz: Class<T>, bundle: Bundle?) {
        UiSwitch.bundleBottom(view()!!.context(), clazz, bundle)
    }

    override fun toast(msg: String?) {
        Toasts.toast(view()!!.context(), msg)
    }

    override fun toast(msgId: Int) {
        Toasts.toast(view()!!.context(), msgId)
    }

    override fun firstReq() {}

    override fun attachView(view: BView) {
        bView = view
        initRepository()
    }

    override fun init() {}
    override fun view(): BView {
        return bView
    }

    @Transient
    private var mCallbacks: PropertyChangeRegistry? = null
    override fun addOnPropertyChangedCallback(callback: OnPropertyChangedCallback) {
        synchronized(this) {
            if (mCallbacks == null) {
                mCallbacks = PropertyChangeRegistry()
            }
        }
        mCallbacks!!.add(callback)
    }

    override fun removeOnPropertyChangedCallback(callback: OnPropertyChangedCallback) {
        synchronized(this) {
            if (mCallbacks == null) {
                return
            }
        }
        mCallbacks!!.remove(callback)
    }

    /**
     * Notifies listeners that all properties of this instance have changed.
     */
    open fun notifyChange() {
        synchronized(this) {
            if (mCallbacks == null) {
                return
            }
        }
        mCallbacks!!.notifyCallbacks(this, 0, null)
    }

    /**
     * Notifies listeners that a specific property has changed. The getter for the property
     * that changes should be marked with [Bindable] to generate a field in
     * `BR` to be used as `fieldId`.
     *
     * @param fieldId The generated BR id for the Bindable field.
     */
    open fun notifyPropertyChanged(fieldId: Int) {
        synchronized(this) {
            if (mCallbacks == null) {
                return
            }
        }
        mCallbacks!!.notifyCallbacks(this, fieldId, null)
    }


    /**
     * 初始化Presenter
     *
     * @return
     */
    private fun initRepository(): BR {
        repository = createRepository()
        repository.attachView(view())
        return repository
    }

    open fun createRepository(): BR {
        return BRepository() as BR
    }

    fun repository(): BR {
        return repository
    }

}