<commit_before>#include <QtTest/QtTest>
#include <QDebug>
#include <random>
#include <typeinfo>
#include "model.h"
#include "model_io.h"
#include <fstream>

using namespace figures;

using std::make_shared;
using std::dynamic_pointer_cast;

class ModelModifier {
public:
    ModelModifier(Model &model, std::default_random_engine::result_type seed)
        : model(model)
        , generator(seed)
        , coordGen(MIN_COORD, MAX_COORD)
        , curveLengthGen(2, 20)
        , labelLengthGen(1, 20)
        , labelLetterGen('a', 'z')
    {}

    void doRandom() {
        int operation = randint(1, 4);
        if (operation == 1) {
            removeFigure();
        } else {
            addFigure();
        }
    }

    void addFigure() {
        int type = randint(0, 4);
        Point a = genPoint();
        Point b = genPoint();

        PFigure figure;
        switch (type) {
        case 0: {
            auto segment = make_shared<Segment>(a, b);
            segment->setArrowedA(randint(0, 1));
            segment->setArrowedB(randint(0, 1));
            figure = segment;
        }   break;
        case 1:
            figure = make_shared<Ellipse>(BoundingBox({ a, b }));
            break;
        case 2:
            figure = make_shared<Rectangle>(BoundingBox({ a, b }));
            break;
        case 3: {
            int len = curveLengthGen(generator);
            std::vector<Point> points;
            for (int i = 0; i < len; i++) {
                points.push_back(genPoint());
            }
            figure = make_shared<Curve>(points);
        }   break;
        case 4: {
            auto figA = getRandomBoundedFigure();
            auto figB = getRandomBoundedFigure();
            if (!figA || !figB) {
                return;
            }
            auto segment = make_shared<SegmentConnection>(figA, figB);
            segment->setArrowedA(randint(0, 1));
            segment->setArrowedB(randint(0, 1));
            figure = segment;
        }
        }
        if (randint(0, 1) == 0) {
            figure->setLabel(genLabel());
        }
        model.addFigure(figure);
    }

    void removeFigure() {
        if (model.size() == 0) {
            return;
        }
        int id = randint(0, model.size() - 1);
        for (auto it = model.begin(); it != model.end(); it++, id--) {
            if (id == 0) {
                model.removeFigure(it);
                return;
            }
        }
    }

private:
    Model &model;
    std::default_random_engine generator;

    PBoundedFigure getRandomBoundedFigure() {
        size_t count = 0;
        for (auto fig : model) {
            auto result = dynamic_pointer_cast<BoundedFigure>(fig);
            if (result) { count++; }
        }
        if (!count) { return nullptr; }
        int id = randint(0, count - 1);
        for (auto fig : model) {
            auto result = dynamic_pointer_cast<BoundedFigure>(fig);
            if (result) {
                if (id == 0) {
                    return result;
                } else {
                    id--;
                }
            }
        }
        abort();
    }

    static const int MIN_COORD = -1e5;
    static const int MAX_COORD =  1e5;
    std::uniform_real_distribution<> coordGen;
    std::uniform_int_distribution<> curveLengthGen;
    std::uniform_int_distribution<> labelLengthGen, labelLetterGen;

    int randint(int l, int r) {
        return std::uniform_int_distribution<>(l, r)(generator);
    }

    Point genPoint() {
        double x = round(coordGen(generator) * 10) / 10;
        double y = round(coordGen(generator) * 10) / 10;
        return Point(x, y);
    }
    std::string genLabel() {
        int len = labelLengthGen(generator);
        std::string result = "";
        for (int i = 0; i < len; i++) {
            result += labelLetterGen(generator);
        }
        return result;
    }
};

class FiguresComparator : public FigureVisitor {
public:
    FiguresComparator(const Figure &other, const std::map<PFigure, PFigure> &othersMapping) : other(other), othersMapping(othersMapping), _result(false) {}
    bool result() const { return _result; }

    virtual void accept(Segment &segm1) override {
        _result = false;
        auto &segm2 = dynamic_cast<const Segment&>(other);
        if (segm1.label() != segm2.label()) { return; }
        if (segm1.getArrowedA() != segm2.getArrowedA()) { return; }
        if (segm1.getArrowedB() != segm2.getArrowedB()) { return; }
        _result =
                segm1.getA() == segm2.getA() &&
                segm1.getB() == segm2.getB();
    }

    virtual void accept(SegmentConnection &segm1) override {
        _result = false;
        auto &segm2 = dynamic_cast<const SegmentConnection&>(other);
        if (segm1.label() != segm2.label()) { return; }
        if (segm1.getArrowedA() != segm2.getArrowedA()) { return; }
        if (segm1.getArrowedB() != segm2.getArrowedB()) { return; }
        _result =
                segm1.getFigureA() == othersMapping.at(segm2.getFigureA()) &&
                segm1.getFigureB() == othersMapping.at(segm2.getFigureB());
    }

    virtual void accept(Curve &curve1) override {
        _result = false;
        auto &curve2 = dynamic_cast<const Curve&>(other);
        if (curve1.label() != curve2.label()) { return; }
        _result = curve1.points == curve2.points;
    }

    virtual void accept(figures::Ellipse &fig1) override {
        _result = false;
        auto &fig2 = dynamic_cast<const Ellipse&>(other);
        if (fig1.label() != fig2.label()) { return; }
        _result = fig1.getBoundingBox() == fig2.getBoundingBox();
    }

    virtual void accept(figures::Rectangle &fig1) override {
        _result = false;
        auto &fig2 = dynamic_cast<const Rectangle&>(other);
        if (fig1.label() != fig2.label()) { return; }
        _result = fig1.getBoundingBox() == fig2.getBoundingBox();
    }

private:
    const Figure &other;
    const std::map<PFigure, PFigure> &othersMapping;
    bool _result;
};

bool modelsAreEqual(const Model &a, const Model &b) {
    if (a.size() != b.size()) {
        return false;
    }

    std::map<PFigure, PFigure> others;

    auto ita = a.begin(), itb = b.begin();
    for (; ita != a.end() && itb != b.end(); ita++, itb++) {
        // one dereference from iterator, second dereference from shared_ptr
        Figure &a = **ita;
        Figure &b = **itb;
        if (typeid(a) != typeid(b)) {
            return false;
        }
        FiguresComparator cmp(b, others);
        a.visit(cmp);
        if (!cmp.result()) {
            return false;
        }
        assert(!others.count(*itb));
        others[*itb] = *ita;
    }
    assert(ita == a.end() && itb == b.end());
    return true;
}

class Tests : public QObject {
    Q_OBJECT
private slots:
    void testDistanceToSegmentBorder() {
        const double EPS = 1e-8;
        Segment s(Point(11, 1), Point(14, 4));
        QVERIFY(fabs(s.getApproximateDistanceToBorder(Point(11, 1)) - 0) < EPS);
        QVERIFY(fabs(s.getApproximateDistanceToBorder(Point(11, 0)) - 1) < EPS);
        QVERIFY(fabs(s.getApproximateDistanceToBorder(Point(10, 0)) - sqrt(2)) < EPS);
        QVERIFY(fabs(s.getApproximateDistanceToBorder(Point(14, 4)) - 0) < EPS);
        QVERIFY(fabs(s.getApproximateDistanceToBorder(Point(15, 4)) - 1) < EPS);
        QVERIFY(fabs(s.getApproximateDistanceToBorder(Point(15, 5)) - sqrt(2)) < EPS);
        QVERIFY(fabs(s.getApproximateDistanceToBorder(Point(12, 2)) - 0) < EPS);
        QVERIFY(fabs(s.getApproximateDistanceToBorder(Point(14, 2)) - sqrt(2)) < EPS);
    }
    void testInsideSegment() {
        Segment s(Point(11, 4), Point(14, 1));
        QVERIFY( s.isInsideOrOnBorder(Point(11, 4)));
        QVERIFY(!s.isInsideOrOnBorder(Point(11, 4.001)));
        QVERIFY(!s.isInsideOrOnBorder(Point(10.999, 4)));
        QVERIFY( s.isInsideOrOnBorder(Point(14, 1)));
        QVERIFY(!s.isInsideOrOnBorder(Point(13.999, 1)));
        QVERIFY(!s.isInsideOrOnBorder(Point(14, 0.999)));
        QVERIFY(!s.isInsideOrOnBorder(Point(13.999, 0.999)));
        QVERIFY( s.isInsideOrOnBorder(Point(12, 3)));
        QVERIFY( s.isInsideOrOnBorder(Point(13, 2)));
    }
    void testDistanceToRectangleBorder() {
        const double EPS = 1e-8;
        Rectangle r({ Point(11, 1), Point(14, 4) });
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(11, 1)) - 0) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(11, 2)) - 0) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(11, 4)) - 0) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(13, 4)) - 0) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(15, 4)) - 1) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(15, 2)) - 1) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(12, 0)) - 1) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(12, 2)) - 1) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(12.5, 2)) - 1) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(13.5, 2)) - 0.5) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(12.5, 3)) - 1) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(10, 3)) - 1) < EPS);

        // Test distance to corners
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(15, 5)) - sqrt(2)) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(16, 5)) - sqrt(5)) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(10, -1)) - sqrt(5)) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(10, 6)) - sqrt(5)) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(16, 5)) - sqrt(5)) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(16, 0)) - sqrt(5)) < EPS);
    }
    void testInsideEllipse() {
        Ellipse e({ Point(11, 1), Point(17, 5) });
        QVERIFY(!e.isInsideOrOnBorder(Point(11, 1)));
        QVERIFY(!e.isInsideOrOnBorder(Point(11.5, 1.5)));
        QVERIFY(!e.isInsideOrOnBorder(Point(17, 5)));
        QVERIFY(!e.isInsideOrOnBorder(Point(11, 5)));
        QVERIFY(e.isInsideOrOnBorder(Point(14, 5)));
        QVERIFY(e.isInsideOrOnBorder(Point(14, 1)));
        QVERIFY(e.isInsideOrOnBorder(Point(14, 3)));
        QVERIFY(e.isInsideOrOnBorder(Point(15, 3.2)));
        QVERIFY( e.isInsideOrOnBorder(Point(16.1, 4.4)));
        QVERIFY(!e.isInsideOrOnBorder(Point(16.2, 4.4)));
        QVERIFY(!e.isInsideOrOnBorder(Point(16.1, 4.5)));
    }
    void testDistanceToEllipseBorder() {
        const double EPS = 1e-8;
        Ellipse e({ Point(11, 1), Point(17, 5) });
        QVERIFY(e.getApproximateDistanceToBorder(Point(11, 1)) <= sqrt(9 + 4) + EPS);
        QVERIFY(e.getApproximateDistanceToBorder(Point(11, 3)) <= EPS);
        QVERIFY(e.getApproximateDistanceToBorder(Point(17, 3)) <= EPS);
        QVERIFY(e.getApproximateDistanceToBorder(Point(14, 1)) <= EPS);
        QVERIFY(e.getApproximateDistanceToBorder(Point(14, 5)) <= EPS);
        QVERIFY(e.getApproximateDistanceToBorder(Point(10, 3)) >= 1 - EPS);
        QVERIFY(e.getApproximateDistanceToBorder(Point(14, 0)) >= 1 - EPS);
        QVERIFY(fabs(e.getApproximateDistanceToBorder(Point(14, 3)) - 2) < EPS);

        Ellipse e2({ Point(11, 1), Point(15, 7) });
        QVERIFY(fabs(e2.getApproximateDistanceToBorder(Point(13, 4)) - 2) < EPS);
    }

    void testSimpleSaveLoad() {
        int testId = 1;
        for (;; testId++) {
            char resourceName[64];
            snprintf(resourceName, sizeof resourceName, ":/tests/%02d.model", testId);
            QFile file(resourceName);
            if (!file.open(QFile::ReadOnly | QFile::Text)) {
                break;
            }
            qDebug() << "Trying" << resourceName;

            QByteArray inData = file.readAll();
            std::stringstream inDataStream;
            inDataStream << inData.toStdString();

            Model model;
            try {
                inDataStream >> model;
            } catch (model_format_error &e) {
                qDebug() << e.what();
                throw;
            }

            std::stringstream outDataStream;
            outDataStream << model;
            std::string outStr = outDataStream.str();
            QByteArray outData(outStr.data(), outStr.length());
            QCOMPARE(outData, inData);
        }
        QVERIFY(testId > 1);
    }

    void testStressSaveLoad() {
        const int PASSES = 10;
        for (int pass = 0; pass < PASSES; pass++) {
            qDebug("pass %d/%d", pass + 1, PASSES);
            Model model;
            ModelModifier modifier(model, pass);
            for (int iteration = 0; iteration < 50; iteration++) {
                std::stringstream data;
                data << model;

                std::string saved1 = data.str();

                Model restored;
                data >> restored;

                std::stringstream data2;
                data2 << restored;

                Model restored2;
                data2 >> restored2;

                std::string saved2 = data.str();
                QCOMPARE(saved1, saved2);
                QVERIFY(modelsAreEqual(model, restored2));
                modifier.doRandom();
            }
        }
    }
};

