Fix typo
[yandex-traffic] / traffic.cpp
index 2abfeed..05d5adf 100644 (file)
 #include <QtCore>
+#include <QtXml>
+
 #include "traffic.hpp"
+#include "log.hpp"
+
+
+// --------------------------------------------------
+// TrafficInfo
+// --------------------------------------------------
+TrafficInfo::TrafficInfo (const QDomElement& elem) throw (const QString&)
+{
+    _valid = false;
+    _len1 = getFloatNode (elem, "length_1", 0);
+    _len2 = getFloatNode (elem, "length_2", 0);
+    _len  = getFloatNode (elem, "length", 0);
+    _ts   = getTSNode (elem, "timestamp");
+    _isotime = getStringNode (elem, "isotime");
+    _localtime = getStringNode (elem, "localtime");
+    _valid = true;
+}
+
+
+float TrafficInfo::getFloatNode (const QDomElement& elem, const char* node, float def)
+{
+    QDomElement e;
+    bool ok;
+    float val;
 
+    e = elem.firstChildElement (node);
+    if (e.isNull ())
+        return def;
+    val = e.text ().toFloat (&ok);
+    if (!ok)
+        return def;
+    return val;
+}
+
+
+int TrafficInfo::getIntNode (const QDomElement& elem, const char* node, int def)
+{
+    QDomElement e;
+    bool ok;
+    int val;
 
-TrafficInfo::TrafficInfo ()
+    e = elem.firstChildElement (node);
+    if (e.isNull ())
+        return def;
+    val = e.text ().toInt (&ok);
+    if (!ok)
+        return def;
+    return val;
+}
+
+
+QString TrafficInfo::getStringNode (const QDomElement& elem, const char* node) throw (const QString&)
 {
+    QDomElement e;
+    QString val;
+
+    e = elem.firstChildElement (node);
+    if (e.isNull ())
+        throw QString (QString::fromAscii (node) + " not found");
+    return e.text ();
+}
+
+
+QDateTime TrafficInfo::getTSNode (const QDomElement& elem, const char* node) throw (const QString&)
+{
+    QDomElement e;
+    bool ok;
+    uint val;
+    QDateTime ts;
+
+    e = elem.firstChildElement (node);
+    if (e.isNull ())
+        throw QString (QString::fromAscii (node) + " not found");
+    val = e.text ().toUInt (&ok);
+    if (!ok)
+        throw QString (QString::fromAscii (node) + " is not a timestamp");
+    ts.setTime_t (val);
+    return ts;
+}
+
+
+void TrafficInfo::dump ()
+{
+    Log::instance ()->add (QString ("TrafficInfo (%1): time = %2").arg (_valid ? "valid" : "not valid").arg (_localtime));
+}
+
+
+// --------------------------------------------------
+// ExtendedTrafficInfo
+// --------------------------------------------------
+ExtendedTrafficInfo::ExtendedTrafficInfo (const QDomElement& elem) throw (const QString&)
+    : TrafficInfo (elem)
+{
+    QString color;
+
+    setValid (false);
+    _level_raw = getFloatNode (elem, "level_raw", 0);
+    _level = getIntNode (elem, "level", 1);
+    _tend = getIntNode (elem, "tend", 0);
+    _hint = getStringNode (elem, "hint");
+
+    color = getStringNode (elem, "icon");
+    if (color == "green")
+        _color = Green;
+    else if (color == "yellow")
+        _color = Yellow;
+    else if (color == "red")
+        _color = Red;
+    else
+        throw "Color is unknown";
+
+    setValid (true);
 }
 
 
-ExtendedTrafficInfo::ExtendedTrafficInfo ()
+void ExtendedTrafficInfo::dump ()
 {
+    TrafficInfo::dump ();
+    Log::instance ()->add (QString ("ExtTrafficInfo: level = %1, hint = %2").arg (_level).arg (_hint));
 }
 
 
+// --------------------------------------------------
+// Traffic
+// --------------------------------------------------
 Traffic::Traffic ()
+    : QObject ()
+{
+    connect (&_fetcher, SIGNAL (done (const QByteArray&)),
+             SLOT (fetchDone (const QByteArray&)));
+}
+
+
+// Perform asyncronous refresh of traffic information. If another update
+// request is in progress, new is discarded. If update request finished
+// successfully, updated() signal called.
+void Traffic::update ()
+{
+    Log::instance ()->add ("Traffic::update: Request status download");
+    _fetcher.fetch ("http://trf.maps.yandex.net/trf/stat.xml");
+}
+
+
+void Traffic::fetchDone (const QByteArray& data)
 {
+    // parse data got
+    if (parse_traffic_data (QString::fromUtf8 (data.data ()))) {
+        Log::instance ()->add ("Traffic::fetchDone: data parsed successfully");
+        updated ();
+    }
+    else
+        Log::instance ()->add ("Traffic::fetchDone: data parse error");
 }
+
+
+bool Traffic::parse_traffic_data (const QString& xml)
+{
+    QDomDocument doc;
+    QDateTime new_ts;
+    QDomElement e;
+    QDomNode n;
+    bool ok;
+    QString s;
+    QMap<QString, TrafficInfo> new_info;
+    QMap<QString, ExtendedTrafficInfo> new_ext_info;
+
+    if (!doc.setContent (xml))
+        return false;
+
+    // get timestamp
+    e = doc.documentElement ();
+    if (e.isNull () || e.tagName () != "jams_stat")
+        return false;
+
+    s = e.attribute ("timestamp");
+    if (s.isNull ())
+        return false;
+
+    new_ts.setTime_t (s.toUInt (&ok));
+    if (!ok)
+        return false;
+
+    // parse all regions
+    n = e.firstChild ();
+    while (!n.isNull ()) {
+        e = n.toElement ();
+        if (!e.isNull () && e.tagName () == "region") {
+            s = e.attribute ("id");
+            try {
+               // Check that it is an extended traffic info
+                if (!e.firstChildElement ("level").isNull ()) {
+                    ExtendedTrafficInfo info (e);
+                    if (info.valid ())
+                        new_ext_info[s] = info;
+                }
+                else {
+                    TrafficInfo info (e);
+                    if (info.valid ())
+                        new_info[s] = info;
+                }
+            }
+            catch (const QString& msg) {
+            }
+        }
+        n = n.nextSibling ();
+    }
+
+    _ts = new_ts;
+    _info = new_info;
+    _ext_info = new_ext_info;
+
+    return true;
+}
+
+
+TrafficInfo Traffic::lookup (const QString &id) const
+{
+    QMap<QString, TrafficInfo>::const_iterator it = _info.find (id);
+
+    if (it == _info.end ())
+        return TrafficInfo ();
+    else
+        return it.value ();
+}
+
+
+ExtendedTrafficInfo Traffic::lookup_ext (const QString &id) const
+{
+    QMap<QString, ExtendedTrafficInfo>::const_iterator it = _ext_info.find (id);
+
+    if (it == _ext_info.end ())
+        return ExtendedTrafficInfo ();
+    else
+        return it.value ();
+}
+