//#####################################################################
// 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
//#####################################################################
#include <Deformables/Collisions_And_Interactions/STRUCTURE_INTERACTION_GEOMETRY.h>
#include <Core/Arrays/INDIRECT_ARRAY.h>
#include <Core/Data_Structures/HASHTABLE.h>
#include <Core/Math_Tools/RANGE.h>
#include <Core/Meshes/TETRAHEDRALIZED_VOLUME.h>
#include <Core/Read_Write/READ_WRITE.h>
#include <Core/Spatial_Acceleration/MESH_HIERARCHY.h>
#include <Deformables/Fracture/EMBEDDING.h>
#include <Deformables/Particles/FREE_PARTICLES.h>
using namespace PhysBAM;
//#####################################################################
// Function Segmented_Curve
//#####################################################################
template<class TV> MESH_OBJECT<TV,1>* STRUCTURE_INTERACTION_GEOMETRY<TV>::
Segmented_Curve(STRUCTURE<TV>* structure)
{
    if(T_SEGMENTED_CURVE* segmented_curve=dynamic_cast<T_SEGMENTED_CURVE*>(structure)) return segmented_curve;
    else return 0;
}
//#####################################################################
// Function Triangulated_Surface
//#####################################################################
template<class TV> TRIANGULATED_SURFACE<typename TV::SCALAR>* STRUCTURE_INTERACTION_GEOMETRY<TV>::
Triangulated_Surface(STRUCTURE<TV>* structure)
{
    if(TV::m==2) return 0;
    if(TRIANGULATED_SURFACE<T>* triangulated_surface=dynamic_cast<TRIANGULATED_SURFACE<T>*>(structure))
        return triangulated_surface;
    else if(TETRAHEDRALIZED_VOLUME<T>* tetrahedralized_volume=dynamic_cast<TETRAHEDRALIZED_VOLUME<T>*>(structure)){
        if(!tetrahedralized_volume->triangulated_surface) tetrahedralized_volume->Initialize_Triangulated_Surface();
        return tetrahedralized_volume->triangulated_surface;} // TODO: This is broken; long term shallow copy of a temporary auxiliary structure
    else if(EMBEDDING<VECTOR<T,3> >* embedding=dynamic_cast<EMBEDDING<VECTOR<T,3> >*>(structure))
        return &embedding->material_surface;
    else return 0;
}
//#####################################################################
// Function Build_Collision_Geometry
//#####################################################################
template<class TV> bool STRUCTURE_INTERACTION_GEOMETRY<TV>::
Build_Collision_Geometry(STRUCTURE<TV>& structure)
{
    Clean_Memory();
    if((segmented_curve=Segmented_Curve(&structure)))
        active_indices=Get_Unique(segmented_curve->mesh.elements.Flattened());
    else if((triangulated_surface=Triangulated_Surface(&structure))){

        active_indices=Get_Unique(triangulated_surface->mesh.elements.Flattened());
        triangulated_surface->Update_Number_Nodes();
        if(!triangulated_surface->mesh.segment_mesh) triangulated_surface->mesh.Initialize_Segment_Mesh();
        segmented_curve=new T_SEGMENTED_CURVE(*triangulated_surface->mesh.segment_mesh,full_particles); // TODO: This is broken; long term shallow copy of a temporary auxiliary structure
        need_destroy_segmented_curve=true;}
    else if(FREE_PARTICLES<TV>* free_particles=dynamic_cast<FREE_PARTICLES<TV>*>(&structure))
        active_indices=free_particles->nodes;
    else PHYSBAM_FATAL_ERROR();
    if(segmented_curve && !segmented_curve->mesh.incident_elements) segmented_curve->mesh.Initialize_Incident_Elements();
    Build_Topological_Structure_Of_Hierarchies();
    return true;
}
//#####################################################################
// Function Update_Faces_And_Hierarchies_With_Collision_Free_Positions
//#####################################################################
template<class T,class TV> void Update_Faces_And_Hierarchies_With_Collision_Free_Positions_Helper(TRIANGULATED_SURFACE<T>& triangulated_surface,ARRAY_VIEW<const T> node_thickness,
    const T node_thickness_multiplier,ARRAY_VIEW<const TV> X_old_full)
{}
template<class T> void Update_Faces_And_Hierarchies_With_Collision_Free_Positions_Helper(TRIANGULATED_SURFACE<T>& triangulated_surface,ARRAY_VIEW<const T> node_thickness,
    const T node_thickness_multiplier,ARRAY_VIEW<const VECTOR<T,3> > X_old_full)
{
    typedef VECTOR<T,3> TV;
    triangulated_surface.Update_Triangle_List(X_old_full);
    const auto& elements=triangulated_surface.mesh.elements;
    ARRAY<RANGE<TV> > ranges(elements.m);
    for(int i=0;i<elements.m;i++)
        ranges(i)=RANGE<TV>::Bounding_Box(X_old_full.Subset(elements(i))).
            Thickened(node_thickness_multiplier*node_thickness.Subset(elements(i)).Min());
    triangulated_surface.hierarchy->Compute(ranges,false);
}
template<class TV> void STRUCTURE_INTERACTION_GEOMETRY<TV>::
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)
{
    PHYSBAM_ASSERT(node_thickness.Size()==full_particles.Size());
    PHYSBAM_ASSERT(node_thickness_multiplier>=1);
    if(segmented_curve)
    {
        const auto& elements=segmented_curve->mesh.elements;
        ARRAY<RANGE<TV> > ranges(elements.m);
        for(int i=0;i<elements.m;i++)
            ranges(i)=RANGE<TV>::Bounding_Box(X_old_full.Subset(elements(i))).
                Thickened(node_thickness_multiplier*node_thickness.Subset(elements(i)).Min());
        segmented_curve->hierarchy->Compute(ranges,false);
    }
    if(d==3 && triangulated_surface)
        Update_Faces_And_Hierarchies_With_Collision_Free_Positions_Helper(
            *triangulated_surface,node_thickness,node_thickness_multiplier,X_old_full);

    ARRAY<RANGE<TV> > ranges(active_indices.m);
    for(int i=0;i<active_indices.m;i++)
        ranges(i)=RANGE<TV>(X_old_full(active_indices(i))).
            Thickened(node_thickness_multiplier*node_thickness(active_indices(i)));
    particle_hierarchy.Compute(ranges,false);
}
//####################################################################
namespace PhysBAM{
template class STRUCTURE_INTERACTION_GEOMETRY<VECTOR<float,1> >;
template class STRUCTURE_INTERACTION_GEOMETRY<VECTOR<float,2> >;
template class STRUCTURE_INTERACTION_GEOMETRY<VECTOR<float,3> >;
template class STRUCTURE_INTERACTION_GEOMETRY<VECTOR<double,1> >;
template class STRUCTURE_INTERACTION_GEOMETRY<VECTOR<double,2> >;
template class STRUCTURE_INTERACTION_GEOMETRY<VECTOR<double,3> >;
}
