package com.github.apognu.otter.repositories import android.content.Context import com.github.apognu.otter.utils.Cache import com.github.apognu.otter.utils.CacheItem import com.github.apognu.otter.utils.untilNetwork import com.google.gson.Gson import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.channels.Channel import java.io.BufferedReader interface Upstream { fun fetch(data: List = listOf()): Channel>? } abstract class Repository> { enum class Origin(val origin: Int) { Cache(0b01), Network(0b10) } data class Response(val origin: Origin, val data: List) abstract val context: Context? abstract val cacheId: String? abstract val upstream: Upstream private var _channel: Channel>? = null private val channel: Channel> get() { if (_channel?.isClosedForSend ?: true) { _channel = Channel(10) } return _channel!! } protected open fun cache(data: List): C? = null protected open fun uncache(reader: BufferedReader): C? = null fun fetch(upstreams: Int = Origin.Cache.origin and Origin.Network.origin, from: List = listOf()): Channel> { if (Origin.Cache.origin and upstreams == upstreams) fromCache() if (Origin.Network.origin and upstreams == upstreams) fromNetwork(from) return channel } private fun fromCache() { cacheId?.let { cacheId -> Cache.get(context, cacheId)?.let { reader -> uncache(reader)?.let { cache -> channel.offer(Response(Origin.Cache, cache.data)) } } } } private fun fromNetwork(from: List) { upstream.fetch(data = from)?.untilNetwork(IO) { val data = onDataFetched(it) cacheId?.let { cacheId -> Cache.set( context, cacheId, Gson().toJson(cache(data)).toByteArray() ) } channel.offer(Response(Origin.Network, data)) } } protected open fun onDataFetched(data: List) = data }