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
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")
|
|
}
|