// ****************************************************************************
//
//          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_PARAM_VALUES_H_
#define AEVOL_PARAM_VALUES_H_

#include <cinttypes>

#include <list>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>

#include "ae_types.h"
#include "AlignmentParams.h"
#include "macros.h"
#include "FitnessFunction.h"
#include "phenotype/Gaussian.h"
#include "phenotype/fuzzy/FuzzyFlavor.h"
#include "SelectionScheme.h"
#include "SelectionScope.h"

#ifdef BASE_4
  #include "aevol_4b/biochemistry/AA_2_MWH_Value_Mapping.h"
#endif

namespace aevol {

class JumpingMT;

struct ParamValues {
  ParamValues();
  ~ParamValues();

  // =========================================================================
  //                               Data Members
  // =========================================================================
  static constexpr int8_t STRAIN_NAME_DEFAULT_SIZE  = 20;
  static constexpr int8_t STRAIN_NAME_LOGIN_SIZE    = 10;

  // ----------------------------------------- PseudoRandom Number Generators
  // Seed for the selection random generator
  int32_t seed = 0;
  // Seed for the mutations random generator
  int32_t mut_seed = 0;
  // Seed for the stochasticity random generator
  int32_t stoch_seed = 0;
  // Seed for the phenotypic target variation random generator
  int32_t env_var_seed = 0;
  // Seed for the phenotypic target noise random generator
  int32_t env_noise_seed = 0;

  // ------------------------------------------------------------ Constraints
  int32_t min_genome_length          = 1;
  int32_t max_genome_length          = 10000000;
  int32_t chromosome_minimal_length  = -1;   // TODO unused ?
  int32_t chromosome_maximal_length  = -1;   // TODO unused ?
  double w_max                       = 0.033333333;

  // ----------------------------------------------------- Initial conditions
  int32_t chromosome_initial_length  = 5000;

  // -------------------------------------------------------- Phenotypic target
  std::list<Gaussian> std_env_gaussians;
  int16_t env_sampling = 300;
  bool normalize_phenotype = false;

  // --------------------------------------------------------- Mutation rates
  double point_mutation_rate   = 1e-5;
  double small_insertion_rate  = 1e-5;
  double small_deletion_rate   = 1e-5;
  int16_t max_indel_size       = 6;

  // ------------------------------ Rearrangement rates (without alignements)
  double duplication_rate    = 1e-5;
  double deletion_rate       = 1e-5;
  double translocation_rate  = 1e-5;
  double inversion_rate      = 1e-5;

  // ------------------------------------ Parameters for sequence alignements
  bool recomb_on_align_                                       = false;
  int16_t align_match_bonus_                                  = 1;        // Score bonus for matching residues
  int16_t align_mismatch_cost_                                = -2;       // Score cost for mismatched residues
  std::unique_ptr<align::ScoreFunction> align_score_function_ = nullptr;  // fn align_score -> mut_event_probability
  double align_neighbourhood_rate_                            = 2.0;
  Dna::size_type max_align_size_ = 150;  // Size at which we should stop evaluating an alignment

  // -------------------------------------------------------------- Selection
  SelectionScheme selection_scheme  = SelectionScheme::FITNESS_PROPORTIONATE;
  double selection_pressure         = 1000;

  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_  = .0;
  #endif

  FitnessFunction fitness_function  = FitnessFunction::EXP;

  // ------------------------------------------------------ Spatial structure
  int16_t grid_width                  = 32;
  int16_t grid_height                 = 32;
  bool well_mixed                     = false;
  int32_t partial_mix_nb_permutations = 0;

  #ifdef BASE_4
  // -------------------------------------------------- MWH bases configuration
  bool mwh_bases_redefined = false;
  int8_t aa_base_m[aevol_4b::NB_AMINO_ACIDS];
  int8_t aa_base_w[aevol_4b::NB_AMINO_ACIDS];
  int8_t aa_base_h[aevol_4b::NB_AMINO_ACIDS];

  std::map<std::string, aevol_4b::AminoAcid> str_to_aminoacid = {
      {std::string("phe"), aevol_4b::AminoAcid::PHENYLALANINE},
      {std::string("leu"), aevol_4b::AminoAcid::LEUCINE},
      {std::string("iso"), aevol_4b::AminoAcid::ISOLEUCINE},
      {std::string("met"), aevol_4b::AminoAcid::METHIONINE},
      {std::string("val"), aevol_4b::AminoAcid::VALINE},
      {std::string("ser"), aevol_4b::AminoAcid::SERINE},
      {std::string("pro"), aevol_4b::AminoAcid::PROLINE},
      {std::string("thr"), aevol_4b::AminoAcid::THREONINE},
      {std::string("ala"), aevol_4b::AminoAcid::ALANINE},
      {std::string("tyr"), aevol_4b::AminoAcid::TYROSINE},
      {std::string("sto"), aevol_4b::AminoAcid::STOP},
      {std::string("his"), aevol_4b::AminoAcid::HISTIDINE},
      {std::string("glu"), aevol_4b::AminoAcid::GLUTAMINE},
      {std::string("asp"), aevol_4b::AminoAcid::ASPARAGINE},
      {std::string("lys"), aevol_4b::AminoAcid::LYSINE},
      {std::string("asa"), aevol_4b::AminoAcid::ASPARTIC_ACID},
      {std::string("gla"), aevol_4b::AminoAcid::GLUTAMIC_ACID},
      {std::string("cys"), aevol_4b::AminoAcid::CYSTEINE},
      {std::string("try"), aevol_4b::AminoAcid::TRYPTOPHAN},
      {std::string("arg"), aevol_4b::AminoAcid::ARGININE},
      {std::string("gly"), aevol_4b::AminoAcid::GLYCINE}
  };
  #endif

  // ---------------------------------------------------------------- Output
  // Checkpoints
  time_type checkpoint_frequency = 1000;

  // Tree
  std::optional<time_type> tree_output_frequency = 1000;

  // Stats
  std::optional<time_type> best_indiv_stats_output_frequency = 1;
  std::optional<time_type> pop_stats_output_frequency        = 1;

  // Fuzzy set flavor
  FuzzyFlavor fuzzy_flavor = FuzzyFlavor::DISCRETE_DOUBLE_TABLE;
};

}  // namespace aevol

#endif  // AEVOL_PARAM_VALUES_H_
