// File: nikosgalanis[P]Vectors-Similarity-Search-and-Clustering/programs/Clustering/cluster_main.cc
// Function: main
int main(int argc, char* argv[]) {
	// parse the arguments
	char* input_file = NULL, *config_file = NULL, *output_file = NULL, *method = NULL;
	bool complete;

	parse_clustering_args(argc, argv, &input_file, &output_file, &config_file, &complete, &method);

	// get the clustering parameters from the config file
	int k, l_lsh, k_lsh, M_hc, k_hc, probes_hc; 

	parse_clustering_config(config_file, &k, &l_lsh, &k_lsh, &M_hc, &k_hc, &probes_hc);

	// parse the dataset in order to get a vector of our feature vector
	vector<vector<double>> feature_vectors = parse_input(input_file);

	// create the output file that we are going to use to print the clustering results
	ofstream output; 
	output.open(output_file);

	output << "Algorithm: " << method << endl << endl;
	Clustering<double>* instant;
	// construct the cluster class depending on which algorithm the user has chosen
	if (!strcmp(method, "Lloyds")) {
		instant = new Clustering<double>("lloyds", feature_vectors, k);
	}
	else if (!strcmp(method, "Range_Search_LSH")) {
		instant = new Clustering<double>("reverse_LSH", feature_vectors, k, l_lsh, k_lsh);

	}
	else if (!strcmp(method, "Range_Search_Hypercube")) {
		instant = new Clustering<double>("reverse_Hypercube", feature_vectors, k, M_hc, k_hc, probes_hc);

	} else {
		cout << "Clustering method not supported\n" << endl;
		exit(EXIT_FAILURE);
	}

	auto c_start = std::chrono::high_resolution_clock::now();
	// run the clustering algorithm
	instant->run_clustering();
	auto c_end = std::chrono::high_resolution_clock::now();

	duration<double> cluster_time = duration_cast<duration<double>>(c_end - c_start);  
	
	// get the map of the centroids
	vector<vector<int>> centroids_map = instant->get_centroids_map();
	// get the actual centroids
	vector<vector<double>> centroids = instant->get_centroids();
	
	// print stats for each cluster
	for (int i = 0; i < k; i++) {
		output << "CLUSTER-" << i << " {size: " << centroids_map.at(i).size() << ", centroid: ";
		print::vector_print_infile(centroids.at(i), &output);
		output << "}\n";
	}

	// print the clustering time
	output << "clustering_time: " <<  cluster_time.count() << endl;
	
	// compute the silhouette
	auto pair = instant->compute_silhouette();
	// print the silhouette results
	output << "\nSilhouette: [";
	print::vector_print_infile(pair.first, &output);
	output << ", " << pair.second << "]\n\n";

	// if the user wants to print the images of each cluster
	if (complete) {
		for (int i = 0; i < k; i++) {
			output << "CLUSTER-" << i << "{";
			print::vector_print_infile(centroids.at(i), &output);
			print::vector_print_infile(centroids_map.at(i), &output);
			output << "}\n";
		}
	}
	// free the class pointer to wrap it up
	
	delete instant;

	output.close();

	free(input_file);
	free(config_file);
	free(output_file);
}

