]> Pileus Git - lackey/blob - src/cal.c
Output cal field for ical events and todos
[lackey] / src / cal.c
1 /*
2  * Copyright (C) 2012-2013 Andy Spencer <andy753421@gmail.com>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <stdlib.h>
19
20 #include "util.h"
21 #include "date.h"
22 #include "cal.h"
23
24 /* Macros */
25 #define CAL(name) \
26         void     name##_config(const char *group, const char *name, const char *key, const char *value); \
27         cal_t   *name##_cals(void); \
28         event_t *name##_events(date_t start, date_t end); \
29         todo_t  *name##_todos(date_t start, date_t end)
30
31 /* Prototypes */
32 CAL(dummy);
33 CAL(ical);
34
35 /* Global data */
36 cal_t   *CALS;
37 event_t *EVENTS;
38 todo_t  *TODOS;
39
40 /* Local data */
41 static date_t start;
42 static date_t end;
43
44 /* Merge events and todos */
45 static void add_event(event_t **first, event_t **last, event_t **next)
46 {
47         if (*last)
48                 (*last)->next = *next;
49         else
50                 (*first) = *next;
51         (*last) = (*next);
52         (*next) = (*next)->next;
53 }
54
55 static void add_todo(todo_t **first, todo_t **last, todo_t **next)
56 {
57         if (*last)
58                 (*last)->next = *next;
59         else
60                 (*first) = *next;
61         (*last) = (*next);
62         (*next) = (*next)->next;
63 }
64
65 static cal_t *merge_cals(cal_t *a, cal_t *b)
66 {
67         // TODO - we should sort these
68         if (!a) return b;
69         if (!b) return a;
70         cal_t *last = a;
71         while (last->next)
72                 last = last->next;
73         last->next = b;
74         return a;
75 }
76
77 static event_t *merge_events(event_t *a, event_t *b)
78 {
79         event_t *first = NULL, *last = NULL;
80         while (a && b)
81                 if (compare(&a->start, &b->start) <= 0)
82                         add_event(&first, &last, &a);
83                 else
84                         add_event(&first, &last, &b);
85         while (a) add_event(&first, &last, &a);
86         while (b) add_event(&first, &last, &b);
87         return first;
88 }
89
90 static todo_t *merge_todos(todo_t *a, todo_t *b)
91 {
92         todo_t *first = NULL, *last = NULL;
93         while (a && b)
94                 if (compare(&a->start, &b->start) <= 0)
95                         add_todo(&first, &last, &a);
96                 else
97                         add_todo(&first, &last, &b);
98         while (a) add_todo(&first, &last, &a);
99         while (b) add_todo(&first, &last, &b);
100         return first;
101 }
102
103 /* Initialize */
104 void cal_init(void)
105 {
106         /* Load calendars */
107         CALS = merge_cals(
108                 dummy_cals(),
109                  ical_cals());
110
111         /* Load data */
112         cal_load(YEAR, MONTH, DAY, 1);
113
114         /* Debug */
115         for (event_t *e = EVENTS; e; e = e->next)
116                 debug("event: %04d-%02d-%02d %02d:%02d: %s - %s",
117                                 e->start.year, e->start.month, e->start.day,
118                                 e->start.hour, e->start.min, e->name, e->desc);
119         for (todo_t *e = TODOS; e; e = e->next)
120                 debug("todo: %04d-%02d-%02d %02d:%02d: %s - %s",
121                                 e->start.year, e->start.month, e->start.day,
122                                 e->start.hour, e->start.min, e->name, e->desc);
123 }
124
125 /* Load events and todos */
126 void cal_load(year_t year, month_t month, day_t day, int days)
127 {
128         year_t  eyear  = year;
129         month_t emonth = month;
130         day_t   eday   = day;
131         add_days(&eyear, &emonth, &eday, days);
132
133         /* Skip if we already loaded enough info */
134         if (before(&start, year,  month,  day,  0, 0) &&
135            !before(&end,  eyear, emonth, eday, 24, 0))
136                 return;
137
138         /* Free uneeded data */
139         for (event_t *next, *cur = EVENTS; cur; cur = next) {
140                 next = cur->next;
141                 if (cur->name) free(cur->name);
142                 if (cur->desc) free(cur->desc);
143                 if (cur->loc)  free(cur->loc);
144                 if (cur->cat)  free(cur->cat);
145                 free(cur);
146         }
147         for (todo_t *next, *cur = TODOS; cur; cur = next) {
148                 next = cur->next;
149                 if (cur->name) free(cur->name);
150                 if (cur->desc) free(cur->desc);
151                 if (cur->cat)  free(cur->cat);
152                 free(cur);
153         }
154
155         /* Push dates out a bit to avoid reloading,
156          * enough to at least cover the current year */
157         add_days(&year,  &month,  &day, -366);
158         add_days(&eyear, &emonth, &eday, 366);
159         start = (date_t){year,  month,  day};
160         end   = (date_t){eyear, emonth, eday};
161
162         /* Load events */
163         EVENTS = merge_events(
164                 dummy_events(start, end),
165                  ical_events(start, end));
166
167         /* Load todos */
168         TODOS  = merge_todos(
169                 dummy_todos(start, end),
170                  ical_todos(start, end));
171
172         /* Verify events and todos*/
173         //for (event_t *cur = EVENTS; cur; cur = cur->next)
174         //      if (!cur->cal)
175         //              error("Missing cal in event '%s'", cur->name);
176         //for (todo_t *cur = TODOS; cur; cur = cur->next)
177         //      if (!cur->cal)
178         //              error("Missing cal in todo '%s'", cur->name);
179 }
180
181 /* Config parser */
182 void cal_config(const char *group, const char *name, const char *key, const char *value)
183 {
184         if (match(group, "dummy"))
185                 dummy_config(group, name, key, value);
186         else if (match(group, "ical"))
187                 ical_config(group, name, key, value);
188 }