// File: It4innovations[P]Handicap/src/main.cpp
// Function: main
int main() {

	std::cout.sync_with_stdio(false);
	std::cout.tie();

	if (REGULAR_NUMBER > 5 || REGULAR_NUMBER < 2) {
		std::cerr << "Regular number must be in <2;4>\n. It is equal to " << REGULAR_NUMBER << '\n';
		return 1;
	}


	if (THREAD_COUNT < 1) {
		std::cerr << "CONST THREAD_COUT must be greater than 0. Please change them.\n";
		return 1;
	}

	std::unique_ptr<ExtendedHandicapGraphFactory> handicapGraphFactory(new ExtendedHandicapGraphFactory());
	std::shared_ptr<ExtendedHandicapGraph> graph;

	int vertexCount = VERTICES_COUNT;
	//std::cin >> vertexCount;

	try {
		// Create extended handicap graphs
		graph = handicapGraphFactory->create(vertexCount, REGULAR_NUMBER);
	} catch (const char * msg) {
		std::cerr << msg;
		return 1;
	}
	GraphInfoPrinter printer;
	printer.print(graph);

	if (STARTING_LABEL < 1 || STARTING_LABEL > graph->getVerticesCount() + 1 || STARTING_LABEL == graph->getMissingLabel()) {
		std::cerr << "CONST STARTING_LABEL is not any label in labeling.\nPlease select another STARTING LABEL.\n";
		return 1;
	}

	std::unique_ptr<int[]> arr(new int[vertexCount - 1]());
	int index = 0;
	for (int i = 1; i < graph->getVerticesCount() + 2; i++) {
		if (i == STARTING_LABEL || i == graph->getMissingLabel()) continue;
		arr[index] = i;
		++index;
	}

	//number of threads running parallel
	ThreadPool pool(THREAD_COUNT);
	std::stack<int> stack;
	kSumProblemSolver<int> solver;
	solver.setK(REGULAR_NUMBER);
	solver.setSearchNumber(STARTING_LABEL + graph->getMagicConstant());
	solver.solve(arr, index, stack);
	const auto countOfResult = (int) (stack.size() / REGULAR_NUMBER);
	std::mutex mut;

	for (int i = 0; i < countOfResult; ++i) {
		std::vector<int> vec;
		for (int j = 0; j < REGULAR_NUMBER; ++j) {
			vec.push_back(stack.top());
			stack.pop();
		}
		int startingLabel = STARTING_LABEL;
		pool.addJob([&graph, startingLabel, vec, &mut]() {
			std::unique_ptr<GraphLabeling> graphLabeling(new GraphLabeling(graph));
			graphLabeling->prepareSolve(startingLabel, vec, mut);
		});
	}
	pool.execute();

	std::cout << "END\n";
	return 0;
}

