1:- module(bc_analytics_ts, [
    2    bc_analytics_ts_zero/2, % +Interval, -EmptySeries
    3    bc_analytics_ts_incr/3,  % +Series, +TimeStamp, -Series
    4    bc_analytics_ts_list/2   % +Series, -List
    5]).

Generic visitor tracking analytics */

    9:- use_module(library(assoc)).   10
   11% Daily time series prefilled with zeroes.
   12
   13bc_analytics_ts_zero(Interval, Series):-
   14    Interval = (YearFrom, MonthFrom)-(YearTo, MonthTo),
   15    StartDate = date(YearFrom, MonthFrom, 1,
   16        0, 0, 0, 0, 'UTC', -),
   17    MonthEnd is MonthTo + 1,
   18    EndDate = date(YearTo, MonthEnd, 1,
   19        0, 0, 0, 0, 'UTC', -),
   20    get_time(CurrentTimeStamp),
   21    date_time_stamp(EndDate, EndTimeStamp),
   22    MinEndTimeStamp is min(CurrentTimeStamp, EndTimeStamp),
   23    prefill_empty(StartDate, MinEndTimeStamp, [], Prefilled),
   24    list_to_assoc(Prefilled, Series).
   25
   26% Helper to fill a list with initial values per day.
   27
   28prefill_empty(CurrentDate, EndTimeStamp, In, Out):-
   29    date_time_stamp(CurrentDate, CurrentTimeStamp),
   30    (   CurrentTimeStamp < EndTimeStamp
   31    ->  stamp_date_time(CurrentTimeStamp, NormalizedDate, 'UTC'),
   32        format_time(atom(Key), '%F', NormalizedDate),
   33        add_days(CurrentDate, 1, NextDate),
   34        prefill_empty(NextDate, EndTimeStamp, [Key-0|In], Out)
   35    ;   reverse(In, Out)).
   36
   37% Adds days to the given date.
   38
   39add_days(Date, Days, NewDate):-
   40    Date = date(Year, Month, Day,
   41        Hour, Minute, Second, Offset, Tz, Dst),
   42    NewDay is Day + Days,
   43    NewDate = date(Year, Month, NewDay,
   44        Hour, Minute, Second, Offset, Tz, Dst).
   45
   46bc_analytics_ts_incr(In, TimeStamp, Out):-
   47    format_time(atom(Key), '%F', TimeStamp), % UTC?
   48    (   get_assoc(Key, In, Current)
   49    ->  New is Current + 1,
   50        put_assoc(Key, In, New, Out)
   51    ;   put_assoc(Key, In, 1, Out)).
   52
   53bc_analytics_ts_list(Series, Dicts):-
   54    assoc_to_list(Series, List),
   55    maplist(timeseries_entry_dict, List, Dicts).
   56
   57timeseries_entry_dict(Date-Count, Dict):-
   58    Dict = _{ date: Date, count: Count }