// File: /workspace/github_c_makefile_star2_O3/ToniWestbrook[P]paladin/uniprot.c
// Function: retrieveUniprotOnline
void retrieveUniprotOnline(UniprotList * passList, CURLBuffer * retBuffer, const char * passProxy) {
	int entryIdx, queryIdx, parseIdx, errorIdx, queryCount;
    long unsigned int jobSize;
	CURL * curlHandle;
	CURLcode curlResult;
	CURLBuffer tempBuffer;
	char queryString[UNIPROT_MAX_SUBMIT * 50], buildString[UNIPROT_MAX_SUBMIT * 50], jobID[50];
    char url[1024];
	char * httpString;

	// Init structures
	curlHandle = curl_easy_init();
	initCURLBuffer(retBuffer, UNIPROT_BUFFER_GROW);
	initCURLBuffer(&tempBuffer, UNIPROT_BUFFER_GROW);
	queryCount = (passList->entryCount < UNIPROT_MAX_SUBMIT) ? passList->entryCount : UNIPROT_MAX_SUBMIT;

	for (entryIdx = 0 ; entryIdx < passList->entryCount ; ) {
        // Preparation - build and sanitize query string outside of error loop 
        queryString[0] = 0;
        for (queryIdx = 0 ; (queryIdx < queryCount) && (entryIdx < passList->entryCount) ; entryIdx++) {
            for (parseIdx = 0 ; parseIdx < strlen(passList->entries[entryIdx].id) ; parseIdx++) {
                sprintf(buildString, "%s%s ", queryString, passList->entries[entryIdx].id);
                sprintf(queryString, "%s", buildString);
                queryIdx++;
                break;
            }
        }

        httpString = curl_easy_escape(curlHandle, queryString, 0);
        sprintf(queryString, "ids=%s&from=UniProtKB_AC-ID&to=UniProtKB", httpString);
        curl_free(httpString);

		// Restart a limited number of times if errors encountered
		for (errorIdx = 0 ; errorIdx < UNIPROT_MAX_ERROR ; errorIdx++) {
            // Stage 1 - Submit query for processing
            logMessage(__func__, LOG_LEVEL_MESSAGE, "Submitting %d of %d entries to UniProt...\n", entryIdx, passList->entryCount);

			curl_easy_setopt(curlHandle, CURLOPT_URL, "https://rest.uniprot.org/idmapping/run");
			curl_easy_setopt(curlHandle, CURLOPT_POSTFIELDS, queryString);
			curl_easy_setopt(curlHandle, CURLOPT_FOLLOWLOCATION, 0L);
			curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, receiveUniprotOutput);
			curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, &tempBuffer);
            if (passProxy) curl_easy_setopt(curlHandle, CURLOPT_PROXY, passProxy);

			resetCURLBuffer(&tempBuffer);
			curlResult = curl_easy_perform(curlHandle);

			if (curlResult != CURLE_OK) {
				logMessage(__func__, LOG_LEVEL_ERROR, "CURL: %s (retrying)\n", curl_easy_strerror(curlResult));
				continue;
			}

            if (strncmp(tempBuffer.buffer, "{\"jobId\":", 9) != 0) {
				logMessage(__func__, LOG_LEVEL_ERROR, "Received unexpected job ID response (retrying)\n");
				continue;
            }

			// Stage 2 - Wait for results
            jobSize = strnlen(tempBuffer.buffer, 8192) - 12;

            if (jobSize > 49) {
				logMessage(__func__, LOG_LEVEL_ERROR, "Received unexpected job ID size (retrying)\n");
				continue;
            }

			strncpy(jobID, tempBuffer.buffer + 10, jobSize);
			sprintf(url, "https://rest.uniprot.org/idmapping/status/%s", jobID);
            queryString[0] = '\0';

			resetCURLBuffer(&tempBuffer);
			curl_easy_setopt(curlHandle, CURLOPT_URL, url);
            curl_easy_setopt(curlHandle, CURLOPT_HTTPGET, 1l);

			while (strcmp(tempBuffer.buffer, "{\"jobStatus\":\"FINISHED\"}") != 0) {
				sleep(1);
				resetCURLBuffer(&tempBuffer);
				curlResult = curl_easy_perform(curlHandle);
				if (curlResult != CURLE_OK) break;
			}

			if (curlResult != CURLE_OK) {
				logMessage(__func__, LOG_LEVEL_ERROR, "CURL: %s (retrying)\n", curl_easy_strerror(curlResult));
				continue;
			}

			// Stage 3 - Retrieve Results
			sprintf(queryString, "format=tsv&fields=accession,organism_name,protein_name,gene_names,cc_pathway,feature_count,go,reviewed,protein_existence,cc_function,xref_kegg,xref_geneid,xref_patric,xref_ensemblbacteria,organism_id,lineage");
			sprintf(url, "https://rest.uniprot.org/idmapping/uniprotkb/results/stream/%s?%s", jobID, queryString);
			curl_easy_setopt(curlHandle, CURLOPT_URL, url);
			curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, retBuffer);

			curlResult = curl_easy_perform(curlHandle);

			if (curlResult != CURLE_OK) {
				logMessage(__func__, LOG_LEVEL_ERROR, "CURL: %s\n", curl_easy_strerror(curlResult));
				continue;
			}

			break;
		}

        // Check if download failed max number of times
        if (errorIdx == UNIPROT_MAX_ERROR) {
            logMessage(__func__, LOG_LEVEL_ERROR, "Download failed after multiple retries.  Please check Internet connection and finalize with PALADIN-plugins\n");
            break;
        }
	}

	curl_easy_cleanup(curlHandle);
	freeCURLBuffer(&tempBuffer);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x7a5a8, %rsp          # imm = 0x7A5A8
