<commit_before>#include "pebble.h"

#define SETTINGS_VERSION_VALUE 2

// I should've used a prefix =/
typedef enum {
    VERSION = 0,
    LIGHT_THEME,
    ANIMATE_SECOND_DOT,
    _UNUSED0,

    DATE_MODE,
    DATE_MONTH_FORMAT,
    DATE_WEEKDAY_FORMAT,
    DATE_FIRST_WEEKDAY,

    ICON_CONNECTION,
    ICON_BATTERY,
    
    NOTIFICATION_DISCONNECTED,
    NOTIFICATION_CONNECTED,

    SKIP_INITIAL_ANIMATION,
    NOTIFICATION_HOURLY,

    LARGE_DATE_FONT,

    CUSTOM_DATE,
    CUSTOM_TIME_OFFSET,
    CUSTOM_TIME_DATE_SPACING_1,
    CUSTOM_TIME_DATE_SPACING_2,
    CUSTOM_DATE_WORD_SPACING,
    CUSTOM_DATE_LINE_SPACING,
    CUSTOM_DATE_MAX,

    CUSTOM_ANIMATIONS = CUSTOM_DATE_MAX,
    CUSTOM_ANIMATION_TIMEOUT_MS,
    CUSTOM_ANIMATION_PERIOD_VIS_FRAMES,
    CUSTOM_ANIMATION_PERIOD_INVIS_FRAMES,
    CUSTOM_ANIMATION_PERIOD_COUNT,
    CUSTOM_ANIMATION_DATE_PERIOD_FRAMES,
    CUSTOM_ANIMATION_TETRIMINO_AGE_STEP_FRAMES,
    CUSTOM_ANIMATIONS_MAX,
    
    MAX_KEY = CUSTOM_ANIMATIONS_MAX,
} SettingsKey;

typedef enum {
    DM_ASYMMETRIC,
    DM_DENSE,
    DM_SPARSE,
    DIM_MAX,
} DigitsMode;

typedef enum {
    DM_INVERTED,
    DM_SAME_COLOR,
    DM_NONE,
    DM_MAX,
} DateMode;

typedef enum {
    DMF_MONTH_BEFORE,
    DMF_MONTH_AFTER,
    DMF_WEEKDAY_BEFORE,
    DMF_WEEKDAY_AFTER,
    DMF_MAX,
} DateMonthFormat;

typedef enum {
    DWF_MARKED,
    DWF_LETTER,
    DWF_TEXT,
    DWF_NO_WEEKDAY,
    DWF_MAX,
} DateWeekdayFormat;

typedef enum {
    NTF_NONE,
    NTF_SHORT_PULSE,
    NTF_LONG_PULSE,
    NTF_DOUBLE_PULSE,
    NTF_MAX,
} NotificationType;

typedef int Settings[MAX_KEY];

static Settings s_settings;

inline static int settings_get_default(SettingsKey key) {
    switch (key) {
    case ANIMATE_SECOND_DOT:
        return 1;
    case DATE_WEEKDAY_FORMAT:
        return DWF_TEXT;
    case NOTIFICATION_DISCONNECTED:
        return NTF_DOUBLE_PULSE;
    default:
        return 0;
    }
}

#define MAKE_IN_RANGE(v, min, max) v = (v < min ? min : (v > max ? max : v))

