// ****************************************************************************
//
//          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_INDIV_IDXS_MAP_H
#define AEVOL_INDIV_IDXS_MAP_H

#include <map>
#include <vector>

#include "ae_types.h"
#include "io/fasta/FastaModifiers.h"
#include "Individual.h"

namespace aevol {

using indivs_idxs_sorted_map_t = std::map<const Individual* const,
                                          std::pair<std::string, std::vector<indiv_id_type>>,
                                          decltype(dna_lexicographical_compare)>;

// Individual-owning structure w/o sorting. Meant for reading purposes
using fasta_structured_individual_t = std::tuple<std::string,
                                                 std::shared_ptr<Individual>,
                                                 FastaModifiers>;
using fasta_structured_population_t = std::vector<fasta_structured_individual_t>;

template <std::ranges::input_range InputRange>
auto to_indivs_idxs_sorted_map(time_type time, InputRange&& indiv_range) -> indivs_idxs_sorted_map_t {
  // Create a map of dna-lexically-ordered pairs of Individual* and indexes thereof
  auto unique_indivs = indivs_idxs_sorted_map_t();

  // Populate the map: for each individual...
  for (indiv_id_type indiv_idx = 0 ; indiv_idx < indiv_range.size() ; ++indiv_idx) {
    // Try insert (indiv*, indiv_idx) in the map
    auto [it, insert_ok] =
        unique_indivs.try_emplace(&indiv_range[indiv_idx], "", std::initializer_list<decltype(indiv_idx)>({indiv_idx}));
    // If it could not be inserted (because it was already there), add indiv_idx to the existing idx vector
    if (not insert_ok) {
      // Add current indiv_idx to the existing entry
      it->second.second.emplace_back(indiv_idx);
    }
  }

  // Map is fully populated, assign a name to each genome
  auto genome_idx = 0u;
  for (auto& [k, val]: unique_indivs) {
    val.first = std::format("Seq{}-{}", time, ++genome_idx);
  }

  return unique_indivs;
}

}  // namespace aevol

#endif  // AEVOL_INDIV_IDXS_MAP_H
