//#####################################################################
// Copyright 2015, Andre Pradhana and Gergely Klar.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
#include <Core/Log/LOG.h>
#include <Core/Meshes/SEGMENTED_CURVE.h>
#include <Core/Meshes/TETRAHEDRALIZED_VOLUME.h>
#include <Core/Meshes/TRIANGULATED_AREA.h>
#include <Core/Meshes/TRIANGULATED_SURFACE.h>
#include <Core/Parsing/PARSE_ARGS.h>
#include <Core/Read_Write/FILE_UTILITIES.h>
#include <Core/Utilities/VIEWER_DIR.h>
#include <Deformables/Deformable_Objects/DEFORMABLE_BODY_COLLECTION.h>
#ifdef USE_OPENMP
#include <omp.h>
#endif

using namespace PhysBAM;

template<class T,int d> void
Convert(PARSE_ARGS& parse_args)
{
    typedef VECTOR<T,d> TV;
    int start_at=0,end_at=INT_MAX;
    std::string input_dir,output_dir;
    bool surface_only=false;
    ARRAY<int> list;
    int threads=1;
    parse_args.Add("-start",&start_at,"start_at","Start conversion from this frame");
    parse_args.Add("-end",&end_at,"end_at","End conversion at this frame");
    parse_args.Add("-o",&output_dir,"dir","Output directory");
    parse_args.Add("-i",&input_dir,"dir","Input directory");
    parse_args.Add("-s",&list,"list","list of structures to convert");
    parse_args.Add("-surface",&surface_only,"dump surface in place of volumetric objects");
    parse_args.Add("-threads",&threads,"num","number of threads");
    parse_args.Parse();

#ifdef USE_OPENMP
    omp_set_num_threads(threads);
#pragma omp parallel
#pragma omp master
    {
        PHYSBAM_ASSERT(threads==omp_get_num_threads());
        LOG::cout<<"Running on "<<threads<<" threads"<<std::endl;
    }
#endif

    PHYSBAM_ASSERT(input_dir!="");
    PHYSBAM_ASSERT(output_dir!="");

    if(end_at==INT_MAX)
    {
        std::string filename=LOG::sprintf("%s/common/last_frame",input_dir);
        PHYSBAM_ASSERT(File_Exists(filename));
        Read_From_Text_File(filename,end_at);
    }

    fs::create_directories(output_dir);

    VIEWER_DIR viewer_dir(input_dir);
    viewer_dir.Read_Last_Frame(0);
    end_at=min(end_at,viewer_dir.frame_stack(0));

#pragma omp parallel for
    for(int f=start_at;f<=end_at;f++)
    {
        VIEWER_DIR viewer_dir(input_dir);
        viewer_dir.Set(f);
        if(!viewer_dir.Valid_Frame(true)) continue;

        ARRAY<int> frame_list=list;
        DEFORMABLE_BODY_COLLECTION<TV> deformable_body_collection(0,0);
        deformable_body_collection.Read(viewer_dir,true);
        if(!frame_list.m)
            Set_Counting(frame_list,deformable_body_collection.structures.m);

        for(auto i:frame_list)
        {
            fs::create_directories(LOG::sprintf("%s/%d",output_dir,i));
            std::string file=LOG::sprintf("%s/%d/object_%04d.obj",output_dir,i,viewer_dir.frame_stack(0));
            STRUCTURE<TV>* structure=deformable_body_collection.structures(i);
            assert(structure);
            TRIANGULATED_SURFACE<T> * ts=0, copy;
            if(auto* obj=dynamic_cast<TRIANGULATED_SURFACE<T>*>(structure)) ts=obj;
            else if(auto* obj=dynamic_cast<TETRAHEDRALIZED_VOLUME<T>*>(structure))
            {
                obj->Initialize_Triangulated_Surface();
                ts=obj->triangulated_surface;
            }
            PHYSBAM_ASSERT(ts);
            copy.Compact_Copy(*ts);
            copy.Write_Obj(file);
        }
        LOG::printf("Frame %P : %P\n",viewer_dir.frame_stack,frame_list);
    }
}

int main(int argc,char *argv[])
{
    bool type_double=true;

    PARSE_ARGS parse_args(argc,argv);
    parse_args.Add_Not("-float",&type_double,"Use floats");
    parse_args.Add("-double",&type_double,"Use doubles");
    parse_args.Parse(true);

    if(type_double)
        Convert<double,3>(parse_args);
    else
        Convert<float,3>(parse_args);

    return 0;
}
