// File: EduBic[P]TSP-MetaheuristicSolvers/main.cpp
// Function: main
int main (int argc, char *argv[]) {
    try {

        if (argc < 2) {
            throw std::runtime_error("usage: ./main <filename>.dat");
        }

        SolversExecutor solversExe(argv[1]);

        bool benchmark = false;

        // Solver option    default = LocalSearch
        bool localSearch = true;

        // Solvers features     default = BI
        bool bestImprove = true;
        bool aspCriteria = false;   // only for TabuSearch

        // Tabu options
        int seconds = 30;
        int tenure = 50;
        int maxIterations = 1000;

        int c;
        int option_index;

        while((c = getopt_long(argc, argv, "lfbtae:i:s:m", long_options, &option_index)) != EOF) {
            switch(c) {
                case 'l': {
                    localSearch = true;
                    break;
                }
                case 't': {
                    localSearch = false;
                    break;
                }
                case 'b': {
                    bestImprove = true;
                    break;
                }
                case 'f': {
                    bestImprove = false;
                    break;
                }
                case 'a': {
                    aspCriteria = true;
                    cout << endl << "AspCriteria: " << aspCriteria << endl;
                    break;
                }
                case 'e': {
                    tenure = strtol(optarg, NULL, 0);
                    cout << endl << "Tenure: " << tenure << endl << endl;
                    break;
                }
                case 'i': {
                    maxIterations = (int)strtol(optarg, NULL, 0);
                    break;
                }
                case 's': {
                    seconds = (int)strtol(optarg, NULL, 0);
                    break;
                }
                case 'm': {
                    benchmark = true;
                    break;
                }
            }
        }

        if (benchmark) {

            // Test initial solutions
            solversExe.addRandomSeedInitSolution(58);
            solversExe.addRandomSeedInitSolution(4);
            solversExe.addRandomSeedInitSolution(25);
            solversExe.addRandomSeedInitSolution(26);
            solversExe.addRandomSeedInitSolution(43);
            solversExe.addRandomSeedInitSolution(46);
            solversExe.addRandomSeedInitSolution(93);
            solversExe.addRandomSeedInitSolution(99);

            //solversExe.addSolver(new LocalSearchSolver());
            //solversExe.addSolver(new LocalSearchSolver(false));


            int maxIteration = 300000;
            double maxSeconds = 10;
            //int tabuLenght = 600;
            int tabuLengths[4] = {0, 20, 180, 480};

            //solversExe.addSolver(TabuSearchSolver::buildTS_BI(tabuLenght, maxIteration, maxSeconds));

            for (int i = 0; i < 4; i++) {
                solversExe.addSolver(TabuSearchSolver::buildTS_BI(tabuLengths[i], maxIteration, maxSeconds));
                //solversExe.addSolver(TabuSearchSolver::buildTS_BI_AC(tabuLengths[i], maxIteration, maxSeconds));
                //solversExe.addSolver(TabuSearchSolver::buildTS_FI(tabuLengths[i], maxIteration, maxSeconds));
                //solversExe.addSolver(TabuSearchSolver::buildTS_FI_AC(tabuLengths[i], maxIteration, maxSeconds));
            }

        } else {
            // Command line program
            solversExe.addRandomInitSolution();

            if (localSearch) {
                solversExe.addSolver(new LocalSearchSolver(bestImprove));
            } else { // tabu search
                solversExe.addSolver(new TabuSearchSolver(tenure, maxIterations, aspCriteria, bestImprove, seconds));
            }
        }

        solversExe.execute();

        solversExe.printInitSolutions();
        solversExe.printResults();

    }
    catch (std::exception& e) {
        std::cout << ">>>EXCEPTION: " << e.what() << std::endl;
    }

    return 0;
}