QTEST_MAIN(Tests)
#include "tests.moc"
<commit_msg>tests.testStressSaveLoad: 100 iterations instead of 50<commit_after>#include <QtTest/QtTest>
#include <QDebug>
#include <random>
#include <typeinfo>
#include "model.h"
#include "model_io.h"
#include <fstream>

using namespace figures;

using std::make_shared;
using std::dynamic_pointer_cast;

class ModelModifier {
public:
    ModelModifier(Model &model, std::default_random_engine::result_type seed)
        : model(model)
        , generator(seed)
        , coordGen(MIN_COORD, MAX_COORD)
        , curveLengthGen(2, 20)
        , labelLengthGen(1, 20)
        , labelLetterGen('a', 'z')
    {}

    void doRandom() {
        int operation = randint(1, 4);
        if (operation == 1) {
            removeFigure();
        } else {
            addFigure();
        }
    }

    void addFigure() {
        int type = randint(0, 4);
        Point a = genPoint();
        Point b = genPoint();

        PFigure figure;
        switch (type) {
        case 0: {
            auto segment = make_shared<Segment>(a, b);
            segment->setArrowedA(randint(0, 1));
            segment->setArrowedB(randint(0, 1));
            figure = segment;
        }   break;
        case 1:
            figure = make_shared<Ellipse>(BoundingBox({ a, b }));
            break;
        case 2:
            figure = make_shared<Rectangle>(BoundingBox({ a, b }));
            break;
        case 3: {
            int len = curveLengthGen(generator);
            std::vector<Point> points;
            for (int i = 0; i < len; i++) {
                points.push_back(genPoint());
            }
            figure = make_shared<Curve>(points);
        }   break;
        case 4: {
            auto figA = getRandomBoundedFigure();
            auto figB = getRandomBoundedFigure();
            if (!figA || !figB) {
                return;
            }
            auto segment = make_shared<SegmentConnection>(figA, figB);
            segment->setArrowedA(randint(0, 1));
            segment->setArrowedB(randint(0, 1));
            figure = segment;
        }
        }
        if (randint(0, 1) == 0) {
            figure->setLabel(genLabel());
        }
        model.addFigure(figure);
    }

    void removeFigure() {
        if (model.size() == 0) {
            return;
        }
        int id = randint(0, model.size() - 1);
        for (auto it = model.begin(); it != model.end(); it++, id--) {
            if (id == 0) {
                model.removeFigure(it);
                return;
            }
        }
    }

private:
    Model &model;
    std::default_random_engine generator;

    PBoundedFigure getRandomBoundedFigure() {
        size_t count = 0;
        for (auto fig : model) {
            auto result = dynamic_pointer_cast<BoundedFigure>(fig);
            if (result) { count++; }
        }
        if (!count) { return nullptr; }
        int id = randint(0, count - 1);
        for (auto fig : model) {
            auto result = dynamic_pointer_cast<BoundedFigure>(fig);
            if (result) {
                if (id == 0) {
                    return result;
                } else {
                    id--;
                }
            }
        }
        abort();
    }

    static const int MIN_COORD = -1e5;
    static const int MAX_COORD =  1e5;
    std::uniform_real_distribution<> coordGen;
    std::uniform_int_distribution<> curveLengthGen;
    std::uniform_int_distribution<> labelLengthGen, labelLetterGen;

    int randint(int l, int r) {
        return std::uniform_int_distribution<>(l, r)(generator);
    }

    Point genPoint() {
        double x = round(coordGen(generator) * 10) / 10;
        double y = round(coordGen(generator) * 10) / 10;
        return Point(x, y);
    }
    std::string genLabel() {
        int len = labelLengthGen(generator);
        std::string result = "";
        for (int i = 0; i < len; i++) {
            result += labelLetterGen(generator);
        }
        return result;
    }
};

class FiguresComparator : public FigureVisitor {
public:
    FiguresComparator(const Figure &other, const std::map<PFigure, PFigure> &othersMapping) : other(other), othersMapping(othersMapping), _result(false) {}
    bool result() const { return _result; }

    virtual void accept(Segment &segm1) override {
        _result = false;
        auto &segm2 = dynamic_cast<const Segment&>(other);
        if (segm1.label() != segm2.label()) { return; }
        if (segm1.getArrowedA() != segm2.getArrowedA()) { return; }
        if (segm1.getArrowedB() != segm2.getArrowedB()) { return; }
        _result =
                segm1.getA() == segm2.getA() &&
                segm1.getB() == segm2.getB();
    }

    virtual void accept(SegmentConnection &segm1) override {
        _result = false;
        auto &segm2 = dynamic_cast<const SegmentConnection&>(other);
        if (segm1.label() != segm2.label()) { return; }
        if (segm1.getArrowedA() != segm2.getArrowedA()) { return; }
        if (segm1.getArrowedB() != segm2.getArrowedB()) { return; }
        _result =
                segm1.getFigureA() == othersMapping.at(segm2.getFigureA()) &&
                segm1.getFigureB() == othersMapping.at(segm2.getFigureB());
    }

    virtual void accept(Curve &curve1) override {
        _result = false;
        auto &curve2 = dynamic_cast<const Curve&>(other);
        if (curve1.label() != curve2.label()) { return; }
        _result = curve1.points == curve2.points;
    }

    virtual void accept(figures::Ellipse &fig1) override {
        _result = false;
        auto &fig2 = dynamic_cast<const Ellipse&>(other);
        if (fig1.label() != fig2.label()) { return; }
        _result = fig1.getBoundingBox() == fig2.getBoundingBox();
    }

    virtual void accept(figures::Rectangle &fig1) override {
        _result = false;
        auto &fig2 = dynamic_cast<const Rectangle&>(other);
        if (fig1.label() != fig2.label()) { return; }
        _result = fig1.getBoundingBox() == fig2.getBoundingBox();
    }

private:
    const Figure &other;
    const std::map<PFigure, PFigure> &othersMapping;
    bool _result;
};

bool modelsAreEqual(const Model &a, const Model &b) {
    if (a.size() != b.size()) {
        return false;
    }

    std::map<PFigure, PFigure> others;

    auto ita = a.begin(), itb = b.begin();
    for (; ita != a.end() && itb != b.end(); ita++, itb++) {
        // one dereference from iterator, second dereference from shared_ptr
        Figure &a = **ita;
        Figure &b = **itb;
        if (typeid(a) != typeid(b)) {
            return false;
        }
        FiguresComparator cmp(b, others);
        a.visit(cmp);
        if (!cmp.result()) {
            return false;
        }
        assert(!others.count(*itb));
        others[*itb] = *ita;
    }
    assert(ita == a.end() && itb == b.end());
    return true;
}

