package cn.muchinfo.rma.lifecycle

import androidx.lifecycle.MutableLiveData

data class Resource<out DATA>(
        var status: Status,
        var msg: CharSequence? = "",
        val data: DATA? = null,
        var error: Throwable? = null
) {
    companion object {
        fun <DATA> loading(loadingStr: CharSequence? = "", data: DATA? = null): Resource<DATA> = Resource(Status.STATUS_LOADING, loadingStr, data)
        fun <DATA> success(data: DATA, successStr: CharSequence? = ""): Resource<DATA> = Resource(Status.STATUS_SUCCESS, successStr, data)
        fun <DATA> error(message: CharSequence? = "", data: DATA? = null) = Resource(Status.STATUS_ERROR, message, data)
        fun <DATA> error(error: Throwable? = null, data: DATA? = null) = Resource(Status.STATUS_ERROR, error?.message, data, error)
        fun <DATA> empty(errorStr: CharSequence? = "", data: DATA? = null) = Resource(Status.STATUS_EMPTY, errorStr, data)
        fun <DATA> errorLiveData(error: Throwable? = null) = MutableLiveData<Resource<DATA>>().apply { postValue(error(error)) }
    }

    fun loadingMsg(msg: CharSequence? = ""): Resource<DATA> {
        if (status == Status.STATUS_LOADING) {
            this.msg = msg
        }
        return this
    }

    fun emptyMsg(msg: CharSequence? = ""): Resource<DATA> {
        if (status == Status.STATUS_EMPTY) {
            this.msg = msg
        }
        return this
    }

    fun successMsg(msg: CharSequence? = ""): Resource<DATA> {
        if (status == Status.STATUS_SUCCESS) {
            this.msg = msg
        }
        return this
    }

    fun errorMsg(msg: CharSequence? = ""): Resource<DATA> {
        if (status == Status.STATUS_ERROR) {
            this.msg = msg
        }
        return this
    }

    fun optMessage(): CharSequence {
        if (msg.isNullOrEmpty()) {
            return error?.message ?: ""
        }
        return msg ?: ""
    }
}


fun <DATA, RESULT> Resource<DATA>?.map(resource: (DATA?) -> RESULT): Resource<RESULT>? {
    this ?: return null
    return Resource<RESULT>(status, msg, resource.invoke(data), error)
}

fun <DATA> Resource<DATA>?.isCompleted(default: Boolean = true): Boolean {
    return isLoading(!default).not()
}

fun <DATA> Resource<DATA>?.isError(default: Boolean = true): Boolean {
    if ((this == null)) {
        return default
    }
    return (status == Status.STATUS_ERROR).or(status == Status.STATUS_EMPTY)
}

fun <DATA> Resource<DATA>?.isLoading(default: Boolean = true): Boolean {
    if ((this == null)) {
        return default
    }
    return status == Status.STATUS_LOADING
}

fun <DATA> Resource<DATA>?.isSuccess(default: Boolean = false): Boolean {
    if ((this == null)) {
        return default
    }
    return status == Status.STATUS_SUCCESS
}