// Assembly:
subq $0x288, %rsp            # imm = 0x288
movl $0x0, 0x284(%rsp)
xorl %edi, %edi
callq 0x20a0
movq 0x1eb58(%rip), %rdi     # 0x20fc8
movq (%rdi), %rax
movq -0x18(%rax), %rax
addq %rax, %rdi
callq 0x22d0
movl $0x1, %edi
callq 0x21b0
movq %rax, %rsi
leaq 0x278(%rsp), %rdi
movq %rdi, 0x60(%rsp)
callq 0x3d40
leaq 0x268(%rsp), %rdi
callq 0x3d70
movq 0x60(%rsp), %rdi
movl $0xc, 0x264(%rsp)
callq 0x3d80
movq %rax, %rsi
movl 0x264(%rsp), %edx
leaq 0x250(%rsp), %rdi
movl $0x5, %ecx
callq 0x3d90
jmp 0x24de
leaq 0x268(%rsp), %rdi
leaq 0x250(%rsp), %rsi
callq 0x3e50
leaq 0x250(%rsp), %rdi
callq 0x3e80
jmp 0x2596
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x248(%rsp)
movl %eax, 0x244(%rsp)
movl 0x244(%rsp), %eax
movl $0x1, %ecx
cmpl %ecx, %eax
jne 0x2af4
movq 0x248(%rsp), %rdi
callq 0x2090
movq %rax, 0x238(%rsp)
movq 0x238(%rsp), %rsi
movq 0x1ea97(%rip), %rdi     # 0x20fe8
callq 0x21a0
jmp 0x2558
movl $0x1, 0x284(%rsp)
movl $0x1, 0x234(%rsp)
callq 0x2260
jmp 0x2acb
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x248(%rsp)
movl %eax, 0x244(%rsp)
callq 0x2260
jmp 0x2af4
leaq 0x268(%rsp), %rdi
callq 0x3e90
jmp 0x25a5
leaq 0x268(%rsp), %rdi
callq 0x3f90
movq %rax, %rdi
callq 0x3fa0
movl %eax, 0x5c(%rsp)
jmp 0x25c0
movl 0x5c(%rsp), %ecx
addl $0x1, %ecx
movl $0x1, %eax
cmpl %ecx, %eax
jg 0x25f8
leaq 0x268(%rsp), %rdi
callq 0x3f90
movq %rax, %rdi
callq 0x3fb0
movl %eax, 0x58(%rsp)
jmp 0x25eb
movl 0x58(%rsp), %ecx
movl $0x1, %eax
cmpl %ecx, %eax
jne 0x2641
movq 0x1e9e9(%rip), %rdi     # 0x20fe8
leaq 0x12a38(%rip), %rsi     # 0x1503e
callq 0x21a0
jmp 0x260d
movl $0x1, 0x284(%rsp)
movl $0x1, 0x234(%rsp)
jmp 0x2acb
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x248(%rsp)
movl %eax, 0x244(%rsp)
jmp 0x2af4
movl 0x264(%rsp), %eax
decl %eax
cltq
movl $0x4, %ecx
mulq %rcx
movq %rax, %rdi
movq $-0x1, %rax
cmovoq %rax, %rdi
movq %rdi, 0x48(%rsp)
callq 0x2030
movq %rax, 0x50(%rsp)
jmp 0x2673
movq 0x50(%rsp), %rdi
movq 0x48(%rsp), %rdx
xorl %esi, %esi
callq 0x20f0
movq 0x50(%rsp), %rsi
leaq 0x228(%rsp), %rdi
callq 0x3fc0
movl $0x0, 0x224(%rsp)
movl $0x1, 0x220(%rsp)
movl 0x220(%rsp), %eax
movl %eax, 0x40(%rsp)
leaq 0x268(%rsp), %rdi
callq 0x3f90
movq %rax, %rdi
callq 0x3fa0
movl %eax, 0x44(%rsp)
jmp 0x26d2
movl 0x40(%rsp), %eax
movl 0x44(%rsp), %ecx
addl $0x2, %ecx
cmpl %ecx, %eax
jge 0x2795
cmpl $0x1, 0x220(%rsp)
je 0x2721
movl 0x220(%rsp), %eax
movl %eax, 0x38(%rsp)
leaq 0x268(%rsp), %rdi
callq 0x3f90
movq %rax, %rdi
callq 0x3fb0
movl %eax, 0x3c(%rsp)
jmp 0x2715
movl 0x38(%rsp), %eax
movl 0x3c(%rsp), %ecx
cmpl %ecx, %eax
jne 0x273c
jmp 0x277f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x248(%rsp)
movl %eax, 0x244(%rsp)
jmp 0x2abc
movl 0x220(%rsp), %eax
movl %eax, 0x2c(%rsp)
movslq 0x224(%rsp), %rsi
leaq 0x228(%rsp), %rdi
callq 0x3290
movq %rax, 0x30(%rsp)
jmp 0x2763
movq 0x30(%rsp), %rax
movl 0x2c(%rsp), %ecx
movl %ecx, (%rax)
movl 0x224(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x224(%rsp)
movl 0x220(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x220(%rsp)
jmp 0x26ac
leaq 0x168(%rsp), %rdi
movl $0x4, %esi
callq 0x3ff0
jmp 0x27a9
leaq 0x118(%rsp), %rdi
callq 0x4020
jmp 0x27b8
leaq 0x10c(%rsp), %rdi
movq %rdi, 0x20(%rsp)
callq 0x4050
movq 0x20(%rsp), %rdi
movl $0x5, %esi
callq 0x3d00
leaq 0x268(%rsp), %rdi
callq 0x3f90
movq %rax, %rdi
callq 0x4070
movl %eax, 0x28(%rsp)
jmp 0x27f4
movl 0x28(%rsp), %esi
incl %esi
leaq 0x10c(%rsp), %rdi
movq %rdi, 0x18(%rsp)
callq 0x3d20
movq 0x18(%rsp), %rdi
leaq 0x228(%rsp), %rsi
leaq 0x224(%rsp), %rdx
leaq 0x118(%rsp), %rcx
callq 0x3910
jmp 0x2830
leaq 0x118(%rsp), %rdi
callq 0x4080
movq %rax, 0x10(%rsp)
jmp 0x2844
movq 0x10(%rsp), %rax
movl $0x5, %ecx
xorl %edx, %edx
divq %rcx
movl %eax, 0x108(%rsp)
leaq 0xe0(%rsp), %rdi
callq 0x4090
movl $0x0, 0xdc(%rsp)
movl 0xdc(%rsp), %eax
cmpl 0x108(%rsp), %eax
jge 0x2a3f
leaq 0xc0(%rsp), %rdi
callq 0x40a0
movl $0x0, 0xbc(%rsp)
cmpl $0x5, 0xbc(%rsp)
jge 0x2943
leaq 0x118(%rsp), %rdi
callq 0x4120
movq %rax, 0x8(%rsp)
jmp 0x28c0
movq 0x8(%rsp), %rsi
leaq 0xc0(%rsp), %rdi
callq 0x40b0
jmp 0x28d4
leaq 0x118(%rsp), %rdi
callq 0x4130
jmp 0x28e3
jmp 0x28e5
movl 0xbc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xbc(%rsp)
jmp 0x289e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x248(%rsp)
movl %eax, 0x244(%rsp)
jmp 0x2aaf
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x248(%rsp)
movl %eax, 0x244(%rsp)
jmp 0x2aa2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x248(%rsp)
movl %eax, 0x244(%rsp)
jmp 0x2a30
movl $0x1, 0xb8(%rsp)
leaq 0x268(%rsp), %rax
movq %rax, 0x68(%rsp)
movl 0xb8(%rsp), %eax
movl %eax, 0x70(%rsp)
leaq 0x78(%rsp), %rdi
leaq 0xc0(%rsp), %rsi
callq 0x41b0
jmp 0x297a
leaq 0xe0(%rsp), %rax
movq %rax, 0x90(%rsp)
leaq 0x98(%rsp), %rdi
leaq 0x68(%rsp), %rsi
callq 0x2b20
jmp 0x299e
leaq 0x168(%rsp), %rdi
leaq 0x98(%rsp), %rsi
callq 0x4140
jmp 0x29b5
leaq 0x98(%rsp), %rdi
callq 0x42b0
leaq 0x68(%rsp), %rdi
callq 0x2bd0
leaq 0xc0(%rsp), %rdi
callq 0x42c0
movl 0xdc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xdc(%rsp)
jmp 0x2872
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x248(%rsp)
movl %eax, 0x244(%rsp)
jmp 0x2a26
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x248(%rsp)
movl %eax, 0x244(%rsp)
leaq 0x98(%rsp), %rdi
callq 0x42b0
leaq 0x68(%rsp), %rdi
callq 0x2bd0
leaq 0xc0(%rsp), %rdi
callq 0x42c0
jmp 0x2aa2
leaq 0x168(%rsp), %rdi
callq 0x4320
jmp 0x2a4e
movq 0x1e573(%rip), %rdi     # 0x20fc8
leaq 0x1263c(%rip), %rsi     # 0x15098
callq 0x21a0
jmp 0x2a63
movl $0x0, 0x284(%rsp)
movl $0x1, 0x234(%rsp)
leaq 0x118(%rsp), %rdi
callq 0x4460
leaq 0x168(%rsp), %rdi
callq 0x4470
leaq 0x228(%rsp), %rdi
callq 0x4490
jmp 0x2acb
leaq 0x118(%rsp), %rdi
callq 0x4460
leaq 0x168(%rsp), %rdi
callq 0x4470
leaq 0x228(%rsp), %rdi
callq 0x4490
jmp 0x2af4
leaq 0x268(%rsp), %rdi
callq 0x3e80
leaq 0x278(%rsp), %rdi
callq 0x4500
movl 0x284(%rsp), %eax
addq $0x288, %rsp            # imm = 0x288
retq
leaq 0x268(%rsp), %rdi
callq 0x3e80
leaq 0x278(%rsp), %rdi
callq 0x4500
movq 0x248(%rsp), %rdi
callq 0x22b0
nopl (%rax,%rax)