/*
Copyright (c) 2015 to 2016 by Cornell University and The Regents Of
The University Of California. All Rights Reserved.

Permission to use this Procedural Yarn Fitting and Generation Tool (the "Work")
and its associated copyrights solely for educational, research and non-profit
purposes, without fee is hereby granted, provided that the user agrees as
follows:

Those desiring to incorporate the Work into commercial products or use Work and
its associated copyrights for commercial purposes should contact the Center for
Technology Licensing at Cornell University at

395 Pine Tree Road, Suite 310, Ithaca, NY 14850;
email: ctl-connect@cornell.edu;
Tel: 607-254-4698;
FAX: 607-254-5454

for a commercial license.

IN NO EVENT SHALL CORNELL UNIVERSITY ("CORNELL") OR THE UNIVERSITY OF
CALIFORNIA ("UC") BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF
THE USE OF THE WORK AND ITS ASSOCIATED COPYRIGHTS, EVEN IF CORNELL OR UC MAY
HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE WORK PROVIDED HEREIN IS ON AN "AS IS" BASIS, AND NEITHER CORNELL NOR UC HAS
ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS. CORNELL AND UC MAKE NO REPRESENTATIONS AND EXTEND NO WARRANTIES
OF ANY KIND, EITHER IMPLIED OR EXPRESS, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR
THAT THE USE OF WORK AND ITS ASSOCIATED COPYRIGHTS WILL NOT INFRINGE ANY PATENT,
TRADEMARK OR OTHER RIGHTS.
*/

#include "stdafx.h"
#include "Fiber.h"
#include "MicroCT.h"

//#define FIX_RAND_SEED

std::string WORK_PATH;
std::vector<Rng> rngs;
float WOVEN_HEIGHT_ADJUST;
float WOVEN_YARN_RADIUS;
float WOVEN_YARN_TO_FIBER_SCALE; 

void init_random(int num);
char *wchar_to_string(_TCHAR* widechar);

