//#####################################################################
// Copyright 2002-2009, Ron Fedkiw, Eilene Hao, Geoffrey Irving, Michael Lentine, Neil Molino, Joseph Teran, Robert Bridson, Andrew Selle, Zhaosheng Bao.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class MESH_OBJECT_BASE
//##################################################################### 
#ifndef __MESH_OBJECT_BASE__
#define __MESH_OBJECT_BASE__

#include <Core/Basic_Geometry/BASIC_GEOMETRY_FORWARD.h>
#include <Core/Geometry_Particles/GEOMETRY_PARTICLES.h>
#include <Core/Meshes/MESHES_FORWARD.h>
#include <Core/Meshes/STRUCTURE.h>
#include <Core/Spatial_Acceleration/SPATIAL_ACCELERATION_FORWARD.h>
namespace PhysBAM{
template<class TV> class RAY;
template<class TV> class RAY_HIT;
template<class TV> class RANGE;

template<class TV,class T_MESH>
class MESH_OBJECT_BASE:public STRUCTURE<TV>
{
    typedef typename TV::SCALAR T;
    typedef VECTOR<int,TV::m> IV;
    static_assert((is_same<VECTOR<T,TV::m>,TV>::value));
public:
    enum WORKAROUND1 {dimension=T_MESH::dimension};
    typedef T_MESH MESH;
    typedef MESH_OBJECT<TV,dimension> T_DERIVED_OBJECT;

    T_MESH& mesh;
    GEOMETRY_PARTICLES<TV>& particles;
    RANGE<TV>* bounding_box;
    PARTICLE_PARTITION<TV>* particle_partition;
    IV desired_particle_partition_counts;
    bool need_destroy_mesh,need_destroy_particles;
    MESH_HIERARCHY<TV,T_MESH>* hierarchy=0;
  protected:
    MESH_OBJECT_BASE(T_MESH& mesh_input,GEOMETRY_PARTICLES<TV>& particles_input);
    virtual ~MESH_OBJECT_BASE();
public:

    void Discard_Valence_Zero_Particles_And_Renumber()
    {ARRAY<int> condensation_mapping;Discard_Valence_Zero_Particles_And_Renumber(condensation_mapping);}

    void Set_Desired_Particle_Partition_Size(const IV& counts)
    {desired_particle_partition_counts=counts;}

    void Own_Mesh()
    {need_destroy_mesh=true;}

    void Own_Particles()
    {need_destroy_particles=true;}

    void Read(TYPED_ISTREAM& input) override;
    void Write(TYPED_OSTREAM& output) const override;
    void Read_Obj(const std::string& filename,
        ARRAY<VECTOR<T,2> >* uv_v=0,
        ARRAY<typename T_MESH::ELEMENT_TYPE>* uv_f=0);
    void Write_Obj(const std::string& filename,
        ARRAY_VIEW<const VECTOR<T,2> > uv_v={},
        ARRAY_VIEW<const typename T_MESH::ELEMENT_TYPE> uv_f={});

//#####################################################################
    virtual void Clean_Memory();
    static T_DERIVED_OBJECT* Create();
    static T_DERIVED_OBJECT* Create(GEOMETRY_PARTICLES<TV>& particles);
    virtual void Refresh_Auxiliary_Structures() final;
    void Update_Number_Nodes() override;
    void Update_Bounding_Box();
    void Initialize_Particle_Partition(const IV& counts=IV());
    STRUCTURE<TV>* Append_Particles_And_Create_Copy(GEOMETRY_PARTICLES<TV>& new_particles,ARRAY<int>* particle_indices=0) const override; // number_nodes must be set elsewhere
    void Discard_Valence_Zero_Particles_And_Renumber(ARRAY<int>& condensation_mapping);
    static T_DERIVED_OBJECT* Union_Mesh_Objects_Relatively(const ARRAY<T_DERIVED_OBJECT*>& object_list,const ARRAY<FRAME<TV> >& relative_frames);
    static void Union_Mesh_Objects_Relatively(T_DERIVED_OBJECT* object,const ARRAY<T_DERIVED_OBJECT*>& object_list,const ARRAY<FRAME<TV> >& relative_frames);
    void Mark_Nodes_Referenced(ARRAY<int>& marks,const int mark) const override;
    T Volumetric_Volume();
    void Compact_Copy(const MESH_OBJECT_BASE& obj,ARRAY<int>* mapping=0);
    void Initialize_Hierarchy(const bool update_boxes=true);
    
private:
    virtual void Refresh_Auxiliary_Structures_Helper()=0;
//#####################################################################
};
template<class T> class RAY_HIT;
template<class TV> class RAY;

template<class T,int d,int s> RAY_HIT<T>
Intersects(const RAY<VECTOR<T,d> >& ray,const MESH_OBJECT<VECTOR<T,d>,s>& mo,
    T thickness_over_two=0);
}
#endif
