#include <Core/Parsing/PARSE_ARGS.h>
#include <Core/Random_Numbers/RANDOM_NUMBERS.h>
#include "SMOKE_DRIVER.h"
#include "SMOKE_EXAMPLE.h"

using namespace PhysBAM;

template<class TV> void Execute_Main_Program(STREAM_TYPE& stream_type,PARSE_ARGS& parse_args)
{ 
    typedef VECTOR<int,TV::m> IV;    

    // ARGS
    int threads=1;
    parse_args.Add("-threads",&threads,"threads","number of threads");
   
    parse_args.Parse(true);
    SMOKE_EXAMPLE<TV>* example=new SMOKE_EXAMPLE<TV>(stream_type,threads);
    RANGE<TV> range(TV(),TV::All_Ones_Vector()*0.5);range.max_corner(1)=1;
    
    // range.min_corner(0)=-0.5;
    // range.min_corner(1)=0;
    // range.max_corner(0)=1;
    // range.max_corner(1)=3;
    LOG::cout<<"range.min_corner(0) "<<range.min_corner(0)<<std::endl;
    LOG::cout<<"range.min_corner(1) "<<range.min_corner(1)<<std::endl;
    LOG::cout<<"range.max_corner(0) "<<range.max_corner(0)<<std::endl;
    LOG::cout<<"range.max_corner(1) "<<range.max_corner(1)<<std::endl;
    int scale = 200*(range.max_corner(1) - range.min_corner(1));
    parse_args.Add("-scale",&scale,"scale","fine scale grid resolution");
    
    IV counts=IV::All_Ones_Vector()*scale/2;counts(1)=scale;
    example->Initialize_Grid(counts,range);
    LOG::cout<<"Grid dX "<<example->grid.dX<<std::endl;
    example->last_frame=1000;// default last_frame = 100
    parse_args.Add("-restart",&example->restart,"frame","restart frame");
    parse_args.Add("-substeps",&example->write_substeps_level,"level","output-substep level");
    parse_args.Add("-e",&example->last_frame,"frame","last frame");
    parse_args.Add("-d_div",&example->debug_divergence,"output the max velocity divergence after projection");
    parse_args.Add("-a",&example->alpha,"alpha","buoyancy parameter alpha");
    parse_args.Add("-b",&example->beta,"beta","buoyancy parameter beta");  // add temperature parameter
    parse_args.Add("-o",&example->viewer_dir.output_directory,"dir","output directory");
    parse_args.Parse();
    
    // SOURCE
    TV point1=TV::All_Ones_Vector()*.23,point2=TV::All_Ones_Vector()*.27;point1(1)=0.05;point2(1)=0.15;    //0.24 0.25 point1(1) = 0.3;point2(1) =0.31
    example->source1.min_corner=point1;
    example->source1.max_corner=point2;

    // point1=TV::All_Ones_Vector()*.23;point2=TV::All_Ones_Vector()*.27;point1(1)=(0.6-0.15);point2(1)=(0.6-.05);  //at top: point1(1) = 1-0.15; point2(1) = (1-0.05)
    // example->source2.min_corner=point1;
    // example->source2.max_corner=point2;

    LOG::cout<<"example->source1: "<<example->source1<<std::endl;
    // LOG::cout<<"example->source1: "<<example->source2<<std::endl;
    
    // DRIVER MAIN LOOP
    SMOKE_DRIVER<TV> driver(*example);
    driver.Execute_Main_Program();
    delete example;
}

int main(int argc,char *argv[])
{
    typedef float T;
    STREAM_TYPE stream_type=STREAM_TYPE::type_float;
    PARSE_ARGS parse_args(argc,argv);
        bool opt_3d=false;
    parse_args.Print_Arguments();
    parse_args.Add("-3d",&opt_3d,"run in 3 dimensions");
    parse_args.Parse(true);
    if(opt_3d) Execute_Main_Program<VECTOR<T,3> >(stream_type,parse_args);
    else Execute_Main_Program<VECTOR<T,2> >(stream_type,parse_args);
    LOG::Finish_Logging();
    return 0;
}
