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