//#####################################################################
// Copyright 2006-2007, Geoffrey Irving, Nipun Kwatra, Andrew Selle, Jonathan Su.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class STRUCTURE_INTERACTION_GEOMETRY
//#####################################################################
#ifndef __STRUCTURE_INTERACTION_GEOMETRY__
#define __STRUCTURE_INTERACTION_GEOMETRY__

#include <Core/Arrays/INDIRECT_ARRAY.h>
#include <Core/Geometry_Particles/GEOMETRY_PARTICLES.h>
#include <Core/Log/DEBUG_UTILITIES.h>
#include <Core/Meshes/POINT_SIMPLICES_1D.h>
#include <Core/Meshes/SEGMENTED_CURVE.h>
#include <Core/Meshes/TRIANGULATED_SURFACE.h>
#include <Core/Spatial_Acceleration/PARTICLE_HIERARCHY.h>
#include <Core/Spatial_Acceleration/SPATIAL_ACCELERATION_FORWARD.h>
namespace PhysBAM{

template<class TV>
class STRUCTURE_INTERACTION_GEOMETRY
{
    typedef typename TV::SCALAR T;
    enum WORKAROUND {d=TV::m};
    struct UNUSABLE{};
    typedef MESH_OBJECT<TV,1> T_SEGMENTED_CURVE;
public:
    GEOMETRY_PARTICLES<TV>& full_particles;
    ARRAY<int> active_indices;
    TRIANGULATED_SURFACE<T>* triangulated_surface;
    T_SEGMENTED_CURVE* segmented_curve;
    POINT_SIMPLICES_1D<T>* point_simplices;
    INDIRECT_ARRAY<ARRAY_VIEW<TV> > subset;
    PARTICLE_HIERARCHY<TV,INDIRECT_ARRAY<ARRAY_VIEW<TV> > > particle_hierarchy;
    ARRAY<bool> triangulated_surface_modified,segmented_curve_modified,point_modified; // whether boxes below you have been modified
private:
    bool need_destroy_segmented_curve;
    UNUSABLE unusable;
public:

    STRUCTURE_INTERACTION_GEOMETRY(GEOMETRY_PARTICLES<TV>& full_particles_input)
        :full_particles(full_particles_input),triangulated_surface(0),segmented_curve(0),point_simplices(0),
        subset(full_particles.X,active_indices),particle_hierarchy(subset,false),need_destroy_segmented_curve(false)
    {}

    ~STRUCTURE_INTERACTION_GEOMETRY()
    {Clean_Memory();}

    void Clean_Memory()
    {if(need_destroy_segmented_curve) delete segmented_curve;need_destroy_segmented_curve=false;
    active_indices.Clean_Memory();triangulated_surface=0;segmented_curve=0;point_simplices=0;particle_hierarchy.Clean_Memory();}

    void Build_Topological_Structure_Of_Hierarchies()
    {if(triangulated_surface) triangulated_surface->Initialize_Hierarchy(false);
    if(segmented_curve) segmented_curve->Initialize_Hierarchy(false);
    subset.array.Set(full_particles.X);
    particle_hierarchy.Compute(true);}

    const typename conditional<d==2,ARRAY<int>,typename conditional<d==3,ARRAY<VECTOR<int,2> >,UNUSABLE>::type>::type& Edges() const
    {
        if constexpr(d==1) return unusable;
        else if constexpr(d==2) return active_indices;
        else return segmented_curve->mesh.elements;
    }

    const MESH_OBJECT<TV,d-1>* Face_Mesh_Object() const
    {
        if constexpr(d==1) return point_simplices;
        else if constexpr(d==2) return segmented_curve;
        else return triangulated_surface;
    }

    const ARRAY<bool>& Edge_Modified() const
    {return d==2?point_modified:segmented_curve_modified;}

    const ARRAY<bool>& Face_Modified() const
    {return d==2?segmented_curve_modified:triangulated_surface_modified;}

    MESH_HIERARCHY<TV,SIMPLEX_MESH<d-1> >& Face_Hierarchy() const
    {return *Face_Mesh_Object()->hierarchy;}

    bool Has_Edges() const
    {return d==2 || segmented_curve!=0;}

    const auto&
    Edge_Hierarchy() const
    {
        if constexpr(d==1) return unusable;
        else if constexpr(d==2) return particle_hierarchy;
        else return *segmented_curve->hierarchy;
    }

//#####################################################################
    static TRIANGULATED_SURFACE<T>* Triangulated_Surface(STRUCTURE<TV>* structure);
    static T_SEGMENTED_CURVE* Segmented_Curve(STRUCTURE<TV>* structure);
    bool Build_Collision_Geometry(STRUCTURE<TV>& structure);
    void Update_Faces_And_Hierarchies_With_Collision_Free_Positions(ARRAY_VIEW<const T> node_thickness,const T node_thickness_multiplier,ARRAY_VIEW<const TV> X_old_full);
//#####################################################################
};
}
#endif
