//=============================================================================


#ifndef GRAPHENE_ENERGY_TERM_DATA_H
#define GRAPHENE_ENERGY_TERM_DATA_H


//== INCLUDES =================================================================

#include <graphene/surface_mesh/algorithms/templatefitting/my_types.h>
#include <graphene/surface_mesh/algorithms/pca/PCA_opencv.h>
#include <graphene/surface_mesh/algorithms/templatefitting/Landmarks_manager.h>
#include <graphene/character/data_structure/Character.h>


//== NAMESPACE ================================================================


namespace graphene {
namespace surface_mesh {


//== CLASS DEFINITION =========================================================


struct Column_offsets
{
    unsigned int  offset_match       = 0;
    unsigned int  offset_nrd_w_rigid = 0;
    unsigned int  offset_nrd_w_pca   = 0;
    unsigned int  offset_nrd_w_arap  = 0;

    void clear()
    {
        offset_match = offset_nrd_w_rigid = offset_nrd_w_pca = offset_nrd_w_arap = 0;
    }
};

struct Energy_fitting_target
{
    geometry::Point_set* point_set            = nullptr;
    std::vector<Mat4f>* pose_vector           = nullptr;
    std::string landmark_property_name        = "";
    std::string landmark_weight_property_name = "";
    std::vector<Correspondence> correspondences;

    explicit Energy_fitting_target()
        : point_set(nullptr),
          pose_vector(nullptr),
          landmark_property_name(""),
          landmark_weight_property_name("")
    {

    }
};


class
Energy_term_data
{
public:

    Energy_term_data() :
        sum_corresp_weights(0.0),
        surface_area_aniso(0.0),
        surface_area(0.0),
        use_dualquaternion_skinning(false),
        template_mesh(NULL),
        character(NULL),
        point_set(NULL),
        landmark_property_name("m:landmarks"),
        landmark_weight_property_name("v:landmark_weight")
    {}

    ~Energy_term_data() {}


public:

    Column_offsets                  column_offsets;
    std::vector<Correspondence>     correspondences;
    std::vector<Correspondence>     fieldlines;
    double                          sum_corresp_weights;
    Landmarks_manager               landmarks_manager;
    PCA_opencv                      pca;
    double                          surface_area_aniso;
    double                          surface_area;
    bool                            use_dualquaternion_skinning;
    Surface_mesh*                   template_mesh;
    graphene::character::Character* character;
    geometry::Point_set*            point_set;
    std::string                     landmark_property_name;
    std::string                     landmark_weight_property_name;

    std::vector<Energy_fitting_target> fitting_targets;

    Energy_fitting_target ear_fitting_target;

    // first: index of vertex
    // second: point with resolved collision
    std::unordered_map<int, Point> collisions_v_vs_tri;
    std::unordered_map<int, Point> collisions_tri_vs_p;

    void clear()
    {
        column_offsets.clear();
        correspondences.clear();
        fieldlines.clear();
        collisions_v_vs_tri.clear();
        collisions_tri_vs_p.clear();
        sum_corresp_weights = 0.0;
        landmarks_manager.clear();
        pca.clear();
        surface_area = 0.0;
        surface_area_aniso = 0.0;
        template_mesh = NULL;
        character = NULL;
        point_set = NULL;
        fitting_targets.clear();
    }

};


//=============================================================================
} // namespace surface_mesh
} // namespace graphene
//=============================================================================
#endif // GRAPHENE_ENERGY_TERM_DATA_H
//=============================================================================
