// File: MarkOates[P]file-downloader/file_downloader.cpp
// Function: FileDownloader::download_file(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>)
FileDownloader::FileHandle FileDownloader::download_file(std::string file_url, std::string local_filename)
{
   FileHandle file_handle(file_url, local_filename);
   std::string temp_filename = std::string(local_filename).insert(0, "~");
   CURL *curl = nullptr;
   FILE *file_pointer = nullptr;
   CURLcode res;
   curl = curl_easy_init();

   if (!curl)
   {
      file_handle.status = ERROR;
      file_handle.error = "CURL initialization error";
      return file_handle;
   }

   file_pointer = fopen(temp_filename.c_str(), "wb");
   curl_easy_setopt(curl, CURLOPT_URL, file_url.c_str());
   curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, FileDownloader::write_data);
   curl_easy_setopt(curl, CURLOPT_WRITEDATA, file_pointer);
   curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
   curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_function);
   curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &file_handle);

   res = curl_easy_perform(curl);

   if (res == CURLE_OK)
   {
      long http_response_code = 0;
      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response_code);

      switch (http_response_code)
      {
      case 200:
         {
            // copy the temp file to the destination
            std::ifstream src(temp_filename, std::ios::binary);
            std::ofstream dst(local_filename, std::ios::binary);
            dst << src.rdbuf();

            file_handle.status = DOWNLOADED;
            file_handle.percentage = 1.0;
         }
         break;
      case 404:
      default:
         file_handle.status = ERROR;
         file_handle.error = std::to_string(http_response_code);
         break;
      }
   }
   else
   {
      file_handle.status = ERROR;
      file_handle.error = curl_easy_strerror(res);
   }

   // erase the temp file
   remove(temp_filename.c_str());

   // cleanup the curl session
   curl_easy_cleanup(curl);
   fclose(file_pointer);

   return file_handle;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x560, %rsp            # imm = 0x560
