#include <igl/readOBJ.h>
#include <igl/writeOBJ.h>
#include <igl/snap_points.h>

#include <cube_style_data.h>
#include <cube_style_precomputation.h>
#include <cube_style_single_iteration.h>
#include <normalize_unitbox.h>

#include <ctime>
#include <vector>
#include <iostream>
#include <fstream>

// to run the code, type "./cubeStyle_bin [meshName] [lambda]"
// [meshDirectory] [lambda] [iterations]

int main(int argc, char *argv[])
{
	using namespace Eigen;
	using namespace std;

    // load mesh and lambda
	MatrixXd V, U;
	MatrixXi F;
    cube_style_data data;

    int maxIter;
    string meshName;
	{
        if (argc == 1)
        {
            meshName = "/home/machine2/houdini18.0/cubify/meshes/ogre.obj"; // default mesh
            data.lambda = 0.2; // default lambda
	    maxIter = 500;
        }
        else if (argc == 2)
        {
            meshName = argv[1];
            data.lambda = 0.2; // default lambda
	    maxIter = 500;
        }
        else if (argc == 3)
        {
            meshName = argv[1];
            data.lambda = stod(argv[2]);
            maxIter = 500;
        }
	else
	{
	    meshName = argv[1];
	    data.lambda = stod(argv[2]);
	    maxIter = stoi(argv[3]);
	}
		string file = meshName;
		igl::readOBJ(file, V, F);
        normalize_unitbox(V);
        RowVector3d meanV = V.colwise().mean();
        V = V.rowwise() - meanV;
        U = V;
	}

    // set a constrained point F(0,0)
    {
        data.bc.resize(1,3);
        data.bc << V.row(F(0,0));

        data.b.resize(1);
        data.b << F(0,0);
    }

    // precomputation ARAP and initialize ADMM parameters
    cube_style_precomputation(V,F,data);

    // cubic stylization
    double stopReldV = 1e-3; // stopping criteria for relative displacement
    for (int iter=0; iter<maxIter; iter++)
    {
        cout << "iteration: " << iter << endl;
        cube_style_single_iteration(V,U,data);
        if (data.reldV < stopReldV) break;
    }

    // write output mesh
    {
	//Overwrite the input mesh.
        string outputFile = meshName;
        igl::writeOBJ(outputFile,U,F);
        cout << "written to: " << outputFile;
    }

    return 0;
}
