//#####################################################################
// 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/Matrices/ROTATION.h>
#include <Core/Meshes/TRIANGULATED_SURFACE.h>
#include <Core/Parsing/PARSE_ARGS.h>
#include <Core/Random_Numbers/RANDOM_NUMBERS.h>
#include <Core/Read_Write/FILE_UTILITIES.h>
#include <Rigids/Rigid_Bodies/MASS_PROPERTIES.h>

using namespace PhysBAM;

template<class T,int d> void
Convert(PARSE_ARGS& parse_args)
{
    typedef VECTOR<T,d> TV;
    std::string input,output;
    T scale=1;
    bool use_volume_centroid=false,in_obj=false,out_obj=false,use_uv=false,move_to_origin=false;
    bool use_random_rotate=false;
    int seed=123;
    parse_args.Add("-o",&output,"dir","Output directory");
    parse_args.Add("-i",&input,"dir","Input directory");
    parse_args.Add("-orig",&move_to_origin,"Move center of mass to origin");
    parse_args.Add("-s",&scale,"factor","Scale about center by this factor");
    parse_args.Add("-c",&use_volume_centroid,"Scale about mesh centroid rather than particle centroid");
    parse_args.Add("-in_obj",&in_obj,"Input is in obj format");
    parse_args.Add("-out_obj",&out_obj,"Write output in obj format");
    parse_args.Add("-use_uv",&use_uv,"Retain uv maps");
    parse_args.Add("-use_rand_rotate",&use_random_rotate,"Rotate object randomly");
    parse_args.Add("-seed",&seed,"seed","Random seed");
    parse_args.Parse();

    PHYSBAM_ASSERT(input!="");
    PHYSBAM_ASSERT(output!="");

    ARRAY<VECTOR<T,2> > uv;
    ARRAY<VECTOR<int,3> > f_uv;
    TRIANGULATED_SURFACE<T> ts;
    if(in_obj) ts.Read_Obj(input,use_uv?&uv:nullptr,use_uv?&f_uv:nullptr);
    else Read_From_File(input,ts);

    TV Z;
    if(use_volume_centroid)
    {
        MASS_PROPERTIES<TV> mp(ts,false);
        Z=mp.Center();
    }
    else Z=ts.particles.X.Average();
    ts.particles.X-=Z;
    if(scale!=1) ts.particles.X*=scale;

    if(use_random_rotate)
    {
        RANDOM_NUMBERS<T> r;
        r.Set_Seed(seed);
        ROTATION<TV> rot;
        r.Fill_Uniform(rot);
        for(auto&x:ts.particles.X) x=rot.Rotate(x);
    }

    if(!move_to_origin) ts.particles.X+=Z;

    ARRAY_VIEW<const VECTOR<T,2> > view_uv_v;
    ARRAY_VIEW<const VECTOR<int,3>> view_uv_f;
    if(use_uv) view_uv_v.Set(uv);
    if(use_uv) view_uv_f.Set(f_uv);

    if(out_obj) ts.Write_Obj(output,view_uv_v,view_uv_f);
    else Write_To_File<T>(output,ts);
}

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;
}
