Find script for gsm
[gregoa/zavai.git] / src / log.vala
1 /*
2  * log - logging functions
3  *
4  * Copyright (C) 2009--2010  Enrico Zini <enrico@enricozini.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 using GLib;
22
23 namespace zavai {
24 namespace log {
25
26 public class Waypoint : Object
27 {
28     public time_t ts;
29     public double lat;
30     public double lon;
31
32     public Waypoint()
33     {
34         if (gps.gps.fix_status() != libgps.STATUS_NO_FIX)
35         {
36             lat = gps.gps.info().fix.latitude;
37             lon = gps.gps.info().fix.longitude;
38             ts = (time_t)gps.gps.info().fix.time;
39         } else {
40             // Use 1000 as missing values
41             lat = 1000;
42             lon = 1000;
43             ts = time_t();
44         }
45     }
46
47     public void writeInside(FileStream outfd)
48     {
49         var t = Time.gm(ts);
50         outfd.printf("   <time>%s</time>\n", t.format("%Y-%m-%dT%H:%M:%SZ"));
51     }
52 }
53
54
55 public class LogEntry : Waypoint
56 {
57     public string msg;
58
59     public LogEntry()
60     {
61         base();
62     }
63
64     public void write(FileStream outfd)
65     {
66         outfd.printf("   <wpt lat=\"%f\" lon=\"%f\">\n", lat, lon);
67         writeInside(outfd);
68         outfd.printf("   <name>%s</name>\n", Markup.escape_text(msg));
69         outfd.puts("   </wpt>\n");
70     }
71 }
72
73 public class TrackEntry : Waypoint
74 {
75     public TrackEntry()
76     {
77         base();
78     }
79
80     public void write(FileStream outfd)
81     {
82         outfd.printf("   <trkpt lat=\"%f\" lon=\"%f\">\n", lat, lon);
83         writeInside(outfd);
84         outfd.puts("   </trkpt>\n");
85     }
86 }
87
88
89 public class Log : Object
90 {
91     public uint id;
92     public string tag;
93     public string title;
94     public List<LogEntry> entries;
95     public List<TrackEntry> track;
96
97     public Log(uint id, string tag, string title)
98     {
99         this.id = id;
100         this.tag = tag;
101         this.title = title;
102         entries = null;
103         track = null;
104     }
105
106     public void add(string msg)
107     {
108         var entry = new LogEntry();
109         entry.msg = msg;
110         entries.append(entry);
111     }
112
113     public void add_trackpoint()
114     {
115         track.append(new TrackEntry());
116     }
117
118     public void save()
119     {
120         if (entries == null) return;
121
122         // Directory where we save the log
123         string dir = config.homedir + "/log-" + tag;
124         DirUtils.create(dir, 0777);
125
126         // First try with a plain name
127         var t = Time.local(entries.data.ts);
128         string basename = dir + "/" + t.format("%Y%m%d-%H%M%S");
129
130         string pathname = basename + ".gpx";
131
132         // Find a pathname that does not exist already
133         for (int i = 1; FileUtils.test(pathname, FileTest.EXISTS); ++i)
134             pathname = "%s-%d.gpx".printf(basename, i);
135
136         // Write out
137         var outfd = FileStream.open(pathname, "w");
138         if (outfd == null)
139         {
140             zavai.log.error("opening " + pathname + ": " + strerror(errno));
141             return;
142         }
143
144         write(outfd);
145         outfd.flush();
146     }
147
148     protected void writeTrack(FileStream outfd)
149     {
150         outfd.puts("   <trk>\n");
151         outfd.puts("     <trkseg>\n");
152         for (weak List<TrackEntry> i = track; i != null; i = i.next)
153             i.data.write(outfd);
154         outfd.puts("     </trkseg>\n");
155         outfd.puts("   </trk>\n");
156     }
157
158     protected void writeEntries(FileStream outfd)
159     {
160         outfd.puts("   <wpt>\n");
161         for (weak List<LogEntry> i = entries; i != null; i = i.next)
162             i.data.write(outfd);
163         outfd.puts("   </wpt>\n");
164     }
165
166     protected void write(FileStream outfd)
167     {
168         outfd.puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
169         outfd.puts("<gpx version=\"1.0\"\n");
170         outfd.printf("     creator=\"zavai %s\"\n", zavai.config.version);
171         outfd.puts("     xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
172         outfd.puts("     xmlns=\"http://www.topografix.com/GPX/1/0\"\n");
173         outfd.puts("     xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">\n");
174         outfd.puts("  <metadata>\n");
175         outfd.printf("    <name>%s</name>\n", Markup.escape_text(title));
176         outfd.puts("  </metadata>\n");
177         if (track != null) writeTrack(outfd);
178         if (entries != null) writeEntries(outfd);
179         outfd.puts(" </gpx>\n");
180     }
181 }
182
183 public class Logger : Resource, Object
184 {
185     protected List<Log> logs;
186     protected uint seq;
187
188     public Logger()
189     {
190         logs = null;
191         seq = 0;
192
193         zavai.registry.register(this);
194     }
195
196     protected void start_trace()
197     {
198         gps.gps.pos_changed += on_pos_changed;
199     }
200
201     protected void end_trace()
202     {
203         gps.gps.pos_changed -= on_pos_changed;
204     }
205
206     protected void on_pos_changed()
207     {
208         for (weak List<Log> i = logs; i != null; i = i.next)
209             i.data.add_trackpoint();
210     }
211
212     protected uint gen_seq()
213     {
214         // Increase avoiding 0 on rollover
215         while (true)
216         {
217             if (++seq == 0) ++seq;
218             bool found = false;
219             for (weak List<Log> i = logs; i != null; i = i.next)
220             {
221                 if (i.data.id == seq)
222                 {
223                     found = true;
224                     break;
225                 }
226             }
227             if (!found) break;
228         }
229         return seq;
230     }
231
232     protected weak Log? find(uint id)
233     {
234         for (weak List<Log> i = logs; i != null; i = i.next)
235             if (i.data.id == id)
236                 return i.data;
237         return null;
238     }
239
240     protected Log? pop(uint id)
241     {
242         for (weak List<Log> i = logs; i != null; i = i.next)
243             if (i.data.id == id)
244             {
245                 Log res = i.data;
246                 logs.delete_link(i);
247                 return res;
248             }
249         return null;
250     }
251
252     public uint start(string tag, string title)
253     {
254         bool was_empty = (logs == null);
255         uint id = gen_seq();
256         logs.append(new Log(id, tag, title));
257         if (was_empty) start_trace();
258         return id;
259     }
260
261     public void add(uint id, string msg)
262     {
263         Log log = find(id);
264         if (log == null) return;
265         log.add(msg);
266     }
267
268     public void end(uint id)
269     {
270         Log log = pop(id);
271         log.save();
272         if (log == null) end_trace();
273     }
274
275     public void instant(string tag, string msg)
276     {
277         var log = new Log(0, tag, msg);
278         log.add(msg);
279         log.save();
280     }
281
282     public void shutdown()
283     {
284         while (logs != null)
285         {
286             var log = pop(logs.data.id);
287             log.save();
288         }
289     }
290 }
291
292 public void error(string s)
293 {
294         stderr.printf("%s\n", s);
295 }
296 public void warning(string s)
297 {
298         stderr.printf("%s\n", s);
299 }
300 public void info(string s)
301 {
302         stderr.printf("%s\n", s);
303 }
304 public void debug(string s)
305 {
306         stderr.printf("%s\n", s);
307 }
308
309 Logger log = null;
310
311 public void init()
312 {
313     log = new Logger();
314 }
315
316 }
317 }