// returns true if resulting settings differ from input settings
static int settings_apply(const int* new_settings) {
    memcpy(&s_settings, new_settings, sizeof(Settings));
    
    s_settings[VERSION] = SETTINGS_VERSION_VALUE;
    s_settings[LIGHT_THEME] %= 2;
    s_settings[ANIMATE_SECOND_DOT] %= 2;
    s_settings[DATE_MODE] %= DM_MAX;
    s_settings[DATE_MONTH_FORMAT] %= DMF_MAX;
    s_settings[DATE_WEEKDAY_FORMAT] %= DWF_MAX;
    s_settings[DATE_FIRST_WEEKDAY] %= 7;
    s_settings[ICON_CONNECTION] %= 2;
    s_settings[ICON_BATTERY] %= 2;
    s_settings[NOTIFICATION_DISCONNECTED] %= NTF_MAX;
    s_settings[NOTIFICATION_CONNECTED] %= NTF_MAX;
    s_settings[SKIP_INITIAL_ANIMATION] %= 2;
    s_settings[NOTIFICATION_HOURLY] %= NTF_MAX;
    s_settings[LARGE_DATE_FONT] %= 2;
    s_settings[CUSTOM_DATE] %= 2;
    s_settings[CUSTOM_ANIMATIONS] %= 2;

    // disable duplicated text weekday
    if (s_settings[DATE_WEEKDAY_FORMAT] == DWF_TEXT) {
        const DateMonthFormat dmf = s_settings[DATE_MONTH_FORMAT];
        if (dmf == DMF_WEEKDAY_BEFORE || dmf == DMF_WEEKDAY_AFTER) {
            s_settings[DATE_WEEKDAY_FORMAT] = DWF_NO_WEEKDAY;
        }
    }

    // fix custom values
    if (!s_settings[CUSTOM_DATE]) {
        if (s_settings[DATE_MODE] != DM_NONE) {
            const int large_font = s_settings[LARGE_DATE_FONT];
            switch (s_settings[DATE_WEEKDAY_FORMAT]) {
            case DWF_MARKED:
                s_settings[CUSTOM_TIME_OFFSET] = large_font ? 2 : 1;
                break;
            case DWF_LETTER:
                s_settings[CUSTOM_TIME_OFFSET] = large_font ? 3 : 2;
                break;
            case DWF_TEXT:
                s_settings[CUSTOM_TIME_OFFSET] = large_font ? 4 : 2;
                break;
            default:
            case DWF_NO_WEEKDAY:
                s_settings[CUSTOM_TIME_OFFSET] = 1;
                break;
            }
        } else {
            s_settings[CUSTOM_TIME_OFFSET] = 0;
        }
        s_settings[CUSTOM_TIME_DATE_SPACING_1] = 2;
        s_settings[CUSTOM_TIME_DATE_SPACING_2] = 2;
        s_settings[CUSTOM_DATE_WORD_SPACING] = 3;
        s_settings[CUSTOM_DATE_LINE_SPACING] = 2;
    } else {
        MAKE_IN_RANGE(s_settings[CUSTOM_TIME_OFFSET], 0, 20);
        MAKE_IN_RANGE(s_settings[CUSTOM_TIME_DATE_SPACING_1], 0, 20);
        MAKE_IN_RANGE(s_settings[CUSTOM_TIME_DATE_SPACING_2], 0, 20);
        MAKE_IN_RANGE(s_settings[CUSTOM_DATE_WORD_SPACING], 0, 20);<commit_msg>custom offset for single-line date<commit_after>#include "pebble.h"

#define SETTINGS_VERSION_VALUE 2

// I should've used a prefix =/
typedef enum {
    VERSION = 0,
    LIGHT_THEME,
    ANIMATE_SECOND_DOT,
    _UNUSED0,

    DATE_MODE,
    DATE_MONTH_FORMAT,
    DATE_WEEKDAY_FORMAT,
    DATE_FIRST_WEEKDAY,

    ICON_CONNECTION,
    ICON_BATTERY,
    
    NOTIFICATION_DISCONNECTED,
    NOTIFICATION_CONNECTED,

    SKIP_INITIAL_ANIMATION,
    NOTIFICATION_HOURLY,

    LARGE_DATE_FONT,

    CUSTOM_DATE,
    CUSTOM_TIME_OFFSET,
    CUSTOM_TIME_DATE_SPACING_1,
    CUSTOM_TIME_DATE_SPACING_2,
    CUSTOM_DATE_WORD_SPACING,
    CUSTOM_DATE_LINE_SPACING,
    CUSTOM_DATE_MAX,

    CUSTOM_ANIMATIONS = CUSTOM_DATE_MAX,
    CUSTOM_ANIMATION_TIMEOUT_MS,
    CUSTOM_ANIMATION_PERIOD_VIS_FRAMES,
    CUSTOM_ANIMATION_PERIOD_INVIS_FRAMES,
    CUSTOM_ANIMATION_PERIOD_COUNT,
    CUSTOM_ANIMATION_DATE_PERIOD_FRAMES,
    CUSTOM_ANIMATION_TETRIMINO_AGE_STEP_FRAMES,
    CUSTOM_ANIMATIONS_MAX,
    
    MAX_KEY = CUSTOM_ANIMATIONS_MAX,
} SettingsKey;

typedef enum {
    DM_ASYMMETRIC,
    DM_DENSE,
    DM_SPARSE,
    DIM_MAX,
} DigitsMode;

typedef enum {
    DM_INVERTED,
    DM_SAME_COLOR,
    DM_NONE,
    DM_MAX,
} DateMode;

typedef enum {
    DMF_MONTH_BEFORE,
    DMF_MONTH_AFTER,
    DMF_WEEKDAY_BEFORE,
    DMF_WEEKDAY_AFTER,
    DMF_MAX,
} DateMonthFormat;

typedef enum {
    DWF_MARKED,
    DWF_LETTER,
    DWF_TEXT,
    DWF_NO_WEEKDAY,
    DWF_MAX,
} DateWeekdayFormat;

typedef enum {
    NTF_NONE,
    NTF_SHORT_PULSE,
    NTF_LONG_PULSE,
    NTF_DOUBLE_PULSE,
    NTF_MAX,
} NotificationType;

typedef int Settings[MAX_KEY];

static Settings s_settings;

inline static int settings_get_default(SettingsKey key) {
    switch (key) {
    case ANIMATE_SECOND_DOT:
        return 1;
    case DATE_WEEKDAY_FORMAT:
        return DWF_TEXT;
    case NOTIFICATION_DISCONNECTED:
        return NTF_DOUBLE_PULSE;
    default:
        return 0;
    }
}

#define MAKE_IN_RANGE(v, min, max) v = (v < min ? min : (v > max ? max : v))

// returns true if resulting settings differ from input settings
static int settings_apply(const int* new_settings) {
    memcpy(&s_settings, new_settings, sizeof(Settings));
    
    s_settings[VERSION] = SETTINGS_VERSION_VALUE;
    s_settings[LIGHT_THEME] %= 2;
    s_settings[ANIMATE_SECOND_DOT] %= 2;
    s_settings[DATE_MODE] %= DM_MAX;
    s_settings[DATE_MONTH_FORMAT] %= DMF_MAX;
    s_settings[DATE_WEEKDAY_FORMAT] %= DWF_MAX;
    s_settings[DATE_FIRST_WEEKDAY] %= 7;
    s_settings[ICON_CONNECTION] %= 2;
    s_settings[ICON_BATTERY] %= 2;
    s_settings[NOTIFICATION_DISCONNECTED] %= NTF_MAX;
    s_settings[NOTIFICATION_CONNECTED] %= NTF_MAX;
    s_settings[SKIP_INITIAL_ANIMATION] %= 2;
    s_settings[NOTIFICATION_HOURLY] %= NTF_MAX;
    s_settings[LARGE_DATE_FONT] %= 2;
    s_settings[CUSTOM_DATE] %= 2;
    s_settings[CUSTOM_ANIMATIONS] %= 2;

    // disable duplicated text weekday
    if (s_settings[DATE_WEEKDAY_FORMAT] == DWF_TEXT) {
        const DateMonthFormat dmf = s_settings[DATE_MONTH_FORMAT];
        if (dmf == DMF_WEEKDAY_BEFORE || dmf == DMF_WEEKDAY_AFTER) {
            s_settings[DATE_WEEKDAY_FORMAT] = DWF_NO_WEEKDAY;
        }
    }

    // fix custom values
    if (!s_settings[CUSTOM_DATE]) {
        if (s_settings[DATE_MODE] != DM_NONE) {
            const int large_font = s_settings[LARGE_DATE_FONT];
            switch (s_settings[DATE_WEEKDAY_FORMAT]) {
            case DWF_MARKED:
                s_settings[CUSTOM_TIME_OFFSET] = large_font ? 2 : 1;
                break;
            case DWF_LETTER:
                s_settings[CUSTOM_TIME_OFFSET] = large_font ? 3 : 2;
                break;
            case DWF_TEXT:
                s_settings[CUSTOM_TIME_OFFSET] = large_font ? 4 : 2;
                break;
            default:
            case DWF_NO_WEEKDAY:
                s_settings[CUSTOM_TIME_OFFSET] = 1;
                break;
            }
        } else {
            s_settings[CUSTOM_TIME_OFFSET] = 0;
        }
        s_settings[CUSTOM_TIME_DATE_SPACING_1] = 2;
        s_settings[CUSTOM_TIME_DATE_SPACING_2] = 2;
        s_settings[CUSTOM_DATE_WORD_SPACING] = 3;
        s_settings[CUSTOM_DATE_LINE_SPACING] = 2;
        if (s_settings[DATE_WEEKDAY_FORMAT] == DWF_NO_WEEKDAY) {
            s_settings[CUSTOM_TIME_DATE_SPACING_1] += 1;
            s_settings[CUSTOM_TIME_DATE_SPACING_2] += 1;
        }
    } else {
        MAKE_IN_RANGE(s_settings[CUSTOM_TIME_OFFSET], 0, 20);
        MAKE_IN_RANGE(s_settings[CUSTOM_TIME_DATE_SPACING_1], 0, 20);
        MAKE_IN_RANGE(s_settings[CUSTOM_TIME_DATE_SPACING_2], 0, 20);
        MAKE_IN_RANGE(s_settings[CUSTOM_DATE_WORD_SPACING], 0, 20);
{'fraction_non_alphanumeric': 0.07941883329691939, 'fraction_numerical': 0.010050251256281407, 'mean_word_length': 3.022407732864675, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7170396', 'n_tokens_mistral': 3787, 'n_tokens_neox': 3614, 'n_words': 524}