// ****************************************************************************
//
//          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 "CheckpointExplorer.h"

namespace aevol {

CheckpointExplorer::CheckpointExplorer(CheckpointData&& chkpt_data) {
  // Set aevol clock
  AeTime::set_time(chkpt_data.time);

  auto nb_indivs = chkpt_data.grid.width() * chkpt_data.grid.height();

  // Init phenotypic target
  target_ = std::move(chkpt_data.phenotypic_target);

  // Init grid
  grid_ = std::move(chkpt_data.grid);

  // Init experiment setup
  aevol::exp_setup = std::move(chkpt_data.exp_setup);

  // Init checkpoint frequency
  checkpoint_frequency_ = chkpt_data.checkpoint_freq;

  // Init tree output frequency
  if (chkpt_data.tree_output_freq) {
    tree_output_frequency_ = chkpt_data.tree_output_freq;
  }

  // Evaluate the individuals
  for (auto& [seqid, indiv, modifiers] : chkpt_data.population) {
    indiv->evaluate(exp_setup->w_max(), exp_setup->selection_pressure(), *target_);
  }

  population_.reset_from_fasta_population(nb_indivs, chkpt_data.population);
  population_.update_best();

  // Store fasta annotations
  for (auto& [seqid, indiv, modifiers] : chkpt_data.population) {
    fasta_annotations_[indiv.get()] = std::make_tuple(seqid, modifiers);
  }
}

auto CheckpointExplorer::make_from_checkpoint(time_type time) -> std::unique_ptr<CheckpointExplorer> {
  return std::unique_ptr<CheckpointExplorer>(
      new CheckpointExplorer(CheckpointHandler::make_default()->read_checkpoint(time)));
}

auto CheckpointExplorer::make_from_checkpoint_path(const std::filesystem::path& checkpoint_file)
    -> std::unique_ptr<CheckpointExplorer> {
  return std::unique_ptr<CheckpointExplorer>(
      new CheckpointExplorer(CheckpointHandler::read_checkpoint(checkpoint_file)));
}

auto CheckpointExplorer::make_from_checkpoint_time_or_path(std::string time_or_path)
    -> std::unique_ptr<CheckpointExplorer> {
  // Try to interpret checkpoint specifier as timestep
  auto timestep = aevol::time_type{};
  auto [ptr, ec] = std::from_chars(time_or_path.data(), time_or_path.data() + time_or_path.size(), timestep);
  if (ec == std::errc()) {
    return make_from_checkpoint(timestep);
  }

  // Conversion to time_type failed, try to interpret argument as path to checkpoint
  return make_from_checkpoint_path(std::filesystem::path{time_or_path});
}

}  // namespace aevol
