From 959f82eba1fc423da6f1947a50800fbf59d82a2b Mon Sep 17 00:00:00 2001
From: vincent <vincent@groupe-sa.fr>
Date: Mon, 21 Dec 2015 17:35:32 +0100
Subject: [PATCH] New class QCronField.

---
 src/CMakeLists.txt  |   1 +
 src/qcron.cpp       | 187 ++++----------------------------------------
 src/qcron.hpp       |  82 +++----------------
 src/qcronfield.cpp  | 165 ++++++++++++++++++++++++++++++++++++++
 src/qcronfield.hpp  |  84 ++++++++++++++++++++
 test/qcron_test.cpp |   7 +-
 6 files changed, 282 insertions(+), 244 deletions(-)
 create mode 100644 src/qcronfield.cpp
 create mode 100644 src/qcronfield.hpp

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index cd3564a..65ad75f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,5 +1,6 @@
 set(${PROJECT}_SRC_FILES
   qcron.cpp
+  qcronfield.cpp
   )
 
 set(${PROJECT}_HEADERS
diff --git a/src/qcron.cpp b/src/qcron.cpp
index e0bb6da..27d6cfe 100644
--- a/src/qcron.cpp
+++ b/src/qcron.cpp
@@ -35,173 +35,12 @@ QCron::
 _init()
 {
     _is_valid = true;
-    _fields[0].field = MINUTE;
-    _fields[1].field = HOUR;
-    _fields[2].field = DOM;
-    _fields[3].field = MONTH;
-    _fields[4].field = DOW;
-    _fields[5].field = YEAR;
-}
-
-/******************************************************************************/
-
-QString
-QCron::
-_validCharacters(EField field)
-{
-    Q_UNUSED(field);
-    return "0123456789*-/,";
-}
-
-/******************************************************************************/
-
-
-QCron::IntNode *
-QCron::
-QCronField::parseInt(QString & str)
-{
-    IntNode * node = new IntNode();
-    int value = 0;
-    int char_idx = 0;
-    QChar c = str[char_idx];
-    while (c.isDigit())
-    {
-        value = value * 10 + c.digitValue();
-        c = str[++char_idx];
-    }
-    if (char_idx == 0)
-    {
-        throw 42;
-    }
-    str.remove(0, char_idx);
-    node->value = value;
-    //qDebug() << "Parsing an Int :" << value;
-    switch (field)
-    {
-    case MINUTE: if (value < 0 || 59 < value) throw 42; break;
-    case HOUR:   if (value < 0 || 23 < value) throw 42; break;
-    case DOM:    if (value < 1 || 31 < value) throw 42; break;
-    case MONTH:  if (value < 1 || 12 < value) throw 42; break;
-    case DOW:    if (value < 1 || 7  < value) throw 42; break;
-    case YEAR:   if (value < 2016 || 2099 < value) throw 42; break;
-    default:                                  throw 42; break;
-    }
-    return node;
-}
-
-QCron::RangeNode*
-QCron::
-QCronField::parseRange(QString & str)
-{
-    //   qDebug() << "Parsing a Range";
-    if (last_node == NULL)
-    {
-        throw 42;
-    }
-    RangeNode * range = new RangeNode();
-    IntNode * begin = dynamic_cast<IntNode *>(last_node);
-    if (begin == NULL)
-    {
-        throw 42;
-    }
-    range->begin = begin;
-    str.remove(0, 1);
-    IntNode * end = dynamic_cast<IntNode *>(parseInt(str));
-    if (end == NULL)
-    {
-        throw 42;
-    }
-    range->end = end;
-    if (range->begin->value > range->end->value)
-    {
-        throw 42;
-    }
-    return range;
-}
-
-QCron::EveryNode*
-QCron::
-QCronField::parseEvery(QString & str)
-{
-//    qDebug() << "Parsing an Every";
-    EveryNode * every = new EveryNode();
-    every->what = last_node;
-    str.remove(0, 1);
-    every->freq = parseInt(str);
-    return every;
-}
-
-QCron::ListNode*
-QCron::
-QCronField::parseList(QString & str)
-{
-//    qDebug() << "Parsing a List";
-    ListNode * list = new ListNode();
-    list->nodes << last_node;
-    last_node = list;
-    while (str[0] == ',')
-    {
-        str.remove(0, 1);
-        Node * node = parseNode(str);
-        list->nodes << node;
-        last_node = node;
-    }
-    return list;
-}
-
-QCron::Node *
-QCron::
-QCronField::
-parseNode(QString & str)
-{
-    //qDebug() << "Parsing a node";
-    QChar c = str[0];
-    if (c.isDigit())
-    {
-        return parseInt(str);
-    }
-    else if ("-" == c)
-    {
-        return parseRange(str);
-    }
-    else if ("/" == c)
-    {
-        return parseEvery(str);
-    }
-    else if ("*" == c)
-    {
-        return new AllNode;
-    }
-    else if ("," == c)
-    {
-        return parseList(str);
-    }
-    throw 42;
-}
-
-/******************************************************************************/
-
-
-void
-QCron::
-QCronField::
-parse(QString & str)
-{
-    try
-    {
-        last_node = NULL;
-        Node * root = parseNode(str);
-        if (!str.isEmpty())
-        {
-            last_node = root;
-            root = parseNode(str);
-        }
-        is_valid = true;
-    }
-    catch (int)
-    {
-        is_valid = false;
-    }
+    _fields[0].setField(MINUTE);
+    _fields[1].setField(HOUR);
+    _fields[2].setField(DOM);
+    _fields[3].setField(MONTH);
+    _fields[4].setField(DOW);
+    _fields[5].setField(YEAR);
 }
 
 /******************************************************************************/
@@ -224,13 +63,17 @@ _parsePattern(QString & pattern)
     for (int i = 0; i < 6; ++i)
     {
         _fields[i].parse(fields[i]);
-        _is_valid &= _fields[i].is_valid;
+        _is_valid &= _fields[i].isValid();
     }
 }
 
 /******************************************************************************/
 
