//#####################################################################
// Copyright 2003-2009, Zhaosheng Bao, Ronald Fedkiw, Geoffrey Irving, Igor Neverov, Craig Schroeder, Andrew Selle, Tamar Shinar, Eftychios Sifakis, Jonthan Su.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class DEFORMABLE_BODY_COLLECTION
//#####################################################################
#ifndef __DEFORMABLE_BODY_COLLECTION__
#define __DEFORMABLE_BODY_COLLECTION__

#include <Core/Arrays/ARRAY.h>
#include <Core/Read_Write/STREAM_TYPE.h>
#include <Rigids/Rigid_Bodies/Find_Type.h>
#include <Deformables/Forces/DEFORMABLES_FORCES.h>
namespace PhysBAM{

template<class TV> class BINDING_LIST;
template<class TV> class COLLISION_BODY_COLLECTION;
template<class TV> class DEFORMABLE_OBJECT_COLLISIONS;
template<class TV> class DEFORMABLE_PARTICLES;
template<class TV> class SOFT_BINDINGS;
template<class TV> class TRIANGLE_REPULSIONS;
template<class TV> class TRIANGLE_COLLISIONS;
template<class TV> class TRIANGLE_REPULSIONS_AND_COLLISIONS_GEOMETRY;
template<class TV> class COLLISION_PENALTY_FORCES;
template<class TV> class DEFORMABLES_EXAMPLE_FORCES_AND_VELOCITIES;
template<class TV> class DEFORMABLES_FORCES;
template<class TV> class TRIANGLE_COLLISION_PARAMETERS;
template<class TV> class STRUCTURE;
struct VIEWER_DIR;
class VIEWER_OUTPUT;

template<class TV>
class DEFORMABLE_BODY_COLLECTION
{
    typedef typename TV::SCALAR T;
    typedef typename DEFORMABLES_FORCES<TV>::FREQUENCY_DATA T_FREQUENCY_DEFORMABLE;
public:
    DEFORMABLE_PARTICLES<TV>& particles;
    ARRAY<STRUCTURE<TV>*> structures;

    int Add_Structure(STRUCTURE<TV>* structure)
    {return structures.Append(structure);}

    template<class T_STRUCTURE> T_STRUCTURE
    Find_Structure(const int index=0)
    {return Find_Type<T_STRUCTURE>(structures,index);}

    template<class T_STRUCTURE> const T_STRUCTURE
    Find_Structure(const int index=0) const
    {return Find_Type<T_STRUCTURE>(structures,index);}

    bool simulate;

    ARRAY<int> simulated_particles;
    ARRAY<int> dynamic_particles;

    BINDING_LIST<TV>& binding_list;
    SOFT_BINDINGS<TV>& soft_bindings;
    ARRAY<DEFORMABLES_FORCES<TV>*> deformables_forces;

    ARRAY<T_FREQUENCY_DEFORMABLE> frequency; // hertz for deformable CFL
    T cfl_number;
    T cfl_elastic,cfl_damping;
    bool implicit_damping;

    bool print_diagnostics;
    bool print_residuals;
    bool print_energy;
    int iterations_used_diagnostic;

    TRIANGLE_REPULSIONS_AND_COLLISIONS_GEOMETRY<TV>& triangle_repulsions_and_collisions_geometry;
    TRIANGLE_REPULSIONS<TV>& triangle_repulsions;
    TRIANGLE_COLLISIONS<TV>& triangle_collisions;
    DEFORMABLE_OBJECT_COLLISIONS<TV>& collisions;
    ARRAY<COLLISION_PENALTY_FORCES<TV>*> collision_penalty_forces;
    bool use_embedded_collisions;
    bool use_nonembedded_self_collision;
    bool own_particles,own_collision_body_collection;

    DEFORMABLE_BODY_COLLECTION(DEFORMABLE_PARTICLES<TV>* particles=0,COLLISION_BODY_COLLECTION<TV>* collision_body_list=0);
    DEFORMABLE_BODY_COLLECTION(const DEFORMABLE_BODY_COLLECTION&) = delete;
    void operator=(const DEFORMABLE_BODY_COLLECTION&) = delete;
    virtual ~DEFORMABLE_BODY_COLLECTION();

    template<class T_FORCE> T_FORCE
    Find_Force(const int index=0)
    {return Find_Type<T_FORCE>(deformables_forces,index);}

    template<class T_FORCE> const T_FORCE
    Find_Force(const int index=0) const
    {return Find_Type<T_FORCE>(deformables_forces,index);}

//#####################################################################
    void Set_CFL_Number(const T cfl_number_input=.5);
    int Add_Force(DEFORMABLES_FORCES<TV>* force);
    void Initialize(TRIANGLE_COLLISION_PARAMETERS<TV>& triangle_collisions_parameters);
    void Update_Collision_Penalty_Forces_And_Derivatives();
    void Read_Static_Variables(const VIEWER_DIR& viewer_dir);
    void Write_Static_Variables(const STREAM_TYPE stream_type,const VIEWER_DIR& viewer_dir,bool static_variables_every_frame) const;
    void Read_Dynamic_Variables(const VIEWER_DIR& viewer_dir);
    void Write_Dynamic_Variables(const STREAM_TYPE stream_type,const VIEWER_DIR& viewer_dir) const;
    void Update_Simulated_Particles();
    void Update_CFL();
    T CFL(const bool verbose=false);
    T CFL_Elastic_And_Damping();
    T CFL_Elastic();
    T CFL_Damping();
    T CFL_Strain_Rate();

    void Update_Position_Based_State(const T time,const bool is_position_update,const bool update_hessian);
    void Add_Forces(ARRAY_VIEW<TV> F_full,const T time) const;
    void Add_Velocity_Dependent_Forces(ARRAY_VIEW<const TV> V_full,ARRAY_VIEW<TV> F_full,const T time) const;
    void Add_Force_Derivatives(ARRAY_VIEW<const TV> V_full,ARRAY_VIEW<TV> F_full,const T time,bool transpose=false) const;

    void Test_Forces(const T time);
    void Read(const VIEWER_DIR& viewer_dir,const bool read_static_variables);
    void Write(const STREAM_TYPE,const VIEWER_DIR& viewer_dir,const bool static_variables_every_frame,const bool write_from_every_process=true) const;
    void Register_Output_Files(VIEWER_OUTPUT& viewer_output);
    void Compute_Auxiliary_Attributes();
    void Compute_Auxiliary_Attributes(const ARRAY<int>& indices,const bool copy_existing_elements=true);
//#####################################################################
};
}
#endif
