#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "restart-io.hh"

template <class ProgramState>
RestartBodyIO<ProgramState>::RestartBodyIO(HDF5::Grouplike &group, const size_t vertexCount, const size_t id)
    : id_(id),
      displacementWriter_(group, "displacement"+std::to_string(id_), vertexCount,
                          ProgramState::Vector::block_type::dimension),
      velocityWriter_(group, "velocity"+std::to_string(id_), vertexCount,
                      ProgramState::Vector::block_type::dimension),
      accelerationWriter_(group, "acceleration"+std::to_string(id_), vertexCount,
                          ProgramState::Vector::block_type::dimension),
      stateWriter_(group, "state"+std::to_string(id_), vertexCount),
      weightedNormalStressWriter_(group, "weightedNormalStress"+std::to_string(id_), vertexCount) {}

template <class ProgramState>
void RestartBodyIO<ProgramState>::write(const ProgramState& programState) {

  addEntry(displacementWriter_, programState.timeStep, programState.u[id_]);
  addEntry(velocityWriter_, programState.timeStep, programState.v[id_]);
  addEntry(accelerationWriter_, programState.timeStep, programState.a[id_]);
  addEntry(stateWriter_, programState.timeStep, programState.alpha[id_]);
  addEntry(weightedNormalStressWriter_, programState.timeStep,
           programState.weightedNormalStress[id_]);
}

template <class ProgramState>
void RestartBodyIO<ProgramState>::read(size_t timeStep,
                                   ProgramState& programState) {

  readEntry(displacementWriter_, timeStep, programState.u[id_]);
  readEntry(velocityWriter_, timeStep, programState.v[id_]);
  readEntry(accelerationWriter_, timeStep, programState.a[id_]);
  readEntry(stateWriter_, timeStep, programState.alpha[id_]);
  readEntry(weightedNormalStressWriter_, timeStep,
            programState.weightedNormalStress[id_]);
}

template <class ProgramState>
RestartIO<ProgramState>::RestartIO(HDF5::Grouplike& group, const std::vector<size_t>& vertexCounts)
    : bodyIO_(vertexCounts.size()),
      relativeTimeWriter_(group, "relativeTime"),
      relativeTimeIncrementWriter_(group, "relativeTimeIncrement") {

  for (size_t i=0; i<bodyIO_.size(); i++) {
    bodyIO_[i] = new RestartBodyIO<ProgramState>(group, vertexCounts[i], i);
  }
}

template <class ProgramState>
RestartIO<ProgramState>::~RestartIO() {
  for (size_t i=0; i<bodyIO_.size(); i++) {
    delete bodyIO_[i];
  }
}

template <class ProgramState>
void RestartIO<ProgramState>::write(ProgramState const &programState) {
  assert(programState.size() == bodyIO_.size());

  for (size_t i=0; i<bodyIO_.size(); i++) {
    bodyIO_[i]->write(programState);
  }

  addEntry(relativeTimeWriter_, programState.timeStep,
           programState.relativeTime);
  addEntry(relativeTimeIncrementWriter_, programState.timeStep,
           programState.relativeTau);
}

template <class ProgramState>
void RestartIO<ProgramState>::read(size_t timeStep,
                                   ProgramState& programState) {
  assert(programState.size() == bodyIO_.size());

  programState.timeStep = timeStep;

  for (size_t i=0; i<bodyIO_.size(); i++) {
    bodyIO_[i]->read(timeStep, programState);
  }

  readEntry(relativeTimeWriter_, timeStep, programState.relativeTime);
  readEntry(relativeTimeIncrementWriter_, timeStep, programState.relativeTau);
}

#include "restart-io_tmpl.cc"