Defines and schedules Garmin workouts
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.

70 lines
2.3 KiB

package com.github.mgifos.workouts.model
import play.api.libs.json.{ JsValue, Json }
import Workout._
trait Workout {
def json: JsValue
}
case class WorkoutDef(sport: String, name: String, steps: Seq[Step] = Nil) extends Workout {
def toRef: WorkoutRef = WorkoutRef(name)
def withStep(step: Step): WorkoutDef = WorkoutDef(sport, name, steps :+ step)
def json: JsValue = Json.obj(
"sportType" -> Json.obj(
"sportTypeId" -> sportId(sport),
"sportTypeKey" -> sportTypeKey(sport)),
"workoutName" -> name,
"workoutSegments" -> Json.arr(
Json.obj(
"segmentOrder" -> 1,
"sportType" -> Json.obj(
"sportTypeId" -> sportId(sport),
"sportTypeKey" -> sport),
"workoutSteps" -> steps.zipWithIndex.map { case (s, i) => s.json(i + 1) })))
}
case class WorkoutRef(name: String) extends Workout {
def json: JsValue = Json.obj()
}
case class WorkoutNote(note: String) extends Workout {
def json: JsValue = Json.obj()
}
object Workout {
private val WorkoutHeader = """^(running|cycling|custom):\s([\u0020-\u007F]+)(([\r\n]+\s*\-\s[a-z]+:.*)*)$""".r
private val NextStepRx = """^((-\s\w*:\s.*)(([\r\n]+\s{1,}-\s.*)*))(([\s].*)*)$""".r
def parseDef(x: String)(implicit msys: MeasurementSystems.MeasurementSystem): Either[String, WorkoutDef] = {
def loop(w: WorkoutDef, steps: String): Either[String, WorkoutDef] = steps match {
case NextStepRx(next, _, _, _, rest, _) =>
val newWorkout = w.withStep(Step.parse(next.trim))
if (rest.trim.isEmpty) Right(newWorkout)
else loop(newWorkout, rest.trim)
case _ => Left(s"Input string cannot be parsed to Workout: $steps")
}
x match {
case WorkoutHeader(sport, name, steps, _) => loop(WorkoutDef(sport, name), steps.trim)
case _ => Left(s"Input string cannot be parsed to Workout: $x")
}
}
def parseRef(x: String): WorkoutRef = x match {
case WorkoutHeader(_, name, _, _) => WorkoutRef(name)
case _ => WorkoutRef(x.trim)
}
def sportId(sport: String) = sport match {
case "running" => 1
case "cycling" => 2
case "custom" => 3
case _ => throw new IllegalArgumentException("Only running, cycling and 'custom' workouts are supported.")
}
def sportTypeKey(sport: String) = sport match {
case "custom" => "other"
case _ => sport
}
}