// File: /workspace/github_c_makefile_star2_O1/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)
xorl %r13d, %r13d
movb %r13b, (%rax)
movl $0x1, %edi
movl $0x2faf080, %esi        # imm = 0x2FAF080
callq 0x31b0
leaq 0x8(%rsp), %rdx
movq %rax, (%rdx)
movq %r15, 0x8(%rdx)
movb %r13b, (%rax)
movq %r14, 0x18(%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 0x18(%rsp), %rax
cmpl 0x8(%rax), %r14d
jge 0xa9e6
movb $0x0, 0x480(%rsp)
cmpl $0x0, 0x28(%rsp)
jle 0xa6d7
movslq %r14d, %r14
leaq (,%r14,8), %rax
leaq (%rax,%rax,4), %r15
xorl %r12d, %r12d
movq 0x18(%rsp), %rax
movslq 0x8(%rax), %rax
cmpq %rax, %r14
jge 0xa6d7
movq 0x18(%rsp), %rax
movq (%rax), %rax
movq (%rax,%r15), %rcx
cmpb $0x0, (%rcx)
je 0xa6c9
leaq 0x3d510(%rsp), %rbp
movq %rbp, %rdi
leaq 0x1ce50(%rip), %rsi     # 0x27501
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 0xa680
movq %r14, 0x20(%rsp)
xorl %r15d, %r15d
movq %rbx, %rdi
movq %r13, %rsi
xorl %edx, %edx
callq 0x3690
movq %rax, %rbp
movq %r13, %rdi
leaq 0x1ce0e(%rip), %rsi     # 0x27507
movq %rax, %rdx
xorl %eax, %eax
callq 0x3070
movq %rbp, %rdi
callq 0x30a0
leaq 0x8(%rsp), %rbp
movq 0x18(%rsp), %rax
movl 0x8(%rax), %r8d
leaq 0x1ce10(%rip), %rdi     # 0x27530
movl $0x3, %esi
leaq 0x1ce1a(%rip), %rdx     # 0x27546
movq 0x20(%rsp), %rcx
xorl %eax, %eax
callq 0xdbeb
movq %rbx, %rdi
movl $0x2712, %esi           # imm = 0x2712
leaq 0x1ce2a(%rip), %rdx     # 0x27571
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 0xb8a(%rip), %rdx       # 0xb30a
xorl %eax, %eax
callq 0x3350
movq %rbx, %rdi
movl $0x2711, %esi           # imm = 0x2711
movq %rbp, %rdx
xorl %eax, %eax
callq 0x3350
cmpq $0x0, 0x30(%rsp)
je 0xa7b5
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 0xa7f7
movl %eax, %edi
callq 0x3520
leaq 0x1cd51(%rip), %rdi     # 0x27530
movl $0x1, %esi
leaq 0x1cdad(%rip), %rdx     # 0x27598
movq %rax, %rcx
xorl %eax, %eax
callq 0xdbeb
jmp 0xa85f
movq 0x8(%rsp), %rbp
movl $0x9, %edx
movq %rbp, %rdi
leaq 0x1cda2(%rip), %rsi     # 0x275ad
callq 0x3120
testl %eax, %eax
je 0xa829
leaq 0x1cd15(%rip), %rdi     # 0x27530
movl $0x1, %esi
leaq 0x1cd90(%rip), %rdx     # 0x275b7
jmp 0xa853
movl $0x2000, %esi           # imm = 0x2000
movq %rbp, %rdi
callq 0x35a0
addq $-0xc, %rax
cmpq $0x32, %rax
jb 0xa871
leaq 0x1cce9(%rip), %rdi     # 0x27530
movl $0x1, %esi
leaq 0x1cd94(%rip), %rdx     # 0x275e7
xorl %eax, %eax
callq 0xdbeb
leaq 0x8(%rsp), %rbp
incl %r15d
cmpl $0x5, %r15d
jne 0xa710
jmp 0xa9b7
addq $0xa, %rbp
leaq 0x40(%rsp), %r14
movq %r14, %rdi
movq %rbp, %rsi
movq %rax, %rdx
callq 0x3130
leaq 0x80(%rsp), %rbp
movq %rbp, %rdi
leaq 0x1cd79(%rip), %rsi     # 0x27613
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 %rbp, %rdx
xorl %eax, %eax
callq 0x3350
movl $0x1, %edx
movq %rbx, %rdi
movl $0x50, %esi
xorl %eax, %eax
callq 0x3350
leaq 0x1cd57(%rip), %rbp     # 0x27640
movq 0x8(%rsp), %rdi
movq %rbp, %rsi
callq 0x34d0
testl %eax, %eax
je 0xa922
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 0xa8e9
jmp 0xa924
xorl %eax, %eax
testl %eax, %eax
leaq 0x8(%rsp), %rbp
jne 0xa7d1
movl $0xd0, %edx
movq %r13, %rdi
leaq 0x1cd19(%rip), %rsi     # 0x27659
callq 0x3260
leaq 0x80(%rsp), %r14
movq %r14, %rdi
leaq 0x1cdd2(%rip), %rsi     # 0x27729
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 0xa9bd
movl %eax, %edi
callq 0x3520
leaq 0x1cb8a(%rip), %rdi     # 0x27530
movl $0x1, %esi
leaq 0x1cdb9(%rip), %rdx     # 0x2776b
jmp 0xa7eb
movl $0x5, %r15d
cmpl $0x5, %r15d
movq 0x20(%rsp), %r14
jne 0xa650
leaq 0x1cb5d(%rip), %rdi     # 0x27530
leaq 0x1cd9b(%rip), %rdx     # 0x27775
movl $0x1, %esi
xorl %eax, %eax
callq 0xdbeb
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