#include "YODA/Histo.h"
#include "YODA/Profile.h"
#include "YODA/Scatter.h"

#include <cmath>
#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <sys/time.h>

using namespace std;
using namespace YODA;

int main() {

    // Creating a histogram and measuring the time it takes to do it.
    Histo3D h(200, 0, 100, 200, 0, 100, 200, 0, 100);

    cout << "Checking if filling does modify the grid:";
    size_t beforeAdd = h.numBins();
    h.fill(12.3, 45.6, 78.9);
    if (h.numBins() != beforeAdd) {
        cout << "FAIL" << endl;
        return -1;
    }
    cout << "PASS" << endl;

    // Checking if everything is still working as desired.
    // It is a good thing to do, as at some earlier stages
    // in development adding a broken bin destroyed the cache of edges.
    cout << "Is the origin working correctly?         ";
    int originIndex = h.fill(0.0, 0.0, 0.0, 1);
    if (originIndex == -1) {
        cout << "FAIL" << endl;
        return -1;
    }
    cout << "PASS" << endl;

    cout << "Does rebinning work?                     ";
    Histo3D h2(20, 0, 100, 20, 0, 100, 20, 0, 100);
    h2.rebin<0>(2,3);
    cout << "PASS" << endl;

    cout << "Trying to fill the newly created bin:    ";
    int fillTest = h.fill(-3, -3, -3, 1);
    if (fillTest != int(h.indexAt(-3,-3, -3))) {
        cout << "FAIL" << endl;
        return -1;
    }
    cout << "PASS" << endl;

    fillTest = h.fill(180, 180, 180, 1);
    if (fillTest != int(h.indexAt(180,180,180))) {
        cout << "FAIL" << endl;
        return -1;
    }

    cout << "Testing if histo2D transforms to Profile:";
    Histo3D test1(100, 0, 100, 100, 0, 100, 100, 0, 100);
    Profile2D test2(100, 0, 100, 100, 0, 100);

    test1.fill(1,1,1,1);
    test2.fill(1,1,1,1);
    if(test2 != test1.mkMarginalProfile<0>()){
      cout << "FAIL" << endl;
      return -1;
    }
    cout << "PASS" << endl;
    cout << "A more elaborate test:                   ";
    for(size_t i = 0; i < 100000; ++i){
      size_t x = rand()%100;
      size_t y = rand()%100;
      size_t z = rand()%100;
      test1.fill(x,y,z);
      test2.fill(x,y,z);
    }
    if(test2 != test1.mkMarginalProfile<0>()){
      cout << "FAIL" << endl;
      return -1;
    }
    cout << "PASS" << endl;

    return EXIT_SUCCESS;
}
