#ifndef FORCE_BRAID_HPP_INCLUDED
#define FORCE_BRAID_HPP_INDLUDED
#include <force.hpp>
#include <drum_parameters_braid.hpp>
#include <drum_variables_braid.hpp>
#include <drum.hpp>

//This force is to be used with params_t = DrumParametersBraid, vars_t = DrumVariablesBraid.

template <typename value_t, typename params_t, typename vars_t, typename buffer_t>
class ForceBraid: public Force<value_t, params_t, vars_t, buffer_t>{
public:
  ForceBraid() = default;
  ~ForceBraid() = default;

  value_t operator()(
  const Drum<value_t, params_t, vars_t, buffer_t>& drum,          //Drum we're calculating the force on
  const Drum<value_t, params_t, vars_t, buffer_t>& neighbour0,    //Neighbour 0
  const Drum<value_t, params_t, vars_t, buffer_t>& neighbour1,    //Neighbour 1
  const Drum<value_t, params_t, vars_t, buffer_t>& neighbour2,    //Neighbour 2
  const value_t time) const noexcept final override
  {
    //fetch data
    //note that no copying is done here, these are all references
    //TODO: implement drive
    const params_t& drum_params = drum.get_parameters(); //parameters of drum
    const vars_t& drum_vars = drum.get_variables();      //variables of drum
    const vars_t& n0_vars = neighbour0.get_variables();  //variables of neighbour 0
    const vars_t& n1_vars = neighbour1.get_variables();  //variables of neighbour 1
    const vars_t& n2_vars = neighbour2.get_variables();  //variables of neighbour 2

    value_t part1 = - drum_params.k0 * drum_vars.x_temp;
    value_t part2 = - drum_params.c * drum_vars.xdot_temp;
    value_t part3 = 0.;
    part3 -= drum_params.k1 + drum_params.k2 * n0_vars.t0 * n0_vars.x_temp;
    part3 -= drum_params.k1 + drum_params.k2 * n1_vars.t1 * n1_vars.x_temp;
    part3 -= drum_params.k1 + drum_params.k2 * n2_vars.t2 * n2_vars.x_temp;

    return part1 + part2 + part3;
  }
};


#endif