// ****************************************************************************
//
//          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_PROTEIN_H_
#define AEVOL_PROTEIN_H_

#include <cstdint>

#include <list>
#include <ranges>
#include <vector>

#include "Dna.h"
#include "Strand.h"

namespace aevol {

class Rna;

class Protein {
 public:
  Protein() = delete;
  ~Protein();

  Protein(Dna::size_type position_first_aa,
          Dna::size_type position_last_base_stop_codon,
          size_t nb_aa,
          Strand strand,
          double e,
          Rna* rna);

  bool operator<(const Protein& other);

  /// position of the first Amino-Acid-coding base on the genome
  auto position_first_aa() const { return position_first_aa_; }
  /// position of the last base of the stop codon on the genome
  auto position_last_base_stop_codon() const { return position_last_base_stop_codon_; }
  /// size (number of Amino-Acids) of the protein
  auto size() const { return nb_aa_; } // nb of amino-acids
  /// strand of the corresponding gene
  auto strand() const { return strand_; }
  /// M parameter of the protein
  auto m() const { return m_; }
  /// W parameter of the protein
  auto w() const { return w_; }
  /// H parameter of the protein
  auto h() const { return h_; }
  /// e-value (~concentration) of the protein
  auto e() const { return e_; }
  /// whether the protein is functional
  auto is_functional() const { return is_functional_; }
  auto is_duplicate() const { return is_duplicate_; }
  auto codon_list_size() const { return codon_list_.size(); }
  auto codon_list(size_t i) const { return codon_list_[i]; }
  auto rna_list() const { return std::views::transform(rna_list_, as_const_ref); }

  /// set M parameter of the protein
  void set_m(double m) { m_ = m; }
  /// set W parameter of the protein
  void set_w(double w) { w_ = w; }
  /// set H parameter of the protein
  void set_h(double h) { h_ = h; }
  /// set whether the protein is functional
  void set_is_functional(bool is_functional) { is_functional_ = is_functional; }
  /// add to e-value (a.k.a. ~concentration)
  void add_to_e(double e_to_add) { e_ += e_to_add; }
  void set_duplicate() { is_duplicate_ = true; }
  void add_codon(int8_t val) { codon_list_.push_back(val); }
  void add_rna(const Rna* rna) { rna_list_.push_back(rna); }

 protected:
  Dna::size_type position_first_aa_ = -1;
  Dna::size_type position_last_base_stop_codon_ = -1;
  size_t nb_aa_ = -1;
  Strand strand_;
  double m_ = -1.0;
  double w_ = -1.0;
  double h_ = -1.0;
  double e_ = -1.0;
  bool is_functional_ = false;
  bool is_duplicate_ = false;
  std::vector<int8_t> codon_list_ = {};
  std::list<const Rna*> rna_list_;

  static auto as_const_ref(const Rna* ptr) -> const Rna& { return *ptr; }
};

}  // namespace aevol

#endif  //AEVOL_PROTEIN_H_