movq %rdx, -0x500(%rbp)
movq %rsi, -0x518(%rbp)
movq %rdi, -0x510(%rbp)
movq %rdi, %rax
movq %rax, -0x508(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movb $0x0, -0x19(%rbp)
leaq -0x40(%rbp), %rdi
callq 0x30c0
movq -0x500(%rbp), %rsi
leaq -0x60(%rbp), %rdi
callq 0x30c0
jmp 0x40c5
movq -0x510(%rbp), %rdi
leaq -0x40(%rbp), %rsi
leaq -0x60(%rbp), %rdx
callq 0x3db0
jmp 0x40db
leaq -0x60(%rbp), %rdi
callq 0x32b0
leaq -0x40(%rbp), %rdi
callq 0x32b0
movq -0x500(%rbp), %rsi
leaq -0xb0(%rbp), %rdi
callq 0x30c0
jmp 0x4102
leaq 0xaeff(%rip), %rdx      # 0xf008
xorl %eax, %eax
movl %eax, %esi
leaq -0xb0(%rbp), %rdi
callq 0x3210
movq %rax, -0x520(%rbp)
jmp 0x4122
movq -0x520(%rbp), %rsi
leaq -0x90(%rbp), %rdi
callq 0x30c0
jmp 0x4137
leaq -0xb0(%rbp), %rdi
callq 0x32b0
movq $0x0, -0xb8(%rbp)
movq $0x0, -0xc0(%rbp)
callq 0x33c0
movq %rax, -0x528(%rbp)
jmp 0x4167
movq -0x528(%rbp), %rax
movq %rax, -0xb8(%rbp)
cmpq $0x0, -0xb8(%rbp)
jne 0x4226
movq -0x510(%rbp), %rdi
movl $0x3, 0x4(%rdi)
addq $0x58, %rdi
leaq 0xae6e(%rip), %rsi      # 0xf00a
callq 0x31c0
jmp 0x41a3
movb $0x1, -0x19(%rbp)
movl $0x1, -0xc8(%rbp)
jmp 0x4524
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0x41d9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x60(%rbp), %rdi
callq 0x32b0
leaq -0x40(%rbp), %rdi
callq 0x32b0
jmp 0x456e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0x4562
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0xb0(%rbp), %rdi
callq 0x32b0
jmp 0x4562
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0x4538
leaq -0x90(%rbp), %rdi
callq 0x30a0
movq %rax, %rdi
leaq 0xade8(%rip), %rsi      # 0xf024
callq 0x3470
movq %rax, -0x530(%rbp)
jmp 0x424a
movq -0x518(%rbp), %rdi
movq -0x530(%rbp), %rax
movq %rax, -0xc0(%rbp)
movq -0xb8(%rbp), %rax
movq %rax, -0x538(%rbp)
callq 0x30a0
movq -0x538(%rbp), %rdi
movq %rax, %rdx
xorl %eax, %eax
movl $0x2712, %esi           # imm = 0x2712
callq 0x3320
jmp 0x428a
movq -0xb8(%rbp), %rdi
leaq 0x2e8(%rip), %rdx       # 0x4580
xorl %eax, %eax
movl $0x4e2b, %esi           # imm = 0x4E2B
callq 0x3320
jmp 0x42a6
movq -0xb8(%rbp), %rdi
movq -0xc0(%rbp), %rdx
xorl %eax, %eax
movl $0x2711, %esi           # imm = 0x2711
callq 0x3320
jmp 0x42c2
movq -0xb8(%rbp), %rdi
xorl %edx, %edx
movb %dl, %al
movl $0x2b, %esi
callq 0x3320
jmp 0x42d9
movq -0xb8(%rbp), %rdi
leaq 0x2d9(%rip), %rdx       # 0x45c0
xorl %eax, %eax
movl $0x4e58, %esi           # imm = 0x4E58
callq 0x3320
jmp 0x42f5
movq -0x510(%rbp), %rdx
movq -0xb8(%rbp), %rdi
xorl %eax, %eax
movl $0x2749, %esi           # imm = 0x2749
callq 0x3320
jmp 0x4311
movq -0xb8(%rbp), %rdi
callq 0x3290
movl %eax, -0x53c(%rbp)
jmp 0x4325
movl -0x53c(%rbp), %eax
movl %eax, -0xc4(%rbp)
cmpl $0x0, -0xc4(%rbp)
jne 0x44a9
movq $0x0, -0xd0(%rbp)
movq -0xb8(%rbp), %rdi
xorl %eax, %eax
movl $0x200002, %esi         # imm = 0x200002
leaq -0xd0(%rbp), %rdx
callq 0x33b0
jmp 0x4365
movq -0xd0(%rbp), %rax
movq %rax, -0x548(%rbp)
subq $0xc8, %rax
je 0x4395
jmp 0x437d
movq -0x548(%rbp), %rax
subq $0x194, %rax            # imm = 0x194
je 0x445f
jmp 0x4461
leaq -0x2d8(%rbp), %rdi
leaq -0x90(%rbp), %rsi
movl $0x4, %edx
callq 0x33e0
jmp 0x43af
movq -0x500(%rbp), %rsi
leaq -0x4d8(%rbp), %rdi
movl $0x4, %edx
callq 0x30f0
jmp 0x43c9
leaq -0x2d8(%rbp), %rdi
callq 0x3200
movq %rax, -0x550(%rbp)
jmp 0x43de
movq -0x550(%rbp), %rsi
leaq -0x4d8(%rbp), %rdi
callq 0x3110
jmp 0x43f3
movq -0x510(%rbp), %rax
movl $0x2, 0x4(%rax)
movss 0xabfb(%rip), %xmm0     # 0xf004
movss %xmm0, 0xc(%rax)
leaq -0x4d8(%rbp), %rdi
callq 0x32d0
leaq -0x2d8(%rbp), %rdi
callq 0x3040
jmp 0x44a7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0x444e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x4d8(%rbp), %rdi
callq 0x32d0
leaq -0x2d8(%rbp), %rdi
callq 0x3040
jmp 0x4538
jmp 0x4461
movq -0x510(%rbp), %rax
movl $0x3, 0x4(%rax)
movq -0xd0(%rbp), %rsi
leaq -0x4f8(%rbp), %rdi
callq 0x4700
jmp 0x4484
movq -0x510(%rbp), %rdi
addq $0x58, %rdi
leaq -0x4f8(%rbp), %rsi
callq 0x3220
leaq -0x4f8(%rbp), %rdi
callq 0x32b0
jmp 0x44e6
movq -0x510(%rbp), %rax
movl $0x3, 0x4(%rax)
movl -0xc4(%rbp), %edi
callq 0x31f0
movq %rax, -0x558(%rbp)
jmp 0x44cb
movq -0x558(%rbp), %rsi
movq -0x510(%rbp), %rdi
addq $0x58, %rdi
callq 0x31c0
jmp 0x44e4
jmp 0x44e6
leaq -0x90(%rbp), %rdi
callq 0x30a0
movq %rax, %rdi
callq 0x3120
movq -0xb8(%rbp), %rdi
callq 0x30d0
jmp 0x4508
movq -0xc0(%rbp), %rdi
callq 0x31e0
jmp 0x4516
movb $0x1, -0x19(%rbp)
movl $0x1, -0xc8(%rbp)
leaq -0x90(%rbp), %rdi
callq 0x32b0
testb $0x1, -0x19(%rbp)
jne 0x4552
jmp 0x4546
leaq -0x90(%rbp), %rdi
callq 0x32b0
jmp 0x4562
movq -0x510(%rbp), %rdi
callq 0x3ea0
movq -0x508(%rbp), %rax
addq $0x560, %rsp            # imm = 0x560
popq %rbp
retq
movq -0x510(%rbp), %rdi
callq 0x3ea0
movq -0x68(%rbp), %rdi
callq 0x3260
nopw (%rax,%rax)