class Tests : public QObject {
    Q_OBJECT
private slots:
    void testDistanceToSegmentBorder() {
        const double EPS = 1e-8;
        Segment s(Point(11, 1), Point(14, 4));
        QVERIFY(fabs(s.getApproximateDistanceToBorder(Point(11, 1)) - 0) < EPS);
        QVERIFY(fabs(s.getApproximateDistanceToBorder(Point(11, 0)) - 1) < EPS);
        QVERIFY(fabs(s.getApproximateDistanceToBorder(Point(10, 0)) - sqrt(2)) < EPS);
        QVERIFY(fabs(s.getApproximateDistanceToBorder(Point(14, 4)) - 0) < EPS);
        QVERIFY(fabs(s.getApproximateDistanceToBorder(Point(15, 4)) - 1) < EPS);
        QVERIFY(fabs(s.getApproximateDistanceToBorder(Point(15, 5)) - sqrt(2)) < EPS);
        QVERIFY(fabs(s.getApproximateDistanceToBorder(Point(12, 2)) - 0) < EPS);
        QVERIFY(fabs(s.getApproximateDistanceToBorder(Point(14, 2)) - sqrt(2)) < EPS);
    }
    void testInsideSegment() {
        Segment s(Point(11, 4), Point(14, 1));
        QVERIFY( s.isInsideOrOnBorder(Point(11, 4)));
        QVERIFY(!s.isInsideOrOnBorder(Point(11, 4.001)));
        QVERIFY(!s.isInsideOrOnBorder(Point(10.999, 4)));
        QVERIFY( s.isInsideOrOnBorder(Point(14, 1)));
        QVERIFY(!s.isInsideOrOnBorder(Point(13.999, 1)));
        QVERIFY(!s.isInsideOrOnBorder(Point(14, 0.999)));
        QVERIFY(!s.isInsideOrOnBorder(Point(13.999, 0.999)));
        QVERIFY( s.isInsideOrOnBorder(Point(12, 3)));
        QVERIFY( s.isInsideOrOnBorder(Point(13, 2)));
    }
    void testDistanceToRectangleBorder() {
        const double EPS = 1e-8;
        Rectangle r({ Point(11, 1), Point(14, 4) });
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(11, 1)) - 0) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(11, 2)) - 0) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(11, 4)) - 0) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(13, 4)) - 0) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(15, 4)) - 1) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(15, 2)) - 1) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(12, 0)) - 1) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(12, 2)) - 1) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(12.5, 2)) - 1) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(13.5, 2)) - 0.5) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(12.5, 3)) - 1) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(10, 3)) - 1) < EPS);

        // Test distance to corners
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(15, 5)) - sqrt(2)) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(16, 5)) - sqrt(5)) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(10, -1)) - sqrt(5)) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(10, 6)) - sqrt(5)) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(16, 5)) - sqrt(5)) < EPS);
        QVERIFY(fabs(r.getApproximateDistanceToBorder(Point(16, 0)) - sqrt(5)) < EPS);
    }
    void testInsideEllipse() {
        Ellipse e({ Point(11, 1), Point(17, 5) });
        QVERIFY(!e.isInsideOrOnBorder(Point(11, 1)));
        QVERIFY(!e.isInsideOrOnBorder(Point(11.5, 1.5)));
        QVERIFY(!e.isInsideOrOnBorder(Point(17, 5)));
        QVERIFY(!e.isInsideOrOnBorder(Point(11, 5)));
        QVERIFY(e.isInsideOrOnBorder(Point(14, 5)));
        QVERIFY(e.isInsideOrOnBorder(Point(14, 1)));
        QVERIFY(e.isInsideOrOnBorder(Point(14, 3)));
        QVERIFY(e.isInsideOrOnBorder(Point(15, 3.2)));
        QVERIFY( e.isInsideOrOnBorder(Point(16.1, 4.4)));
        QVERIFY(!e.isInsideOrOnBorder(Point(16.2, 4.4)));
        QVERIFY(!e.isInsideOrOnBorder(Point(16.1, 4.5)));
    }
    void testDistanceToEllipseBorder() {
        const double EPS = 1e-8;
        Ellipse e({ Point(11, 1), Point(17, 5) });
        QVERIFY(e.getApproximateDistanceToBorder(Point(11, 1)) <= sqrt(9 + 4) + EPS);
        QVERIFY(e.getApproximateDistanceToBorder(Point(11, 3)) <= EPS);
        QVERIFY(e.getApproximateDistanceToBorder(Point(17, 3)) <= EPS);
        QVERIFY(e.getApproximateDistanceToBorder(Point(14, 1)) <= EPS);
        QVERIFY(e.getApproximateDistanceToBorder(Point(14, 5)) <= EPS);
        QVERIFY(e.getApproximateDistanceToBorder(Point(10, 3)) >= 1 - EPS);
        QVERIFY(e.getApproximateDistanceToBorder(Point(14, 0)) >= 1 - EPS);
        QVERIFY(fabs(e.getApproximateDistanceToBorder(Point(14, 3)) - 2) < EPS);

        Ellipse e2({ Point(11, 1), Point(15, 7) });
        QVERIFY(fabs(e2.getApproximateDistanceToBorder(Point(13, 4)) - 2) < EPS);
    }

    void testSimpleSaveLoad() {
        int testId = 1;
        for (;; testId++) {
            char resourceName[64];
            snprintf(resourceName, sizeof resourceName, ":/tests/%02d.model", testId);
            QFile file(resourceName);
            if (!file.open(QFile::ReadOnly | QFile::Text)) {
                break;
            }
            qDebug() << "Trying" << resourceName;

            QByteArray inData = file.readAll();
            std::stringstream inDataStream;
            inDataStream << inData.toStdString();

            Model model;
            try {
                inDataStream >> model;
            } catch (model_format_error &e) {
                qDebug() << e.what();
                throw;
            }

            std::stringstream outDataStream;
            outDataStream << model;
            std::string outStr = outDataStream.str();
            QByteArray outData(outStr.data(), outStr.length());
            QCOMPARE(outData, inData);
        }
        QVERIFY(testId > 1);
    }

    void testStressSaveLoad() {
        const int PASSES = 10;
        for (int pass = 0; pass < PASSES; pass++) {
            qDebug("pass %d/%d", pass + 1, PASSES);
            Model model;
            ModelModifier modifier(model, pass);
            for (int iteration = 0; iteration < 100; iteration++) {
                std::stringstream data;
                data << model;

                std::string saved1 = data.str();

                Model restored;
                data >> restored;

                std::stringstream data2;
                data2 << restored;

                Model restored2;
                data2 >> restored2;

                std::string saved2 = data.str();
                QCOMPARE(saved1, saved2);
                QVERIFY(modelsAreEqual(model, restored2));
                modifier.doRandom();
            }
        }
    }
};

QTEST_MAIN(Tests)
#include "tests.moc"
<|endoftext|>


<commit_before>#include "PiecewisePolynomial.h"
#include <stdexcept>
#include <cassert>
#include <algorithm>
#include <complex>

using namespace std;
using namespace Eigen;

template <typename CoefficientType>
PiecewisePolynomial<CoefficientType>::PiecewisePolynomial(std::vector<PolynomialMatrix> const& polynomials, std::vector<double> const& segment_times) :
    PiecewisePolynomialBase(segment_times),
    polynomials(polynomials)
{
  assert(segment_times.size() == (polynomials.size() + 1));
  for (int i = 1; i < getNumberOfSegments(); i++) {
    if (polynomials[i].rows() != polynomials[0].rows())
      throw std::runtime_error("The polynomial matrix for each segment must have the same number of rows.");
    if (polynomials[i].cols() != polynomials[0].cols())
      throw std::runtime_error("The polynomial matrix for each segment must have the same number of columns.");
  }
}

template <typename CoefficientType>
PiecewisePolynomial<CoefficientType>::PiecewisePolynomial(std::vector<PolynomialType> const& polynomials, std::vector<double> const& segment_times) :
    PiecewisePolynomialBase(segment_times)
{
  assert(segment_times.size() == (polynomials.size() + 1));

  for (int i = 0; i < polynomials.size(); i++) {
    PolynomialMatrix matrix(1, 1);
    matrix(0, 0) = polynomials[i];
    this->polynomials.push_back(matrix);
  }
}

template <typename CoefficientType>
PiecewisePolynomial<CoefficientType>::PiecewisePolynomial() {
  // empty
}

template <typename CoefficientType>
PiecewisePolynomial<CoefficientType> PiecewisePolynomial<CoefficientType>::derivative(int derivative_order) const {
  PiecewisePolynomial ret = *this;
  for (auto it = ret.polynomials.begin(); it != ret.polynomials.end(); ++it) {
    PolynomialMatrix& matrix = *it;
    for (DenseIndex row = 0; row < rows(); row++) {
      for (DenseIndex col = 0; col < cols(); col++) {
        matrix(row, col) = matrix(row, col).derivative(derivative_order);
      }
    }
  }
  return ret;
}

template <typename CoefficientType>
PiecewisePolynomial<CoefficientType> PiecewisePolynomial<CoefficientType>::integral(double value_at_start_time) const {
  CoefficientMatrix matrix_value_at_start_time = CoefficientMatrix::Constant(rows(), cols(), value_at_start_time);
  return integral(matrix_value_at_start_time);
}

template <typename CoefficientType>
PiecewisePolynomial<CoefficientType> PiecewisePolynomial<CoefficientType>::integral(const Eigen::Ref<PiecewisePolynomial<CoefficientType>::CoefficientMatrix> & value_at_start_time) const {
  PiecewisePolynomial ret = *this;
  for (int segment_index = 0; segment_index < getNumberOfSegments(); segment_index++) {
    PolynomialMatrix& matrix = ret.polynomials[segment_index];
    for (DenseIndex row = 0; row < rows(); row++) {
      for (DenseIndex col = 0; col < cols(); col++) {
        if (segment_index == 0) {
          matrix(row, col) = matrix(row, col).integral(value_at_start_time(row, col));
        }
        else {
          matrix(row, col) = matrix(row, col).integral(ret.segmentValueAtGlobalAbscissa(segment_index - 1, getStartTime(segment_index), row, col));
        }
      }
    }
  }
  return ret;
}

