// File: ridiculousfish[P]docopt_fish/docopt_matching.cpp
// Function: docopt_fish::match_usages(std::vector<docopt_fish::usage_t, std::allocator<docopt_fish::usage_t>> const&, unsigned int, std::vector<docopt_fish::option_t, std::allocator<docopt_fish::option_t>> const&, docopt_fish::arg_classification_t const&, std::vector<std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>, std::allocator<std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>>> const&)
match_results_t match_usages(const std::vector<usage_t> &usages,
                             parse_flags_t flags,
                             const option_list_t &shortcut_options,
                             const arg_classification_t &aclass,
                             const string_list_t &argv) {
    
    match_context_t ctx(flags, shortcut_options, aclass, argv);
    size_t opt_count = ctx.aclass.resolved_options.size();
    match_state_list_t states;
    match(usages, match_state_t(opt_count), ctx, &states);
    
    // Illustration of some logging to help debug matching
    const bool log_stuff = false;
    if (log_stuff) {
        errstream() << "Matched " << states.size() << " way(s)\n";
        for (size_t i = 0; i < states.size(); i++) {
            const match_state_t &state = states.at(i);
            bool is_incomplete = !ctx.unused_arguments(&state).empty();
            errstream() << "Result " << i << (is_incomplete ? " (INCOMPLETE)" : "") << ":\n";
            for (const auto &kv : *state.argument_values) {
                const rstring_t &name = kv.first;
                const argument_t &arg = kv.second;
                errstream() << "\t" << name.std_string() << ": ";
                for (size_t j = 0; j < arg.values.size(); j++) {
                    if (j > 0) {
                        errstream() << ", ";
                    }
                    errstream() << arg.values.at(j);
                }
                errstream() << '\n';
            }
        }
    }
    
    match_results_t r;
    if (states.empty()) {
        // We had no states
        // Every arg is unused
        for (size_t i = 0; i < argv.size(); i++) {
            r.unused_args.push_back(i);
        }
    } else {
        // We got at least one state
        // Find the ones with the fewest unused arguments
        size_t fewest_unused_args = SIZE_MAX;
        for (match_state_t &st: states) {
            index_list_t unused_args = ctx.unused_arguments(&st);
            if (unused_args.size() < fewest_unused_args) {
                // Fewer unused args
                // Replace the suggestions
                fewest_unused_args = unused_args.size();
                r.option_map = std::move(st.argument_values.mut());
                r.unused_args = std::move(unused_args);
                r.suggestions = std::move(st.suggested_next_arguments);
            } else if (unused_args.size() == fewest_unused_args) {
                // Same number of unused args
                // Incorporate these suggestions too
                r.suggestions.insert(st.suggested_next_arguments.cbegin(),
                                     st.suggested_next_arguments.cend());
            }
        }
    }
    
    return r;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x170, %rsp            # imm = 0x170
movq %rdi, -0x150(%rbp)
movq %rdi, %rax
movq %rax, -0x148(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl %edx, -0x14(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq %r9, -0x30(%rbp)
movl -0x14(%rbp), %esi
movq -0x20(%rbp), %rdx
movq -0x28(%rbp), %rcx
movq -0x30(%rbp), %r8
leaq -0x50(%rbp), %rdi
callq 0x32030
movq -0x40(%rbp), %rdi
addq $0x18, %rdi
callq 0x25030
movq %rax, -0x58(%rbp)
leaq -0x70(%rbp), %rdi
callq 0x32070
movq -0x10(%rbp), %rax
movq %rax, -0x140(%rbp)
movq -0x58(%rbp), %rsi
leaq -0xd0(%rbp), %rdi
callq 0x32090
jmp 0x2fb82
movq -0x140(%rbp), %rdi
leaq -0xd0(%rbp), %rsi
leaq -0x50(%rbp), %rdx
leaq -0x70(%rbp), %rcx
callq 0x2feb0
jmp 0x2fb9f
leaq -0xd0(%rbp), %rdi
callq 0x321f0
movq -0x150(%rbp), %rdi
movb $0x0, -0xdd(%rbp)
movb $0x0, -0xde(%rbp)
callq 0x32230
leaq -0x70(%rbp), %rdi
callq 0x32270
testb $0x1, %al
jne 0x2fbd7
jmp 0x2fc89
movq $0x0, -0xe8(%rbp)
movq -0xe8(%rbp), %rax
movq %rax, -0x158(%rbp)
movq -0x30(%rbp), %rdi
callq 0xc910
movq %rax, %rcx
movq -0x158(%rbp), %rax
cmpq %rcx, %rax
jae 0x2fc84
movq -0x150(%rbp), %rdi
leaq -0xe8(%rbp), %rsi
callq 0x322b0
jmp 0x2fc1d
jmp 0x2fc1f
movq -0xe8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xe8(%rbp)
jmp 0x2fbe2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xd8(%rbp)
movl %eax, -0xdc(%rbp)
jmp 0x2fe90
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xd8(%rbp)
movl %eax, -0xdc(%rbp)
leaq -0xd0(%rbp), %rdi
callq 0x321f0
jmp 0x2fe90
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xd8(%rbp)
movl %eax, -0xdc(%rbp)
jmp 0x2fe84
jmp 0x2fe4f
movq $-0x1, -0xf0(%rbp)
leaq -0x70(%rbp), %rax
movq %rax, -0xf8(%rbp)
movq -0xf8(%rbp), %rdi
callq 0x32320
movq %rax, -0x100(%rbp)
movq -0xf8(%rbp), %rdi
callq 0x32350
movq %rax, -0x108(%rbp)
leaq -0x100(%rbp), %rdi
leaq -0x108(%rbp), %rsi
callq 0x32380
testb $0x1, %al
jne 0x2fce1
jmp 0x2fe4d
leaq -0x100(%rbp), %rdi
callq 0x323c0
movq %rax, -0x110(%rbp)
movq -0x110(%rbp), %rdx
leaq -0x128(%rbp), %rdi
leaq -0x50(%rbp), %rsi
callq 0x323e0
jmp 0x2fd0d
leaq -0x128(%rbp), %rdi
callq 0x32820
cmpq -0xf0(%rbp), %rax
jae 0x2fdbb
leaq -0x128(%rbp), %rdi
callq 0x32820
movq %rax, -0xf0(%rbp)
movq -0x110(%rbp), %rdi
callq 0x32840
movq %rax, -0x160(%rbp)
jmp 0x2fd4e
movq -0x150(%rbp), %rdi
movq -0x160(%rbp), %rsi
addq $0x18, %rdi
callq 0x12860
movq -0x150(%rbp), %rdi
leaq -0x128(%rbp), %rsi
callq 0x12830
movq -0x150(%rbp), %rdi
movq -0x110(%rbp), %rsi
addq $0x28, %rsi
addq $0x48, %rdi
callq 0x328a0
jmp 0x2fe30
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xd8(%rbp)
movl %eax, -0xdc(%rbp)
leaq -0x128(%rbp), %rdi
callq 0xd160
jmp 0x2fe84
leaq -0x128(%rbp), %rdi
callq 0x32820
cmpq -0xf0(%rbp), %rax
jne 0x2fe2e
movq -0x150(%rbp), %rax
addq $0x48, %rax
movq %rax, -0x168(%rbp)
movq -0x110(%rbp), %rdi
addq $0x28, %rdi
callq 0x32910
movq %rax, -0x130(%rbp)
movq -0x110(%rbp), %rdi
addq $0x28, %rdi
callq 0x32940
movq -0x168(%rbp), %rdi
movq %rax, -0x138(%rbp)
movq -0x130(%rbp), %rsi
movq -0x138(%rbp), %rdx
callq 0x328d0
jmp 0x2fe2c
jmp 0x2fe2e
jmp 0x2fe30
leaq -0x128(%rbp), %rdi
callq 0xd160
leaq -0x100(%rbp), %rdi
callq 0x32970
jmp 0x2fcc5
jmp 0x2fe4f
movb $0x1, -0xde(%rbp)
testb $0x1, -0xde(%rbp)
jne 0x2fe6b
movq -0x150(%rbp), %rdi
callq 0x12890
leaq -0x70(%rbp), %rdi
callq 0x32990
movq -0x148(%rbp), %rax
addq $0x170, %rsp            # imm = 0x170
popq %rbp
retq
movq -0x150(%rbp), %rdi
callq 0x12890
leaq -0x70(%rbp), %rdi
callq 0x32990
movq -0xd8(%rbp), %rdi
callq 0x85d0
nopw %cs:(%rax,%rax)