-/*
-
-
- */
+QDateTime
+QCron::
+next(int n) const
+{
+    Q_UNUSED(n);
+    //QCronField seconds = _fields[0];
+    return QDateTime::currentDateTime();
+}
diff --git a/src/qcron.hpp b/src/qcron.hpp
index 6d2b6d3..d0f999d 100644
--- a/src/qcron.hpp
+++ b/src/qcron.hpp
@@ -2,6 +2,8 @@
 #define _QCRON_HPP
 
 #include <QObject>
+#include <QDateTime>
+#include "qcronfield.hpp"
 
 class QCron : public QObject
 {
@@ -12,87 +14,25 @@ public:
     QCron(QString & pattern);
     ~QCron();
 
-    // Features.
+    // Accessors.
+    void setBeginning(const QDateTime & date_time)
+        { _beginning = date_time; }
+
     bool isValid() const
         { return _is_valid; }
 
+    // Features.
+
+    QDateTime next(int n = 1) const;
+
 signals:
     void activated();
     void deactivated();
 
 private:
-    enum EField
-    {
-        MINUTE,
-        HOUR,
-        DOM,
-        MONTH,
-        DOW,
-        YEAR
-    };
-
-
-    struct Node
-    {
-        virtual ~Node() {}
-    };
-
-    struct ValueNode : public Node
-    {
-    };
-
-    struct IntNode : public ValueNode
-    {
-        int value;
-    };
-
-    struct StrNode : public ValueNode
-    {
-    };
-
-    struct AllNode : public ValueNode
-    {
-    };
-
-    struct RangeNode : public Node
-    {
-        IntNode * begin;
-        IntNode * end;
-    };
-
-    struct EveryNode : public Node
-    {
-        Node * what;
-        IntNode * freq;
-    };
-
-    struct ListNode : public Node
-    {
-        QList<Node*> nodes;
-    };
-
-    struct QCronField
-    {
-        EField field;
-        bool is_valid;
-        Node * last_node;
-        Node * root;
-
-        QCronField()
-            : is_valid(false)
-            {}
-
-        IntNode * parseInt(QString & str);
-        RangeNode* parseRange(QString & str);
-        EveryNode* parseEvery(QString & str);
-        ListNode * parseList(QString & str);
-        Node * parseNode(QString & str);
-        void parse(QString&);
-
-    };
-
     bool _is_valid;
     QCronField _fields[6];
+    QDateTime _beginning;
 
     void _init();
     void _parsePattern(QString & pattern);
diff --git a/src/qcronfield.cpp b/src/qcronfield.cpp
new file mode 100644
index 0000000..d1912aa
--- /dev/null
+++ b/src/qcronfield.cpp
@@ -0,0 +1,165 @@
+#include "qcronfield.hpp"
+
+/******************************************************************************/
+
+QCronField::
+QCronField()
+    : _is_valid(false)
+{}
+
+/******************************************************************************/
+
+IntNode *
+QCronField::
+_parseInt(QString & str)
+{
+    IntNode * node = new IntNode();
+    int value = 0;
+    int char_idx = 0;
+    QChar c = str[char_idx];
+    while (c.isDigit())
+    {
+        value = value * 10 + c.digitValue();
+        c = str[++char_idx];
+    }
+    if (char_idx == 0)
+    {
+        throw 42;
+    }
+    str.remove(0, char_idx);
+    node->value = value;
+    //qDebug() << "Parsing an Int :" << value;
+    switch (_field)
+    {
+    case MINUTE: if (value < 0 || 59 < value) throw 42; break;
+    case HOUR:   if (value < 0 || 23 < value) throw 42; break;
+    case DOM:    if (value < 1 || 31 < value) throw 42; break;
+    case MONTH:  if (value < 1 || 12 < value) throw 42; break;
+    case DOW:    if (value < 1 || 7  < value) throw 42; break;
+    case YEAR:   if (value < 2016 || 2099 < value) throw 42; break;
+    default:                                  throw 42; break;
+    }
+    return node;
+}
+
+/******************************************************************************/
+
+RangeNode*
+QCronField::
+_parseRange(QString & str)
+{
+    //   qDebug() << "Parsing a Range";
+    if (_last_node == NULL)
+    {
+        throw 42;
+    }
+    RangeNode * range = new RangeNode();
+    IntNode * begin = dynamic_cast<IntNode *>(_last_node);
+    if (begin == NULL)
+    {
+        throw 42;
+    }
+    range->begin = begin;
+    str.remove(0, 1);
+    IntNode * end = dynamic_cast<IntNode *>(_parseInt(str));
+    if (end == NULL)
+    {
+        throw 42;
+    }
+    range->end = end;
+    if (range->begin->value > range->end->value)
+    {
+        throw 42;
+    }
+    return range;
+}
+
+/******************************************************************************/
+
+EveryNode*
+QCronField::
+_parseEvery(QString & str)
+{
+//    qDebug() << "Parsing an Every";
+    EveryNode * every = new EveryNode();
+    every->what = _last_node;
+    str.remove(0, 1);
+    every->freq = _parseInt(str);
+    return every;
+}
+
+/******************************************************************************/
+
+ListNode*
+QCronField::
+_parseList(QString & str)
+{
+//    qDebug() << "Parsing a List";
+    ListNode * list = new ListNode();
+    list->nodes << _last_node;
+    _last_node = list;
+    while (str[0] == ',')
+    {
+        str.remove(0, 1);
+        Node * node = _parseNode(str);
+        list->nodes << node;
+        _last_node = node;
+    }
+    return list;
+}
+
+/******************************************************************************/
+
+Node *
+QCronField::
+_parseNode(QString & str)
+{
+    //qDebug() << "Parsing a node";
+    QChar c = str[0];
+    if (c.isDigit())
+    {
+        return _parseInt(str);
+    }
+    else if ("-" == c)
+    {
+        return _parseRange(str);
+    }
+    else if ("/" == c)
+    {
+        return _parseEvery(str);
+    }
+    else if ("*" == c)
+    {
+        return new AllNode;
+    }
+    else if ("," == c)
+    {
+        return _parseList(str);
+    }
+    throw 42;
+}
+
+/******************************************************************************/
+
+void
+QCronField::
+parse(QString & str)
+{
+    try
+    {
+        _last_node = NULL;
+        Node * _root = _parseNode(str);
+        if (!str.isEmpty())
+        {
+            _last_node = _root;
+            _root = _parseNode(str);
+        }
+        _is_valid = true;
+    }
+    catch (int)
+    {
+        _is_valid = false;
+    }
+}
+
+/******************************************************************************/
diff --git a/src/qcronfield.hpp b/src/qcronfield.hpp
new file mode 100644
index 0000000..27faef1
--- /dev/null
+++ b/src/qcronfield.hpp
@@ -0,0 +1,84 @@
+#ifndef _QCRONFIELD_HPP
+#define _QCRONFIELD_HPP
+
+#include <QList>
+#include <QString>
+
+enum EField
+{
+    MINUTE,
+    HOUR,
+    DOM,
+    MONTH,
+    DOW,
+    YEAR
+};
+
+struct Node
+{
+    virtual ~Node() {}
+};
+
+struct ValueNode : public Node
+{
+};
+
+struct IntNode : public ValueNode
+{
+    int value;
+};
+
+struct StrNode : public ValueNode
+{
+};
+
+struct AllNode : public ValueNode
+{
+};
+
+struct RangeNode : public Node
+{
+    IntNode * begin;
+    IntNode * end;
+};
+
+struct EveryNode : public Node
+{
+    Node * what;
+    IntNode * freq;
+};
+
+struct ListNode : public Node
+{
+    QList<Node*> nodes;
+};
+
+class QCronField
+{
+public:
+    QCronField();
+
+    // Accessors.
+    void setField(EField field)
+        { _field = field; }
+
+    // Features.
+    void parse(QString & str);
+
+    bool isValid() const
+        { return _is_valid; }
+
+private:
+    EField _field;
+    bool _is_valid;
+    Node * _last_node;
+    Node * _root;
+
+    IntNode * _parseInt(QString & str);
+    RangeNode* _parseRange(QString & str);
+    EveryNode* _parseEvery(QString & str);
+    ListNode * _parseList(QString & str);
+    Node * _parseNode(QString & str);
+};
+
+#endif
diff --git a/test/qcron_test.cpp b/test/qcron_test.cpp
index a780bbe..6b26631 100644
--- a/test/qcron_test.cpp
+++ b/test/qcron_test.cpp
@@ -8,7 +8,12 @@ void
 QCronTest::
 basics()
 {
-    QFAIL("Nothing here.");
+    QDateTime now = QDateTime::currentDateTime();
+    QCron c("* * * * * *");
+    c.setBeginning(now);
+    QDateTime next = c.next();
+    qDebug() << next;
+    QFAIL("Nope!");
 }
 
 /******************************************************************************/