// Assembly:
subq $0x558, %rsp            # imm = 0x558
movl $0x0, 0x554(%rsp)
movl %edi, 0x550(%rsp)
movq %rsi, 0x548(%rsp)
movq $0x0, 0x540(%rsp)
movq $0x0, 0x538(%rsp)
movq $0x0, 0x530(%rsp)
movq $0x0, 0x528(%rsp)
movl 0x550(%rsp), %edi
movq 0x548(%rsp), %rsi
movq %rsp, %rax
leaq 0x528(%rsp), %rcx
movq %rcx, (%rax)
leaq 0x540(%rsp), %rdx
leaq 0x530(%rsp), %rcx
leaq 0x538(%rsp), %r8
leaq 0x527(%rsp), %r9
callq 0x2e80
movq 0x538(%rsp), %rdi
movq %rsp, %rax
leaq 0x50c(%rsp), %rcx
movq %rcx, (%rax)
leaq 0x520(%rsp), %rsi
leaq 0x51c(%rsp), %rdx
leaq 0x518(%rsp), %rcx
leaq 0x514(%rsp), %r8
leaq 0x510(%rsp), %r9
callq 0x3090
movq 0x540(%rsp), %rax
movq %rax, 0xe8(%rsp)
leaq 0x4cf(%rsp), %rdi
movq %rdi, 0xf0(%rsp)
callq 0x2410
movq 0xe8(%rsp), %rsi
movq 0xf0(%rsp), %rdx
leaq 0x4d0(%rsp), %rdi
callq 0x22b0
jmp 0x533a
leaq 0x4f0(%rsp), %rdi
leaq 0x4d0(%rsp), %rsi
callq 0x25e0
jmp 0x5351
leaq 0x4d0(%rsp), %rdi
callq 0x2150
leaq 0x4cf(%rsp), %rdi
callq 0x2230
leaq 0x2b8(%rsp), %rdi
callq 0x23c0
jmp 0x537a
movq 0x530(%rsp), %rsi
leaq 0x2b8(%rsp), %rdi
movl $0x10, %edx
callq 0x2040
jmp 0x5396
leaq 0x15ea3(%rip), %rsi     # 0x1b240
leaq 0x2b8(%rsp), %rdi
callq 0x2200
movq %rax, 0xe0(%rsp)
jmp 0x53b4
movq 0xe0(%rsp), %rdi
movq 0x528(%rsp), %rsi
callq 0x2200
movq %rax, 0xd8(%rsp)
jmp 0x53d3
movq 0xd8(%rsp), %rdi
movq 0x21be6(%rip), %rsi     # 0x26fc8
callq 0x2220
movq %rax, 0xd0(%rsp)
jmp 0x53f1
movq 0xd0(%rsp), %rdi
movq 0x21bc8(%rip), %rsi     # 0x26fc8
callq 0x2220
jmp 0x5407
movq 0x528(%rsp), %rdi
leaq 0x15e36(%rip), %rsi     # 0x1b24c
callq 0x22e0
cmpl $0x0, %eax
jne 0x55f4
movl $0xa0, %edi
callq 0x2210
movq %rax, 0xc8(%rsp)
jmp 0x5438
movb $0x1, 0x26f(%rsp)
leaq 0x28f(%rsp), %rdi
movq %rdi, 0xc0(%rsp)
callq 0x2410
movq 0xc0(%rsp), %rdx
leaq 0x15def(%rip), %rsi     # 0x1b253
leaq 0x290(%rsp), %rdi
callq 0x22b0
jmp 0x5473
leaq 0x270(%rsp), %rdi
leaq 0x4f0(%rsp), %rsi
callq 0x5f70
jmp 0x548a
movq 0xc8(%rsp), %rdi
movl 0x520(%rsp), %ecx
leaq 0x290(%rsp), %rsi
leaq 0x270(%rsp), %rdx
callq 0x6070
jmp 0x54b0
movq 0xc8(%rsp), %rax
movb $0x0, 0x26f(%rsp)
movq %rax, 0x2b0(%rsp)
leaq 0x270(%rsp), %rdi
callq 0x35b0
leaq 0x290(%rsp), %rdi
callq 0x2150
leaq 0x28f(%rsp), %rdi
callq 0x2230
jmp 0x5945
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
jmp 0x552b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
leaq 0x4d0(%rsp), %rdi
callq 0x2150
leaq 0x4cf(%rsp), %rdi
callq 0x2230
jmp 0x5f5a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
jmp 0x5f4d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
jmp 0x5f40
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
jmp 0x55c9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
jmp 0x55bc
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
leaq 0x270(%rsp), %rdi
callq 0x35b0
leaq 0x290(%rsp), %rdi
callq 0x2150
leaq 0x28f(%rsp), %rdi
callq 0x2230
testb $0x1, 0x26f(%rsp)
jne 0x55e2
jmp 0x55ef
movq 0xc8(%rsp), %rdi
callq 0x21f0
jmp 0x5f40
movq 0x528(%rsp), %rdi
leaq 0x15c57(%rip), %rsi     # 0x1b25a
callq 0x22e0
cmpl $0x0, %eax
jne 0x5776
movl $0xa0, %edi
callq 0x2210
movq %rax, 0xb8(%rsp)
jmp 0x5625
movb $0x1, 0x227(%rsp)
leaq 0x247(%rsp), %rdi
movq %rdi, 0xb0(%rsp)
callq 0x2410
movq 0xb0(%rsp), %rdx
leaq 0x15c1a(%rip), %rsi     # 0x1b26b
leaq 0x248(%rsp), %rdi
callq 0x22b0
jmp 0x5660
leaq 0x228(%rsp), %rdi
leaq 0x4f0(%rsp), %rsi
callq 0x5f70
jmp 0x5677
movq 0xb8(%rsp), %rdi
movl 0x520(%rsp), %ecx
movl 0x51c(%rsp), %r8d
movl 0x518(%rsp), %r9d
leaq 0x248(%rsp), %rsi
leaq 0x228(%rsp), %rdx
callq 0x62d0
jmp 0x56ad
movq 0xb8(%rsp), %rax
movb $0x0, 0x227(%rsp)
movq %rax, 0x2b0(%rsp)
leaq 0x228(%rsp), %rdi
callq 0x35b0
leaq 0x248(%rsp), %rdi
callq 0x2150
leaq 0x247(%rsp), %rdi
callq 0x2230
jmp 0x5943
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
jmp 0x574b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
jmp 0x573e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
leaq 0x228(%rsp), %rdi
callq 0x35b0
leaq 0x248(%rsp), %rdi
callq 0x2150
leaq 0x247(%rsp), %rdi
callq 0x2230
testb $0x1, 0x227(%rsp)
jne 0x5764
jmp 0x5771
movq 0xb8(%rsp), %rdi
callq 0x21f0
jmp 0x5f40
movq 0x528(%rsp), %rdi
leaq 0x15af2(%rip), %rsi     # 0x1b277
callq 0x22e0
cmpl $0x0, %eax
jne 0x5904
movl $0xa0, %edi
callq 0x2210
movq %rax, 0xa8(%rsp)
jmp 0x57a7
movb $0x1, 0x1df(%rsp)
leaq 0x1ff(%rsp), %rdi
movq %rdi, 0xa0(%rsp)
callq 0x2410
movq 0xa0(%rsp), %rdx
leaq 0x15abb(%rip), %rsi     # 0x1b28e
leaq 0x200(%rsp), %rdi
callq 0x22b0
jmp 0x57e2
leaq 0x1e0(%rsp), %rdi
leaq 0x4f0(%rsp), %rsi
callq 0x5f70
jmp 0x57f9
movq 0xa8(%rsp), %rdi
movl 0x520(%rsp), %ecx
movl 0x514(%rsp), %r8d
movl 0x510(%rsp), %r9d
movl 0x50c(%rsp), %edx
movq %rsp, %rax
movl %edx, (%rax)
leaq 0x200(%rsp), %rsi
leaq 0x1e0(%rsp), %rdx
callq 0x6760
jmp 0x583b
movq 0xa8(%rsp), %rax
movb $0x0, 0x1df(%rsp)
movq %rax, 0x2b0(%rsp)
leaq 0x1e0(%rsp), %rdi
callq 0x35b0
leaq 0x200(%rsp), %rdi
callq 0x2150
leaq 0x1ff(%rsp), %rdi
callq 0x2230
jmp 0x5941
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
jmp 0x58d9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
jmp 0x58cc
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
leaq 0x1e0(%rsp), %rdi
callq 0x35b0
leaq 0x200(%rsp), %rdi
callq 0x2150
leaq 0x1ff(%rsp), %rdi
callq 0x2230
testb $0x1, 0x1df(%rsp)
jne 0x58f2
jmp 0x58ff
movq 0xa8(%rsp), %rdi
callq 0x21f0
jmp 0x5f40
movq 0x216cd(%rip), %rdi     # 0x26fd8
leaq 0x1598e(%rip), %rsi     # 0x1b2a0
callq 0x2200
movq %rax, 0x98(%rsp)
jmp 0x5921
movq 0x98(%rsp), %rdi
movq 0x21698(%rip), %rsi     # 0x26fc8
callq 0x2220
jmp 0x5937
movl $0x1, %edi
callq 0x2260
jmp 0x5943
jmp 0x5945
callq 0x2050
movq %rax, 0x1d0(%rsp)
movq 0x2b0(%rsp), %rdi
callq 0x6bd0
jmp 0x5961
callq 0x2050
movq %rax, 0x1c8(%rsp)
leaq 0x1c8(%rsp), %rdi
leaq 0x1d0(%rsp), %rsi
callq 0x6c90
movq %rax, 0x90(%rsp)
jmp 0x598d
movq 0x90(%rsp), %rax
movq %rax, 0x1b8(%rsp)
leaq 0x1b8(%rsp), %rdi
callq 0x6c60
movsd %xmm0, 0x88(%rsp)
jmp 0x59b5
movsd 0x88(%rsp), %xmm0
movsd %xmm0, 0x1c0(%rsp)
movq 0x2b0(%rsp), %rsi
leaq 0x1a0(%rsp), %rdi
callq 0x6ce0
jmp 0x59de
movq 0x2b0(%rsp), %rsi
leaq 0x188(%rsp), %rdi
callq 0x6e20
jmp 0x59f5
movl $0x0, 0x184(%rsp)
movl 0x184(%rsp), %eax
cmpl 0x520(%rsp), %eax
jge 0x5b8c
leaq 0x158a6(%rip), %rsi     # 0x1b2c1
leaq 0x2b8(%rsp), %rdi
callq 0x2200
movq %rax, 0x80(%rsp)
jmp 0x5a32
movq 0x80(%rsp), %rdi
movl 0x184(%rsp), %esi
callq 0x23e0
movq %rax, 0x78(%rsp)
jmp 0x5a4d
movq 0x78(%rsp), %rdi
leaq 0x15871(%rip), %rsi     # 0x1b2ca
callq 0x2200
movq %rax, 0x70(%rsp)
jmp 0x5a65
movslq 0x184(%rsp), %rsi
leaq 0x1a0(%rsp), %rdi
callq 0x6e50
movq %rax, 0x68(%rsp)
jmp 0x5a81
movq 0x68(%rsp), %rdi
callq 0x6e90
movq 0x70(%rsp), %rdi
movq %rax, %rsi
callq 0x2080
movq %rax, 0x60(%rsp)
jmp 0x5a9f
movq 0x60(%rsp), %rdi
leaq 0x15828(%rip), %rsi     # 0x1b2d3
callq 0x2200
jmp 0x5ab2
movslq 0x184(%rsp), %rsi
leaq 0x188(%rsp), %rdi
callq 0x6f30
movq %rax, 0x58(%rsp)
jmp 0x5ace
movq 0x58(%rsp), %rsi
leaq 0x168(%rsp), %rdi
callq 0x45a0
jmp 0x5ae2
leaq 0x168(%rsp), %rdi
leaq 0x2b8(%rsp), %rsi
callq 0x6eb0
jmp 0x5af9
leaq 0x168(%rsp), %rdi
callq 0x3550
leaq 0x157d3(%rip), %rsi     # 0x1b2e0
leaq 0x2b8(%rsp), %rdi
callq 0x2200
jmp 0x5b1c
jmp 0x5b1e
movl 0x184(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x184(%rsp)
jmp 0x5a00
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
jmp 0x5f33
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
jmp 0x5f26
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
leaq 0x168(%rsp), %rdi
callq 0x3550
jmp 0x5f26
leaq 0x15750(%rip), %rsi     # 0x1b2e3
leaq 0x2b8(%rsp), %rdi
callq 0x2200
movq %rax, 0x50(%rsp)
jmp 0x5ba7
leaq 0x1c0(%rsp), %rdi
callq 0x6f70
movsd %xmm0, 0x48(%rsp)
jmp 0x5bbc
movsd 0x48(%rsp), %xmm0
movq 0x50(%rsp), %rdi
callq 0x2440
movq %rax, 0x40(%rsp)
jmp 0x5bd3
movq 0x40(%rsp), %rdi
movq 0x213e9(%rip), %rsi     # 0x26fc8
callq 0x2220
jmp 0x5be6
movq 0x2b0(%rsp), %rsi
leaq 0x148(%rsp), %rdi
callq 0x6f80
jmp 0x5bfd
leaq 0x156f1(%rip), %rsi     # 0x1b2f5
leaq 0x2b8(%rsp), %rdi
callq 0x2200
jmp 0x5c13
leaq 0x130(%rsp), %rdi
leaq 0x148(%rsp), %rsi
callq 0x45a0
jmp 0x5c2a
leaq 0x130(%rsp), %rdi
leaq 0x2b8(%rsp), %rsi
callq 0x6eb0
jmp 0x5c41
leaq 0x130(%rsp), %rdi
callq 0x3550
leaq 0x156af(%rip), %rsi     # 0x1b304
leaq 0x2b8(%rsp), %rdi
callq 0x2200
movq %rax, 0x38(%rsp)
jmp 0x5c69
movq 0x38(%rsp), %rdi
movsd 0x160(%rsp), %xmm0
callq 0x2440
movq %rax, 0x30(%rsp)
jmp 0x5c83
movq 0x30(%rsp), %rdi
leaq 0x15678(%rip), %rsi     # 0x1b307
callq 0x2200
jmp 0x5c96
testb $0x1, 0x527(%rsp)
je 0x5e6c
movl $0x0, 0x12c(%rsp)
movl 0x12c(%rsp), %eax
cmpl 0x520(%rsp), %eax
jge 0x5e6a
leaq 0x155f7(%rip), %rsi     # 0x1b2c1
leaq 0x2b8(%rsp), %rdi
callq 0x2200
movq %rax, 0x28(%rsp)
jmp 0x5cde
movq 0x28(%rsp), %rdi
movl 0x12c(%rsp), %esi
callq 0x23e0
movq %rax, 0x20(%rsp)
jmp 0x5cf6
movq 0x20(%rsp), %rdi
leaq 0x15609(%rip), %rsi     # 0x1b30b
callq 0x2200
jmp 0x5d09
movslq 0x12c(%rsp), %rsi
leaq 0x188(%rsp), %rdi
callq 0x6f30
movq %rax, 0x18(%rsp)
jmp 0x5d25
movq 0x18(%rsp), %rsi
leaq 0x110(%rsp), %rdi
callq 0x45a0
jmp 0x5d39
leaq 0x110(%rsp), %rdi
leaq 0x2b8(%rsp), %rsi
callq 0x6eb0
jmp 0x5d50
leaq 0x110(%rsp), %rdi
callq 0x3550
movslq 0x12c(%rsp), %rsi
leaq 0x1a0(%rsp), %rdi
callq 0x6e50
movq %rax, 0x10(%rsp)
jmp 0x5d79
movq 0x10(%rsp), %rsi
leaq 0xf8(%rsp), %rdi
callq 0x7950
jmp 0x5d8d
leaq 0xf8(%rsp), %rdi
leaq 0x2b8(%rsp), %rsi
callq 0x78d0
jmp 0x5da4
leaq 0xf8(%rsp), %rdi
callq 0x7a50
leaq 0x15528(%rip), %rsi     # 0x1b2e0
leaq 0x2b8(%rsp), %rdi
callq 0x2200
jmp 0x5dc7
jmp 0x5dc9
movl 0x12c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x12c(%rsp)
jmp 0x5caf
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
jmp 0x5f19
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
leaq 0x130(%rsp), %rdi
callq 0x3550
jmp 0x5f19
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
leaq 0x110(%rsp), %rdi
callq 0x3550
jmp 0x5f19
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c0(%rsp)
movl %eax, 0x4bc(%rsp)
leaq 0xf8(%rsp), %rdi
callq 0x7a50
jmp 0x5f19
jmp 0x5e6c
movq 0x2b0(%rsp), %rax
movq %rax, 0x8(%rsp)
cmpq $0x0, %rax
je 0x5e93
movq 0x8(%rsp), %rdi
callq 0x7ab0
movq 0x8(%rsp), %rdi
callq 0x21f0
leaq 0x2b8(%rsp), %rdi
callq 0x22f0
jmp 0x5ea2
movq 0x540(%rsp), %rdi
callq 0x2250
movq 0x538(%rsp), %rdi
callq 0x2250
movq 0x530(%rsp), %rdi
callq 0x2250
leaq 0x148(%rsp), %rdi
callq 0x7b90
leaq 0x188(%rsp), %rdi
callq 0x35b0
leaq 0x1a0(%rsp), %rdi
callq 0x7ba0
leaq 0x2b8(%rsp), %rdi
callq 0x2320
leaq 0x4f0(%rsp), %rdi
callq 0x35b0
movl 0x554(%rsp), %eax
addq $0x558, %rsp            # imm = 0x558
retq
leaq 0x148(%rsp), %rdi
callq 0x7b90
leaq 0x188(%rsp), %rdi
callq 0x35b0
leaq 0x1a0(%rsp), %rdi
callq 0x7ba0
leaq 0x2b8(%rsp), %rdi
callq 0x2320
leaq 0x4f0(%rsp), %rdi
callq 0x35b0
movq 0x4c0(%rsp), %rdi
callq 0x2400
nopw (%rax,%rax)