You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

89 lines
3.0 KiB

package net.aiterp.git.ykonsole2.domain.models
import net.aiterp.git.ykonsole2.domain.runtime.*
fun MutableMap<Value, List<Value>>.tryMilestone(event: ValuesReceived): MilestoneReached? = tryMilestone(event.values)
fun List<WorkoutState>.makeMilestoneReachedEvents(): List<MilestoneReached> {
val cache = mutableMapOf<Value, List<Value>>()
return mapNotNull { cache.tryMilestone(it) }
}
private fun MutableMap<Value, List<Value>>.tryMilestone(state: WorkoutState): MilestoneReached? =
tryMilestone(state.asValueList())
private fun MutableMap<Value, List<Value>>.tryMilestone(newValues: List<Value>): MilestoneReached? {
val time = newValues.find<Time>() ?: return null
val calories = newValues.find<Calories>() ?: return null
val distance = newValues.find<Distance>() ?: return null
var next: MilestoneReached? = null
val roundDistance = distance.roundedDown
if (roundDistance.isMilestone && !containsKey(roundDistance)) {
val last = getOrDefault(distance.lastMilestone, default)
this[roundDistance] = listOf(time, calories)
next = MilestoneReached(
roundDistance, listOf(time, calories), listOf(
Time(time.seconds - last.findInt<Time>()),
Calories(calories.kcal - last.findInt<Calories>()),
)
)
}
val roundedCals = calories.roundedDown
if (roundedCals.isMilestone && !containsKey(roundedCals)) {
val last = getOrDefault(roundedCals.lastMilestone, default)
this[roundedCals] = listOf(time, distance)
next = MilestoneReached(
roundedCals, listOf(time, distance), listOf(
Time(time.seconds - last.findInt<Time>()),
Distance(distance.meters - last.findInt<Distance>()),
)
)
}
val roundedTime = time.roundedDown
if (roundedTime.isMilestone && !containsKey(roundedTime)) {
val last = this.getOrDefault(time.lastMilestone, default)
this[roundedTime] = listOf(calories, distance)
next = MilestoneReached(
roundedTime, listOf(calories, distance), listOf(
Calories(calories.kcal - last.findInt<Calories>()),
Distance(distance.meters - last.findInt<Distance>()),
)
)
}
return next
}
private val default = listOf(Time(0), Calories(0), Distance(0))
private val Value.roundedDown
get() = when (this) {
is Time -> Time(seconds - (seconds % 2))
is Calories -> Calories(kcal - (kcal % 4))
is Distance -> Distance(meters - (meters % 10))
else -> error("Not milestone-able")
}
private val Value.isMilestone
get() = when (this) {
is Time -> seconds > 0 && seconds % 60 == 0
is Calories -> kcal > 0 && kcal % 100 == 0
is Distance -> meters > 0 && meters % 1000 == 0
else -> error("Not milestone-able")
}
private val Value.lastMilestone
get() = when (this) {
is Time -> Time(maxOf(0, (seconds - 1) - ((seconds - 1) % 60)))
is Calories -> Calories(maxOf(0, (kcal - 1) - ((kcal - 1) % 100)))
is Distance -> Distance(maxOf(0, (meters - 1) - ((meters - 1) % 1000)))
else -> error("Not milestone-able")
}