template <typename CoefficientType>
double PiecewisePolynomial<CoefficientType>::scalarValue(double t, Eigen::DenseIndex row, Eigen::DenseIndex col) {
  int segment_index = getSegmentIndex(t);
  return segmentValueAtGlobalAbscissa(segment_index, t, row, col);
}

template <typename CoefficientType>
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> PiecewisePolynomial<CoefficientType>::value(double t) {
  int segment_index = getSegmentIndex(t);
  Eigen::Matrix<double, PolynomialMatrix::RowsAtCompileTime, PolynomialMatrix::ColsAtCompileTime> ret(rows(), cols());
  for (DenseIndex row = 0; row < rows(); row++) {
    for (DenseIndex col = 0; col < cols(); col++) {
      ret(row, col) = segmentValueAtGlobalAbscissa(segment_index, t, row, col);
    }
  }
  return ret;
}

template <typename CoefficientType>
const Polynomial<CoefficientType>& PiecewisePolynomial<CoefficientType>::getPolynomial(int segment_index, Eigen::DenseIndex row, Eigen::DenseIndex col) const {
  segmentNumberRangeCheck(segment_index);
  return polynomials[segment_index](row, col);
}

template <typename CoefficientType>
int PiecewisePolynomial<CoefficientType>::getSegmentPolynomialDegree(int segment_index, Eigen::DenseIndex row, Eigen::DenseIndex col) const {
  segmentNumberRangeCheck(segment_index);
  return polynomials[segment_index](row, col).getDegree();
}

template <typename CoefficientType>
PiecewisePolynomial<CoefficientType>& PiecewisePolynomial<CoefficientType>::operator+=(const PiecewisePolynomial<CoefficientType>& other) {
  if (!segmentTimesEqual(other, 1e-10))
    throw runtime_error("Addition not yet implemented when segment times are not equal");
  for (int i = 0; i < polynomials.size(); i++)
    polynomials[i] += other.polynomials[i];
  return *this;
}

template <typename CoefficientType>
PiecewisePolynomial<CoefficientType>& PiecewisePolynomial<CoefficientType>::operator*=(const PiecewisePolynomial<CoefficientType>& other) {
  if (!segmentTimesEqual(other, 1e-10))
    throw runtime_error("Multiplication not yet implemented when segment times are not equal");
  for (int i = 0; i < polynomials.size(); i++)
    polynomials[i] *= other.polynomials[i];
  return *this;
}

template <typename CoefficientType>
const PiecewisePolynomial<CoefficientType> PiecewisePolynomial<CoefficientType>::operator+(const PiecewisePolynomial<CoefficientType> &other) const {
  PiecewisePolynomial<CoefficientType> ret = *this;
  ret += other;
  return ret;
}

template <typename CoefficientType>
const PiecewisePolynomial<CoefficientType> PiecewisePolynomial<CoefficientType>::operator*(const PiecewisePolynomial<CoefficientType> &other) const {
  PiecewisePolynomial<CoefficientType> ret = *this;
  ret *= other;
  return ret;
}

template <typename CoefficientType>
bool PiecewisePolynomial<CoefficientType>::isApprox(const PiecewisePolynomial<CoefficientType>& other, double tol) const {
  if (rows() != other.rows() || cols() != other.cols())
    return false;

  if (!segmentTimesEqual(other, tol))
    return false;

  for (int segment_index = 0; segment_index < getNumberOfSegments(); segment_index++) {
    const PolynomialMatrix& matrix = polynomials[segment_index];
    const PolynomialMatrix& other_matrix = other.polynomials[segment_index];
    for (DenseIndex row = 0; row < rows(); row++) {
      for (DenseIndex col = 0; col < cols(); col++) {
      if (!matrix(row, col).isApprox(other_matrix(row, col), tol))
        return false;
      }
    }
  }
  return true;
}

template<typename CoefficientType>
void PiecewisePolynomial<CoefficientType>::shiftRight(double offset) {
  for (auto it = segment_times.begin(); it != segment_times.end(); ++it) {
    *it += offset;
  }
}

template <typename CoefficientType>
double PiecewisePolynomial<CoefficientType>::segmentValueAtGlobalAbscissa(int segment_index, double t, Eigen::DenseIndex row, Eigen::DenseIndex col) const {
  return polynomials[segment_index](row, col).value(t - getStartTime(segment_index));
}

template <typename CoefficientType>
Eigen::DenseIndex PiecewisePolynomial<CoefficientType>::rows() const
{
  if (polynomials.size() > 0)
    return polynomials[0].rows();
  else
    throw std::runtime_error("PiecewisePolynomial has no segments. Number of rows is undefined.");
}

template <typename CoefficientType>
Eigen::DenseIndex PiecewisePolynomial<CoefficientType>::cols() const
{
    if (polynomials.size() > 0)
    return polynomials[0].cols();
  else
    throw std::runtime_error("PiecewisePolynomial has no segments. Number of columns is undefined.");
}

template class DLLEXPORT PiecewisePolynomial<double>;
//template class DLLEXPORT PiecewisePolynomial<std::complex<double>>; // doesn't work yet
<commit_msg>Bug fix: add implementation for getPolynomialMatrix.<commit_after>#include "PiecewisePolynomial.h"
#include <stdexcept>
#include <cassert>
#include <algorithm>
#include <complex>

using namespace std;
using namespace Eigen;

template <typename CoefficientType>
PiecewisePolynomial<CoefficientType>::PiecewisePolynomial(std::vector<PolynomialMatrix> const& polynomials, std::vector<double> const& segment_times) :
    PiecewisePolynomialBase(segment_times),
    polynomials(polynomials)
{
  assert(segment_times.size() == (polynomials.size() + 1));
  for (int i = 1; i < getNumberOfSegments(); i++) {
    if (polynomials[i].rows() != polynomials[0].rows())
      throw std::runtime_error("The polynomial matrix for each segment must have the same number of rows.");
    if (polynomials[i].cols() != polynomials[0].cols())
      throw std::runtime_error("The polynomial matrix for each segment must have the same number of columns.");
  }
}

template <typename CoefficientType>
PiecewisePolynomial<CoefficientType>::PiecewisePolynomial(std::vector<PolynomialType> const& polynomials, std::vector<double> const& segment_times) :
    PiecewisePolynomialBase(segment_times)
{
  assert(segment_times.size() == (polynomials.size() + 1));

  for (int i = 0; i < polynomials.size(); i++) {
    PolynomialMatrix matrix(1, 1);
    matrix(0, 0) = polynomials[i];
    this->polynomials.push_back(matrix);
  }
}

template <typename CoefficientType>
PiecewisePolynomial<CoefficientType>::PiecewisePolynomial() {
  // empty
}

template <typename CoefficientType>
PiecewisePolynomial<CoefficientType> PiecewisePolynomial<CoefficientType>::derivative(int derivative_order) const {
  PiecewisePolynomial ret = *this;
  for (auto it = ret.polynomials.begin(); it != ret.polynomials.end(); ++it) {
    PolynomialMatrix& matrix = *it;
    for (DenseIndex row = 0; row < rows(); row++) {
      for (DenseIndex col = 0; col < cols(); col++) {
        matrix(row, col) = matrix(row, col).derivative(derivative_order);
      }
    }
  }
  return ret;
}

template <typename CoefficientType>
PiecewisePolynomial<CoefficientType> PiecewisePolynomial<CoefficientType>::integral(double value_at_start_time) const {
  CoefficientMatrix matrix_value_at_start_time = CoefficientMatrix::Constant(rows(), cols(), value_at_start_time);
  return integral(matrix_value_at_start_time);
}

template <typename CoefficientType>
PiecewisePolynomial<CoefficientType> PiecewisePolynomial<CoefficientType>::integral(const Eigen::Ref<PiecewisePolynomial<CoefficientType>::CoefficientMatrix> & value_at_start_time) const {
  PiecewisePolynomial ret = *this;
  for (int segment_index = 0; segment_index < getNumberOfSegments(); segment_index++) {
    PolynomialMatrix& matrix = ret.polynomials[segment_index];
    for (DenseIndex row = 0; row < rows(); row++) {
      for (DenseIndex col = 0; col < cols(); col++) {
        if (segment_index == 0) {
          matrix(row, col) = matrix(row, col).integral(value_at_start_time(row, col));
        }
        else {
          matrix(row, col) = matrix(row, col).integral(ret.segmentValueAtGlobalAbscissa(segment_index - 1, getStartTime(segment_index), row, col));
        }
      }
    }
  }
  return ret;
}

template <typename CoefficientType>
double PiecewisePolynomial<CoefficientType>::scalarValue(double t, Eigen::DenseIndex row, Eigen::DenseIndex col) {
  int segment_index = getSegmentIndex(t);
  return segmentValueAtGlobalAbscissa(segment_index, t, row, col);
}

template <typename CoefficientType>
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> PiecewisePolynomial<CoefficientType>::value(double t) {
  int segment_index = getSegmentIndex(t);
  Eigen::Matrix<double, PolynomialMatrix::RowsAtCompileTime, PolynomialMatrix::ColsAtCompileTime> ret(rows(), cols());
  for (DenseIndex row = 0; row < rows(); row++) {
    for (DenseIndex col = 0; col < cols(); col++) {
      ret(row, col) = segmentValueAtGlobalAbscissa(segment_index, t, row, col);
    }
  }
  return ret;
}

template <typename CoefficientType>
const typename PiecewisePolynomial<CoefficientType>::PolynomialMatrix& PiecewisePolynomial<CoefficientType>::getPolynomialMatrix(int segment_index) const {
  return polynomials[segment_index];
}

template <typename CoefficientType>
const Polynomial<CoefficientType>& PiecewisePolynomial<CoefficientType>::getPolynomial(int segment_index, Eigen::DenseIndex row, Eigen::DenseIndex col) const {
  segmentNumberRangeCheck(segment_index);
  return polynomials[segment_index](row, col);
}

