// File: /workspace/github_c_makefile_star2_O0/sc932[P]ALE/src/ssw.c
// Function: ssw_align
s_align* ssw_align (const s_profile* prof,
					const int8_t* ref,
				  	int32_t refLen,
				  	const uint8_t weight_gapO,
				  	const uint8_t weight_gapE,
					const uint8_t flag,	//  (from high to low) bit 5: return the best alignment beginning position; 6: if (ref_end1 - ref_begin1 <= filterd) && (read_end1 - read_begin1 <= filterd), return cigar; 7: if max score >= filters, return cigar; 8: always return cigar; if 6 & 7 are both setted, only return cigar when both filter fulfilled
					const uint16_t filters,
					const int32_t filterd,
					const int32_t maskLen) {

	alignment_end* bests = 0, *bests_reverse = 0;
	__m128i* vP = 0;
	int32_t word = 0, band_width = 0, readLen = prof->readLen;
	int8_t* read_reverse = 0;
	cigar* path;
	s_align* r = (s_align*)calloc(1, sizeof(s_align));
	r->ref_begin1 = -1;
	r->read_begin1 = -1;
	r->cigar = 0;
	r->cigarLen = 0;
    r->flag = 0;
	if (maskLen < 15) {
		fprintf(stderr, "When maskLen < 15, the function ssw_align doesn't return 2nd best alignment information.\n");
	}

	// Find the alignment scores and ending positions
	if (prof->profile_byte) {
		bests = sw_sse2_byte(ref, 0, refLen, readLen, weight_gapO, weight_gapE, prof->profile_byte, -1, prof->bias, maskLen);
		if (prof->profile_word && bests[0].score == 255) {
			free(bests);
			bests = sw_sse2_word(ref, 0, refLen, readLen, weight_gapO, weight_gapE, prof->profile_word, -1, maskLen);
			word = 1;
		} else if (bests[0].score == 255) {
			fprintf(stderr, "Please set 2 to the score_size parameter of the function ssw_init, otherwise the alignment results will be incorrect.\n");
			free(r);
			return NULL;
		}
	}else if (prof->profile_word) {
		bests = sw_sse2_word(ref, 0, refLen, readLen, weight_gapO, weight_gapE, prof->profile_word, -1, maskLen);
		word = 1;
	}else {
		fprintf(stderr, "Please call the function ssw_init before ssw_align.\n");
		free(r);
		return NULL;
	}
	r->score1 = bests[0].score;
	r->ref_end1 = bests[0].ref; // 0_based, always count from the input seq begin
	r->read_end1 = bests[0].read;   // 0_based, count from the alignment begin (aligned length of the read)
	if (maskLen >= 15) {
		r->score2 = bests[1].score;
		r->ref_end2 = bests[1].ref;
	} else {
		r->score2 = 0;
		r->ref_end2 = -1;
	}
	free(bests);
	if (flag == 0 || (flag == 2 && r->score1 < filters)) goto end;

	// Find the beginning position of the best alignment.
	read_reverse = seq_reverse(prof->read, r->read_end1);
	if (word == 0) {
		vP = qP_byte(read_reverse, prof->mat, r->read_end1 + 1, prof->n, prof->bias);
		bests_reverse = sw_sse2_byte(ref, 1, r->ref_end1 + 1, r->read_end1 + 1, weight_gapO, weight_gapE, vP, r->score1, prof->bias, maskLen);
	} else {
		vP = qP_word(read_reverse, prof->mat, r->read_end1 + 1, prof->n);
		bests_reverse = sw_sse2_word(ref, 1, r->ref_end1 + 1, r->read_end1 + 1, weight_gapO, weight_gapE, vP, r->score1, maskLen);
	}
	free(vP);
	free(read_reverse);
	r->ref_begin1 = bests_reverse[0].ref;
	r->read_begin1 = r->read_end1 - bests_reverse[0].read;

    if (UNLIKELY(r->score1 > bests_reverse[0].score)) { // banded_sw result will miss a small part
		fprintf(stderr, "Warning: The alignment path of one pair of sequences may miss a small part. [ssw.c ssw_align]\n");
        r->flag = 2;  
    }
    free(bests_reverse);

//    fprintf(stderr, "1: %d, ref_end: %d, read_end: %d\n 2: %d, ref_end: %d, read_end: %d\n", r->score1, r->ref_end1, r->read_end1, bests_reverse[0].score, bests_reverse[0].ref, bests_reverse[0].read);
	if ((7&flag) == 0 || ((2&flag) != 0 && r->score1 < filters) || ((4&flag) != 0 && (r->ref_end1 - r->ref_begin1 > filterd || r->read_end1 - r->read_begin1 > filterd))) goto end;

	// Generate cigar.
	refLen = r->ref_end1 - r->ref_begin1 + 1;
	readLen = r->read_end1 - r->read_begin1 + 1;
	band_width = abs(refLen - readLen) + 1;
	path = banded_sw(ref + r->ref_begin1, prof->read + r->read_begin1, refLen, readLen, r->score1, weight_gapO, weight_gapE, band_width, prof->mat, prof->n);
	
    if (path == 0) r->flag = 1;    // banded_sw is failed.
    else {
		r->cigar = path->seq;
		r->cigarLen = path->length;
		free(path);
	}

end:
	return r;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %rbx
subq $0x98, %rsp
movl %r8d, -0x7c(%rbp)
movl %ecx, %eax
movl -0x7c(%rbp), %ecx
movl %eax, -0x78(%rbp)
movl %edx, %eax
movl -0x78(%rbp), %edx
movl %eax, -0x74(%rbp)
movq %rsi, %rax
movl -0x74(%rbp), %esi
movq %rax, -0x70(%rbp)
movq %rdi, %r8
movq -0x70(%rbp), %rdi
movb %r9b, %al
movl 0x20(%rbp), %r9d
movl 0x18(%rbp), %r9d
movw 0x10(%rbp), %r9w
movq %r8, -0x18(%rbp)
movq %rdi, -0x20(%rbp)
movl %esi, -0x24(%rbp)
movb %dl, -0x25(%rbp)
movb %cl, -0x26(%rbp)
movb %al, -0x27(%rbp)
movq $0x0, -0x30(%rbp)
movq $0x0, -0x38(%rbp)
movq $0x0, -0x40(%rbp)
movl $0x0, -0x44(%rbp)
movl $0x0, -0x48(%rbp)
movq -0x18(%rbp), %rax
movl 0x20(%rax), %eax
movl %eax, -0x4c(%rbp)
movq $0x0, -0x58(%rbp)
movl $0x1, %edi
movl $0x28, %esi
callq 0x3310
movq %rax, -0x68(%rbp)
movq -0x68(%rbp), %rax
movl $0xffffffff, 0x4(%rax)  # imm = 0xFFFFFFFF
movq -0x68(%rbp), %rax
movl $0xffffffff, 0xc(%rax)  # imm = 0xFFFFFFFF
movq -0x68(%rbp), %rax
movq $0x0, 0x18(%rax)
movq -0x68(%rbp), %rax
movl $0x0, 0x20(%rax)
movq -0x68(%rbp), %rax
movw $0x0, 0x24(%rax)
cmpl $0xf, 0x20(%rbp)
jge 0x10a15
movq 0x285f4(%rip), %rax     # 0x38ff8
movq (%rax), %rdi
leaq 0x215d2(%rip), %rsi     # 0x31fe0
movb $0x0, %al
callq 0x3350
movq -0x18(%rbp), %rax
cmpq $0x0, (%rax)
je 0x10b21
movq -0x20(%rbp), %rdi
movl -0x24(%rbp), %edx
movl -0x4c(%rbp), %ecx
movb -0x25(%rbp), %r8b
movb -0x26(%rbp), %r9b
movq -0x18(%rbp), %rax
movq (%rax), %r11
movq -0x18(%rbp), %rax
movb 0x28(%rax), %r10b
movl 0x20(%rbp), %eax
xorl %esi, %esi
movzbl %r8b, %r8d
movzbl %r9b, %r9d
movq %r11, (%rsp)
movl $0xff, 0x8(%rsp)
movzbl %r10b, %r10d
movl %r10d, 0x10(%rsp)
movl %eax, 0x18(%rsp)
callq 0x10f50
movq %rax, -0x30(%rbp)
movq -0x18(%rbp), %rax
cmpq $0x0, 0x8(%rax)
je 0x10ade
movq -0x30(%rbp), %rax
movzwl (%rax), %eax
cmpl $0xff, %eax
jne 0x10ade
movq -0x30(%rbp), %rdi
callq 0x3050
movq -0x20(%rbp), %rdi
movl -0x24(%rbp), %edx
movl -0x4c(%rbp), %ecx
movb -0x25(%rbp), %r8b
movb -0x26(%rbp), %r9b
movq -0x18(%rbp), %rax
movq 0x8(%rax), %r10
movl 0x20(%rbp), %eax
xorl %esi, %esi
movzbl %r8b, %r8d
movzbl %r9b, %r9d
movq %r10, (%rsp)
movl $0xffff, 0x8(%rsp)      # imm = 0xFFFF
movl %eax, 0x10(%rsp)
callq 0x121f0
movq %rax, -0x30(%rbp)
movl $0x1, -0x44(%rbp)
jmp 0x10b1c
movq -0x30(%rbp), %rax
movzwl (%rax), %eax
cmpl $0xff, %eax
jne 0x10b1a
movq 0x28505(%rip), %rax     # 0x38ff8
movq (%rax), %rdi
leaq 0x2153d(%rip), %rsi     # 0x3203a
movb $0x0, %al
callq 0x3350
movq -0x68(%rbp), %rdi
callq 0x3050
movq $0x0, -0x10(%rbp)
jmp 0x10f33
jmp 0x10b1c
jmp 0x10ba5
movq -0x18(%rbp), %rax
cmpq $0x0, 0x8(%rax)
je 0x10b75
movq -0x20(%rbp), %rdi
movl -0x24(%rbp), %edx
movl -0x4c(%rbp), %ecx
movb -0x25(%rbp), %r8b
movb -0x26(%rbp), %r9b
movq -0x18(%rbp), %rax
movq 0x8(%rax), %r10
movl 0x20(%rbp), %eax
xorl %esi, %esi
movzbl %r8b, %r8d
movzbl %r9b, %r9d
movq %r10, (%rsp)
movl $0xffff, 0x8(%rsp)      # imm = 0xFFFF
movl %eax, 0x10(%rsp)
callq 0x121f0
movq %rax, -0x30(%rbp)
movl $0x1, -0x44(%rbp)
jmp 0x10ba3
movq 0x2847c(%rip), %rax     # 0x38ff8
movq (%rax), %rdi
leaq 0x2152b(%rip), %rsi     # 0x320b1
movb $0x0, %al
callq 0x3350
movq -0x68(%rbp), %rdi
callq 0x3050
movq $0x0, -0x10(%rbp)
jmp 0x10f33
jmp 0x10ba5
movq -0x30(%rbp), %rax
movw (%rax), %cx
movq -0x68(%rbp), %rax
movw %cx, (%rax)
movq -0x30(%rbp), %rax
movl 0x4(%rax), %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x8(%rax)
movq -0x30(%rbp), %rax
movl 0x8(%rax), %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x10(%rax)
cmpl $0xf, 0x20(%rbp)
jl 0x10bf5
movq -0x30(%rbp), %rax
movw 0xc(%rax), %cx
movq -0x68(%rbp), %rax
movw %cx, 0x2(%rax)
movq -0x30(%rbp), %rax
movl 0x10(%rax), %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x14(%rax)
jmp 0x10c0a
movq -0x68(%rbp), %rax
movw $0x0, 0x2(%rax)
movq -0x68(%rbp), %rax
movl $0xffffffff, 0x14(%rax) # imm = 0xFFFFFFFF
movq -0x30(%rbp), %rdi
callq 0x3050
movzbl -0x27(%rbp), %eax
cmpl $0x0, %eax
je 0x10c34
movzbl -0x27(%rbp), %eax
cmpl $0x2, %eax
jne 0x10c39
movq -0x68(%rbp), %rax
movzwl (%rax), %eax
movzwl 0x10(%rbp), %ecx
cmpl %ecx, %eax
jge 0x10c39
jmp 0x10f2b
movq -0x18(%rbp), %rax
movq 0x10(%rax), %rdi
movq -0x68(%rbp), %rax
movl 0x10(%rax), %esi
callq 0x131c0
movq %rax, -0x58(%rbp)
cmpl $0x0, -0x44(%rbp)
jne 0x10cf5
movq -0x58(%rbp), %rdi
movq -0x18(%rbp), %rax
movq 0x18(%rax), %rsi
movq -0x68(%rbp), %rax
movl 0x10(%rax), %edx
addl $0x1, %edx
movq -0x18(%rbp), %rax
movl 0x24(%rax), %ecx
movq -0x18(%rbp), %rax
movzbl 0x28(%rax), %r8d
callq 0x10680
movq %rax, -0x40(%rbp)
movq -0x20(%rbp), %rdi
movq -0x68(%rbp), %rax
movl 0x8(%rax), %edx
addl $0x1, %edx
movq -0x68(%rbp), %rax
movl 0x10(%rax), %ecx
addl $0x1, %ecx
movb -0x25(%rbp), %r8b
movb -0x26(%rbp), %r9b
movq -0x40(%rbp), %rbx
movq -0x68(%rbp), %rax
movw (%rax), %ax
movb %al, %r11b
movq -0x18(%rbp), %rax
movb 0x28(%rax), %r10b
movl 0x20(%rbp), %eax
movl $0x1, %esi
movzbl %r8b, %r8d
movzbl %r9b, %r9d
movq %rbx, (%rsp)
movzbl %r11b, %r11d
movl %r11d, 0x8(%rsp)
movzbl %r10b, %r10d
movl %r10d, 0x10(%rsp)
movl %eax, 0x18(%rsp)
callq 0x10f50
movq %rax, -0x38(%rbp)
jmp 0x10d71
movq -0x58(%rbp), %rdi
movq -0x18(%rbp), %rax
movq 0x18(%rax), %rsi
movq -0x68(%rbp), %rax
movl 0x10(%rax), %edx
addl $0x1, %edx
movq -0x18(%rbp), %rax
movl 0x24(%rax), %ecx
callq 0x107b0
movq %rax, -0x40(%rbp)
movq -0x20(%rbp), %rdi
movq -0x68(%rbp), %rax
movl 0x8(%rax), %edx
addl $0x1, %edx
movq -0x68(%rbp), %rax
movl 0x10(%rax), %ecx
addl $0x1, %ecx
movb -0x25(%rbp), %r8b
movb -0x26(%rbp), %r9b
movq -0x40(%rbp), %r11
movq -0x68(%rbp), %rax
movw (%rax), %r10w
movl 0x20(%rbp), %eax
movl $0x1, %esi
movzbl %r8b, %r8d
movzbl %r9b, %r9d
movq %r11, (%rsp)
movzwl %r10w, %r10d
movl %r10d, 0x8(%rsp)
movl %eax, 0x10(%rsp)
callq 0x121f0
movq %rax, -0x38(%rbp)
movq -0x40(%rbp), %rdi
callq 0x3050
movq -0x58(%rbp), %rdi
callq 0x3050
movq -0x38(%rbp), %rax
movl 0x4(%rax), %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x4(%rax)
movq -0x68(%rbp), %rax
movl 0x10(%rax), %ecx
movq -0x38(%rbp), %rax
subl 0x8(%rax), %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0xc(%rax)
movq -0x68(%rbp), %rax
movzwl (%rax), %eax
movq -0x38(%rbp), %rcx
movzwl (%rcx), %ecx
cmpl %ecx, %eax
setg %al
andb $0x1, %al
movzbl %al, %eax
cltq
cmpq $0x0, %rax
je 0x10de8
movq 0x2822b(%rip), %rax     # 0x38ff8
movq (%rax), %rdi
leaq 0x2130f(%rip), %rsi     # 0x320e6
movb $0x0, %al
callq 0x3350
movq -0x68(%rbp), %rax
movw $0x2, 0x24(%rax)
movq -0x38(%rbp), %rdi
callq 0x3050
movzbl -0x27(%rbp), %eax
andl $0x7, %eax
cmpl $0x0, %eax
je 0x10e4a
movzbl -0x27(%rbp), %eax
andl $0x2, %eax
cmpl $0x0, %eax
je 0x10e18
movq -0x68(%rbp), %rax
movzwl (%rax), %eax
movzwl 0x10(%rbp), %ecx
cmpl %ecx, %eax
jl 0x10e4a
movzbl -0x27(%rbp), %eax
andl $0x4, %eax
cmpl $0x0, %eax
je 0x10e4f
movq -0x68(%rbp), %rax
movl 0x8(%rax), %eax
movq -0x68(%rbp), %rcx
subl 0x4(%rcx), %eax
cmpl 0x18(%rbp), %eax
jg 0x10e4a
movq -0x68(%rbp), %rax
movl 0x10(%rax), %eax
movq -0x68(%rbp), %rcx
subl 0xc(%rcx), %eax
cmpl 0x18(%rbp), %eax
jle 0x10e4f
jmp 0x10f2b
movq -0x68(%rbp), %rax
movl 0x8(%rax), %eax
movq -0x68(%rbp), %rcx
subl 0x4(%rcx), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
movq -0x68(%rbp), %rax
movl 0x10(%rax), %eax
movq -0x68(%rbp), %rcx
subl 0xc(%rcx), %eax
addl $0x1, %eax
movl %eax, -0x4c(%rbp)
movl -0x24(%rbp), %eax
subl -0x4c(%rbp), %eax
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
addl $0x1, %eax
movl %eax, -0x48(%rbp)
movq -0x20(%rbp), %rdi
movq -0x68(%rbp), %rax
movslq 0x4(%rax), %rax
addq %rax, %rdi
movq -0x18(%rbp), %rax
movq 0x10(%rax), %rsi
movq -0x68(%rbp), %rax
movslq 0xc(%rax), %rax
addq %rax, %rsi
movl -0x24(%rbp), %edx
movl -0x4c(%rbp), %ecx
movq -0x68(%rbp), %rax
movzwl (%rax), %r8d
movzbl -0x25(%rbp), %r9d
movzbl -0x26(%rbp), %ebx
movl -0x48(%rbp), %r11d
movq -0x18(%rbp), %rax
movq 0x18(%rax), %r10
movq -0x18(%rbp), %rax
movl 0x24(%rax), %eax
movl %ebx, (%rsp)
movl %r11d, 0x8(%rsp)
movq %r10, 0x10(%rsp)
movl %eax, 0x18(%rsp)
callq 0x13250
movq %rax, -0x60(%rbp)
cmpq $0x0, -0x60(%rbp)
jne 0x10f03
movq -0x68(%rbp), %rax
movw $0x1, 0x24(%rax)
jmp 0x10f29
movq -0x60(%rbp), %rax
movq (%rax), %rcx
movq -0x68(%rbp), %rax
movq %rcx, 0x18(%rax)
movq -0x60(%rbp), %rax
movl 0x8(%rax), %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x20(%rax)
movq -0x60(%rbp), %rdi
callq 0x3050
jmp 0x10f2b
movq -0x68(%rbp), %rax
movq %rax, -0x10(%rbp)
movq -0x10(%rbp), %rax
addq $0x98, %rsp
popq %rbx
popq %rbp
retq
nopw %cs:(%rax,%rax)