#include <gtest/gtest.h>
#include <string>
#include <vector>
#include <iostream>
#include <testHelpers.hpp>
using std::string;
using std::vector;
template<typename T>
class Histogram : public ::testing::Test
{
    public:
        virtual void SetUp() {}
};
typedef ::testing::Types<float, double, int, uint, char, uchar, short, ushort, intl, uintl> TestTypes;
TYPED_TEST_CASE(Histogram, TestTypes);
template<typename inType, typename outType>
void histTest(string pTestFile, unsigned nbins, double minval, double maxval)
{
    if (noDoubleTests<inType>()) return;
    if (noDoubleTests<outType>()) return;
    vector<af::dim4> numDims;
    vector<vector<inType> >  in;
    vector<vector<outType> > tests;
    readTests<inType,uint,int>(pTestFile,numDims,in,tests);
    outType *outData;
    outData = new outType[dims.elements()];
    for (size_t testIter=0; testIter<tests.size(); ++testIter) {
        vector<outType> currGoldBar = tests[testIter];
        size_t nElems        = currGoldBar.size();
        for (size_t elIter=0; elIter<nElems; ++elIter) {
            ASSERT_EQ(currGoldBar[elIter],outData[elIter])<< "at: " << elIter<< std::endl;
        }
    }
    
    delete[] outData;
}
TYPED_TEST(Histogram,256Bins0min255max_ones)
{
    histTest<TypeParam,uint>(string(TEST_DIR"/histogram/256bin1min1max.test"),256,0,255);
}
TYPED_TEST(Histogram,100Bins0min99max)
{
    histTest<TypeParam,uint>(string(TEST_DIR"/histogram/100bin0min99max.test"),100,0,99);
}
TYPED_TEST(Histogram,40Bins0min100max)
{
    histTest<TypeParam,uint>(string(TEST_DIR"/histogram/40bin0min100max.test"),40,0,100);
}
TYPED_TEST(Histogram,40Bins0min100max_Batch)
{
    histTest<TypeParam,uint>(string(TEST_DIR"/histogram/40bin0min100max_batch.test"),40,0,100);
}
TYPED_TEST(Histogram,256Bins0min255max_zeros)
{
    histTest<TypeParam,uint>(string(TEST_DIR"/histogram/256bin0min0max.test"),256,0,255);
}
TEST(Histogram, CPP)
{
    if (noDoubleTests<float>()) return;
    if (noDoubleTests<int>()) return;
    const unsigned nbins = 100;
    const double minval = 0.0;
    const double maxval = 99.0;
    vector<af::dim4> numDims;
    vector<vector<float> >  in;
    vector<vector<uint> > tests;
    readTests<float,uint,int>(string(TEST_DIR"/histogram/100bin0min99max.test"),numDims,in,tests);
    af::array input(numDims[0], &(in[0].front()));
 
    uint *outData = 
new uint[output.
elements()];
    output.
host((
void*)outData);
    for (size_t testIter=0; testIter<tests.size(); ++testIter) {
        vector<uint> currGoldBar = tests[testIter];
        size_t nElems        = currGoldBar.size();
        for (size_t elIter=0; elIter<nElems; ++elIter) {
            ASSERT_EQ(currGoldBar[elIter],outData[elIter])<< "at: " << elIter<< std::endl;
        }
    }
    
    delete[] outData;
}
TEST(Histogram, SNIPPET_hist_nominmax)
{
    using std::ostream_iterator;
    using std::cout;
    using std::endl;
    unsigned output[] = {3, 1, 2, 0, 0, 0, 0, 1, 1, 1};
    float input[]  = {1, 2, 1, 1, 3, 6, 7, 8, 3};
    int nbins = 10;
    size_t nElems = sizeof(input)/sizeof(float);
    array hist_in(nElems, input);
 
    
    vector<unsigned> h_out(nbins);
    hist_out.host((void*)h_out.data());
    if( false == equal(h_out.begin(), h_out.end(), output) ) {
        cout << "Expected: ";
        copy(output, output + nbins, ostream_iterator<unsigned>(cout, 
", "));
 
        cout << endl << "Actual: ";
        copy(h_out.begin(), h_out.end(), ostream_iterator<unsigned>(cout, 
", "));
 
        FAIL() << "Output did not match";
    }
}
TEST(Histogram, SNIPPET_hist_minmax)
{
    using std::ostream_iterator;
    using std::cout;
    using std::endl;
    unsigned output[] = {0, 3, 1, 2, 0, 0, 1, 1, 1, 0};
    float input[]  = {1, 2, 1, 1, 3, 6, 7, 8, 3};
    int nbins = 10;
    size_t nElems = sizeof(input)/sizeof(float);
    array hist_in(nElems, input);
 
    
    vector<unsigned> h_out(nbins);
    hist_out.host((void*)h_out.data());
    if( false == equal(h_out.begin(), h_out.end(), output) ) {
        cout << "Expected: ";
        copy(output, output + nbins, ostream_iterator<unsigned>(cout, 
", "));
 
        cout << endl << "Actual: ";
        copy(h_out.begin(), h_out.end(), ostream_iterator<unsigned>(cout, 
", "));
 
        FAIL() << "Output did not match";
    }
}
TEST(Histogram, SNIPPET_histequal)
{
    using std::ostream_iterator;
    using std::cout;
    using std::endl;
    float output[] = { 1.5, 4.5,  1.5, 1.5, 4.5, 4.5, 6.0, 7.5, 4.5 };
    float input[]  = {1, 2, 1, 1, 3, 6, 7, 8, 3};
    int nbins = 10;
    size_t nElems = sizeof(input)/sizeof(float);
    array hist_in(nElems, input);
 
    
    
    
    vector<float> h_out(nElems);
    eq_out.host((void*)h_out.data());
    if( false == equal(h_out.begin(), h_out.end(), output) ) {
        cout << "Expected: ";
        copy(output, output + nbins, ostream_iterator<float>(cout, 
", "));
 
        cout << endl << "Actual: ";
        copy(h_out.begin(), h_out.end(), ostream_iterator<float>(cout, 
", "));
 
        FAIL() << "Output did not match";
    }
}
{
    }
    for(int ii = 0; ii < 3; ii++) {
        ASSERT_EQ(max<double>(
abs(c_ii - b_ii)) < 1E-5, 
true);
    }
}
{
    for (int i=16; i<28; ++i) {
    }
    unsigned out[4];
    ASSERT_EQ(true, out[0] == 16);
    ASSERT_EQ(true, out[1] ==  8);
    ASSERT_EQ(true, out[2] ==  8);
    ASSERT_EQ(true, out[3] ==  8);
}