//#####################################################################
// Copyright 2012.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################

#include <Core/Viewer/VIEWER_OPTIONS.h>
#include <Core/Interpolation/INTERPOLATED_COLOR_MAP.h>
#include <Core/Parsing/PARSE_ARGS.h>
#include <Core/Read_Write/FILE_UTILITIES.h>
#include <Core/Vectors/VECTOR.h>
#include <cfloat>
#include <functional>
namespace PhysBAM{

template<class T> void Write_Helper(std::ostream& out,const std::string& obj_name,const std::string& var,const OPTION<T>& value)
{
    if(!value.Valid()) return;
    LOG::fprintf(out,"set %s %s ",std::quoted(obj_name),std::quoted(var));
    RAW_OSTREAM ro(out);
    UNTYPED_OSTREAM<char> uo(ro);
    Write_Binary(uo,value.Value());
    LOG::fprintf(out,"\n");
}

template<class T> void Read_Helper(std::istream& in,OPTION<T>& value)
{
    RAW_ISTREAM ri(in);
    UNTYPED_ISTREAM<char> ui(ri);
    T x;
    Read_Binary(ui,x);
    value.Set(x);
}

template<class T> void Merge_Helper(OPTION<T>& o,const OPTION<T>& n)
{
    if(n.Valid()) o=n;
}
void GLOBAL_OPTIONS::Read_Entry(std::istream& in)
{
    std::string var;
    in>>std::quoted(var);
    if(var=="draw"){Read_Helper(in,draw);return;}
    if(var=="name"){Read_Helper(in,name);return;}
    if(var=="is_2d"){Read_Helper(in,is_2d);return;}
    if(var=="scale"){Read_Helper(in,scale);return;}
    if(var=="point_size"){Read_Helper(in,point_size);return;}
    if(var=="view_scale"){Read_Helper(in,view_scale);return;}
    if(var=="substeps_level"){Read_Helper(in,substeps_level);return;}
    if(var=="window_size"){Read_Helper(in,window_size);return;}
    if(var=="target_position"){Read_Helper(in,target_position);return;}
    if(var=="rotation_matrix"){Read_Helper(in,rotation_matrix);return;}
    LOG::printf("Unrecognized entry: \"%s\"\n",var);
};

void GLOBAL_OPTIONS::Write(std::ostream& out,const std::string& obj_name) const
{
    Write_Helper(out,obj_name,"draw",draw);
    Write_Helper(out,obj_name,"name",name);
    Write_Helper(out,obj_name,"is_2d",is_2d);
    Write_Helper(out,obj_name,"scale",scale);
    Write_Helper(out,obj_name,"point_size",point_size);
    Write_Helper(out,obj_name,"view_scale",view_scale);
    Write_Helper(out,obj_name,"substeps_level",substeps_level);
    Write_Helper(out,obj_name,"window_size",window_size);
    Write_Helper(out,obj_name,"target_position",target_position);
    Write_Helper(out,obj_name,"rotation_matrix",rotation_matrix);
};

void GLOBAL_OPTIONS::Merge(const GLOBAL_OPTIONS& o)
{
    Merge_Helper(draw,o.draw);
    Merge_Helper(name,o.name);
    Merge_Helper(is_2d,o.is_2d);
    Merge_Helper(scale,o.scale);
    Merge_Helper(point_size,o.point_size);
    Merge_Helper(view_scale,o.view_scale);
    Merge_Helper(substeps_level,o.substeps_level);
    Merge_Helper(window_size,o.window_size);
    Merge_Helper(target_position,o.target_position);
    Merge_Helper(rotation_matrix,o.rotation_matrix);
}

GLOBAL_OPTIONS GLOBAL_OPTIONS::def=
{
    .draw=true,
    .name=std::string{},
    .is_2d=false,
    .scale=1,
    .point_size=4,
    .view_scale={},
    .substeps_level=0,
    .window_size={{640,480}},
    .target_position={},
    .rotation_matrix={},
};

const char* GLOBAL_OPTIONS::st_type_prefix="global";
void VECTOR_FIELD_OPTIONS::Read_Entry(std::istream& in)
{
    std::string var;
    in>>std::quoted(var);
    if(var=="draw"){Read_Helper(in,draw);return;}
    if(var=="name"){Read_Helper(in,name);return;}
    if(var=="color"){Read_Helper(in,color);return;}
    if(var=="cell_centered"){Read_Helper(in,cell_centered);return;}
    if(var=="node_selectors"){Read_Helper(in,node_selectors);return;}
    if(var=="face_selectors"){Read_Helper(in,face_selectors);return;}
    if(var=="cell_selectors"){Read_Helper(in,cell_selectors);return;}
    LOG::printf("Unrecognized entry: \"%s\"\n",var);
};

void VECTOR_FIELD_OPTIONS::Write(std::ostream& out,const std::string& obj_name) const
{
    Write_Helper(out,obj_name,"draw",draw);
    Write_Helper(out,obj_name,"name",name);
    Write_Helper(out,obj_name,"color",color);
    Write_Helper(out,obj_name,"cell_centered",cell_centered);
    Write_Helper(out,obj_name,"node_selectors",node_selectors);
    Write_Helper(out,obj_name,"face_selectors",face_selectors);
    Write_Helper(out,obj_name,"cell_selectors",cell_selectors);
};

void VECTOR_FIELD_OPTIONS::Merge(const VECTOR_FIELD_OPTIONS& o)
{
    Merge_Helper(draw,o.draw);
    Merge_Helper(name,o.name);
    Merge_Helper(color,o.color);
    Merge_Helper(cell_centered,o.cell_centered);
    Merge_Helper(node_selectors,o.node_selectors);
    Merge_Helper(face_selectors,o.face_selectors);
    Merge_Helper(cell_selectors,o.cell_selectors);
}

VECTOR_FIELD_OPTIONS VECTOR_FIELD_OPTIONS::def=
{
    .draw=true,
    .name=std::string{},
    .color=COLOR{1,0,1},
    .cell_centered=false,
    .node_selectors=false,
    .face_selectors=false,
    .cell_selectors=false,
};

const char* VECTOR_FIELD_OPTIONS::st_type_prefix="grid_vector";
void AXES_OPTIONS::Read_Entry(std::istream& in)
{
    std::string var;
    in>>std::quoted(var);
    if(var=="draw"){Read_Helper(in,draw);return;}
    if(var=="name"){Read_Helper(in,name);return;}
    if(var=="length"){Read_Helper(in,length);return;}
    LOG::printf("Unrecognized entry: \"%s\"\n",var);
};

void AXES_OPTIONS::Write(std::ostream& out,const std::string& obj_name) const
{
    Write_Helper(out,obj_name,"draw",draw);
    Write_Helper(out,obj_name,"name",name);
    Write_Helper(out,obj_name,"length",length);
};

void AXES_OPTIONS::Merge(const AXES_OPTIONS& o)
{
    Merge_Helper(draw,o.draw);
    Merge_Helper(name,o.name);
    Merge_Helper(length,o.length);
}

AXES_OPTIONS AXES_OPTIONS::def=
{
    .draw=true,
    .name=std::string{},
    .length=1,
};

const char* AXES_OPTIONS::st_type_prefix="axes";
void DEBUG_PARTICLES_OPTIONS::Read_Entry(std::istream& in)
{
    std::string var;
    in>>std::quoted(var);
    if(var=="draw"){Read_Helper(in,draw);return;}
    if(var=="name"){Read_Helper(in,name);return;}
    LOG::printf("Unrecognized entry: \"%s\"\n",var);
};

void DEBUG_PARTICLES_OPTIONS::Write(std::ostream& out,const std::string& obj_name) const
{
    Write_Helper(out,obj_name,"draw",draw);
    Write_Helper(out,obj_name,"name",name);
};

void DEBUG_PARTICLES_OPTIONS::Merge(const DEBUG_PARTICLES_OPTIONS& o)
{
    Merge_Helper(draw,o.draw);
    Merge_Helper(name,o.name);
}

DEBUG_PARTICLES_OPTIONS DEBUG_PARTICLES_OPTIONS::def=
{
    .draw=true,
    .name=std::string{},
};

const char* DEBUG_PARTICLES_OPTIONS::st_type_prefix="debug";
void FACE_FIELD_OPTIONS<bool>::Read_Entry(std::istream& in)
{
    std::string var;
    in>>std::quoted(var);
    if(var=="draw"){Read_Helper(in,draw);return;}
    if(var=="name"){Read_Helper(in,name);return;}
    if(var=="cell_centered"){Read_Helper(in,cell_centered);return;}
    if(var=="draw_points"){Read_Helper(in,draw_points);return;}
    if(var=="draw_diamonds"){Read_Helper(in,draw_diamonds);return;}
    if(var=="color"){Read_Helper(in,color);return;}
    LOG::printf("Unrecognized entry: \"%s\"\n",var);
};

void FACE_FIELD_OPTIONS<bool>::Write(std::ostream& out,const std::string& obj_name) const
{
    Write_Helper(out,obj_name,"draw",draw);
    Write_Helper(out,obj_name,"name",name);
    Write_Helper(out,obj_name,"cell_centered",cell_centered);
    Write_Helper(out,obj_name,"draw_points",draw_points);
    Write_Helper(out,obj_name,"draw_diamonds",draw_diamonds);
    Write_Helper(out,obj_name,"color",color);
};

void FACE_FIELD_OPTIONS<bool>::Merge(const FACE_FIELD_OPTIONS& o)
{
    Merge_Helper(draw,o.draw);
    Merge_Helper(name,o.name);
    Merge_Helper(cell_centered,o.cell_centered);
    Merge_Helper(draw_points,o.draw_points);
    Merge_Helper(draw_diamonds,o.draw_diamonds);
    Merge_Helper(color,o.color);
}

FACE_FIELD_OPTIONS<bool> FACE_FIELD_OPTIONS<bool>::def=
{
    .draw=true,
    .name=std::string{},
    .cell_centered=false,
    .draw_points=false,
    .draw_diamonds=false,
    .color=COLOR{1,0,0},
};

const char* FACE_FIELD_OPTIONS<bool>::st_type_prefix="grid_face";
void FACE_FIELD_OPTIONS<int>::Read_Entry(std::istream& in)
{
    std::string var;
    in>>std::quoted(var);
    if(var=="draw"){Read_Helper(in,draw);return;}
    if(var=="name"){Read_Helper(in,name);return;}
    if(var=="cell_centered"){Read_Helper(in,cell_centered);return;}
    if(var=="draw_points"){Read_Helper(in,draw_points);return;}
    if(var=="draw_diamonds"){Read_Helper(in,draw_diamonds);return;}
    if(var=="color_map"){Read_Helper(in,color_map);return;}
    LOG::printf("Unrecognized entry: \"%s\"\n",var);
};

void FACE_FIELD_OPTIONS<int>::Write(std::ostream& out,const std::string& obj_name) const
{
    Write_Helper(out,obj_name,"draw",draw);
    Write_Helper(out,obj_name,"name",name);
    Write_Helper(out,obj_name,"cell_centered",cell_centered);
    Write_Helper(out,obj_name,"draw_points",draw_points);
    Write_Helper(out,obj_name,"draw_diamonds",draw_diamonds);
    Write_Helper(out,obj_name,"color_map",color_map);
};

void FACE_FIELD_OPTIONS<int>::Merge(const FACE_FIELD_OPTIONS& o)
{
    Merge_Helper(draw,o.draw);
    Merge_Helper(name,o.name);
    Merge_Helper(cell_centered,o.cell_centered);
    Merge_Helper(draw_points,o.draw_points);
    Merge_Helper(draw_diamonds,o.draw_diamonds);
    Merge_Helper(color_map,o.color_map);
}

FACE_FIELD_OPTIONS<int> FACE_FIELD_OPTIONS<int>::def=
{
    .draw=true,
    .name=std::string{},
    .cell_centered=false,
    .draw_points=false,
    .draw_diamonds=false,
    .color_map=ARRAY<COLOR>{},
};

const char* FACE_FIELD_OPTIONS<int>::st_type_prefix="grid_face";
void FACE_FIELD_OPTIONS<float>::Read_Entry(std::istream& in)
{
    std::string var;
    in>>std::quoted(var);
    if(var=="draw"){Read_Helper(in,draw);return;}
    if(var=="name"){Read_Helper(in,name);return;}
    if(var=="cell_centered"){Read_Helper(in,cell_centered);return;}
    if(var=="draw_vorticity"){Read_Helper(in,draw_vorticity);return;}
    if(var=="draw_divergence"){Read_Helper(in,draw_divergence);return;}
    if(var=="draw_streamlines"){Read_Helper(in,draw_streamlines);return;}
    if(var=="use_seed_for_streamlines"){Read_Helper(in,use_seed_for_streamlines);return;}
    if(var=="draw_arrows"){Read_Helper(in,draw_arrows);return;}
    if(var=="draw_points"){Read_Helper(in,draw_points);return;}
    if(var=="draw_diamonds"){Read_Helper(in,draw_diamonds);return;}
    if(var=="use_fixed_color"){Read_Helper(in,use_fixed_color);return;}
    if(var=="color"){Read_Helper(in,color);return;}
    if(var=="min"){Read_Helper(in,min);return;}
    if(var=="max"){Read_Helper(in,max);return;}
    if(var=="color_map"){Read_Helper(in,color_map);return;}
    if(var=="number_of_steps"){Read_Helper(in,number_of_steps);return;}
    if(var=="min_vorticity"){Read_Helper(in,min_vorticity);return;}
    if(var=="max_vorticity"){Read_Helper(in,max_vorticity);return;}
    if(var=="streamline_seed"){Read_Helper(in,streamline_seed);return;}
    LOG::printf("Unrecognized entry: \"%s\"\n",var);
};

void FACE_FIELD_OPTIONS<float>::Write(std::ostream& out,const std::string& obj_name) const
{
    Write_Helper(out,obj_name,"draw",draw);
    Write_Helper(out,obj_name,"name",name);
    Write_Helper(out,obj_name,"cell_centered",cell_centered);
    Write_Helper(out,obj_name,"draw_vorticity",draw_vorticity);
    Write_Helper(out,obj_name,"draw_divergence",draw_divergence);
    Write_Helper(out,obj_name,"draw_streamlines",draw_streamlines);
    Write_Helper(out,obj_name,"use_seed_for_streamlines",use_seed_for_streamlines);
    Write_Helper(out,obj_name,"draw_arrows",draw_arrows);
    Write_Helper(out,obj_name,"draw_points",draw_points);
    Write_Helper(out,obj_name,"draw_diamonds",draw_diamonds);
    Write_Helper(out,obj_name,"use_fixed_color",use_fixed_color);
    Write_Helper(out,obj_name,"color",color);
    Write_Helper(out,obj_name,"min",min);
    Write_Helper(out,obj_name,"max",max);
    Write_Helper(out,obj_name,"color_map",color_map);
    Write_Helper(out,obj_name,"number_of_steps",number_of_steps);
    Write_Helper(out,obj_name,"min_vorticity",min_vorticity);
    Write_Helper(out,obj_name,"max_vorticity",max_vorticity);
    Write_Helper(out,obj_name,"streamline_seed",streamline_seed);
};

void FACE_FIELD_OPTIONS<float>::Merge(const FACE_FIELD_OPTIONS& o)
{
    Merge_Helper(draw,o.draw);
    Merge_Helper(name,o.name);
    Merge_Helper(cell_centered,o.cell_centered);
    Merge_Helper(draw_vorticity,o.draw_vorticity);
    Merge_Helper(draw_divergence,o.draw_divergence);
    Merge_Helper(draw_streamlines,o.draw_streamlines);
    Merge_Helper(use_seed_for_streamlines,o.use_seed_for_streamlines);
    Merge_Helper(draw_arrows,o.draw_arrows);
    Merge_Helper(draw_points,o.draw_points);
    Merge_Helper(draw_diamonds,o.draw_diamonds);
    Merge_Helper(use_fixed_color,o.use_fixed_color);
    Merge_Helper(color,o.color);
    Merge_Helper(min,o.min);
    Merge_Helper(max,o.max);
    Merge_Helper(color_map,o.color_map);
    Merge_Helper(number_of_steps,o.number_of_steps);
    Merge_Helper(min_vorticity,o.min_vorticity);
    Merge_Helper(max_vorticity,o.max_vorticity);
    Merge_Helper(streamline_seed,o.streamline_seed);
}

FACE_FIELD_OPTIONS<float> FACE_FIELD_OPTIONS<float>::def=
{
    .draw=true,
    .name=std::string{},
    .cell_centered=false,
    .draw_vorticity=false,
    .draw_divergence=false,
    .draw_streamlines=false,
    .use_seed_for_streamlines=false,
    .draw_arrows=true,
    .draw_points=false,
    .draw_diamonds=false,
    .use_fixed_color=true,
    .color=COLOR{1,0,0},
    .min=0,
    .max=1,
    .color_map=INTERPOLATED_COLOR_MAP<float>{},
    .number_of_steps=10,
    .min_vorticity=FLT_MAX,
    .max_vorticity=FLT_MIN,
    .streamline_seed=0,
};

const char* FACE_FIELD_OPTIONS<float>::st_type_prefix="grid_face";
void GRID_OPTIONS::Read_Entry(std::istream& in)
{
    std::string var;
    in>>std::quoted(var);
    if(var=="draw"){Read_Helper(in,draw);return;}
    if(var=="name"){Read_Helper(in,name);return;}
    if(var=="color"){Read_Helper(in,color);return;}
    if(var=="ghost"){Read_Helper(in,ghost);return;}
    LOG::printf("Unrecognized entry: \"%s\"\n",var);
};

void GRID_OPTIONS::Write(std::ostream& out,const std::string& obj_name) const
{
    Write_Helper(out,obj_name,"draw",draw);
    Write_Helper(out,obj_name,"name",name);
    Write_Helper(out,obj_name,"color",color);
    Write_Helper(out,obj_name,"ghost",ghost);
};

void GRID_OPTIONS::Merge(const GRID_OPTIONS& o)
{
    Merge_Helper(draw,o.draw);
    Merge_Helper(name,o.name);
    Merge_Helper(color,o.color);
    Merge_Helper(ghost,o.ghost);
}

GRID_OPTIONS GRID_OPTIONS::def=
{
    .draw=true,
    .name=std::string{},
    .color=COLOR{.5f,.5f,.5f},
    .ghost=3,
};

const char* GRID_OPTIONS::st_type_prefix="grid";
void GROUP_OPTIONS::Read_Entry(std::istream& in)
{
    std::string var;
    in>>std::quoted(var);
    if(var=="draw"){Read_Helper(in,draw);return;}
    if(var=="name"){Read_Helper(in,name);return;}
    if(var=="add"){Read_Helper(in,add);return;}
    if(var=="source"){Read_Helper(in,source);return;}
    if(var=="attr"){Read_Helper(in,attr);return;}
    if(var=="particle_id"){Read_Helper(in,particle_id);return;}
    if(var=="frame"){Read_Helper(in,frame);return;}
    LOG::printf("Unrecognized entry: \"%s\"\n",var);
};

void GROUP_OPTIONS::Write(std::ostream& out,const std::string& obj_name) const
{
    Write_Helper(out,obj_name,"draw",draw);
    Write_Helper(out,obj_name,"name",name);
    Write_Helper(out,obj_name,"add",add);
    Write_Helper(out,obj_name,"source",source);
    Write_Helper(out,obj_name,"attr",attr);
    Write_Helper(out,obj_name,"particle_id",particle_id);
    Write_Helper(out,obj_name,"frame",frame);
};

void GROUP_OPTIONS::Merge(const GROUP_OPTIONS& o)
{
    Merge_Helper(draw,o.draw);
    Merge_Helper(name,o.name);
    Merge_Helper(add,o.add);
    Merge_Helper(source,o.source);
    Merge_Helper(attr,o.attr);
    Merge_Helper(particle_id,o.particle_id);
    Merge_Helper(frame,o.frame);
}

GROUP_OPTIONS GROUP_OPTIONS::def=
{
    .draw=true,
    .name=std::string{},
    .add=ARRAY<std::string>{},
    .source=std::string{},
    .attr=std::string{},
    .particle_id=-1,
    .frame=FRAME<VECTOR<float,3>>{},
};

const char* GROUP_OPTIONS::st_type_prefix="group";
void PARTICLES_OPTIONS::Read_Entry(std::istream& in)
{
    std::string var;
    in>>std::quoted(var);
    if(var=="draw"){Read_Helper(in,draw);return;}
    if(var=="name"){Read_Helper(in,name);return;}
    if(var=="draw_vectors"){Read_Helper(in,draw_vectors);return;}
    if(var=="default_color"){Read_Helper(in,default_color);return;}
    if(var=="min"){Read_Helper(in,min);return;}
    if(var=="max"){Read_Helper(in,max);return;}
    if(var=="color_map"){Read_Helper(in,color_map);return;}
    if(var=="use_vector_color"){Read_Helper(in,use_vector_color);return;}
    if(var=="vector_color"){Read_Helper(in,vector_color);return;}
    if(var=="visualize_matrix"){Read_Helper(in,visualize_matrix);return;}
    if(var=="position_attr"){Read_Helper(in,position_attr);return;}
    if(var=="color_attr"){Read_Helper(in,color_attr);return;}
    if(var=="vector_attr"){Read_Helper(in,vector_attr);return;}
    if(var=="matrix_attr"){Read_Helper(in,matrix_attr);return;}
    if(var=="use_color_prog"){Read_Helper(in,use_color_prog);return;}
    if(var=="color_prog"){Read_Helper(in,color_prog);return;}
    LOG::printf("Unrecognized entry: \"%s\"\n",var);
};

void PARTICLES_OPTIONS::Write(std::ostream& out,const std::string& obj_name) const
{
    Write_Helper(out,obj_name,"draw",draw);
    Write_Helper(out,obj_name,"name",name);
    Write_Helper(out,obj_name,"draw_vectors",draw_vectors);
    Write_Helper(out,obj_name,"default_color",default_color);
    Write_Helper(out,obj_name,"min",min);
    Write_Helper(out,obj_name,"max",max);
    Write_Helper(out,obj_name,"color_map",color_map);
    Write_Helper(out,obj_name,"use_vector_color",use_vector_color);
    Write_Helper(out,obj_name,"vector_color",vector_color);
    Write_Helper(out,obj_name,"visualize_matrix",visualize_matrix);
    Write_Helper(out,obj_name,"position_attr",position_attr);
    Write_Helper(out,obj_name,"color_attr",color_attr);
    Write_Helper(out,obj_name,"vector_attr",vector_attr);
    Write_Helper(out,obj_name,"matrix_attr",matrix_attr);
    Write_Helper(out,obj_name,"use_color_prog",use_color_prog);
    Write_Helper(out,obj_name,"color_prog",color_prog);
};

void PARTICLES_OPTIONS::Merge(const PARTICLES_OPTIONS& o)
{
    Merge_Helper(draw,o.draw);
    Merge_Helper(name,o.name);
    Merge_Helper(draw_vectors,o.draw_vectors);
    Merge_Helper(default_color,o.default_color);
    Merge_Helper(min,o.min);
    Merge_Helper(max,o.max);
    Merge_Helper(color_map,o.color_map);
    Merge_Helper(use_vector_color,o.use_vector_color);
    Merge_Helper(vector_color,o.vector_color);
    Merge_Helper(visualize_matrix,o.visualize_matrix);
    Merge_Helper(position_attr,o.position_attr);
    Merge_Helper(color_attr,o.color_attr);
    Merge_Helper(vector_attr,o.vector_attr);
    Merge_Helper(matrix_attr,o.matrix_attr);
    Merge_Helper(use_color_prog,o.use_color_prog);
    Merge_Helper(color_prog,o.color_prog);
}

PARTICLES_OPTIONS PARTICLES_OPTIONS::def=
{
    .draw=true,
    .name=std::string{},
    .draw_vectors=false,
    .default_color=COLOR{1,0,0},
    .min=0,
    .max=1,
    .color_map=INTERPOLATED_COLOR_MAP<float>{},
    .use_vector_color=false,
    .vector_color=COLOR{1,0,0},
    .visualize_matrix=false,
    .position_attr=std::string{"X"},
    .color_attr=std::string{"color"},
    .vector_attr=std::string{"V"},
    .matrix_attr=std::string{},
    .use_color_prog=false,
    .color_prog=std::string{},
};

const char* PARTICLES_OPTIONS::st_type_prefix="particles";
void SCALAR_FIELD_OPTIONS<bool>::Read_Entry(std::istream& in)
{
    std::string var;
    in>>std::quoted(var);
    if(var=="draw"){Read_Helper(in,draw);return;}
    if(var=="name"){Read_Helper(in,name);return;}
    if(var=="draw_cell_colors"){Read_Helper(in,draw_cell_colors);return;}
    if(var=="draw_points"){Read_Helper(in,draw_points);return;}
    if(var=="color"){Read_Helper(in,color);return;}
    if(var=="cell_centered"){Read_Helper(in,cell_centered);return;}
    LOG::printf("Unrecognized entry: \"%s\"\n",var);
};

void SCALAR_FIELD_OPTIONS<bool>::Write(std::ostream& out,const std::string& obj_name) const
{
    Write_Helper(out,obj_name,"draw",draw);
    Write_Helper(out,obj_name,"name",name);
    Write_Helper(out,obj_name,"draw_cell_colors",draw_cell_colors);
    Write_Helper(out,obj_name,"draw_points",draw_points);
    Write_Helper(out,obj_name,"color",color);
    Write_Helper(out,obj_name,"cell_centered",cell_centered);
};

void SCALAR_FIELD_OPTIONS<bool>::Merge(const SCALAR_FIELD_OPTIONS& o)
{
    Merge_Helper(draw,o.draw);
    Merge_Helper(name,o.name);
    Merge_Helper(draw_cell_colors,o.draw_cell_colors);
    Merge_Helper(draw_points,o.draw_points);
    Merge_Helper(color,o.color);
    Merge_Helper(cell_centered,o.cell_centered);
}

SCALAR_FIELD_OPTIONS<bool> SCALAR_FIELD_OPTIONS<bool>::def=
{
    .draw=true,
    .name=std::string{},
    .draw_cell_colors=true,
    .draw_points=false,
    .color=COLOR{1,0,0},
    .cell_centered=false,
};

const char* SCALAR_FIELD_OPTIONS<bool>::st_type_prefix="grid_scalar";
void SCALAR_FIELD_OPTIONS<int>::Read_Entry(std::istream& in)
{
    std::string var;
    in>>std::quoted(var);
    if(var=="draw"){Read_Helper(in,draw);return;}
    if(var=="name"){Read_Helper(in,name);return;}
    if(var=="draw_cell_colors"){Read_Helper(in,draw_cell_colors);return;}
    if(var=="draw_points"){Read_Helper(in,draw_points);return;}
    if(var=="color_map"){Read_Helper(in,color_map);return;}
    if(var=="cell_centered"){Read_Helper(in,cell_centered);return;}
    LOG::printf("Unrecognized entry: \"%s\"\n",var);
};

void SCALAR_FIELD_OPTIONS<int>::Write(std::ostream& out,const std::string& obj_name) const
{
    Write_Helper(out,obj_name,"draw",draw);
    Write_Helper(out,obj_name,"name",name);
    Write_Helper(out,obj_name,"draw_cell_colors",draw_cell_colors);
    Write_Helper(out,obj_name,"draw_points",draw_points);
    Write_Helper(out,obj_name,"color_map",color_map);
    Write_Helper(out,obj_name,"cell_centered",cell_centered);
};

void SCALAR_FIELD_OPTIONS<int>::Merge(const SCALAR_FIELD_OPTIONS& o)
{
    Merge_Helper(draw,o.draw);
    Merge_Helper(name,o.name);
    Merge_Helper(draw_cell_colors,o.draw_cell_colors);
    Merge_Helper(draw_points,o.draw_points);
    Merge_Helper(color_map,o.color_map);
    Merge_Helper(cell_centered,o.cell_centered);
}

SCALAR_FIELD_OPTIONS<int> SCALAR_FIELD_OPTIONS<int>::def=
{
    .draw=true,
    .name=std::string{},
    .draw_cell_colors=true,
    .draw_points=false,
    .color_map=ARRAY<COLOR>{},
    .cell_centered=false,
};

const char* SCALAR_FIELD_OPTIONS<int>::st_type_prefix="grid_scalar";
void SCALAR_FIELD_OPTIONS<float>::Read_Entry(std::istream& in)
{
    std::string var;
    in>>std::quoted(var);
    if(var=="draw"){Read_Helper(in,draw);return;}
    if(var=="name"){Read_Helper(in,name);return;}
    if(var=="min"){Read_Helper(in,min);return;}
    if(var=="max"){Read_Helper(in,max);return;}
    if(var=="draw_cell_colors"){Read_Helper(in,draw_cell_colors);return;}
    if(var=="draw_smooth_field"){Read_Helper(in,draw_smooth_field);return;}
    if(var=="draw_points"){Read_Helper(in,draw_points);return;}
    if(var=="color_map"){Read_Helper(in,color_map);return;}
    if(var=="draw_contours"){Read_Helper(in,draw_contours);return;}
    if(var=="num_contours"){Read_Helper(in,num_contours);return;}
    if(var=="cell_centered"){Read_Helper(in,cell_centered);return;}
    LOG::printf("Unrecognized entry: \"%s\"\n",var);
};

void SCALAR_FIELD_OPTIONS<float>::Write(std::ostream& out,const std::string& obj_name) const
{
    Write_Helper(out,obj_name,"draw",draw);
    Write_Helper(out,obj_name,"name",name);
    Write_Helper(out,obj_name,"min",min);
    Write_Helper(out,obj_name,"max",max);
    Write_Helper(out,obj_name,"draw_cell_colors",draw_cell_colors);
    Write_Helper(out,obj_name,"draw_smooth_field",draw_smooth_field);
    Write_Helper(out,obj_name,"draw_points",draw_points);
    Write_Helper(out,obj_name,"color_map",color_map);
    Write_Helper(out,obj_name,"draw_contours",draw_contours);
    Write_Helper(out,obj_name,"num_contours",num_contours);
    Write_Helper(out,obj_name,"cell_centered",cell_centered);
};

void SCALAR_FIELD_OPTIONS<float>::Merge(const SCALAR_FIELD_OPTIONS& o)
{
    Merge_Helper(draw,o.draw);
    Merge_Helper(name,o.name);
    Merge_Helper(min,o.min);
    Merge_Helper(max,o.max);
    Merge_Helper(draw_cell_colors,o.draw_cell_colors);
    Merge_Helper(draw_smooth_field,o.draw_smooth_field);
    Merge_Helper(draw_points,o.draw_points);
    Merge_Helper(color_map,o.color_map);
    Merge_Helper(draw_contours,o.draw_contours);
    Merge_Helper(num_contours,o.num_contours);
    Merge_Helper(cell_centered,o.cell_centered);
}

SCALAR_FIELD_OPTIONS<float> SCALAR_FIELD_OPTIONS<float>::def=
{
    .draw=true,
    .name=std::string{},
    .min=0,
    .max=1,
    .draw_cell_colors=true,
    .draw_smooth_field=false,
    .draw_points=false,
    .color_map=INTERPOLATED_COLOR_MAP<float>{},
    .draw_contours=false,
    .num_contours=1,
    .cell_centered=false,
};

const char* SCALAR_FIELD_OPTIONS<float>::st_type_prefix="grid_scalar";
void MESH_OPTIONS<1>::Read_Entry(std::istream& in)
{
    std::string var;
    in>>std::quoted(var);
    if(var=="draw"){Read_Helper(in,draw);return;}
    if(var=="name"){Read_Helper(in,name);return;}
    if(var=="vertex_color"){Read_Helper(in,vertex_color);return;}
    if(var=="draw_vertices"){Read_Helper(in,draw_vertices);return;}
    if(var=="color"){Read_Helper(in,color);return;}
    if(var=="velocity_color"){Read_Helper(in,velocity_color);return;}
    if(var=="draw_velocities"){Read_Helper(in,draw_velocities);return;}
    LOG::printf("Unrecognized entry: \"%s\"\n",var);
};

void MESH_OPTIONS<1>::Write(std::ostream& out,const std::string& obj_name) const
{
    Write_Helper(out,obj_name,"draw",draw);
    Write_Helper(out,obj_name,"name",name);
    Write_Helper(out,obj_name,"vertex_color",vertex_color);
    Write_Helper(out,obj_name,"draw_vertices",draw_vertices);
    Write_Helper(out,obj_name,"color",color);
    Write_Helper(out,obj_name,"velocity_color",velocity_color);
    Write_Helper(out,obj_name,"draw_velocities",draw_velocities);
};

void MESH_OPTIONS<1>::Merge(const MESH_OPTIONS& o)
{
    Merge_Helper(draw,o.draw);
    Merge_Helper(name,o.name);
    Merge_Helper(vertex_color,o.vertex_color);
    Merge_Helper(draw_vertices,o.draw_vertices);
    Merge_Helper(color,o.color);
    Merge_Helper(velocity_color,o.velocity_color);
    Merge_Helper(draw_velocities,o.draw_velocities);
}

MESH_OPTIONS<1> MESH_OPTIONS<1>::def=
{
    .draw=true,
    .name=std::string{},
    .vertex_color=COLOR{1,1,0},
    .draw_vertices=false,
    .color=COLOR{1,0,0},
    .velocity_color=COLOR{1,0,1},
    .draw_velocities=false,
};

const char* MESH_OPTIONS<1>::st_type_prefix="mesh";
void MESH_OPTIONS<2>::Read_Entry(std::istream& in)
{
    std::string var;
    in>>std::quoted(var);
    if(var=="draw"){Read_Helper(in,draw);return;}
    if(var=="name"){Read_Helper(in,name);return;}
    if(var=="vertex_color"){Read_Helper(in,vertex_color);return;}
    if(var=="draw_vertices"){Read_Helper(in,draw_vertices);return;}
    if(var=="edge_color"){Read_Helper(in,edge_color);return;}
    if(var=="draw_edges"){Read_Helper(in,draw_edges);return;}
    if(var=="color"){Read_Helper(in,color);return;}
    if(var=="bgcolor"){Read_Helper(in,bgcolor);return;}
    if(var=="two_sided"){Read_Helper(in,two_sided);return;}
    if(var=="velocity_color"){Read_Helper(in,velocity_color);return;}
    if(var=="draw_velocities"){Read_Helper(in,draw_velocities);return;}
    LOG::printf("Unrecognized entry: \"%s\"\n",var);
};

void MESH_OPTIONS<2>::Write(std::ostream& out,const std::string& obj_name) const
{
    Write_Helper(out,obj_name,"draw",draw);
    Write_Helper(out,obj_name,"name",name);
    Write_Helper(out,obj_name,"vertex_color",vertex_color);
    Write_Helper(out,obj_name,"draw_vertices",draw_vertices);
    Write_Helper(out,obj_name,"edge_color",edge_color);
    Write_Helper(out,obj_name,"draw_edges",draw_edges);
    Write_Helper(out,obj_name,"color",color);
    Write_Helper(out,obj_name,"bgcolor",bgcolor);
    Write_Helper(out,obj_name,"two_sided",two_sided);
    Write_Helper(out,obj_name,"velocity_color",velocity_color);
    Write_Helper(out,obj_name,"draw_velocities",draw_velocities);
};

void MESH_OPTIONS<2>::Merge(const MESH_OPTIONS& o)
{
    Merge_Helper(draw,o.draw);
    Merge_Helper(name,o.name);
    Merge_Helper(vertex_color,o.vertex_color);
    Merge_Helper(draw_vertices,o.draw_vertices);
    Merge_Helper(edge_color,o.edge_color);
    Merge_Helper(draw_edges,o.draw_edges);
    Merge_Helper(color,o.color);
    Merge_Helper(bgcolor,o.bgcolor);
    Merge_Helper(two_sided,o.two_sided);
    Merge_Helper(velocity_color,o.velocity_color);
    Merge_Helper(draw_velocities,o.draw_velocities);
}

MESH_OPTIONS<2> MESH_OPTIONS<2>::def=
{
    .draw=true,
    .name=std::string{},
    .vertex_color=COLOR{1,1,0},
    .draw_vertices=false,
    .edge_color=COLOR{0,1,1},
    .draw_edges=false,
    .color=COLOR{1,0,0},
    .bgcolor=COLOR{0,0,1},
    .two_sided=true,
    .velocity_color=COLOR{1,0,1},
    .draw_velocities=false,
};

const char* MESH_OPTIONS<2>::st_type_prefix="mesh";
void MESH_OPTIONS<3>::Read_Entry(std::istream& in)
{
    std::string var;
    in>>std::quoted(var);
    if(var=="draw"){Read_Helper(in,draw);return;}
    if(var=="name"){Read_Helper(in,name);return;}
    if(var=="vertex_color"){Read_Helper(in,vertex_color);return;}
    if(var=="draw_vertices"){Read_Helper(in,draw_vertices);return;}
    if(var=="edge_color"){Read_Helper(in,edge_color);return;}
    if(var=="draw_edges"){Read_Helper(in,draw_edges);return;}
    if(var=="color"){Read_Helper(in,color);return;}
    if(var=="bgcolor"){Read_Helper(in,bgcolor);return;}
    if(var=="two_sided"){Read_Helper(in,two_sided);return;}
    if(var=="velocity_color"){Read_Helper(in,velocity_color);return;}
    if(var=="draw_velocities"){Read_Helper(in,draw_velocities);return;}
    LOG::printf("Unrecognized entry: \"%s\"\n",var);
};

void MESH_OPTIONS<3>::Write(std::ostream& out,const std::string& obj_name) const
{
    Write_Helper(out,obj_name,"draw",draw);
    Write_Helper(out,obj_name,"name",name);
    Write_Helper(out,obj_name,"vertex_color",vertex_color);
    Write_Helper(out,obj_name,"draw_vertices",draw_vertices);
    Write_Helper(out,obj_name,"edge_color",edge_color);
    Write_Helper(out,obj_name,"draw_edges",draw_edges);
    Write_Helper(out,obj_name,"color",color);
    Write_Helper(out,obj_name,"bgcolor",bgcolor);
    Write_Helper(out,obj_name,"two_sided",two_sided);
    Write_Helper(out,obj_name,"velocity_color",velocity_color);
    Write_Helper(out,obj_name,"draw_velocities",draw_velocities);
};

void MESH_OPTIONS<3>::Merge(const MESH_OPTIONS& o)
{
    Merge_Helper(draw,o.draw);
    Merge_Helper(name,o.name);
    Merge_Helper(vertex_color,o.vertex_color);
    Merge_Helper(draw_vertices,o.draw_vertices);
    Merge_Helper(edge_color,o.edge_color);
    Merge_Helper(draw_edges,o.draw_edges);
    Merge_Helper(color,o.color);
    Merge_Helper(bgcolor,o.bgcolor);
    Merge_Helper(two_sided,o.two_sided);
    Merge_Helper(velocity_color,o.velocity_color);
    Merge_Helper(draw_velocities,o.draw_velocities);
}

MESH_OPTIONS<3> MESH_OPTIONS<3>::def=
{
    .draw=true,
    .name=std::string{},
    .vertex_color=COLOR{1,1,0},
    .draw_vertices=false,
    .edge_color=COLOR{0,1,1},
    .draw_edges=false,
    .color=COLOR{1,0,0},
    .bgcolor=COLOR{0,0,1},
    .two_sided=true,
    .velocity_color=COLOR{1,0,1},
    .draw_velocities=false,
};

const char* MESH_OPTIONS<3>::st_type_prefix="mesh";

INTERPOLATED_COLOR_MAP<float> Color_Map_Const(const VECTOR<float,3>& color)
{
    INTERPOLATED_COLOR_MAP<float> m;
    m.colors.Add_Control_Point(0,color);
    return m;
}
INTERPOLATED_COLOR_MAP<float> Color_Map_Ramp(const VECTOR<float,3>& c0,const VECTOR<float,3>& c1)
{
    INTERPOLATED_COLOR_MAP<float> m;
    m.colors.Add_Control_Point(0,c0);
    m.colors.Add_Control_Point(1,c1);
    return m;
}
INTERPOLATED_COLOR_MAP<float> Color_Map_Rainbow(bool log_scale,bool reverse,bool two_sets)
{
    INTERPOLATED_COLOR_MAP<float> m;
    m.Initialize_Colors(0,1,log_scale,reverse,two_sets);
    return m;
}
INTERPOLATED_COLOR_MAP<float> Color_Map_Jet(bool log_scale,bool reverse)
{
    INTERPOLATED_COLOR_MAP<float> m;
    m.Initialize_Matlab_Jet(0,1,log_scale,reverse);
    return m;
}
INTERPOLATED_COLOR_MAP<float> Color_Map_Hot(bool log_scale,bool reverse)
{
    INTERPOLATED_COLOR_MAP<float> m;
    m.Initialize_Matlab_Hot(0,1,log_scale,reverse);
    return m;
}


}

