Index: trunk/FACT++/src/dimctrl.cc
===================================================================
--- trunk/FACT++/src/dimctrl.cc	(revision 13670)
+++ trunk/FACT++/src/dimctrl.cc	(revision 13671)
@@ -1,4 +1,9 @@
+#ifndef FACT_DimCtrl
+#define FACT_DimCtrl
+
+#include "Main.h"
+#include "tools.h"
+#include "MessageDim.h"
 #include "RemoteControl.h"
-#include "Main.h"
 
 using namespace std;
@@ -33,17 +38,218 @@
 
 // A simple dummy state machine
-class DimCtrl : public MainImp, public MessageImp
-{
-    bool fStop;
+class DimCtrl : public MainImp, public DimCommandHandler, public MessageDimTX
+{
+    int  fLabel;
+    int  fStop;
+    int  fVerbosity;
+    bool fDebug;
+    bool fIsServer;
+
+    DimDescribedService fSrvState;
+    DimCommand          fDimStart;
+    DimCommand          fDimStop;
+
+    map<string,string> fData;
+    string fScript;
+
+    void ProcessStart()
+    {
+        if (!fScript.empty() || fLabel>=0)
+        {
+            Error("Script execution still in progress.");
+            return;
+        }
+
+        string opt(fDimStart.getString());
+
+        fData = Tools::Split(opt);
+
+        if (opt.size()==0)
+        {
+            if (fData.size()==0)
+                Error("File name missing in DIM_CONTROL/START");
+            else
+                Error("Equal sign missing in argument '"+fData.begin()->first+"'");
+
+            return;
+        }
+
+        Debug("Start '"+opt+"' received.");
+        if (fDebug)
+        {
+            string d(fDimStart.getString());
+            if (d.length()>opt.length())
+                Debug("Received data: "+string(fDimStart.getString()).substr(opt.length()+1));
+        }
+
+        if (fDebug)
+        {
+            for (auto it=fData.begin(); it!=fData.end(); it++)
+                Debug("   Arg: "+it->first+" = "+it->second);
+        }
+
+        fScript = opt;
+    }
+
+    void commandHandler()
+    {
+        if (getCommand()==&fDimStop)
+        {
+            Debug("Stop received");
+            Readline::SetLabel(0);
+        }
+
+        if (getCommand()==&fDimStart)
+            ProcessStart();
+    }
 
 public:
-    DimCtrl(ostream &out=cout) : MessageImp(out), fStop(false)
-    {
-    }
-
-    int EvalOptions(Configuration &) { return -1; }
-    void Stop() { fStop = true; }
-    int Run(bool) { while (!fStop) usleep(1000); return 0; }
+    DimCtrl(ostream &out=cout) : MessageDimTX("DIM_CONTROL", out),
+        fLabel(-3), fStop(false), fVerbosity(0), fDebug(false), fIsServer(false),
+        fSrvState("DIM_CONTROL/STATE", "C",
+                  "Provides the state of the state machine as quality of service."
+                  "|Text[string]:A human readable string sent by the last state change."),
+        fDimStart("DIM_CONTROL/START", "C", this),
+        fDimStop("DIM_CONTROL/STOP", "", this)
+    {
+    }
+    ~DimCtrl()
+    {
+        DimServer::stop();
+    }
+
+    bool check(string &str)
+    {
+        for (auto c=str.begin(); c<str.end(); c++)
+        {
+            if ((*c>='A' && *c<='Z') || *c=='_')
+                continue;
+
+            if (*c++!=':')
+                return false;
+
+            if (c==str.end())
+                return false;
+
+            if (*c!=' ')
+                return false;
+
+            str = string(c+1, str.end());
+            return true;
+        }
+
+        return false;
+    }
+
+    int Write(const Time &time, const std::string &txt, int qos=kMessage)
+    {
+        if (txt=="")
+        {
+            fLabel = qos;
+
+            if (fDebug)
+            {
+                ostringstream out;
+                if (fLabel<0)
+                {
+                    if (fLabel==-1)
+                        out << "========================== Begin ========================";
+                    else
+                        out << "=========================== End =========================";
+                }
+                else
+                    out << "------------------------ Label " << setfill('0') << setw(3) << fLabel << " ----------------------";
+
+                MessageDimTX::Write(time, out.str(), 90);
+            }
+
+            fSrvState.setQuality(fLabel);
+            switch (fLabel)
+            {
+            case -2: return fSrvState.Update("End of script execution");
+            case -1: return fSrvState.Update("Start of script execution");
+            default: return fSrvState.Update("New label");
+            }
+        }
+
+        if (qos<fVerbosity)
+            return 0;
+
+        // Avoid recursions
+        if (fIsServer && txt.substr(0, 13)=="DIM_CONTROL: ")
+            return 0;
+
+        // Don't send received messages via dim
+        string cpy(txt);
+        if (fIsServer && check(cpy))
+            return MessageImp::Write(time, cpy, qos);
+
+        // Send all of our own messages via dim
+        return MessageDimTX::Write(time, txt, qos);
+    }
+
+    int EvalOptions(Configuration &conf)
+    {
+        fVerbosity = 90;
+
+        if (conf.Get<bool>("stop"))
+            return Dim::SendCommand("DIM_CONTROL/STOP") + 1;
+
+        if (conf.Has("start"))
+            return Dim::SendCommand("DIM_CONTROL/START", conf.Get<string>("start")) + 1;
+
+        fVerbosity = 40;
+
+        fIsServer = conf.Get<bool>("server");
+        if (fIsServer)
+        {
+            // Sleep needed to ensure that the server can send
+            // an EXIT if another instance is already running
+            DimServer::start("DIM_CONTROL");
+            sleep(1);
+        }
+
+        if (conf.Has("verbosity"))
+            fVerbosity = conf.Get<uint32_t>("verbosity");
+
+        if (conf.Get<bool>("quiet"))
+            fVerbosity = 90;
+
+        fDebug = conf.Get<bool>("debug");
+
+        return -1;
+    }
+
+    void Stop(int stop=1) { fStop = stop; Readline::SetLabel(0); }
+    int Run(bool)
+    {
+        while (!fStop)
+        {
+            const string s = fScript;
+            if (!s.empty())
+            {
+                Readline::Instance()->Execute(s, fData);
+                fScript = "";
+            }
+
+            usleep(1000);
+        }
+        return fStop-1; }
 };
+
+void SetupConfiguration(Configuration &conf)
+{
+    po::options_description control("Dim Control");
+    control.add_options()
+        ("server",      po_bool(false),  "Start dimctrl as a dim server")
+        ("verbosity,v", var<uint32_t>()->implicit_value(0), "Set a new verbosity level (see MessageImp)")
+        ("quiet,q",     po_bool(false),  "Suppress all output except comments (log-level>=90)")
+        ("debug",       po_bool(false),  "Print the labels for debugging purpose")
+        ("start",       var<string>(),  "")
+        ("stop",        po_switch(),  "")
+        ;
+
+    conf.AddOptions(control);
+}
 
 int main(int argc, const char *argv[])
@@ -52,9 +258,13 @@
     conf.SetPrintUsage(PrintUsage);
     Main::SetupConfiguration(conf);
+    SetupConfiguration(conf);
 
     if (!conf.DoParse(argc, argv, PrintHelp))
         return -1;
 
-    if (!conf.Has("console") || conf.Get<int>("console")==0)
+    if (!conf.Has("console"))
+        return Main::execute<RemoteStream, DimCtrl>(conf);
+
+    if (conf.Get<int>("console")==0)
         return Main::execute<RemoteShell, DimCtrl>(conf);
     else
@@ -63,2 +273,3 @@
     return 0;
 }
+#endif