template <typename CoefficientType>
int PiecewisePolynomial<CoefficientType>::getSegmentPolynomialDegree(int segment_index, Eigen::DenseIndex row, Eigen::DenseIndex col) const {
  segmentNumberRangeCheck(segment_index);
  return polynomials[segment_index](row, col).getDegree();
}

template <typename CoefficientType>
PiecewisePolynomial<CoefficientType>& PiecewisePolynomial<CoefficientType>::operator+=(const PiecewisePolynomial<CoefficientType>& other) {
  if (!segmentTimesEqual(other, 1e-10))
    throw runtime_error("Addition not yet implemented when segment times are not equal");
  for (int i = 0; i < polynomials.size(); i++)
    polynomials[i] += other.polynomials[i];
  return *this;
}

template <typename CoefficientType>
PiecewisePolynomial<CoefficientType>& PiecewisePolynomial<CoefficientType>::operator*=(const PiecewisePolynomial<CoefficientType>& other) {
  if (!segmentTimesEqual(other, 1e-10))
    throw runtime_error("Multiplication not yet implemented when segment times are not equal");
  for (int i = 0; i < polynomials.size(); i++)
    polynomials[i] *= other.polynomials[i];
  return *this;
}

template <typename CoefficientType>
const PiecewisePolynomial<CoefficientType> PiecewisePolynomial<CoefficientType>::operator+(const PiecewisePolynomial<CoefficientType> &other) const {
  PiecewisePolynomial<CoefficientType> ret = *this;
  ret += other;
  return ret;
}

template <typename CoefficientType>
const PiecewisePolynomial<CoefficientType> PiecewisePolynomial<CoefficientType>::operator*(const PiecewisePolynomial<CoefficientType> &other) const {
  PiecewisePolynomial<CoefficientType> ret = *this;
  ret *= other;
  return ret;
}

template <typename CoefficientType>
bool PiecewisePolynomial<CoefficientType>::isApprox(const PiecewisePolynomial<CoefficientType>& other, double tol) const {
  if (rows() != other.rows() || cols() != other.cols())
    return false;

  if (!segmentTimesEqual(other, tol))
    return false;

  for (int segment_index = 0; segment_index < getNumberOfSegments(); segment_index++) {
    const PolynomialMatrix& matrix = polynomials[segment_index];
    const PolynomialMatrix& other_matrix = other.polynomials[segment_index];
    for (DenseIndex row = 0; row < rows(); row++) {
      for (DenseIndex col = 0; col < cols(); col++) {
      if (!matrix(row, col).isApprox(other_matrix(row, col), tol))
        return false;
      }
    }
  }
  return true;
}

template<typename CoefficientType>
void PiecewisePolynomial<CoefficientType>::shiftRight(double offset) {
  for (auto it = segment_times.begin(); it != segment_times.end(); ++it) {
    *it += offset;
  }
}

template <typename CoefficientType>
double PiecewisePolynomial<CoefficientType>::segmentValueAtGlobalAbscissa(int segment_index, double t, Eigen::DenseIndex row, Eigen::DenseIndex col) const {
  return polynomials[segment_index](row, col).value(t - getStartTime(segment_index));
}

template <typename CoefficientType>
Eigen::DenseIndex PiecewisePolynomial<CoefficientType>::rows() const
{
  if (polynomials.size() > 0)
    return polynomials[0].rows();
  else
    throw std::runtime_error("PiecewisePolynomial has no segments. Number of rows is undefined.");
}

template <typename CoefficientType>
Eigen::DenseIndex PiecewisePolynomial<CoefficientType>::cols() const
{
    if (polynomials.size() > 0)
    return polynomials[0].cols();
  else
    throw std::runtime_error("PiecewisePolynomial has no segments. Number of columns is undefined.");
}

template class DLLEXPORT PiecewisePolynomial<double>;
//template class DLLEXPORT PiecewisePolynomial<std::complex<double>>; // doesn't work yet
<|endoftext|>


<commit_before>/**
 * @file
 * @author  Mohammad S. Babaei <info@babaei.net>
 * @version 0.1.0
 *
 * @section LICENSE
 *
 * (The MIT License)
 *
 * Copyright (c) 2016 Mohammad S. Babaei
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @section DESCRIPTION
 *
 * Manage website pages.
 */

#include <ctime>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <pqxx/pqxx>
#include <Wt/WApplication>
#include <Wt/WPushButton>
#include <Wt/WString>
#include <Wt/WTable>
#include <Wt/WTemplate>
#include <Wt/WText>
#include <Wt/WWidget>
#include <CoreLib/CDate.hpp>
#include <CoreLib/Crypto.hpp>
#include <CoreLib/Database.hpp>
#include <CoreLib/FileSystem.hpp>
#include <CoreLib/Log.hpp>
#include "CgiEnv.hpp"
#include "CgiRoot.hpp"
#include "CmsSubscribers.hpp"
#include "Div.hpp"
#include "Pool.hpp"

using namespace std;
using namespace boost;
using namespace pqxx;
using namespace Wt;
using namespace CoreLib;
using namespace Service;

struct CmsSubscribers::Impl : public Wt::WObject
{
public:
    enum class Table : unsigned char {
        All,
        EnFa,
        En,
        Fa,
        Inactive
    };

public:
    WContainerWidget *SubscribersTableContainer;

public:
    Impl();
    ~Impl();

public:
    void OnAllButtonPressed();
    void OnEnFaButtonPressed();
    void OnEnButtonPressed();
    void OnFaButtonPressed();
    void OnInactiveButtonPressed();

private:
    void GetDate(const std::string &timeSinceEpoch, Wt::WString &out_date);
    void GetSubscriptionTypeName(const std::string &type, Wt::WString &out_name);

    void FillDataTable(const CmsSubscribers::Impl::Table &table);
};

CmsSubscribers::CmsSubscribers()
    : Page(),
    m_pimpl(make_unique<CmsSubscribers::Impl>())
{
    this->clear();
    this->setId("CmsSubscribersPage");
    this->addWidget(this->Layout());
}

CmsSubscribers::~CmsSubscribers() = default;

WWidget *CmsSubscribers::Layout()
{
    Div *container = new Div("CmsSubscribers", "container-fluid");

    try {
        CgiRoot *cgiRoot = static_cast<CgiRoot *>(WApplication::instance());
        CgiEnv *cgiEnv = cgiRoot->GetCgiEnvInstance();

        string htmlData;
        string file;
        if (cgiEnv->GetInformation().Client.Language.Code
                == CgiEnv::InformationRecord::ClientRecord::LanguageCode::Fa) {
            file = "../templates/cms-subscribers-fa.wtml";
        } else {
            file = "../templates/cms-subscribers.wtml";
        }

        if (CoreLib::FileSystem::Read(file, htmlData)) {
            /// Fill the template
            WTemplate *tmpl = new WTemplate(container);
            tmpl->setTemplateText(WString::fromUTF8(htmlData), TextFormat::XHTMLUnsafeText);

            WPushButton *allSubscribersPushButton = new WPushButton(tr("cms-subscribers-all"));
            allSubscribersPushButton->setStyleClass("btn btn-default");

            WPushButton *englishFarsiSubscribersPushButton = new WPushButton(tr("cms-subscribers-english-farsi"));
            englishFarsiSubscribersPushButton->setStyleClass("btn btn-default");

            WPushButton *englishSubscribersPushButton = new WPushButton(tr("cms-subscribers-english"));
            englishSubscribersPushButton->setStyleClass("btn btn-default");

            WPushButton *farsiSubscribersPushButton = new WPushButton(tr("cms-subscribers-farsi"));
            farsiSubscribersPushButton->setStyleClass("btn btn-default");

            WPushButton *inactiveSubscribersPushButton = new WPushButton(tr("cms-subscribers-inactive"));
            inactiveSubscribersPushButton->setStyleClass("btn btn-default");

            m_pimpl->SubscribersTableContainer = new Div("SubscribersTableContainer", "subscribers-table-container");

            tmpl->bindWidget("subscribers-title", new WText(tr("cms-subscribers-page-title")));

            tmpl->bindWidget("subscribers-table", m_pimpl->SubscribersTableContainer);

            tmpl->bindWidget("all-subscribers-button", allSubscribersPushButton);
            tmpl->bindWidget("english-farsi-subscribers-button", englishFarsiSubscribersPushButton);
            tmpl->bindWidget("english-subscribers-button", englishSubscribersPushButton);
            tmpl->bindWidget("farsi-subscribers-button", farsiSubscribersPushButton);
            tmpl->bindWidget("inactive-subscribers-button", inactiveSubscribersPushButton);

            allSubscribersPushButton->clicked().connect(m_pimpl.get(), &CmsSubscribers::Impl::OnAllButtonPressed);
            englishFarsiSubscribersPushButton->clicked().connect(m_pimpl.get(), &CmsSubscribers::Impl::OnEnFaButtonPressed);
            englishSubscribersPushButton->clicked().connect(m_pimpl.get(), &CmsSubscribers::Impl::OnEnButtonPressed);
            farsiSubscribersPushButton->clicked().connect(m_pimpl.get(), &CmsSubscribers::Impl::OnFaButtonPressed);
            inactiveSubscribersPushButton->clicked().connect(m_pimpl.get(), &CmsSubscribers::Impl::OnInactiveButtonPressed);

            allSubscribersPushButton->setFocus();
        }
    }

    catch (const boost::exception &ex) {
        LOG_ERROR(boost::diagnostic_information(ex));
    }

    catch (const std::exception &ex) {
        LOG_ERROR(ex.what());
    }

    catch (...) {
        LOG_ERROR(UNKNOWN_ERROR);
    }

    return container;
}

CmsSubscribers::Impl::Impl()
{

}

CmsSubscribers::Impl::~Impl() = default;

void CmsSubscribers::Impl::OnAllButtonPressed()
{
    FillDataTable(Table::All);
}

