package com.github.insanusmokrassar.SauceNaoAPI.utils import com.github.insanusmokrassar.SauceNaoAPI.additional.LONG_TIME_RECALCULATING_MILLIS import com.github.insanusmokrassar.SauceNaoAPI.additional.SHORT_TIME_RECALCULATING_MILLIS import com.soywiz.klock.DateTime import com.soywiz.klock.TimeSpan import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.launch import java.io.Closeable import kotlin.coroutines.Continuation import kotlin.coroutines.suspendCoroutine private fun MutableList.clearTooOldTimes(relatedTo: DateTime = DateTime.now()) { val limitValue = relatedTo - LONG_TIME_RECALCULATING_MILLIS removeAll { it < limitValue } } private interface TimeManagerAction { suspend fun makeChangeWith(times: MutableList) suspend operator fun invoke(times: MutableList) = makeChangeWith(times) } private data class TimeManagerClean(private val relatedTo: DateTime = DateTime.now()) : TimeManagerAction { override suspend fun makeChangeWith(times: MutableList) { times.clearTooOldTimes(relatedTo) } } private data class TimeManagerTimeAdder( private val time: DateTime = DateTime.now() ) : TimeManagerAction { override suspend fun makeChangeWith(times: MutableList) { times.add(time) times.clearTooOldTimes() } } private data class TimeManagerMostOldestInLongGetter( private val continuation: Continuation ) : TimeManagerAction { override suspend fun makeChangeWith(times: MutableList) { times.clearTooOldTimes() continuation.resumeWith(Result.success(times.min())) } } private data class TimeManagerMostOldestInShortGetter( private val continuation: Continuation ) : TimeManagerAction { override suspend fun makeChangeWith(times: MutableList) { times.clearTooOldTimes() val now = DateTime.now() val limitTime = now - SHORT_TIME_RECALCULATING_MILLIS continuation.resumeWith( Result.success( times.asSequence().filter { limitTime < it }.min() ) ) } } internal class TimeManager( scope: CoroutineScope ) : Closeable { private val actionsChannel = Channel(Channel.UNLIMITED) private val timeUpdateJob = scope.launch { val times = mutableListOf() for (action in actionsChannel) { action(times) } } suspend fun addTimeAndClear() { actionsChannel.send(TimeManagerTimeAdder()) } suspend fun getMostOldestInLongPeriod(): DateTime? { return suspendCoroutine { actionsChannel.offer( TimeManagerMostOldestInLongGetter(it) ) } } suspend fun getMostOldestInShortPeriod(): DateTime? { return suspendCoroutine { actionsChannel.offer(TimeManagerMostOldestInShortGetter(it)) } } override fun close() { actionsChannel.close() timeUpdateJob.cancel() } }