// File: /workspace/github_c_makefile_star2_O1/c-zhou[P]yahs/yahs.c
// Function: run_scaffolding
int run_scaffolding(char *fai, char *agp, char *link_file, cov_norm_t *cov_norm, uint32_t ml, uint8_t mq, re_cuts_t *re_cuts, int8_t *telo_ends, char *out, int resolution, double *noise, uint32_t d_min_cell, double d_mass_frac, long rss_limit, int no_mem_check)
{
    //TODO: adjust wt thres by resolution
    sdict_t *sdict = make_sdict_from_index(fai, ml);
    asm_dict_t *dict = agp? make_asm_dict_from_agp(sdict, agp, 1) : make_asm_dict_from_sdict(sdict);
    
    int i, re = 0;
    uint64_t len = 0;
    for (i = 0; i < dict->n; ++i)
        len += dict->s[i].len;
#ifdef DEBUG_GRAPH_PRUNE
    fprintf(stderr, "[DEBUG_GRAPH_PRUNE::%s] #sequences loaded %d = %lubp\n", __func__, dict->n, len);
#endif

    long rss_intra, rss_inter;

    rss_intra = no_mem_check? 0 : estimate_intra_link_mat_init_rss(dict, resolution, 1);
    if ((rss_limit >= 0 && rss_intra > rss_limit) || rss_intra < 0) {
        // no enough memory
        fprintf(stderr, "[I::%s] No enough memory. Try lower resolutions... End of scaffolding round.\n", __func__);
        fprintf(stderr, "[I::%s] RAM    limit: %.3fGB\n", __func__, (double) rss_limit / GB);
        fprintf(stderr, "[I::%s] RAM required: %.3fGB\n", __func__, (double) rss_intra / GB);
        re = ENOMEM_ERR;
        goto scaff_failed_0;
    }
    rss_limit -= rss_intra;
    fprintf(stderr, "[I::%s] starting norm estimation...\n", __func__);
    intra_link_mat_t *intra_link_mat = intra_link_mat_from_file(link_file, cov_norm, dict, re_cuts, resolution, 1, mq);

#ifdef DEBUG_RAM_USAGE
    fprintf(stderr, "[DEBUG_RAM_USAGE::%s] RAM  peak: %.3fGB\n", __func__, (double) peakrss() / GB);
    fprintf(stderr, "[DEBUG_RAM_USAGE::%s] RAM intra: %.3fGB\n", __func__, (double) rss_intra / GB);
    fprintf(stderr, "[DEBUG_RAM_USAGE::%s] RAM  free: %.3fGB\n", __func__, (double) rss_limit / GB);
#endif

    norm_t *norm = calc_norms(intra_link_mat, d_min_cell, d_mass_frac);
    if (norm == 0) {
        fprintf(stderr, "[W::%s] No enough bands for norm calculation... End of scaffolding round.\n", __func__);
        re = ENOBND_ERR;
        goto scaff_failed_1;
    }

    rss_inter = no_mem_check? 0 : estimate_inter_link_mat_init_rss(dict, resolution, norm->r);
    if ((rss_limit >= 0 && rss_inter > rss_limit) || rss_inter < 0) {
        // no enough memory
        fprintf(stderr, "[I::%s] No enough memory. Try lower resolutions... End of scaffolding round.\n", __func__);
        fprintf(stderr, "[I::%s] RAM    limit: %.3fGB\n", __func__, (double) rss_limit / GB);
        fprintf(stderr, "[I::%s] RAM required: %.3fGB\n", __func__, (double) rss_inter / GB);
        re = ENOMEM_ERR;
        goto scaff_failed_1;
    }
    rss_limit -= rss_inter;
    fprintf(stderr, "[I::%s] starting link estimation...\n", __func__);
    inter_link_mat_t *inter_link_mat = inter_link_mat_from_file(link_file, cov_norm, dict, re_cuts, resolution, norm->r, mq);

#ifdef DEBUG_RAM_USAGE
    fprintf(stderr, "[DEBUG_RAM_USAGE::%s] RAM  peak: %.3fGB\n", __func__, (double) peakrss() / GB);
    fprintf(stderr, "[DEBUG_RAM_USAGE::%s] RAM inter: %.3fGB\n", __func__, (double) rss_inter / GB);
    fprintf(stderr, "[DEBUG_RAM_USAGE::%s] RAM  free: %.3fGB\n", __func__, (double) rss_limit / GB);
#endif

    *noise = inter_link_mat->noise / resolution / resolution;

    double la;
    re = inter_link_norms(inter_link_mat, norm, 1, max_noise_ratio, &la);
    if (re) {
        goto scaff_failed_2;
    }

    int8_t *directs = 0;
    // directs = calc_link_directs_from_file(link_file, dict);
    calc_link_directs(inter_link_mat, .1, dict, directs);
    if(directs) free(directs);

#ifdef DEBUG_LINK
    fprintf(stderr, "[DEBUG_LINK::%s] print_inter_link_norms\n", __func__);
    print_inter_link_norms(stderr, inter_link_mat, dict);
#endif

    int8_t *telos;
    telos = find_aseq_telos(dict, telo_ends);
    fprintf(stderr, "[I::%s] starting scaffolding graph contruction...\n", __func__);
    graph_t *g = build_graph_from_links(inter_link_mat, dict, .1, la, telos);
    
    free(telos);

#ifdef DEBUG_GRAPH_PRUNE
    fprintf(stderr, "[DEBUG_GRAPH_PRUNE::%s] scaffolding graph (before pruning) in GV format\n", __func__);
    graph_print_gv(g, stderr);
    fprintf(stderr, "[DEBUG_GRAPH_PRUNE::%s] scaffolding graph (before pruning) in GFA format\n", __func__);
    graph_print(g, stderr, 1);
#endif

    uint64_t n_arc;
    n_arc = g->n_arc;
#ifdef DEBUG_GRAPH_PRUNE
    fprintf(stderr, "[DEBUG_GRAPH_PRUNE::%s] number edges before trimming: %ld\n", __func__, n_arc);
    int round = 0;
#endif
    while (1) {
        trim_graph_simple_filter(g, .1, .7, .1, 0);
#ifdef DEBUG_GRAPH_PRUNE
        fprintf(stderr, "[DEBUG_GRAPH_PRUNE::%s] number edges after simple trimming round %d: %ld\n", __func__, round, g->n_arc);
        graph_print_gv(g, stderr);
#endif
        trim_graph_tips(g);
        trim_graph_blunts(g);
        trim_graph_repeats(g);
        trim_graph_transitive_edges(g);
        trim_graph_pop_bubbles(g);
        trim_graph_pop_undirected(g);
        trim_graph_weak_edges(g);
        trim_graph_self_loops(g);
#ifdef DEBUG_GRAPH_PRUNE
        fprintf(stderr, "[DEBUG_GRAPH_PRUNE::%s] number edges after trimming round %d: %ld\n", __func__, ++round, g->n_arc);
        graph_print_gv(g, stderr);
#endif
        if (g->n_arc == n_arc)
            break;
        else
            n_arc = g->n_arc;
    }
    trim_graph_ambiguous_edges(g);

#ifdef DEBUG_GRAPH_PRUNE
    fprintf(stderr, "[DEBUG_GRAPH_PRUNE::%s] scaffolding graph (after pruning) in GV format\n", __func__);
    graph_print_gv(g, stderr);
    fprintf(stderr, "[DEBUG_GRAPH_PRUNE::%s] scaffolding graph (after pruning) in GFA format\n", __func__);
    graph_print(g, stderr, 1);
#endif

    asm_dict_t *d = make_asm_dict_from_graph(g, g->sdict);
    // write scaffolds to AGP file
    FILE *agp_out = NULL;
    if (out) {
        char *agp_out_name = (char *) malloc(strlen(out) + 5);
        sprintf(agp_out_name, "%s.agp", out);
        agp_out = fopen(agp_out_name, "w");
        free(agp_out_name);
    } else {
        agp_out = fopen("scaffolds_FINAL.agp", "w");
    }
    if (agp_out == NULL) {
        fprintf(stderr, "[E::%s] fail to open file to write\n", __func__);
        re = 1;
    } else {
        write_asm_dict_to_agp(d, agp_out);
        fclose(agp_out);
    }

    asm_destroy(d);
    graph_destroy(g);

scaff_failed_2:
    inter_link_mat_destroy(inter_link_mat);

scaff_failed_1:
    norm_destroy(norm);
    intra_link_mat_destroy(intra_link_mat);

scaff_failed_0:
    asm_destroy(dict);
    sd_destroy(sdict);

    return re;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movsd %xmm0, 0x30(%rsp)
movl %r9d, %ebx
movq %rcx, 0x18(%rsp)
movq %rdx, 0x20(%rsp)
movq %rsi, %r14
movl %r8d, %esi
callq 0x11f82
testq %r14, %r14
movq %rax, 0x38(%rsp)
movq %rax, %rdi
jne 0x1e648
callq 0x12528
jmp 0x1e655
movq %r14, %rsi
movl $0x1, %edx
callq 0x129a4
movq %rax, %r14
movq 0xb0(%rsp), %r12
movl 0x98(%rsp), %r13d
cmpl $0x0, 0xb8(%rsp)
jne 0x1e687
movq %r14, %rdi
movl %r13d, %esi
movl $0x1, %edx
callq 0xca47
movq %rax, %r15
jmp 0x1e68a
xorl %r15d, %r15d
testq %r12, %r12
js 0x1e723
cmpq %r15, %r12
jb 0x1e72c
movq 0x80(%rsp), %rbp
movq 0xc94d(%rip), %rax      # 0x2aff8
movq (%rax), %rdi
leaq 0x4eed(%rip), %rsi      # 0x235a2
leaq 0x4e9a(%rip), %rdx      # 0x23556
xorl %eax, %eax
callq 0x22c0
movzbl %bl, %ebx
movl %ebx, (%rsp)
movq 0x20(%rsp), %rdi
movq 0x18(%rsp), %rsi
movq %r14, 0x10(%rsp)
movq %r14, %rdx
movq %rbp, %rcx
movl %r13d, %r8d
movl $0x1, %r9d
callq 0xcb09
movq %rax, 0x28(%rsp)
movq %rax, %rdi
movl 0xa8(%rsp), %esi
movsd 0x30(%rsp), %xmm0
callq 0xdc5a
movq %rax, %r13
testq %rax, %rax
jne 0x1e742
callq 0x42a3
movl $0xe, %r15d
movq 0x10(%rsp), %r14
jmp 0x1e84c
testq %r15, %r15
jns 0x1e69c
movq %r12, %rdi
movq %r15, %rsi
callq 0x42c2
movl $0xf, %r15d
jmp 0x1e85e
subq %r15, %r12
cmpl $0x0, 0xb8(%rsp)
jne 0x1e769
movl 0x20(%r13), %edx
movq 0x10(%rsp), %r14
movq %r14, %rdi
movl 0x98(%rsp), %esi
callq 0xc7f4
jmp 0x1e770
xorl %eax, %eax
movq 0x10(%rsp), %r14
movq 0xc881(%rip), %rcx      # 0x2aff8
testq %r12, %r12
js 0x1e832
cmpq %r12, %rax
ja 0x1e83b
movq 0xa0(%rsp), %r14
movq (%rcx), %rdi
leaq 0x4e77(%rip), %rsi      # 0x23612
leaq 0x4db4(%rip), %rdx      # 0x23556
xorl %eax, %eax
movq %rcx, %r12
callq 0x22c0
movl 0x20(%r13), %r9d
movl %ebx, (%rsp)
movq 0x20(%rsp), %rdi
movq 0x18(%rsp), %rsi
movq 0x10(%rsp), %rdx
movq 0x80(%rsp), %rcx
movl 0x98(%rsp), %ebx
movl %ebx, %r8d
callq 0xd072
movq %r13, %rsi
movq %rax, %r13
xorps %xmm0, %xmm0
cvtsi2sd %ebx, %xmm0
movsd 0x8(%rax), %xmm1
divsd %xmm0, %xmm1
divsd %xmm0, %xmm1
movsd %xmm1, (%r14)
movq 0x10(%rsp), %r14
movsd 0x2e33(%rip), %xmm0     # 0x21638
leaq 0x40(%rsp), %rcx
movq %rax, %rdi
movq %rsi, 0x18(%rsp)
movl $0x1, %edx
callq 0xe42c
movl %eax, %r15d
testl %eax, %eax
je 0x1e882
movq %r13, %rdi
callq 0xc42e
movq 0x18(%rsp), %r13
jmp 0x1e84c
testq %rax, %rax
jns 0x1e789
movq %r12, %rdi
movq %rax, %rsi
callq 0x4223
movl $0xf, %r15d
movq %r13, %rdi
callq 0xdc08
movq 0x28(%rsp), %rdi
callq 0xc3d4
movq %r14, %rdi
callq 0x11528
movq 0x38(%rsp), %rdi
callq 0x1148c
movl %r15d, %eax
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x90(%rsp), %r15
movq 0x88(%rsp), %rbx
movsd 0x2d9e(%rip), %xmm0     # 0x21638
movq %r13, %rdi
movq %r14, %rsi
xorl %edx, %edx
callq 0xeb4f
movq %r14, %rdi
movq %rbx, %rsi
callq 0x1e4d1
movq %rax, %rbx
movq (%r12), %rdi
leaq 0x4d77(%rip), %rsi      # 0x23637
leaq 0x4c8f(%rip), %rdx      # 0x23556
xorl %eax, %eax
callq 0x22c0
movsd 0x40(%rsp), %xmm1
movq %r13, %rdi
movq %r14, %rsi
movsd 0x2d56(%rip), %xmm0     # 0x21638
movq %rbx, %rdx
callq 0x1e2dc
movq %rax, %rbp
movq %rbx, %rdi
callq 0x2060
movq 0x18(%rbp), %rbx
movq %rbp, %rdi
movsd 0x2d34(%rip), %xmm0     # 0x21638
movsd 0x3fb4(%rip), %xmm1     # 0x228c0
movaps %xmm0, %xmm2
xorl %esi, %esi
callq 0x904f
movq %rbp, %rdi
callq 0x931e
movq %rbp, %rdi
callq 0x9464
movq %rbp, %rdi
callq 0x957e
movq %rbp, %rdi
callq 0x99f2
movq %rbp, %rdi
callq 0x9b53
movq %rbp, %rdi
callq 0x9de3
movq %rbp, %rdi
callq 0x9f31
movq %rbp, %rdi
callq 0x98e7
movq 0x18(%rbp), %rax
cmpq %rbx, %rax
movq %rax, %rbx
jne 0x1e8f9
movq %rbp, %rdi
callq 0xa08b
movq 0x8(%rbp), %rsi
movq %rbp, %rdi
callq 0xa167
movq %rax, %rbx
testq %r15, %r15
je 0x1e9c2
movq %r15, %rdi
callq 0x2160
leaq 0x5(%rax), %rdi
callq 0x2330
movq %r15, %rdx
movq %rax, %r15
leaq 0x4cce(%rip), %rsi      # 0x2366a
movq %rax, %rdi
xorl %eax, %eax
callq 0x24a0
leaq 0x2663(%rip), %rsi      # 0x21010
movq %r15, %rdi
callq 0x23e0
movq %rax, %r14
movq %r15, %rdi
callq 0x2060
jmp 0x1e9d8
leaq 0x4ca8(%rip), %rdi      # 0x23671
leaq 0x2640(%rip), %rsi      # 0x21010
callq 0x23e0
movq %rax, %r14
testq %r14, %r14
je 0x1ea0d
movq %rbx, %rdi
movq %r14, %rsi
callq 0x14f33
movq %r14, %rdi
callq 0x2150
xorl %r15d, %r15d
movq 0x10(%rsp), %r14
movq %rbx, %rdi
callq 0x11528
movq %rbp, %rdi
callq 0x82a0
jmp 0x1e823
callq 0x41fe
movl $0x1, %r15d
jmp 0x1e9f3