summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/c/fastforge_core.c112
-rw-r--r--src/c/fastforge_logic.c108
-rw-r--r--src/c/fastforge_logic.h1
3 files changed, 110 insertions, 111 deletions
diff --git a/src/c/fastforge_core.c b/src/c/fastforge_core.c
index 39d9ea8..a9bec03 100644
--- a/src/c/fastforge_core.c
+++ b/src/c/fastforge_core.c
@@ -1,6 +1,5 @@
#include "fastforge_internal.h"
-#include <stdlib.h>
#include <string.h>
FastEntry history[MAX_FASTS];
@@ -49,38 +48,6 @@ static void normalize_loaded_data(void) {
}
}
-static int compare_time_t_ascending(const void *a, const void *b) {
- const time_t time_a = *(const time_t *)a;
- const time_t time_b = *(const time_t *)b;
- if (time_a < time_b) {
- return -1;
- }
- if (time_a > time_b) {
- return 1;
- }
- return 0;
-}
-
-static bool is_next_local_day(time_t first_day, time_t second_day) {
- if (first_day <= 0 || second_day <= 0 || second_day < first_day) {
- return false;
- }
-
- struct tm *tm_info = localtime(&first_day);
- if (!tm_info) {
- return false;
- }
-
- struct tm next_day_tm = *tm_info;
- next_day_tm.tm_mday += 1;
- next_day_tm.tm_hour = 0;
- next_day_tm.tm_min = 0;
- next_day_tm.tm_sec = 0;
- next_day_tm.tm_isdst = -1;
- time_t expected_next_day = mktime(&next_day_tm);
- return expected_next_day == second_day;
-}
-
#ifdef DEBUG
time_t fastforge_now(void) {
return time(NULL) + (s_fake_time_enabled ? s_fake_time_offset_seconds : 0);
@@ -91,85 +58,8 @@ time_t fastforge_now(void) {
}
#endif
-static int collect_completion_days(time_t *completion_days, int max_days) {
- int completion_day_count = 0;
-
- for (int i = 0; i < history_count && completion_day_count < max_days; i++) {
- const FastEntry *entry = &history[i];
- time_t duration = entry_duration_seconds(entry);
- if (duration <= 0 || entry->end_time <= 0) {
- continue;
- }
-
- if (entry->end_time > streak_data.last_completed_fast_end) {
- streak_data.last_completed_fast_end = entry->end_time;
- }
-
- time_t day_start = local_day_start(entry->end_time);
- if (day_start <= 0) {
- continue;
- }
- completion_days[completion_day_count++] = day_start;
- }
-
- return completion_day_count;
-}
-
-static void apply_completion_days_to_streaks(time_t *completion_days, int completion_day_count) {
- qsort(completion_days, (size_t)completion_day_count, sizeof(time_t), compare_time_t_ascending);
-
- uint16_t run_length = 0;
- uint16_t longest = 0;
- for (int i = 0; i < completion_day_count; i++) {
- if (i == 0 || completion_days[i] == completion_days[i - 1]) {
- if (i == 0) {
- run_length = 1;
- }
- continue;
- }
-
- if (is_next_local_day(completion_days[i - 1], completion_days[i])) {
- run_length++;
- } else {
- run_length = 1;
- }
-
- if (run_length > longest) {
- longest = run_length;
- }
- }
-
- if (longest == 0) {
- longest = 1;
- }
-
- time_t today_day_start = local_day_start(fastforge_now());
- time_t last_completion_day = completion_days[completion_day_count - 1];
- if (last_completion_day == today_day_start ||
- is_next_local_day(last_completion_day, today_day_start)) {
- streak_data.current_streak = run_length;
- } else {
- streak_data.current_streak = 0;
- }
- streak_data.longest_streak = longest;
-}
-
static void recompute_streak_data_from_history(void) {
- streak_data.current_streak = 0;
- streak_data.longest_streak = 0;
- streak_data.last_completed_fast_end = 0;
-
- if (history_count <= 0) {
- return;
- }
-
- time_t completion_days[MAX_FASTS];
- int completion_day_count = collect_completion_days(completion_days, MAX_FASTS);
- if (completion_day_count == 0) {
- return;
- }
-
- apply_completion_days_to_streaks(completion_days, completion_day_count);
+ fastforge_streak_recompute(history, history_count, fastforge_now(), &streak_data);
}
void recompute_streak_data_for_today(void) {
diff --git a/src/c/fastforge_logic.c b/src/c/fastforge_logic.c
index 0f00f76..4015ec6 100644
--- a/src/c/fastforge_logic.c
+++ b/src/c/fastforge_logic.c
@@ -9,6 +9,7 @@ typedef time_t ff_sys_time_t;
#define time_t long
#include <stdio.h>
+#include <stdlib.h>
time_t entry_duration_seconds(const FastEntry *entry) {
@@ -82,6 +83,113 @@ time_t local_day_start(time_t timestamp) {
return (time_t)mktime(&tm_copy);
}
+static int compare_time_t_ascending(const void *a, const void *b) {
+ const time_t time_a = *(const time_t *)a;
+ const time_t time_b = *(const time_t *)b;
+ if (time_a < time_b) {
+ return -1;
+ }
+ if (time_a > time_b) {
+ return 1;
+ }
+ return 0;
+}
+
+static bool is_next_local_day(time_t first_day, time_t second_day) {
+ if (first_day <= 0 || second_day <= 0 || second_day < first_day) {
+ return false;
+ }
+
+ ff_sys_time_t sys_first_day = (ff_sys_time_t)first_day;
+ struct tm *tm_info = localtime(&sys_first_day);
+ if (!tm_info) {
+ return false;
+ }
+
+ struct tm next_day_tm = *tm_info;
+ next_day_tm.tm_mday += 1;
+ next_day_tm.tm_hour = 0;
+ next_day_tm.tm_min = 0;
+ next_day_tm.tm_sec = 0;
+ next_day_tm.tm_isdst = -1;
+ return (time_t)mktime(&next_day_tm) == second_day;
+}
+
+void fastforge_streak_recompute(const FastEntry *entries, int count, time_t now, StreakData *out) {
+ if (!out) {
+ return;
+ }
+
+ out->current_streak = 0;
+ out->longest_streak = 0;
+ out->last_completed_fast_end = 0;
+
+ if (!entries || count <= 0) {
+ return;
+ }
+
+ time_t completion_days[MAX_FASTS];
+ int completion_day_count = 0;
+
+ for (int i = 0; i < count && completion_day_count < MAX_FASTS; i++) {
+ const FastEntry *entry = &entries[i];
+ time_t duration = entry_duration_seconds(entry);
+ if (duration <= 0 || entry->end_time <= 0) {
+ continue;
+ }
+
+ if (entry->end_time > out->last_completed_fast_end) {
+ out->last_completed_fast_end = entry->end_time;
+ }
+
+ time_t day_start = local_day_start(entry->end_time);
+ if (day_start <= 0) {
+ continue;
+ }
+
+ completion_days[completion_day_count++] = day_start;
+ }
+
+ if (completion_day_count <= 0) {
+ return;
+ }
+
+ qsort(completion_days, (size_t)completion_day_count, sizeof(time_t), compare_time_t_ascending);
+
+ uint16_t run_length = 0;
+ uint16_t longest = 0;
+ for (int i = 0; i < completion_day_count; i++) {
+ if (i == 0 || completion_days[i] == completion_days[i - 1]) {
+ if (i == 0) {
+ run_length = 1;
+ }
+ continue;
+ }
+
+ if (is_next_local_day(completion_days[i - 1], completion_days[i])) {
+ run_length++;
+ } else {
+ run_length = 1;
+ }
+
+ if (run_length > longest) {
+ longest = run_length;
+ }
+ }
+
+ if (longest == 0) {
+ longest = 1;
+ }
+
+ time_t today_day_start = local_day_start(now);
+ time_t last_completion_day = completion_days[completion_day_count - 1];
+ if (last_completion_day == today_day_start ||
+ is_next_local_day(last_completion_day, today_day_start)) {
+ out->current_streak = run_length;
+ }
+ out->longest_streak = longest;
+}
+
bool running_fast_is_at_target(const FastEntry *entry, time_t now) {
if (!entry || entry->start_time == 0 || entry->end_time != 0 || entry->target_minutes == 0) {
return false;
diff --git a/src/c/fastforge_logic.h b/src/c/fastforge_logic.h
index 4ccaba7..81ced54 100644
--- a/src/c/fastforge_logic.h
+++ b/src/c/fastforge_logic.h
@@ -14,5 +14,6 @@ void format_hhmmss(time_t seconds, char *buffer, size_t size);
void format_duration_hours_minutes(time_t seconds, char *buffer, size_t size);
time_t local_day_start(time_t timestamp);
bool running_fast_is_at_target(const FastEntry *entry, time_t now);
+void fastforge_streak_recompute(const FastEntry *entries, int count, time_t now, StreakData *out);
#endif