#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "calendar.h"
#include "basics.h"
#include "dates.h"
#include "gregorian.h"
#include "io.h"
#include "utils.h"
struct event {
bool variable;
char date[32];
char date_user[64];
struct cal_desc *description;
char *extra;
struct event *next;
};
static struct cal_day *cal_days = NULL;
void
generate_dates(void)
{
struct cal_day *dp;
struct date date;
int daycount, dow, year, month, day;
int rd_month1, rd_nextmonth, rd_nextyear;
daycount = Options.day_end - Options.day_begin + 1;
cal_days = xcalloc((size_t)daycount, sizeof(struct cal_day));
dow = dayofweek_from_fixed(Options.day_begin);
gregorian_from_fixed(Options.day_begin, &date);
year = date.year;
month = date.month;
day = date.day;
date.day = 1;
rd_month1 = fixed_from_gregorian(&date);
if (date.month == 12) {
date_set(&date, date.year+1, 1, 1);
rd_nextmonth = fixed_from_gregorian(&date);
rd_nextyear = rd_nextmonth;
} else {
date.month++;
rd_nextmonth = fixed_from_gregorian(&date);
date_set(&date, date.year+1, 1, 1);
rd_nextyear = fixed_from_gregorian(&date);
}
for (int i = 0; i < daycount; i++) {
dp = &cal_days[i];
dp->rd = Options.day_begin + i;
if (dp->rd == rd_nextmonth) {
month++;
day = 1;
rd_month1 = rd_nextmonth;
if (dp->rd == rd_nextyear) {
year++;
month = 1;
}
date_set(&date, year, month, day);
if (date.month == 12) {
date_set(&date, date.year+1, 1, 1);
rd_nextmonth = fixed_from_gregorian(&date);
rd_nextyear = rd_nextmonth;
} else {
date.month++;
rd_nextmonth = fixed_from_gregorian(&date);
date_set(&date, date.year+1, 1, 1);
rd_nextyear = fixed_from_gregorian(&date);
}
}
dp->year = year;
dp->month = month;
dp->day = dp->rd - rd_month1 + 1;
dp->dow[0] = (dow + i) % 7;
dp->dow[1] = (dp->rd - rd_month1) / 7 + 1;
dp->dow[2] = -((rd_nextmonth - dp->rd - 1) / 7 + 1);
dp->last_dom = (dp->rd == rd_nextmonth - 1);
DPRINTF("%s: [%d] rd:%d, date:%d-%02d-%02d, dow:[%d,%d,%d]\n",
__func__, i, dp->rd, dp->year, dp->month,
dp->day, dp->dow[0], dp->dow[1], dp->dow[2]);
}
}
void
free_dates(void)
{
struct event *e;
struct cal_day *dp = NULL;
while ((dp = loop_dates(dp)) != NULL) {
while ((e = dp->events) != NULL) {
dp->events = e->next;
free(e->extra);
free(e);
}
}
free(cal_days);
}
struct cal_day *
loop_dates(struct cal_day *dp)
{
int daycount = Options.day_end - Options.day_begin + 1;
if (dp == NULL)
dp = &cal_days[0];
else
dp++;
if (dp < &cal_days[0] || dp > &cal_days[daycount-1])
return NULL;
else
return dp;
}
struct cal_day *
find_rd(int rd, int offset)
{
rd += offset;
if (rd < Options.day_begin || rd > Options.day_end)
return NULL;
return &cal_days[rd - Options.day_begin];
}
struct event *
event_add(struct cal_day *dp, bool day_first, bool variable,
struct cal_desc *desc, char *extra)
{
struct event *e;
struct date gdate;
struct tm tm = { 0 };
e = xcalloc(1, sizeof(*e));
gregorian_from_fixed(dp->rd, &gdate);
tm.tm_year = gdate.year - 1900;
tm.tm_mon = gdate.month - 1;
tm.tm_mday = gdate.day;
strftime(e->date, sizeof(e->date),
(day_first ? "%e %b" : "%b %e"), &tm);
if (Calendar->format_date != NULL) {
(Calendar->format_date)(e->date_user, sizeof(e->date_user),
dp->rd);
}
e->variable = variable;
e->description = desc;
if (extra != NULL && extra[0] != '\0')
e->extra = extra;
e->next = dp->events;
dp->events = e;
return (e);
}
void
event_print_all(FILE *fp)
{
struct event *e;
struct cal_day *dp = NULL;
struct cal_desc *desc;
struct cal_line *line;
while ((dp = loop_dates(dp)) != NULL) {
for (e = dp->events; e != NULL; e = e->next) {
fprintf(fp, "%s%c\t", e->date, e->variable ? '*' : ' ');
if (e->date_user[0] != '\0')
fprintf(fp, "[%s] ", e->date_user);
desc = e->description;
for (line = desc->firstline; line; line = line->next) {
fprintf(fp, "%s%s%s",
(line == desc->firstline) ? "" : "\t\t",
line->str,
(line == desc->lastline) ? "" : "\n");
}
if (e->extra)
fprintf(fp, " (%s)", e->extra);
fputc('\n', fp);
fflush(fp);
}
}
}