// File: /workspace/github_cpp_makefile_star2_O2/AlgoLab[P]bwt-lcp-parallel/bwt_lcp.cpp
// Function: main
int main(int argc, char *argv[]) {
  // Initialization
  gzFile fp;
  kseq_t *seq;

  // Error if no file is given as input
  if (argc < 2 || argc > 3) {
    std::cerr << "Usage: " << argv[0] << " <in.fasta> [<nthreads>]" << std::endl;
    return 1;
  }

  if (argc == 3) {
    int nthreads = std::atoi(argv[2]);
    if (nthreads <= 0) {
      std::cerr << "Usage: " << argv[0] << " <in.fasta> [<nthreads>]" << std::endl;
      std::cerr << "nthreads cannot be less than 1. Given: " << nthreads << std::endl;
      return 1;
    }
    concurrency_level = static_cast<unsigned>(nthreads);
  } else {
    unsigned ncores = std::thread::hardware_concurrency();
    concurrency_level = ncores == 0 ? 1 : std::min(ncores, 4u);
  }
  std::cout << "Using " << concurrency_level << " threads." << std::endl;

  fp = gzopen(argv[1], "r");
  seq = kseq_init(fp);

  strnum_t read_num = 0;
  int maxl = 0;

  {
    // int is required by library kseq
    int l = 0;

    // Calculate the length of the longest read
    while ((l = kseq_read(seq)) >= 0) {
      ++read_num;
      if (l > maxl) maxl = l;
    }

    if (maxl > 254) {
      std::cerr << "Input reads are too long! Current = "
                << maxl << ", max = 254"
                << std::endl;
      kseq_destroy(seq);
      gzclose(fp);
      return 1;
    }
  }

  const strlen_t read_max_length = static_cast<strlen_t>(maxl);

  std::cout << "longest read length = " << static_cast<fuint_t>(read_max_length) << std::endl;
  std::cout << "number of reads = " << read_num << std::endl;

  const fnames_t S_tpl= template_generator("supportfile-S%.3d.tmp", 0, read_max_length+1);
  const fnames_t B_tpl= template_generator("supportfile-B%.3d.tmp", 0, read_max_length+1);
  const fname_t IXk_name("supportfile-IXk.tmp");

  std::cout << "Preparing arrays S_l..." << std::endl;
  occ_countv_t occv(read_max_length+1);
  {
    multi_enc_fasta_writer_t S(S_tpl);
    kseq_rewind(seq);
    gzrewind(fp);

    int l = 0;
    while ((l = kseq_read(seq)) >= 0) {
      const strlen_t len = static_cast<strlen_t>(l);
      for (strlen_t i = 0; i <= len; ++i) {
        const enc_nucl_t c = encode(seq->seq.s[len-i]);
        S.write(i, c);
        ++occv[i][c];
      }
      for (strlen_t i = len+1; i <= read_max_length; ++i) {
        S.write(i, ALPHSIZE-1);
        ++occv[i][ALPHSIZE-1];
      }
    }

  }

  kseq_destroy(seq);
  gzclose(fp);

  std::cout << "Computing partial BWT..." << std::endl;
  compute_partial_BWT(read_max_length, read_num, S_tpl, B_tpl);
  remove_files(S_tpl);

  std::cout << "Computing interleave and LCP..." << std::endl;
  compute_interleave_LCP(read_max_length, read_num, occv, B_tpl, IXk_name);

  std::cout << "Computing BWT..." << std::endl;
  compute_BWT(read_max_length, read_num, B_tpl, IXk_name);

  std::cout << "Done." << std::endl;

  return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xc8, %rsp
movq %rsi, %rbx
leal -0x4(%rdi), %eax
pushq $0x1
popq %rbp
cmpl $-0x3, %eax
ja 0x4015
movq 0xb00e(%rip), %rdi      # 0xeff0
leaq 0x5124(%rip), %rsi      # 0x910d
callq 0x2230
movq (%rbx), %rsi
movq %rax, %rdi
callq 0x2230
leaq 0x5115(%rip), %rsi      # 0x9115
movq %rax, %rdi
callq 0x2230
movq %rax, %rdi
callq 0x20f0
jmp 0x44a6
cmpl $0x3, %edi
jne 0x407e
movq 0x10(%rbx), %rdi
callq 0x2360
movl %eax, %r14d
testl %eax, %eax
jg 0x4094
movq 0xafbf(%rip), %r15      # 0xeff0
leaq 0x50d5(%rip), %rsi      # 0x910d
movq %r15, %rdi
callq 0x2230
movq (%rbx), %rsi
movq %rax, %rdi
callq 0x2230
leaq 0x50c3(%rip), %rsi      # 0x9115
movq %rax, %rdi
callq 0x2230
movq %rax, %rdi
callq 0x20f0
leaq 0x50c5(%rip), %rsi      # 0x912e
movq %r15, %rdi
callq 0x2230
movq %rax, %rdi
movl %r14d, %esi
callq 0x23c0
jmp 0x4008
callq 0x22f0
cmpl $0x4, %eax
pushq $0x4
popq %r14
cmovbl %eax, %r14d
testl %eax, %eax
cmovel %ebp, %r14d
movl %r14d, 0xb1a5(%rip)     # 0xf240
movq 0xaf2e(%rip), %rdi      # 0xefd0
leaq 0x50ad(%rip), %rsi      # 0x9156
callq 0x2230
movl 0xb18c(%rip), %esi      # 0xf240
movq %rax, %rdi
callq 0x2170
leaq 0x509a(%rip), %rsi      # 0x915d
movq %rax, %rdi
callq 0x2230
movq %rax, %rdi
callq 0x20f0
movq 0x8(%rbx), %rdi
leaq 0x559e(%rip), %rsi      # 0x967c
callq 0x2340
movq %rax, %r15
pushq $0x1
popq %rbx
pushq $0x70
popq %rsi
movq %rbx, %rdi
callq 0x2150
movq %rax, %r14
pushq $0x20
popq %rsi
movq %rbx, %rdi
callq 0x2150
movq %rax, %rbx
movq %r15, 0x18(%rax)
movl $0x4000, %edi           # imm = 0x4000
callq 0x22d0
movq %rax, (%rbx)
movq %r14, 0x8(%rsp)
movq %rbx, 0x68(%r14)
movq $0x0, 0x10(%rsp)
xorl %r14d, %r14d
movq 0x8(%rsp), %rdi
callq 0x453e
testl %eax, %eax
js 0x414d
incl %r14d
movq 0x10(%rsp), %rcx
cmpl %ecx, %eax
cmovgl %eax, %ecx
movq %rcx, 0x10(%rsp)
jmp 0x412b
movq 0x10(%rsp), %r12
cmpl $0xff, %r12d
jae 0x4344
movq 0xae6a(%rip), %rbx      # 0xefd0
leaq 0x502b(%rip), %rsi      # 0x9198
movq %rbx, %rdi
callq 0x2230
movl %r12d, %esi
movq %rax, %rdi
callq 0x2170
movq %rax, %rdi
callq 0x20f0
leaq 0x5020(%rip), %rsi      # 0x91af
movq %rbx, %rdi
callq 0x2230
movl %r14d, %esi
movq %rax, %rdi
callq 0x2170
movq %rax, %rdi
callq 0x20f0
leaq 0x5011(%rip), %rsi      # 0x91c2
leaq 0x28(%rsp), %rdi
leaq 0xa8(%rsp), %rdx
callq 0x4ad4
leal 0x1(%r12), %ebp
leaq 0x90(%rsp), %rdi
leaq 0x28(%rsp), %rsi
xorl %edx, %edx
movl %ebp, %ecx
callq 0x256c
leaq 0x28(%rsp), %rdi
callq 0x20d0
leaq 0x4fe9(%rip), %rsi      # 0x91d8
leaq 0x28(%rsp), %rdi
leaq 0xa8(%rsp), %rdx
callq 0x4ad4
leaq 0x78(%rsp), %rdi
leaq 0x28(%rsp), %rsi
xorl %edx, %edx
movl %ebp, %ecx
callq 0x256c
leaq 0x28(%rsp), %rdi
callq 0x20d0
leaq 0x4fc9(%rip), %rsi      # 0x91ee
leaq 0xa8(%rsp), %rdi
leaq 0x28(%rsp), %rdx
callq 0x4ad4
movq 0xad92(%rip), %rdi      # 0xefd0
leaq 0x4fbd(%rip), %rsi      # 0x9202
callq 0x2230
movq %rax, %rdi
callq 0x20f0
movl %ebp, %esi
leaq 0x60(%rsp), %rdi
leaq 0x28(%rsp), %rdx
callq 0x5b32
leaq 0x4de2(%rip), %rdx      # 0x904c
leaq 0x28(%rsp), %rdi
leaq 0x90(%rsp), %rsi
callq 0x5b84
movq 0x10(%rsp), %r12
movl %r14d, 0x1c(%rsp)
movq 0x8(%rsp), %rcx
movq 0x68(%rcx), %rax
andq $0x0, 0x8(%rax)
andl $0x0, 0x10(%rax)
andl $0x0, 0x60(%rcx)
movq %r15, 0x20(%rsp)
movq %r15, %rdi
callq 0x2280
leaq 0x28(%rsp), %r13
movq 0x8(%rsp), %rdi
callq 0x453e
movl %eax, %r14d
testl %eax, %eax
js 0x4390
movzbl %r14b, %r15d
xorl %ebp, %ebp
cmpb %r14b, %bpl
ja 0x4311
movzbl %bpl, %ebx
movq 0x8(%rsp), %rax
movq 0x40(%rax), %rax
movl %r15d, %ecx
subl %ebx, %ecx
movslq %ecx, %rcx
movsbl (%rax,%rcx), %edi
callq 0x82cc
movzbl %al, %r12d
movq %r13, %rdi
movl %ebx, %esi
movl %r12d, %edx
callq 0x5bd2
movl %ebx, %eax
imulq $0x30, %rax, %rax
addq 0x60(%rsp), %rax
incq (%rax,%r12,8)
incb %bpl
jmp 0x42c9
incb %r14b
movq 0x10(%rsp), %r12
pushq $0x5
popq %rbp
cmpb %r12b, %r14b
ja 0x42ae
movzbl %r14b, %ebx
movq %r13, %rdi
movl %ebx, %esi
movl %ebp, %edx
callq 0x5bd2
movq 0x60(%rsp), %rax
imulq $0x30, %rbx, %rcx
incq 0x28(%rax,%rcx)
incb %r14b
jmp 0x431c
movq 0xaca5(%rip), %rdi      # 0xeff0
leaq 0x4e15(%rip), %rsi      # 0x9167
callq 0x2230
movq %rax, %rdi
movl %r12d, %esi
callq 0x23c0
leaq 0x4e23(%rip), %rsi      # 0x918c
movq %rax, %rdi
callq 0x2230
movq %rax, %rdi
callq 0x20f0
movq 0x8(%rsp), %rdi
callq 0x4731
movq %r15, %rdi
callq 0x23a0
jmp 0x44a6
leaq 0x28(%rsp), %rdi
callq 0x5bf2
movq 0x8(%rsp), %rdi
callq 0x4731
movq 0x20(%rsp), %rdi
callq 0x23a0
movl 0x1c(%rsp), %ebx
movq 0xac17(%rip), %rdi      # 0xefd0
leaq 0x4e5a(%rip), %rsi      # 0x921a
callq 0x2230
movq %rax, %rdi
callq 0x20f0
movzbl %r12b, %ebp
leaq 0x90(%rsp), %rdx
leaq 0x78(%rsp), %rcx
movl %ebp, %edi
movl %ebx, %esi
callq 0x26cb
leaq 0x90(%rsp), %rdi
callq 0x269a
movq 0xabd5(%rip), %rdi      # 0xefd0
leaq 0x4e31(%rip), %rsi      # 0x9233
callq 0x2230
movq %rax, %rdi
callq 0x20f0
leaq 0x60(%rsp), %rdx
leaq 0x78(%rsp), %rcx
leaq 0xa8(%rsp), %r8
movl %ebp, %edi
movl %ebx, %esi
callq 0x32c3
movq 0xab9f(%rip), %rdi      # 0xefd0
leaq 0x4e1b(%rip), %rsi      # 0x9253
callq 0x2230
movq %rax, %rdi
callq 0x20f0
leaq 0x78(%rsp), %rdx
leaq 0xa8(%rsp), %rcx
movl %ebp, %edi
movl %ebx, %esi
callq 0x3e54
movq 0xab6e(%rip), %rdi      # 0xefd0
leaq 0x4dfb(%rip), %rsi      # 0x9264
callq 0x2230
movq %rax, %rdi
callq 0x20f0
leaq 0x60(%rsp), %rdi
callq 0x7f22
leaq 0xa8(%rsp), %rdi
callq 0x20d0
leaq 0x78(%rsp), %rdi
callq 0x4ab2
leaq 0x90(%rsp), %rdi
callq 0x4ab2
xorl %ebp, %ebp
movl %ebp, %eax
addq $0xc8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x44fb
jmp 0x44f2
jmp 0x44ed
movq %rax, %rbx
jmp 0x451f
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x20d0
jmp 0x4529
movq %rax, %rbx
jmp 0x4529
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x20d0
jmp 0x4536
movq %rax, %rbx
jmp 0x4536
movq %rax, %rbx
jmp 0x4512
movq %rax, %rbx
jmp 0x4508
jmp 0x44fb
jmp 0x44fb
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x5bf2
leaq 0x60(%rsp), %rdi
callq 0x7f22
leaq 0xa8(%rsp), %rdi
callq 0x20d0
leaq 0x78(%rsp), %rdi
callq 0x4ab2
leaq 0x90(%rsp), %rdi
callq 0x4ab2
movq %rbx, %rdi
callq 0x23d0