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

namespace aevol {
namespace gff3 {

void write_individual_gff3(const std::string& seqid, const Individual& individual, std::filesystem::path filename) {
  std::ofstream out(filename);
  if (not out) {
    throw std::runtime_error(std::string("failed to open file ") + filename.string());
  }

  // See https://github.com/The-Sequence-Ontology/Specifications/blob/master/gff3.md for syntax details
  // ----- Write GFF version (mandatory)
  out << "##gff-version 3" << std::endl;

  for (auto chrsm: chrsms) {
    // Separate chromosomes with new lines (diploid-only)
    if (chrsm == Chrsm::B) out << "\n\n";

    // Shorthand
    auto chrsm_length = individual.dna(chrsm).length();

    // Initialize counters for ID-generation
    auto rna_count = size_t{0};
    auto cds_count = size_t{0};

    auto region_handler = RegionHandler(
        seqid + (exp_setup->diploid() ? "-" + to_string(chrsm) : ""), chrsm_length, not exp_setup->linear_chrsm());

    // For each RNA, add corresponding features
    for (const auto& rna: individual.rnas(chrsm)) {
      auto rna_id = std::string("RNA_") + std::to_string(++rna_count);
      // ----- Add mRNA feature
      region_handler.add_feature(
          FeatureType::mRNA, rna.promoter_pos() + 1, PROM_SIZE + rna.length(), rna.strand(), rna_id);

      // ----- Add Promoter feature
      region_handler.add_feature(FeatureType::PROMOTER,
                                 rna.promoter_pos() + 1,
                                 PROM_SIZE,
                                 rna.strand(),
                                 std::string("Prom_") + std::to_string(rna_count),
                                 {{"Parent", rna_id}});

      // ----- Add Terminator feature
      // Compute terminator position from rna.end() (which returns the *last transcribed position*)
      auto terminator_pos =
          (rna.strand() == Strand::LEADING)
              ? mod(rna.end() - TERM_SIZE + 2, chrsm_length)  // +1 for "passed the end"; +1 for 1-based
              : mod(rna.end() + TERM_SIZE, chrsm_length);     // -1 for "passed the end"; +1 for 1-based
      region_handler.add_feature(FeatureType::TERMINATOR,
                                 terminator_pos,
                                 TERM_SIZE,
                                 rna.strand(),
                                 std::string("Term_") + std::to_string(rna_count),
                                 {{"Parent", rna_id}});

      // ----- Add CDS features
      for (const auto& protein: rna.protein_list()) {
        auto cds_id = std::string("CDS_") + std::to_string(++cds_count);
        region_handler.add_feature(FeatureType::CDS,
                                   protein->position_first_aa() + 1,
                                   protein->size() * 3,
                                   protein->strand(),
                                   cds_id,
                                   {{"Parent", rna_id}});
      }
    }

    // Write to file
    out << region_handler;
  }
}

}  // namespace gff3
}  // namespace aevol
