// File: c2-d2[P]disty/src/main.cpp
// Function: main
int main (int argc, const char **argv) {
    params_t params;
    parse_arguments(argc, argv, params);

    assert(params.n_strategy!=n_strategy_t::REPLACE_CLOSEST);

    cerr << "Loading sequences from " << params.fasta_fn << endl;
    vector<string> names, seqs;
    load_sequences(params.fasta_fn, names, seqs);
    //print_sequences(seqs);

    int count=(int)seqs.size();
    int len=(int)seqs[0].size();

    cerr << "Computing pileup" << endl;
    vector<vector<int>> pileup(len, vector<int>(128));
    compute_pileup(seqs, pileup);
    //print_pileup(pileup);

    string consensus(len, '?');
    if(params.n_strategy==n_strategy_t::REPLACE_MAJOR){
        cerr << "Computing consensus" << endl;
        compute_consensus(pileup, consensus);
        //print_consensus(consensus);
    }


    cerr << "Computing mask" << endl;
    string mask(len, '?');
    if(params.n_strategy==n_strategy_t::IGNORE_GLOBALLY){
        compute_mask(mask, pileup, 1);
    }
    else{
        int min_n=ceil(count*params.skip_n);
        compute_mask(mask, pileup, min_n);
    }
    //print_mask(mask);


    cerr << "Computing distance matrix" << endl;
    vector<vector<int>> pair_matrix(128, vector<int>(128, 0));
    vector<vector<int>> distance_matrix(count, vector<int>(count, 0));
    pair_char_t pair_char;

    if(params.n_strategy==n_strategy_t::REPLACE_MAJOR){
        cerr << "Replacing N's by major alleles" << endl;
        for (auto &seq: seqs){
            for(int i=0;i<static_cast<int>(seq.size());i++){
                if (seq[i]=='N'||seq[i]=='N'){
                    seq[i]=consensus[i];
                }
            }
        }
    }


    /*
     * For each pair:
     */
    for(int i=0;i<count;i++){
        for(int j=0;j<=i;j++){
            //cerr << "\n(" << i << "," << j << ")" << endl;

            /*
             * 1) Pair matrix
             */
            compute_pair_matrix(seqs[i], seqs[j], mask, pair_matrix);

            /*
             * 2) Characteristics
             */

            if (params.input==input_t::ACGT){
                pair_matrix_char_acgt(pair_matrix, pair_char);
            }
            else{
                if (params.input==input_t::BINARY){
                    pair_matrix_char_binary(pair_matrix, pair_char);
                }
                else{
                    assert(false);
                }
            }

            //print_pair_matrix_char(pair_char);

            /*
             * 3) Distance
             */

            int dist=0;
            if(params.n_strategy==n_strategy_t::IGNORE_PAIRWISE_NORM){
                dist=distance_norm(pair_char);
            }
            else{
                dist=distance(pair_char);
            }
            distance_matrix[i][j]=distance_matrix[j][i]=dist;
        }
    }


    print_distance_matrix(distance_matrix, names);


    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x2d0, %rsp            # imm = 0x2D0
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
leaq -0x40(%rbp), %rdi
movq %rdi, -0x1c8(%rbp)
callq 0x4100
movq -0x1c8(%rbp), %rdx
movl -0x8(%rbp), %edi
movq -0x10(%rbp), %rsi
callq 0x25a0
jmp 0x2aee
cmpl $0x4, -0x1c(%rbp)
je 0x2af6
jmp 0x2b26
leaq 0x5b78(%rip), %rdi      # 0x8675
leaq 0x5aca(%rip), %rsi      # 0x85ce
movl $0x209, %edx            # imm = 0x209
leaq 0x5b96(%rip), %rcx      # 0x86a6
callq 0x2110
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x3538
movq 0xa4c3(%rip), %rdi      # 0xcff0
leaq 0x5b8f(%rip), %rsi      # 0x86c3
callq 0x21d0
movq %rax, -0x1d0(%rbp)
jmp 0x2b42
movq -0x1d0(%rbp), %rdi
leaq -0x40(%rbp), %rsi
callq 0x21c0
movq %rax, -0x1d8(%rbp)
jmp 0x2b5b
movq -0x1d8(%rbp), %rdi
movq 0xa43f(%rip), %rsi      # 0xcfa8
callq 0x2210
jmp 0x2b70
leaq -0x68(%rbp), %rdi
movq %rdi, -0x1e8(%rbp)
callq 0x4190
leaq -0x80(%rbp), %rdi
movq %rdi, -0x1e0(%rbp)
callq 0x4190
movq -0x1e8(%rbp), %rsi
movq -0x1e0(%rbp), %rdx
leaq -0x40(%rbp), %rdi
callq 0x41b0
jmp 0x2ba9
leaq -0x80(%rbp), %rdi
movq %rdi, -0x1f8(%rbp)
callq 0x4550
movq -0x1f8(%rbp), %rdi
movl %eax, -0x84(%rbp)
xorl %eax, %eax
movl %eax, %esi
callq 0x4570
movq %rax, %rdi
callq 0x2140
movl %eax, -0x88(%rbp)
movq 0xa40c(%rip), %rdi      # 0xcff0
leaq 0x5af0(%rip), %rsi      # 0x86db
callq 0x21d0
movq %rax, -0x1f0(%rbp)
jmp 0x2bf9
movq -0x1f0(%rbp), %rdi
movq 0xa3a1(%rip), %rsi      # 0xcfa8
callq 0x2210
jmp 0x2c0e
movslq -0x88(%rbp), %rax
movq %rax, -0x208(%rbp)
leaq -0xb9(%rbp), %rdi
movq %rdi, -0x200(%rbp)
callq 0x4590
movq -0x200(%rbp), %rdx
leaq -0xb8(%rbp), %rdi
movl $0x80, %esi
callq 0x45b0
jmp 0x2c49
leaq -0xba(%rbp), %rdi
movq %rdi, -0x210(%rbp)
callq 0x4620
movq -0x208(%rbp), %rsi
movq -0x210(%rbp), %rcx
leaq -0xa0(%rbp), %rdi
leaq -0xb8(%rbp), %rdx
callq 0x4640
jmp 0x2c7f
leaq -0xba(%rbp), %rdi
callq 0x46c0
leaq -0xb8(%rbp), %rdi
callq 0x46e0
leaq -0xb9(%rbp), %rdi
callq 0x4740
leaq -0x80(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
callq 0x4760
jmp 0x2cb5
movslq -0x88(%rbp), %rax
movq %rax, -0x220(%rbp)
leaq -0xe1(%rbp), %rdi
movq %rdi, -0x218(%rbp)
callq 0x2380
movq -0x220(%rbp), %rsi
movq -0x218(%rbp), %rcx
leaq -0xe0(%rbp), %rdi
movl $0x3f, %edx
callq 0x4920
jmp 0x2cf7
leaq -0xe1(%rbp), %rdi
callq 0x2230
cmpl $0x3, -0x1c(%rbp)
jne 0x2deb
movq 0xa2dc(%rip), %rdi      # 0xcff0
leaq 0x59d1(%rip), %rsi      # 0x86ec
callq 0x21d0
movq %rax, -0x228(%rbp)
jmp 0x2d29
movq -0x228(%rbp), %rdi
movq 0xa271(%rip), %rsi      # 0xcfa8
callq 0x2210
jmp 0x2d3e
leaq -0xa0(%rbp), %rdi
leaq -0xe0(%rbp), %rsi
callq 0x4990
jmp 0x2d53
jmp 0x2deb
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x3526
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x2d9b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0xba(%rbp), %rdi
callq 0x46c0
leaq -0xb8(%rbp), %rdi
callq 0x46e0
leaq -0xb9(%rbp), %rdi
callq 0x4740
jmp 0x3526
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x351a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0xe1(%rbp), %rdi
callq 0x2230
jmp 0x351a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x350e
movq 0xa1fe(%rip), %rdi      # 0xcff0
leaq 0x5907(%rip), %rsi      # 0x8700
callq 0x21d0
movq %rax, -0x230(%rbp)
jmp 0x2e07
movq -0x230(%rbp), %rdi
movq 0xa193(%rip), %rsi      # 0xcfa8
callq 0x2210
jmp 0x2e1c
movslq -0x88(%rbp), %rax
movq %rax, -0x240(%rbp)
leaq -0x109(%rbp), %rdi
movq %rdi, -0x238(%rbp)
callq 0x2380
movq -0x240(%rbp), %rsi
movq -0x238(%rbp), %rcx
leaq -0x108(%rbp), %rdi
movl $0x3f, %edx
callq 0x4920
jmp 0x2e5e
leaq -0x109(%rbp), %rdi
callq 0x2230
cmpl $0x2, -0x1c(%rbp)
jne 0x2eba
leaq -0x108(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
movl $0x1, %edx
callq 0x4ae0
jmp 0x2e8a
jmp 0x2f09
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0x109(%rbp), %rdi
callq 0x2230
jmp 0x350e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x3502
cvtsi2ssl -0x84(%rbp), %xmm0
movss -0x18(%rbp), %xmm1
mulss %xmm1, %xmm0
callq 0x4d30
movss %xmm0, -0x244(%rbp)
jmp 0x2eda
movss -0x244(%rbp), %xmm0
cvttss2si %xmm0, %eax
movl %eax, -0x110(%rbp)
movl -0x110(%rbp), %edx
leaq -0x108(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
callq 0x4ae0
jmp 0x2f07
jmp 0x2f09
movq 0xa0e0(%rip), %rdi      # 0xcff0
leaq 0x57f8(%rip), %rsi      # 0x870f
callq 0x21d0
movq %rax, -0x250(%rbp)
jmp 0x2f25
movq -0x250(%rbp), %rdi
movq 0xa075(%rip), %rsi      # 0xcfa8
callq 0x2210
jmp 0x2f3a
movl $0x0, -0x144(%rbp)
leaq -0x145(%rbp), %rdi
movq %rdi, -0x258(%rbp)
callq 0x4590
movq -0x258(%rbp), %rcx
leaq -0x140(%rbp), %rdi
movl $0x80, %esi
leaq -0x144(%rbp), %rdx
callq 0x4d50
jmp 0x2f78
leaq -0x146(%rbp), %rdi
movq %rdi, -0x260(%rbp)
callq 0x4620
movq -0x260(%rbp), %rcx
leaq -0x128(%rbp), %rdi
movl $0x80, %esi
leaq -0x140(%rbp), %rdx
callq 0x4640
jmp 0x2fac
leaq -0x146(%rbp), %rdi
callq 0x46c0
leaq -0x140(%rbp), %rdi
callq 0x46e0
leaq -0x145(%rbp), %rdi
callq 0x4740
movslq -0x84(%rbp), %rax
movq %rax, -0x270(%rbp)
movl $0x0, -0x17c(%rbp)
leaq -0x17d(%rbp), %rdi
movq %rdi, -0x268(%rbp)
callq 0x4590
movq -0x270(%rbp), %rsi
movq -0x268(%rbp), %rcx
leaq -0x178(%rbp), %rdi
leaq -0x17c(%rbp), %rdx
callq 0x4d50
jmp 0x301e
leaq -0x17e(%rbp), %rdi
movq %rdi, -0x278(%rbp)
callq 0x4620
movq -0x270(%rbp), %rsi
movq -0x278(%rbp), %rcx
leaq -0x160(%rbp), %rdi
leaq -0x178(%rbp), %rdx
callq 0x4640
jmp 0x3054
leaq -0x17e(%rbp), %rdi
callq 0x46c0
leaq -0x178(%rbp), %rdi
callq 0x46e0
leaq -0x17d(%rbp), %rdi
callq 0x4740
cmpl $0x3, -0x1c(%rbp)
jne 0x32c9
movq 0x9f67(%rip), %rdi      # 0xcff0
leaq 0x5699(%rip), %rsi      # 0x8729
callq 0x21d0
movq %rax, -0x280(%rbp)
jmp 0x309e
movq -0x280(%rbp), %rdi
movq 0x9efc(%rip), %rsi      # 0xcfa8
callq 0x2210
jmp 0x30b3
leaq -0x80(%rbp), %rax
movq %rax, -0x198(%rbp)
movq -0x198(%rbp), %rdi
callq 0x4dd0
movq %rax, -0x1a0(%rbp)
movq -0x198(%rbp), %rdi
callq 0x4e00
movq %rax, -0x1a8(%rbp)
leaq -0x1a0(%rbp), %rdi
leaq -0x1a8(%rbp), %rsi
callq 0x4e30
testb $0x1, %al
jne 0x3100
jmp 0x32c7
leaq -0x1a0(%rbp), %rdi
callq 0x4e70
movq %rax, -0x1b0(%rbp)
movl $0x0, -0x1b4(%rbp)
movl -0x1b4(%rbp), %eax
movl %eax, -0x284(%rbp)
movq -0x1b0(%rbp), %rdi
callq 0x2140
movq %rax, %rcx
movl -0x284(%rbp), %eax
cmpl %ecx, %eax
jge 0x32b4
movq -0x1b0(%rbp), %rdi
movslq -0x1b4(%rbp), %rsi
callq 0x23d0
movq %rax, -0x290(%rbp)
jmp 0x3162
movq -0x290(%rbp), %rax
movsbl (%rax), %eax
cmpl $0x4e, %eax
je 0x31a0
movq -0x1b0(%rbp), %rdi
movslq -0x1b4(%rbp), %rsi
callq 0x23d0
movq %rax, -0x298(%rbp)
jmp 0x318d
movq -0x298(%rbp), %rax
movsbl (%rax), %eax
cmpl $0x4e, %eax
jne 0x329e
movslq -0x1b4(%rbp), %rsi
leaq -0xe0(%rbp), %rdi
callq 0x23d0
movq %rax, -0x2a0(%rbp)
jmp 0x31bc
movq -0x2a0(%rbp), %rax
movb (%rax), %al
movb %al, -0x2a9(%rbp)
movq -0x1b0(%rbp), %rdi
movslq -0x1b4(%rbp), %rsi
callq 0x23d0
movq %rax, -0x2a8(%rbp)
jmp 0x31e7
movq -0x2a8(%rbp), %rax
movb -0x2a9(%rbp), %cl
movb %cl, (%rax)
jmp 0x329e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x322d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0x146(%rbp), %rdi
callq 0x46c0
leaq -0x140(%rbp), %rdi
callq 0x46e0
leaq -0x145(%rbp), %rdi
callq 0x4740
jmp 0x3502
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x3270
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0x17e(%rbp), %rdi
callq 0x46c0
leaq -0x178(%rbp), %rdi
callq 0x46e0
leaq -0x17d(%rbp), %rdi
callq 0x4740
jmp 0x34f6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0x160(%rbp), %rdi
callq 0x55d0
jmp 0x34f6
jmp 0x32a0
movl -0x1b4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1b4(%rbp)
jmp 0x311d
jmp 0x32b6
leaq -0x1a0(%rbp), %rdi
callq 0x4e90
jmp 0x30e4
jmp 0x32c9
movl $0x0, -0x1b8(%rbp)
movl -0x1b8(%rbp), %eax
cmpl -0x84(%rbp), %eax
jge 0x347a
movl $0x0, -0x1bc(%rbp)
movl -0x1bc(%rbp), %eax
cmpl -0x1b8(%rbp), %eax
jg 0x3464
movslq -0x1b8(%rbp), %rsi
leaq -0x80(%rbp), %rdi
movq %rdi, -0x2c0(%rbp)
callq 0x4570
movq -0x2c0(%rbp), %rdi
movq %rax, -0x2b8(%rbp)
movslq -0x1bc(%rbp), %rsi
callq 0x4570
movq -0x2b8(%rbp), %rdi
movq %rax, %rsi
leaq -0x108(%rbp), %rdx
leaq -0x128(%rbp), %rcx
callq 0x4eb0
jmp 0x3351
cmpl $0x0, -0x20(%rbp)
jne 0x336e
leaq -0x128(%rbp), %rdi
leaq -0x18c(%rbp), %rsi
callq 0x50a0
jmp 0x336c
jmp 0x33ac
cmpl $0x1, -0x20(%rbp)
jne 0x338b
leaq -0x128(%rbp), %rdi
leaq -0x18c(%rbp), %rsi
callq 0x5250
jmp 0x3389
jmp 0x33aa
leaq 0x53b6(%rip), %rdi      # 0x8748
leaq 0x5235(%rip), %rsi      # 0x85ce
movl $0x255, %edx            # imm = 0x255
leaq 0x5301(%rip), %rcx      # 0x86a6
callq 0x2110
jmp 0x33ac
movl $0x0, -0x1c0(%rbp)
cmpl $0x1, -0x1c(%rbp)
jne 0x33de
leaq -0x18c(%rbp), %rdi
callq 0x2a40
movl %eax, -0x2c4(%rbp)
jmp 0x33d0
movl -0x2c4(%rbp), %eax
movl %eax, -0x1c0(%rbp)
jmp 0x33f0
leaq -0x18c(%rbp), %rdi
callq 0x2a20
movl %eax, -0x1c0(%rbp)
movl -0x1c0(%rbp), %eax
movl %eax, -0x2c8(%rbp)
movslq -0x1bc(%rbp), %rsi
leaq -0x160(%rbp), %rdi
callq 0x53b0
movq %rax, %rdi
movslq -0x1b8(%rbp), %rsi
callq 0x53d0
movl -0x2c8(%rbp), %ecx
movl %ecx, (%rax)
movslq -0x1b8(%rbp), %rsi
leaq -0x160(%rbp), %rdi
callq 0x53b0
movq %rax, %rdi
movslq -0x1bc(%rbp), %rsi
callq 0x53d0
movl -0x2c8(%rbp), %ecx
movl %ecx, (%rax)
movl -0x1bc(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1bc(%rbp)
jmp 0x32ef
jmp 0x3466
movl -0x1b8(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1b8(%rbp)
jmp 0x32d3
leaq -0x160(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x53f0
jmp 0x348c
movl $0x0, -0x4(%rbp)
leaq -0x160(%rbp), %rdi
callq 0x55d0
leaq -0x128(%rbp), %rdi
callq 0x55d0
leaq -0x108(%rbp), %rdi
callq 0x23e8
leaq -0xe0(%rbp), %rdi
callq 0x23e8
leaq -0xa0(%rbp), %rdi
callq 0x55d0
leaq -0x80(%rbp), %rdi
callq 0x5630
leaq -0x68(%rbp), %rdi
callq 0x5630
leaq -0x40(%rbp), %rdi
callq 0x5690
movl -0x4(%rbp), %eax
addq $0x2d0, %rsp            # imm = 0x2D0
popq %rbp
retq
leaq -0x128(%rbp), %rdi
callq 0x55d0
leaq -0x108(%rbp), %rdi
callq 0x23e8
leaq -0xe0(%rbp), %rdi
callq 0x23e8
leaq -0xa0(%rbp), %rdi
callq 0x55d0
leaq -0x80(%rbp), %rdi
callq 0x5630
leaq -0x68(%rbp), %rdi
callq 0x5630
leaq -0x40(%rbp), %rdi
callq 0x5690
movq -0x48(%rbp), %rdi
callq 0x2370
nopw (%rax,%rax)