// ****************************************************************************
//
//          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_ABSTRACTSTATSHANDLER_H_
#define AEVOL_ABSTRACTSTATSHANDLER_H_

#include <charconv>
#include <fstream>
#include <iostream>

#include "AeTime.h"

namespace aevol {

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

  virtual void write_header() = 0;

 protected:
  std::ofstream statfile_;

  void prepare_empty(std::filesystem::path path);
  void prepare_for_resume(std::filesystem::path path, time_type generation);
};

inline void AbstractStatsHandler::prepare_empty(std::filesystem::path path) {
  statfile_.open(path, std::ofstream::trunc);
  if (not statfile_) {
    std::cerr << "failed to open " << path << std::endl;
    exit(1);
  }
  write_header();
}

inline void AbstractStatsHandler::prepare_for_resume(std::filesystem::path path, time_type generation) {
  auto tmp_file_path = path;
  tmp_file_path += ".tmp";

  std::filesystem::copy(path, tmp_file_path, std::filesystem::copy_options::overwrite_existing);

  auto tmp_statfile = std::ifstream(tmp_file_path, std::ifstream::in);
  statfile_.open(path, std::ofstream::trunc);
  if (not statfile_) {
    std::cerr << "failed to open " << path << std::endl;
    exit(1);
  }

  std::string str;

  // Copy file "header"
  std::getline(tmp_statfile, str);
  if (str != "") {
    statfile_ << str << "\n";
  }

  // Copy data up to the generation of interest
  auto gener = time_type{0};
  while (tmp_statfile) {
    std::getline(tmp_statfile, str);
    if (std::from_chars(str.data(), str.data() + str.size(), gener).ec == std::errc()) {
      if (gener <= generation) {
        statfile_ << str << "\n";
      } else {
        break;
      }
    }
  }

  tmp_statfile.close();

  statfile_.flush();
}

}  // namespace aevol

#endif  // AEVOL_ABSTRACTSTATSHANDLER_H_
