Log connection state transitions.
[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     // parse data got
138     if (parse_traffic_data (QString::fromUtf8 (data.data ())))
139         updated ();
140 }
141
142
143 bool Traffic::parse_traffic_data (const QString& xml)
144 {
145     QDomDocument doc;
146     QDateTime new_ts;
147     QDomElement e;
148     QDomNode n;
149     bool ok;
150     QString s;
151     QMap<QString, TrafficInfo> new_info;
152     QMap<QString, ExtendedTrafficInfo> new_ext_info;
153
154     if (!doc.setContent (xml))
155         return false;
156
157     // get timestamp
158     e = doc.documentElement ();
159     if (e.isNull () || e.tagName () != "jams_stat")
160         return false;
161
162     s = e.attribute ("timestamp");
163     if (s.isNull ())
164         return false;
165
166     new_ts.setTime_t (s.toUInt (&ok));
167     if (!ok)
168         return false;
169
170     // parse all regions
171     n = e.firstChild ();
172     while (!n.isNull ()) {
173         e = n.toElement ();
174         if (!e.isNull () && e.tagName () == "region") {
175             s = e.attribute ("id");
176             try {
177                 // Check that it is an extended traffic info
178                 if (!e.firstChildElement ("level").isNull ()) {
179                     ExtendedTrafficInfo info (e);
180                     if (info.valid ())
181                         new_ext_info[s] = info;
182                 }
183                 else {
184                     TrafficInfo info (e);
185                     if (info.valid ())
186                         new_info[s] = info;
187                 }
188             }
189             catch (const QString& msg) {
190             }
191         }
192         n = n.nextSibling ();
193     }
194
195     _ts = new_ts;
196     _info = new_info;
197     _ext_info = new_ext_info;
198
199     return true;
200 }
201
202
203 TrafficInfo Traffic::lookup (const QString &id) const
204 {
205     QMap<QString, TrafficInfo>::const_iterator it = _info.find (id);
206
207     if (it == _info.end ())
208         return TrafficInfo ();
209     else
210         return it.value ();
211 }
212
213
214 ExtendedTrafficInfo Traffic::lookup_ext (const QString &id) const
215 {
216     QMap<QString, ExtendedTrafficInfo>::const_iterator it = _ext_info.find (id);
217
218     if (it == _ext_info.end ())
219         return ExtendedTrafficInfo ();
220     else
221         return it.value ();
222 }