ppa stats graph
[ppastats.git] / src / html.c
1 /*
2     Copyright (C) 2011 jeanfi@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 2 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, write to the Free Software
16     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17     02110-1301 USA
18 */
19
20 #include <string.h>
21
22 #include "chart.h"
23 #include "html.h"
24 #include "list.h"
25 #include "lp_ws.h"
26 #include "ppastats.h"
27
28 #include <json/json.h>
29
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #define HTML_TEMPLATE \
34 "<html>\n\
35   <head>\n\
36     <script type='text/javascript'\
37             src='https://www.google.com/jsapi'></script>\n\
38     <script type='text/javascript'>\n\
39       google.load('visualization', '1', {packages:['corechart']});\
40       google.setOnLoadCallback(drawChart);\n\
41       function drawChart() {\n\
42         var data = new google.visualization.DataTable();\n\
43         data.addColumn('string', 'Date');\n\
44 %s\
45         data.addRows(%s);\n\
46         data.sort(0);\n\
47         var chart = new google.visualization.LineChart\
48                 (document.getElementById('chart_div'));\n\
49         chart.draw(data, {width: 1024, height: 768,\
50                           title: 'PPA Statistics'});\n\
51       }\n\
52     </script>\n\
53   </head>\n\
54 \n\
55   <body>\n\
56     <div id='chart_div'></div>\n\
57   </body>\n\
58 </html>\n"
59
60 static json_object *
61 get_count_array(json_object *data, const char *date)
62 {
63         int n, i;
64         json_object *o, *o_date;
65         const char *date2;
66
67         n = json_object_array_length(data);
68         for (i = 0; i < n; i++) {
69                 o = json_object_array_get_idx(data, i);
70                 o_date = json_object_array_get_idx(o, 0);
71                 date2 = json_object_get_string(o_date);
72
73                 if (!strcmp(date2, date))
74                         return o;
75         }
76
77         return NULL;
78 }
79
80 static json_object *count_array_new(json_object *data, const char *d, int n)
81 {
82         json_object *result = json_object_new_array();
83         int i;
84
85         json_object_array_add(result, json_object_new_string(d));
86
87         for (i = 0; i < n; i++)
88                 json_object_array_add(result, json_object_new_int(0));
89
90         json_object_array_add(data, result);
91
92         return result;
93 }
94
95 static char *
96 build_package_display_name(struct binary_package_publishing_history *b)
97 {
98         char *str = malloc(strlen(b->binary_package_name)+
99                            1+
100                            strlen(b->binary_package_version)+
101                            1);
102
103         sprintf(str, "%s-%s",
104                 b->binary_package_name, b->binary_package_version);
105
106         return str;
107 }
108
109 static char *
110 build_addcolums_str(struct binary_package_publishing_history **list)
111 {
112         struct binary_package_publishing_history **cur = list;
113         struct binary_package_publishing_history *b;
114         char *str, *tmpstr;
115         char *dname;
116
117         str = malloc(1);
118         *str = '\0';
119         const char *pattern = "%s        data.addColumn('number', '%s');\n";
120
121         while (*cur) {
122                 b = *cur;
123                 dname = build_package_display_name(b);
124
125                 tmpstr = malloc(strlen(str)+strlen(pattern)+strlen(dname)+1);
126                 sprintf(tmpstr, pattern, str, dname);
127
128                 free(str);
129                 free(dname);
130
131                 str = tmpstr;
132
133                 cur++;
134         }
135
136         return str;
137 }
138
139 static char *
140 build_data_str(struct binary_package_publishing_history **list)
141 {
142         int n, i;
143         json_object *data;
144         char *str;
145
146         n = list_length((void **)list);
147
148         data = json_object_new_array();
149         for (i = 0; i < n; i++) {
150                 struct binary_package_publishing_history *binary;
151                 const struct distro_arch_series *dist;
152                 struct daily_download_total **totals;
153                 struct daily_download_total **t_cur;
154
155                 binary = list[i];
156                 dist = get_distro_arch_series(binary->distro_arch_series_link);
157
158                 totals = get_daily_download_totals(binary->self_link);
159
160                 t_cur = totals;
161                 while (*t_cur) {
162                         char *d = malloc(10+1);
163                         json_object *data2;
164
165                         sprintf(d, "%d-%02d-%02d",
166                                 (*t_cur)->date.tm_year+1900,
167                                 (*t_cur)->date.tm_mon+1,
168                                 (*t_cur)->date.tm_mday);
169
170                         data2 = get_count_array(data, d);
171
172                         if (!data2)
173                                 data2 = count_array_new(data, d, n);
174
175                         json_object_array_put_idx
176                                 (data2,
177                                  i+1, json_object_new_int((*t_cur)->count));
178
179                         free(d);
180                         t_cur++;
181                 }
182
183                 daily_download_total_list_free(totals);
184         }
185
186         str = strdup(json_object_to_json_string(data));
187
188         json_object_put(data);
189
190         return str;
191 }
192
193 static char *get_path(const char *dir, const char *file)
194 {
195         char *path = malloc(strlen(dir)+1+strlen(file)+1);
196
197         strcpy(path, dir);
198         strcat(path, "/");
199         strcat(path, file);
200
201         return path;
202 }
203
204 void
205 ppa_to_html(const char *owner,
206             const char *ppa,
207             const char *package_status,
208             const char *output_dir)
209 {
210         struct binary_package_publishing_history **list;
211         char *archive_url, *addcolumns_str, *data_str, *path;
212         FILE *f;
213         struct ppa_stats *ppastats;
214         struct daily_download_total **totals;
215
216         ppastats = create_ppa_stats(owner, ppa, package_status);
217         totals = ppastats->daily_download_totals;
218
219         path = get_path(output_dir, "ppa.html");
220         generate_chart(path, "PPA Statistics", ppa, totals);
221         free(path);
222
223         archive_url = get_archive_url(owner, ppa);
224         list = get_binary_package_publishing_history_list(archive_url,
225                                                           package_status);
226         free(archive_url);
227
228         if (!list) {
229                 fprintf(stderr, "ERROR: Failed to retrieve PPA information\n");
230                 exit(EXIT_FAILURE);
231         }
232
233         addcolumns_str = build_addcolums_str(list);
234         data_str = build_data_str(list);
235
236         path = get_path(output_dir, "index.html");
237         f = fopen(path, "w");
238         if (f) {
239                 fprintf(f, HTML_TEMPLATE, addcolumns_str, data_str);
240                 fclose(f);
241         } else {
242                 fprintf(stderr, "ERROR: failed to write %s\n", path);
243         }
244         free(path);
245
246         free(addcolumns_str);
247         free(data_str);
248         binary_package_publishing_history_list_free(list);
249         ppa_stats_free(ppastats);
250 }