int _tmain(int argc, TCHAR* argv[]) {
	int num_cores = omp_get_num_procs();
 
	init_random(num_cores);	 

	if (argc >= 2) {
		int step = atoi(wchar_to_string(argv[2]));
		std::cout << "Processing stepId = " << step << std::endl;
		if (step == 1) {
			if (argc != 12)     goto USAGE;
			std::cout << "StepId 1: Ply unrolling & cross-section fitting." << std::endl;
			const std::string 
				ct_vol_file = wchar_to_string(argv[4]), 
				ct_fiber_file = wchar_to_string(argv[5]), 
				ct_curves_file = wchar_to_string(argv[6]);
			const std::string 
				ct_ply_file = wchar_to_string(argv[9]),
				out_config_file = wchar_to_string(argv[8]); 
			const float pixelsPerFiber = atof(wchar_to_string(argv[11]));
			std::cout << "Inputs: \n" 
					  << "Micro-CT volume:        " << ct_vol_file << std::endl
					  << "Micro-CT fibers:        " << ct_fiber_file << std::endl
					  << "Micro-CT curves:        " << ct_curves_file << std::endl
					  << "Pixels per fiber:       " << pixelsPerFiber << std::endl;
			std::cout << "Outputs: \n"
					  << "Config:                 " << out_config_file << std::endl
					  << "Micro-CT unrolled ply:  " << ct_ply_file << std::endl;

			CT::CTAnalyzer ctAnalyzer;
			ctAnalyzer.load_ct_volume(ct_vol_file);
			ctAnalyzer.load_ply_curves(ct_curves_file);
			ctAnalyzer.load_ct_fibers(ct_fiber_file);
			ctAnalyzer.set_pixels_per_fiber(pixelsPerFiber);
			ctAnalyzer.set_unrolled_ply_file(ct_ply_file);

			CT::Config config;
			ctAnalyzer.RobustFit(config, step);
			config.save(out_config_file);

		} else if (step == 2) {
			if (argc != 8)     goto USAGE;
			std::cout << "StepId 2: Ply-wise fitting (migration, distribution and fly-aways)." << std::endl;
			
			const std::string 
				in_config_file = wchar_to_string(argv[4]);
			const std::string 
				out_config_file = wchar_to_string(argv[7]);
			const std::string 
				ct_ply_file = wchar_to_string(argv[5]);
			
			std::cout << "Inputs: \n" 
					  << "Micro-CT unrolled ply:  " << ct_ply_file << std::endl
				      << "Config:                 " << in_config_file << std::endl;
			std::cout << "Outputs: \n" 
					  << "Config:                 " << out_config_file << std::endl;

			CT::Config config;
			config.load(in_config_file);

			const int K = config.ply_num;

			CT::CTAnalyzer ctAnalyzer;
			ctAnalyzer.load_unrolled_ply(K, ct_ply_file);
			ctAnalyzer.RobustFit(config, step);

			config.save(out_config_file);			

		} else if (step == 3) {
			if (argc != 7)     goto USAGE;
			std::cout << "StepId 3: Ply generation." << std::endl;
			const std::string 
				in_config_file = wchar_to_string(argv[4]);
			const std::string
				gen_ply_file = wchar_to_string(argv[6]);
			std::cout << "Inputs: \n" 
					  << "Config:                   " << in_config_file << std::endl;					  
			std::cout << "Outputs: \n"
				      << "Procedural unrolled ply:  " << gen_ply_file << std::endl;
			
			Fiber::Yarn yarn;
			yarn.parse(in_config_file.c_str());
			yarn.simulate_ply();
			yarn.write_plys(gen_ply_file.c_str()); 

		} else if (step == 4) {
			if (argc != 8)     goto USAGE;
			std::cout << "StepId 4: Ply rolling and yarn generation. " << std::endl;
			const std::string 
				in_config_file = wchar_to_string(argv[4]),
				gen_ply_file = wchar_to_string(argv[5]);
			const std::string
				gen_fibers_file = wchar_to_string(argv[7]);
			std::cout << "Inputs: \n" 
					  << "Config:                   " << in_config_file << std::endl
					  << "Procedural unrolled ply:  " << gen_ply_file << std::endl;
			std::cout << "Outputs:\n"
					  << "Procedural fibers:        " << gen_fibers_file << std::endl;
			
			Fiber::Yarn yarn;
			yarn.parse(in_config_file.c_str());

			const int K = yarn.getPlyNum();

			yarn.roll_plys(K, gen_ply_file, gen_fibers_file);
			
		} else {
			goto USAGE;
		}

	
	} else {
USAGE:
		std::cout << "[Usage]: FiberGenerator [--step stepId] [--in inputs] [--out outputs] [--ppf fiberpixel] " << std::endl;
		std::cout << "StepId 0: Clean-up Micro-CT data." << std::endl;
		std::cout << "StepId 1: Ply unrolling & cross-section fitting." << std::endl;
		std::cout << "StepId 2: Ply-wise fitting (migration, distribution and fly-aways)." << std::endl;
		std::cout << "StepId 3: Ply generation. " << std::endl;
		std::cout << "StepId 4: Ply rolling and yarn generation. " << std::endl;
		std::cout << "------------------------------------------------------------------" << std::endl;
		std::cout << "[Example Filename]:  " << std::endl;
		std::cout << "Micro-CT volume:          ct_vol.vol " << std::endl;
		std::cout << "Micro-CT fibers:          ct_fibers.txt " << std::endl;
		std::cout << "Micro-CT ply curves:      ct_curves.txt" << std::endl;
		std::cout << "Micro-CT unrolled ply:    ct_ply.txt" << std::endl;
		std::cout << "Config file:              config.txt" << std::endl;
		std::cout << "Procedural unrolled ply:  gen_gly.txt" << std::endl;
		std::cout << "Procedural fibers:        gen_fibers.txt" << std::endl;
		std::cout << "------------------------------------------------------------------" << std::endl;
		std::cout << "[Example Run] (filenames should be ordered!):" << std::endl;
		std::cout << "FiberGenerator  --step 1  --in ct_vol.vol ct_fibers.txt ct_curves.txt      --out config.txt ct_ply.txt   --ppf 14" << std::endl;
		std::cout << "FiberGenerator  --step 2  --in config.txt ct_ply.txt                       --out config.txt" << std::endl;
		std::cout << "FiberGenerator  --step 3  --in config.txt                                  --out gen_ply.txt" << std::endl;
		std::cout << "FiberGenerator  --step 4  --in config.txt gen_ply.txt                      --out gen_fibers.txt" << std::endl;
	}

	return 0;
}

void init_random(int num) {
#ifndef FIX_RAND_SEED
	std::random_device rd;
	for (int i = 0; i < num; i++) {
		Rng rng(rd); 		rng.index = i;		rngs.push_back(rng);
	}
#else 
	for (int i = 0; i < num; i++) {
		const int seed = 17 * i + 13;
		Rng rng(seed); 		rng.index = i;		rngs.push_back(rng);
	}
#endif
}

char *wchar_to_string(_TCHAR* widechar) {
	int size=0;
	while( (char)widechar[size] != '\0'){
		size++;
	}
	size++;
	char * charpointer = new char[size];
	wcstombs(charpointer, widechar, size );
	return charpointer;
}