//#####################################################################
// Copyright 2009, Nipun Kwatra.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
#include <Solids/Examples_And_Drivers/EXAMPLE.h>
#include <Core/Log/DEBUG_SUBSTEPS.h>
#include <Core/Log/SCOPE.h>
#include <Core/Parsing/PARSE_ARGS.h>
#include <Core/Utilities/PROCESS_UTILITIES.h>
using namespace PhysBAM;
//#####################################################################
// EXAMPLE
//#####################################################################
template<class TV> EXAMPLE<TV>::
EXAMPLE(STREAM_TYPE stream_type_input,PARSE_ARGS& parse_args)
    :stream_type(stream_type_input)
{
    stored_args=parse_args.Print_Arguments();
    PROCESS_UTILITIES::Set_Floating_Point_Exception_Handling(true);
    PROCESS_UTILITIES::Set_Backtrace(true);

    if(const char* d=getenv("PHYSBAM_DATA_DIRECTORY")) data_directory=d;
    else data_directory="../../Public_Data";

    T frame_rate=1/frame_dt;
    bool user_frame_rate=false;
    parse_args.Add("-dt",&fixed_dt,"size","fix the time step size to this value.");
    parse_args.Add("-frame_dt",&frame_dt,&user_frame_dt,"rate","frame rate");
    parse_args.Add("-framerate",&frame_rate,&user_frame_rate,"rate","frame rate");
    parse_args.Add("-max_dt",&max_dt,"size","fix the time step size to be no larger than this value.");
    parse_args.Add("-delay_substeps",&substeps_delay_frame,"frame","delay substeps until later frame");
    parse_args.Add("-last_frame",&last_frame,&user_last_frame,"frame","last frame");
    parse_args.Add("-restart",&restart,"frame","restart frame");
    parse_args.Add("-substeps",&substeps_delay_level,"level","substep output level");
    parse_args.Add("-v",&opt_verbosity,"level","verbosity level");
    parse_args.Add("-auto_restart",&auto_restart,"restart from last_frame");
    parse_args.Add("-nolog",&opt_nolog,"disable log.txt");
    parse_args.Add("-d",&data_directory,"dir","data directory");
    parse_args.Add("-o",&viewer_dir.output_directory,&user_output_directory,"dir","output directory");
    parse_args.Add("-test_output_prefix",&test_output_prefix,&use_test_output,"","prefix to use for test output");
    parse_args.Add("-m",&m,"scale","length unit");
    parse_args.Add("-s",&s,"scale","time unit");
    parse_args.Add("-kg",&kg,"scale","mass unit");
    parse_args.Parse(true);
    if(user_frame_rate && !user_frame_dt) frame_dt=1/frame_rate;
    
    LOG::Initialize_Logging(opt_verbosity<10,false,opt_verbosity,!opt_nolog);
    LOG::cout<<stored_args<<std::endl;
    fixed_dt*=s;
    frame_dt*=s;
    max_dt*=s;
    min_dt*=s;

    if(substeps_delay_frame==-1) Set_Write_Substeps_Level(substeps_delay_level);
    else Set_Write_Substeps_Level(-1);
}
//#####################################################################
// ~EXAMPLE
//#####################################################################
template<class TV> EXAMPLE<TV>::
~EXAMPLE()
{
    LOG::Finish_Logging();
}
//#####################################################################
// Function Time_At_Frame
//#####################################################################
template<class TV> typename TV::SCALAR EXAMPLE<TV>::
Time_At_Frame(int frame) const
{
    return frame*frame_dt;
}
//#####################################################################
// Function Clamp_Time_Step_With_Target_Time
//#####################################################################
template<class TV> bool EXAMPLE<TV>::
Clamp_Time_Step_With_Target_Time(T time,T target_time,T& dt)
{
    if(limit_dt) limit_dt(dt,time);
    if(max_dt && dt>max_dt) dt=max_dt;
    if(min_dt && dt<min_dt) dt=min_dt;
    if(fixed_dt) dt=fixed_dt;
    if(time+dt>=target_time){dt=target_time-time;return true;}
    else if(time+2*dt>=target_time) dt=min(dt,(T).51*(target_time-time));
    return false;
}
//#####################################################################
// Function Set_Write_Substeps_Level
//#####################################################################
template<class TV> void EXAMPLE<TV>::
Set_Write_Substeps_Level(int level)
{
    write_substeps_level=level;
    DEBUG_SUBSTEPS::write_substeps_level=level;
}
//#####################################################################
// Function Log_Parameters
//#####################################################################
template<class TV> void EXAMPLE<TV>::
Log_Parameters() const
{
    LOG::SCOPE scope("EXAMPLE parameters");
    LOG::cout<<"last_frame="<<last_frame<<std::endl;
    LOG::cout<<"frame_dt="<<frame_dt<<std::endl;
    LOG::cout<<"auto_restart="<<auto_restart<<std::endl;
    LOG::cout<<"restart="<<restart<<std::endl;
    LOG::cout<<"write_output_files="<<write_output_files<<std::endl;
    LOG::cout<<"write_substeps_level="<<write_substeps_level<<std::endl;
    LOG::cout<<"output_directory="<<viewer_dir.output_directory<<std::endl;
    LOG::cout<<"data_directory="<<data_directory<<std::endl;
    LOG::cout<<"frame_title="<<frame_title<<std::endl;
}
//#####################################################################
// Function Register_Output_Files
//#####################################################################
template<class TV> void EXAMPLE<TV>::
Register_Output_Files()
{
}
//#####################################################################
namespace PhysBAM{
template class EXAMPLE<VECTOR<float,1> >;
template class EXAMPLE<VECTOR<float,2> >;
template class EXAMPLE<VECTOR<float,3> >;
template class EXAMPLE<VECTOR<double,1> >;
template class EXAMPLE<VECTOR<double,2> >;
template class EXAMPLE<VECTOR<double,3> >;
}
