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