void CmsSubscribers::Impl::OnEnFaButtonPressed()
{
    FillDataTable(Table::EnFa);
}

void CmsSubscribers::Impl::OnEnButtonPressed()
{
    FillDataTable(Table::En);
}

void CmsSubscribers::Impl::OnFaButtonPressed()
{
    FillDataTable(Table::Fa);
}

void CmsSubscribers::Impl::OnInactiveButtonPressed()
{
    FillDataTable(Table::Inactive);
}

void CmsSubscribers::Impl::GetDate(const std::string &timeSinceEpoch, Wt::WString &out_date)
{
    try {
        time_t tt = lexical_cast<time_t>(timeSinceEpoch);

        struct tm *utc_tm = gmtime(&tt);

        int year = utc_tm->tm_year + 1900;
        int month = utc_tm->tm_mon + 1;
        int day = utc_tm->tm_mday;

        CgiRoot *cgiRoot = static_cast<CgiRoot *>(WApplication::instance());
        CgiEnv *cgiEnv = cgiRoot->GetCgiEnvInstance();

        if (cgiEnv->GetInformation().Client.Language.Code
                == CgiEnv::InformationRecord::ClientRecord::LanguageCode::Fa) {
            out_date = (boost::wformat(L"%1%/%2%/%3%/")
                        % lexical_cast<wstring>(year)
                        % lexical_cast<wstring>(month)
                        % lexical_cast<wstring>(day)).str();
        } else {
            out_date = CDate::DateConv::FormatToPersianNums(CDate::DateConv::ToJalali(year, month, day));
        }
    } catch (...) {
        out_date = L"-";
    }
}

void CmsSubscribers::Impl::GetSubscriptionTypeName(const std::string &type, Wt::WString &out_name)
{
    static const std::string EN_FA_TYPE("en_fa");
    static const std::string EN_TYPE("en");
    static const std::string FA_TYPE("fa");
    static const std::string NONE_TYPE("none");

    static const std::string EN_FA_NAME(tr("cms-subscribers-subscription-en-fa").toUTF8());
    static const std::string EN_NAME(tr("cms-subscribers-subscription-en").toUTF8());
    static const std::string FA_NAME(tr("cms-subscribers-subscription-fa").toUTF8());
    static const std::string NONE_NAME(tr("cms-subscribers-subscription-none").toUTF8());

    if (type == EN_FA_TYPE) {
        out_name = WString::fromUTF8(EN_FA_NAME);
    } else if (type == EN_TYPE) {
        out_name = WString::fromUTF8(EN_NAME);
    } else if (type == FA_TYPE) {
        out_name = WString::fromUTF8(FA_NAME);
    } else if (type == NONE_TYPE) {
        out_name = WString::fromUTF8(NONE_NAME);
    }
}

void CmsSubscribers::Impl::FillDataTable(const CmsSubscribers::Impl::Table &tableType)
{
    CgiRoot *cgiRoot = static_cast<CgiRoot *>(WApplication::instance());
    CgiEnv *cgiEnv = cgiRoot->GetCgiEnvInstance();

    try {
        SubscribersTableContainer->clear();

        WTable *table = new WTable(SubscribersTableContainer);
        table->setStyleClass("table table-striped table-hover");
        table->setHeaderCount(1, Orientation::Horizontal);

        table->elementAt(0, 0)->addWidget(new WText(tr("cms-subscribers-no")));
        table->elementAt(0, 1)->addWidget(new WText(tr("cms-subscribers-inbox")));
        table->elementAt(0, 2)->addWidget(new WText(tr("cms-subscribers-subscription")));
        table->elementAt(0, 3)->addWidget(new WText(tr("cms-subscribers-pending-confirm")));
        table->elementAt(0, 4)->addWidget(new WText(tr("cms-subscribers-pending-cancel")));
        table->elementAt(0, 5)->addWidget(new WText(tr("cms-subscribers-join-date")));
        table->elementAt(0, 6)->addWidget(new WText(tr("cms-subscribers-update-date")));
        table->elementAt(0, 7)->addWidget(new WText(tr("cms-subscribers-uuid")));

        string query;
        switch (tableType) {
        case Table::All:
            query.assign((format("SELECT inbox, uuid, subscription, pending_confirm, pending_cancel, join_date, update_date"
                                 " FROM \"%1%\" ORDER BY inbox COLLATE \"en_US.UTF-8\" ASC;")
                          % Pool::Database().GetTableName("SUBSCRIBERS")).str());
            break;
        case Table::EnFa:
            query.assign((format("SELECT inbox, uuid, subscription, pending_confirm, pending_cancel, join_date, update_date"
                                 " FROM \"%1%\" WHERE subscription = 'en_fa' ORDER BY inbox COLLATE \"en_US.UTF-8\" ASC;")
                          % Pool::Database().GetTableName("SUBSCRIBERS")).str());
            break;
        case Table::En:
            query.assign((format("SELECT inbox, uuid, subscription, pending_confirm, pending_cancel, join_date, update_date"
                                 " FROM \"%1%\" WHERE subscription = 'en' ORDER BY inbox COLLATE \"en_US.UTF-8\" ASC;")
                          % Pool::Database().GetTableName("SUBSCRIBERS")).str());
            break;
        case Table::Fa:
            query.assign((format("SELECT inbox, uuid, subscription, pending_confirm, pending_cancel, join_date, update_date"
                                 " FROM \"%1%\" WHERE subscription = 'fa' ORDER BY inbox COLLATE \"en_US.UTF-8\" ASC;")
                          % Pool::Database().GetTableName("SUBSCRIBERS")).str());
            break;
        case Table::Inactive:
            query.assign((format("SELECT inbox, uuid, subscription, pending_confirm, pending_cancel, join_date, update_date"
                                 " FROM \"%1%\" WHERE subscription = 'none' ORDER BY inbox COLLATE \"en_US.UTF-8\" ASC;")
                          % Pool::Database().GetTableName("SUBSCRIBERS")).str());
            break;
        }

        LOG_INFO("Running query...", query, cgiEnv->GetInformation().ToJson());

        auto conn = Pool::Database().Connection();
        conn->activate();
        pqxx::work txn(*conn.get());

        result r = txn.exec(query);

        int i = 0;
        for (const auto & row : r) {
            ++i;

            const string inbox(row["inbox"].c_str());
            const string uuid(row["uuid"].c_str());
            const string subscription(row["subscription"].c_str());
            const string pendingConfirm(row["pending_confirm"].c_str());
            const string pendingCancel(row["pending_cancel"].c_str());
            const string joinDate(row["join_date"].c_str());
            const string updateDate(row["update_date"].c_str());

            WString subscriptionTypeName;
            WString pendingConfirmTypeName;
            WString pendingCancelTypeName;

            this->GetSubscriptionTypeName(subscription, subscriptionTypeName);
            this->GetSubscriptionTypeName(pendingConfirm, pendingConfirmTypeName);
            this->GetSubscriptionTypeName(pendingCancel, pendingCancelTypeName);

            WString joinDateFormatted;
            WString updateDateFormatted;

            this->GetDate(joinDate, joinDateFormatted);
            this->GetDate(updateDate, updateDateFormatted);

            table->elementAt(i, 0)->addWidget(new WText(WString::fromUTF8(lexical_cast<string>(i))));
            table->elementAt(i, 1)->addWidget(new WText(WString::fromUTF8(inbox)));
            table->elementAt(i, 2)->addWidget(new WText(subscriptionTypeName));
            table->elementAt(i, 3)->addWidget(new WText(pendingConfirmTypeName));
            table->elementAt(i, 4)->addWidget(new WText(pendingCancelTypeName));
            table->elementAt(i, 5)->addWidget(new WText(joinDateFormatted));
            table->elementAt(i, 6)->addWidget(new WText(updateDateFormatted));
            table->elementAt(i, 7)->addWidget(new WText(WString::fromUTF8(uuid)));
        }
    }

    catch (const pqxx::sql_error &ex) {
        LOG_ERROR(ex.what(), ex.query(), cgiEnv->GetInformation().ToJson());
    }

    catch (const boost::exception &ex) {
        LOG_ERROR(boost::diagnostic_information(ex), cgiEnv->GetInformation().ToJson());
    }

    catch (const std::exception &ex) {
        LOG_ERROR(ex.what(), cgiEnv->GetInformation().ToJson());
    }

    catch (...) {
        LOG_ERROR(UNKNOWN_ERROR, cgiEnv->GetInformation().ToJson());
    }
}
<commit_msg>fix the wrong date format (jalali/gregorian) on subscribers page<commit_after>/**
 * @file
 * @author  Mohammad S. Babaei <info@babaei.net>
 * @version 0.1.0
 *
 * @section LICENSE
 *
 * (The MIT License)
 *
 * Copyright (c) 2016 Mohammad S. Babaei
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @section DESCRIPTION
 *
 * Manage website pages.
 */

#include <ctime>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <pqxx/pqxx>
#include <Wt/WApplication>
#include <Wt/WPushButton>
#include <Wt/WString>
#include <Wt/WTable>
#include <Wt/WTemplate>
#include <Wt/WText>
#include <Wt/WWidget>
#include <CoreLib/CDate.hpp>
#include <CoreLib/Crypto.hpp>
#include <CoreLib/Database.hpp>
#include <CoreLib/FileSystem.hpp>
#include <CoreLib/Log.hpp>
#include "CgiEnv.hpp"
#include "CgiRoot.hpp"
#include "CmsSubscribers.hpp"
#include "Div.hpp"
#include "Pool.hpp"

using namespace std;
using namespace boost;
using namespace pqxx;
using namespace Wt;
using namespace CoreLib;
using namespace Service;

