#include <igl/read_triangle_mesh.h>
#include <igl/randperm.h>
#include <igl/orientable_patches.h>
#include <igl/slice.h>
#include <igl/hsv_to_rgb.h>
#include <igl/embree/reorient_facets_raycast.h>
#include <igl/opengl/glfw/Viewer.h>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

igl::opengl::glfw::Viewer viewer;
Eigen::MatrixXd V;
std::vector<Eigen::VectorXi> C(2);
std::vector<Eigen::MatrixXd> RGBcolors(2);
Eigen::MatrixXi F;
std::vector<Eigen::MatrixXi> FF(2);
bool is_showing_reoriented = false;
bool facetwise = false;

int main(int argc, char * argv[])
{
  using namespace std;
  cout<<R"(
Usage:

[space]  Toggle between original and reoriented faces
F,f      Toggle between patchwise and facetwise reorientation
S,s      Scramble colors
)";
  igl::read_triangle_mesh(TUTORIAL_SHARED_PATH "/truck.obj",V,F);

  const auto & scramble_colors = []()
  {
    for(int pass = 0;pass<2;pass++)
    {
      Eigen::MatrixXi R;
      igl::randperm(C[pass].maxCoeff()+1,R);
      C[pass] = igl::slice(R,Eigen::MatrixXi(C[pass]));
      Eigen::MatrixXd HSV(C[pass].rows(),3);
      HSV.col(0) = 
        360.*C[pass].array().cast<double>()/(double)C[pass].maxCoeff();
      HSV.rightCols(2).setConstant(1.0);
      igl::hsv_to_rgb(HSV,RGBcolors[pass]);
    }
    viewer.data().set_colors(RGBcolors[facetwise]);
  };

  viewer.callback_key_pressed = 
    [&scramble_colors]
    (igl::opengl::glfw::Viewer& /*viewer*/, unsigned int key, int mod)->bool
  {
    switch(key)
    {
    default:
      return false;
    case 'F':
    case 'f':
    {
      facetwise = !facetwise;
      break;
    }
    case 'S':
    case 's':
    {
      scramble_colors();
      return true;
    }
    case ' ':
    {
      is_showing_reoriented = !is_showing_reoriented;
      break;
    }
    }
    viewer.data().clear();
    viewer.data().set_mesh(V,is_showing_reoriented?FF[facetwise]:F);
    viewer.data().set_colors(RGBcolors[facetwise]);
    return true;
  };


  // Compute patches
  for(int pass = 0;pass<2;pass++)
  {
    Eigen::VectorXi I;
    igl::embree::reorient_facets_raycast(
      V,F,F.rows()*100,10,pass==1,false,false,I,C[pass]);
    // apply reorientation
    FF[pass].conservativeResize(F.rows(),F.cols());
    for(int i = 0;i<I.rows();i++)
    {
      if(I(i))
      {
        FF[pass].row(i) = (F.row(i).reverse()).eval();
      }else
      {
        FF[pass].row(i) = F.row(i);
      }
    }
  }

  viewer.data().set_mesh(V,is_showing_reoriented?FF[facetwise]:F);
  viewer.data().set_face_based(true);
  scramble_colors();
  viewer.launch();
}