Check for device state on update.
[yandex-traffic] / traffic.cpp
1 #include <QtCore>
2 #include <QtXml>
3
4 #include "traffic.hpp"
5
6
7 // --------------------------------------------------
8 // TrafficInfo
9 // --------------------------------------------------
10 TrafficInfo::TrafficInfo (const QDomElement& elem) throw (const QString&)
11 {
12     _valid = false;
13     _len1 = getFloatNode (elem, "length_1", 0);
14     _len2 = getFloatNode (elem, "length_2", 0);
15     _len  = getFloatNode (elem, "length", 0);
16     _ts   = getTSNode (elem, "timestamp");
17     _isotime = getStringNode (elem, "isotime");
18     _localtime = getStringNode (elem, "localtime");
19     _valid = true;
20 }
21
22
23 float TrafficInfo::getFloatNode (const QDomElement& elem, const char* node, float def)
24 {
25     QDomElement e;
26     bool ok;
27     float val;
28
29     e = elem.firstChildElement (node);
30     if (e.isNull ())
31         return def;
32     val = e.text ().toFloat (&ok);
33     if (!ok)
34         return def;
35     return val;
36 }
37
38
39 int TrafficInfo::getIntNode (const QDomElement& elem, const char* node, int def)
40 {
41     QDomElement e;
42     bool ok;
43     int val;
44
45     e = elem.firstChildElement (node);
46     if (e.isNull ())
47         return def;
48     val = e.text ().toInt (&ok);
49     if (!ok)
50         return def;
51     return val;
52 }
53
54
55 QString TrafficInfo::getStringNode (const QDomElement& elem, const char* node) throw (const QString&)
56 {
57     QDomElement e;
58     QString val;
59
60     e = elem.firstChildElement (node);
61     if (e.isNull ())
62         throw QString (QString::fromAscii (node) + " not found");
63     return e.text ();
64 }
65
66
67 QDateTime TrafficInfo::getTSNode (const QDomElement& elem, const char* node) throw (const QString&)
68 {
69     QDomElement e;
70     bool ok;
71     uint val;
72     QDateTime ts;
73
74     e = elem.firstChildElement (node);
75     if (e.isNull ())
76         throw QString (QString::fromAscii (node) + " not found");
77     val = e.text ().toUInt (&ok);
78     if (!ok)
79         throw QString (QString::fromAscii (node) + " is not a timestamp");
80     ts.setTime_t (val);
81     return ts;
82 }
83
84
85 // --------------------------------------------------
86 // ExtendedTrafficInfo
87 // --------------------------------------------------
88 ExtendedTrafficInfo::ExtendedTrafficInfo (const QDomElement& elem) throw (const QString&)
89     : TrafficInfo (elem)
90 {
91     QString color;
92
93     setValid (false);
94     _level_raw = getFloatNode (elem, "level_raw", 0);
95     _level = getIntNode (elem, "level", 1);
96     _tend = getIntNode (elem, "tend", 0);
97     _hint = getStringNode (elem, "hint");
98
99     color = getStringNode (elem, "icon");
100     if (color == "green")
101         _color = Green;
102     else if (color == "yellow")
103         _color = Yellow;
104     else if (color == "red")
105         _color = Red;
106     else
107         throw "Color is unknown";
108
109     setValid (true);
110 }
111
112
113 // --------------------------------------------------
114 // Traffic
115 // --------------------------------------------------
116 Traffic::Traffic ()
117     : QObject ()
118 {
119     connect (&_fetcher, SIGNAL (done (const QByteArray&)),
120              SLOT (fetchDone (const QByteArray&)));
121 }
122
123 // Perform asyncronous refresh of traffic information. If another update
124 // request is in progress, new is discarded. If update request finished
125 // successfully, updated() signal called.
126 void Traffic::update ()
127 {
128     if (_fetcher.busy ())
129         return;
130
131     _fetcher.fetch ("http://trf.maps.yandex.net/trf/stat.xml");
132 }
133
134
135 void Traffic::fetchDone (const QByteArray& data)
136 {
137     printf ("Got %d bytes of data\n", data.size ());
138     // parse data got
139     if (parse_traffic_data (QString::fromUtf8 (data.data ())))
140         updated ();
141     else
142         printf ("Parse failed\n");
143 }
144
145
146 bool Traffic::parse_traffic_data (const QString& xml)
147 {
148     QDomDocument doc;
149     QDateTime new_ts;
150     QDomElement e;
151     QDomNode n;
152     bool ok;
153     QString s;
154     QMap<QString, TrafficInfo> new_info;
155     QMap<QString, ExtendedTrafficInfo> new_ext_info;
156
157     if (!doc.setContent (xml))
158         return false;
159
160     // get timestamp
161     e = doc.documentElement ();
162     if (e.isNull () || e.tagName () != "jams_stat")
163         return false;
164
165     s = e.attribute ("timestamp");
166     if (s.isNull ())
167         return false;
168
169     new_ts.setTime_t (s.toUInt (&ok));
170     if (!ok)
171         return false;
172
173     // parse all regions
174     n = e.firstChild ();
175     while (!n.isNull ()) {
176         e = n.toElement ();
177         if (!e.isNull () && e.tagName () == "region") {
178             s = e.attribute ("id");
179             printf ("Process region %s\n", s.toUtf8 ().data ());
180             try {
181                 // Check that it is an extended traffic info
182                 if (!e.firstChildElement ("level").isNull ()) {
183                     ExtendedTrafficInfo info (e);
184                     if (info.valid ())
185                         new_ext_info[s] = info;
186                 }
187                 else {
188                     TrafficInfo info (e);
189                     if (info.valid ())
190                         new_info[s] = info;
191                 }
192             }
193             catch (const QString& msg) {
194                 printf ("Region %s parse failed: %s\n", s.toUtf8 ().data (), msg.toUtf8 ().data ());
195             }
196         }
197         n = n.nextSibling ();
198     }
199
200     _ts = new_ts;
201     _info = new_info;
202     _ext_info = new_ext_info;
203
204     return true;
205 }
206
207
208 TrafficInfo Traffic::lookup (const QString &id) const
209 {
210     QMap<QString, TrafficInfo>::const_iterator it = _info.find (id);
211
212     if (it == _info.end ())
213         return TrafficInfo ();
214     else
215         return it.value ();
216 }
217
218
219 ExtendedTrafficInfo Traffic::lookup_ext (const QString &id) const
220 {
221     QMap<QString, ExtendedTrafficInfo>::const_iterator it = _ext_info.find (id);
222
223     if (it == _ext_info.end ())
224         return ExtendedTrafficInfo ();
225     else
226         return it.value ();
227 }