struct CmsSubscribers::Impl : public Wt::WObject
{
public:
    enum class Table : unsigned char {
        All,
        EnFa,
        En,
        Fa,
        Inactive
    };

public:
    WContainerWidget *SubscribersTableContainer;

public:
    Impl();
    ~Impl();

public:
    void OnAllButtonPressed();
    void OnEnFaButtonPressed();
    void OnEnButtonPressed();
    void OnFaButtonPressed();
    void OnInactiveButtonPressed();

private:
    void GetDate(const std::string &timeSinceEpoch, Wt::WString &out_date);
    void GetSubscriptionTypeName(const std::string &type, Wt::WString &out_name);

    void FillDataTable(const CmsSubscribers::Impl::Table &table);
};

CmsSubscribers::CmsSubscribers()
    : Page(),
    m_pimpl(make_unique<CmsSubscribers::Impl>())
{
    this->clear();
    this->setId("CmsSubscribersPage");
    this->addWidget(this->Layout());
}

CmsSubscribers::~CmsSubscribers() = default;

WWidget *CmsSubscribers::Layout()
{
    Div *container = new Div("CmsSubscribers", "container-fluid");

    try {
        CgiRoot *cgiRoot = static_cast<CgiRoot *>(WApplication::instance());
        CgiEnv *cgiEnv = cgiRoot->GetCgiEnvInstance();

        string htmlData;
        string file;
        if (cgiEnv->GetInformation().Client.Language.Code
                == CgiEnv::InformationRecord::ClientRecord::LanguageCode::Fa) {
            file = "../templates/cms-subscribers-fa.wtml";
        } else {
            file = "../templates/cms-subscribers.wtml";
        }

        if (CoreLib::FileSystem::Read(file, htmlData)) {
            /// Fill the template
            WTemplate *tmpl = new WTemplate(container);
            tmpl->setTemplateText(WString::fromUTF8(htmlData), TextFormat::XHTMLUnsafeText);

            WPushButton *allSubscribersPushButton = new WPushButton(tr("cms-subscribers-all"));
            allSubscribersPushButton->setStyleClass("btn btn-default");

            WPushButton *englishFarsiSubscribersPushButton = new WPushButton(tr("cms-subscribers-english-farsi"));
            englishFarsiSubscribersPushButton->setStyleClass("btn btn-default");

            WPushButton *englishSubscribersPushButton = new WPushButton(tr("cms-subscribers-english"));
            englishSubscribersPushButton->setStyleClass("btn btn-default");

            WPushButton *farsiSubscribersPushButton = new WPushButton(tr("cms-subscribers-farsi"));
            farsiSubscribersPushButton->setStyleClass("btn btn-default");

            WPushButton *inactiveSubscribersPushButton = new WPushButton(tr("cms-subscribers-inactive"));
            inactiveSubscribersPushButton->setStyleClass("btn btn-default");

            m_pimpl->SubscribersTableContainer = new Div("SubscribersTableContainer", "subscribers-table-container");

            tmpl->bindWidget("subscribers-title", new WText(tr("cms-subscribers-page-title")));

            tmpl->bindWidget("subscribers-table", m_pimpl->SubscribersTableContainer);

            tmpl->bindWidget("all-subscribers-button", allSubscribersPushButton);
            tmpl->bindWidget("english-farsi-subscribers-button", englishFarsiSubscribersPushButton);
            tmpl->bindWidget("english-subscribers-button", englishSubscribersPushButton);
            tmpl->bindWidget("farsi-subscribers-button", farsiSubscribersPushButton);
            tmpl->bindWidget("inactive-subscribers-button", inactiveSubscribersPushButton);

            allSubscribersPushButton->clicked().connect(m_pimpl.get(), &CmsSubscribers::Impl::OnAllButtonPressed);
            englishFarsiSubscribersPushButton->clicked().connect(m_pimpl.get(), &CmsSubscribers::Impl::OnEnFaButtonPressed);
            englishSubscribersPushButton->clicked().connect(m_pimpl.get(), &CmsSubscribers::Impl::OnEnButtonPressed);
            farsiSubscribersPushButton->clicked().connect(m_pimpl.get(), &CmsSubscribers::Impl::OnFaButtonPressed);
            inactiveSubscribersPushButton->clicked().connect(m_pimpl.get(), &CmsSubscribers::Impl::OnInactiveButtonPressed);

            allSubscribersPushButton->setFocus();
        }
    }

    catch (const boost::exception &ex) {
        LOG_ERROR(boost::diagnostic_information(ex));
    }

    catch (const std::exception &ex) {
        LOG_ERROR(ex.what());
    }

    catch (...) {
        LOG_ERROR(UNKNOWN_ERROR);
    }

    return container;
}

CmsSubscribers::Impl::Impl()
{

}

CmsSubscribers::Impl::~Impl() = default;

void CmsSubscribers::Impl::OnAllButtonPressed()
{
    FillDataTable(Table::All);
}

void CmsSubscribers::Impl::OnEnFaButtonPressed()
{
    FillDataTable(Table::EnFa);
}

void CmsSubscribers::Impl::OnEnButtonPressed()
{
    FillDataTable(Table::En);
}

void CmsSubscribers::Impl::OnFaButtonPressed()
{
    FillDataTable(Table::Fa);
}

void CmsSubscribers::Impl::OnInactiveButtonPressed()
{
    FillDataTable(Table::Inactive);
}

void CmsSubscribers::Impl::GetDate(const std::string &timeSinceEpoch, Wt::WString &out_date)
{
    try {
        time_t tt = lexical_cast<time_t>(timeSinceEpoch);

        struct tm *utc_tm = gmtime(&tt);

        int year = utc_tm->tm_year + 1900;
        int month = utc_tm->tm_mon + 1;
        int day = utc_tm->tm_mday;

        CgiRoot *cgiRoot = static_cast<CgiRoot *>(WApplication::instance());
        CgiEnv *cgiEnv = cgiRoot->GetCgiEnvInstance();

        if (cgiEnv->GetInformation().Client.Language.Code
                == CgiEnv::InformationRecord::ClientRecord::LanguageCode::En) {
            out_date = (boost::wformat(L"%1%/%2%/%3%")
                        % lexical_cast<wstring>(year)
                        % lexical_cast<wstring>(month)
                        % lexical_cast<wstring>(day)).str();
        } else {
            out_date = CDate::DateConv::FormatToPersianNums(CDate::DateConv::ToJalali(year, month, day));
        }
    } catch (...) {
        out_date = L"-";
    }
}

void CmsSubscribers::Impl::GetSubscriptionTypeName(const std::string &type, Wt::WString &out_name)
{
    static const std::string EN_FA_TYPE("en_fa");
    static const std::string EN_TYPE("en");
    static const std::string FA_TYPE("fa");
    static const std::string NONE_TYPE("none");

    static const std::string EN_FA_NAME(tr("cms-subscribers-subscription-en-fa").toUTF8());
    static const std::string EN_NAME(tr("cms-subscribers-subscription-en").toUTF8());
    static const std::string FA_NAME(tr("cms-subscribers-subscription-fa").toUTF8());
    static const std::string NONE_NAME(tr("cms-subscribers-subscription-none").toUTF8());

    if (type == EN_FA_TYPE) {
        out_name = WString::fromUTF8(EN_FA_NAME);
    } else if (type == EN_TYPE) {
        out_name = WString::fromUTF8(EN_NAME);
    } else if (type == FA_TYPE) {
        out_name = WString::fromUTF8(FA_NAME);
    } else if (type == NONE_TYPE) {
        out_name = WString::fromUTF8(NONE_NAME);
    }
}

