  //#####################################################################
// Copyright 2002-2008, Ronald Fedkiw, Eran Guendelman, Eilene Hao, Sergey Koltakov, Neil Molino, Tamar Shinar.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
#include <Core/Arrays/INDIRECT_ARRAY.h>
#include "../QT_RENDER_UTILS.h"
#include "../QT_WORLD.h"
#include "QT_COMPONENT_OPTIONS.h"
#include "QT_OBJECT.h"
#include "QT_SEGMENTED_CURVE.h"
#include <QAction>
namespace PhysBAM{
#define SET(name,value) (opt.name.Set(value),raw_opt[0].name=opt.name)
#define GET(name) opt.name.Value()
//#####################################################################
// Constructor
//#####################################################################
template<class TV> QT_SEGMENTED_CURVE<TV>::
QT_SEGMENTED_CURVE(QT_WORLD& world,const std::string& name,const std::string& file)
    :BASE(world,name,file),opt(OPT::def),raw_opt{{},{},{},OPT::def}
{
}
//#####################################################################
// Constructor
//#####################################################################
template<class TV> QT_SEGMENTED_CURVE<TV>::
QT_SEGMENTED_CURVE(QT_WORLD& world,const std::string& name,const std::string& mesh_file,const std::string& part_file)
    :BASE(world,name,mesh_file,part_file),opt(OPT::def),raw_opt{{},{},{},OPT::def}
{
}
//#####################################################################
// Destructor
//#####################################################################
template<class TV> QT_SEGMENTED_CURVE<TV>::
~QT_SEGMENTED_CURVE()
{
}
//#####################################################################
// Function Display
//#####################################################################
template<class TV> void QT_SEGMENTED_CURVE<TV>::
Render(QT_RENDER_UTILS& ru)
{
    if(!GET(draw)) return;
    this->Read();
    if(!valid) return;
    auto& sc=Obj();

    ru.pick.Push(0);
    if(GET(draw_vertices))
    {
        auto old=ru.Push(ru.depth_offset,ru.depth_offset-ru.depth_offset_unit);
        ru.Render_Points<TV>(sc.particles.X,GET(vertex_color));
    }

    ru.pick.Set(1);
    ru.Render_Mesh(sc,GET(color));
    ru.pick.Pop();

    if(ru.select) return;

    if(selected_vertex>=0)
    {
        auto old=ru.Push(ru.depth_offset,ru.depth_offset-ru.depth_offset_unit*2.5f);
        ru.Render_Point(sc.particles.X(selected_vertex),ru.highlight_color);
        LOG::fprintf(ru.info_text,"vertex %P\n",selected_vertex);
        sc.particles.Print(ru.info_text,selected_vertex);
    }

    if(selected_segment>=0)
    {
        auto old=ru.Push(ru.depth_offset,ru.depth_offset-ru.depth_offset_unit*1.5f);
        auto e=sc.mesh.elements(selected_segment);
        ru.Render_Line(sc.particles.X(e.x),sc.particles.X(e.y),
            ru.highlight_color);
        LOG::fprintf(ru.info_text,"segment %P %P\n",selected_segment,e);
        for(auto p:e)
        {
            LOG::fprintf(ru.info_text,"\nparticle %P\n",p);
            sc.particles.Print(ru.info_text,p);
        }
    }

    if(GET(draw_velocities) && sc.particles.V.m)
        ru.Render_Arrows<TV>(sc.particles.X,sc.particles.V,GET(velocity_color));
}
//#####################################################################
// Bounding_Box
//#####################################################################
template<class TV> auto QT_SEGMENTED_CURVE<TV>::
Bounding_Box() -> RANGE<FV>
{
    if(!GET(draw)) return RANGE<FV>::Empty_Box();
    this->Read();
    return BASE::Bounding_Box();
}
//#####################################################################
// Function Clear_Selection
//#####################################################################
template<class TV> void QT_SEGMENTED_CURVE<TV>::
Clear_Selection()
{
    selected_vertex=-1;
    selected_segment=-1;
}
//#####################################################################
// Function Set_Selection
//#####################################################################
template<class TV> void QT_SEGMENTED_CURVE<TV>::
Set_Selection(ARRAY_VIEW<int> selection)
{
    PHYSBAM_ASSERT(selection.m>=2);
    if(selection(0)==0) selected_vertex=selection(1);
    else if(selection(0)==1) selected_segment=selection(1);
    else PHYSBAM_FATAL_ERROR();
}
//#####################################################################
// Function Selection_Point
//#####################################################################
template<class TV> auto QT_SEGMENTED_CURVE<TV>::
Selection_Point() -> FV
{
    PHYSBAM_ASSERT(valid);
    auto& sc=Obj();
    if(selected_vertex>=0) return FV(sc.particles.X(selected_vertex));
    if(selected_segment>=0)
    {
        auto e=sc.mesh.elements(selected_segment);
        return FV(sc.particles.X.Subset(e).Average());
    }
    PHYSBAM_FATAL_ERROR();
}
//#####################################################################
// Function Make_Dialog
//#####################################################################
template<class TV> void QT_SEGMENTED_CURVE<TV>::
Make_Dialog(QT_WINDOW& window)
{
    QT_COMPONENT_OPTIONS* dialog=new QT_COMPONENT_OPTIONS(window,*this);
    dialog->setWindowTitle(QString::fromStdString(name));
    OPT opt2,raw_opt2;
    opt2=opt;
    raw_opt2=raw_opt[0];
    dialog->Add("Show object in viewer",opt.draw,raw_opt[0].draw);
    dialog->Add("Name to display in viewer",opt.name,raw_opt[0].name);
    dialog->Add("vertex color",opt.vertex_color,raw_opt[0].vertex_color);
    dialog->Add("display vertices",opt.draw_vertices,raw_opt[0].draw_vertices);
    dialog->Add("front color of triangles",opt.color,raw_opt[0].color);
    dialog->Add("velocity color",opt.velocity_color,raw_opt[0].velocity_color);
    dialog->Add("display vertex velocites",opt.draw_velocities,raw_opt[0].draw_velocities);
    dialog->Add_End_Buttons();
    int result=dialog->exec();
    if(result!=QDialog::Accepted)
    {
        opt=opt2;
        raw_opt[0]=raw_opt2;
    }
    window.update();
}
//#####################################################################
// Function Read_Option
//#####################################################################
template<class TV> void QT_SEGMENTED_CURVE<TV>::
Read_Option(std::istream& in,int level)
{
    auto& o=raw_opt[level];
    o.Read_Entry(in);
    opt=raw_opt[3];
    opt.Merge(raw_opt[2]);
    opt.Merge(raw_opt[1]);
    opt.Merge(raw_opt[0]);
}
//#####################################################################
// Function Set_Draw
//#####################################################################
template<class TV> void QT_SEGMENTED_CURVE<TV>::
Set_Draw(bool draw)
{
    SET(draw,draw);
    action->setChecked(Draw());
}
//#####################################################################
// Function Draw
//#####################################################################
template<class TV> bool QT_SEGMENTED_CURVE<TV>::
Draw() const
{
    return GET(draw);
}
//#####################################################################
// Function Save_Settings
//#####################################################################
template<class TV> void QT_SEGMENTED_CURVE<TV>::
Save_Settings(std::ostream& out)
{
    raw_opt[0].Write(out,name);
}
//#####################################################################
// Function Clear_Settings
//#####################################################################
template<class TV> void QT_SEGMENTED_CURVE<TV>::
Clear_Settings()
{
    raw_opt[0]={};
    opt=raw_opt[3];
    opt.Merge(raw_opt[2]);
    opt.Merge(raw_opt[1]);
    opt.Merge(raw_opt[0]);
}
template class QT_SEGMENTED_CURVE<VECTOR<float,2>>;
template class QT_SEGMENTED_CURVE<VECTOR<float,3>>;
template class QT_SEGMENTED_CURVE<VECTOR<double,2>>;
template class QT_SEGMENTED_CURVE<VECTOR<double,3>>;
}
