// File: mhe[P]raytracerframework_cpp/lodepng.cpp
// Function: HuffmanTree_makeFromFrequencies(HuffmanTree*, unsigned int const*, unsigned long, unsigned int)
static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies, size_t numcodes, unsigned maxbitlen)
{
  unsigned i, j;
  size_t sum = 0, numpresent = 0;
  unsigned error = 0;
  
  vector prev_row; /*type Coin, the previous row of coins*/
  vector coins; /*type Coin, the coins of the currently calculated row*/
  
  tree->maxbitlen = maxbitlen;
  
  for(i = 0; i < numcodes; i++)
  {
    if(frequencies[i] > 0)
    {
      numpresent++;
      sum += frequencies[i];
    }
  }
  
  if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/
  tree->numcodes = (unsigned)numcodes; /*number of symbols*/
  uivector_resize(&tree->lengths, 0);
  if(!uivector_resizev(&tree->lengths, tree->numcodes, 0)) return 9905;
  
  if(numpresent == 0) /*there are no symbols at all, in that case add one symbol of value 0 to the tree (see RFC 1951 section 3.2.7) */
  {
    tree->lengths.data[0] = 1;
    return HuffmanTree_makeFromLengths2(tree);
  }
  else if(numpresent == 1) /*the package merge algorithm gives wrong results if there's only one symbol (theoretically 0 bits would then suffice, but we need a proper symbol for zlib)*/
  {
    for(i = 0; i < numcodes; i++) if(frequencies[i]) tree->lengths.data[i] = 1;
    return HuffmanTree_makeFromLengths2(tree);
  }
  
  vector_init(&coins, sizeof(Coin));
  vector_init(&prev_row, sizeof(Coin));

  /*Package-Merge algorithm represented by coin collector's problem
  For every symbol, maxbitlen coins will be created*/
  
  /*first row, lowest denominator*/
  error = HuffmanTree_fillInCoins(&coins, frequencies, tree->numcodes, sum);
  if(!error)
  {
    for(j = 1; j <= maxbitlen && !error; j++) /*each of the remaining rows*/
    {
      vector_swap(&coins, &prev_row); /*swap instead of copying*/
      if(!vector_resized(&coins, 0, Coin_cleanup)) { error = 9906; break; }

      for(i = 0; i + 1 < prev_row.size; i += 2)
      {
        if(!vector_resize(&coins, coins.size + 1)) { error = 9907; break; }
        Coin_init((Coin*)vector_get(&coins, coins.size - 1));
        Coin_copy((Coin*)vector_get(&coins, coins.size - 1), (Coin*)vector_get(&prev_row, i));
        addCoins((Coin*)vector_get(&coins, coins.size - 1), (Coin*)vector_get(&prev_row, i + 1)); /*merge the coins into packages*/
      }
      if(j < maxbitlen)
      {
        error = HuffmanTree_fillInCoins(&coins, frequencies, tree->numcodes, sum);
      }
    }
  }
  
  if(!error)
  {
    /*keep the coins with lowest weight, so that they add up to the amount of symbols - 1*/
    vector_resized(&coins, numpresent - 1, Coin_cleanup);
    
    /*calculate the lenghts of each symbol, as the amount of times a coin of each symbol is used*/
    for(i = 0; i < coins.size; i++)
    {
      Coin* coin = (Coin*)vector_get(&coins, i);
      for(j = 0; j < coin->symbols.size; j++) tree->lengths.data[coin->symbols.data[j]]++;
    }
    
    error = HuffmanTree_makeFromLengths2(tree);
  }

  vector_cleanupd(&coins, Coin_cleanup);
  vector_cleanupd(&prev_row, Coin_cleanup);
  
  return error;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xb0, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movl %ecx, -0x24(%rbp)
movq $0x0, -0x38(%rbp)
movq $0x0, -0x40(%rbp)
movl $0x0, -0x44(%rbp)
movl -0x24(%rbp), %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0x48(%rax)
movl $0x0, -0x28(%rbp)
movl -0x28(%rbp), %eax
cmpq -0x20(%rbp), %rax
jae 0x2ebe3
movq -0x18(%rbp), %rax
movl -0x28(%rbp), %ecx
cmpl $0x0, (%rax,%rcx,4)
jbe 0x2ebd6
movq -0x40(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x40(%rbp)
movq -0x18(%rbp), %rax
movl -0x28(%rbp), %ecx
movl (%rax,%rcx,4), %eax
addq -0x38(%rbp), %rax
movq %rax, -0x38(%rbp)
jmp 0x2ebd8
movl -0x28(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x28(%rbp)
jmp 0x2eba2
cmpq $0x0, -0x20(%rbp)
jne 0x2ebf6
movl $0x50, -0x4(%rbp)
jmp 0x2ef54
movq -0x20(%rbp), %rax
movl %eax, %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0x4c(%rax)
movq -0x10(%rbp), %rdi
addq $0x30, %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x2d870
movq -0x10(%rbp), %rdi
addq $0x30, %rdi
movq -0x10(%rbp), %rax
movl 0x4c(%rax), %eax
movl %eax, %esi
xorl %edx, %edx
callq 0x2dbb0
cmpl $0x0, %eax
jne 0x2ec3d
movl $0x26b1, -0x4(%rbp)     # imm = 0x26B1
jmp 0x2ef54
cmpq $0x0, -0x40(%rbp)
jne 0x2ec63
movq -0x10(%rbp), %rax
movq 0x30(%rax), %rax
movl $0x1, (%rax)
movq -0x10(%rbp), %rdi
callq 0x2da00
movl %eax, -0x4(%rbp)
jmp 0x2ef54
cmpq $0x1, -0x40(%rbp)
jne 0x2ecb7
movl $0x0, -0x28(%rbp)
movl -0x28(%rbp), %eax
cmpq -0x20(%rbp), %rax
jae 0x2eca6
movq -0x18(%rbp), %rax
movl -0x28(%rbp), %ecx
cmpl $0x0, (%rax,%rcx,4)
je 0x2ec99
movq -0x10(%rbp), %rax
movq 0x30(%rax), %rax
movl -0x28(%rbp), %ecx
movl $0x1, (%rax,%rcx,4)
jmp 0x2ec9b
movl -0x28(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x28(%rbp)
jmp 0x2ec71
movq -0x10(%rbp), %rdi
callq 0x2da00
movl %eax, -0x4(%rbp)
jmp 0x2ef54
jmp 0x2ecb9
leaq -0x88(%rbp), %rdi
movl $0x20, %esi
callq 0x2e6b0
leaq -0x68(%rbp), %rdi
movl $0x20, %esi
callq 0x2e6b0
movq -0x18(%rbp), %rsi
movq -0x10(%rbp), %rax
movl 0x4c(%rax), %edx
movq -0x38(%rbp), %rcx
leaq -0x88(%rbp), %rdi
callq 0x2ef60
movl %eax, -0x44(%rbp)
cmpl $0x0, -0x44(%rbp)
jne 0x2ee82
movl $0x1, -0x2c(%rbp)
movl -0x2c(%rbp), %ecx
xorl %eax, %eax
cmpl -0x24(%rbp), %ecx
movb %al, -0x91(%rbp)
ja 0x2ed26
cmpl $0x0, -0x44(%rbp)
setne %al
xorb $-0x1, %al
movb %al, -0x91(%rbp)
movb -0x91(%rbp), %al
testb $0x1, %al
jne 0x2ed35
jmp 0x2ee80
leaq -0x88(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x2f0a0
leaq -0x88(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
leaq 0x459(%rip), %rdx       # 0x2f1b0
callq 0x2f130
cmpl $0x0, %eax
jne 0x2ed6d
movl $0x26b2, -0x44(%rbp)    # imm = 0x26B2
jmp 0x2ee80
movl $0x0, -0x28(%rbp)
movl -0x28(%rbp), %eax
addl $0x1, %eax
movl %eax, %eax
cmpq -0x60(%rbp), %rax
jae 0x2ee4a
movq -0x80(%rbp), %rsi
addq $0x1, %rsi
leaq -0x88(%rbp), %rdi
callq 0x2e6f0
cmpl $0x0, %eax
jne 0x2edab
movl $0x26b3, -0x44(%rbp)    # imm = 0x26B3
jmp 0x2ee4a
movq -0x80(%rbp), %rsi
subq $0x1, %rsi
leaq -0x88(%rbp), %rdi
callq 0x2e7a0
movq %rax, %rdi
callq 0x2f1d0
movq -0x80(%rbp), %rsi
subq $0x1, %rsi
leaq -0x88(%rbp), %rdi
callq 0x2e7a0
movq %rax, -0xa8(%rbp)
movl -0x28(%rbp), %eax
movl %eax, %esi
leaq -0x68(%rbp), %rdi
callq 0x2e7a0
movq -0xa8(%rbp), %rdi
movq %rax, %rsi
callq 0x2f1f0
movq -0x80(%rbp), %rsi
subq $0x1, %rsi
leaq -0x88(%rbp), %rdi
callq 0x2e7a0
movq %rax, -0xa0(%rbp)
movl -0x28(%rbp), %eax
addl $0x1, %eax
movl %eax, %eax
movl %eax, %esi
leaq -0x68(%rbp), %rdi
callq 0x2e7a0
movq -0xa0(%rbp), %rdi
movq %rax, %rsi
callq 0x2f230
movl -0x28(%rbp), %eax
addl $0x2, %eax
movl %eax, -0x28(%rbp)
jmp 0x2ed74
movl -0x2c(%rbp), %eax
cmpl -0x24(%rbp), %eax
jae 0x2ee70
movq -0x18(%rbp), %rsi
movq -0x10(%rbp), %rax
movl 0x4c(%rax), %edx
movq -0x38(%rbp), %rcx
leaq -0x88(%rbp), %rdi
callq 0x2ef60
movl %eax, -0x44(%rbp)
jmp 0x2ee72
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
jmp 0x2ed07
jmp 0x2ee82
cmpl $0x0, -0x44(%rbp)
jne 0x2ef2b
movq -0x40(%rbp), %rsi
subq $0x1, %rsi
leaq -0x88(%rbp), %rdi
leaq 0x30e(%rip), %rdx       # 0x2f1b0
callq 0x2f130
movl $0x0, -0x28(%rbp)
movl -0x28(%rbp), %eax
cmpq -0x80(%rbp), %rax
jae 0x2ef1f
movl -0x28(%rbp), %eax
movl %eax, %esi
leaq -0x88(%rbp), %rdi
callq 0x2e7a0
movq %rax, -0x90(%rbp)
movl $0x0, -0x2c(%rbp)
movl -0x2c(%rbp), %eax
movq -0x90(%rbp), %rcx
cmpq 0x8(%rcx), %rax
jae 0x2ef12
movq -0x10(%rbp), %rax
movq 0x30(%rax), %rax
movq -0x90(%rbp), %rcx
movq (%rcx), %rcx
movl -0x2c(%rbp), %edx
movl (%rcx,%rdx,4), %ecx
movl (%rax,%rcx,4), %edx
addl $0x1, %edx
movl %edx, (%rax,%rcx,4)
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
jmp 0x2eed6
jmp 0x2ef14
movl -0x28(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x28(%rbp)
jmp 0x2eeae
movq -0x10(%rbp), %rdi
callq 0x2da00
movl %eax, -0x44(%rbp)
leaq -0x88(%rbp), %rdi
leaq 0x277(%rip), %rsi       # 0x2f1b0
callq 0x2f2a0
leaq -0x68(%rbp), %rdi
leaq 0x267(%rip), %rsi       # 0x2f1b0
callq 0x2f2a0
movl -0x44(%rbp), %eax
movl %eax, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0xb0, %rsp
popq %rbp
retq