//#####################################################################
// Copyright 2002-2009, Robert Bridson, Ronald Fedkiw, Jon Gretarsson, Geoffrey Irving, Sergey Koltakov, Nipun Kwatra, Frank Losasso, Neil Molino, Eftychios Sifakis, Jerry Talton.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class SEGMENT_MESH
//#####################################################################
#include <Core/Meshes/SEGMENT_MESH.h>
#include <Core/Data_Structures/UNION_FIND.h>
#include <Core/Meshes/POINT_SIMPLEX_MESH.h>
using namespace PhysBAM;
//#####################################################################
// Constructor
//#####################################################################
SIMPLEX_MESH<1>::
SIMPLEX_MESH()
    :connected_segments(0),ordered_loop_nodes(0),boundary_mesh(0)
{}
//#####################################################################
// Constructor
//#####################################################################
SIMPLEX_MESH<1>::
SIMPLEX_MESH(const int number_nodes_input,const ARRAY<VECTOR<int,2> >& segment_list)
    :SIMPLEX_MESH_BASE<1>(number_nodes_input,segment_list),connected_segments(0),ordered_loop_nodes(0),boundary_mesh(0)
{}
//#####################################################################
// Constructor
//#####################################################################
SIMPLEX_MESH<1>::
SIMPLEX_MESH(const SIMPLEX_MESH& segment_mesh)
    :SIMPLEX_MESH_BASE<1>(segment_mesh),connected_segments(0),ordered_loop_nodes(0),boundary_mesh(0)
{}
//#####################################################################
// Destructor
//#####################################################################
SIMPLEX_MESH<1>::
~SIMPLEX_MESH()
{
    delete connected_segments;
    delete ordered_loop_nodes;
}
//#####################################################################
// Function Delete_Auxiliary_Structures
//#####################################################################
void SIMPLEX_MESH<1>::
Delete_Auxiliary_Structures()
{
    SIMPLEX_MESH_BASE<1>::Delete_Auxiliary_Structures();
    delete connected_segments;
    connected_segments=0;
    delete ordered_loop_nodes;
    ordered_loop_nodes=0;
}
//#####################################################################
// Function Refresh_Auxiliary_Structures
//#####################################################################
void SIMPLEX_MESH<1>::
Refresh_Auxiliary_Structures()
{
    SIMPLEX_MESH_BASE<1>::Refresh_Auxiliary_Structures();
    Initialize_Ordered_Components();
}

//#####################################################################
// Function Initialize_Ordered_Components
//#####################################################################
void SIMPLEX_MESH<1>::
Initialize_Ordered_Components()
{
    delete ordered_loop_nodes;
    ordered_loop_nodes=new ARRAY<ARRAY<int> >;
    delete connected_segments;
    connected_segments=new ARRAY<ARRAY<int> >;
    bool created_neighbor_nodes=false;
    if(!neighbor_nodes){
        Initialize_Neighbor_Nodes();
        created_neighbor_nodes=true;} 
    auto& nn=*neighbor_nodes;
    ARRAY<bool> done(number_nodes);

    for(int i=0;i<number_nodes;i++)
        if(!done(i) && nn(i).m==1)
        {
            auto& list=(*connected_segments)(connected_segments->Add_End());
            list.Append(i);
            done(i)=1;
            int j=i,k=nn(i)(0);
            while(1)
            {
                list.Append(k);
                done(k)=1;
                PHYSBAM_ASSERT(nn(k).m<=2);
                if(nn(k).m==1) break;
                int m=nn(k)(0)==j?nn(k)(1):nn(k)(0);
                j=k;
                k=m;
            }
            list.Append(k);
            done(k)=1;
        }

    for(int i=0;i<number_nodes;i++)
        if(!done(i) && nn(i).m==2)
        {
            auto& list=(*ordered_loop_nodes)(ordered_loop_nodes->Add_End());
            list.Append(i);
            done(i)=1;
            int j=i,k=nn(i)(0);
            while(k!=i)
            {
                list.Append(k);
                done(k)=1;
                int m=nn(k)(0)==j?nn(k)(1):nn(k)(0);
                j=k;
                k=m;
            }
        }
    
    if(created_neighbor_nodes)
    {
        delete neighbor_nodes;
        neighbor_nodes=0;
    }
}
//#####################################################################
// Function Initialize_Straight_Mesh
//#####################################################################
void SIMPLEX_MESH<1>::
Initialize_Straight_Mesh(const int number_of_points,bool loop,int start_offset)
{
    Clean_Memory();
    number_nodes=number_of_points+start_offset;
    elements.Exact_Resize(number_of_points-!loop);
    for(int i=0;i<number_of_points-1;i++)elements(i).Set(start_offset+i,start_offset+i+1);
    if(loop) elements(number_of_points-1).Set(number_nodes-1,start_offset);
}
//#####################################################################
// Function Initialize_Boundary_Mesh
//#####################################################################
void SIMPLEX_MESH<1>::
Initialize_Boundary_Mesh()
{
    delete boundary_mesh;
    boundary_mesh=new POINT_SIMPLEX_MESH();

    ARRAY<VECTOR<int,dimension> >& boundary_elements=boundary_mesh->elements;
    ARRAY<bool>& boundary_directions=boundary_mesh->directions;
    bool incident_elements_defined=incident_elements!=0;

    if(!incident_elements_defined) Initialize_Incident_Elements();
    for(int i=0;i<incident_elements->m;i++){
        ARRAY<int>& current_incident_elements=(*incident_elements)(i);
        if(current_incident_elements.m==1){
            boundary_elements.Append(VECTOR<int,dimension>(i));
            boundary_directions.Append(elements(current_incident_elements(0)).x!=i);}}
    boundary_elements.Compact();boundary_directions.Compact();
    boundary_mesh->number_nodes=number_nodes;

    if(incident_elements_defined){delete incident_elements;incident_elements=0;}
}
//#####################################################################
// Function Assert_Consistent
//#####################################################################
bool SIMPLEX_MESH<1>::
Assert_Consistent() const
{
    if(connected_segments && ordered_loop_nodes) assert(connected_segments->m==ordered_loop_nodes->m);
    return SIMPLEX_MESH_BASE<1>::Assert_Consistent();
}
//#####################################################################