void CmsSubscribers::Impl::FillDataTable(const CmsSubscribers::Impl::Table &tableType)
{
    CgiRoot *cgiRoot = static_cast<CgiRoot *>(WApplication::instance());
    CgiEnv *cgiEnv = cgiRoot->GetCgiEnvInstance();

    try {
        SubscribersTableContainer->clear();

        WTable *table = new WTable(SubscribersTableContainer);
        table->setStyleClass("table table-striped table-hover");
        table->setHeaderCount(1, Orientation::Horizontal);

        table->elementAt(0, 0)->addWidget(new WText(tr("cms-subscribers-no")));
        table->elementAt(0, 1)->addWidget(new WText(tr("cms-subscribers-inbox")));
        table->elementAt(0, 2)->addWidget(new WText(tr("cms-subscribers-subscription")));
        table->elementAt(0, 3)->addWidget(new WText(tr("cms-subscribers-pending-confirm")));
        table->elementAt(0, 4)->addWidget(new WText(tr("cms-subscribers-pending-cancel")));
        table->elementAt(0, 5)->addWidget(new WText(tr("cms-subscribers-join-date")));
        table->elementAt(0, 6)->addWidget(new WText(tr("cms-subscribers-update-date")));
        table->elementAt(0, 7)->addWidget(new WText(tr("cms-subscribers-uuid")));

        string query;
        switch (tableType) {
        case Table::All:
            query.assign((format("SELECT inbox, uuid, subscription, pending_confirm, pending_cancel, join_date, update_date"
                                 " FROM \"%1%\" ORDER BY inbox COLLATE \"en_US.UTF-8\" ASC;")
                          % Pool::Database().GetTableName("SUBSCRIBERS")).str());
            break;
        case Table::EnFa:
            query.assign((format("SELECT inbox, uuid, subscription, pending_confirm, pending_cancel, join_date, update_date"
                                 " FROM \"%1%\" WHERE subscription = 'en_fa' ORDER BY inbox COLLATE \"en_US.UTF-8\" ASC;")
                          % Pool::Database().GetTableName("SUBSCRIBERS")).str());
            break;
        case Table::En:
            query.assign((format("SELECT inbox, uuid, subscription, pending_confirm, pending_cancel, join_date, update_date"
                                 " FROM \"%1%\" WHERE subscription = 'en' ORDER BY inbox COLLATE \"en_US.UTF-8\" ASC;")
                          % Pool::Database().GetTableName("SUBSCRIBERS")).str());
            break;
        case Table::Fa:
            query.assign((format("SELECT inbox, uuid, subscription, pending_confirm, pending_cancel, join_date, update_date"
                                 " FROM \"%1%\" WHERE subscription = 'fa' ORDER BY inbox COLLATE \"en_US.UTF-8\" ASC;")
                          % Pool::Database().GetTableName("SUBSCRIBERS")).str());
            break;
        case Table::Inactive:
            query.assign((format("SELECT inbox, uuid, subscription, pending_confirm, pending_cancel, join_date, update_date"
                                 " FROM \"%1%\" WHERE subscription = 'none' ORDER BY inbox COLLATE \"en_US.UTF-8\" ASC;")
                          % Pool::Database().GetTableName("SUBSCRIBERS")).str());
            break;
        }

        LOG_INFO("Running query...", query, cgiEnv->GetInformation().ToJson());

        auto conn = Pool::Database().Connection();
        conn->activate();
        pqxx::work txn(*conn.get());

        result r = txn.exec(query);

        int i = 0;
        for (const auto & row : r) {
            ++i;

            const string inbox(row["inbox"].c_str());
            const string uuid(row["uuid"].c_str());
            const string subscription(row["subscription"].c_str());
            const string pendingConfirm(row["pending_confirm"].c_str());
            const string pendingCancel(row["pending_cancel"].c_str());
            const string joinDate(row["join_date"].c_str());
            const string updateDate(row["update_date"].c_str());

            WString subscriptionTypeName;
            WString pendingConfirmTypeName;
            WString pendingCancelTypeName;

            this->GetSubscriptionTypeName(subscription, subscriptionTypeName);
            this->GetSubscriptionTypeName(pendingConfirm, pendingConfirmTypeName);
            this->GetSubscriptionTypeName(pendingCancel, pendingCancelTypeName);

            WString joinDateFormatted;
            WString updateDateFormatted;

            this->GetDate(joinDate, joinDateFormatted);
            this->GetDate(updateDate, updateDateFormatted);

            table->elementAt(i, 0)->addWidget(new WText(WString::fromUTF8(lexical_cast<string>(i))));
            table->elementAt(i, 1)->addWidget(new WText(WString::fromUTF8(inbox)));
            table->elementAt(i, 2)->addWidget(new WText(subscriptionTypeName));
            table->elementAt(i, 3)->addWidget(new WText(pendingConfirmTypeName));
            table->elementAt(i, 4)->addWidget(new WText(pendingCancelTypeName));
            table->elementAt(i, 5)->addWidget(new WText(joinDateFormatted));
            table->elementAt(i, 6)->addWidget(new WText(updateDateFormatted));
            table->elementAt(i, 7)->addWidget(new WText(WString::fromUTF8(uuid)));
        }
    }

    catch (const pqxx::sql_error &ex) {
        LOG_ERROR(ex.what(), ex.query(), cgiEnv->GetInformation().ToJson());
    }

    catch (const boost::exception &ex) {
        LOG_ERROR(boost::diagnostic_information(ex), cgiEnv->GetInformation().ToJson());
    }

    catch (const std::exception &ex) {
        LOG_ERROR(ex.what(), cgiEnv->GetInformation().ToJson());
    }

    catch (...) {
        LOG_ERROR(UNKNOWN_ERROR, cgiEnv->GetInformation().ToJson());
    }
}
<|endoftext|>


<commit_before><commit_msg>menus are way too wide, wrong checkbox/radiobutton width<commit_after><|endoftext|>


<commit_before><commit_msg>compilation fix: disable method inside the name space<commit_after><|endoftext|>


<commit_before>/**************************************************************************
 *
 * Copyright 2011 Jose Fonseca
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

#include "glproc.hpp"

#if !defined(_WIN32)
#ifndef _GNU_SOURCE
#define _GNU_SOURCE // for dladdr
#endif
#include <dlfcn.h>
#endif

/*
 * Handle to the true OpenGL library.
 * XXX: Not really used yet.
 */
#if defined(_WIN32)
HINSTANCE __libGlHandle = NULL;
#else
void *__libGlHandle = NULL;
#endif

#if defined(_WIN32)

#error Unsupported

#elif defined(__APPLE__)

#error Unsupported

#else

/*
 * Lookup a public EGL/GL/GLES symbol
 *
 * The spec states that eglGetProcAddress should only be used for non-core
 * (extensions) entry-points.  Core entry-points should be taken directly from
 * the API specific libraries.
 *
 * We cannot tell here which API a symbol is meant for here (as some are
 * exported by many).  So this code assumes that the appropriate shared
 * libraries have been loaded previously (either dlopened with RTLD_GLOBAL, or
 * as part of the executable dependencies), and that their symbols available
 * for quering via dlsym(RTLD_NEXT, ...).
 */
void *
__getPublicProcAddress(const char *procName)
{
#if defined(ANDROID)
    /*
     * Android does not support LD_PRELOAD.  It is assumed that applications
     * are explicitely loading egltrace.so.
     */
    void *lib = NULL;
    if (procName[0] == 'e' && procName[1] == 'g' && procName[2] == 'l') {
        static void *libEGL = NULL;
        if (!libEGL) {
            libEGL = dlopen("libEGL.so", RTLD_LOCAL | RTLD_LAZY);
        }
        lib = libEGL;
    } else if (procName[0] == 'g' && procName[1] == 'l') {
        /* TODO: Support libGLESv1_CM.so too somehow. */
        static void *libGLESv2 = NULL;
        if (!libGLESv2) {
            libGLESv2 = dlopen("libGLESv2.so", RTLD_LOCAL | RTLD_LAZY);
        }
        lib = libGLESv2;
    }
    if (lib) {
        return dlsym(lib, procName);
    }
    return NULL;
#else
    return dlsym(RTLD_NEXT, procName);
#endif
}

/*
 * Lookup a private EGL/GL/GLES symbol
 *
 * Private symbols should always be available through eglGetProcAddress, and
 * they are guaranteed to work with any context bound (regardless of the API).
 *
 * However, per issue#57, eglGetProcAddress returns garbage on some
 * implementations, and the spec states that implementations may choose to also
 * export extension functions publicly, so we always attempt dlsym before
 * eglGetProcAddress to mitigate that.
 */
void *
__getPrivateProcAddress(const char *procName)
{
    void *proc;
    proc = __getPublicProcAddress(procName);
    if (!proc &&
        ((procName[0] == 'e' && procName[1] == 'g' && procName[2] == 'l') ||
         (procName[0] == 'g' && procName[1] == 'l'))) {
        proc = (void *) __eglGetProcAddress(procName);
    }

    return proc;
}

#endif
<commit_msg>gles: fix lookup for GLESv1 functions<commit_after>/**************************************************************************
 *
 * Copyright 2011 Jose Fonseca
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

#include "glproc.hpp"

#if !defined(_WIN32)
#ifndef _GNU_SOURCE
#define _GNU_SOURCE // for dladdr
#endif
#include <dlfcn.h>
#endif

/*
 * Handle to the true OpenGL library.
 * XXX: Not really used yet.
 */
#if defined(_WIN32)
HINSTANCE __libGlHandle = NULL;
#else
void *__libGlHandle = NULL;
#endif

#if defined(_WIN32)

#error Unsupported

#elif defined(__APPLE__)

#error Unsupported

#else

/*
 * Lookup a public EGL/GL/GLES symbol
 *
 * The spec states that eglGetProcAddress should only be used for non-core
 * (extensions) entry-points.  Core entry-points should be taken directly from
 * the API specific libraries.
 *
 * We cannot tell here which API a symbol is meant for here (as some are
 * exported by many).  So this code assumes that the appropriate shared
 * libraries have been loaded previously (either dlopened with RTLD_GLOBAL, or
 * as part of the executable dependencies), and that their symbols available
 * for quering via dlsym(RTLD_NEXT, ...).
 */
void *
__getPublicProcAddress(const char *procName)
{
#if defined(ANDROID)
    /*
     * Android does not support LD_PRELOAD.  It is assumed that applications
     * are explicitely loading egltrace.so.
     */

    if (procName[0] == 'e' && procName[1] == 'g' && procName[2] == 'l') {
        static void *libEGL = NULL;
        if (!libEGL) {
            libEGL = dlopen("libEGL.so", RTLD_LOCAL | RTLD_LAZY);
            if (!libEGL) {
                return NULL;
            }
        }
        return dlsym(libEGL, procName);
    }

    if (procName[0] == 'g' && procName[1] == 'l') {
        /* TODO: Use GLESv1/GLESv2 on a per-context basis. */
        static void *sym = NULL;

        static void *libGLESv2 = NULL;
        if (!libGLESv2) {
            libGLESv2 = dlopen("libGLESv2.so", RTLD_LOCAL | RTLD_LAZY);
        }
        if (libGLESv2) {
            sym = dlsym(libGLESv2, procName);
        }
        if (sym) {
            return sym;
        }

        static void *libGLESv1 = NULL;
        if (!libGLESv1) {
            libGLESv1 = dlopen("libGLESv1_CM.so", RTLD_LOCAL | RTLD_LAZY);
        }
        if (libGLESv1) {
            sym = dlsym(libGLESv1, procName);
        }
        if (sym) {
            return sym;
        }
    }

    return NULL;
#else
    return dlsym(RTLD_NEXT, procName);
#endif
}

/*
 * Lookup a private EGL/GL/GLES symbol
 *
 * Private symbols should always be available through eglGetProcAddress, and
 * they are guaranteed to work with any context bound (regardless of the API).
 *
 * However, per issue#57, eglGetProcAddress returns garbage on some
 * implementations, and the spec states that implementations may choose to also
 * export extension functions publicly, so we always attempt dlsym before
 * eglGetProcAddress to mitigate that.
 */
void *
__getPrivateProcAddress(const char *procName)
{
    void *proc;
    proc = __getPublicProcAddress(procName);
    if (!proc &&
        ((procName[0] == 'e' && procName[1] == 'g' && procName[2] == 'l') ||
         (procName[0] == 'g' && procName[1] == 'l'))) {
        proc = (void *) __eglGetProcAddress(procName);
    }

    return proc;
}

#endif
<|endoftext|>