#include <igl/readOBJ.h>
#include <igl/readDMAT.h>
#include <igl/viewer/Viewer.h>
#include <igl/barycenter.h>
#include <igl/avg_edge_length.h>
#include <vector>
#include <igl/n_polyvector.h>
#include <stdlib.h>

// Input mesh
Eigen::MatrixXd V;
Eigen::MatrixXi F;

// Face barycenters
Eigen::MatrixXd B;

// Scale for visualizing the fields
double global_scale;

// Input constraints
Eigen::VectorXi isConstrained;
std::vector<Eigen::MatrixXd> constraints;




bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
{
  using namespace std;
  using namespace Eigen;

  if (key <'0' || key >'4')
    return false;

  viewer.clear_mesh();
  viewer.set_mesh(V, F);
  viewer.options.show_lines = false;
  viewer.options.show_texture = false;

  int num = key  - '0';

  if (num == 0)
    return false;
  // Interpolate
  cerr<<"Interpolating for n = "<<num<<"... ";
  // Interpolated polyVector field
  Eigen::MatrixXd pvf;
  igl::n_polyvector(V, F, isConstrained, constraints[num-1], pvf);
  cerr<<"done." <<endl;

  // Highlight in red the constrained faces
  MatrixXd C = MatrixXd::Constant(F.rows(),3,1);
  for (unsigned i=0; i<F.rows();++i)
    if (isConstrained[i])
      C.row(i) << 1, 0, 0;
  viewer.set_colors(C);

  for (int n =0; n<num; ++n)
  {
    // Frame field constraints
    MatrixXd F_t = MatrixXd::Zero(F.rows(),3);
    for (unsigned i=0; i<F.rows();++i)
      if (isConstrained[i])
        F_t.row(i) = constraints[num-1].block(i,n*3,1,3);
    const Eigen::MatrixXd &pvf_t = pvf.block(0,n*3,F.rows(),3);
    viewer.add_edges (B - global_scale*F_t, B + global_scale*F_t , Eigen::RowVector3d(0,0,1));
    viewer.add_edges (B - global_scale*pvf_t, B + global_scale*pvf_t , Eigen::RowVector3d(0,1,0));
  }


  return false;
}

int main(int argc, char *argv[])
{
  using namespace Eigen;
  using namespace std;
  // Load a mesh in OBJ format
  igl::readOBJ("../shared/snail.obj", V, F);

  // Compute face barycenters
  igl::barycenter(V, F, B);

  // Compute scale for visualizing fields
  global_scale =  .2*igl::avg_edge_length(V, F);

  // Allocate constraints and polyvector field
  constraints.resize(4);

  // Load constraints
  MatrixXd temp;
  for (int n =0; n<=3; ++n)
  {
    char cfile[1024]; sprintf(cfile, "../shared/snail%d.dmat",n+1);

    igl::readDMAT(cfile,temp);
    if (n == 0)
      isConstrained = temp.block(0,0,temp.rows(),1).cast<int>();

    constraints[n] = temp.block(0,1,temp.rows(),temp.cols()-1);
  }


  igl::Viewer viewer;

  // Plot the original mesh with a texture parametrization
  key_down(viewer,'0',0);

  // Launch the viewer
  viewer.callback_key_down = &key_down;
  viewer.launch();
}