// Assembly:
subq $0x158, %rsp            # imm = 0x158
movl $0x0, 0x154(%rsp)
movl %edi, 0x150(%rsp)
movq %rsi, 0x148(%rsp)
cmpl $0x2, 0x150(%rsp)
jge 0xccd7
movl $0x10, %edi
callq 0x3140
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x68(%rsp)
leaq 0x1759(%rip), %rsi      # 0xe3d0
callq 0x3100
jmp 0xcc7e
movq 0x68(%rsp), %rdi
movq 0x7366(%rip), %rsi      # 0x13ff0
movq 0x7337(%rip), %rdx      # 0x13fc8
callq 0x33f0
jmp 0xd279
movq 0x68(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x140(%rsp)
movl %eax, 0x13c(%rsp)
callq 0x31e0
jmp 0xd1c5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x140(%rsp)
movl %eax, 0x13c(%rsp)
jmp 0xd1c5
movq 0x148(%rsp), %rax
movq 0x8(%rax), %rsi
leaq 0xc0(%rsp), %rdi
callq 0x36a0
jmp 0xccf2
movb $0x0, 0xbf(%rsp)
movb $0x1, 0xbe(%rsp)
movb $0x1, 0xbd(%rsp)
movb $0x0, 0xbc(%rsp)
movl $0x1e, 0xb8(%rsp)
movl $0x32, 0xb4(%rsp)
movl $0x3e8, 0xb0(%rsp) # imm = 0x3E8
movl 0x150(%rsp), %edi
movq 0x148(%rsp), %rsi
leaq 0x16a4(%rip), %rdx      # 0xe3ed
leaq 0x7530(%rip), %rcx      # 0x14280
leaq 0xa8(%rsp), %r8
callq 0x33e0
movl %eax, 0xac(%rsp)
cmpl $-0x1, %eax
je 0xcf31
movl 0xac(%rsp), %eax
addl $-0x61, %eax
movl %eax, %ecx
movq %rcx, 0x60(%rsp)
subl $0x13, %eax
ja 0xcf2c
movq 0x60(%rsp), %rax
leaq 0x15ed(%rip), %rcx      # 0xe380
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movb $0x1, 0xbe(%rsp)
jmp 0xcf2c
movb $0x0, 0xbe(%rsp)
jmp 0xcf2c
movb $0x1, 0xbd(%rsp)
jmp 0xcf2c
movb $0x0, 0xbd(%rsp)
jmp 0xcf2c
movb $0x1, 0xbc(%rsp)
movq 0x71f1(%rip), %rdi      # 0x13fd0
movq 0x71ca(%rip), %rsi      # 0x13fb0
callq 0x32b0
movq %rax, 0x58(%rsp)
jmp 0xcdf2
movq 0x58(%rsp), %rdi
leaq 0x15fc(%rip), %rsi      # 0xe3fa
callq 0x3280
movq %rax, 0x50(%rsp)
jmp 0xce0a
movq 0x50(%rsp), %rdi
movzbl 0xbc(%rsp), %esi
andl $0x1, %esi
callq 0x3440
movq %rax, 0x48(%rsp)
jmp 0xce26
movq 0x48(%rsp), %rdi
movq 0x717e(%rip), %rsi      # 0x13fb0
callq 0x32b0
jmp 0xce39
jmp 0xcf2c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x140(%rsp)
movl %eax, 0x13c(%rsp)
jmp 0xd1b8
movq 0x715a(%rip), %rax      # 0x13fb8
movq (%rax), %rdi
xorl %edx, %edx
movl %edx, %esi
callq 0x3340
movl %eax, 0xb4(%rsp)
movq 0x7158(%rip), %rdi      # 0x13fd0
movq 0x7131(%rip), %rsi      # 0x13fb0
callq 0x32b0
movq %rax, 0x40(%rsp)
jmp 0xce8b
movq 0x40(%rsp), %rdi
leaq 0x1571(%rip), %rsi      # 0xe408
callq 0x3280
movq %rax, 0x38(%rsp)
jmp 0xcea3
movq 0x38(%rsp), %rdi
movl 0xb4(%rsp), %esi
callq 0x3410
movq %rax, 0x30(%rsp)
jmp 0xcebb
movq 0x30(%rsp), %rdi
movq 0x70e9(%rip), %rsi      # 0x13fb0
callq 0x32b0
movq %rax, 0x28(%rsp)
jmp 0xced3
movq 0x28(%rsp), %rdi
movq 0x70d1(%rip), %rsi      # 0x13fb0
callq 0x32b0
jmp 0xcee6
jmp 0xcf2c
movq 0x70c9(%rip), %rax      # 0x13fb8
movq (%rax), %rdi
xorl %eax, %eax
movl %eax, %esi
xorl %edx, %edx
callq 0x3340
movl %eax, 0xb0(%rsp)
jmp 0xcf2c
movq 0x70ab(%rip), %rax      # 0x13fb8
movq (%rax), %rdi
xorl %eax, %eax
movl %eax, %esi
xorl %edx, %edx
callq 0x3340
movl %eax, 0xb8(%rsp)
jmp 0xcf2c
movb $0x1, 0xbf(%rsp)
jmp 0xcd33
testb $0x1, 0xbf(%rsp)
je 0xd078
leaq 0xc0(%rsp), %rdi
movl $0x3a, %esi
callq 0x3760
jmp 0xcf53
leaq 0xc0(%rsp), %rdi
movl $0x4, %esi
callq 0x3760
jmp 0xcf67
leaq 0xc0(%rsp), %rdi
movl $0x19, %esi
callq 0x3760
jmp 0xcf7b
leaq 0xc0(%rsp), %rdi
movl $0x1a, %esi
callq 0x3760
jmp 0xcf8f
leaq 0xc0(%rsp), %rdi
movl $0x2b, %esi
callq 0x3760
jmp 0xcfa3
leaq 0xc0(%rsp), %rdi
movl $0x2e, %esi
callq 0x3760
jmp 0xcfb7
leaq 0xc0(%rsp), %rdi
movl $0x5d, %esi
callq 0x3760
jmp 0xcfcb
leaq 0xc0(%rsp), %rdi
movl $0x63, %esi
callq 0x3760
jmp 0xcfdf
movl $0x493e0, 0xa4(%rsp) # imm = 0x493E0
movsd 0x1386(%rip), %xmm0     # 0xe378
movsd %xmm0, 0x98(%rsp)
movq 0x145e(%rip), %rax      # 0xe460
movq %rax, 0x80(%rsp)
movq 0x1457(%rip), %rax      # 0xe468
movq %rax, 0x88(%rsp)
movl $0x0, 0x7c(%rsp)
cmpl $0x4, 0x7c(%rsp)
jge 0xd073
movslq 0x7c(%rsp), %rax
movl 0x80(%rsp,%rax,4), %edi
movl 0xa4(%rsp), %esi
movsd 0x98(%rsp), %xmm0
callq 0xd280
movq %rax, 0x20(%rsp)
jmp 0xd050
movq 0x20(%rsp), %rsi
leaq 0xc0(%rsp), %rdi
callq 0x3820
jmp 0xd064
jmp 0xd066
movl 0x7c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x7c(%rsp)
jmp 0xd021
jmp 0xd179
leaq 0xc0(%rsp), %rdi
callq 0x37f0
jmp 0xd087
testb $0x1, 0xbe(%rsp)
je 0xd0f5
movl $0x10, %edi
callq 0x3290
movq %rax, 0x18(%rsp)
jmp 0xd0a2
movq 0x18(%rsp), %rdi
movzbl 0xbd(%rsp), %esi
andl $0x1, %esi
callq 0xd2f0
jmp 0xd0b9
movq 0x18(%rsp), %rsi
leaq 0xc0(%rsp), %rdi
callq 0x3820
jmp 0xd0cd
jmp 0xd177
movq 0x18(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x140(%rsp)
movl %eax, 0x13c(%rsp)
callq 0x3260
jmp 0xd1b8
movl $0xb8, %edi
callq 0x3290
movq %rax, 0x10(%rsp)
jmp 0xd106
movq 0x10(%rsp), %rdi
movl 0xb4(%rsp), %esi
movl 0xb0(%rsp), %edx
cvtsi2sdl 0xb8(%rsp), %xmm0
movzbl 0xbd(%rsp), %r8d
movzbl 0xbc(%rsp), %ecx
andl $0x1, %ecx
andl $0x1, %r8d
callq 0xd3a0
jmp 0xd141
movq 0x10(%rsp), %rsi
leaq 0xc0(%rsp), %rdi
callq 0x3820
jmp 0xd155
jmp 0xd177
movq 0x10(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x140(%rsp)
movl %eax, 0x13c(%rsp)
callq 0x3260
jmp 0xd1b8
jmp 0xd179
leaq 0xc0(%rsp), %rdi
callq 0x3850
jmp 0xd188
leaq 0xc0(%rsp), %rdi
callq 0x4940
jmp 0xd197
leaq 0xc0(%rsp), %rdi
callq 0x4b00
jmp 0xd1a6
leaq 0xc0(%rsp), %rdi
callq 0xd450
jmp 0xd23d
leaq 0xc0(%rsp), %rdi
callq 0xd450
movl 0x13c(%rsp), %eax
movl $0x1, %ecx
cmpl %ecx, %eax
jne 0xd264
movq 0x140(%rsp), %rdi
callq 0x3110
movq %rax, 0x70(%rsp)
movq 0x6dde(%rip), %rdi      # 0x13fd0
leaq 0x1099(%rip), %rsi      # 0xe292
callq 0x3280
movq %rax, 0x8(%rsp)
jmp 0xd205
movq 0x70(%rsp), %rdi
movq (%rdi), %rax
movq 0x10(%rax), %rax
callq *%rax
movq 0x8(%rsp), %rdi
movq %rax, %rsi
callq 0x3280
movq %rax, (%rsp)
jmp 0xd226
movq (%rsp), %rdi
movq 0x6d7f(%rip), %rsi      # 0x13fb0
callq 0x32b0
jmp 0xd238
callq 0x33d0
xorl %eax, %eax
addq $0x158, %rsp            # imm = 0x158
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x140(%rsp)
movl %eax, 0x13c(%rsp)
callq 0x33d0
jmp 0xd262
jmp 0xd264
movq 0x140(%rsp), %rdi
callq 0x3420
movq %rax, %rdi
callq 0x6770
nopl (%rax)