#include <numeric>
#include <limits>
#include <vector>
#include <map>
#include <cmath>
#include <iostream>
#include <iomanip>

#include <QDebug>

#include "tracepluscombiner.h"
#include "../../trace/trace.h"
#include "../../types.h"
#include "pappsomspp/core/utils.h"
#include "pappsomspp/core/pappsoexception.h"
#include "pappsomspp/core/exception/exceptionoutofrange.h"


namespace pappso
{


TracePlusCombiner::TracePlusCombiner() : TraceCombiner()
{
}


TracePlusCombiner::TracePlusCombiner(int decimal_places) : TraceCombiner(decimal_places)
{
}


TracePlusCombiner::TracePlusCombiner(const TracePlusCombiner &other) : TraceCombiner(other)
{
}


TracePlusCombiner::TracePlusCombiner(TracePlusCombinerCstSPtr other) : TraceCombiner(other)
{
  qDebug();
}


TracePlusCombiner::~TracePlusCombiner()
{
}


MapTrace &
TracePlusCombiner::combine(MapTrace &map_trace, const Trace &trace) const
{
  // qDebug() << "With m_decimalPlaces:" << m_decimalPlaces << "map trace size:" << map_trace.size()
  //          << "trace size:" << trace.size();

  if(!trace.size())
    return map_trace;

  for(auto &current_data_point : trace)
    {

      // If the data point is 0-intensity, then do nothing!
      if(!current_data_point.y)
        continue;

      double x = Utils::roundToDecimals(current_data_point.x, m_decimalPlaces);
      // double x = current_data_point.x;

      std::map<double, double>::iterator map_iterator;

      std::pair<std::map<pappso_double, pappso_double>::iterator, bool> result;

      result = map_trace.insert(std::pair<pappso_double, pappso_double>(x, current_data_point.y));

      if(result.second)
        {
          // qDebug() << " The element to insert was not there already, we added it.";
          // The new element was inserted, we have nothing to do.
        }
      else
        {
          // The key already existed! The item was not inserted. We need to
          // update the value.

          // qDebug() << " The element to insert was there already, we increment y.";
          result.first->second += current_data_point.y;
        }
    }

  // qDebug() << "Prior to returning map_trace, its size is:" << map_trace.size();
  return map_trace;
}


MapTrace &
TracePlusCombiner::combine(MapTrace &map_trace_out, const MapTrace &map_trace_in) const
{
  // qDebug() << __FILE__ << "@" << __LINE__ << __FUNCTION__ << " ()"
  //<< "map trace size:" << map_trace_out.size()
  //<< "trace size:" << trace.size();

  if(!map_trace_in.size())
    return map_trace_out;

  return combine(map_trace_out, map_trace_in.toTrace());
}


} // namespace pappso
