//Author: Yusuf Sahillioglu
//implementation of Y. Sahillioglu, Y. Yemez, Coarse-to-Fine Isometric Shape Correspondence by Tracking Symmetric Flips, CGF, 2012

#include "Model.h" //a screen object

#include <windows.h> //for get_time just-below (canceling this should make the portable code compile on unix as well)
inline double get_time()
{
	LARGE_INTEGER t, frequency;
	QueryPerformanceCounter(&t);
	QueryPerformanceFrequency(&frequency);
	return (double)t.QuadPart/(double)frequency.QuadPart;
}

int main(int argc, char ** argv)
{
	//get arguments from user
	int a, b, symHeal, fileFormat, ttl, lti, mls;
	if (argc != 8)
	{
		cout << "\n7 parameters expected: ShapeCorresponderSymFlip_x64.exe <sourceID> <targetID> <meshFormat> <symFlipStep> <trackTillLevel> <levelToInterpolate>\n\n";
		cout << "<*ID>: nonnegative integer for mesh ID\n";
		cout << "<meshFormat>: input mesh file in 1: obj, 2: off, 3: ply format\n\n";
		cout << "<symFlipStep>: 1 to create top10 initial mappings to be tracked until level <trackTillLevel>\n2 to track top10 mappings to learn the min-cost mapping at level <trackTillLevel>\n" <<
				"3 to start w/ the advertised mapping and go until dense correspondence achieved**\n7 to evaluate the computed/stored correspondence [not in use]\n" <<
				"77 to interpolate coarse correspondence into full dense map\n\n";
		cout << "<trackTillLevel>: top10 maps will be tracked until this level (inclusive), which is typically 4 [inactive if symFlipStep = 77]\n";
		cout << "<levelToInterpolate>: level on which interpolation is performed towards dense matching [active only if symFlipStep = 77]\n";
		cout << "**<maxLevel>: proceed until maxLevel in [0,13], i.e., an intermediate level; use other numbers for automatic maxLevel leading to the full dense map [active only if symFlipStep = 3]\n";
		//cout << "<shortcutEdges?>: 1 to use shortcut edges to smooth out traditional dijkstra shortest paths, otherwise: no shortcut edges\n";
		exit(0);
	}
	symHeal = atoi(argv[4]);
	ttl = atoi(argv[5]);
	lti = atoi(argv[6]);
	mls = atoi(argv[7]);
	//sedges = atoi(argv[8]);
	a = atoi(argv[1]);
	b = atoi(argv[2]);
	fileFormat = atoi(argv[3]);
	if (symHeal == 1)
		symHeal = -1; //my code expects -1 although 1 is more user-friendly; so, do this conversion
	else if (symHeal == 2 || symHeal == 3) //similar convesions for some other values
		symHeal--;
	else if (symHeal == 7)
		symHeal = 3;
	else if (symHeal == 77)
		symHeal = 4;
	else //undefined value
		exit(0);

	//start execution
	Model* jModel = new Model("Model # 1", a, true);
	jModel->init(fileFormat);
	Model* jModel2 = new Model("Model # 2", b, false);
	jModel2->init(fileFormat);

	double start_time = get_time(), geodesics = 0.0f;
#ifdef EM_ALGO //never define it in this project; refer to my website to download the EM algo implementation which should be the same as here but i never tested this project w/ EM_ALGO defined
	jModel->getMesh()->C2Fmode = jModel2->getMesh()->C2Fmode = false;
	bool coarseCorresp = true;
	//make coarseCorresp=true for the 1st time if running after long time 'cos coarseStg output file may be overwritten by EM_ALGO undefined algos, i.e. coarseToFineMatching()
	if (coarseCorresp)
	{
		int k = jModel->getMesh()->initialSpectralMatching( jModel2->getMesh() );
		//cout << get_time()-start_time << " secs for geodesics computations (plus spectral corresp which is negligible for nBases = ~80)\n"; printing here takes extra 0.1secs
		geodesics = get_time()-start_time;
		jModel->getMesh()->greedyOpt(jModel2->getMesh(), true, k); //just skip here to see initial corresp
		jModel->getMesh()->finalizeMatching(jModel2->getMesh(), k, true);
	}
	else //denseCorresp
		jModel->getMesh()->denseMatching( jModel2->getMesh() );
#else
	jModel->getMesh()->C2Fmode = jModel2->getMesh()->C2Fmode = true;
	jModel->getMesh()->shortcutEdges = jModel2->getMesh()->shortcutEdges = false;//(sedges == 1);
	jModel->getMesh()->fileForSymProblem = symHeal; //no need to set mesh2.fileForSymProblem 'cos all fnctns that access fileForSymProblem called over mesh1, e.g. coarseToFineMatching() & matchSmallTmpBases()
	jModel->getMesh()->trackTillLevel = ttl;
	jModel->getMesh()->levelToEvaluate = 5; //no evaluation, just computation, in this public package; so use a random number
	jModel->getMesh()->levelToInterpolate = lti;
	jModel->getMesh()->maxLevelSuggested = (mls >= 0 && mls <= 13 ? mls + 1 : -1); //+1 for inclusive condition

	if (symHeal == 3) //compute and show error of the correspondence precomputed and stored in a file
	{
		cout << "evaluation module never tested and prepared, i.e. file path stuff, for this publicly shared code as the purpose here is to generate correspondences, not to evaluate them; you may easily fix it though if my evaluation fits to yours\n";
		exit(0);
		jModel->getMesh()->computeCorrespondenceErrorC2F(jModel2->getMesh(), false, false);
		//jModel->getMesh()->computeCorrespondenceErrorBIM(jModel2->getMesh(), false);
		//jModel->getMesh()->computeCorrespondenceErrorGMDS(jModel2->getMesh(), true);
	}
	else if (symHeal == 4) //interpolate coarse corresp into full dense map
		jModel->getMesh()->interpolateCoarseCorresp(jModel2->getMesh(), false); //false computes interpolation-based dense map, true evaluates precomputed interpolated full map
	else //perform C2F correspondence
		jModel->getMesh()->coarseToFineMatching( jModel2->getMesh() );
#endif
	cout << geodesics << " secs for geodesics computations (plus spectral corresp which is negligible for nBases = ~80)\n";
	cout << get_time()-start_time << " secs for all computations (excluding load time of 2 input meshes)\n";

	return 0;
}
