// File: karel-brinda[P]ococo/src/caller.h
// Function: ococo::caller_t<unsigned short, 3, 4>::run()
void caller_t<T, counter_size, refbase_size>::run() {
    /*
     * Process alignments.
     */
    ococo::info("Starting the main loop.\n");

    int32_t r;
    b              = bam_init1();
    int64_t n_upd0 = 0;
    int64_t i_read = 0;
    while ((r = sam_read1(params->sam_file, header, b)) >= 0) {
        const char *rname          = bam_get_qname(b);
        const uint8_t *seq         = bam_get_seq(b);
        const uint8_t *qual        = bam_get_qual(b);
        const uint32_t *cigar      = bam_get_cigar(b);
        const int32_t n_cigar      = b->core.n_cigar;
        const int32_t seqid        = b->core.tid;
        const int64_t mappping_pos = b->core.pos;
        const int32_t mapq         = b->core.qual;
        const int32_t flags        = b->core.flag;

        bool read_ok = check_read(seqid, flags, mapq);
        if (!read_ok) {
            continue;
        }

        int32_t ref_pos = mappping_pos;
        for (int32_t cigar_grp = 0, read_pos = 0; cigar_grp < n_cigar;
             cigar_grp++) {
            const int32_t op = bam_cigar_op(cigar[cigar_grp]);
            const int32_t ol = bam_cigar_oplen(cigar[cigar_grp]);

            const int32_t next_read_pos = read_pos + ol;
            switch (op) {
                case BAM_CMATCH:
                case BAM_CDIFF:
                case BAM_CEQUAL:

                    for (; read_pos < next_read_pos; read_pos++, ref_pos++) {
                        const uint8_t nt16 = bam_seqi(seq, read_pos);
                        const uint8_t nt4  = ococo::nt16_nt4[nt16];
                        // const char nt256 =
                        // ococo::nt16_nt256[nt16];
                        const int32_t bq = qual[read_pos];

                        if (bq != 0xff && bq < (stats->params->min_baseq)) {
                            continue;
                        }

                        if (nt4 == 0x4) {
                            continue;
                        }

                        stats->seq_stats[seqid][ref_pos] = stats->increment(
                            stats->seq_stats[seqid][ref_pos], nt4);

                        if (stats->params->mode == ococo::mode_t::REALTIME) {
                            stats->call_consensus_position(params->vcf_file,
                                                           params->pileup_file,
                                                           seqid, ref_pos);
                        }
                    }

                    break;

                case BAM_CDEL:
                case BAM_CREF_SKIP:
                    ref_pos += ol;
                    break;

                case BAM_CSOFT_CLIP:
                    read_pos += ol;
                    break;

                case BAM_CBACK:
                    ref_pos -= ol;
                    break;

                case BAM_CINS:
                    read_pos += ol;
                    break;

                case BAM_CPAD:
                case BAM_CHARD_CLIP:
                    break;
            }

        }

        if (stats->params->log_file != nullptr) {
            fprintf(stats->params->log_file,
                    "%" PRIu64 "\t%s\t%" PRIu64 "\n", i_read, rname,
                    stats->params->n_upd - n_upd0);
            n_upd0 = stats->params->n_upd;
        }

        i_read += 1;
    }

    /*
     * Call final consensus and export stats.
     */

    if (stats->params->mode == ococo::mode_t::BATCH) {
        stats->call_consensus(params->vcf_file, params->pileup_file);

        if (params->fasta_out_fn.size() > 0) {
            int error_code = stats->save_fasta(params->fasta_out_fn);
            if (error_code != 0) {
                ococo::error("FASTA '%s' could not be saved.\n",
                             params->fasta_out_fn.c_str());
                return_code = EXIT_FAILURE;
            }
        }
    }

    if (params->stats_out_fn.size() > 0) {
        ococo::info("Saving statistics ('%s').\n",
                    params->stats_out_fn.c_str());

        int error_code = stats->export_stats(params->stats_out_fn);
        if (error_code != 0) {
            ococo::error("Statistics could not be saved ('%s').\n",
                         params->stats_out_fn.c_str());
            return_code = EXIT_FAILURE;
        }
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xa0, %rsp
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x90(%rbp)
leaq 0x724ea(%rip), %rdi     # 0x78a3b
movb $0x0, %al
callq 0xf5e0
callq 0x1b5f0
movq %rax, %rcx
movq -0x90(%rbp), %rax
movq %rcx, 0x10(%rax)
movq $0x0, -0x18(%rbp)
movq $0x0, -0x20(%rbp)
movq -0x90(%rbp), %rax
movq 0x28(%rax), %rcx
movq 0x198(%rcx), %rdi
movq 0x18(%rax), %rsi
movq 0x10(%rax), %rdx
callq 0x1f060
movl %eax, -0xc(%rbp)
cmpl $0x0, %eax
jl 0x693c
movq -0x90(%rbp), %rdi
movq 0x10(%rdi), %rax
movq 0x28(%rax), %rax
movq %rax, -0x28(%rbp)
movq 0x10(%rdi), %rax
movq 0x28(%rax), %rax
movq 0x10(%rdi), %rcx
movq 0x8(%rcx), %rcx
shrq $0x30, %rcx
shll $0x2, %ecx
movslq %ecx, %rcx
addq %rcx, %rax
movq 0x10(%rdi), %rcx
movq 0x8(%rcx), %rcx
shrq $0x18, %rcx
andq $0xff, %rcx
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, -0x30(%rbp)
movq 0x10(%rdi), %rax
movq 0x28(%rax), %rax
movq 0x10(%rdi), %rcx
movq 0x8(%rcx), %rcx
shrq $0x30, %rcx
shll $0x2, %ecx
movslq %ecx, %rcx
addq %rcx, %rax
movq 0x10(%rdi), %rcx
movq 0x8(%rcx), %rcx
shrq $0x18, %rcx
andq $0xff, %rcx
movslq %ecx, %rcx
addq %rcx, %rax
movq 0x10(%rdi), %rcx
movl 0x10(%rcx), %ecx
addl $0x1, %ecx
sarl %ecx
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, -0x38(%rbp)
movq 0x10(%rdi), %rax
movq 0x28(%rax), %rax
movq 0x10(%rdi), %rcx
movq 0x8(%rcx), %rcx
shrq $0x18, %rcx
andq $0xff, %rcx
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, -0x40(%rbp)
movq 0x10(%rdi), %rax
movq 0x8(%rax), %rax
shrq $0x30, %rax
movl %eax, -0x44(%rbp)
movq 0x10(%rdi), %rax
movl (%rax), %eax
movl %eax, -0x48(%rbp)
movq 0x10(%rdi), %rax
movslq 0x4(%rax), %rax
movq %rax, -0x50(%rbp)
movq 0x10(%rdi), %rax
movq 0x8(%rax), %rax
shrq $0x10, %rax
andq $0xff, %rax
movl %eax, -0x54(%rbp)
movq 0x10(%rdi), %rax
movq 0x8(%rax), %rax
shrq $0x20, %rax
andq $0xffff, %rax           # imm = 0xFFFF
movl %eax, -0x58(%rbp)
movl -0x48(%rbp), %esi
movl -0x58(%rbp), %edx
movl -0x54(%rbp), %ecx
callq 0xa460
andb $0x1, %al
movb %al, -0x59(%rbp)
testb $0x1, -0x59(%rbp)
jne 0x66d0
jmp 0x657b
movq -0x50(%rbp), %rax
movl %eax, -0x60(%rbp)
movl $0x0, -0x64(%rbp)
movl $0x0, -0x68(%rbp)
movl -0x64(%rbp), %eax
cmpl -0x44(%rbp), %eax
jge 0x68b9
movq -0x40(%rbp), %rax
movslq -0x64(%rbp), %rcx
movl (%rax,%rcx,4), %eax
andl $0xf, %eax
movl %eax, -0x6c(%rbp)
movq -0x40(%rbp), %rax
movslq -0x64(%rbp), %rcx
movl (%rax,%rcx,4), %eax
shrl $0x4, %eax
movl %eax, -0x70(%rbp)
movl -0x68(%rbp), %eax
movl -0x70(%rbp), %ecx
addl %ecx, %eax
movl %eax, -0x74(%rbp)
movl -0x6c(%rbp), %eax
movq %rax, -0x98(%rbp)
subq $0x9, %rax
ja 0x68a9
movq -0x98(%rbp), %rax
leaq 0x718c4(%rip), %rcx     # 0x78004
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
jmp 0x674b
movl -0x68(%rbp), %eax
cmpl -0x74(%rbp), %eax
jge 0x6877
movq -0x30(%rbp), %rax
movl -0x68(%rbp), %ecx
sarl %ecx
movslq %ecx, %rcx
movzbl (%rax,%rcx), %eax
movl -0x68(%rbp), %ecx
xorl $-0x1, %ecx
andl $0x1, %ecx
shll $0x2, %ecx
sarl %cl, %eax
andl $0xf, %eax
movb %al, -0x75(%rbp)
movzbl -0x75(%rbp), %eax
movl %eax, %ecx
leaq 0x73328(%rip), %rax     # 0x79ab0
movb (%rax,%rcx), %al
movb %al, -0x76(%rbp)
movq -0x38(%rbp), %rax
movslq -0x68(%rbp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, -0x7c(%rbp)
cmpl $0xff, -0x7c(%rbp)
je 0x67c5
movq -0x90(%rbp), %rcx
movl -0x7c(%rbp), %eax
movq 0x20(%rcx), %rcx
movq 0x30(%rcx), %rcx
cmpl 0x1b4(%rcx), %eax
jge 0x67c5
jmp 0x6860
movzbl -0x76(%rbp), %eax
cmpl $0x4, %eax
jne 0x67d3
jmp 0x6860
movq -0x90(%rbp), %rax
movq 0x20(%rax), %rax
movq 0x28(%rax), %rax
movslq -0x48(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movslq -0x60(%rbp), %rcx
movw (%rax,%rcx,2), %ax
movzwl %ax, %edi
movzbl -0x76(%rbp), %esi
callq 0xa4d0
movw %ax, %si
movq -0x90(%rbp), %rax
movq 0x20(%rax), %rcx
movq 0x28(%rcx), %rcx
movslq -0x48(%rbp), %rdx
movq (%rcx,%rdx,8), %rcx
movslq -0x60(%rbp), %rdx
movw %si, (%rcx,%rdx,2)
movq 0x20(%rax), %rax
movq 0x30(%rax), %rax
cmpl $0x1, 0x1a8(%rax)
jne 0x685e
movq -0x90(%rbp), %rax
movq 0x20(%rax), %rdi
movq 0x28(%rax), %rcx
movq 0x180(%rcx), %rsi
movq 0x28(%rax), %rax
movq 0x188(%rax), %rdx
movl -0x48(%rbp), %ecx
movslq -0x60(%rbp), %r8
callq 0xa5a0
jmp 0x6860
movl -0x68(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x68(%rbp)
movl -0x60(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x60(%rbp)
jmp 0x674b
jmp 0x68a9
movl -0x70(%rbp), %eax
addl -0x60(%rbp), %eax
movl %eax, -0x60(%rbp)
jmp 0x68a9
movl -0x70(%rbp), %eax
addl -0x68(%rbp), %eax
movl %eax, -0x68(%rbp)
jmp 0x68a9
movl -0x70(%rbp), %ecx
movl -0x60(%rbp), %eax
subl %ecx, %eax
movl %eax, -0x60(%rbp)
jmp 0x68a9
movl -0x70(%rbp), %eax
addl -0x68(%rbp), %eax
movl %eax, -0x68(%rbp)
jmp 0x68a9
jmp 0x68a9
jmp 0x68ab
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x66e5
movq -0x90(%rbp), %rax
movq 0x20(%rax), %rax
movq 0x30(%rax), %rax
cmpq $0x0, 0x1a0(%rax)
je 0x692b
movq -0x90(%rbp), %rax
movq 0x20(%rax), %rcx
movq 0x30(%rcx), %rcx
movq 0x1a0(%rcx), %rdi
movq -0x20(%rbp), %rdx
movq -0x28(%rbp), %rcx
movq 0x20(%rax), %rax
movq 0x30(%rax), %rax
movq 0x208(%rax), %r8
subq -0x18(%rbp), %r8
leaq 0x7214a(%rip), %rsi     # 0x78a54
movb $0x0, %al
callq 0x4830
movq -0x90(%rbp), %rax
movq 0x20(%rax), %rax
movq 0x30(%rax), %rax
movq 0x208(%rax), %rax
movq %rax, -0x18(%rbp)
movq -0x20(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x20(%rbp)
jmp 0x657b
movq -0x90(%rbp), %rax
movq 0x20(%rax), %rax
movq 0x30(%rax), %rax
cmpl $0x0, 0x1a8(%rax)
jne 0x69f9
movq -0x90(%rbp), %rax
movq 0x20(%rax), %rdi
movq 0x28(%rax), %rcx
movq 0x180(%rcx), %rsi
movq 0x28(%rax), %rax
movq 0x188(%rax), %rdx
callq 0xa700
movq -0x90(%rbp), %rax
movq 0x28(%rax), %rdi
addq $0x100, %rdi            # imm = 0x100
callq 0x43a0
cmpq $0x0, %rax
jbe 0x69f7
movq -0x90(%rbp), %rax
movq 0x20(%rax), %rdi
movq 0x28(%rax), %rsi
addq $0x100, %rsi            # imm = 0x100
callq 0xa7c0
movl %eax, -0x80(%rbp)
cmpl $0x0, -0x80(%rbp)
je 0x69f5
movq -0x90(%rbp), %rax
movq 0x28(%rax), %rdi
addq $0x100, %rdi            # imm = 0x100
callq 0x4200
movq %rax, %rsi
leaq 0x72080(%rip), %rdi     # 0x78a60
movb $0x0, %al
callq 0xf460
movq -0x90(%rbp), %rax
movl $0x1, 0x4(%rax)
jmp 0x69f7
jmp 0x69f9
movq -0x90(%rbp), %rax
movq 0x28(%rax), %rdi
addq $0x120, %rdi            # imm = 0x120
callq 0x43a0
cmpq $0x0, %rax
jbe 0x6aa4
movq -0x90(%rbp), %rax
movq 0x28(%rax), %rdi
addq $0x120, %rdi            # imm = 0x120
callq 0x4200
movq %rax, %rsi
leaq 0x72045(%rip), %rdi     # 0x78a80
movb $0x0, %al
callq 0xf5e0
movq -0x90(%rbp), %rax
movq 0x20(%rax), %rdi
movq 0x28(%rax), %rsi
addq $0x120, %rsi            # imm = 0x120
callq 0xa9e0
movl %eax, -0x84(%rbp)
cmpl $0x0, -0x84(%rbp)
je 0x6aa2
movq -0x90(%rbp), %rax
movq 0x28(%rax), %rdi
addq $0x120, %rdi            # imm = 0x120
callq 0x4200
movq %rax, %rsi
leaq 0x7200e(%rip), %rdi     # 0x78a9b
movb $0x0, %al
callq 0xf460
movq -0x90(%rbp), %rax
movl $0x1, 0x4(%rax)
jmp 0x6aa4
addq $0xa0, %rsp
popq %rbp
retq
nopl (%rax)