#include "UnitTest++.h"

#include "test_utils.hh"

#include "geners/StringArchive.hh"
#include "geners/RowPacker.hh"

using namespace gs;
using namespace std;

#ifdef CPP11_STD_AVAILABLE

namespace {
    TEST(RowPacker)
    {
        StringArchive ar0("archive");

        // Test that archive works with bare tuples
        auto tuple1 = tuple<int, float, double, long long>();

        typedef RowPacker<decltype(tuple1)> Packer1;
        const unsigned bufferSize = 1024;
        Packer1 packer({"i1", "f1", "d1", "ll1"},
                       "Title", ar0, "Name", "Category", bufferSize);
        std::vector<decltype(tuple1)> t1copy;

        // We need to have enough data to fill at least a few buffers
        // in order to understand if things work correctly.
        unsigned datasize = sizeof(int) + sizeof(float) + sizeof(double) +
            sizeof(long long);
        const unsigned long rows_per_buffer = bufferSize/datasize + 1;
        const unsigned long nrows = 5*rows_per_buffer + 1;

        for (unsigned long row=0; row<nrows; ++row)
        {
            tuple1 = make_tuple(
                (int)(test_rng()*10000),
                (float)(test_rng()),
                (double)(test_rng()),
                (long long)(test_rng()*100000)
            );
            t1copy.push_back(tuple1);
            CHECK(packer.fill(tuple1));
        }

        // Now, let see if we can compare the contents to the
        // original tuple
        CHECK_EQUAL(nrows, packer.nRows());
        CHECK_EQUAL(std::tuple_size<decltype(tuple1)>::value,
                    packer.nColumns());
        for (unsigned long row=0; row<nrows; ++row)
        {
            packer.rowContents(row, &tuple1);
            CHECK(tuple1 == t1copy[row]);
        }

        // Write the packer to the archive and redo the comparison
        packer.write();
        CHECK_EQUAL(nrows, packer.nRows());
        CHECK_EQUAL(std::tuple_size<decltype(tuple1)>::value,
                    packer.nColumns());
        for (unsigned long row=0; row<nrows; ++row)
        {
            packer.rowContents(row, &tuple1);
            CHECK(tuple1 == t1copy[row]);
        }

        // Check if we can read the packer back
        std::unique_ptr<Packer1> rp = 
            RPReference<Packer1>(ar0, "Name", "Category").get(0);
        assert(rp.get());

        CHECK_EQUAL(nrows, rp->nRows());
        CHECK_EQUAL(std::tuple_size<decltype(tuple1)>::value, rp->nColumns());
        for (unsigned long row=0; row<nrows; ++row)
        {
            rp->rowContents(row, &tuple1);
            CHECK(tuple1 == t1copy[row]);
        }

        CHECK(*rp == packer);
    }
}

#else // CPP11_STD_AVAILABLE

namespace {
    TEST(RowPacker)
    {
    }
}

#endif // CPP11_STD_AVAILABLE
