| @@ -20,6 +20,8 @@ struct GymLogDbParsedEntry { | |||
| string name; | |||
| }; | |||
| typedef GymLogDbEntry Exercise; | |||
| struct GymLogDbParsed { | |||
| GymLogDbHeader header; | |||
| list<GymLogDbParsedEntry> entries; | |||
| @@ -38,6 +40,11 @@ struct GymLogEntry { | |||
| }; | |||
| }; | |||
| struct WorkSummary { | |||
| real32 totalWork; | |||
| uint32 restTime; | |||
| }; | |||
| GymLogDbParsed *parseDb(Arena *arena, string database) { | |||
| GymLogDbParsed *dbParsed = PushStruct(arena, GymLogDbParsed); | |||
| @@ -73,27 +80,24 @@ list<GymLogEntry> loadEntryLog(Arena *arena, string fileLocation) { | |||
| return result; | |||
| } | |||
| struct WorkSummary { | |||
| real32 totalWork; | |||
| uint32 restTime; | |||
| }; | |||
| WorkSummary workSummaryForExercise(list<GymLogEntry> entries) { | |||
| WorkSummary workSummaryForExercise(list<GymLogEntry> entries, Exercise exercise) { | |||
| WorkSummary result = {0}; | |||
| UnixTimestamp lastTimestamp = 0; | |||
| for (EachInReversed(entries, i)) { | |||
| GymLogEntry logEntry = entries.data[i]; | |||
| result.totalWork += logEntry.weightRepsInfo.weight * logEntry.weightRepsInfo.reps; | |||
| if (lastTimestamp > 0) { | |||
| result.restTime += (uint32)(lastTimestamp - logEntry.timestamp); | |||
| if (entries.data[i].exerciseId == exercise.id) { | |||
| GymLogEntry logEntry = entries.data[i]; | |||
| result.totalWork += logEntry.weightRepsInfo.weight * logEntry.weightRepsInfo.reps; | |||
| if (lastTimestamp > 0) { | |||
| result.restTime += (uint32)(lastTimestamp - logEntry.timestamp); | |||
| } | |||
| lastTimestamp = logEntry.timestamp; | |||
| } | |||
| lastTimestamp = logEntry.timestamp; | |||
| } | |||
| return result; | |||
| } | |||
| int gymTrackerWorkToday(Arena *arena, uint32 exerciseId, string exerciseName) { | |||
| int gymTrackerLogWorkToday(Arena *arena, Exercise exercise) { | |||
| int statusCode = 0; | |||
| string logfile = os_readEntireFile(arena, LOG_FILE_LOCATION); | |||
| @@ -119,8 +123,8 @@ int gymTrackerWorkToday(Arena *arena, uint32 exerciseId, string exerciseName) { | |||
| if (todaysEntries.data) { | |||
| todaysEntries.length = todaysEntries.head; | |||
| WorkSummary summary = workSummaryForExercise(todaysEntries); | |||
| log("Total work today for %S:\n%.2fkg in ~%.2fmin.\n", exerciseName, summary.totalWork, (real32)summary.restTime / 60.0f); | |||
| WorkSummary summary = workSummaryForExercise(todaysEntries, exercise); | |||
| log("Total work today for %S:\n%.2fkg in ~%.2fmin.\n", exercise.name, summary.totalWork, (real32)summary.restTime / 60.0f); | |||
| } | |||
| } | |||
| @@ -284,12 +288,13 @@ int gymTrackerDeleteEntries(Arena *arena, list<string> args) { | |||
| // Syntax: do <exercise-name> weightKg reps | |||
| int gymTrackerDo(Arena *arena, list<string> args) { | |||
| int statusCode = 0; | |||
| string exerciseName = {0}; | |||
| Exercise exercise = {}; | |||
| if (args.length < 3 || args.data[0].length == 0) { | |||
| log("Invalid exercise name and/or number of arguments.\n"); | |||
| statusCode = 1; | |||
| } else { | |||
| exerciseName = args.data[0]; | |||
| exercise.name = args.data[0]; | |||
| } | |||
| GymLogDbParsedEntry *existingEntry = 0; | |||
| @@ -298,23 +303,23 @@ int gymTrackerDo(Arena *arena, list<string> args) { | |||
| GymLogDbParsed *db = parseDb(arena, os_readEntireFile(arena, DB_FILE_LOCATION)); | |||
| for (EachIn(db->entries, i)) { | |||
| GymLogDbParsedEntry entry = db->entries.data[i]; | |||
| if (strStartsWith(entry.name, exerciseName)) { | |||
| if (strStartsWith(entry.name, exercise.name)) { | |||
| existingEntry = &entry; | |||
| if (entry.name.length != exerciseName.length) { | |||
| exerciseName = entry.name; | |||
| if (entry.name.length != exercise.name.length) { | |||
| exercise.name = entry.name; | |||
| log("Assuming exercise \"%S\".\n\n", entry.name); | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| if (!existingEntry) { | |||
| log("The exercise \"%S\" hasn't been registered.", exerciseName); | |||
| log("The exercise \"%S\" hasn't been registered.", exercise.name); | |||
| statusCode = 1; | |||
| } | |||
| } | |||
| if (statusCode == 0) { | |||
| uint32 exerciseId = existingEntry->id; | |||
| exercise.id = existingEntry->id; | |||
| size_t parsedCount = 0; | |||
| real32 kg = parsePositiveReal32(args.data[1], &parsedCount); | |||
| uint8 reps = parsePositiveInt(args.data[2], &parsedCount); | |||
| @@ -324,13 +329,13 @@ int gymTrackerDo(Arena *arena, list<string> args) { | |||
| } else { | |||
| GymLogEntry entry = { | |||
| getSystemUnixTime(), | |||
| exerciseId, | |||
| exercise.id, | |||
| reps, | |||
| kg, | |||
| }; | |||
| os_fileAppend(arena, LOG_FILE_LOCATION, (byte *)&entry, sizeof(entry)); | |||
| statusCode = gymTrackerWorkToday(arena, exerciseId, exerciseName); | |||
| statusCode = gymTrackerLogWorkToday(arena, exercise); | |||
| } | |||
| } | |||