package com.adealink.frame.imkit.widget.adapter

import androidx.collection.SparseArrayCompat
import com.adealink.frame.imkit.model.TAG_IM_UI
import com.adealink.frame.log.Log

class ProviderManager<T>() {
    val lock: Any = Any()
    private val DEFAULT_ITEM_VIEW_TYPE = -100
    private val providers = SparseArrayCompat<IViewProvider<T>>()
    private var defaultProvider: IViewProvider<T>

    init {
        defaultProvider = DefaultProvider()
    }

    constructor(providerList: List<IViewProvider<T>>) : this() {
        for (provider in providerList) {
            addProvider(provider)
        }
    }

    val providerCount: Int
        get() = providers.size()

    fun addProvider(provider: IViewProvider<T>?) {
        synchronized(lock) {
            val viewType = providers.size()
            if (provider != null) {
                providers.put(viewType, provider)
            }
        }
    }

    fun addProvider(viewType: Int, provider: IViewProvider<T>?) {
        synchronized(lock) {
            val viewProvider = providers[viewType]
            if (viewProvider != null) {
                Log.e(
                    TAG_IM_UI,
                    "An ItemViewProvider is already registered for the viewType = "
                            + viewType
                            + ". Already registered ItemViewProvider is "
                            + viewProvider
                )
            } else {
                if (provider != null) {
                    providers.put(viewType, provider)
                } else {
                    //Ntd.
                }
            }
        }
    }

    /** 设置默认模板。当找不到和 viewType 对应的模板时，使用此默认模板进行 ui 处理。  */
    fun setDefaultProvider(defaultProvider: IViewProvider<T>) {
        this.defaultProvider = defaultProvider
    }

    fun removeProvider(provider: IViewProvider<T>?) {
        if (provider == null) {
            Log.e(TAG_IM_UI, "ItemViewProvider is null")
            return
        }
        val indexToRemove = providers.indexOfValue(provider)

        if (indexToRemove >= 0) {
            providers.removeAt(indexToRemove)
        }
    }

    fun replaceProvider(oldProviderClass: Class<*>, provider: IViewProvider<T>) {
        var key = -1
        for (i in 0 until providers.size()) {
            val index = providers.keyAt(i)
            val item = providers[index]
            if (item != null && item.javaClass == oldProviderClass) {
                key = index
                break
            }
        }
        if (key != -1) {
            providers.put(key, provider)
        }
    }

    fun removeProvider(itemType: Int) {
        val indexToRemove = providers.indexOfKey(itemType)
        if (indexToRemove >= 0) {
            providers.removeAt(indexToRemove)
        }
    }

    fun getProvider(viewType: Int): IViewProvider<T> {
        var provider = providers[viewType]
        if (provider == null) {
            provider = defaultProvider
        }
        return provider
    }

    fun getItemViewType(provider: IViewProvider<T>): Int {
        return providers.indexOfValue(provider)
    }

    fun getItemViewType(item: T, position: Int): Int {
        val count = providers.size()
        for (i in count - 1 downTo 0) {
            val provider = providers.valueAt(i)
            if (provider != null && provider.isItemViewType(item)) {
                return providers.keyAt(i)
            }
        }
        return DEFAULT_ITEM_VIEW_TYPE
    }

    fun getProvider(item: T): IViewProvider<T> {
        for (i in 0 until providers.size()) {
            val provider = providers.valueAt(i)
            if (provider != null && provider.isItemViewType(item)) {
                return provider
            }
        }
        return defaultProvider
    }

    fun copy(): ProviderManager<T> {
        val providers = this.providers.clone()
        val list = (0 until providers.size()).map { providers.valueAt(it) }
        return ProviderManager(list).apply {
            setDefaultProvider(this@ProviderManager.defaultProvider)
        }
    }
}
