/**
 * \file pappsomspp/processing/spectree/bucketclustering.cpp
 * \date 13/12/2023
 * \author Olivier Langella
 * \brief rearrange itemcarts into buckets
 *
 * C++ implementation of algorithm already described in :
 * 1. David, M., Fertin, G., Rogniaux, H. & Tessier, D. SpecOMS: A Full Open
 * Modification Search Method Performing All-to-All Spectra Comparisons within
 * Minutes. J. Proteome Res. 16, 3030–3038 (2017).
 *
 * https://www.theses.fr/2019NANT4092
 */


/*
 * SpecTree
 * Copyright (C) 2023  Olivier Langella
 * <olivier.langella@universite-paris-saclay.fr>
 *
 * This program is free software: you can redistribute ipetide to spectrum
 * alignmentt and/or modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of th^e GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "bucketclustering.h"
#include <algorithm>
#include "pappsomspp/core/pappsoexception.h"
#include <QObject>
// #include <experimental/map>


namespace pappso
{
namespace spectree
{

// for std::map
template <class K, class T, class C, class A, class Predicate>
void
erase_if(std::map<K, T, C, A> &c, Predicate pred)
{
  for(auto i = c.begin(), last = c.end(); i != last;)
    if(pred(*i))
      i = c.erase(i);
    else
      ++i;
}

BucketClustering::BucketClustering()
{
}

std::size_t
BucketClustering::size() const
{
  return m_bucketMap.size();
}


std::size_t
BucketClustering::getItemCartCount() const
{
  return m_itemCartCount;
}


void
BucketClustering::addItemCart(const ItemCart &spectrum_int)
{
  // qDebug() << " " << m_bucketMap.size();
  m_itemCartCount++;
  for(std::size_t mass : spectrum_int.getItemList())
    {
      std::pair<std::map<std::size_t, Bucket>::iterator, bool> ret;
      ret = m_bucketMap.insert(std::pair<std::size_t, Bucket>(mass, Bucket(mass)));
      if(ret.second == false)
        {
        }
      else
        {
        }

      ret.first->second.push_back(spectrum_int.getId());
    }

  // Param.defineHighestMassValue(max_mass);
  // return clusters;
}
std::vector<Bucket>
BucketClustering::asSortedList() const
{
  qDebug() << " " << m_bucketMap.size();
  if(m_bucketMap.size() == 0)
    {
      throw pappso::PappsoException(QObject::tr("bucket map is empty"));
    }
  std::vector<Bucket> bucketList;
  bucketList.reserve(m_bucketMap.size());


  for(auto &&map_pair : m_bucketMap)
    {
      if(map_pair.second.size() > 1)
        bucketList.push_back(map_pair.second);
    }
  // m_bucketMap.clear();

  std::sort(bucketList.begin(), bucketList.end());

  qDebug() << " " << m_bucketMap.size();
  return bucketList;
}

void
BucketClustering::removeBucketsWithinCartIdRange(std::size_t spectrum_idx_begin,
                                                 std::size_t spectrum_idx_end)
{

  qDebug() << "spectrum_idx_begin=" << spectrum_idx_begin
           << " spectrum_idx_end=" << spectrum_idx_end;
  erase_if(m_bucketMap, [spectrum_idx_begin, spectrum_idx_end](const auto &item) {
    return ((item.second.front() >= spectrum_idx_begin) &&
            (item.second.back() <= spectrum_idx_end));
  });
}

} // namespace spectree
} // namespace pappso
