// ****************************************************************************
//
//          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_SELECTION_PARAMS_H_
#define AEVOL_SELECTION_PARAMS_H_

#include <cassert>
#include <cinttypes>
#include <cstdio>
#include <cstdlib>
#include <memory>

#include "checkpointing/mxifstream.h"
#include "checkpointing/mxofstream.h"
#include "FitnessFunction.h"
#include "SelectionScheme.h"
#include "SelectionScope.h"

namespace aevol {

class SelectionParams {
 public:
  SelectionParams()                                        = default;
  SelectionParams(const SelectionParams&)                  = default;
  SelectionParams(SelectionParams&&)                       = default;
  SelectionParams& operator=(const SelectionParams& clone) = default;
  SelectionParams& operator=(SelectionParams&& clone)      = default;
  virtual ~SelectionParams()                               = default;

  // =================================================================
  //                        Accessors: getters
  // =================================================================
  auto selection_scheme() const { return selection_scheme_; };
  auto selection_pressure() const { return selection_pressure_; };

  auto selection_scope() const { return selection_scope_; };
  auto selection_scope_x() const { return selection_scope_x_; };
  auto selection_scope_y() const { return selection_scope_y_; };

  #ifdef SEX
  auto selfing_control() const { return selfing_control_; }
  auto selfing_rate() const { return selfing_rate_; }
  #endif

  auto fitness_func() const { return fitness_function_; };

  // =================================================================
  //                        Accessors: setters
  // =================================================================
  void set_selection_scheme(SelectionScheme sel_scheme) { selection_scheme_ = sel_scheme; };
  void set_selection_pressure(double sel_pressure) { selection_pressure_ = sel_pressure; };

  void set_selection_scope(SelectionScope sel_scope) { selection_scope_ = sel_scope; };
  void set_selection_scope_x(int32_t sel_scope_x) { selection_scope_x_ = sel_scope_x; };
  void set_selection_scope_y(int32_t sel_scope_y) { selection_scope_y_ = sel_scope_y; };

  #ifdef SEX
  void set_selfing_control(bool selfing_control) { selfing_control_ = selfing_control; }
  void set_selfing_rate(double selfing_rate) { selfing_rate_ = selfing_rate; }
  #endif

  void set_fitness_function(FitnessFunction fit_func) { fitness_function_ = fit_func; };

  void write_to_checkpoint(std::ofstream& os, mxofstream& mxos) const;
  void load_from_checkpoint(std::ifstream& is, mxifstream& mxis);

 protected:
  SelectionScheme selection_scheme_ = SelectionScheme::RANK_EXPONENTIAL;
  double selection_pressure_        = 0.998;

  SelectionScope selection_scope_ = SelectionScope::LOCAL;
  int32_t selection_scope_x_      = 3;
  int32_t selection_scope_y_      = 3;

  #ifdef SEX
  bool selfing_control_ = false;
  double selfing_rate_;
  #endif

  FitnessFunction fitness_function_ = FitnessFunction::EXP;
};

std::ostream& operator<<(std::ostream&, const SelectionParams&);

}  // namespace aevol

#endif  // AEVOL_SELECTION_PARAMS_H_
