//#####################################################################
// Copyright 2007, Geoffrey Irving, Craig Schroeder, Andrew Selle.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class ANGLE_SPRINGS
//#####################################################################
#ifndef __ANGLE_SPRINGS__
#define __ANGLE_SPRINGS__

#include <Core/Matrices/MATRIX.h>
#include <Deformables/Forces/DEFORMABLES_FORCES.h>
#include <cfloat>
namespace PhysBAM{

template<class TV>
class ANGLE_SPRINGS:public DEFORMABLES_FORCES<TV>
{
    typedef typename TV::SCALAR T;
    enum WORKAROUND {d=TV::m};
public:
    typedef DEFORMABLES_FORCES<TV> BASE;
    using BASE::particles;
    typedef typename BASE::FREQUENCY_DATA FREQUENCY_DATA;

    SIMPLEX_MESH<d-1>& mesh;
    T stiffness=0;

    struct DATA
    {
        VECTOR<int,TV::m+1> e;
        T rest_angle=0;
        T E=0;
        VECTOR<TV,TV::m+1> dE;
        MATRIX<MATRIX<T,TV::m>,TV::m+1> ddE;
    };

    ARRAY<DATA> data;
    
    ANGLE_SPRINGS(DEFORMABLE_PARTICLES<TV>& particles,SIMPLEX_MESH<d-1>& mesh);
    ~ANGLE_SPRINGS()=default;

    T CFL_Strain_Rate() const override
    {return FLT_MAX;}

    void Initialize_CFL(ARRAY_VIEW<FREQUENCY_DATA> frequency) override
    {}

//#####################################################################
    void Update_Position_Based_State(const T time,const bool is_position_update,const bool update_hessian) override;
    void Add_Dependencies(SEGMENT_MESH& dependency_mesh) const override;
    void Update_Mpi(const ARRAY<bool>& particle_is_simulated) override;
    void Add_Forces(ARRAY_VIEW<TV> F,const T time) const override;
    void Add_Velocity_Dependent_Forces(ARRAY_VIEW<const TV> V,ARRAY_VIEW<TV> F,const T time) const override;
    T Potential_Energy(const T time) const override;
    void Add_Force_Derivatives(ARRAY_VIEW<const TV> V,ARRAY_VIEW<TV> F,const T time,bool transpose=false) const override;
private:
    void Update_Mesh();
//#####################################################################
};

template<class TV> ANGLE_SPRINGS<TV>*
Create_Angle_Springs(DEFORMABLE_PARTICLES<TV>& particles,
    SIMPLEX_MESH<TV::m-1>& mesh,
    const typename TV::SCALAR stiffness)
{
    ANGLE_SPRINGS<TV>* bend=new ANGLE_SPRINGS<TV>(particles,mesh);
    bend->stiffness=stiffness;
    return bend;
}

template<class T_OBJECT> ANGLE_SPRINGS<typename T_OBJECT::VECTOR_T>*
Create_Angle_Springs(T_OBJECT& object,const typename T_OBJECT::VECTOR_T::SCALAR stiffness)
{
    return Create_Angle_Springs(dynamic_cast<DEFORMABLE_PARTICLES<typename T_OBJECT::VECTOR_T>&>(object.particles),object.mesh,stiffness);
}

}
#endif