movq %rdx, 0x30(%rsp)
movq %rsi, %r13
movq %rdi, %r14
callq 0x3440
movq %rax, %rbx
movl $0x1, %edi
movl $0x2faf080, %esi        # imm = 0x2FAF080
callq 0x31b0
movq %rax, (%r13)
movabsq $0x2faf08000000000, %r15 # imm = 0x2FAF08000000000
movq %r13, 0x38(%rsp)
movq %r15, 0x8(%r13)
movl $0x1, %edi
movl $0x2faf080, %esi        # imm = 0x2FAF080
callq 0x31b0
leaq 0x8(%rsp), %rcx
movq %rax, (%rcx)
movq %r15, 0x8(%rcx)
movq %r14, 0x20(%rsp)
movl 0x8(%r14), %eax
movl $0x1388, %ecx           # imm = 0x1388
cmpl %ecx, %eax
movl %eax, 0x28(%rsp)
cmovll %eax, %ecx
movl %ecx, 0x2c(%rsp)
leaq 0x480(%rsp), %r13
xorl %r14d, %r14d
movq 0x20(%rsp), %rax
cmpl 0x8(%rax), %r14d
jge 0xabfd
movb $0x0, 0x480(%rsp)
cmpl $0x0, 0x28(%rsp)
jle 0xa8fd
movslq %r14d, %r14
leaq (,%r14,8), %rax
leaq (%rax,%rax,4), %r15
xorl %r12d, %r12d
movq 0x20(%rsp), %rax
movslq 0x8(%rax), %rax
cmpq %rax, %r14
jge 0xa8fd
movq 0x20(%rsp), %rax
movq (%rax), %rax
movq (%rax,%r15), %rcx
cmpb $0x0, (%rcx)
je 0xa8ef
leaq 0x3d510(%rsp), %rbp
movq %rbp, %rdi
leaq 0x1ccaa(%rip), %rsi     # 0x27581
movq %r13, %rdx
xorl %eax, %eax
callq 0x3070
movq %r13, %rdi
movq %rbp, %rsi
callq 0x32c0
incl %r12d
incq %r14
addq $0x28, %r15
cmpl 0x2c(%rsp), %r12d
jl 0xa8a6
movq %r14, 0x18(%rsp)
xorl %ebp, %ebp
movq %rbx, %rdi
movq %r13, %rsi
xorl %edx, %edx
callq 0x3690
movq %rax, %r15
movq %r13, %rdi
leaq 0x1cc69(%rip), %rsi     # 0x27587
movq %rax, %rdx
xorl %eax, %eax
callq 0x3070
movq %r15, %rdi
callq 0x30a0
leaq 0x8(%rsp), %r15
movq 0x18(%rsp), %rcx
movq 0x20(%rsp), %rax
movl 0x8(%rax), %r8d
leaq 0x1cc66(%rip), %rdi     # 0x275b0
movl $0x3, %esi
leaq 0x1cc70(%rip), %rdx     # 0x275c6
xorl %eax, %eax
callq 0xde80
movq %rbx, %rdi
movl $0x2712, %esi           # imm = 0x2712
leaq 0x1cc85(%rip), %rdx     # 0x275f1
xorl %eax, %eax
callq 0x3350
movq %rbx, %rdi
movl $0x271f, %esi           # imm = 0x271F
movq %r13, %rdx
xorl %eax, %eax
callq 0x3350
movq %rbx, %rdi
movl $0x34, %esi
xorl %edx, %edx
xorl %eax, %eax
callq 0x3350
movq %rbx, %rdi
movl $0x4e2b, %esi           # imm = 0x4E2B
leaq 0xb84(%rip), %rdx       # 0xb529
xorl %eax, %eax
callq 0x3350
movq %rbx, %rdi
movl $0x2711, %esi           # imm = 0x2711
movq %r15, %rdx
xorl %eax, %eax
callq 0x3350
cmpq $0x0, 0x30(%rsp)
je 0xa9da
movq %rbx, %rdi
movl $0x2714, %esi           # imm = 0x2714
movq 0x30(%rsp), %rdx
xorl %eax, %eax
callq 0x3350
movl $0x0, 0x10(%rsp)
movq 0x8(%rsp), %rax
movb $0x0, (%rax)
movq %rbx, %rdi
callq 0x3460
testl %eax, %eax
je 0xaa1c
movl %eax, %edi
callq 0x3520
leaq 0x1cbac(%rip), %rdi     # 0x275b0
movl $0x1, %esi
leaq 0x1cc08(%rip), %rdx     # 0x27618
movq %rax, %rcx
xorl %eax, %eax
callq 0xde80
jmp 0xaa84
movq 0x8(%rsp), %r15
movl $0x9, %edx
movq %r15, %rdi
leaq 0x1cbfd(%rip), %rsi     # 0x2762d
callq 0x3120
testl %eax, %eax
je 0xaa4e
leaq 0x1cb70(%rip), %rdi     # 0x275b0
movl $0x1, %esi
leaq 0x1cbeb(%rip), %rdx     # 0x27637
jmp 0xaa78
movl $0x2000, %esi           # imm = 0x2000
movq %r15, %rdi
callq 0x35a0
addq $-0xc, %rax
cmpq $0x32, %rax
jb 0xaa99
leaq 0x1cb44(%rip), %rdi     # 0x275b0
movl $0x1, %esi
leaq 0x1cbef(%rip), %rdx     # 0x27667
xorl %eax, %eax
callq 0xde80
leaq 0x8(%rsp), %r15
incl %ebp
cmpl $0x5, %ebp
movq 0x18(%rsp), %rcx
jne 0xa93a
jmp 0xabe3
addq $0xa, %r15
leaq 0x40(%rsp), %r14
movq %r14, %rdi
movq %r15, %rsi
movq %rax, %rdx
callq 0x3130
leaq 0x80(%rsp), %r15
movq %r15, %rdi
leaq 0x1cbd1(%rip), %rsi     # 0x27693
movq %r14, %rdx
xorl %eax, %eax
callq 0x3070
xorl %ecx, %ecx
movb %cl, 0x480(%rsp)
movl $0x0, 0x10(%rsp)
movq 0x8(%rsp), %rax
movb %cl, (%rax)
movq %rbx, %rdi
movl $0x2712, %esi           # imm = 0x2712
movq %r15, %rdx
xorl %eax, %eax
callq 0x3350
movl $0x1, %edx
movq %rbx, %rdi
movl $0x50, %esi
xorl %eax, %eax
callq 0x3350
leaq 0x8(%rsp), %r15
movq 0x8(%rsp), %rdi
leaq 0x1cba5(%rip), %rsi     # 0x276c0
callq 0x34d0
testl %eax, %eax
je 0xab4f
movl $0x1, %edi
callq 0x31e0
movl $0x0, 0x10(%rsp)
movq 0x8(%rsp), %rax
movb $0x0, (%rax)
movq %rbx, %rdi
callq 0x3460
testl %eax, %eax
je 0xab0f
jmp 0xa9f6
movl $0xd0, %edx
movq %r13, %rdi
leaq 0x1cb7b(%rip), %rsi     # 0x276d9
callq 0x3260
leaq 0x80(%rsp), %r14
movq %r14, %rdi
leaq 0x1cc34(%rip), %rsi     # 0x277a9
leaq 0x40(%rsp), %rdx
movq %r13, %rcx
xorl %eax, %eax
callq 0x3070
movq %rbx, %rdi
movl $0x2712, %esi           # imm = 0x2712
movq %r14, %rdx
xorl %eax, %eax
callq 0x3350
movq %rbx, %rdi
movl $0x2711, %esi           # imm = 0x2711
movq 0x38(%rsp), %rdx
xorl %eax, %eax
callq 0x3350
movq %rbx, %rdi
callq 0x3460
testl %eax, %eax
je 0xabd5
movl %eax, %edi
callq 0x3520
leaq 0x1c9ec(%rip), %rdi     # 0x275b0
movl $0x1, %esi
leaq 0x1cc1b(%rip), %rdx     # 0x277eb
jmp 0xaa10
cmpl $0x5, %ebp
movq 0x18(%rsp), %r14
jne 0xa876
leaq 0x1c9c6(%rip), %rdi     # 0x275b0
leaq 0x1cc04(%rip), %rdx     # 0x277f5
movl $0x1, %esi
xorl %eax, %eax
callq 0xde80
movq %rbx, %rdi
callq 0x33f0
movq 0x8(%rsp), %rdi
callq 0x3390
addq $0x7a5a8, %rsp          # imm = 0x7A5A8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq