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

#include <cassert>

#include "ExpSetup.h"
#include "utils.h"

namespace aevol {

MutationEvent::~MutationEvent() {
  if (seq_ != nullptr)
    delete[] seq_;
}

auto MutationEvent::make_switch(size_type pos) -> std::unique_ptr<MutationEvent> {
  #ifdef BASE_2
  auto obj = std::unique_ptr<MutationEvent>(new MutationEvent);

  obj->type_  = Type::SWITCH;
  obj->pos_1_ = pos;

  return obj;
  #else
  exit_with_dev_msg("calling 2b version of make_switch in 4b setting", __FILE__, __LINE__);
  // Suppress warnings
  (void)pos; exit(1);
  #endif
}

auto MutationEvent::make_switch(size_type pos, int8_t offset) -> std::unique_ptr<MutationEvent> {
  #ifdef BASE_4
  auto obj = std::unique_ptr<MutationEvent>(new MutationEvent);

  obj->type_  = Type::SWITCH;
  obj->pos_1_ = pos;
  obj->offset_ = offset;

  return obj;
  #else
  exit_with_dev_msg("calling 4b version of make_switch in 2b setting", __FILE__, __LINE__);
  // Suppress warnings
  (void)pos; (void)offset; exit(1);
  #endif
}

auto MutationEvent::make_small_insertion(size_type pos, size_type number, char* seq) -> std::unique_ptr<MutationEvent> {
  auto obj = std::unique_ptr<MutationEvent>(new MutationEvent);

  obj->type_  = Type::SMALL_INSERTION;
  obj->pos_1_ = pos;
  obj->number_ = number;
  obj->seq_    = seq;

  return obj;
}

auto MutationEvent::make_small_deletion(size_type pos, size_type number) -> std::unique_ptr<MutationEvent> {
  auto obj = std::unique_ptr<MutationEvent>(new MutationEvent);

  obj->type_  = Type::SMALL_DELETION;
  obj->pos_1_ = pos;
  obj->number_ = number;

  return obj;
}

auto MutationEvent::make_large_duplication(
    size_type pos1, size_type pos2, size_type pos3) -> std::unique_ptr<MutationEvent> {
  if (exp_setup->linear_chrsm()) {
    assert(pos1 < pos2);
  }

  auto obj = std::unique_ptr<MutationEvent>(new MutationEvent);

  obj->type_  = Type::DUPLICATION;
  obj->pos_1_ = pos1;
  obj->pos_2_ = pos2;
  obj->pos_3_ = pos3;

  return obj;
}

auto MutationEvent::make_large_deletion(size_type pos1, size_type pos2) -> std::unique_ptr<MutationEvent> {
  if (exp_setup->linear_chrsm()) {
    assert(pos1 < pos2);
  }

  auto obj = std::unique_ptr<MutationEvent>(new MutationEvent);

  obj->type_  = Type::DELETION;
  obj->pos_1_ = pos1;
  obj->pos_2_ = pos2;

  return obj;
}

auto MutationEvent::make_translocation(
    size_type pos1, size_type pos2, size_type pos3, size_type pos4, bool invert) -> std::unique_ptr<MutationEvent> {
  if (exp_setup->linear_chrsm()) {
    assert(pos1 < pos2);
  }

  auto obj = std::unique_ptr<MutationEvent>(new MutationEvent);

  obj->type_  = Type::TRANSLOCATION;
  obj->pos_1_ = pos1;
  obj->pos_2_ = pos2;
  obj->pos_3_ = pos3;
  obj->pos_4_ = pos4;
  obj->invert_ = invert;

  return obj;
}

auto MutationEvent::make_inversion(
    size_type pos1, size_type pos2) -> std::unique_ptr<MutationEvent> {
  if (exp_setup->linear_chrsm()) {
    assert(pos1 < pos2);
  }

  auto obj = std::unique_ptr<MutationEvent>(new MutationEvent);

  obj->type_  = Type::INVERSION;
  obj->pos_1_ = pos1;
  obj->pos_2_ = pos2;

  return obj;
}

}  // namespace aevol
