// File: /workspace/github_c_makefile_star2_O2/felipelouza[P]egap/unbwt.c
// Function: invert_bwt
void invert_bwt(char *bnam, char *tnam)
{
  FILE *b, *t;
  uint64_t occ[_BW_ALPHA_SIZE];      // emulation of first column of bwt matrix 
  uint64_t start_sa_range[_BW_ALPHA_SIZE+1];
  uint64_t i,tot;
  uint32_t *rankprev, *bwt;
  uint8_t *high8 = NULL;

  b = fopen(bnam,"r");
  if(b==NULL) perror_die("Error opening infile");
  t = fopen(tnam,"w");
  if(t==NULL) perror_die("Error opening outfile");

  // get BWT size
  long bsize = fseek(b,0,SEEK_END);
  if(bsize<0) perror_die("fseek error");
  bsize = ftell(b);
  if(bsize<0) perror_die("ftell error");
  rewind(b);
  
  if(bsize>0xFFFFFFFFFF) 
    die("BWT too large for internal memory inversion");// maximum limit is 2^40 -1
  if(bsize>0xFFFFFFFF) {
    fprintf(stderr,"Large file (>4GB): using 5n bytes ram\n");
    // we need an extra array to store the highest 8 bits 
    high8 = malloc(bsize*sizeof(*high8));
    if(high8==NULL) die("Out of mem");
  }
  bwt = rankprev = (uint32_t *) malloc(bsize*sizeof(*rankprev));
  if(rankprev==NULL) die("Out of mem");

  // clear occ
  for(i=0;i<_BW_ALPHA_SIZE;i++) occ[i]=0;  
  // read bwt from file and compute occ
  for(i=0;i<bsize;i++) {
    int e = fread(bwt+i,1,1,b);
    if(e!=1) perror_die("Error reading BWT");
    occ[bwt[i]]++; // increment count
  }
  if(fclose(b)!=0) perror_die("Error closing BWT file");
  
  // compute start sa_range  
  for(i=0,tot=0;i<_BW_ALPHA_SIZE;i++) {
    start_sa_range[i] = tot; tot+= occ[i];
  }
  start_sa_range[_BW_ALPHA_SIZE] = tot;  
  assert(tot==bsize);

  fprintf(stderr,"Computing rankprev\n");
  // bwt -> rankprev inplace
  for(i=0;i<bsize;i++) {
      // if(i%10000==0) fprintf(stderr,"%ld outof %ld\n",i,bsize);
      uint64_t rp = (start_sa_range[bwt[i]]++);
      assert(rp<bsize);
      rankprev[i] = (uint32_t) rp;
      if(high8) high8[i]=(uint8_t)(rp>>32);
  } 
  assert(start_sa_range[_BW_ALPHA_SIZE-1]==start_sa_range[_BW_ALPHA_SIZE]);
  fprintf(stderr,"Done\n");  
  // recover the original start_sa_range values
  tot=0;
  for(i=0;i<_BW_ALPHA_SIZE;i++) {
    uint64_t temp = start_sa_range[i];
    start_sa_range[i]=tot;
    tot=temp;
  }
  assert(tot==start_sa_range[_BW_ALPHA_SIZE]);

  // start recovering of sequences
  // init buffer
  long s_size=1024; long s_step = 1024;
  char *s = malloc(s_size*sizeof(*s));
  if(!s) die("out of mem");
  long s_pos = 0;
  for(int i=0;i<occ[0];i++) {
    if(i%10000==0) fprintf(stderr,"Recovering sequecence %d\n",i);
    s_pos=0;
    long old_rank = i;
    while(true) {
      // move to first column
      uint64_t rank = rankprev[old_rank];
      if(high8!=NULL) rank += ((uint64_t) high8[old_rank]) << 32;
      int32_t c = get_char_from_first_column64(rank, start_sa_range);
      //fprintf(stderr,"%ld --> %d\n",rank,c); 
      if(c==0) break; //end of sequence
      if(s_pos>=s_size) {
        assert(s_pos==s_size);
        s_size += s_step;
        s = realloc(s,s_size*sizeof(*s));
      }
      assert(s_pos<s_size);  
      s[s_pos++] = c;
      old_rank = rank;
    }
    if(s_pos==0)
      die("Empty string in BWT file");
    // ---- reverse string ----
    for(long k=0;k<s_pos/2;k++) {
     char c = s[k]; s[k] = s[s_pos-1-k]; s[s_pos-1-k]=c;
    }
    // write string
    // fprintf(t,">\n");
    int e = fwrite(s,1,s_pos,t);
    if(e!=s_pos) perror_die("Error writing ouput sequence");
    fprintf(t,"\n");
  }
  fprintf(stderr,"Recovered %zu sequences\n",occ[0]);
  if(fclose(t)!=0) perror_die("Error closing output file");      
  free(rankprev);
  if(high8) free(high8);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x1038, %rsp           # imm = 0x1038
movq %rsi, %rbx
leaq 0xdd6(%rip), %rsi       # 0x203f
callq 0x10e0
testq %rax, %rax
je 0x1760
movq %rax, %r14
leaq 0xd9c(%rip), %rsi       # 0x201d
movq %rbx, %rdi
callq 0x10e0
testq %rax, %rax
je 0x176c
movq %rax, %r15
pushq $0x2
popq %rbp
movq %r14, %rdi
xorl %esi, %esi
movl %ebp, %edx
callq 0x10c0
testl %eax, %eax
js 0x1778
movq %r14, %rdi
callq 0x10a0
testq %rax, %rax
js 0x1784
movq %rax, %rbx
movq %r14, %rdi
callq 0x1060
movq %rbx, %rax
shrq $0x28, %rax
jne 0x1790
movq %rbx, %rax
shrq $0x20, %rax
je 0x1310
movq 0x2d13(%rip), %rax      # 0x3ff8
movq (%rax), %rcx
leaq 0xd8a(%rip), %rdi       # 0x2079
pushq $0x26
popq %rsi
pushq $0x1
popq %rdx
callq 0x1110
movq %rbx, %rdi
callq 0x10b0
movq %rax, (%rsp)
testq %rax, %rax
jne 0x1318
jmp 0x1754
movq $0x0, (%rsp)
leaq (,%rbx,4), %rdi
callq 0x10b0
testq %rax, %rax
je 0x1754
movq %rax, %r12
xorl %eax, %eax
cmpq $0x100, %rax            # imm = 0x100
je 0x1349
andq $0x0, 0x830(%rsp,%rax,8)
incq %rax
jmp 0x1333
movq %rbx, %rax
movq %r14, %rbx
pushq $0x1
popq %r13
movq %r12, 0x8(%rsp)
movq %rax, 0x10(%rsp)
movq %rax, %r14
subq $0x1, %r14
jb 0x1392
movq %r12, %rdi
movq %r13, %rsi
movq %r13, %rdx
movq %rbx, %rcx
callq 0x1040
cmpl $0x1, %eax
jne 0x1713
movl (%r12), %eax
incq 0x830(%rsp,%rax,8)
addq $0x4, %r12
jmp 0x1360
movq %rbx, %rdi
callq 0x1050
testl %eax, %eax
jne 0x179c
xorl %eax, %eax
xorl %ecx, %ecx
movq 0x10(%rsp), %rbx
cmpq $0x100, %rcx            # imm = 0x100
je 0x13c6
movq %rax, 0x20(%rsp,%rcx,8)
addq 0x830(%rsp,%rcx,8), %rax
incq %rcx
jmp 0x13ab
movq %rax, 0x820(%rsp)
cmpq %rbx, %rax
jne 0x17a8
movq 0x2c1a(%rip), %rax      # 0x3ff8
movq (%rax), %rcx
leaq 0xd1f(%rip), %rdi       # 0x2107
pushq $0x13
popq %rsi
pushq $0x1
popq %rdx
callq 0x1110
xorl %eax, %eax
movq (%rsp), %rdi
movq 0x8(%rsp), %r8
cmpq %rax, %rbx
je 0x1433
movl (%r8,%rax,4), %edx
movq 0x20(%rsp,%rdx,8), %rcx
leaq 0x1(%rcx), %rsi
movq %rsi, 0x20(%rsp,%rdx,8)
cmpq %rbx, %rcx
jae 0x171f
movl %ecx, (%r8,%rax,4)
testq %rdi, %rdi
je 0x142e
shrq $0x20, %rcx
movb %cl, (%rdi,%rax)
incq %rax
jmp 0x13fe
movq 0x818(%rsp), %rax
cmpq 0x820(%rsp), %rax
jne 0x17c4
movq 0x2ba8(%rip), %rax      # 0x3ff8
movq (%rax), %rcx
leaq 0xd0b(%rip), %rdi       # 0x2165
pushq $0x5
popq %rsi
pushq $0x1
popq %rdx
callq 0x1110
xorl %eax, %eax
xorl %ecx, %ecx
cmpq $0x100, %rcx            # imm = 0x100
je 0x1484
movq 0x20(%rsp,%rcx,8), %rdx
movq %rax, 0x20(%rsp,%rcx,8)
incq %rcx
movq %rdx, %rax
jmp 0x1469
cmpq 0x820(%rsp), %rax
jne 0x17e0
movl $0x400, %edi            # imm = 0x400
callq 0x10b0
testq %rax, %rax
je 0x17fc
movq %rax, %r13
xorl %r14d, %r14d
movq (%rsp), %rsi
movq 0x8(%rsp), %rdi
movl $0x400, %r8d            # imm = 0x400
movq %r15, 0x18(%rsp)
movq 0x830(%rsp), %rdx
cmpq %r14, %rdx
jbe 0x164b
movl %r14d, %eax
xorl %edx, %edx
movl $0x2710, %ecx           # imm = 0x2710
divl %ecx
testl %edx, %edx
je 0x161c
pushq $-0x1
popq %r15
xorl %ebx, %ebx
movq %r14, 0x10(%rsp)
movl (%rdi,%r14,4), %eax
testq %rsi, %rsi
je 0x1506
movzbl (%rsi,%r14), %r14d
shlq $0x20, %r14
orq %rax, %r14
jmp 0x1509
movq %rax, %r14
cmpq %r14, 0x20(%rsp)
ja 0x1697
cmpq %r14, 0x820(%rsp)
jbe 0x1697
movl $0xff, %ecx
xorl %r12d, %r12d
cmpl %ecx, %r12d
jge 0x154d
leal (%r12,%rcx), %eax
incl %eax
cltd
idivl %ebp
cltq
cmpq %r14, 0x20(%rsp,%rax,8)
leal -0x1(%rax), %edx
cmovbel %eax, %r12d
cmovbel %ecx, %edx
movl %edx, %ecx
jmp 0x152a
jne 0x16b6
testl %r12d, %r12d
je 0x15a0
cmpq %r8, %rbx
jl 0x1587
jne 0x16f4
addq $0x400, %r8             # imm = 0x400
movq %r13, %rdi
movq %r8, %rsi
movq %r8, %r13
callq 0x10d0
movq %r13, %r8
movq 0x8(%rsp), %rdi
movq (%rsp), %rsi
movq %rax, %r13
cmpq %r8, %rbx
jge 0x16d5
movb %r12b, (%r13,%rbx)
incq %rbx
incq %r15
jmp 0x14ef
testq %rbx, %rbx
je 0x173c
movq %rbx, %rax
shrq %rax
addq %r13, %r15
xorl %ecx, %ecx
cmpq %rcx, %rax
je 0x15d1
movb (%r13,%rcx), %dl
movb (%r15), %sil
movb %sil, (%r13,%rcx)
movb %dl, (%r15)
incq %rcx
decq %r15
jmp 0x15b4
movq %r8, %r14
movq %r13, %rdi
pushq $0x1
popq %rsi
movq %rbx, %rdx
movq 0x18(%rsp), %r15
movq %r15, %rcx
callq 0x1110
cltq
cmpq %rbx, %rax
jne 0x1748
pushq $0xa
popq %rdi
movq %r15, %rsi
callq 0x1080
movq 0x10(%rsp), %rax
incq %rax
movq (%rsp), %rsi
movq 0x8(%rsp), %rdi
movq %r14, %r8
movq %rax, %r14
jmp 0x14bf
movq 0x29d5(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
leaq 0xb6d(%rip), %rsi       # 0x219a
movl %r14d, %edx
xorl %eax, %eax
movq %r8, %rbx
callq 0x1090
movq %rbx, %r8
movq 0x8(%rsp), %rdi
movq (%rsp), %rsi
jmp 0x14e4
movq 0x29a6(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
leaq 0xba9(%rip), %rsi       # 0x2205
xorl %eax, %eax
callq 0x1090
movq %r15, %rdi
callq 0x1050
testl %eax, %eax
jne 0x1808
movq 0x8(%rsp), %rdi
callq 0x1030
movq (%rsp), %rdi
addq $0x1038, %rsp           # imm = 0x1038
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1030
leaq 0xc49(%rip), %rdi       # 0x22e7
leaq 0xa3a(%rip), %rsi       # 0x20df
leaq 0xc69(%rip), %rcx       # 0x2315
movl $0xb1, %edx
callq 0x1070
leaq 0xc93(%rip), %rdi       # 0x2350
leaq 0xa1b(%rip), %rsi       # 0x20df
leaq 0xc4a(%rip), %rcx       # 0x2315
movl $0xb9, %edx
callq 0x1070
leaq 0xae6(%rip), %rdi       # 0x21c2
leaq 0x9fc(%rip), %rsi       # 0x20df
leaq 0x9fd(%rip), %rcx       # 0x20e7
movl $0x93, %edx
callq 0x1070
leaq 0xab9(%rip), %rdi       # 0x21b4
leaq 0x9dd(%rip), %rsi       # 0x20df
leaq 0x9de(%rip), %rcx       # 0x20e7
movl $0x8f, %edx
callq 0x1070
leaq 0x991(%rip), %rdi       # 0x20ab
callq 0x1240
leaq 0x9f5(%rip), %rdi       # 0x211b
leaq 0x9b2(%rip), %rsi       # 0x20df
leaq 0x9b3(%rip), %rcx       # 0x20e7
pushq $0x6e
popq %rdx
callq 0x1070
leaq 0xa8c(%rip), %rdi       # 0x21cf
callq 0x121c
leaq 0xa99(%rip), %rdi       # 0x21e8
callq 0x1240
leaq 0x945(%rip), %rdi       # 0x20a0
callq 0x121c
leaq 0x8a1(%rip), %rdi       # 0x2008
callq 0x1240
leaq 0x8ac(%rip), %rdi       # 0x201f
callq 0x1240
leaq 0x8b6(%rip), %rdi       # 0x2035
callq 0x1240
leaq 0x8b6(%rip), %rdi       # 0x2041
callq 0x1240
leaq 0x8b6(%rip), %rdi       # 0x204d
callq 0x121c
leaq 0x91a(%rip), %rdi       # 0x20bd
callq 0x1240
leaq 0x925(%rip), %rdi       # 0x20d4
leaq 0x929(%rip), %rsi       # 0x20df
leaq 0x92a(%rip), %rcx       # 0x20e7
pushq $0x67
jmp 0x1736
leaq 0x959(%rip), %rdi       # 0x2124
leaq 0x90d(%rip), %rsi       # 0x20df
leaq 0x90e(%rip), %rcx       # 0x20e7
pushq $0x72
jmp 0x1736
leaq 0x984(%rip), %rdi       # 0x216b
leaq 0x8f1(%rip), %rsi       # 0x20df
leaq 0x8f2(%rip), %rcx       # 0x20e7
pushq $0x7b
jmp 0x1736
leaq 0x98c(%rip), %rdi       # 0x218f
callq 0x121c
leaq 0xa0f(%rip), %rdi       # 0x221e
callq 0x1240