#ifndef RESULTS_HPP
#define RESULTS_HPP

#include <cilk/cilk.h>
#include <cilk/reducer.h>
#include "config.hpp"
#include "flint/fmpq_poly.h"


//! Number of results
static const size_t result_size=max_len/2;

//! Structure storing results
struct Results{
  //! Number of SAP
  size_t numbers[result_size];
  //! Sum of the Fp
  fmpq_poly_t sum_fp[result_size];
  //! Empty constructor
  Results();
  //! Reset 
  void reset();
};

//!**************************
//! Class for esults reducer
//!**************************
class ResultsReducer{
private:
  struct Monoid:cilk::monoid_base<Results>{
    static void reduce(Results* left, Results* Right);
  };
  cilk::reducer<Monoid> imp_;
public:
  ResultsReducer();
  //! Obtain reference to numbers
  size_t& numbers(size_t i);
  //! Add an Fp coeff
  //! \param i lenght of the SAP
  //! \param p poly of the FP
  void add_fp(size_t i,fmpq_poly_t p);
  //! Return pointer to th FP poly
  fmpq_poly_struct* get_fp(size_t i);
  void reset();
};

extern ResultsReducer cilk_results;

//***********
//* Inlines *
//***********

inline
Results::Results(){
  reset();
}

inline void
Results::reset(){
  for(size_t i=0;i<result_size;++i){
    numbers[i]=0;
    fmpq_poly_init(sum_fp[i]);
    fmpq_poly_zero(sum_fp[i]);
  }
}

inline
ResultsReducer::ResultsReducer(){
  reset();
}
inline void
ResultsReducer::Monoid::reduce(Results* left,Results* right){
  for(size_t i=0;i<result_size;++i){
    left->numbers[i]+=right->numbers[i];
    fmpq_poly_add(left->sum_fp[i],left->sum_fp[i],right->sum_fp[i]);
  }
}

inline void
ResultsReducer::reset(){
  imp_.view().reset();
}

inline size_t&
ResultsReducer::numbers(size_t i){
  return imp_.view().numbers[i];
}

inline void
ResultsReducer::add_fp(size_t i,fmpq_poly_t p){
  return fmpq_poly_add(imp_.view().sum_fp[i],imp_.view().sum_fp[i],p);
}

inline fmpq_poly_struct*
ResultsReducer::get_fp(size_t i){
  return imp_.view().sum_fp[i];
}
#endif
