#include "YODA/Counter.h"
#include "YODA/Histo.h"
#include "YODA/Profile.h"
#include "YODA/BinnedEstimate.h"
#include "YODA/Scatter.h"
#include "YODA/WriterYODA.h"
#include "YODA/WriterYODA1.h"
#include <cmath>
#include <vector>
#include <iostream>
#include <memory>
#include <type_traits>

using namespace std;
using namespace YODA;


int main() {

  //shared_ptr<AnalysisObject>
  auto c = make_shared<Counter>();
  auto h1 = make_shared<Histo1D>(20, 0.0, 1.0);
  auto h2 = make_shared<Histo2D>(20, 0.0, 1.0, 10, 0.0, 1.0);
  auto p1 = make_shared<Profile1D>(20, 0.0, 1.0);
  auto p2 = make_shared<Profile2D>(20, 0.0, 1.0, 10, 0.0, 1.0);
  for (size_t n = 0; n < 1000; ++n) {
    const double num = rand()/static_cast<double>(RAND_MAX);
    c->fill();
    h1->fill(num);
    h2->fill(num, num);
    p1->fill(num, num);
    p2->fill(num, num, num);
  }
  WriterYODA::create().write("testwriter1.yoda", h1);
  WriterYODA::write("testwriter1.yoda", h1);

  auto e0 = make_shared<Estimate0D>(c->mkEstimate());
  auto e1 = make_shared<Estimate1D>(h1->mkEstimate());
  auto e2 = make_shared<Estimate2D>(h2->mkEstimate());
  auto s0 = make_shared<Scatter1D>(e0->mkScatter());
  auto s1 = make_shared<Scatter2D>(e1->mkScatter());
  auto s2 = make_shared<Scatter3D>(e2->mkScatter());
  vector<shared_ptr<AnalysisObject>> aos = { static_pointer_cast<AnalysisObject>(c),
                                             static_pointer_cast<AnalysisObject>(h1),
                                             static_pointer_cast<AnalysisObject>(h2),
                                             static_pointer_cast<AnalysisObject>(p1),
                                             static_pointer_cast<AnalysisObject>(p2),
                                             static_pointer_cast<AnalysisObject>(e0),
                                             static_pointer_cast<AnalysisObject>(e1),
                                             static_pointer_cast<AnalysisObject>(e2),
                                             static_pointer_cast<AnalysisObject>(s0),
                                             static_pointer_cast<AnalysisObject>(s1),
                                             static_pointer_cast<AnalysisObject>(s2)
                                           };
  WriterYODA::write("testwriter2.yoda", aos);

  #ifdef HAVE_LIBZ
  WriterYODA::write("testwriter2.yoda.gz", aos);
  #endif

  WriterYODA1::create().write("testwriter1.yoda", h1);
  WriterYODA1::write("testwriter1.yoda", h1);

  WriterYODA1::write("testwriter2.yoda", aos);


  return EXIT_SUCCESS;
}
