// ****************************************************************************
//
//          Aevol - An in silico experimental evolution platform
//
// ****************************************************************************
//
// Copyright: See the AUTHORS file provided with the package or <www.aevol.fr>
// Web: http://www.aevol.fr/
// E-mail: See <http://www.aevol.fr/contact/>
// Original Authors : Guillaume Beslon, Carole Knibbe, David Parsons
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 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 the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// ****************************************************************************

#ifndef AEVOL_MULTIINDIVIDUALDATACOLLECTOR_H_
#define AEVOL_MULTIINDIVIDUALDATACOLLECTOR_H_

#include <ranges>
#include <tuple>
#include <utility>
#include <vector>

#include "Individual.h"

namespace aevol {

template <typename T>
inline auto collect_data(std::ranges::input_range auto&& indiv_range) {
  // data is a 2D vector of doubles. It will hold all the metrics defined by T for each individual.
  // Initialize data with n empty vector, n being the size of the tuple returned by
  // function T::collect_data(const Individual&)
  auto data = std::vector<std::vector<double>>(
      std::tuple_size_v<decltype(T::collect_data(std::declval<const Individual&>()))>);

  // For each individual in the range, collect its data and push it back into the relevant data vector
  for (const Individual& indiv: indiv_range) {
    auto indiv_data = T::collect_data(indiv);
    auto i = size_t(0);
    std::apply(
        [&](auto&... elt) {
          (data[i++].push_back({double(elt)}), ...);
        }, indiv_data
    );
  }
  return data;
}

}  // namespace aevol

#endif  // AEVOL_MULTIINDIVIDUALDATACOLLECTOR_H_
