// ****************************************************************************
//
//          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/>.
//
// ****************************************************************************

#include "EukaryoteIndividualMutator.h"

#include "Individual.h"

namespace aevol {

EukaryoteIndividualMutator::EukaryoteIndividualMutator(const Individual& indiv,
                                                       std::shared_ptr<MutationParams> mut_params,
                                                       const GenomeLimits& genome_limits) {
  dna_mutator_ = {std::make_unique<DnaMutator>(
                      indiv.dna(Chrsm::A).length(), mut_params, genome_limits),
                  std::make_unique<DnaMutator>(
                      indiv.dna(Chrsm::B).length(), mut_params, genome_limits)};
}

auto EukaryoteIndividualMutator::has_mutations() const -> bool {
  return (dna_mutator_[std::to_underlying(Chrsm::A)]->has_mutations() or
          dna_mutator_[std::to_underlying(Chrsm::B)]->has_mutations());
}

void EukaryoteIndividualMutator::generate_mutations(JumpingMT& prng) {
  for (DnaMutator* dna_mutator: {dna_mutator_[std::to_underlying(Chrsm::A)].get(),
                                 dna_mutator_[std::to_underlying(Chrsm::B)].get()}) {
    dna_mutator->compute_nb_mutations_per_type(prng);

    if (dna_mutator->mutations_to_generate()) {
      dna_mutator->generate_all_mutations(prng);
    }
  }
}

auto EukaryoteIndividualMutator::apply_mutations(Individual& indiv) -> std::list<std::unique_ptr<MutationReport>> {
  auto undergone_mutations =
      indiv.mutable_dna(Chrsm::A).apply_mutations(dna_mutator_[std::to_underlying(Chrsm::A)]->mutation_list());
  undergone_mutations.merge(
      indiv.mutable_dna(Chrsm::B).apply_mutations(dna_mutator_[std::to_underlying(Chrsm::B)]->mutation_list()));
  return undergone_mutations;
}

void EukaryoteIndividualMutator::apply_mutations(Individual& indiv, indiv_id_type, PhylogeneticTreeHandler*) {
  // No trees in Eukaryote mode, simply apply mutations
  apply_mutations(indiv);
}

}  // namespace aevol
