// File: chuckwolber[P]Cube/order/cli.cpp
// Function: main
int main(int argc, char *argv[]) {
    int ch;
    char* algorithmStart = nullptr;
    unsigned long long int algmathAddVal = 0;
    char* algmathLtVal = nullptr;
    bool algmathAdd = false;
    bool algmathLt = false;
    bool algBench = false;
    bool algBenchLite = false;
    algorithmCountMax = DEFAULT_ALG_MAX;
    keepDuplicates = false;
    skipFoundOrders = false;
    showFoundOrder = false;
    skip_nth = 1;
    heartbeat = 0;
    numThreads = std::thread::hardware_concurrency();

    opterr = 0;
    while((ch = getopt_long(argc, argv, "a:gep:l:c:b:ks:t:f:o:ih", longopts, NULL)) != -1) {
        switch(ch) {
            case 'a':
                algorithmStart = optarg;
                break;
            case 'g':
                algBench = true;
                break;
            case 'e':
                algBench = true;
                algBenchLite = true;
                break;
            case 'p':
                algmathAddVal = (unsigned long long int)(std::strtoll(optarg, nullptr, 10));
                algmathAdd = true;
                break;
            case 'l':
                algmathLtVal = optarg;
                algmathLt = true;
                break;
            case 'c':
                algorithmCountMax = (unsigned long long int)(std::strtoll(optarg, nullptr, 10));
                break;
            case 'b':
                heartbeat = (unsigned long long int)(std::strtoll(optarg, nullptr, 10));
                break;
            case 'k':
                keepDuplicates = true;
                break;
            case 's':
                skip_nth = (unsigned long long int)std::strtoll(optarg, nullptr, 10);
                ++skip_nth;
                break;
            case 't':
                numThreads = (unsigned int)std::stoul(optarg, nullptr, 10);
                break;
            case 'i':
                setFindAllOrders();
                break;
            case 'f':
                setFindOrders(optarg);
                break;
            case 'o':
                showFoundOrder = true;
                try {
                    foundOrder = (unsigned int)std::stoul(optarg, nullptr, 10);
                } catch (std::invalid_argument) {
                    usage(argv[0]);
                    return 0;
                }
                break;
            case 'h':
            default:
                usage(argv[0]);
                return 0;
                break;
        }
    }

    if (skip_nth == 0)
        skip_nth = 1;
    if (numThreads < 1)
        numThreads = 1;
    std::vector<std::thread> threads(numThreads);

    initialAlgorithm.reset();
    if (algorithmStart != nullptr)
        initialAlgorithm.setAlgorithm(algorithmStart);

    if (algmathAdd) {
        Algorithm endAlgorithm(initialAlgorithm);
        endAlgorithm += algmathAddVal;
        std::cout << endAlgorithm.getAlgorithmStr() << std::endl;
    } else if (algmathLt) {
        Algorithm ltAlgorithm(algmathLtVal);
        if (initialAlgorithm < ltAlgorithm)
            std::cout << "true" << std::endl;
        else
            std::cout << "false" << std::endl;
    } else if (algBench) {
        std::cerr << "Threads: " << numThreads << std::endl;
        doAlgBench(algBenchLite);
    } else {
        std::cerr << "Algorithm Count: " << algorithmCountMax << std::endl;
        std::cerr << "Algorithm Start: " << initialAlgorithm.getAlgorithmStr() << std::endl;

        if (skipFoundOrders)
            std::cerr << "Finding Orders: " << findOrders << std::endl;
        std::cerr << "Threads: " << numThreads << std::endl;
   
        for (unsigned int i=0; i<numThreads; i++)
            threads.at(i) = std::thread(calculateOrder, i);
        for (std::thread &t : threads)
            t.join();

        if (heartbeat > 0)
            std::cout << "HB:-1" << std::endl;
    }
    
    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x260, %rsp            # imm = 0x260
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq $0x0, -0x20(%rbp)
movq $0x0, -0x28(%rbp)
movq $0x0, -0x30(%rbp)
movb $0x0, -0x31(%rbp)
movb $0x0, -0x32(%rbp)
movb $0x0, -0x33(%rbp)
movb $0x0, -0x34(%rbp)
movabsq $0x183870714, %rax      # imm = 0x183870714
movq %rax, 0x1f2ce(%rip)     # 0x2b700
movb $0x0, 0x1f2e7(%rip)     # 0x2b720
movb $0x0, 0x1f2e1(%rip)     # 0x2b721
movb $0x0, 0x1f2db(%rip)     # 0x2b722
movq $0x1, 0x1f2a6(%rip) # 0x2b6f8
movq $0x0, 0x1f2b3(%rip) # 0x2b710
callq 0x44f0
movl %eax, 0x1f2b0(%rip)     # 0x2b718
movq 0x1eb51(%rip), %rax     # 0x2afc0
movl $0x0, (%rax)
movl -0x8(%rbp), %edi
movq -0x10(%rbp), %rsi
leaq 0xff15(%rip), %rdx      # 0x1c398
leaq 0x1eff6(%rip), %rcx     # 0x2b480
xorl %eax, %eax
movl %eax, %r8d
callq 0x45a0
movl %eax, -0x14(%rbp)
cmpl $-0x1, %eax
je 0xc7f2
movl -0x14(%rbp), %eax
addl $-0x61, %eax
movl %eax, %ecx
movq %rcx, -0x190(%rbp)
subl $0x13, %eax
ja 0xc7d5
movq -0x190(%rbp), %rax
leaq 0xfdda(%rip), %rcx      # 0x1c2a0
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x1ea92(%rip), %rax     # 0x2af68
movq (%rax), %rax
movq %rax, -0x20(%rbp)
jmp 0xc7ed
movb $0x1, -0x33(%rbp)
jmp 0xc7ed
movb $0x1, -0x33(%rbp)
movb $0x1, -0x34(%rbp)
jmp 0xc7ed
movq 0x1ea69(%rip), %rax     # 0x2af68
movq (%rax), %rdi
xorl %eax, %eax
movl %eax, %esi
movl $0xa, %edx
callq 0x4060
movq %rax, -0x28(%rbp)
movb $0x1, -0x31(%rbp)
jmp 0xc7ed
movq 0x1ea44(%rip), %rax     # 0x2af68
movq (%rax), %rax
movq %rax, -0x30(%rbp)
movb $0x1, -0x32(%rbp)
jmp 0xc7ed
movq 0x1ea2d(%rip), %rax     # 0x2af68
movq (%rax), %rdi
xorl %eax, %eax
movl %eax, %esi
movl $0xa, %edx
callq 0x4060
movq %rax, 0x1f1ad(%rip)     # 0x2b700
jmp 0xc7ed
movq 0x1ea09(%rip), %rax     # 0x2af68
movq (%rax), %rdi
xorl %eax, %eax
movl %eax, %esi
movl $0xa, %edx
callq 0x4060
movq %rax, 0x1f199(%rip)     # 0x2b710
jmp 0xc7ed
movb $0x1, 0x1f19d(%rip)     # 0x2b720
jmp 0xc7ed
movq 0x1e9d9(%rip), %rax     # 0x2af68
movq (%rax), %rdi
xorl %eax, %eax
movl %eax, %esi
movl $0xa, %edx
callq 0x4060
movq %rax, 0x1f151(%rip)     # 0x2b6f8
movq 0x1f14a(%rip), %rax     # 0x2b6f8
addq $0x1, %rax
movq %rax, 0x1f13f(%rip)     # 0x2b6f8
jmp 0xc7ed
movq 0x1e9a3(%rip), %rax     # 0x2af68
movq (%rax), %rax
movq %rax, -0x1a0(%rbp)
leaq -0x59(%rbp), %rdi
movq %rdi, -0x198(%rbp)
callq 0x45f0
movq -0x1a0(%rbp), %rsi
movq -0x198(%rbp), %rdx
leaq -0x58(%rbp), %rdi
callq 0x7410
jmp 0xc5f8
xorl %eax, %eax
movl %eax, %esi
leaq -0x58(%rbp), %rdi
movl $0xa, %edx
callq 0xec60
movq %rax, -0x1a8(%rbp)
jmp 0xc613
movq -0x1a8(%rbp), %rax
movl %eax, 0x1f0f8(%rip)     # 0x2b718
leaq -0x58(%rbp), %rdi
callq 0x4678
leaq -0x59(%rbp), %rdi
callq 0x43d0
jmp 0xc7ed
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0xc65a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x58(%rbp), %rdi
callq 0x4678
leaq -0x59(%rbp), %rdi
callq 0x43d0
jmp 0xcdce
callq 0xcde0
jmp 0xc7ed
movq 0x1e8ef(%rip), %rax     # 0x2af68
movq (%rax), %rdi
callq 0xcf50
jmp 0xc7ed
movb $0x1, 0x1f095(%rip)     # 0x2b722
movq 0x1e8d4(%rip), %rax     # 0x2af68
movq (%rax), %rax
movq %rax, -0x1b8(%rbp)
leaq -0x91(%rbp), %rdi
movq %rdi, -0x1b0(%rbp)
callq 0x45f0
movq -0x1b8(%rbp), %rsi
movq -0x1b0(%rbp), %rdx
leaq -0x90(%rbp), %rdi
callq 0x7410
jmp 0xc6cd
xorl %eax, %eax
movl %eax, %esi
leaq -0x90(%rbp), %rdi
movl $0xa, %edx
callq 0xec60
movq %rax, -0x1c0(%rbp)
jmp 0xc6eb
movq -0x1c0(%rbp), %rax
movl %eax, 0x1f024(%rip)     # 0x2b71c
leaq -0x90(%rbp), %rdi
callq 0x4678
leaq -0x91(%rbp), %rdi
callq 0x43d0
jmp 0xc7d1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0xc73b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x90(%rbp), %rdi
callq 0x4678
leaq -0x91(%rbp), %rdi
callq 0x43d0
movl -0x6c(%rbp), %eax
movl $0x1, %ecx
cmpl %ecx, %eax
jne 0xcdce
movq -0x68(%rbp), %rdi
movq %rdi, -0x1c8(%rbp)
callq 0x4480
movq %rax, %rsi
leaq -0xa8(%rbp), %rdi
callq 0xeca0
movq -0x1c8(%rbp), %rdi
callq 0x4120
movq -0x10(%rbp), %rax
movq (%rax), %rdi
callq 0xd3a0
jmp 0xc790
movl $0x0, -0x4(%rbp)
leaq -0xa8(%rbp), %rdi
callq 0x45b0
callq 0x4590
jmp 0xcdc2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0xa8(%rbp), %rdi
callq 0x45b0
callq 0x4590
jmp 0xc7cc
jmp 0xcdce
jmp 0xc7ed
jmp 0xc7d5
movq -0x10(%rbp), %rax
movq (%rax), %rdi
callq 0xd3a0
movl $0x0, -0x4(%rbp)
jmp 0xcdc2
jmp 0xc475
cmpq $0x0, 0x1eefe(%rip)     # 0x2b6f8
jne 0xc807
movq $0x1, 0x1eef1(%rip) # 0x2b6f8
cmpl $0x1, 0x1ef0a(%rip)     # 0x2b718
jae 0xc81a
movl $0x1, 0x1eefe(%rip)     # 0x2b718
movl 0x1eef8(%rip), %eax     # 0x2b718
movq %rax, -0x1d8(%rbp)
leaq -0xc1(%rbp), %rdi
movq %rdi, -0x1d0(%rbp)
callq 0xece0
movq -0x1d8(%rbp), %rsi
movq -0x1d0(%rbp), %rdx
leaq -0xc0(%rbp), %rdi
callq 0xed00
jmp 0xc856
leaq -0xc1(%rbp), %rdi
callq 0xed70
leaq 0x1eebf(%rip), %rdi     # 0x2b728
callq 0x5470
jmp 0xc870
cmpq $0x0, -0x20(%rbp)
je 0xc8b9
movq -0x20(%rbp), %rsi
leaq 0x1eea6(%rip), %rdi     # 0x2b728
callq 0x4c90
jmp 0xc889
jmp 0xc8b9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0xc1(%rbp), %rdi
callq 0xed70
jmp 0xcdce
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0xcdb4
testb $0x1, -0x31(%rbp)
je 0xc984
leaq 0x1ee5e(%rip), %rsi     # 0x2b728
leaq -0xf0(%rbp), %rdi
callq 0x4bb0
jmp 0xc8d8
movq -0x28(%rbp), %rsi
leaq -0xf0(%rbp), %rdi
callq 0x5010
jmp 0xc8ea
leaq -0x110(%rbp), %rdi
leaq -0xf0(%rbp), %rsi
callq 0x5540
jmp 0xc8ff
movq 0x1e6aa(%rip), %rdi     # 0x2afb0
leaq -0x110(%rbp), %rsi
callq 0x4300
movq %rax, -0x1e0(%rbp)
jmp 0xc91b
movq -0x1e0(%rbp), %rdi
movq 0x1e637(%rip), %rsi     # 0x2af60
callq 0x43b0
jmp 0xc930
leaq -0x110(%rbp), %rdi
callq 0x4678
leaq -0xf0(%rbp), %rdi
callq 0x7010
jmp 0xcd9f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0xc973
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x110(%rbp), %rdi
callq 0x4678
leaq -0xf0(%rbp), %rdi
callq 0x7010
jmp 0xcdb4
testb $0x1, -0x32(%rbp)
je 0xca5b
movq -0x30(%rbp), %rsi
leaq -0x138(%rbp), %rdi
callq 0x4c30
jmp 0xc9a0
leaq 0x1ed81(%rip), %rdi     # 0x2b728
leaq -0x138(%rbp), %rsi
callq 0x50a0
movb %al, -0x1e1(%rbp)
jmp 0xc9bb
movb -0x1e1(%rbp), %al
testb $0x1, %al
jne 0xc9c7
jmp 0xca17
movq 0x1e5e2(%rip), %rdi     # 0x2afb0
leaq 0xf9db(%rip), %rsi      # 0x1c3b0
callq 0x4370
movq %rax, -0x1f0(%rbp)
jmp 0xc9e3
movq -0x1f0(%rbp), %rdi
movq 0x1e56f(%rip), %rsi     # 0x2af60
callq 0x43b0
jmp 0xc9f8
jmp 0xca4a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x138(%rbp), %rdi
callq 0x7010
jmp 0xcdb4
movq 0x1e592(%rip), %rdi     # 0x2afb0
leaq 0xf990(%rip), %rsi      # 0x1c3b5
callq 0x4370
movq %rax, -0x1f8(%rbp)
jmp 0xca33
movq -0x1f8(%rbp), %rdi
movq 0x1e51f(%rip), %rsi     # 0x2af60
callq 0x43b0
jmp 0xca48
jmp 0xca4a
leaq -0x138(%rbp), %rdi
callq 0x7010
jmp 0xcd9d
testb $0x1, -0x33(%rbp)
je 0xcac0
movq 0x1e588(%rip), %rdi     # 0x2aff0
leaq 0xf94c(%rip), %rsi      # 0x1c3bb
callq 0x4370
movq %rax, -0x200(%rbp)
jmp 0xca7d
movq -0x200(%rbp), %rdi
movl 0x1ec8e(%rip), %esi     # 0x2b718
callq 0x44d0
movq %rax, -0x208(%rbp)
jmp 0xca98
movq -0x208(%rbp), %rdi
movq 0x1e4ba(%rip), %rsi     # 0x2af60
callq 0x43b0
jmp 0xcaad
movzbl -0x34(%rbp), %edi
andl $0x1, %edi
callq 0xd7b0
jmp 0xcabb
jmp 0xcd9b
movq 0x1e529(%rip), %rdi     # 0x2aff0
leaq 0xf8f7(%rip), %rsi      # 0x1c3c5
callq 0x4370
movq %rax, -0x210(%rbp)
jmp 0xcadc
movq -0x210(%rbp), %rdi
movq 0x1ec16(%rip), %rsi     # 0x2b700
callq 0x4340
movq %rax, -0x218(%rbp)
jmp 0xcaf8
movq -0x218(%rbp), %rdi
movq 0x1e45a(%rip), %rsi     # 0x2af60
callq 0x43b0
jmp 0xcb0d
movq 0x1e4dc(%rip), %rdi     # 0x2aff0
leaq 0xf8bc(%rip), %rsi      # 0x1c3d7
callq 0x4370
movq %rax, -0x220(%rbp)
jmp 0xcb29
leaq 0x1ebf8(%rip), %rsi     # 0x2b728
leaq -0x158(%rbp), %rdi
callq 0x5540
jmp 0xcb3e
movq -0x220(%rbp), %rdi
leaq -0x158(%rbp), %rsi
callq 0x4300
movq %rax, -0x228(%rbp)
jmp 0xcb5a
movq -0x228(%rbp), %rdi
movq 0x1e3f8(%rip), %rsi     # 0x2af60
callq 0x43b0
jmp 0xcb6f
leaq -0x158(%rbp), %rdi
callq 0x4678
testb $0x1, 0x1eb9f(%rip)     # 0x2b721
je 0xcbf0
movq 0x1e465(%rip), %rdi     # 0x2aff0
leaq 0xf857(%rip), %rsi      # 0x1c3e9
callq 0x4370
movq %rax, -0x230(%rbp)
jmp 0xcba0
movq -0x230(%rbp), %rdi
leaq 0x1eb02(%rip), %rsi     # 0x2b6b0
callq 0x4300
movq %rax, -0x238(%rbp)
jmp 0xcbbc
movq -0x238(%rbp), %rdi
movq 0x1e396(%rip), %rsi     # 0x2af60
callq 0x43b0
jmp 0xcbd1
jmp 0xcbf0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x158(%rbp), %rdi
callq 0x4678
jmp 0xcdb4
movq 0x1e3f9(%rip), %rdi     # 0x2aff0
leaq 0xf7bd(%rip), %rsi      # 0x1c3bb
callq 0x4370
movq %rax, -0x240(%rbp)
jmp 0xcc0c
movq -0x240(%rbp), %rdi
movl 0x1eaff(%rip), %esi     # 0x2b718
callq 0x44d0
movq %rax, -0x248(%rbp)
jmp 0xcc27
movq -0x248(%rbp), %rdi
movq 0x1e32b(%rip), %rsi     # 0x2af60
callq 0x43b0
jmp 0xcc3c
movl $0x0, -0x15c(%rbp)
movl -0x15c(%rbp), %eax
cmpl 0x1eac6(%rip), %eax     # 0x2b718
jae 0xccde
leaq 0x1541(%rip), %rsi      # 0xe1a0
leaq -0x168(%rbp), %rdi
leaq -0x15c(%rbp), %rdx
callq 0xed90
jmp 0xcc74
movl -0x15c(%rbp), %eax
movl %eax, %esi
leaq -0xc0(%rbp), %rdi
callq 0xee50
movq %rax, -0x250(%rbp)
jmp 0xcc91
movq -0x250(%rbp), %rdi
leaq -0x168(%rbp), %rsi
callq 0xee90
leaq -0x168(%rbp), %rdi
callq 0xeed0
movl -0x15c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x15c(%rbp)
jmp 0xcc46
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x168(%rbp), %rdi
callq 0xeed0
jmp 0xcdb4
leaq -0xc0(%rbp), %rax
movq %rax, -0x170(%rbp)
movq -0x170(%rbp), %rdi
callq 0xef00
movq %rax, -0x178(%rbp)
movq -0x170(%rbp), %rdi
callq 0xef30
movq %rax, -0x180(%rbp)
leaq -0x178(%rbp), %rdi
leaq -0x180(%rbp), %rsi
callq 0xef60
testb $0x1, %al
jne 0xcd2b
jmp 0xcd5c
leaq -0x178(%rbp), %rdi
callq 0xefa0
movq %rax, -0x188(%rbp)
movq -0x188(%rbp), %rdi
callq 0x4680
jmp 0xcd4c
jmp 0xcd4e
leaq -0x178(%rbp), %rdi
callq 0xefc0
jmp 0xcd12
cmpq $0x0, 0x1e9ac(%rip)     # 0x2b710
jbe 0xcd99
movq 0x1e243(%rip), %rdi     # 0x2afb0
leaq 0xf686(%rip), %rsi      # 0x1c3fa
callq 0x4370
movq %rax, -0x258(%rbp)
jmp 0xcd82
movq -0x258(%rbp), %rdi
movq 0x1e1d0(%rip), %rsi     # 0x2af60
callq 0x43b0
jmp 0xcd97
jmp 0xcd99
jmp 0xcd9b
jmp 0xcd9d
jmp 0xcd9f
movl $0x0, -0x4(%rbp)
leaq -0xc0(%rbp), %rdi
callq 0xefe0
jmp 0xcdc2
leaq -0xc0(%rbp), %rdi
callq 0xefe0
jmp 0xcdce
movl -0x4(%rbp), %eax
addq $0x260, %rsp            # imm = 0x260
popq %rbp
retq
movq -0x68(%rbp), %rdi
callq 0x45e0
movq %rax, %rdi
callq 0x76d0
nop