Index: trunk/FACT++/src/DimState.h
===================================================================
--- trunk/FACT++/src/DimState.h	(revision 13842)
+++ trunk/FACT++/src/DimState.h	(revision 13842)
@@ -0,0 +1,119 @@
+#ifndef FACT_DimState
+#define FACT_DimState
+
+class DimState
+{
+protected:
+    typedef function<void(const EventImp &)> callback;
+
+    callback fCallback;
+
+public:
+    DimState(const string &n, const string s="STATE") : server(n),
+        service(n+"/"+s), info(make_pair(Time(), -4))
+    {
+    }
+    virtual ~DimState()
+    {
+    }
+
+    string server;
+    string service;
+
+    pair<Time, int> info;
+    string msg;
+
+    void Subscribe(StateMachineImp &imp)
+    {
+        imp.Subscribe(service.c_str())
+            (imp.Wrap(bind(&DimState::Handler, this, placeholders::_1)));
+    }
+
+    void SetCallback(const callback &cb)
+    {
+        fCallback = cb;
+    }
+
+    virtual void Handler(const EventImp &evt)
+    {
+        const bool disconnected = evt.GetSize()==0;
+
+        info = make_pair(evt.GetTime(), disconnected ? -4 : evt.GetQoS());
+
+        msg = disconnected ? "" : evt.GetString();
+
+        if (fCallback)
+            fCallback(evt);
+    }
+
+    const Time &time() const { return info.first; }
+    const int  &state() const { return info.second; }
+
+    bool online() const { return info.second>-4; }
+
+    const string &name() const { return server; }
+};
+
+class DimVersion : public DimState
+{
+public:
+    DimVersion() : DimState("DIS_DNS", "VERSION_NUMBER") { }
+
+    void Handler(const EventImp &evt)
+    {
+        DimState::Handler(evt);
+        info.second = evt.GetSize()==4 ? evt.GetInt() : 0;
+    }
+
+    string version() const
+    {
+        if (info.second==0)
+            return "Offline";
+
+        ostringstream out;
+        out << "V" << info.second/100 << 'r' << info.second%100;
+        return out.str();
+    }
+};
+
+class DimControl : public DimState
+{
+    map<string, callback> fCallbacks;
+
+public:
+    DimControl() : DimState("DIM_CONTROL") { }
+
+    void AddCallback(const string &script, const callback &cb)
+    {
+        fCallbacks[script] = cb;
+    }
+
+    void Handler(const EventImp &evt)
+    {
+        DimState::Handler(evt);
+
+        // Evaluate msg
+        const size_t p0 = msg.find_first_of(':');
+        if (p0==string::npos)
+            return;
+
+        const size_t p1 = msg.find_last_of('[');
+        if (p1==string::npos)
+            return;
+
+        const size_t p2 = msg.find_first_of(':', p0+1);
+
+        const size_t p3 = p2==string::npos || p2>p1 ? p1-1 : p2;
+
+        const string file = msg.substr(p0+2, p3-p0-2);
+
+        const auto func = fCallbacks.find(file);
+        if (func==fCallbacks.end())
+            return;
+
+        // Call callback
+        func->second(evt);
+    }
+};
+
+#endif
