// ****************************************************************************
//
//          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_MUTATION_H_
#define AEVOL_MUTATION_H_

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

#include <zlib.h>

namespace aevol {

class MutationReport {
 public :
  enum class Type;

  MutationReport() = default;
  MutationReport(const MutationReport& model) = default;
  MutationReport(MutationReport&& model) = delete;
  MutationReport& operator=(const MutationReport& other) = delete;
  MutationReport& operator=(MutationReport&& other) = delete;

  virtual ~MutationReport() noexcept = default;

  virtual auto Clone() const -> std::unique_ptr<MutationReport> = 0;
  static auto Load(gzFile tree_file) -> std::unique_ptr<MutationReport>;

  virtual void save(gzFile tree_file) const = 0;
  virtual void load(gzFile tree_file) = 0;

  virtual auto mut_type() const -> MutationReport::Type = 0;
  virtual bool is_local_mut() const { return false; };
  virtual bool is_rear() const { return false; };
  virtual bool is_ht() const { return false; };

  virtual auto pos1() const -> int32_t { return -1; }
  virtual auto pos2() const -> int32_t { return -1; }
  virtual auto pos3() const -> int32_t { return -1; }
  virtual auto pos4() const -> int32_t { return -1; }
  virtual auto sequence() const -> std::string { return ""; }
  virtual auto invert() const -> int8_t { return -1; }
  virtual auto align_score() const -> int16_t { return -1; }
  virtual auto align_score_2() const -> int16_t { return -1; }
  virtual auto length() const -> int32_t { return -1; }
  virtual auto repl_seg_len() const -> int32_t { return -1; }
};

enum class MutationReport::Type {
  // Simple mutation types.
  SWITCH  = 0,
  S_INS,
  S_DEL,
  DUPL,
  DEL,
  TRANS,
  INV,
  INSERT,
  INS_HT,
  REPL_HT,

  // Composite mutation types follow. They represent categories of
  // several simple mutation types. Therefore, they should not be used
  // as array index for counters.
  //
  // The composite mutations should extend MutationType but
  // C++ enums can't be inherited directly.
  S_MUT, // SWITCH or S_INS or S_DEL
  REARR, // DUPL or DEL or TRANS or INV
  H_T,    // INS_HT or REPL_HT
  INDEL  // S_INS or S_DEL
};

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

} // namespace aevol

#endif // AEVOL_MUTATION_H_
