#ifndef PARTICLESYS_H
#define PARTICLESYS_H

#include "rcpointer.h"
#include "odesolver.h"
#include "force.h"
#include "vl/VLd.h"
#include <vector>

class ParticleFunc : public OdeFunc2
{
public:
    ParticleFunc(
        const std::vector<RcPointer<Force> > &forces,
        const Vecd &mass);

    Vecd        operator()(const Vecd &x, const Vecd &v) const;
    SparseMatd  dx(const Vecd &x, const Vecd &v) const;
    SparseMatd  dv(const Vecd &x, const Vecd &v) const;

    std::vector<RcPointer<Force> > _forces;
  
  double max_displacement(const Vecd &x) const;
  
    Vecd _mass;
};

class ParticleSys
{
public:
	// initialize with particles etc
    ParticleSys(
        const std::vector<Vec3d>  &positions,
        const std::vector<Vec3d>  &velocities,
        const std::vector<double> &masses,
        const std::vector< RcPointer<Force> > &forces,
        const RcPointer<OdeSolver2> &solver
        );

	~ParticleSys() {}

    // if you want to tweak with forces after construction
    // you should just mess with the pointers that you hold.
    std::vector<Vec3d>   getPositions() const;
    std::vector<Vec3d>   getVelocities() const;
    std::vector<double>  getMasses() const;
    
    void setPosition(int p, const Vec3d &v);
    void setVelocity(int p, const Vec3d &v);
    void setMass(int p, double m);

  // Main routine
  void step(double h, double max_allowed_displacement = 0.0);
  
    double max_displacement() const {
      return (_pf->max_displacement(_x));
    }
  
private:
  Vecd         _x;
  Vecd         _v;
  
    RcPointer<ParticleFunc> _pf;
    RcPointer<OdeSolver2>    _solver;
};

#endif
