// ****************************************************************************
//
//          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_GFF3_REGION_SEQUENCE_HANDLER_H_
#define AEVOL_GFF3_REGION_SEQUENCE_HANDLER_H_

#include <array>
#include <map>
#include <ranges>
#include <optional>
#include <string>
#include <vector>

#include "ae_types.h"
#include "Dna.h"
#include "Feature.h"
#include "FeatureType.h"
#include "Strand.h"
#include "utility.h"

namespace aevol {
namespace gff3 {

class RegionHandler {
 public:
  RegionHandler()                                = delete;
  RegionHandler(const RegionHandler&)            = delete;
  RegionHandler(RegionHandler&&)                 = delete;
  RegionHandler& operator=(const RegionHandler&) = delete;
  RegionHandler& operator=(RegionHandler&&)      = delete;
  virtual ~RegionHandler()                       = default;

  RegionHandler(std::string seqid, dna_size_type size, bool circular);

  const auto& seqid() const { return seqid_; }
  auto start() const { return decltype(size_){1}; }
  auto end() const { return size_ + 1; }
  const auto& root_feature() const { return root_feature_; }
  auto features(Strand strand) const {
    return std::views::transform(features_[std::to_underlying(strand)], value_as_const_ref);
  }

  void add_feature(const FeatureType type,
                   dna_size_type start,
                   dna_size_type size,
                   Strand strand,
                   std::optional<std::string> id = std::nullopt,
                   std::map<std::string, std::string> attributes = {});

 protected:
  std::string seqid_;
  dna_size_type size_ = 0;
  Feature root_feature_;
  std::array<std::map<std::pair<dna_size_type, FeatureType>, Feature>, 2> features_ = {};

  static auto value_as_const_ref(const decltype(features_)::value_type::value_type& ref) -> const Feature& {
    return ref.second;
  }
};

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

}  // namespace gff3
}  // namespace aevol

#endif  // AEVOL_GFF3_REGION_SEQUENCE_HANDLER_H_
