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.
92 lines
2.9 KiB
92 lines
2.9 KiB
package net.aiterp.git.ykonsole2.infrastructure.drivers
|
|
|
|
import net.aiterp.git.ykonsole2.application.logging.log
|
|
import net.aiterp.git.ykonsole2.domain.models.*
|
|
import net.aiterp.git.ykonsole2.domain.runtime.*
|
|
import net.aiterp.git.ykonsole2.infrastructure.drivers.abstracts.ReactiveDriver
|
|
|
|
class ProgramEnforcer(
|
|
private val programRepo: ProgramRepository,
|
|
private val workoutRepo: WorkoutRepository,
|
|
) : ReactiveDriver() {
|
|
private var lastTransition: WorkoutState = WorkoutState()
|
|
private var lastValues: ValuesReceived? = null
|
|
private var lastStep: ProgramStep? = null
|
|
private var stepIndex: Int = 0
|
|
private var program: Program? = null
|
|
|
|
private suspend fun runTransition(input: CommandBus, newEvent: ValuesReceived? = null) {
|
|
val prog = program ?: return
|
|
val event = newEvent ?: lastValues ?: return
|
|
|
|
if (prog.steps.size > stepIndex + 1) {
|
|
stepIndex += 1
|
|
|
|
log.info("$stepIndex: Jumped!")
|
|
// Go to next step and send the change
|
|
lastTransition = lastTransition.copy(
|
|
time = event.values.find() ?: lastTransition.time,
|
|
calories = event.values.find(),
|
|
distance = event.values.find(),
|
|
level = event.values.find(),
|
|
)
|
|
lastStep = prog.steps[stepIndex]
|
|
lastStep?.values?.forEach { input.emit(SetValueCommand(it)) }
|
|
} else {
|
|
log.info("$stepIndex: Stopped!")
|
|
// The program is done, let's stop it
|
|
lastStep = null
|
|
program = null
|
|
input.emit(StopCommand)
|
|
}
|
|
}
|
|
|
|
override suspend fun onEvent(event: Event, input: FlowBus<Command>) {
|
|
if (event is Connected) {
|
|
// Start program on connecting
|
|
val programId = workoutRepo.findActive()?.apply {
|
|
lastTransition = WorkoutState(workoutId = id)
|
|
}?.programId ?: return
|
|
program = programRepo.findById(programId)?.takeIf { it.steps.isNotEmpty() }
|
|
lastStep = program?.steps?.firstOrNull()
|
|
stepIndex = 0
|
|
}
|
|
|
|
if (event is Started) {
|
|
// Set up the first step
|
|
lastStep?.apply {
|
|
values.map { input.emit(SetValueCommand(it)) }
|
|
}
|
|
}
|
|
|
|
if (event is Skipped) {
|
|
runTransition(input)
|
|
}
|
|
|
|
if (event is ValuesReceived && program != null && lastStep != null) {
|
|
// If there's a program, look for next transition
|
|
|
|
val step = lastStep!!
|
|
|
|
val transition = when (step.duration) {
|
|
is Time -> (event.values.findInt<Time>()) >= lastTransition.time.toInt() + step.duration.toInt()
|
|
is Calories -> (event.values.findInt<Calories>()) >= (lastTransition.calories.toInt()) + step.duration.toInt()
|
|
is Distance -> (event.values.findInt<Distance>()) >= (lastTransition.distance.toInt()) + step.duration.toInt()
|
|
else -> false
|
|
}
|
|
|
|
if (transition) {
|
|
runTransition(input, event)
|
|
}
|
|
|
|
lastValues = event
|
|
}
|
|
|
|
if (event is Disconnected) {
|
|
// Let's clear everything
|
|
lastTransition = WorkoutState()
|
|
lastStep = null
|
|
program = null
|
|
}
|
|
}
|
|
}
|