// File: /workspace/github_c_makefile_star2_O2/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, %r15
movq %rdi, %r14
callq 0x3440
movq %rax, %rbx
movq %r15, 0x38(%rsp)
movq %r15, %rdi
movl $0x2faf080, %esi        # imm = 0x2FAF080
callq 0x9d20
pushq $0x1
popq %rdi
movl $0x2faf080, %esi        # imm = 0x2FAF080
callq 0x31b0
leaq 0x8(%rsp), %rdx
movq %rax, (%rdx)
movabsq $0x2faf08000000000, %rax # imm = 0x2FAF08000000000
movq %rax, 0x8(%rdx)
movq %r14, 0x18(%rsp)
movl 0x8(%r14), %eax
movl $0x1388, %ecx           # imm = 0x1388
cmpl %ecx, %eax
cmovll %eax, %ecx
movl %ecx, 0x24(%rsp)
leaq 0x480(%rsp), %r13
xorl %r14d, %r14d
movq 0x18(%rsp), %rax
cmpl 0x8(%rax), %r14d
jge 0x9477
movb $0x0, 0x480(%rsp)
movslq %r14d, %r14
imulq $0x28, %r14, %r15
xorl %r12d, %r12d
cmpl 0x24(%rsp), %r12d
jge 0x919f
movq 0x18(%rsp), %rax
movslq 0x8(%rax), %rax
cmpq %rax, %r14
jge 0x919f
movq 0x18(%rsp), %rax
movq (%rax), %rax
movq (%rax,%r15), %rcx
cmpb $0x0, (%rcx)
je 0x9196
leaq 0x3d510(%rsp), %rbp
movq %rbp, %rdi
leaq 0x193b3(%rip), %rsi     # 0x22531
movq %r13, %rdx
xorl %eax, %eax
callq 0x3070
movq %r13, %rdi
movq %rbp, %rsi
callq 0x32c0
incl %r12d
incq %r14
addq $0x28, %r15
jmp 0x9146
movq %r14, 0x28(%rsp)
xorl %ebp, %ebp
movq %rbx, %rdi
movq %r13, %rsi
xorl %edx, %edx
callq 0x3690
movq %rax, %r15
movq %r13, %rdi
leaq 0x19377(%rip), %rsi     # 0x22537
movq %rax, %rdx
xorl %eax, %eax
callq 0x3070
movq %r15, %rdi
callq 0x30a0
leaq 0x8(%rsp), %r15
cmpl $0x5, %ebp
je 0x945f
movq 0x18(%rsp), %rax
movl 0x8(%rax), %r8d
leaq 0x19370(%rip), %rdi     # 0x22560
pushq $0x3
popq %rsi
leaq 0x1937c(%rip), %rdx     # 0x22576
movq 0x28(%rsp), %rcx
xorl %eax, %eax
callq 0xc78e
movq %rbx, %rdi
movl $0x2712, %esi           # imm = 0x2712
leaq 0x1938c(%rip), %rdx     # 0x225a1
xorl %eax, %eax
callq 0x3350
movq %rbx, %rdi
movl $0x271f, %esi           # imm = 0x271F
movq %r13, %rdx
xorl %eax, %eax
callq 0x3350
movq %rbx, %rdi
pushq $0x34
popq %rsi
xorl %edx, %edx
xorl %eax, %eax
callq 0x3350
movq %rbx, %rdi
movl $0x4e2b, %esi           # imm = 0x4E2B
leaq 0xafc(%rip), %rdx       # 0x9d48
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 0x9281
movq %rbx, %rdi
movl $0x2714, %esi           # imm = 0x2714
movq 0x30(%rsp), %rdx
xorl %eax, %eax
callq 0x3350
andl $0x0, 0x10(%rsp)
movq 0x8(%rsp), %rax
movb $0x0, (%rax)
movq %rbx, %rdi
callq 0x3460
testl %eax, %eax
je 0x92be
movl %eax, %edi
callq 0x3520
leaq 0x192b8(%rip), %rdi     # 0x22560
pushq $0x1
popq %rsi
leaq 0x19316(%rip), %rdx     # 0x225c8
movq %rax, %rcx
xorl %eax, %eax
callq 0xc78e
jmp 0x9320
movq 0x8(%rsp), %r15
movq %r15, %rdi
leaq 0x19310(%rip), %rsi     # 0x225dd
pushq $0x9
popq %rdx
callq 0x3120
testl %eax, %eax
je 0x92ec
leaq 0x19280(%rip), %rdi     # 0x22560
pushq $0x1
popq %rsi
leaq 0x192fd(%rip), %rdx     # 0x225e7
jmp 0x9314
movl $0x2000, %esi           # imm = 0x2000
movq %r15, %rdi
callq 0x35a0
addq $-0xc, %rax
cmpq $0x32, %rax
jb 0x9327
leaq 0x19256(%rip), %rdi     # 0x22560
pushq $0x1
popq %rsi
leaq 0x19303(%rip), %rdx     # 0x22617
xorl %eax, %eax
callq 0xc78e
leaq 0x8(%rsp), %r15
incl %ebp
jmp 0x91d7
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 0x192f3(%rip), %rsi     # 0x22643
movq %r14, %rdx
xorl %eax, %eax
callq 0x3070
andl $0x0, 0x10(%rsp)
xorl %ecx, %ecx
movb %cl, 0x480(%rsp)
movq 0x8(%rsp), %rax
movb %cl, (%rax)
movq %rbx, %rdi
movl $0x2712, %esi           # imm = 0x2712
movq %r15, %rdx
xorl %eax, %eax
callq 0x3350
movq %rbx, %rdi
pushq $0x50
popq %rsi
pushq $0x1
popq %rdx
xorl %eax, %eax
callq 0x3350
leaq 0x8(%rsp), %r15
movq 0x8(%rsp), %rdi
leaq 0x192ce(%rip), %rsi     # 0x22670
callq 0x34d0
testl %eax, %eax
je 0x93d1
pushq $0x1
popq %rdi
callq 0x31e0
andl $0x0, 0x10(%rsp)
movq 0x8(%rsp), %rax
movb $0x0, (%rax)
movq %rbx, %rdi
callq 0x3460
testl %eax, %eax
je 0x9396
jmp 0x929a
movl $0xd0, %edx
movq %r13, %rdi
leaq 0x192a9(%rip), %rsi     # 0x22689
callq 0x3260
leaq 0x80(%rsp), %r14
movq %r14, %rdi
leaq 0x19362(%rip), %rsi     # 0x22759
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 0x9455
movl %eax, %edi
callq 0x3520
leaq 0x1911a(%rip), %rdi     # 0x22560
pushq $0x1
popq %rsi
leaq 0x1934b(%rip), %rdx     # 0x2279b
jmp 0x92b2
movq 0x28(%rsp), %r14
jmp 0x9125
leaq 0x190fa(%rip), %rdi     # 0x22560
leaq 0x19338(%rip), %rdx     # 0x227a5
pushq $0x1
popq %rsi
xorl %eax, %eax
callq 0xc78e
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